OLD | NEW |
(Empty) | |
| 1 GLSLGenerator = (function() { |
| 2 |
| 3 var vertexShaderTemplate = [ |
| 4 "attribute vec4 aPosition;", |
| 5 "", |
| 6 "varying vec4 vColor;", |
| 7 "", |
| 8 "$(extra)", |
| 9 "$(emu)", |
| 10 "", |
| 11 "void main()", |
| 12 "{", |
| 13 " gl_Position = aPosition;", |
| 14 " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));", |
| 15 " vec4 color = vec4(", |
| 16 " texcoord,", |
| 17 " texcoord.x * texcoord.y,", |
| 18 " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);", |
| 19 " $(test)", |
| 20 "}" |
| 21 ].join("\n"); |
| 22 |
| 23 var fragmentShaderTemplate = [ |
| 24 "#if defined(GL_ES)", |
| 25 "precision mediump float;", |
| 26 "#endif", |
| 27 "", |
| 28 "varying vec4 vColor;", |
| 29 "", |
| 30 "$(extra)", |
| 31 "$(emu)", |
| 32 "", |
| 33 "void main()", |
| 34 "{", |
| 35 " $(test)", |
| 36 "}" |
| 37 ].join("\n"); |
| 38 |
| 39 var baseVertexShader = [ |
| 40 "attribute vec4 aPosition;", |
| 41 "", |
| 42 "varying vec4 vColor;", |
| 43 "", |
| 44 "void main()", |
| 45 "{", |
| 46 " gl_Position = aPosition;", |
| 47 " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));", |
| 48 " vColor = vec4(", |
| 49 " texcoord,", |
| 50 " texcoord.x * texcoord.y,", |
| 51 " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);", |
| 52 "}" |
| 53 ].join("\n"); |
| 54 |
| 55 var baseFragmentShader = [ |
| 56 "#if defined(GL_ES)", |
| 57 "precision mediump float;", |
| 58 "#endif", |
| 59 "varying vec4 vColor;", |
| 60 "", |
| 61 "void main()", |
| 62 "{", |
| 63 " gl_FragColor = vColor;", |
| 64 "}" |
| 65 ].join("\n"); |
| 66 |
| 67 var types = [ |
| 68 { type: "float", |
| 69 code: [ |
| 70 "float $(func)_emu($(args)) {", |
| 71 " return $(func)_base($(baseArgs));", |
| 72 "}"].join("\n") |
| 73 }, |
| 74 { type: "vec2", |
| 75 code: [ |
| 76 "vec2 $(func)_emu($(args)) {", |
| 77 " return vec2(", |
| 78 " $(func)_base($(baseArgsX)),", |
| 79 " $(func)_base($(baseArgsY)));", |
| 80 "}"].join("\n") |
| 81 }, |
| 82 { type: "vec3", |
| 83 code: [ |
| 84 "vec3 $(func)_emu($(args)) {", |
| 85 " return vec3(", |
| 86 " $(func)_base($(baseArgsX)),", |
| 87 " $(func)_base($(baseArgsY)),", |
| 88 " $(func)_base($(baseArgsZ)));", |
| 89 "}"].join("\n") |
| 90 }, |
| 91 { type: "vec4", |
| 92 code: [ |
| 93 "vec4 $(func)_emu($(args)) {", |
| 94 " return vec4(", |
| 95 " $(func)_base($(baseArgsX)),", |
| 96 " $(func)_base($(baseArgsY)),", |
| 97 " $(func)_base($(baseArgsZ)),", |
| 98 " $(func)_base($(baseArgsW)));", |
| 99 "}"].join("\n") |
| 100 } |
| 101 ]; |
| 102 |
| 103 var bvecTypes = [ |
| 104 { type: "bvec2", |
| 105 code: [ |
| 106 "bvec2 $(func)_emu($(args)) {", |
| 107 " return bvec2(", |
| 108 " $(func)_base($(baseArgsX)),", |
| 109 " $(func)_base($(baseArgsY)));", |
| 110 "}"].join("\n") |
| 111 }, |
| 112 { type: "bvec3", |
| 113 code: [ |
| 114 "bvec3 $(func)_emu($(args)) {", |
| 115 " return bvec3(", |
| 116 " $(func)_base($(baseArgsX)),", |
| 117 " $(func)_base($(baseArgsY)),", |
| 118 " $(func)_base($(baseArgsZ)));", |
| 119 "}"].join("\n") |
| 120 }, |
| 121 { type: "bvec4", |
| 122 code: [ |
| 123 "vec4 $(func)_emu($(args)) {", |
| 124 " return bvec4(", |
| 125 " $(func)_base($(baseArgsX)),", |
| 126 " $(func)_base($(baseArgsY)),", |
| 127 " $(func)_base($(baseArgsZ)),", |
| 128 " $(func)_base($(baseArgsW)));", |
| 129 "}"].join("\n") |
| 130 } |
| 131 ]; |
| 132 |
| 133 var replaceRE = /\$\((\w+)\)/g; |
| 134 |
| 135 var replaceParams = function(str) { |
| 136 var args = arguments; |
| 137 return str.replace(replaceRE, function(str, p1, offset, s) { |
| 138 for (var ii = 1; ii < args.length; ++ii) { |
| 139 if (args[ii][p1] !== undefined) { |
| 140 return args[ii][p1]; |
| 141 } |
| 142 } |
| 143 throw "unknown string param '" + p1 + "'"; |
| 144 }); |
| 145 }; |
| 146 |
| 147 var generateReferenceShader = function( |
| 148 shaderInfo, template, params, typeInfo, test) { |
| 149 var input = shaderInfo.input; |
| 150 var output = shaderInfo.output; |
| 151 var feature = params.feature; |
| 152 var testFunc = params.testFunc; |
| 153 var emuFunc = params.emuFunc || ""; |
| 154 var extra = params.extra || ''; |
| 155 var args = params.args || "$(type) value"; |
| 156 var type = typeInfo.type; |
| 157 var typeCode = typeInfo.code; |
| 158 |
| 159 var baseArgs = params.baseArgs || "value$(field)"; |
| 160 var baseArgsX = replaceParams(baseArgs, {field: ".x"}); |
| 161 var baseArgsY = replaceParams(baseArgs, {field: ".y"}); |
| 162 var baseArgsZ = replaceParams(baseArgs, {field: ".z"}); |
| 163 var baseArgsW = replaceParams(baseArgs, {field: ".w"}); |
| 164 var baseArgs = replaceParams(baseArgs, {field: ""}); |
| 165 |
| 166 test = replaceParams(test, { |
| 167 input: input, |
| 168 output: output, |
| 169 func: feature + "_emu" |
| 170 }); |
| 171 emuFunc = replaceParams(emuFunc, { |
| 172 func: feature |
| 173 }); |
| 174 args = replaceParams(args, { |
| 175 type: type |
| 176 }); |
| 177 typeCode = replaceParams(typeCode, { |
| 178 func: feature, |
| 179 type: type, |
| 180 args: args, |
| 181 baseArgs: baseArgs, |
| 182 baseArgsX: baseArgsX, |
| 183 baseArgsY: baseArgsY, |
| 184 baseArgsZ: baseArgsZ, |
| 185 baseArgsW: baseArgsW |
| 186 }); |
| 187 var shader = replaceParams(template, { |
| 188 extra: extra, |
| 189 emu: emuFunc + "\n\n" + typeCode, |
| 190 test: test |
| 191 }); |
| 192 return shader; |
| 193 }; |
| 194 |
| 195 var generateTestShader = function( |
| 196 shaderInfo, template, params, test) { |
| 197 var input = shaderInfo.input; |
| 198 var output = shaderInfo.output; |
| 199 var feature = params.feature; |
| 200 var testFunc = params.testFunc; |
| 201 var extra = params.extra || ''; |
| 202 |
| 203 test = replaceParams(test, { |
| 204 input: input, |
| 205 output: output, |
| 206 func: feature |
| 207 }); |
| 208 var shader = replaceParams(template, { |
| 209 extra: extra, |
| 210 emu: '', |
| 211 test: test |
| 212 }); |
| 213 return shader; |
| 214 }; |
| 215 |
| 216 var makeImage = function(canvas) { |
| 217 var img = document.createElement('img'); |
| 218 img.src = canvas.toDataURL(); |
| 219 return img; |
| 220 }; |
| 221 |
| 222 var runFeatureTest = function(params) { |
| 223 if (window.initNonKhronosFramework) { |
| 224 window.initNonKhronosFramework(false); |
| 225 } |
| 226 |
| 227 var wtu = WebGLTestUtils; |
| 228 var gridRes = params.gridRes; |
| 229 var vertexTolerance = params.tolerance || 0; |
| 230 var fragmentTolerance = vertexTolerance; |
| 231 if ('fragmentTolerance' in params) |
| 232 fragmentTolerance = params.fragmentTolerance || 0; |
| 233 |
| 234 description("Testing GLSL feature: " + params.feature); |
| 235 |
| 236 var width = 32; |
| 237 var height = 32; |
| 238 |
| 239 var console = document.getElementById("console"); |
| 240 var canvas = document.createElement('canvas'); |
| 241 canvas.width = width; |
| 242 canvas.height = height; |
| 243 var gl = wtu.create3DContext(canvas); |
| 244 if (!gl) { |
| 245 testFailed("context does not exist"); |
| 246 finishTest(); |
| 247 return; |
| 248 } |
| 249 |
| 250 var canvas2d = document.createElement('canvas'); |
| 251 canvas2d.width = width; |
| 252 canvas2d.height = height; |
| 253 var ctx = canvas2d.getContext("2d"); |
| 254 var imgData = ctx.getImageData(0, 0, width, height); |
| 255 |
| 256 var shaderInfos = [ |
| 257 { type: "vertex", |
| 258 input: "color", |
| 259 output: "vColor", |
| 260 vertexShaderTemplate: vertexShaderTemplate, |
| 261 fragmentShaderTemplate: baseFragmentShader, |
| 262 tolerance: vertexTolerance |
| 263 }, |
| 264 { type: "fragment", |
| 265 input: "vColor", |
| 266 output: "gl_FragColor", |
| 267 vertexShaderTemplate: baseVertexShader, |
| 268 fragmentShaderTemplate: fragmentShaderTemplate, |
| 269 tolerance: fragmentTolerance |
| 270 } |
| 271 ]; |
| 272 for (var ss = 0; ss < shaderInfos.length; ++ss) { |
| 273 var shaderInfo = shaderInfos[ss]; |
| 274 var tests = params.tests; |
| 275 var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types); |
| 276 // Test vertex shaders |
| 277 for (var ii = 0; ii < tests.length; ++ii) { |
| 278 var type = testTypes[ii]; |
| 279 if (params.simpleEmu) { |
| 280 type = { |
| 281 type: type.type, |
| 282 code: params.simpleEmu |
| 283 }; |
| 284 } |
| 285 debug(""); |
| 286 var str = replaceParams(params.testFunc, { |
| 287 func: params.feature, |
| 288 type: type.type, |
| 289 arg0: type.type |
| 290 }); |
| 291 debug("Testing: " + str + " in " + shaderInfo.type + " shader"); |
| 292 |
| 293 var referenceVertexShaderSource = generateReferenceShader( |
| 294 shaderInfo, |
| 295 shaderInfo.vertexShaderTemplate, |
| 296 params, |
| 297 type, |
| 298 tests[ii]); |
| 299 var referenceFragmentShaderSource = generateReferenceShader( |
| 300 shaderInfo, |
| 301 shaderInfo.fragmentShaderTemplate, |
| 302 params, |
| 303 type, |
| 304 tests[ii]); |
| 305 var testVertexShaderSource = generateTestShader( |
| 306 shaderInfo, |
| 307 shaderInfo.vertexShaderTemplate, |
| 308 params, |
| 309 tests[ii]); |
| 310 var testFragmentShaderSource = generateTestShader( |
| 311 shaderInfo, |
| 312 shaderInfo.fragmentShaderTemplate, |
| 313 params, |
| 314 tests[ii]); |
| 315 |
| 316 debug(""); |
| 317 addShaderSource( |
| 318 "reference vertex shader", referenceVertexShaderSource); |
| 319 addShaderSource( |
| 320 "reference fragment shader", referenceFragmentShaderSource); |
| 321 addShaderSource( |
| 322 "test vertex shader", testVertexShaderSource); |
| 323 addShaderSource( |
| 324 "test fragment shader", testFragmentShaderSource); |
| 325 debug(""); |
| 326 |
| 327 var refData = draw( |
| 328 canvas, referenceVertexShaderSource, referenceFragmentShaderSource); |
| 329 var refImg = makeImage(canvas); |
| 330 if (ss == 0) { |
| 331 var testData = draw( |
| 332 canvas, testVertexShaderSource, referenceFragmentShaderSource); |
| 333 } else { |
| 334 var testData = draw( |
| 335 canvas, referenceVertexShaderSource, testFragmentShaderSource); |
| 336 } |
| 337 var testImg = makeImage(canvas); |
| 338 |
| 339 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance); |
| 340 } |
| 341 } |
| 342 |
| 343 finishTest(); |
| 344 |
| 345 function addShaderSource(label, source) { |
| 346 var div = document.createElement("div"); |
| 347 var s = document.createElement("pre"); |
| 348 s.className = "shader-source"; |
| 349 s.style.display = "none"; |
| 350 var ol = document.createElement("ol"); |
| 351 //s.appendChild(document.createTextNode(source)); |
| 352 var lines = source.split("\n"); |
| 353 for (var ii = 0; ii < lines.length; ++ii) { |
| 354 var line = lines[ii]; |
| 355 var li = document.createElement("li"); |
| 356 li.appendChild(document.createTextNode(line)); |
| 357 ol.appendChild(li); |
| 358 } |
| 359 s.appendChild(ol); |
| 360 var l = document.createElement("a"); |
| 361 l.href = "show-shader-source"; |
| 362 l.appendChild(document.createTextNode(label)); |
| 363 l.addEventListener('click', function(event) { |
| 364 if (event.preventDefault) { |
| 365 event.preventDefault(); |
| 366 } |
| 367 s.style.display = (s.style.display == 'none') ? 'block' : 'none'; |
| 368 return false; |
| 369 }, false); |
| 370 div.appendChild(l); |
| 371 div.appendChild(s); |
| 372 console.appendChild(div); |
| 373 } |
| 374 |
| 375 function reportResults(refData, refImage, testData, testImage, tolerance) { |
| 376 var same = true; |
| 377 for (var yy = 0; yy < height; ++yy) { |
| 378 for (var xx = 0; xx < width; ++xx) { |
| 379 var offset = (yy * width + xx) * 4; |
| 380 var imgOffset = ((height - yy - 1) * width + xx) * 4; |
| 381 imgData.data[imgOffset + 0] = 0; |
| 382 imgData.data[imgOffset + 1] = 0; |
| 383 imgData.data[imgOffset + 2] = 0; |
| 384 imgData.data[imgOffset + 3] = 255; |
| 385 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance || |
| 386 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance || |
| 387 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance || |
| 388 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) { |
| 389 imgData.data[imgOffset] = 255; |
| 390 same = false; |
| 391 } |
| 392 } |
| 393 } |
| 394 |
| 395 var diffImg = null; |
| 396 if (!same) { |
| 397 ctx.putImageData(imgData, 0, 0); |
| 398 diffImg = makeImage(canvas2d); |
| 399 } |
| 400 |
| 401 var div = document.createElement("div"); |
| 402 div.className = "testimages"; |
| 403 insertImg(div, "ref", refImg); |
| 404 insertImg(div, "test", testImg); |
| 405 if (diffImg) { |
| 406 insertImg(div, "diff", diffImg); |
| 407 } |
| 408 div.appendChild(document.createElement('br')); |
| 409 |
| 410 function insertImg(element, caption, img) { |
| 411 var div = document.createElement("div"); |
| 412 div.appendChild(img); |
| 413 var label = document.createElement("div"); |
| 414 label.appendChild(document.createTextNode(caption)); |
| 415 div.appendChild(label); |
| 416 element.appendChild(div); |
| 417 } |
| 418 |
| 419 console.appendChild(div); |
| 420 |
| 421 if (!same) { |
| 422 testFailed("images are different"); |
| 423 } else { |
| 424 testPassed("images are the same"); |
| 425 } |
| 426 |
| 427 console.appendChild(document.createElement('hr')); |
| 428 } |
| 429 |
| 430 function draw(canvas, vsSource, fsSource) { |
| 431 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed); |
| 432 |
| 433 var posLoc = gl.getAttribLocation(program, "aPosition"); |
| 434 WebGLTestUtils.setupQuad(gl, gridRes, posLoc); |
| 435 |
| 436 gl.useProgram(program); |
| 437 gl.clearColor(0, 0, 1, 1); |
| 438 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 439 gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0); |
| 440 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); |
| 441 |
| 442 var img = new Uint8Array(width * height * 4); |
| 443 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); |
| 444 return img; |
| 445 } |
| 446 |
| 447 }; |
| 448 |
| 449 var runBasicTest = function(params) { |
| 450 if (window.initNonKhronosFramework) { |
| 451 window.initNonKhronosFramework(false); |
| 452 } |
| 453 |
| 454 var wtu = WebGLTestUtils; |
| 455 var gridRes = params.gridRes; |
| 456 var vertexTolerance = params.tolerance || 0; |
| 457 var fragmentTolerance = vertexTolerance; |
| 458 if ('fragmentTolerance' in params) |
| 459 fragmentTolerance = params.fragmentTolerance || 0; |
| 460 |
| 461 description("Testing : " + document.getElementsByTagName("title")[0].innerText
); |
| 462 |
| 463 var width = 32; |
| 464 var height = 32; |
| 465 |
| 466 var console = document.getElementById("console"); |
| 467 var canvas = document.createElement('canvas'); |
| 468 canvas.width = width; |
| 469 canvas.height = height; |
| 470 var gl = wtu.create3DContext(canvas); |
| 471 if (!gl) { |
| 472 testFailed("context does not exist"); |
| 473 finishTest(); |
| 474 return; |
| 475 } |
| 476 |
| 477 var canvas2d = document.createElement('canvas'); |
| 478 canvas2d.width = width; |
| 479 canvas2d.height = height; |
| 480 var ctx = canvas2d.getContext("2d"); |
| 481 var imgData = ctx.getImageData(0, 0, width, height); |
| 482 |
| 483 var shaderInfos = [ |
| 484 { type: "vertex", |
| 485 input: "color", |
| 486 output: "vColor", |
| 487 vertexShaderTemplate: vertexShaderTemplate, |
| 488 fragmentShaderTemplate: baseFragmentShader, |
| 489 tolerance: vertexTolerance |
| 490 }, |
| 491 { type: "fragment", |
| 492 input: "vColor", |
| 493 output: "gl_FragColor", |
| 494 vertexShaderTemplate: baseVertexShader, |
| 495 fragmentShaderTemplate: fragmentShaderTemplate, |
| 496 tolerance: fragmentTolerance |
| 497 } |
| 498 ]; |
| 499 for (var ss = 0; ss < shaderInfos.length; ++ss) { |
| 500 var shaderInfo = shaderInfos[ss]; |
| 501 var tests = params.tests; |
| 502 // var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types); |
| 503 // Test vertex shaders |
| 504 for (var ii = 0; ii < tests.length; ++ii) { |
| 505 var test = tests[ii]; |
| 506 debug(""); |
| 507 debug("Testing: " + test.name + " in " + shaderInfo.type + " shader"); |
| 508 |
| 509 function genShader(shaderInfo, template, shader, subs) { |
| 510 shader = replaceParams(shader, subs, { |
| 511 input: shaderInfo.input, |
| 512 output: shaderInfo.output |
| 513 }); |
| 514 shader = replaceParams(template, subs, { |
| 515 test: shader, |
| 516 emu: "", |
| 517 extra: "" |
| 518 }); |
| 519 return shader; |
| 520 } |
| 521 |
| 522 var referenceVertexShaderSource = genShader( |
| 523 shaderInfo, |
| 524 shaderInfo.vertexShaderTemplate, |
| 525 test.reference.shader, |
| 526 test.reference.subs); |
| 527 var referenceFragmentShaderSource = genShader( |
| 528 shaderInfo, |
| 529 shaderInfo.fragmentShaderTemplate, |
| 530 test.reference.shader, |
| 531 test.reference.subs); |
| 532 var testVertexShaderSource = genShader( |
| 533 shaderInfo, |
| 534 shaderInfo.vertexShaderTemplate, |
| 535 test.test.shader, |
| 536 test.test.subs); |
| 537 var testFragmentShaderSource = genShader( |
| 538 shaderInfo, |
| 539 shaderInfo.fragmentShaderTemplate, |
| 540 test.test.shader, |
| 541 test.test.subs); |
| 542 |
| 543 debug(""); |
| 544 addShaderSource( |
| 545 "reference vertex shader", referenceVertexShaderSource); |
| 546 addShaderSource( |
| 547 "reference fragment shader", referenceFragmentShaderSource); |
| 548 addShaderSource( |
| 549 "test vertex shader", testVertexShaderSource); |
| 550 addShaderSource( |
| 551 "test fragment shader", testFragmentShaderSource); |
| 552 debug(""); |
| 553 |
| 554 var refData = draw( |
| 555 canvas, referenceVertexShaderSource, referenceFragmentShaderSource); |
| 556 var refImg = makeImage(canvas); |
| 557 if (ss == 0) { |
| 558 var testData = draw( |
| 559 canvas, testVertexShaderSource, referenceFragmentShaderSource); |
| 560 } else { |
| 561 var testData = draw( |
| 562 canvas, referenceVertexShaderSource, testFragmentShaderSource); |
| 563 } |
| 564 var testImg = makeImage(canvas); |
| 565 |
| 566 reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance); |
| 567 } |
| 568 } |
| 569 |
| 570 finishTest(); |
| 571 |
| 572 function addShaderSource(label, source) { |
| 573 var div = document.createElement("div"); |
| 574 var s = document.createElement("pre"); |
| 575 s.className = "shader-source"; |
| 576 s.style.display = "none"; |
| 577 var ol = document.createElement("ol"); |
| 578 //s.appendChild(document.createTextNode(source)); |
| 579 var lines = source.split("\n"); |
| 580 for (var ii = 0; ii < lines.length; ++ii) { |
| 581 var line = lines[ii]; |
| 582 var li = document.createElement("li"); |
| 583 li.appendChild(document.createTextNode(line)); |
| 584 ol.appendChild(li); |
| 585 } |
| 586 s.appendChild(ol); |
| 587 var l = document.createElement("a"); |
| 588 l.href = "show-shader-source"; |
| 589 l.appendChild(document.createTextNode(label)); |
| 590 l.addEventListener('click', function(event) { |
| 591 if (event.preventDefault) { |
| 592 event.preventDefault(); |
| 593 } |
| 594 s.style.display = (s.style.display == 'none') ? 'block' : 'none'; |
| 595 return false; |
| 596 }, false); |
| 597 div.appendChild(l); |
| 598 div.appendChild(s); |
| 599 console.appendChild(div); |
| 600 } |
| 601 |
| 602 function reportResults(refData, refImage, testData, testImage, tolerance) { |
| 603 var same = true; |
| 604 for (var yy = 0; yy < height; ++yy) { |
| 605 for (var xx = 0; xx < width; ++xx) { |
| 606 var offset = (yy * width + xx) * 4; |
| 607 var imgOffset = ((height - yy - 1) * width + xx) * 4; |
| 608 imgData.data[imgOffset + 0] = 0; |
| 609 imgData.data[imgOffset + 1] = 0; |
| 610 imgData.data[imgOffset + 2] = 0; |
| 611 imgData.data[imgOffset + 3] = 255; |
| 612 if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance || |
| 613 Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance || |
| 614 Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance || |
| 615 Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) { |
| 616 imgData.data[imgOffset] = 255; |
| 617 same = false; |
| 618 } |
| 619 } |
| 620 } |
| 621 |
| 622 var diffImg = null; |
| 623 if (!same) { |
| 624 ctx.putImageData(imgData, 0, 0); |
| 625 diffImg = makeImage(canvas2d); |
| 626 } |
| 627 |
| 628 var div = document.createElement("div"); |
| 629 div.className = "testimages"; |
| 630 insertImg(div, "ref", refImg); |
| 631 insertImg(div, "test", testImg); |
| 632 if (diffImg) { |
| 633 insertImg(div, "diff", diffImg); |
| 634 } |
| 635 div.appendChild(document.createElement('br')); |
| 636 |
| 637 function insertImg(element, caption, img) { |
| 638 var div = document.createElement("div"); |
| 639 div.appendChild(img); |
| 640 var label = document.createElement("div"); |
| 641 label.appendChild(document.createTextNode(caption)); |
| 642 div.appendChild(label); |
| 643 element.appendChild(div); |
| 644 } |
| 645 |
| 646 console.appendChild(div); |
| 647 |
| 648 if (!same) { |
| 649 testFailed("images are different"); |
| 650 } else { |
| 651 testPassed("images are the same"); |
| 652 } |
| 653 |
| 654 console.appendChild(document.createElement('hr')); |
| 655 } |
| 656 |
| 657 function draw(canvas, vsSource, fsSource) { |
| 658 var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed); |
| 659 |
| 660 var posLoc = gl.getAttribLocation(program, "aPosition"); |
| 661 WebGLTestUtils.setupQuad(gl, gridRes, posLoc); |
| 662 |
| 663 gl.useProgram(program); |
| 664 gl.clearColor(0, 0, 1, 1); |
| 665 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 666 gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0); |
| 667 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); |
| 668 |
| 669 var img = new Uint8Array(width * height * 4); |
| 670 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); |
| 671 return img; |
| 672 } |
| 673 |
| 674 }; |
| 675 |
| 676 return { |
| 677 /** |
| 678 * runs a bunch of GLSL tests using the passed in parameters |
| 679 * The parameters are: |
| 680 * |
| 681 * feature: |
| 682 * the name of the function being tested (eg, sin, dot, |
| 683 * normalize) |
| 684 * |
| 685 * testFunc: |
| 686 * The prototype of function to be tested not including the |
| 687 * return type. |
| 688 * |
| 689 * emuFunc: |
| 690 * A base function that can be used to generate emulation |
| 691 * functions. Example for 'ceil' |
| 692 * |
| 693 * float $(func)_base(float value) { |
| 694 * float m = mod(value, 1.0); |
| 695 * return m != 0.0 ? (value + 1.0 - m) : value; |
| 696 * } |
| 697 * |
| 698 * args: |
| 699 * The arguments to the function |
| 700 * |
| 701 * baseArgs: (optional) |
| 702 * The arguments when a base function is used to create an |
| 703 * emulation function. For example 'float sign_base(float v)' |
| 704 * is used to implemenent vec2 sign_emu(vec2 v). |
| 705 * |
| 706 * simpleEmu: |
| 707 * if supplied, the code that can be used to generate all |
| 708 * functions for all types. |
| 709 * |
| 710 * Example for 'normalize': |
| 711 * |
| 712 * $(type) $(func)_emu($(args)) { |
| 713 * return value / length(value); |
| 714 * } |
| 715 * |
| 716 * gridRes: (optional) |
| 717 * The resolution of the mesh to generate. The default is a |
| 718 * 1x1 grid but many vertex shaders need a higher resolution |
| 719 * otherwise the only values passed in are the 4 corners |
| 720 * which often have the same value. |
| 721 * |
| 722 * tests: |
| 723 * The code for each test. It is assumed the tests are for |
| 724 * float, vec2, vec3, vec4 in that order. |
| 725 * |
| 726 * tolerance: (optional) |
| 727 * Allow some tolerance in the comparisons. The tolerance is applied to |
| 728 * both vertex and fragment shaders. The default tolerance is 0, meaning |
| 729 * the values have to be identical. |
| 730 * |
| 731 * fragmentTolerance: (optional) |
| 732 * Specify a tolerance which only applies to fragment shaders. The |
| 733 * fragment-only tolerance will override the shared tolerance for |
| 734 * fragment shaders if both are specified. Fragment shaders usually |
| 735 * use mediump float precision so they sometimes require higher tolerance |
| 736 * than vertex shaders which use highp. |
| 737 */ |
| 738 runFeatureTest: runFeatureTest, |
| 739 |
| 740 /* |
| 741 * Runs a bunch of GLSL tests using the passed in parameters |
| 742 * |
| 743 * The parameters are: |
| 744 * |
| 745 * tests: |
| 746 * Array of tests. For each test the following parameters are expected |
| 747 * |
| 748 * name: |
| 749 * some description of the test |
| 750 * reference: |
| 751 * parameters for the reference shader (see below) |
| 752 * test: |
| 753 * parameters for the test shader (see below) |
| 754 * |
| 755 * The parameter for the reference and test shaders are |
| 756 * |
| 757 * shader: the GLSL for the shader |
| 758 * subs: any substitutions you wish to define for the shader. |
| 759 * |
| 760 * Each shader is created from a basic template that |
| 761 * defines an input and an output. You can see the |
| 762 * templates at the top of this file. The input and output |
| 763 * change depending on whether or not we are generating |
| 764 * a vertex or fragment shader. |
| 765 * |
| 766 * All this code function does is a bunch of string substitutions. |
| 767 * A substitution is defined by $(name). If name is found in |
| 768 * the 'subs' parameter it is replaced. 4 special names exist. |
| 769 * |
| 770 * 'input' the input to your GLSL. Always a vec4. All change |
| 771 * from 0 to 1 over the quad to be drawn. |
| 772 * |
| 773 * 'output' the output color. Also a vec4 |
| 774 * |
| 775 * 'emu' a place to insert extra stuff |
| 776 * 'extra' a place to insert extra stuff. |
| 777 * |
| 778 * You can think of the templates like this |
| 779 * |
| 780 * $(extra) |
| 781 * $(emu) |
| 782 * |
| 783 * void main() { |
| 784 * // do math to calculate input |
| 785 * ... |
| 786 * |
| 787 * $(shader) |
| 788 * } |
| 789 * |
| 790 * Your shader first has any subs you provided applied as well |
| 791 * as 'input' and 'output' |
| 792 * |
| 793 * It is then inserted into the template which is also provided |
| 794 * with your subs. |
| 795 * |
| 796 * gridRes: (optional) |
| 797 * The resolution of the mesh to generate. The default is a |
| 798 * 1x1 grid but many vertex shaders need a higher resolution |
| 799 * otherwise the only values passed in are the 4 corners |
| 800 * which often have the same value. |
| 801 * |
| 802 * tolerance: (optional) |
| 803 * Allow some tolerance in the comparisons. The tolerance is applied to |
| 804 * both vertex and fragment shaders. The default tolerance is 0, meaning |
| 805 * the values have to be identical. |
| 806 * |
| 807 * fragmentTolerance: (optional) |
| 808 * Specify a tolerance which only applies to fragment shaders. The |
| 809 * fragment-only tolerance will override the shared tolerance for |
| 810 * fragment shaders if both are specified. Fragment shaders usually |
| 811 * use mediump float precision so they sometimes require higher tolerance |
| 812 * than vertex shaders which use highp. |
| 813 */ |
| 814 runBasicTest: runBasicTest, |
| 815 |
| 816 none: false |
| 817 }; |
| 818 |
| 819 }()); |
| 820 |
OLD | NEW |