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