OLD | NEW |
(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 |
OLD | NEW |