Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(739)

Side by Side Diff: conformance/resources/glsl-generator.js

Issue 42083002: Add ToT WebGL conformance tests : part 10 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/webgl/sdk/tests/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
## -0,0 +1 ##
+LF
\ No newline at end of property
OLDNEW
(Empty)
1 /*
2 ** Copyright (c) 2012 The Khronos Group Inc.
3 **
4 ** Permission is hereby granted, free of charge, to any person obtaining a
5 ** copy of this software and/or associated documentation files (the
6 ** "Materials"), to deal in the Materials without restriction, including
7 ** without limitation the rights to use, copy, modify, merge, publish,
8 ** distribute, sublicense, and/or sell copies of the Materials, and to
9 ** permit persons to whom the Materials are furnished to do so, subject to
10 ** the following conditions:
11 **
12 ** The above copyright notice and this permission notice shall be included
13 ** in all copies or substantial portions of the Materials.
14 **
15 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
22 */
23 GLSLGenerator = (function() {
24
25 var vertexShaderTemplate = [
26 "attribute vec4 aPosition;",
27 "",
28 "varying vec4 vColor;",
29 "",
30 "$(extra)",
31 "$(emu)",
32 "",
33 "void main()",
34 "{",
35 " gl_Position = aPosition;",
36 " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));",
37 " vec4 color = vec4(",
38 " texcoord,",
39 " texcoord.x * texcoord.y,",
40 " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);",
41 " $(test)",
42 "}"
43 ].join("\n");
44
45 var fragmentShaderTemplate = [
46 "#if defined(GL_ES)",
47 "precision mediump float;",
48 "#endif",
49 "",
50 "varying vec4 vColor;",
51 "",
52 "$(extra)",
53 "$(emu)",
54 "",
55 "void main()",
56 "{",
57 " $(test)",
58 "}"
59 ].join("\n");
60
61 var baseVertexShader = [
62 "attribute vec4 aPosition;",
63 "",
64 "varying vec4 vColor;",
65 "",
66 "void main()",
67 "{",
68 " gl_Position = aPosition;",
69 " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));",
70 " vColor = vec4(",
71 " texcoord,",
72 " texcoord.x * texcoord.y,",
73 " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);",
74 "}"
75 ].join("\n");
76
77 var baseVertexShaderWithColor = [
78 "attribute vec4 aPosition;",
79 "attribute vec4 aColor;",
80 "",
81 "varying vec4 vColor;",
82 "",
83 "void main()",
84 "{",
85 " gl_Position = aPosition;",
86 " vColor = aColor;",
87 "}"
88 ].join("\n");
89
90 var baseFragmentShader = [
91 "#if defined(GL_ES)",
92 "precision mediump float;",
93 "#endif",
94 "varying vec4 vColor;",
95 "",
96 "void main()",
97 "{",
98 " gl_FragColor = vColor;",
99 "}"
100 ].join("\n");
101
102 var types = [
103 { type: "float",
104 code: [
105 "float $(func)_emu($(args)) {",
106 " return $(func)_base($(baseArgs));",
107 "}"].join("\n")
108 },
109 { type: "vec2",
110 code: [
111 "vec2 $(func)_emu($(args)) {",
112 " return vec2(",
113 " $(func)_base($(baseArgsX)),",
114 " $(func)_base($(baseArgsY)));",
115 "}"].join("\n")
116 },
117 { type: "vec3",
118 code: [
119 "vec3 $(func)_emu($(args)) {",
120 " return vec3(",
121 " $(func)_base($(baseArgsX)),",
122 " $(func)_base($(baseArgsY)),",
123 " $(func)_base($(baseArgsZ)));",
124 "}"].join("\n")
125 },
126 { type: "vec4",
127 code: [
128 "vec4 $(func)_emu($(args)) {",
129 " return vec4(",
130 " $(func)_base($(baseArgsX)),",
131 " $(func)_base($(baseArgsY)),",
132 " $(func)_base($(baseArgsZ)),",
133 " $(func)_base($(baseArgsW)));",
134 "}"].join("\n")
135 }
136 ];
137
138 var bvecTypes = [
139 { type: "bvec2",
140 code: [
141 "bvec2 $(func)_emu($(args)) {",
142 " return bvec2(",
143 " $(func)_base($(baseArgsX)),",
144 " $(func)_base($(baseArgsY)));",
145 "}"].join("\n")
146 },
147 { type: "bvec3",
148 code: [
149 "bvec3 $(func)_emu($(args)) {",
150 " return bvec3(",
151 " $(func)_base($(baseArgsX)),",
152 " $(func)_base($(baseArgsY)),",
153 " $(func)_base($(baseArgsZ)));",
154 "}"].join("\n")
155 },
156 { type: "bvec4",
157 code: [
158 "vec4 $(func)_emu($(args)) {",
159 " return bvec4(",
160 " $(func)_base($(baseArgsX)),",
161 " $(func)_base($(baseArgsY)),",
162 " $(func)_base($(baseArgsZ)),",
163 " $(func)_base($(baseArgsW)));",
164 "}"].join("\n")
165 }
166 ];
167
168 var replaceRE = /\$\((\w+)\)/g;
169
170 var replaceParams = function(str) {
171 var args = arguments;
172 return str.replace(replaceRE, function(str, p1, offset, s) {
173 for (var ii = 1; ii < args.length; ++ii) {
174 if (args[ii][p1] !== undefined) {
175 return args[ii][p1];
176 }
177 }
178 throw "unknown string param '" + p1 + "'";
179 });
180 };
181
182 var generateReferenceShader = function(
183 shaderInfo, template, params, typeInfo, test) {
184 var input = shaderInfo.input;
185 var output = shaderInfo.output;
186 var feature = params.feature;
187 var testFunc = params.testFunc;
188 var emuFunc = params.emuFunc || "";
189 var extra = params.extra || '';
190 var args = params.args || "$(type) value";
191 var type = typeInfo.type;
192 var typeCode = typeInfo.code;
193
194 var baseArgs = params.baseArgs || "value$(field)";
195 var baseArgsX = replaceParams(baseArgs, {field: ".x"});
196 var baseArgsY = replaceParams(baseArgs, {field: ".y"});
197 var baseArgsZ = replaceParams(baseArgs, {field: ".z"});
198 var baseArgsW = replaceParams(baseArgs, {field: ".w"});
199 var baseArgs = replaceParams(baseArgs, {field: ""});
200
201 test = replaceParams(test, {
202 input: input,
203 output: output,
204 func: feature + "_emu"
205 });
206 emuFunc = replaceParams(emuFunc, {
207 func: feature
208 });
209 args = replaceParams(args, {
210 type: type
211 });
212 typeCode = replaceParams(typeCode, {
213 func: feature,
214 type: type,
215 args: args,
216 baseArgs: baseArgs,
217 baseArgsX: baseArgsX,
218 baseArgsY: baseArgsY,
219 baseArgsZ: baseArgsZ,
220 baseArgsW: baseArgsW
221 });
222 var shader = replaceParams(template, {
223 extra: extra,
224 emu: emuFunc + "\n\n" + typeCode,
225 test: test
226 });
227 return shader;
228 };
229
230 var generateTestShader = function(
231 shaderInfo, template, params, test) {
232 var input = shaderInfo.input;
233 var output = shaderInfo.output;
234 var feature = params.feature;
235 var testFunc = params.testFunc;
236 var extra = params.extra || '';
237
238 test = replaceParams(test, {
239 input: input,
240 output: output,
241 func: feature
242 });
243 var shader = replaceParams(template, {
244 extra: extra,
245 emu: '',
246 test: test
247 });
248 return shader;
249 };
250
251 var runFeatureTest = function(params) {
252 var wtu = WebGLTestUtils;
253 var gridRes = params.gridRes;
254 var vertexTolerance = params.tolerance || 0;
255 var fragmentTolerance = vertexTolerance;
256 if ('fragmentTolerance' in params)
257 fragmentTolerance = params.fragmentTolerance || 0;
258
259 description("Testing GLSL feature: " + params.feature);
260
261 var width = 32;
262 var height = 32;
263
264 var console = document.getElementById("console");
265 var canvas = document.createElement('canvas');
266 canvas.width = width;
267 canvas.height = height;
268 var gl = wtu.create3DContext(canvas, { premultipliedAlpha: false });
269 if (!gl) {
270 testFailed("context does not exist");
271 finishTest();
272 return;
273 }
274
275 var canvas2d = document.createElement('canvas');
276 canvas2d.width = width;
277 canvas2d.height = height;
278 var ctx = canvas2d.getContext("2d");
279 var imgData = ctx.getImageData(0, 0, width, height);
280
281 var shaderInfos = [
282 { type: "vertex",
283 input: "color",
284 output: "vColor",
285 vertexShaderTemplate: vertexShaderTemplate,
286 fragmentShaderTemplate: baseFragmentShader,
287 tolerance: vertexTolerance
288 },
289 { type: "fragment",
290 input: "vColor",
291 output: "gl_FragColor",
292 vertexShaderTemplate: baseVertexShader,
293 fragmentShaderTemplate: fragmentShaderTemplate,
294 tolerance: fragmentTolerance
295 }
296 ];
297 for (var ss = 0; ss < shaderInfos.length; ++ss) {
298 var shaderInfo = shaderInfos[ss];
299 var tests = params.tests;
300 var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
301 // Test vertex shaders
302 for (var ii = 0; ii < tests.length; ++ii) {
303 var type = testTypes[ii];
304 if (params.simpleEmu) {
305 type = {
306 type: type.type,
307 code: params.simpleEmu
308 };
309 }
310 debug("");
311 var str = replaceParams(params.testFunc, {
312 func: params.feature,
313 type: type.type,
314 arg0: type.type
315 });
316 debug("Testing: " + str + " in " + shaderInfo.type + " shader");
317
318 var referenceVertexShaderSource = generateReferenceShader(
319 shaderInfo,
320 shaderInfo.vertexShaderTemplate,
321 params,
322 type,
323 tests[ii]);
324 var referenceFragmentShaderSource = generateReferenceShader(
325 shaderInfo,
326 shaderInfo.fragmentShaderTemplate,
327 params,
328 type,
329 tests[ii]);
330 var testVertexShaderSource = generateTestShader(
331 shaderInfo,
332 shaderInfo.vertexShaderTemplate,
333 params,
334 tests[ii]);
335 var testFragmentShaderSource = generateTestShader(
336 shaderInfo,
337 shaderInfo.fragmentShaderTemplate,
338 params,
339 tests[ii]);
340
341 debug("");
342 wtu.addShaderSource(
343 console, "reference vertex shader", referenceVertexShaderSource);
344 wtu.addShaderSource(
345 console, "reference fragment shader", referenceFragmentShaderSource);
346 wtu.addShaderSource(
347 console, "test vertex shader", testVertexShaderSource);
348 wtu.addShaderSource(
349 console, "test fragment shader", testFragmentShaderSource);
350 debug("");
351
352 var refData = draw(
353 canvas, referenceVertexShaderSource, referenceFragmentShaderSource);
354 var refImg = wtu.makeImage(canvas);
355 if (ss == 0) {
356 var testData = draw(
357 canvas, testVertexShaderSource, referenceFragmentShaderSource);
358 } else {
359 var testData = draw(
360 canvas, referenceVertexShaderSource, testFragmentShaderSource);
361 }
362 var testImg = wtu.makeImage(canvas);
363
364 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance);
365 }
366 }
367
368 finishTest();
369
370 function reportResults(refData, refImage, testData, testImage, tolerance) {
371 var same = true;
372 for (var yy = 0; yy < height; ++yy) {
373 for (var xx = 0; xx < width; ++xx) {
374 var offset = (yy * width + xx) * 4;
375 var imgOffset = ((height - yy - 1) * width + xx) * 4;
376 imgData.data[imgOffset + 0] = 0;
377 imgData.data[imgOffset + 1] = 0;
378 imgData.data[imgOffset + 2] = 0;
379 imgData.data[imgOffset + 3] = 255;
380 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
381 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
382 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
383 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
384 imgData.data[imgOffset] = 255;
385 same = false;
386 }
387 }
388 }
389
390 var diffImg = null;
391 if (!same) {
392 ctx.putImageData(imgData, 0, 0);
393 diffImg = wtu.makeImage(canvas2d);
394 }
395
396 var div = document.createElement("div");
397 div.className = "testimages";
398 wtu.insertImage(div, "ref", refImg);
399 wtu.insertImage(div, "test", testImg);
400 if (diffImg) {
401 wtu.insertImage(div, "diff", diffImg);
402 }
403 div.appendChild(document.createElement('br'));
404
405
406 console.appendChild(div);
407
408 if (!same) {
409 testFailed("images are different");
410 } else {
411 testPassed("images are the same");
412 }
413
414 console.appendChild(document.createElement('hr'));
415 }
416
417 function draw(canvas, vsSource, fsSource) {
418 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
419
420 var posLoc = gl.getAttribLocation(program, "aPosition");
421 wtu.setupIndexedQuad(gl, gridRes, posLoc);
422
423 gl.useProgram(program);
424 wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
425 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
426
427 var img = new Uint8Array(width * height * 4);
428 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
429 return img;
430 }
431
432 };
433
434 var runBasicTest = function(params) {
435 var wtu = WebGLTestUtils;
436 var gridRes = params.gridRes;
437 var vertexTolerance = params.tolerance || 0;
438 var fragmentTolerance = vertexTolerance;
439 if ('fragmentTolerance' in params)
440 fragmentTolerance = params.fragmentTolerance || 0;
441
442 description("Testing : " + document.getElementsByTagName("title")[0].innerText );
443
444 var width = 32;
445 var height = 32;
446
447 var console = document.getElementById("console");
448 var canvas = document.createElement('canvas');
449 canvas.width = width;
450 canvas.height = height;
451 var gl = wtu.create3DContext(canvas);
452 if (!gl) {
453 testFailed("context does not exist");
454 finishTest();
455 return;
456 }
457
458 var canvas2d = document.createElement('canvas');
459 canvas2d.width = width;
460 canvas2d.height = height;
461 var ctx = canvas2d.getContext("2d");
462 var imgData = ctx.getImageData(0, 0, width, height);
463
464 var shaderInfos = [
465 { type: "vertex",
466 input: "color",
467 output: "vColor",
468 vertexShaderTemplate: vertexShaderTemplate,
469 fragmentShaderTemplate: baseFragmentShader,
470 tolerance: vertexTolerance
471 },
472 { type: "fragment",
473 input: "vColor",
474 output: "gl_FragColor",
475 vertexShaderTemplate: baseVertexShader,
476 fragmentShaderTemplate: fragmentShaderTemplate,
477 tolerance: fragmentTolerance
478 }
479 ];
480 for (var ss = 0; ss < shaderInfos.length; ++ss) {
481 var shaderInfo = shaderInfos[ss];
482 var tests = params.tests;
483 // var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
484 // Test vertex shaders
485 for (var ii = 0; ii < tests.length; ++ii) {
486 var test = tests[ii];
487 debug("");
488 debug("Testing: " + test.name + " in " + shaderInfo.type + " shader");
489
490 function genShader(shaderInfo, template, shader, subs) {
491 shader = replaceParams(shader, subs, {
492 input: shaderInfo.input,
493 output: shaderInfo.output
494 });
495 shader = replaceParams(template, subs, {
496 test: shader,
497 emu: "",
498 extra: ""
499 });
500 return shader;
501 }
502
503 var referenceVertexShaderSource = genShader(
504 shaderInfo,
505 shaderInfo.vertexShaderTemplate,
506 test.reference.shader,
507 test.reference.subs);
508 var referenceFragmentShaderSource = genShader(
509 shaderInfo,
510 shaderInfo.fragmentShaderTemplate,
511 test.reference.shader,
512 test.reference.subs);
513 var testVertexShaderSource = genShader(
514 shaderInfo,
515 shaderInfo.vertexShaderTemplate,
516 test.test.shader,
517 test.test.subs);
518 var testFragmentShaderSource = genShader(
519 shaderInfo,
520 shaderInfo.fragmentShaderTemplate,
521 test.test.shader,
522 test.test.subs);
523
524 debug("");
525 wtu.addShaderSource(
526 console, "reference vertex shader", referenceVertexShaderSource);
527 wtu.addShaderSource(
528 console, "reference fragment shader", referenceFragmentShaderSource);
529 wtu.addShaderSource(
530 console, "test vertex shader", testVertexShaderSource);
531 wtu.addShaderSource(
532 console, "test fragment shader", testFragmentShaderSource);
533 debug("");
534
535 var refData = draw(
536 canvas, referenceVertexShaderSource, referenceFragmentShaderSource);
537 var refImg = wtu.makeImage(canvas);
538 if (ss == 0) {
539 var testData = draw(
540 canvas, testVertexShaderSource, referenceFragmentShaderSource);
541 } else {
542 var testData = draw(
543 canvas, referenceVertexShaderSource, testFragmentShaderSource);
544 }
545 var testImg = wtu.makeImage(canvas);
546
547 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance);
548 }
549 }
550
551 finishTest();
552
553 function reportResults(refData, refImage, testData, testImage, tolerance) {
554 var same = true;
555 for (var yy = 0; yy < height; ++yy) {
556 for (var xx = 0; xx < width; ++xx) {
557 var offset = (yy * width + xx) * 4;
558 var imgOffset = ((height - yy - 1) * width + xx) * 4;
559 imgData.data[imgOffset + 0] = 0;
560 imgData.data[imgOffset + 1] = 0;
561 imgData.data[imgOffset + 2] = 0;
562 imgData.data[imgOffset + 3] = 255;
563 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
564 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
565 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
566 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
567 imgData.data[imgOffset] = 255;
568 same = false;
569 }
570 }
571 }
572
573 var diffImg = null;
574 if (!same) {
575 ctx.putImageData(imgData, 0, 0);
576 diffImg = wtu.makeImage(canvas2d);
577 }
578
579 var div = document.createElement("div");
580 div.className = "testimages";
581 wtu.insertImage(div, "ref", refImg);
582 wtu.insertImage(div, "test", testImg);
583 if (diffImg) {
584 wtu.insertImage(div, "diff", diffImg);
585 }
586 div.appendChild(document.createElement('br'));
587
588 console.appendChild(div);
589
590 if (!same) {
591 testFailed("images are different");
592 } else {
593 testPassed("images are the same");
594 }
595
596 console.appendChild(document.createElement('hr'));
597 }
598
599 function draw(canvas, vsSource, fsSource) {
600 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
601
602 var posLoc = gl.getAttribLocation(program, "aPosition");
603 wtu.setupIndexedQuad(gl, gridRes, posLoc);
604
605 gl.useProgram(program);
606 wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
607 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
608
609 var img = new Uint8Array(width * height * 4);
610 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
611 return img;
612 }
613
614 };
615
616 var runReferenceImageTest = function(params) {
617 var wtu = WebGLTestUtils;
618 var gridRes = params.gridRes;
619 var vertexTolerance = params.tolerance || 0;
620 var fragmentTolerance = vertexTolerance;
621 if ('fragmentTolerance' in params)
622 fragmentTolerance = params.fragmentTolerance || 0;
623
624 description("Testing GLSL feature: " + params.feature);
625
626 var width = 32;
627 var height = 32;
628
629 var console = document.getElementById("console");
630 var canvas = document.createElement('canvas');
631 canvas.width = width;
632 canvas.height = height;
633 var gl = wtu.create3DContext(canvas, { antialias: false, premultipliedAlpha: f alse });
634 if (!gl) {
635 testFailed("context does not exist");
636 finishTest();
637 return;
638 }
639
640 var canvas2d = document.createElement('canvas');
641 canvas2d.width = width;
642 canvas2d.height = height;
643 var ctx = canvas2d.getContext("2d");
644 var imgData = ctx.getImageData(0, 0, width, height);
645
646 // State for reference images for vertex shader tests.
647 // These are drawn with the same tessellated grid as the test vertex
648 // shader so that the interpolation is identical. The grid is reused
649 // from test to test; the colors are changed.
650
651 var indexedQuadForReferenceVertexShader =
652 wtu.setupIndexedQuad(gl, gridRes, 0);
653 var referenceVertexShaderProgram =
654 wtu.setupProgram(gl, [ baseVertexShaderWithColor, baseFragmentShader ],
655 ["aPosition", "aColor"]);
656 var referenceVertexShaderColorBuffer = gl.createBuffer();
657
658 var shaderInfos = [
659 { type: "vertex",
660 input: "color",
661 output: "vColor",
662 vertexShaderTemplate: vertexShaderTemplate,
663 fragmentShaderTemplate: baseFragmentShader,
664 tolerance: vertexTolerance
665 },
666 { type: "fragment",
667 input: "vColor",
668 output: "gl_FragColor",
669 vertexShaderTemplate: baseVertexShader,
670 fragmentShaderTemplate: fragmentShaderTemplate,
671 tolerance: fragmentTolerance
672 }
673 ];
674 for (var ss = 0; ss < shaderInfos.length; ++ss) {
675 var shaderInfo = shaderInfos[ss];
676 var tests = params.tests;
677 var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
678 // Test vertex shaders
679 for (var ii = 0; ii < tests.length; ++ii) {
680 var type = testTypes[ii];
681 var isVertex = (ss == 0);
682 debug("");
683 var str = replaceParams(params.testFunc, {
684 func: params.feature,
685 type: type.type,
686 arg0: type.type
687 });
688 debug("Testing: " + str + " in " + shaderInfo.type + " shader");
689
690 var referenceVertexShaderSource = generateReferenceShader(
691 shaderInfo,
692 shaderInfo.vertexShaderTemplate,
693 params,
694 type,
695 tests[ii].source);
696 var referenceFragmentShaderSource = generateReferenceShader(
697 shaderInfo,
698 shaderInfo.fragmentShaderTemplate,
699 params,
700 type,
701 tests[ii].source);
702 var testVertexShaderSource = generateTestShader(
703 shaderInfo,
704 shaderInfo.vertexShaderTemplate,
705 params,
706 tests[ii].source);
707 var testFragmentShaderSource = generateTestShader(
708 shaderInfo,
709 shaderInfo.fragmentShaderTemplate,
710 params,
711 tests[ii].source);
712 var referenceTextureOrArray = generateReferenceImage(
713 gl,
714 tests[ii].generator,
715 isVertex ? gridRes : width,
716 isVertex ? gridRes : height,
717 isVertex);
718
719 debug("");
720 wtu.addShaderSource(
721 console, "test vertex shader", testVertexShaderSource);
722 wtu.addShaderSource(
723 console, "test fragment shader", testFragmentShaderSource);
724 debug("");
725 var refData;
726 if (isVertex) {
727 refData = drawVertexReferenceImage(canvas, referenceTextureOrArray);
728 } else {
729 refData = drawFragmentReferenceImage(canvas, referenceTextureOrArray);
730 }
731 var refImg = wtu.makeImage(canvas);
732 var testData;
733 if (isVertex) {
734 testData = draw(
735 canvas, testVertexShaderSource, referenceFragmentShaderSource);
736 } else {
737 testData = draw(
738 canvas, referenceVertexShaderSource, testFragmentShaderSource);
739 }
740 var testImg = wtu.makeImage(canvas);
741 var testTolerance = shaderInfo.tolerance;
742 // Provide per-test tolerance so that we can increase it only for those de sired.
743 if ('tolerance' in tests[ii])
744 testTolerance = tests[ii].tolerance || 0;
745 reportResults(refData, refImg, testData, testImg, testTolerance);
746 }
747 }
748
749 finishTest();
750
751 function reportResults(refData, refImage, testData, testImage, tolerance) {
752 var same = true;
753 for (var yy = 0; yy < height; ++yy) {
754 for (var xx = 0; xx < width; ++xx) {
755 var offset = (yy * width + xx) * 4;
756 var imgOffset = ((height - yy - 1) * width + xx) * 4;
757 imgData.data[imgOffset + 0] = 0;
758 imgData.data[imgOffset + 1] = 0;
759 imgData.data[imgOffset + 2] = 0;
760 imgData.data[imgOffset + 3] = 255;
761 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
762 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
763 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
764 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
765 console.appendChild(document.createTextNode('at (' + xx + ',' + yy + ' ): ref=(' +
766 refData[offset + 0] + ',' +
767 refData[offset + 1] + ',' +
768 refData[offset + 2] + ',' +
769 refData[offset + 3] + ') test=(' +
770 testData[offset + 0] + ',' +
771 testData[offset + 1] + ',' +
772 testData[offset + 2] + ',' +
773 testData[offset + 3] + ')' ));
774 console.appendChild(document.createElement('br'));
775
776
777
778 imgData.data[imgOffset] = 255;
779 same = false;
780 }
781 }
782 }
783
784 var diffImg = null;
785 if (!same) {
786 ctx.putImageData(imgData, 0, 0);
787 diffImg = wtu.makeImage(canvas2d);
788 }
789
790 var div = document.createElement("div");
791 div.className = "testimages";
792 wtu.insertImage(div, "ref", refImg);
793 wtu.insertImage(div, "test", testImg);
794 if (diffImg) {
795 wtu.insertImage(div, "diff", diffImg);
796 }
797 div.appendChild(document.createElement('br'));
798
799 console.appendChild(div);
800
801 if (!same) {
802 testFailed("images are different");
803 } else {
804 testPassed("images are the same");
805 }
806
807 console.appendChild(document.createElement('hr'));
808 }
809
810 function draw(canvas, vsSource, fsSource) {
811 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
812
813 var posLoc = gl.getAttribLocation(program, "aPosition");
814 wtu.setupIndexedQuad(gl, gridRes, posLoc);
815
816 gl.useProgram(program);
817 wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
818 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
819
820 var img = new Uint8Array(width * height * 4);
821 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
822 return img;
823 }
824
825 function drawVertexReferenceImage(canvas, colors) {
826 gl.bindBuffer(gl.ARRAY_BUFFER, indexedQuadForReferenceVertexShader[0]);
827 gl.enableVertexAttribArray(0);
828 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
829 gl.bindBuffer(gl.ARRAY_BUFFER, referenceVertexShaderColorBuffer);
830 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
831 gl.enableVertexAttribArray(1);
832 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
833 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexedQuadForReferenceVertexShader[1 ]);
834 gl.useProgram(referenceVertexShaderProgram);
835 wtu.clearAndDrawIndexedQuad(gl, gridRes);
836 gl.disableVertexAttribArray(0);
837 gl.disableVertexAttribArray(1);
838 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
839
840 var img = new Uint8Array(width * height * 4);
841 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
842 return img;
843 }
844
845 function drawFragmentReferenceImage(canvas, texture) {
846 var program = wtu.setupTexturedQuad(gl);
847
848 gl.activeTexture(gl.TEXTURE0);
849 gl.bindTexture(gl.TEXTURE_2D, texture);
850 var texLoc = gl.getUniformLocation(program, "tex");
851 gl.uniform1i(texLoc, 0);
852 wtu.clearAndDrawUnitQuad(gl);
853 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
854
855 var img = new Uint8Array(width * height * 4);
856 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
857 return img;
858 }
859
860 /**
861 * Creates and returns either a Uint8Array (for vertex shaders) or
862 * WebGLTexture (for fragment shaders) containing the reference
863 * image for the function being tested. Exactly how the function is
864 * evaluated, and the size of the returned texture or array, depends on
865 * whether we are testing a vertex or fragment shader. If a fragment
866 * shader, the function is evaluated at the pixel centers. If a
867 * vertex shader, the function is evaluated at the triangle's
868 * vertices.
869 *
870 * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use to gene rate texture objects.
871 * @param {!function(number,number,number,number): !Array.<number>} generator The reference image generator function.
872 * @param {number} width The width of the texture to generate if testing a fra gment shader; the grid resolution if testing a vertex shader.
873 * @param {number} height The height of the texture to generate if testing a f ragment shader; the grid resolution if testing a vertex shader.
874 * @param {boolean} isVertex True if generating a reference image for a vertex shader; false if for a fragment shader.
875 * @return {!WebGLTexture|!Uint8Array} The texture object or array that was ge nerated.
876 */
877 function generateReferenceImage(
878 gl,
879 generator,
880 width,
881 height,
882 isVertex) {
883
884 // Note: the math in this function must match that in the vertex and
885 // fragment shader templates above.
886 function computeTexCoord(x) {
887 return x * 0.5 + 0.5;
888 }
889
890 function computeVertexColor(texCoordX, texCoordY) {
891 return [ texCoordX,
892 texCoordY,
893 texCoordX * texCoordY,
894 (1.0 - texCoordX) * texCoordY * 0.5 + 0.5 ];
895 }
896
897 /**
898 * Computes fragment color according to the algorithm used for interpolation
899 * in OpenGL (GLES 2.0 spec 3.5.1, OpenGL 4.3 spec 14.6.1).
900 */
901 function computeInterpolatedColor(texCoordX, texCoordY) {
902 // Calculate grid line indexes below and to the left from texCoord.
903 var gridBottom = Math.floor(texCoordY * gridRes);
904 if (gridBottom == gridRes) {
905 --gridBottom;
906 }
907 var gridLeft = Math.floor(texCoordX * gridRes);
908 if (gridLeft == gridRes) {
909 --gridLeft;
910 }
911
912 // Calculate coordinates relative to the grid cell.
913 var cellX = texCoordX * gridRes - gridLeft;
914 var cellY = texCoordY * gridRes - gridBottom;
915
916 // Barycentric coordinates inside either triangle ACD or ABC
917 // are used as weights for the vertex colors in the corners:
918 // A--B
919 // |\ |
920 // | \|
921 // D--C
922
923 var aColor = computeVertexColor(gridLeft / gridRes, (gridBottom + 1) / gri dRes);
924 var bColor = computeVertexColor((gridLeft + 1) / gridRes, (gridBottom + 1) / gridRes);
925 var cColor = computeVertexColor((gridLeft + 1) / gridRes, gridBottom / gri dRes);
926 var dColor = computeVertexColor(gridLeft / gridRes, gridBottom / gridRes);
927
928 // Calculate weights.
929 var a, b, c, d;
930
931 if (cellX + cellY < 1) {
932 // In bottom triangle ACD.
933 a = cellY; // area of triangle C-D-(cellX, cellY) relative to ACD
934 c = cellX; // area of triangle D-A-(cellX, cellY) relative to ACD
935 d = 1 - a - c;
936 b = 0;
937 } else {
938 // In top triangle ABC.
939 a = 1 - cellX; // area of the triangle B-C-(cellX, cellY) relative to AB C
940 c = 1 - cellY; // area of the triangle A-B-(cellX, cellY) relative to AB C
941 b = 1 - a - c;
942 d = 0;
943 }
944
945 var interpolated = [];
946 for (var ii = 0; ii < aColor.length; ++ii) {
947 interpolated.push(a * aColor[ii] + b * bColor[ii] + c * cColor[ii] + d * dColor[ii]);
948 }
949 return interpolated;
950 }
951
952 function clamp(value, minVal, maxVal) {
953 return Math.max(minVal, Math.min(value, maxVal));
954 }
955
956 // Evaluates the function at clip coordinates (px,py), storing the
957 // result in the array "pixel". Each channel's result is clamped
958 // between 0 and 255.
959 function evaluateAtClipCoords(px, py, pixel, colorFunc) {
960 var tcx = computeTexCoord(px);
961 var tcy = computeTexCoord(py);
962
963 var color = colorFunc(tcx, tcy);
964
965 var output = generator(color[0], color[1], color[2], color[3]);
966
967 // Multiply by 256 to get even distribution for all values between 0 and 1 .
968 // Use rounding rather than truncation to more closely match the GPU's beh avior.
969 pixel[0] = clamp(Math.round(256 * output[0]), 0, 255);
970 pixel[1] = clamp(Math.round(256 * output[1]), 0, 255);
971 pixel[2] = clamp(Math.round(256 * output[2]), 0, 255);
972 pixel[3] = clamp(Math.round(256 * output[3]), 0, 255);
973 }
974
975 function generateFragmentReference() {
976 var data = new Uint8Array(4 * width * height);
977
978 var horizTexel = 1.0 / width;
979 var vertTexel = 1.0 / height;
980 var halfHorizTexel = 0.5 * horizTexel;
981 var halfVertTexel = 0.5 * vertTexel;
982
983 var pixel = new Array(4);
984
985 for (var yi = 0; yi < height; ++yi) {
986 for (var xi = 0; xi < width; ++xi) {
987 // The function must be evaluated at pixel centers.
988
989 // Compute desired position in clip space
990 var px = -1.0 + 2.0 * (halfHorizTexel + xi * horizTexel);
991 var py = -1.0 + 2.0 * (halfVertTexel + yi * vertTexel);
992
993 evaluateAtClipCoords(px, py, pixel, computeInterpolatedColor);
994 var index = 4 * (width * yi + xi);
995 data[index + 0] = pixel[0];
996 data[index + 1] = pixel[1];
997 data[index + 2] = pixel[2];
998 data[index + 3] = pixel[3];
999 }
1000 }
1001
1002 var texture = gl.createTexture();
1003 gl.bindTexture(gl.TEXTURE_2D, texture);
1004 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1005 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1006 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1007 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1008 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0,
1009 gl.RGBA, gl.UNSIGNED_BYTE, data);
1010 return texture;
1011 }
1012
1013 function generateVertexReference() {
1014 // We generate a Uint8Array which contains the evaluation of the
1015 // function at the vertices of the triangle mesh. It is expected
1016 // that the width and the height are identical, and equivalent
1017 // to the grid resolution.
1018 if (width != height) {
1019 throw "width and height must be equal";
1020 }
1021
1022 var texSize = 1 + width;
1023 var data = new Uint8Array(4 * texSize * texSize);
1024
1025 var step = 2.0 / width;
1026
1027 var pixel = new Array(4);
1028
1029 for (var yi = 0; yi < texSize; ++yi) {
1030 for (var xi = 0; xi < texSize; ++xi) {
1031 // The function is evaluated at the triangles' vertices.
1032
1033 // Compute desired position in clip space
1034 var px = -1.0 + (xi * step);
1035 var py = -1.0 + (yi * step);
1036
1037 evaluateAtClipCoords(px, py, pixel, computeVertexColor);
1038 var index = 4 * (texSize * yi + xi);
1039 data[index + 0] = pixel[0];
1040 data[index + 1] = pixel[1];
1041 data[index + 2] = pixel[2];
1042 data[index + 3] = pixel[3];
1043 }
1044 }
1045
1046 return data;
1047 }
1048
1049 //----------------------------------------------------------------------
1050 // Body of generateReferenceImage
1051 //
1052
1053 if (isVertex) {
1054 return generateVertexReference();
1055 } else {
1056 return generateFragmentReference();
1057 }
1058 }
1059 };
1060
1061 return {
1062 /**
1063 * runs a bunch of GLSL tests using the passed in parameters
1064 * The parameters are:
1065 *
1066 * feature:
1067 * the name of the function being tested (eg, sin, dot,
1068 * normalize)
1069 *
1070 * testFunc:
1071 * The prototype of function to be tested not including the
1072 * return type.
1073 *
1074 * emuFunc:
1075 * A base function that can be used to generate emulation
1076 * functions. Example for 'ceil'
1077 *
1078 * float $(func)_base(float value) {
1079 * float m = mod(value, 1.0);
1080 * return m != 0.0 ? (value + 1.0 - m) : value;
1081 * }
1082 *
1083 * args:
1084 * The arguments to the function
1085 *
1086 * baseArgs: (optional)
1087 * The arguments when a base function is used to create an
1088 * emulation function. For example 'float sign_base(float v)'
1089 * is used to implemenent vec2 sign_emu(vec2 v).
1090 *
1091 * simpleEmu:
1092 * if supplied, the code that can be used to generate all
1093 * functions for all types.
1094 *
1095 * Example for 'normalize':
1096 *
1097 * $(type) $(func)_emu($(args)) {
1098 * return value / length(value);
1099 * }
1100 *
1101 * gridRes: (optional)
1102 * The resolution of the mesh to generate. The default is a
1103 * 1x1 grid but many vertex shaders need a higher resolution
1104 * otherwise the only values passed in are the 4 corners
1105 * which often have the same value.
1106 *
1107 * tests:
1108 * The code for each test. It is assumed the tests are for
1109 * float, vec2, vec3, vec4 in that order.
1110 *
1111 * tolerance: (optional)
1112 * Allow some tolerance in the comparisons. The tolerance is applied to
1113 * both vertex and fragment shaders. The default tolerance is 0, meaning
1114 * the values have to be identical.
1115 *
1116 * fragmentTolerance: (optional)
1117 * Specify a tolerance which only applies to fragment shaders. The
1118 * fragment-only tolerance will override the shared tolerance for
1119 * fragment shaders if both are specified. Fragment shaders usually
1120 * use mediump float precision so they sometimes require higher tolerance
1121 * than vertex shaders which use highp by default.
1122 */
1123 runFeatureTest: runFeatureTest,
1124
1125 /*
1126 * Runs a bunch of GLSL tests using the passed in parameters
1127 *
1128 * The parameters are:
1129 *
1130 * tests:
1131 * Array of tests. For each test the following parameters are expected
1132 *
1133 * name:
1134 * some description of the test
1135 * reference:
1136 * parameters for the reference shader (see below)
1137 * test:
1138 * parameters for the test shader (see below)
1139 *
1140 * The parameter for the reference and test shaders are
1141 *
1142 * shader: the GLSL for the shader
1143 * subs: any substitutions you wish to define for the shader.
1144 *
1145 * Each shader is created from a basic template that
1146 * defines an input and an output. You can see the
1147 * templates at the top of this file. The input and output
1148 * change depending on whether or not we are generating
1149 * a vertex or fragment shader.
1150 *
1151 * All this code function does is a bunch of string substitutions.
1152 * A substitution is defined by $(name). If name is found in
1153 * the 'subs' parameter it is replaced. 4 special names exist.
1154 *
1155 * 'input' the input to your GLSL. Always a vec4. All change
1156 * from 0 to 1 over the quad to be drawn.
1157 *
1158 * 'output' the output color. Also a vec4
1159 *
1160 * 'emu' a place to insert extra stuff
1161 * 'extra' a place to insert extra stuff.
1162 *
1163 * You can think of the templates like this
1164 *
1165 * $(extra)
1166 * $(emu)
1167 *
1168 * void main() {
1169 * // do math to calculate input
1170 * ...
1171 *
1172 * $(shader)
1173 * }
1174 *
1175 * Your shader first has any subs you provided applied as well
1176 * as 'input' and 'output'
1177 *
1178 * It is then inserted into the template which is also provided
1179 * with your subs.
1180 *
1181 * gridRes: (optional)
1182 * The resolution of the mesh to generate. The default is a
1183 * 1x1 grid but many vertex shaders need a higher resolution
1184 * otherwise the only values passed in are the 4 corners
1185 * which often have the same value.
1186 *
1187 * tolerance: (optional)
1188 * Allow some tolerance in the comparisons. The tolerance is applied to
1189 * both vertex and fragment shaders. The default tolerance is 0, meaning
1190 * the values have to be identical.
1191 *
1192 * fragmentTolerance: (optional)
1193 * Specify a tolerance which only applies to fragment shaders. The
1194 * fragment-only tolerance will override the shared tolerance for
1195 * fragment shaders if both are specified. Fragment shaders usually
1196 * use mediump float precision so they sometimes require higher tolerance
1197 * than vertex shaders which use highp.
1198 */
1199 runBasicTest: runBasicTest,
1200
1201 /**
1202 * Runs a bunch of GLSL tests using the passed in parameters. The
1203 * expected results are computed as a reference image in JavaScript
1204 * instead of on the GPU. The parameters are:
1205 *
1206 * feature:
1207 * the name of the function being tested (eg, sin, dot,
1208 * normalize)
1209 *
1210 * testFunc:
1211 * The prototype of function to be tested not including the
1212 * return type.
1213 *
1214 * args:
1215 * The arguments to the function
1216 *
1217 * gridRes: (optional)
1218 * The resolution of the mesh to generate. The default is a
1219 * 1x1 grid but many vertex shaders need a higher resolution
1220 * otherwise the only values passed in are the 4 corners
1221 * which often have the same value.
1222 *
1223 * tests:
1224 * Array of tests. It is assumed the tests are for float, vec2,
1225 * vec3, vec4 in that order. For each test the following
1226 * parameters are expected:
1227 *
1228 * source: the GLSL source code for the tests
1229 *
1230 * generator: a JavaScript function taking four parameters
1231 * which evaluates the same function as the GLSL source,
1232 * returning its result as a newly allocated array.
1233 *
1234 * tolerance: (optional) a per-test tolerance.
1235 *
1236 * extra: (optional)
1237 * Extra GLSL code inserted at the top of each test's shader.
1238 *
1239 * tolerance: (optional)
1240 * Allow some tolerance in the comparisons. The tolerance is applied to
1241 * both vertex and fragment shaders. The default tolerance is 0, meaning
1242 * the values have to be identical.
1243 *
1244 * fragmentTolerance: (optional)
1245 * Specify a tolerance which only applies to fragment shaders. The
1246 * fragment-only tolerance will override the shared tolerance for
1247 * fragment shaders if both are specified. Fragment shaders usually
1248 * use mediump float precision so they sometimes require higher tolerance
1249 * than vertex shaders which use highp.
1250 */
1251 runReferenceImageTest: runReferenceImageTest,
1252
1253 none: false
1254 };
1255
1256 }());
1257
OLDNEW
« no previous file with comments | « conformance/resources/glsl-feature-tests.css ('k') | conformance/resources/intArrayUniformShader.vert » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698