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

Side by Side Diff: third_party/webgl/sdk/tests/conformance/resources/glsl-generator.js

Issue 10399113: Roll webgl conformance tests to r17874: part 2, adding r17874 (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/
Patch Set: Created 8 years, 7 months 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
+ LF
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 baseFragmentShader = [
78 "#if defined(GL_ES)",
79 "precision mediump float;",
80 "#endif",
81 "varying vec4 vColor;",
82 "",
83 "void main()",
84 "{",
85 " gl_FragColor = vColor;",
86 "}"
87 ].join("\n");
88
89 var types = [
90 { type: "float",
91 code: [
92 "float $(func)_emu($(args)) {",
93 " return $(func)_base($(baseArgs));",
94 "}"].join("\n")
95 },
96 { type: "vec2",
97 code: [
98 "vec2 $(func)_emu($(args)) {",
99 " return vec2(",
100 " $(func)_base($(baseArgsX)),",
101 " $(func)_base($(baseArgsY)));",
102 "}"].join("\n")
103 },
104 { type: "vec3",
105 code: [
106 "vec3 $(func)_emu($(args)) {",
107 " return vec3(",
108 " $(func)_base($(baseArgsX)),",
109 " $(func)_base($(baseArgsY)),",
110 " $(func)_base($(baseArgsZ)));",
111 "}"].join("\n")
112 },
113 { type: "vec4",
114 code: [
115 "vec4 $(func)_emu($(args)) {",
116 " return vec4(",
117 " $(func)_base($(baseArgsX)),",
118 " $(func)_base($(baseArgsY)),",
119 " $(func)_base($(baseArgsZ)),",
120 " $(func)_base($(baseArgsW)));",
121 "}"].join("\n")
122 }
123 ];
124
125 var bvecTypes = [
126 { type: "bvec2",
127 code: [
128 "bvec2 $(func)_emu($(args)) {",
129 " return bvec2(",
130 " $(func)_base($(baseArgsX)),",
131 " $(func)_base($(baseArgsY)));",
132 "}"].join("\n")
133 },
134 { type: "bvec3",
135 code: [
136 "bvec3 $(func)_emu($(args)) {",
137 " return bvec3(",
138 " $(func)_base($(baseArgsX)),",
139 " $(func)_base($(baseArgsY)),",
140 " $(func)_base($(baseArgsZ)));",
141 "}"].join("\n")
142 },
143 { type: "bvec4",
144 code: [
145 "vec4 $(func)_emu($(args)) {",
146 " return bvec4(",
147 " $(func)_base($(baseArgsX)),",
148 " $(func)_base($(baseArgsY)),",
149 " $(func)_base($(baseArgsZ)),",
150 " $(func)_base($(baseArgsW)));",
151 "}"].join("\n")
152 }
153 ];
154
155 var replaceRE = /\$\((\w+)\)/g;
156
157 var replaceParams = function(str) {
158 var args = arguments;
159 return str.replace(replaceRE, function(str, p1, offset, s) {
160 for (var ii = 1; ii < args.length; ++ii) {
161 if (args[ii][p1] !== undefined) {
162 return args[ii][p1];
163 }
164 }
165 throw "unknown string param '" + p1 + "'";
166 });
167 };
168
169 var generateReferenceShader = function(
170 shaderInfo, template, params, typeInfo, test) {
171 var input = shaderInfo.input;
172 var output = shaderInfo.output;
173 var feature = params.feature;
174 var testFunc = params.testFunc;
175 var emuFunc = params.emuFunc || "";
176 var extra = params.extra || '';
177 var args = params.args || "$(type) value";
178 var type = typeInfo.type;
179 var typeCode = typeInfo.code;
180
181 var baseArgs = params.baseArgs || "value$(field)";
182 var baseArgsX = replaceParams(baseArgs, {field: ".x"});
183 var baseArgsY = replaceParams(baseArgs, {field: ".y"});
184 var baseArgsZ = replaceParams(baseArgs, {field: ".z"});
185 var baseArgsW = replaceParams(baseArgs, {field: ".w"});
186 var baseArgs = replaceParams(baseArgs, {field: ""});
187
188 test = replaceParams(test, {
189 input: input,
190 output: output,
191 func: feature + "_emu"
192 });
193 emuFunc = replaceParams(emuFunc, {
194 func: feature
195 });
196 args = replaceParams(args, {
197 type: type
198 });
199 typeCode = replaceParams(typeCode, {
200 func: feature,
201 type: type,
202 args: args,
203 baseArgs: baseArgs,
204 baseArgsX: baseArgsX,
205 baseArgsY: baseArgsY,
206 baseArgsZ: baseArgsZ,
207 baseArgsW: baseArgsW
208 });
209 var shader = replaceParams(template, {
210 extra: extra,
211 emu: emuFunc + "\n\n" + typeCode,
212 test: test
213 });
214 return shader;
215 };
216
217 var generateTestShader = function(
218 shaderInfo, template, params, test) {
219 var input = shaderInfo.input;
220 var output = shaderInfo.output;
221 var feature = params.feature;
222 var testFunc = params.testFunc;
223 var extra = params.extra || '';
224
225 test = replaceParams(test, {
226 input: input,
227 output: output,
228 func: feature
229 });
230 var shader = replaceParams(template, {
231 extra: extra,
232 emu: '',
233 test: test
234 });
235 return shader;
236 };
237
238 var runFeatureTest = function(params) {
239 if (window.initNonKhronosFramework) {
240 window.initNonKhronosFramework(false);
241 }
242
243 var wtu = WebGLTestUtils;
244 var gridRes = params.gridRes;
245 var vertexTolerance = params.tolerance || 0;
246 var fragmentTolerance = vertexTolerance;
247 if ('fragmentTolerance' in params)
248 fragmentTolerance = params.fragmentTolerance || 0;
249
250 description("Testing GLSL feature: " + params.feature);
251
252 var width = 32;
253 var height = 32;
254
255 var console = document.getElementById("console");
256 var canvas = document.createElement('canvas');
257 canvas.width = width;
258 canvas.height = height;
259 var gl = wtu.create3DContext(canvas);
260 if (!gl) {
261 testFailed("context does not exist");
262 finishTest();
263 return;
264 }
265
266 var canvas2d = document.createElement('canvas');
267 canvas2d.width = width;
268 canvas2d.height = height;
269 var ctx = canvas2d.getContext("2d");
270 var imgData = ctx.getImageData(0, 0, width, height);
271
272 var shaderInfos = [
273 { type: "vertex",
274 input: "color",
275 output: "vColor",
276 vertexShaderTemplate: vertexShaderTemplate,
277 fragmentShaderTemplate: baseFragmentShader,
278 tolerance: vertexTolerance
279 },
280 { type: "fragment",
281 input: "vColor",
282 output: "gl_FragColor",
283 vertexShaderTemplate: baseVertexShader,
284 fragmentShaderTemplate: fragmentShaderTemplate,
285 tolerance: fragmentTolerance
286 }
287 ];
288 for (var ss = 0; ss < shaderInfos.length; ++ss) {
289 var shaderInfo = shaderInfos[ss];
290 var tests = params.tests;
291 var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
292 // Test vertex shaders
293 for (var ii = 0; ii < tests.length; ++ii) {
294 var type = testTypes[ii];
295 if (params.simpleEmu) {
296 type = {
297 type: type.type,
298 code: params.simpleEmu
299 };
300 }
301 debug("");
302 var str = replaceParams(params.testFunc, {
303 func: params.feature,
304 type: type.type,
305 arg0: type.type
306 });
307 debug("Testing: " + str + " in " + shaderInfo.type + " shader");
308
309 var referenceVertexShaderSource = generateReferenceShader(
310 shaderInfo,
311 shaderInfo.vertexShaderTemplate,
312 params,
313 type,
314 tests[ii]);
315 var referenceFragmentShaderSource = generateReferenceShader(
316 shaderInfo,
317 shaderInfo.fragmentShaderTemplate,
318 params,
319 type,
320 tests[ii]);
321 var testVertexShaderSource = generateTestShader(
322 shaderInfo,
323 shaderInfo.vertexShaderTemplate,
324 params,
325 tests[ii]);
326 var testFragmentShaderSource = generateTestShader(
327 shaderInfo,
328 shaderInfo.fragmentShaderTemplate,
329 params,
330 tests[ii]);
331
332 debug("");
333 wtu.addShaderSource(
334 console, "reference vertex shader", referenceVertexShaderSource);
335 wtu.addShaderSource(
336 console, "reference fragment shader", referenceFragmentShaderSource);
337 wtu.addShaderSource(
338 console, "test vertex shader", testVertexShaderSource);
339 wtu.addShaderSource(
340 console, "test fragment shader", testFragmentShaderSource);
341 debug("");
342
343 var refData = draw(
344 canvas, referenceVertexShaderSource, referenceFragmentShaderSource);
345 var refImg = wtu.makeImage(canvas);
346 if (ss == 0) {
347 var testData = draw(
348 canvas, testVertexShaderSource, referenceFragmentShaderSource);
349 } else {
350 var testData = draw(
351 canvas, referenceVertexShaderSource, testFragmentShaderSource);
352 }
353 var testImg = wtu.makeImage(canvas);
354
355 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance);
356 }
357 }
358
359 finishTest();
360
361 function reportResults(refData, refImage, testData, testImage, tolerance) {
362 var same = true;
363 for (var yy = 0; yy < height; ++yy) {
364 for (var xx = 0; xx < width; ++xx) {
365 var offset = (yy * width + xx) * 4;
366 var imgOffset = ((height - yy - 1) * width + xx) * 4;
367 imgData.data[imgOffset + 0] = 0;
368 imgData.data[imgOffset + 1] = 0;
369 imgData.data[imgOffset + 2] = 0;
370 imgData.data[imgOffset + 3] = 255;
371 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
372 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
373 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
374 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
375 imgData.data[imgOffset] = 255;
376 same = false;
377 }
378 }
379 }
380
381 var diffImg = null;
382 if (!same) {
383 ctx.putImageData(imgData, 0, 0);
384 diffImg = wtu.makeImage(canvas2d);
385 }
386
387 var div = document.createElement("div");
388 div.className = "testimages";
389 wtu.insertImage(div, "ref", refImg);
390 wtu.insertImage(div, "test", testImg);
391 if (diffImg) {
392 wtu.insertImage(div, "diff", diffImg);
393 }
394 div.appendChild(document.createElement('br'));
395
396
397 console.appendChild(div);
398
399 if (!same) {
400 testFailed("images are different");
401 } else {
402 testPassed("images are the same");
403 }
404
405 console.appendChild(document.createElement('hr'));
406 }
407
408 function draw(canvas, vsSource, fsSource) {
409 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
410
411 var posLoc = gl.getAttribLocation(program, "aPosition");
412 WebGLTestUtils.setupQuad(gl, gridRes, posLoc);
413
414 gl.useProgram(program);
415 gl.clearColor(0, 0, 1, 1);
416 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
417 gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0);
418 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
419
420 var img = new Uint8Array(width * height * 4);
421 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
422 return img;
423 }
424
425 };
426
427 var runBasicTest = function(params) {
428 if (window.initNonKhronosFramework) {
429 window.initNonKhronosFramework(false);
430 }
431
432 var wtu = WebGLTestUtils;
433 var gridRes = params.gridRes;
434 var vertexTolerance = params.tolerance || 0;
435 var fragmentTolerance = vertexTolerance;
436 if ('fragmentTolerance' in params)
437 fragmentTolerance = params.fragmentTolerance || 0;
438
439 description("Testing : " + document.getElementsByTagName("title")[0].innerText );
440
441 var width = 32;
442 var height = 32;
443
444 var console = document.getElementById("console");
445 var canvas = document.createElement('canvas');
446 canvas.width = width;
447 canvas.height = height;
448 var gl = wtu.create3DContext(canvas);
449 if (!gl) {
450 testFailed("context does not exist");
451 finishTest();
452 return;
453 }
454
455 var canvas2d = document.createElement('canvas');
456 canvas2d.width = width;
457 canvas2d.height = height;
458 var ctx = canvas2d.getContext("2d");
459 var imgData = ctx.getImageData(0, 0, width, height);
460
461 var shaderInfos = [
462 { type: "vertex",
463 input: "color",
464 output: "vColor",
465 vertexShaderTemplate: vertexShaderTemplate,
466 fragmentShaderTemplate: baseFragmentShader,
467 tolerance: vertexTolerance
468 },
469 { type: "fragment",
470 input: "vColor",
471 output: "gl_FragColor",
472 vertexShaderTemplate: baseVertexShader,
473 fragmentShaderTemplate: fragmentShaderTemplate,
474 tolerance: fragmentTolerance
475 }
476 ];
477 for (var ss = 0; ss < shaderInfos.length; ++ss) {
478 var shaderInfo = shaderInfos[ss];
479 var tests = params.tests;
480 // var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
481 // Test vertex shaders
482 for (var ii = 0; ii < tests.length; ++ii) {
483 var test = tests[ii];
484 debug("");
485 debug("Testing: " + test.name + " in " + shaderInfo.type + " shader");
486
487 function genShader(shaderInfo, template, shader, subs) {
488 shader = replaceParams(shader, subs, {
489 input: shaderInfo.input,
490 output: shaderInfo.output
491 });
492 shader = replaceParams(template, subs, {
493 test: shader,
494 emu: "",
495 extra: ""
496 });
497 return shader;
498 }
499
500 var referenceVertexShaderSource = genShader(
501 shaderInfo,
502 shaderInfo.vertexShaderTemplate,
503 test.reference.shader,
504 test.reference.subs);
505 var referenceFragmentShaderSource = genShader(
506 shaderInfo,
507 shaderInfo.fragmentShaderTemplate,
508 test.reference.shader,
509 test.reference.subs);
510 var testVertexShaderSource = genShader(
511 shaderInfo,
512 shaderInfo.vertexShaderTemplate,
513 test.test.shader,
514 test.test.subs);
515 var testFragmentShaderSource = genShader(
516 shaderInfo,
517 shaderInfo.fragmentShaderTemplate,
518 test.test.shader,
519 test.test.subs);
520
521 debug("");
522 wtu.addShaderSource(
523 console, "reference vertex shader", referenceVertexShaderSource);
524 wtu.addShaderSource(
525 console, "reference fragment shader", referenceFragmentShaderSource);
526 wtu.addShaderSource(
527 console, "test vertex shader", testVertexShaderSource);
528 wtu.addShaderSource(
529 console, "test fragment shader", testFragmentShaderSource);
530 debug("");
531
532 var refData = draw(
533 canvas, referenceVertexShaderSource, referenceFragmentShaderSource);
534 var refImg = wtu.makeImage(canvas);
535 if (ss == 0) {
536 var testData = draw(
537 canvas, testVertexShaderSource, referenceFragmentShaderSource);
538 } else {
539 var testData = draw(
540 canvas, referenceVertexShaderSource, testFragmentShaderSource);
541 }
542 var testImg = wtu.makeImage(canvas);
543
544 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance);
545 }
546 }
547
548 finishTest();
549
550 function reportResults(refData, refImage, testData, testImage, tolerance) {
551 var same = true;
552 for (var yy = 0; yy < height; ++yy) {
553 for (var xx = 0; xx < width; ++xx) {
554 var offset = (yy * width + xx) * 4;
555 var imgOffset = ((height - yy - 1) * width + xx) * 4;
556 imgData.data[imgOffset + 0] = 0;
557 imgData.data[imgOffset + 1] = 0;
558 imgData.data[imgOffset + 2] = 0;
559 imgData.data[imgOffset + 3] = 255;
560 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
561 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
562 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
563 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
564 imgData.data[imgOffset] = 255;
565 same = false;
566 }
567 }
568 }
569
570 var diffImg = null;
571 if (!same) {
572 ctx.putImageData(imgData, 0, 0);
573 diffImg = wtu.makeImage(canvas2d);
574 }
575
576 var div = document.createElement("div");
577 div.className = "testimages";
578 wtu.insertImage(div, "ref", refImg);
579 wtu.insertImage(div, "test", testImg);
580 if (diffImg) {
581 wtu.insertImage(div, "diff", diffImg);
582 }
583 div.appendChild(document.createElement('br'));
584
585 console.appendChild(div);
586
587 if (!same) {
588 testFailed("images are different");
589 } else {
590 testPassed("images are the same");
591 }
592
593 console.appendChild(document.createElement('hr'));
594 }
595
596 function draw(canvas, vsSource, fsSource) {
597 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
598
599 var posLoc = gl.getAttribLocation(program, "aPosition");
600 WebGLTestUtils.setupQuad(gl, gridRes, posLoc);
601
602 gl.useProgram(program);
603 gl.clearColor(0, 0, 1, 1);
604 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
605 gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0);
606 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
607
608 var img = new Uint8Array(width * height * 4);
609 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
610 return img;
611 }
612
613 };
614
615 var runReferenceImageTest = function(params) {
616 if (window.initNonKhronosFramework) {
617 window.initNonKhronosFramework(false);
618 }
619
620 var wtu = WebGLTestUtils;
621 var gridRes = params.gridRes;
622 var vertexTolerance = params.tolerance || 0;
623 var fragmentTolerance = vertexTolerance;
624 if ('fragmentTolerance' in params)
625 fragmentTolerance = params.fragmentTolerance || 0;
626
627 description("Testing GLSL feature: " + params.feature);
628
629 var width = 32;
630 var height = 32;
631
632 var console = document.getElementById("console");
633 var canvas = document.createElement('canvas');
634 canvas.width = width;
635 canvas.height = height;
636 var gl = wtu.create3DContext(canvas, { antialias: false });
637 if (!gl) {
638 testFailed("context does not exist");
639 finishTest();
640 return;
641 }
642
643 var canvas2d = document.createElement('canvas');
644 canvas2d.width = width;
645 canvas2d.height = height;
646 var ctx = canvas2d.getContext("2d");
647 var imgData = ctx.getImageData(0, 0, width, height);
648
649 var shaderInfos = [
650 { type: "vertex",
651 input: "color",
652 output: "vColor",
653 vertexShaderTemplate: vertexShaderTemplate,
654 fragmentShaderTemplate: baseFragmentShader,
655 tolerance: vertexTolerance
656 },
657 { type: "fragment",
658 input: "vColor",
659 output: "gl_FragColor",
660 vertexShaderTemplate: baseVertexShader,
661 fragmentShaderTemplate: fragmentShaderTemplate,
662 tolerance: fragmentTolerance
663 }
664 ];
665 for (var ss = 0; ss < shaderInfos.length; ++ss) {
666 var shaderInfo = shaderInfos[ss];
667 var tests = params.tests;
668 var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
669 // Test vertex shaders
670 for (var ii = 0; ii < tests.length; ++ii) {
671 var type = testTypes[ii];
672 var isVertex = (ss == 0);
673 debug("");
674 var str = replaceParams(params.testFunc, {
675 func: params.feature,
676 type: type.type,
677 arg0: type.type
678 });
679 debug("Testing: " + str + " in " + shaderInfo.type + " shader");
680
681 var referenceVertexShaderSource = generateReferenceShader(
682 shaderInfo,
683 shaderInfo.vertexShaderTemplate,
684 params,
685 type,
686 tests[ii].source);
687 var referenceFragmentShaderSource = generateReferenceShader(
688 shaderInfo,
689 shaderInfo.fragmentShaderTemplate,
690 params,
691 type,
692 tests[ii].source);
693 var testVertexShaderSource = generateTestShader(
694 shaderInfo,
695 shaderInfo.vertexShaderTemplate,
696 params,
697 tests[ii].source);
698 var testFragmentShaderSource = generateTestShader(
699 shaderInfo,
700 shaderInfo.fragmentShaderTemplate,
701 params,
702 tests[ii].source);
703 var referenceTexture = generateReferenceTexture(
704 gl,
705 tests[ii].generator,
706 isVertex ? gridRes : width,
707 isVertex ? gridRes : height,
708 isVertex);
709
710 debug("");
711 wtu.addShaderSource(
712 console, "test vertex shader", testVertexShaderSource);
713 wtu.addShaderSource(
714 console, "test fragment shader", testFragmentShaderSource);
715 debug("");
716 var refData = drawReferenceImage(canvas, referenceTexture, isVertex);
717 var refImg = wtu.makeImage(canvas);
718 if (isVertex) {
719 var testData = draw(
720 canvas, testVertexShaderSource, referenceFragmentShaderSource);
721 } else {
722 var testData = draw(
723 canvas, referenceVertexShaderSource, testFragmentShaderSource);
724 }
725 var testImg = wtu.makeImage(canvas);
726 var testTolerance = shaderInfo.tolerance;
727 // Provide per-test tolerance so that we can increase it only for those de sired.
728 if ('tolerance' in tests[ii])
729 testTolerance = tests[ii].tolerance || 0;
730 reportResults(refData, refImg, testData, testImg, testTolerance);
731 }
732 }
733
734 finishTest();
735
736 function reportResults(refData, refImage, testData, testImage, tolerance) {
737 var same = true;
738 for (var yy = 0; yy < height; ++yy) {
739 for (var xx = 0; xx < width; ++xx) {
740 var offset = (yy * width + xx) * 4;
741 var imgOffset = ((height - yy - 1) * width + xx) * 4;
742 imgData.data[imgOffset + 0] = 0;
743 imgData.data[imgOffset + 1] = 0;
744 imgData.data[imgOffset + 2] = 0;
745 imgData.data[imgOffset + 3] = 255;
746 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
747 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
748 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
749 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
750 console.appendChild(document.createTextNode('at (' + xx + ',' + yy + ' ): ref=(' +
751 refData[offset + 0] + ',' +
752 refData[offset + 1] + ',' +
753 refData[offset + 2] + ',' +
754 refData[offset + 3] + ') test=(' +
755 testData[offset + 0] + ',' +
756 testData[offset + 1] + ',' +
757 testData[offset + 2] + ',' +
758 testData[offset + 3] + ')' ));
759 console.appendChild(document.createElement('br'));
760
761
762
763 imgData.data[imgOffset] = 255;
764 same = false;
765 }
766 }
767 }
768
769 var diffImg = null;
770 if (!same) {
771 ctx.putImageData(imgData, 0, 0);
772 diffImg = wtu.makeImage(canvas2d);
773 }
774
775 var div = document.createElement("div");
776 div.className = "testimages";
777 wtu.insertImage(div, "ref", refImg);
778 wtu.insertImage(div, "test", testImg);
779 if (diffImg) {
780 wtu.insertImage(div, "diff", diffImg);
781 }
782 div.appendChild(document.createElement('br'));
783
784 console.appendChild(div);
785
786 if (!same) {
787 testFailed("images are different");
788 } else {
789 testPassed("images are the same");
790 }
791
792 console.appendChild(document.createElement('hr'));
793 }
794
795 function draw(canvas, vsSource, fsSource) {
796 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed);
797
798 var posLoc = gl.getAttribLocation(program, "aPosition");
799 WebGLTestUtils.setupQuad(gl, gridRes, posLoc);
800
801 gl.useProgram(program);
802 gl.clearColor(0, 0, 1, 1);
803 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
804 gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0);
805 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
806
807 var img = new Uint8Array(width * height * 4);
808 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
809 return img;
810 }
811
812 function drawReferenceImage(canvas, texture, isVertex) {
813 var program;
814 if (isVertex) {
815 var halfTexel = 0.5 / (1.0 + gridRes);
816 program = WebGLTestUtils.setupTexturedQuadWithTexCoords(
817 gl, [halfTexel, halfTexel], [1.0 - halfTexel, 1.0 - halfTexel]);
818 } else {
819 program = WebGLTestUtils.setupTexturedQuad(gl);
820 }
821
822 gl.activeTexture(gl.TEXTURE0);
823 gl.bindTexture(gl.TEXTURE_2D, texture);
824 var texLoc = gl.getUniformLocation(program, "tex");
825 gl.uniform1i(texLoc, 0);
826 wtu.drawQuad(gl);
827 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
828
829 var img = new Uint8Array(width * height * 4);
830 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
831 return img;
832 }
833
834 /**
835 * Creates and returns a texture containing the reference image for
836 * the function being tested. Exactly how the function is evaluated,
837 * and the size of the returned texture, depends on whether we are
838 * testing a vertex or fragment shader. If a fragment shader, the
839 * function is evaluated at the pixel centers. If a vertex shader,
840 * the function is evaluated at the triangle's vertices, and the
841 * resulting texture must be offset by half a texel during
842 * rendering.
843 *
844 * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use to gene rate texture objects.
845 * @param {!function(number,number,number,number): !Array.<number>} generator The reference image generator function.
846 * @param {number} width The width of the texture to generate if testing a fra gment shader; the grid resolution if testing a vertex shader.
847 * @param {number} height The height of the texture to generate if testing a f ragment shader; the grid resolution if testing a vertex shader.
848 * @param {boolean} isVertex True if generating a reference image for a vertex shader; false if for a fragment shader.
849 * @return {!WebGLTexture} The texture object that was generated.
850 */
851 function generateReferenceTexture(
852 gl,
853 generator,
854 width,
855 height,
856 isVertex) {
857
858 // Note: the math in this function must match that in the vertex and
859 // fragment shader templates above.
860 function computeTexCoord(x) {
861 return x * 0.5 + 0.5;
862 }
863
864 function computeColor(texCoordX, texCoordY) {
865 return [ texCoordX,
866 texCoordY,
867 texCoordX * texCoordY,
868 (1.0 - texCoordX) * texCoordY * 0.5 + 0.5 ];
869 }
870
871 function clamp(value, minVal, maxVal) {
872 return Math.max(minVal, Math.min(value, maxVal));
873 }
874
875 // Evaluates the function at clip coordinates (px,py), storing the
876 // result in the array "pixel". Each channel's result is clamped
877 // between 0 and 255.
878 function evaluateAtClipCoords(px, py, pixel) {
879 var tcx = computeTexCoord(px);
880 var tcy = computeTexCoord(py);
881
882 var color = computeColor(tcx, tcy);
883
884 var output = generator(color[0], color[1], color[2], color[3]);
885
886 // Multiply by 256 to get even distribution for all values between 0 and 1 .
887 // Use rounding rather than truncation to more closely match the GPU's beh avior.
888 pixel[0] = clamp(Math.round(256 * output[0]), 0, 255);
889 pixel[1] = clamp(Math.round(256 * output[1]), 0, 255);
890 pixel[2] = clamp(Math.round(256 * output[2]), 0, 255);
891 pixel[3] = clamp(Math.round(256 * output[3]), 0, 255);
892 }
893
894 function fillFragmentReference() {
895 var data = new Uint8Array(4 * width * height);
896
897 var horizTexel = 1.0 / width;
898 var vertTexel = 1.0 / height;
899 var halfHorizTexel = 0.5 * horizTexel;
900 var halfVertTexel = 0.5 * vertTexel;
901
902 var pixel = new Array(4);
903
904 for (var yi = 0; yi < height; ++yi) {
905 for (var xi = 0; xi < width; ++xi) {
906 // The function must be evaluated at pixel centers.
907
908 // Compute desired position in clip space
909 var px = -1.0 + 2.0 * (halfHorizTexel + xi * horizTexel);
910 var py = -1.0 + 2.0 * (halfVertTexel + yi * vertTexel);
911
912 evaluateAtClipCoords(px, py, pixel);
913 var index = 4 * (width * yi + xi);
914 data[index + 0] = pixel[0];
915 data[index + 1] = pixel[1];
916 data[index + 2] = pixel[2];
917 data[index + 3] = pixel[3];
918 }
919 }
920
921 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0,
922 gl.RGBA, gl.UNSIGNED_BYTE, data);
923 }
924
925 function fillVertexReference() {
926 // We generate a texture which contains the evaluation of the
927 // function at the vertices of the triangle mesh. It is expected
928 // that the width and the height are identical, and equivalent
929 // to the grid resolution.
930 if (width != height) {
931 throw "width and height must be equal";
932 }
933
934 var texSize = 1 + width;
935 var data = new Uint8Array(4 * texSize * texSize);
936
937 var step = 2.0 / width;
938
939 var pixel = new Array(4);
940
941 for (var yi = 0; yi < texSize; ++yi) {
942 for (var xi = 0; xi < texSize; ++xi) {
943 // The function is evaluated at the triangles' vertices.
944
945 // Compute desired position in clip space
946 var px = -1.0 + (xi * step);
947 var py = -1.0 + (yi * step);
948
949 evaluateAtClipCoords(px, py, pixel);
950 var index = 4 * (texSize * yi + xi);
951 data[index + 0] = pixel[0];
952 data[index + 1] = pixel[1];
953 data[index + 2] = pixel[2];
954 data[index + 3] = pixel[3];
955 }
956 }
957
958 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0,
959 gl.RGBA, gl.UNSIGNED_BYTE, data);
960 }
961
962 //----------------------------------------------------------------------
963 // Body of generateReferenceTexture
964 //
965
966 var texture = gl.createTexture();
967 gl.bindTexture(gl.TEXTURE_2D, texture);
968 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
969 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
970 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
971 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
972
973 if (isVertex) {
974 fillVertexReference();
975 } else {
976 fillFragmentReference();
977 }
978
979 return texture;
980 }
981 };
982
983 return {
984 /**
985 * runs a bunch of GLSL tests using the passed in parameters
986 * The parameters are:
987 *
988 * feature:
989 * the name of the function being tested (eg, sin, dot,
990 * normalize)
991 *
992 * testFunc:
993 * The prototype of function to be tested not including the
994 * return type.
995 *
996 * emuFunc:
997 * A base function that can be used to generate emulation
998 * functions. Example for 'ceil'
999 *
1000 * float $(func)_base(float value) {
1001 * float m = mod(value, 1.0);
1002 * return m != 0.0 ? (value + 1.0 - m) : value;
1003 * }
1004 *
1005 * args:
1006 * The arguments to the function
1007 *
1008 * baseArgs: (optional)
1009 * The arguments when a base function is used to create an
1010 * emulation function. For example 'float sign_base(float v)'
1011 * is used to implemenent vec2 sign_emu(vec2 v).
1012 *
1013 * simpleEmu:
1014 * if supplied, the code that can be used to generate all
1015 * functions for all types.
1016 *
1017 * Example for 'normalize':
1018 *
1019 * $(type) $(func)_emu($(args)) {
1020 * return value / length(value);
1021 * }
1022 *
1023 * gridRes: (optional)
1024 * The resolution of the mesh to generate. The default is a
1025 * 1x1 grid but many vertex shaders need a higher resolution
1026 * otherwise the only values passed in are the 4 corners
1027 * which often have the same value.
1028 *
1029 * tests:
1030 * The code for each test. It is assumed the tests are for
1031 * float, vec2, vec3, vec4 in that order.
1032 *
1033 * tolerance: (optional)
1034 * Allow some tolerance in the comparisons. The tolerance is applied to
1035 * both vertex and fragment shaders. The default tolerance is 0, meaning
1036 * the values have to be identical.
1037 *
1038 * fragmentTolerance: (optional)
1039 * Specify a tolerance which only applies to fragment shaders. The
1040 * fragment-only tolerance will override the shared tolerance for
1041 * fragment shaders if both are specified. Fragment shaders usually
1042 * use mediump float precision so they sometimes require higher tolerance
1043 * than vertex shaders which use highp by default.
1044 */
1045 runFeatureTest: runFeatureTest,
1046
1047 /*
1048 * Runs a bunch of GLSL tests using the passed in parameters
1049 *
1050 * The parameters are:
1051 *
1052 * tests:
1053 * Array of tests. For each test the following parameters are expected
1054 *
1055 * name:
1056 * some description of the test
1057 * reference:
1058 * parameters for the reference shader (see below)
1059 * test:
1060 * parameters for the test shader (see below)
1061 *
1062 * The parameter for the reference and test shaders are
1063 *
1064 * shader: the GLSL for the shader
1065 * subs: any substitutions you wish to define for the shader.
1066 *
1067 * Each shader is created from a basic template that
1068 * defines an input and an output. You can see the
1069 * templates at the top of this file. The input and output
1070 * change depending on whether or not we are generating
1071 * a vertex or fragment shader.
1072 *
1073 * All this code function does is a bunch of string substitutions.
1074 * A substitution is defined by $(name). If name is found in
1075 * the 'subs' parameter it is replaced. 4 special names exist.
1076 *
1077 * 'input' the input to your GLSL. Always a vec4. All change
1078 * from 0 to 1 over the quad to be drawn.
1079 *
1080 * 'output' the output color. Also a vec4
1081 *
1082 * 'emu' a place to insert extra stuff
1083 * 'extra' a place to insert extra stuff.
1084 *
1085 * You can think of the templates like this
1086 *
1087 * $(extra)
1088 * $(emu)
1089 *
1090 * void main() {
1091 * // do math to calculate input
1092 * ...
1093 *
1094 * $(shader)
1095 * }
1096 *
1097 * Your shader first has any subs you provided applied as well
1098 * as 'input' and 'output'
1099 *
1100 * It is then inserted into the template which is also provided
1101 * with your subs.
1102 *
1103 * gridRes: (optional)
1104 * The resolution of the mesh to generate. The default is a
1105 * 1x1 grid but many vertex shaders need a higher resolution
1106 * otherwise the only values passed in are the 4 corners
1107 * which often have the same value.
1108 *
1109 * tolerance: (optional)
1110 * Allow some tolerance in the comparisons. The tolerance is applied to
1111 * both vertex and fragment shaders. The default tolerance is 0, meaning
1112 * the values have to be identical.
1113 *
1114 * fragmentTolerance: (optional)
1115 * Specify a tolerance which only applies to fragment shaders. The
1116 * fragment-only tolerance will override the shared tolerance for
1117 * fragment shaders if both are specified. Fragment shaders usually
1118 * use mediump float precision so they sometimes require higher tolerance
1119 * than vertex shaders which use highp.
1120 */
1121 runBasicTest: runBasicTest,
1122
1123 /**
1124 * Runs a bunch of GLSL tests using the passed in parameters. The
1125 * expected results are computed as a reference image in JavaScript
1126 * instead of on the GPU. The parameters are:
1127 *
1128 * feature:
1129 * the name of the function being tested (eg, sin, dot,
1130 * normalize)
1131 *
1132 * testFunc:
1133 * The prototype of function to be tested not including the
1134 * return type.
1135 *
1136 * args:
1137 * The arguments to the function
1138 *
1139 * gridRes: (optional)
1140 * The resolution of the mesh to generate. The default is a
1141 * 1x1 grid but many vertex shaders need a higher resolution
1142 * otherwise the only values passed in are the 4 corners
1143 * which often have the same value.
1144 *
1145 * tests:
1146 * Array of tests. It is assumed the tests are for float, vec2,
1147 * vec3, vec4 in that order. For each test the following
1148 * parameters are expected:
1149 *
1150 * source: the GLSL source code for the tests
1151 *
1152 * generator: a JavaScript function taking four parameters
1153 * which evaluates the same function as the GLSL source,
1154 * returning its result as a newly allocated array.
1155 *
1156 * tolerance: (optional) a per-test tolerance.
1157 *
1158 * extra: (optional)
1159 * Extra GLSL code inserted at the top of each test's shader.
1160 *
1161 * tolerance: (optional)
1162 * Allow some tolerance in the comparisons. The tolerance is applied to
1163 * both vertex and fragment shaders. The default tolerance is 0, meaning
1164 * the values have to be identical.
1165 *
1166 * fragmentTolerance: (optional)
1167 * Specify a tolerance which only applies to fragment shaders. The
1168 * fragment-only tolerance will override the shared tolerance for
1169 * fragment shaders if both are specified. Fragment shaders usually
1170 * use mediump float precision so they sometimes require higher tolerance
1171 * than vertex shaders which use highp.
1172 */
1173 runReferenceImageTest: runReferenceImageTest,
1174
1175 none: false
1176 };
1177
1178 }());
1179
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698