1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/test/webgl-conformance/conformance/resources/glsl-generator.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1157 @@ 1.4 +GLSLGenerator = (function() { 1.5 + 1.6 +var vertexShaderTemplate = [ 1.7 + "attribute vec4 aPosition;", 1.8 + "", 1.9 + "varying vec4 vColor;", 1.10 + "", 1.11 + "$(extra)", 1.12 + "$(emu)", 1.13 + "", 1.14 + "void main()", 1.15 + "{", 1.16 + " gl_Position = aPosition;", 1.17 + " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));", 1.18 + " vec4 color = vec4(", 1.19 + " texcoord,", 1.20 + " texcoord.x * texcoord.y,", 1.21 + " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);", 1.22 + " $(test)", 1.23 + "}" 1.24 +].join("\n"); 1.25 + 1.26 +var fragmentShaderTemplate = [ 1.27 + "#if defined(GL_ES)", 1.28 + "precision mediump float;", 1.29 + "#endif", 1.30 + "", 1.31 + "varying vec4 vColor;", 1.32 + "", 1.33 + "$(extra)", 1.34 + "$(emu)", 1.35 + "", 1.36 + "void main()", 1.37 + "{", 1.38 + " $(test)", 1.39 + "}" 1.40 +].join("\n"); 1.41 + 1.42 +var baseVertexShader = [ 1.43 + "attribute vec4 aPosition;", 1.44 + "", 1.45 + "varying vec4 vColor;", 1.46 + "", 1.47 + "void main()", 1.48 + "{", 1.49 + " gl_Position = aPosition;", 1.50 + " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));", 1.51 + " vColor = vec4(", 1.52 + " texcoord,", 1.53 + " texcoord.x * texcoord.y,", 1.54 + " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);", 1.55 + "}" 1.56 +].join("\n"); 1.57 + 1.58 +var baseFragmentShader = [ 1.59 + "#if defined(GL_ES)", 1.60 + "precision mediump float;", 1.61 + "#endif", 1.62 + "varying vec4 vColor;", 1.63 + "", 1.64 + "void main()", 1.65 + "{", 1.66 + " gl_FragColor = vColor;", 1.67 + "}" 1.68 +].join("\n"); 1.69 + 1.70 +var types = [ 1.71 + { type: "float", 1.72 + code: [ 1.73 + "float $(func)_emu($(args)) {", 1.74 + " return $(func)_base($(baseArgs));", 1.75 + "}"].join("\n") 1.76 + }, 1.77 + { type: "vec2", 1.78 + code: [ 1.79 + "vec2 $(func)_emu($(args)) {", 1.80 + " return vec2(", 1.81 + " $(func)_base($(baseArgsX)),", 1.82 + " $(func)_base($(baseArgsY)));", 1.83 + "}"].join("\n") 1.84 + }, 1.85 + { type: "vec3", 1.86 + code: [ 1.87 + "vec3 $(func)_emu($(args)) {", 1.88 + " return vec3(", 1.89 + " $(func)_base($(baseArgsX)),", 1.90 + " $(func)_base($(baseArgsY)),", 1.91 + " $(func)_base($(baseArgsZ)));", 1.92 + "}"].join("\n") 1.93 + }, 1.94 + { type: "vec4", 1.95 + code: [ 1.96 + "vec4 $(func)_emu($(args)) {", 1.97 + " return vec4(", 1.98 + " $(func)_base($(baseArgsX)),", 1.99 + " $(func)_base($(baseArgsY)),", 1.100 + " $(func)_base($(baseArgsZ)),", 1.101 + " $(func)_base($(baseArgsW)));", 1.102 + "}"].join("\n") 1.103 + } 1.104 +]; 1.105 + 1.106 +var bvecTypes = [ 1.107 + { type: "bvec2", 1.108 + code: [ 1.109 + "bvec2 $(func)_emu($(args)) {", 1.110 + " return bvec2(", 1.111 + " $(func)_base($(baseArgsX)),", 1.112 + " $(func)_base($(baseArgsY)));", 1.113 + "}"].join("\n") 1.114 + }, 1.115 + { type: "bvec3", 1.116 + code: [ 1.117 + "bvec3 $(func)_emu($(args)) {", 1.118 + " return bvec3(", 1.119 + " $(func)_base($(baseArgsX)),", 1.120 + " $(func)_base($(baseArgsY)),", 1.121 + " $(func)_base($(baseArgsZ)));", 1.122 + "}"].join("\n") 1.123 + }, 1.124 + { type: "bvec4", 1.125 + code: [ 1.126 + "vec4 $(func)_emu($(args)) {", 1.127 + " return bvec4(", 1.128 + " $(func)_base($(baseArgsX)),", 1.129 + " $(func)_base($(baseArgsY)),", 1.130 + " $(func)_base($(baseArgsZ)),", 1.131 + " $(func)_base($(baseArgsW)));", 1.132 + "}"].join("\n") 1.133 + } 1.134 +]; 1.135 + 1.136 +var replaceRE = /\$\((\w+)\)/g; 1.137 + 1.138 +var replaceParams = function(str) { 1.139 + var args = arguments; 1.140 + return str.replace(replaceRE, function(str, p1, offset, s) { 1.141 + for (var ii = 1; ii < args.length; ++ii) { 1.142 + if (args[ii][p1] !== undefined) { 1.143 + return args[ii][p1]; 1.144 + } 1.145 + } 1.146 + throw "unknown string param '" + p1 + "'"; 1.147 + }); 1.148 +}; 1.149 + 1.150 +var generateReferenceShader = function( 1.151 + shaderInfo, template, params, typeInfo, test) { 1.152 + var input = shaderInfo.input; 1.153 + var output = shaderInfo.output; 1.154 + var feature = params.feature; 1.155 + var testFunc = params.testFunc; 1.156 + var emuFunc = params.emuFunc || ""; 1.157 + var extra = params.extra || ''; 1.158 + var args = params.args || "$(type) value"; 1.159 + var type = typeInfo.type; 1.160 + var typeCode = typeInfo.code; 1.161 + 1.162 + var baseArgs = params.baseArgs || "value$(field)"; 1.163 + var baseArgsX = replaceParams(baseArgs, {field: ".x"}); 1.164 + var baseArgsY = replaceParams(baseArgs, {field: ".y"}); 1.165 + var baseArgsZ = replaceParams(baseArgs, {field: ".z"}); 1.166 + var baseArgsW = replaceParams(baseArgs, {field: ".w"}); 1.167 + var baseArgs = replaceParams(baseArgs, {field: ""}); 1.168 + 1.169 + test = replaceParams(test, { 1.170 + input: input, 1.171 + output: output, 1.172 + func: feature + "_emu" 1.173 + }); 1.174 + emuFunc = replaceParams(emuFunc, { 1.175 + func: feature 1.176 + }); 1.177 + args = replaceParams(args, { 1.178 + type: type 1.179 + }); 1.180 + typeCode = replaceParams(typeCode, { 1.181 + func: feature, 1.182 + type: type, 1.183 + args: args, 1.184 + baseArgs: baseArgs, 1.185 + baseArgsX: baseArgsX, 1.186 + baseArgsY: baseArgsY, 1.187 + baseArgsZ: baseArgsZ, 1.188 + baseArgsW: baseArgsW 1.189 + }); 1.190 + var shader = replaceParams(template, { 1.191 + extra: extra, 1.192 + emu: emuFunc + "\n\n" + typeCode, 1.193 + test: test 1.194 + }); 1.195 + return shader; 1.196 +}; 1.197 + 1.198 +var generateTestShader = function( 1.199 + shaderInfo, template, params, test) { 1.200 + var input = shaderInfo.input; 1.201 + var output = shaderInfo.output; 1.202 + var feature = params.feature; 1.203 + var testFunc = params.testFunc; 1.204 + var extra = params.extra || ''; 1.205 + 1.206 + test = replaceParams(test, { 1.207 + input: input, 1.208 + output: output, 1.209 + func: feature 1.210 + }); 1.211 + var shader = replaceParams(template, { 1.212 + extra: extra, 1.213 + emu: '', 1.214 + test: test 1.215 + }); 1.216 + return shader; 1.217 +}; 1.218 + 1.219 +var runFeatureTest = function(params) { 1.220 + if (window.initNonKhronosFramework) { 1.221 + window.initNonKhronosFramework(false); 1.222 + } 1.223 + 1.224 + var wtu = WebGLTestUtils; 1.225 + var gridRes = params.gridRes; 1.226 + var vertexTolerance = params.tolerance || 0; 1.227 + var fragmentTolerance = vertexTolerance; 1.228 + if ('fragmentTolerance' in params) 1.229 + fragmentTolerance = params.fragmentTolerance || 0; 1.230 + 1.231 + description("Testing GLSL feature: " + params.feature); 1.232 + 1.233 + var width = 32; 1.234 + var height = 32; 1.235 + 1.236 + var console = document.getElementById("console"); 1.237 + var canvas = document.createElement('canvas'); 1.238 + canvas.width = width; 1.239 + canvas.height = height; 1.240 + var gl = wtu.create3DContext(canvas); 1.241 + if (!gl) { 1.242 + testFailed("context does not exist"); 1.243 + finishTest(); 1.244 + return; 1.245 + } 1.246 + 1.247 + var canvas2d = document.createElement('canvas'); 1.248 + canvas2d.width = width; 1.249 + canvas2d.height = height; 1.250 + var ctx = canvas2d.getContext("2d"); 1.251 + var imgData = ctx.getImageData(0, 0, width, height); 1.252 + 1.253 + var shaderInfos = [ 1.254 + { type: "vertex", 1.255 + input: "color", 1.256 + output: "vColor", 1.257 + vertexShaderTemplate: vertexShaderTemplate, 1.258 + fragmentShaderTemplate: baseFragmentShader, 1.259 + tolerance: vertexTolerance 1.260 + }, 1.261 + { type: "fragment", 1.262 + input: "vColor", 1.263 + output: "gl_FragColor", 1.264 + vertexShaderTemplate: baseVertexShader, 1.265 + fragmentShaderTemplate: fragmentShaderTemplate, 1.266 + tolerance: fragmentTolerance 1.267 + } 1.268 + ]; 1.269 + for (var ss = 0; ss < shaderInfos.length; ++ss) { 1.270 + var shaderInfo = shaderInfos[ss]; 1.271 + var tests = params.tests; 1.272 + var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types); 1.273 + // Test vertex shaders 1.274 + for (var ii = 0; ii < tests.length; ++ii) { 1.275 + var type = testTypes[ii]; 1.276 + if (params.simpleEmu) { 1.277 + type = { 1.278 + type: type.type, 1.279 + code: params.simpleEmu 1.280 + }; 1.281 + } 1.282 + debug(""); 1.283 + var str = replaceParams(params.testFunc, { 1.284 + func: params.feature, 1.285 + type: type.type, 1.286 + arg0: type.type 1.287 + }); 1.288 + debug("Testing: " + str + " in " + shaderInfo.type + " shader"); 1.289 + 1.290 + var referenceVertexShaderSource = generateReferenceShader( 1.291 + shaderInfo, 1.292 + shaderInfo.vertexShaderTemplate, 1.293 + params, 1.294 + type, 1.295 + tests[ii]); 1.296 + var referenceFragmentShaderSource = generateReferenceShader( 1.297 + shaderInfo, 1.298 + shaderInfo.fragmentShaderTemplate, 1.299 + params, 1.300 + type, 1.301 + tests[ii]); 1.302 + var testVertexShaderSource = generateTestShader( 1.303 + shaderInfo, 1.304 + shaderInfo.vertexShaderTemplate, 1.305 + params, 1.306 + tests[ii]); 1.307 + var testFragmentShaderSource = generateTestShader( 1.308 + shaderInfo, 1.309 + shaderInfo.fragmentShaderTemplate, 1.310 + params, 1.311 + tests[ii]); 1.312 + 1.313 + debug(""); 1.314 + wtu.addShaderSource( 1.315 + console, "reference vertex shader", referenceVertexShaderSource); 1.316 + wtu.addShaderSource( 1.317 + console, "reference fragment shader", referenceFragmentShaderSource); 1.318 + wtu.addShaderSource( 1.319 + console, "test vertex shader", testVertexShaderSource); 1.320 + wtu.addShaderSource( 1.321 + console, "test fragment shader", testFragmentShaderSource); 1.322 + debug(""); 1.323 + 1.324 + var refData = draw( 1.325 + canvas, referenceVertexShaderSource, referenceFragmentShaderSource); 1.326 + var refImg = wtu.makeImage(canvas); 1.327 + if (ss == 0) { 1.328 + var testData = draw( 1.329 + canvas, testVertexShaderSource, referenceFragmentShaderSource); 1.330 + } else { 1.331 + var testData = draw( 1.332 + canvas, referenceVertexShaderSource, testFragmentShaderSource); 1.333 + } 1.334 + var testImg = wtu.makeImage(canvas); 1.335 + 1.336 + reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance); 1.337 + } 1.338 + } 1.339 + 1.340 + finishTest(); 1.341 + 1.342 + function reportResults(refData, refImage, testData, testImage, tolerance) { 1.343 + var same = true; 1.344 + for (var yy = 0; yy < height; ++yy) { 1.345 + for (var xx = 0; xx < width; ++xx) { 1.346 + var offset = (yy * width + xx) * 4; 1.347 + var imgOffset = ((height - yy - 1) * width + xx) * 4; 1.348 + imgData.data[imgOffset + 0] = 0; 1.349 + imgData.data[imgOffset + 1] = 0; 1.350 + imgData.data[imgOffset + 2] = 0; 1.351 + imgData.data[imgOffset + 3] = 255; 1.352 + if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance || 1.353 + Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance || 1.354 + Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance || 1.355 + Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) { 1.356 + imgData.data[imgOffset] = 255; 1.357 + same = false; 1.358 + } 1.359 + } 1.360 + } 1.361 + 1.362 + var diffImg = null; 1.363 + if (!same) { 1.364 + ctx.putImageData(imgData, 0, 0); 1.365 + diffImg = wtu.makeImage(canvas2d); 1.366 + } 1.367 + 1.368 + var div = document.createElement("div"); 1.369 + div.className = "testimages"; 1.370 + wtu.insertImage(div, "ref", refImg); 1.371 + wtu.insertImage(div, "test", testImg); 1.372 + if (diffImg) { 1.373 + wtu.insertImage(div, "diff", diffImg); 1.374 + } 1.375 + div.appendChild(document.createElement('br')); 1.376 + 1.377 + 1.378 + console.appendChild(div); 1.379 + 1.380 + if (!same) { 1.381 + testFailed("images are different"); 1.382 + } else { 1.383 + testPassed("images are the same"); 1.384 + } 1.385 + 1.386 + console.appendChild(document.createElement('hr')); 1.387 + } 1.388 + 1.389 + function draw(canvas, vsSource, fsSource) { 1.390 + var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed); 1.391 + 1.392 + var posLoc = gl.getAttribLocation(program, "aPosition"); 1.393 + WebGLTestUtils.setupQuad(gl, gridRes, posLoc); 1.394 + 1.395 + gl.useProgram(program); 1.396 + gl.clearColor(0, 0, 1, 1); 1.397 + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 1.398 + gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0); 1.399 + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); 1.400 + 1.401 + var img = new Uint8Array(width * height * 4); 1.402 + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); 1.403 + return img; 1.404 + } 1.405 + 1.406 +}; 1.407 + 1.408 +var runBasicTest = function(params) { 1.409 + if (window.initNonKhronosFramework) { 1.410 + window.initNonKhronosFramework(false); 1.411 + } 1.412 + 1.413 + var wtu = WebGLTestUtils; 1.414 + var gridRes = params.gridRes; 1.415 + var vertexTolerance = params.tolerance || 0; 1.416 + var fragmentTolerance = vertexTolerance; 1.417 + if ('fragmentTolerance' in params) 1.418 + fragmentTolerance = params.fragmentTolerance || 0; 1.419 + 1.420 + description("Testing : " + document.getElementsByTagName("title")[0].innerText); 1.421 + 1.422 + var width = 32; 1.423 + var height = 32; 1.424 + 1.425 + var console = document.getElementById("console"); 1.426 + var canvas = document.createElement('canvas'); 1.427 + canvas.width = width; 1.428 + canvas.height = height; 1.429 + var gl = wtu.create3DContext(canvas); 1.430 + if (!gl) { 1.431 + testFailed("context does not exist"); 1.432 + finishTest(); 1.433 + return; 1.434 + } 1.435 + 1.436 + var canvas2d = document.createElement('canvas'); 1.437 + canvas2d.width = width; 1.438 + canvas2d.height = height; 1.439 + var ctx = canvas2d.getContext("2d"); 1.440 + var imgData = ctx.getImageData(0, 0, width, height); 1.441 + 1.442 + var shaderInfos = [ 1.443 + { type: "vertex", 1.444 + input: "color", 1.445 + output: "vColor", 1.446 + vertexShaderTemplate: vertexShaderTemplate, 1.447 + fragmentShaderTemplate: baseFragmentShader, 1.448 + tolerance: vertexTolerance 1.449 + }, 1.450 + { type: "fragment", 1.451 + input: "vColor", 1.452 + output: "gl_FragColor", 1.453 + vertexShaderTemplate: baseVertexShader, 1.454 + fragmentShaderTemplate: fragmentShaderTemplate, 1.455 + tolerance: fragmentTolerance 1.456 + } 1.457 + ]; 1.458 + for (var ss = 0; ss < shaderInfos.length; ++ss) { 1.459 + var shaderInfo = shaderInfos[ss]; 1.460 + var tests = params.tests; 1.461 +// var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types); 1.462 + // Test vertex shaders 1.463 + for (var ii = 0; ii < tests.length; ++ii) { 1.464 + var test = tests[ii]; 1.465 + debug(""); 1.466 + debug("Testing: " + test.name + " in " + shaderInfo.type + " shader"); 1.467 + 1.468 + function genShader(shaderInfo, template, shader, subs) { 1.469 + shader = replaceParams(shader, subs, { 1.470 + input: shaderInfo.input, 1.471 + output: shaderInfo.output 1.472 + }); 1.473 + shader = replaceParams(template, subs, { 1.474 + test: shader, 1.475 + emu: "", 1.476 + extra: "" 1.477 + }); 1.478 + return shader; 1.479 + } 1.480 + 1.481 + var referenceVertexShaderSource = genShader( 1.482 + shaderInfo, 1.483 + shaderInfo.vertexShaderTemplate, 1.484 + test.reference.shader, 1.485 + test.reference.subs); 1.486 + var referenceFragmentShaderSource = genShader( 1.487 + shaderInfo, 1.488 + shaderInfo.fragmentShaderTemplate, 1.489 + test.reference.shader, 1.490 + test.reference.subs); 1.491 + var testVertexShaderSource = genShader( 1.492 + shaderInfo, 1.493 + shaderInfo.vertexShaderTemplate, 1.494 + test.test.shader, 1.495 + test.test.subs); 1.496 + var testFragmentShaderSource = genShader( 1.497 + shaderInfo, 1.498 + shaderInfo.fragmentShaderTemplate, 1.499 + test.test.shader, 1.500 + test.test.subs); 1.501 + 1.502 + debug(""); 1.503 + wtu.addShaderSource( 1.504 + console, "reference vertex shader", referenceVertexShaderSource); 1.505 + wtu.addShaderSource( 1.506 + console, "reference fragment shader", referenceFragmentShaderSource); 1.507 + wtu.addShaderSource( 1.508 + console, "test vertex shader", testVertexShaderSource); 1.509 + wtu.addShaderSource( 1.510 + console, "test fragment shader", testFragmentShaderSource); 1.511 + debug(""); 1.512 + 1.513 + var refData = draw( 1.514 + canvas, referenceVertexShaderSource, referenceFragmentShaderSource); 1.515 + var refImg = wtu.makeImage(canvas); 1.516 + if (ss == 0) { 1.517 + var testData = draw( 1.518 + canvas, testVertexShaderSource, referenceFragmentShaderSource); 1.519 + } else { 1.520 + var testData = draw( 1.521 + canvas, referenceVertexShaderSource, testFragmentShaderSource); 1.522 + } 1.523 + var testImg = wtu.makeImage(canvas); 1.524 + 1.525 + reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance); 1.526 + } 1.527 + } 1.528 + 1.529 + finishTest(); 1.530 + 1.531 + function reportResults(refData, refImage, testData, testImage, tolerance) { 1.532 + var same = true; 1.533 + for (var yy = 0; yy < height; ++yy) { 1.534 + for (var xx = 0; xx < width; ++xx) { 1.535 + var offset = (yy * width + xx) * 4; 1.536 + var imgOffset = ((height - yy - 1) * width + xx) * 4; 1.537 + imgData.data[imgOffset + 0] = 0; 1.538 + imgData.data[imgOffset + 1] = 0; 1.539 + imgData.data[imgOffset + 2] = 0; 1.540 + imgData.data[imgOffset + 3] = 255; 1.541 + if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance || 1.542 + Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance || 1.543 + Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance || 1.544 + Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) { 1.545 + imgData.data[imgOffset] = 255; 1.546 + same = false; 1.547 + } 1.548 + } 1.549 + } 1.550 + 1.551 + var diffImg = null; 1.552 + if (!same) { 1.553 + ctx.putImageData(imgData, 0, 0); 1.554 + diffImg = wtu.makeImage(canvas2d); 1.555 + } 1.556 + 1.557 + var div = document.createElement("div"); 1.558 + div.className = "testimages"; 1.559 + wtu.insertImage(div, "ref", refImg); 1.560 + wtu.insertImage(div, "test", testImg); 1.561 + if (diffImg) { 1.562 + wtu.insertImage(div, "diff", diffImg); 1.563 + } 1.564 + div.appendChild(document.createElement('br')); 1.565 + 1.566 + console.appendChild(div); 1.567 + 1.568 + if (!same) { 1.569 + testFailed("images are different"); 1.570 + } else { 1.571 + testPassed("images are the same"); 1.572 + } 1.573 + 1.574 + console.appendChild(document.createElement('hr')); 1.575 + } 1.576 + 1.577 + function draw(canvas, vsSource, fsSource) { 1.578 + var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed); 1.579 + 1.580 + var posLoc = gl.getAttribLocation(program, "aPosition"); 1.581 + WebGLTestUtils.setupQuad(gl, gridRes, posLoc); 1.582 + 1.583 + gl.useProgram(program); 1.584 + gl.clearColor(0, 0, 1, 1); 1.585 + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 1.586 + gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0); 1.587 + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); 1.588 + 1.589 + var img = new Uint8Array(width * height * 4); 1.590 + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); 1.591 + return img; 1.592 + } 1.593 + 1.594 +}; 1.595 + 1.596 +var runReferenceImageTest = function(params) { 1.597 + if (window.initNonKhronosFramework) { 1.598 + window.initNonKhronosFramework(false); 1.599 + } 1.600 + 1.601 + var wtu = WebGLTestUtils; 1.602 + var gridRes = params.gridRes; 1.603 + var vertexTolerance = params.tolerance || 0; 1.604 + var fragmentTolerance = vertexTolerance; 1.605 + if ('fragmentTolerance' in params) 1.606 + fragmentTolerance = params.fragmentTolerance || 0; 1.607 + 1.608 + description("Testing GLSL feature: " + params.feature); 1.609 + 1.610 + var width = 32; 1.611 + var height = 32; 1.612 + 1.613 + var console = document.getElementById("console"); 1.614 + var canvas = document.createElement('canvas'); 1.615 + canvas.width = width; 1.616 + canvas.height = height; 1.617 + var gl = wtu.create3DContext(canvas, { antialias: false }); 1.618 + if (!gl) { 1.619 + testFailed("context does not exist"); 1.620 + finishTest(); 1.621 + return; 1.622 + } 1.623 + 1.624 + var canvas2d = document.createElement('canvas'); 1.625 + canvas2d.width = width; 1.626 + canvas2d.height = height; 1.627 + var ctx = canvas2d.getContext("2d"); 1.628 + var imgData = ctx.getImageData(0, 0, width, height); 1.629 + 1.630 + var shaderInfos = [ 1.631 + { type: "vertex", 1.632 + input: "color", 1.633 + output: "vColor", 1.634 + vertexShaderTemplate: vertexShaderTemplate, 1.635 + fragmentShaderTemplate: baseFragmentShader, 1.636 + tolerance: vertexTolerance 1.637 + }, 1.638 + { type: "fragment", 1.639 + input: "vColor", 1.640 + output: "gl_FragColor", 1.641 + vertexShaderTemplate: baseVertexShader, 1.642 + fragmentShaderTemplate: fragmentShaderTemplate, 1.643 + tolerance: fragmentTolerance 1.644 + } 1.645 + ]; 1.646 + for (var ss = 0; ss < shaderInfos.length; ++ss) { 1.647 + var shaderInfo = shaderInfos[ss]; 1.648 + var tests = params.tests; 1.649 + var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types); 1.650 + // Test vertex shaders 1.651 + for (var ii = 0; ii < tests.length; ++ii) { 1.652 + var type = testTypes[ii]; 1.653 + var isVertex = (ss == 0); 1.654 + debug(""); 1.655 + var str = replaceParams(params.testFunc, { 1.656 + func: params.feature, 1.657 + type: type.type, 1.658 + arg0: type.type 1.659 + }); 1.660 + debug("Testing: " + str + " in " + shaderInfo.type + " shader"); 1.661 + 1.662 + var referenceVertexShaderSource = generateReferenceShader( 1.663 + shaderInfo, 1.664 + shaderInfo.vertexShaderTemplate, 1.665 + params, 1.666 + type, 1.667 + tests[ii].source); 1.668 + var referenceFragmentShaderSource = generateReferenceShader( 1.669 + shaderInfo, 1.670 + shaderInfo.fragmentShaderTemplate, 1.671 + params, 1.672 + type, 1.673 + tests[ii].source); 1.674 + var testVertexShaderSource = generateTestShader( 1.675 + shaderInfo, 1.676 + shaderInfo.vertexShaderTemplate, 1.677 + params, 1.678 + tests[ii].source); 1.679 + var testFragmentShaderSource = generateTestShader( 1.680 + shaderInfo, 1.681 + shaderInfo.fragmentShaderTemplate, 1.682 + params, 1.683 + tests[ii].source); 1.684 + var referenceTexture = generateReferenceTexture( 1.685 + gl, 1.686 + tests[ii].generator, 1.687 + isVertex ? gridRes : width, 1.688 + isVertex ? gridRes : height, 1.689 + isVertex); 1.690 + 1.691 + debug(""); 1.692 + wtu.addShaderSource( 1.693 + console, "test vertex shader", testVertexShaderSource); 1.694 + wtu.addShaderSource( 1.695 + console, "test fragment shader", testFragmentShaderSource); 1.696 + debug(""); 1.697 + var refData = drawReferenceImage(canvas, referenceTexture, isVertex); 1.698 + var refImg = wtu.makeImage(canvas); 1.699 + if (isVertex) { 1.700 + var testData = draw( 1.701 + canvas, testVertexShaderSource, referenceFragmentShaderSource); 1.702 + } else { 1.703 + var testData = draw( 1.704 + canvas, referenceVertexShaderSource, testFragmentShaderSource); 1.705 + } 1.706 + var testImg = wtu.makeImage(canvas); 1.707 + var testTolerance = shaderInfo.tolerance; 1.708 + // Provide per-test tolerance so that we can increase it only for those desired. 1.709 + if ('tolerance' in tests[ii]) 1.710 + testTolerance = tests[ii].tolerance || 0; 1.711 + reportResults(refData, refImg, testData, testImg, testTolerance); 1.712 + } 1.713 + } 1.714 + 1.715 + finishTest(); 1.716 + 1.717 + function reportResults(refData, refImage, testData, testImage, tolerance) { 1.718 + var same = true; 1.719 + for (var yy = 0; yy < height; ++yy) { 1.720 + for (var xx = 0; xx < width; ++xx) { 1.721 + var offset = (yy * width + xx) * 4; 1.722 + var imgOffset = ((height - yy - 1) * width + xx) * 4; 1.723 + imgData.data[imgOffset + 0] = 0; 1.724 + imgData.data[imgOffset + 1] = 0; 1.725 + imgData.data[imgOffset + 2] = 0; 1.726 + imgData.data[imgOffset + 3] = 255; 1.727 + if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance || 1.728 + Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance || 1.729 + Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance || 1.730 + Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) { 1.731 + console.appendChild(document.createTextNode('at (' + xx + ',' + yy + '): ref=(' + 1.732 + refData[offset + 0] + ',' + 1.733 + refData[offset + 1] + ',' + 1.734 + refData[offset + 2] + ',' + 1.735 + refData[offset + 3] + ') test=(' + 1.736 + testData[offset + 0] + ',' + 1.737 + testData[offset + 1] + ',' + 1.738 + testData[offset + 2] + ',' + 1.739 + testData[offset + 3] + ')')); 1.740 + console.appendChild(document.createElement('br')); 1.741 + 1.742 + 1.743 + 1.744 + imgData.data[imgOffset] = 255; 1.745 + same = false; 1.746 + } 1.747 + } 1.748 + } 1.749 + 1.750 + var diffImg = null; 1.751 + if (!same) { 1.752 + ctx.putImageData(imgData, 0, 0); 1.753 + diffImg = wtu.makeImage(canvas2d); 1.754 + } 1.755 + 1.756 + var div = document.createElement("div"); 1.757 + div.className = "testimages"; 1.758 + wtu.insertImage(div, "ref", refImg); 1.759 + wtu.insertImage(div, "test", testImg); 1.760 + if (diffImg) { 1.761 + wtu.insertImage(div, "diff", diffImg); 1.762 + } 1.763 + div.appendChild(document.createElement('br')); 1.764 + 1.765 + console.appendChild(div); 1.766 + 1.767 + if (!same) { 1.768 + testFailed("images are different"); 1.769 + } else { 1.770 + testPassed("images are the same"); 1.771 + } 1.772 + 1.773 + console.appendChild(document.createElement('hr')); 1.774 + } 1.775 + 1.776 + function draw(canvas, vsSource, fsSource) { 1.777 + var program = wtu.loadProgram(gl, vsSource, fsSource, testFailed); 1.778 + 1.779 + var posLoc = gl.getAttribLocation(program, "aPosition"); 1.780 + WebGLTestUtils.setupQuad(gl, gridRes, posLoc); 1.781 + 1.782 + gl.useProgram(program); 1.783 + gl.clearColor(0, 0, 1, 1); 1.784 + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 1.785 + gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0); 1.786 + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); 1.787 + 1.788 + var img = new Uint8Array(width * height * 4); 1.789 + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); 1.790 + return img; 1.791 + } 1.792 + 1.793 + function drawReferenceImage(canvas, texture, isVertex) { 1.794 + var program; 1.795 + if (isVertex) { 1.796 + var halfTexel = 0.5 / (1.0 + gridRes); 1.797 + program = WebGLTestUtils.setupTexturedQuadWithTexCoords( 1.798 + gl, [halfTexel, halfTexel], [1.0 - halfTexel, 1.0 - halfTexel]); 1.799 + } else { 1.800 + program = WebGLTestUtils.setupTexturedQuad(gl); 1.801 + } 1.802 + 1.803 + gl.activeTexture(gl.TEXTURE0); 1.804 + gl.bindTexture(gl.TEXTURE_2D, texture); 1.805 + var texLoc = gl.getUniformLocation(program, "tex"); 1.806 + gl.uniform1i(texLoc, 0); 1.807 + wtu.drawQuad(gl); 1.808 + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw"); 1.809 + 1.810 + var img = new Uint8Array(width * height * 4); 1.811 + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img); 1.812 + return img; 1.813 + } 1.814 + 1.815 + /** 1.816 + * Creates and returns a texture containing the reference image for 1.817 + * the function being tested. Exactly how the function is evaluated, 1.818 + * and the size of the returned texture, depends on whether we are 1.819 + * testing a vertex or fragment shader. If a fragment shader, the 1.820 + * function is evaluated at the pixel centers. If a vertex shader, 1.821 + * the function is evaluated at the triangle's vertices, and the 1.822 + * resulting texture must be offset by half a texel during 1.823 + * rendering. 1.824 + * 1.825 + * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use to generate texture objects. 1.826 + * @param {!function(number,number,number,number): !Array.<number>} generator The reference image generator function. 1.827 + * @param {number} width The width of the texture to generate if testing a fragment shader; the grid resolution if testing a vertex shader. 1.828 + * @param {number} height The height of the texture to generate if testing a fragment shader; the grid resolution if testing a vertex shader. 1.829 + * @param {boolean} isVertex True if generating a reference image for a vertex shader; false if for a fragment shader. 1.830 + * @return {!WebGLTexture} The texture object that was generated. 1.831 + */ 1.832 + function generateReferenceTexture( 1.833 + gl, 1.834 + generator, 1.835 + width, 1.836 + height, 1.837 + isVertex) { 1.838 + 1.839 + // Note: the math in this function must match that in the vertex and 1.840 + // fragment shader templates above. 1.841 + function computeTexCoord(x) { 1.842 + return x * 0.5 + 0.5; 1.843 + } 1.844 + 1.845 + function computeColor(texCoordX, texCoordY) { 1.846 + return [ texCoordX, 1.847 + texCoordY, 1.848 + texCoordX * texCoordY, 1.849 + (1.0 - texCoordX) * texCoordY * 0.5 + 0.5 ]; 1.850 + } 1.851 + 1.852 + function clamp(value, minVal, maxVal) { 1.853 + return Math.max(minVal, Math.min(value, maxVal)); 1.854 + } 1.855 + 1.856 + // Evaluates the function at clip coordinates (px,py), storing the 1.857 + // result in the array "pixel". Each channel's result is clamped 1.858 + // between 0 and 255. 1.859 + function evaluateAtClipCoords(px, py, pixel) { 1.860 + var tcx = computeTexCoord(px); 1.861 + var tcy = computeTexCoord(py); 1.862 + 1.863 + var color = computeColor(tcx, tcy); 1.864 + 1.865 + var output = generator(color[0], color[1], color[2], color[3]); 1.866 + 1.867 + // Multiply by 256 to get even distribution for all values between 0 and 1. 1.868 + // Use rounding rather than truncation to more closely match the GPU's behavior. 1.869 + pixel[0] = clamp(Math.round(256 * output[0]), 0, 255); 1.870 + pixel[1] = clamp(Math.round(256 * output[1]), 0, 255); 1.871 + pixel[2] = clamp(Math.round(256 * output[2]), 0, 255); 1.872 + pixel[3] = clamp(Math.round(256 * output[3]), 0, 255); 1.873 + } 1.874 + 1.875 + function fillFragmentReference() { 1.876 + var data = new Uint8Array(4 * width * height); 1.877 + 1.878 + var horizTexel = 1.0 / width; 1.879 + var vertTexel = 1.0 / height; 1.880 + var halfHorizTexel = 0.5 * horizTexel; 1.881 + var halfVertTexel = 0.5 * vertTexel; 1.882 + 1.883 + var pixel = new Array(4); 1.884 + 1.885 + for (var yi = 0; yi < height; ++yi) { 1.886 + for (var xi = 0; xi < width; ++xi) { 1.887 + // The function must be evaluated at pixel centers. 1.888 + 1.889 + // Compute desired position in clip space 1.890 + var px = -1.0 + 2.0 * (halfHorizTexel + xi * horizTexel); 1.891 + var py = -1.0 + 2.0 * (halfVertTexel + yi * vertTexel); 1.892 + 1.893 + evaluateAtClipCoords(px, py, pixel); 1.894 + var index = 4 * (width * yi + xi); 1.895 + data[index + 0] = pixel[0]; 1.896 + data[index + 1] = pixel[1]; 1.897 + data[index + 2] = pixel[2]; 1.898 + data[index + 3] = pixel[3]; 1.899 + } 1.900 + } 1.901 + 1.902 + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, 1.903 + gl.RGBA, gl.UNSIGNED_BYTE, data); 1.904 + } 1.905 + 1.906 + function fillVertexReference() { 1.907 + // We generate a texture which contains the evaluation of the 1.908 + // function at the vertices of the triangle mesh. It is expected 1.909 + // that the width and the height are identical, and equivalent 1.910 + // to the grid resolution. 1.911 + if (width != height) { 1.912 + throw "width and height must be equal"; 1.913 + } 1.914 + 1.915 + var texSize = 1 + width; 1.916 + var data = new Uint8Array(4 * texSize * texSize); 1.917 + 1.918 + var step = 2.0 / width; 1.919 + 1.920 + var pixel = new Array(4); 1.921 + 1.922 + for (var yi = 0; yi < texSize; ++yi) { 1.923 + for (var xi = 0; xi < texSize; ++xi) { 1.924 + // The function is evaluated at the triangles' vertices. 1.925 + 1.926 + // Compute desired position in clip space 1.927 + var px = -1.0 + (xi * step); 1.928 + var py = -1.0 + (yi * step); 1.929 + 1.930 + evaluateAtClipCoords(px, py, pixel); 1.931 + var index = 4 * (texSize * yi + xi); 1.932 + data[index + 0] = pixel[0]; 1.933 + data[index + 1] = pixel[1]; 1.934 + data[index + 2] = pixel[2]; 1.935 + data[index + 3] = pixel[3]; 1.936 + } 1.937 + } 1.938 + 1.939 + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texSize, texSize, 0, 1.940 + gl.RGBA, gl.UNSIGNED_BYTE, data); 1.941 + } 1.942 + 1.943 + //---------------------------------------------------------------------- 1.944 + // Body of generateReferenceTexture 1.945 + // 1.946 + 1.947 + var texture = gl.createTexture(); 1.948 + gl.bindTexture(gl.TEXTURE_2D, texture); 1.949 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 1.950 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 1.951 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 1.952 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 1.953 + 1.954 + if (isVertex) { 1.955 + fillVertexReference(); 1.956 + } else { 1.957 + fillFragmentReference(); 1.958 + } 1.959 + 1.960 + return texture; 1.961 + } 1.962 +}; 1.963 + 1.964 +return { 1.965 + /** 1.966 + * runs a bunch of GLSL tests using the passed in parameters 1.967 + * The parameters are: 1.968 + * 1.969 + * feature: 1.970 + * the name of the function being tested (eg, sin, dot, 1.971 + * normalize) 1.972 + * 1.973 + * testFunc: 1.974 + * The prototype of function to be tested not including the 1.975 + * return type. 1.976 + * 1.977 + * emuFunc: 1.978 + * A base function that can be used to generate emulation 1.979 + * functions. Example for 'ceil' 1.980 + * 1.981 + * float $(func)_base(float value) { 1.982 + * float m = mod(value, 1.0); 1.983 + * return m != 0.0 ? (value + 1.0 - m) : value; 1.984 + * } 1.985 + * 1.986 + * args: 1.987 + * The arguments to the function 1.988 + * 1.989 + * baseArgs: (optional) 1.990 + * The arguments when a base function is used to create an 1.991 + * emulation function. For example 'float sign_base(float v)' 1.992 + * is used to implemenent vec2 sign_emu(vec2 v). 1.993 + * 1.994 + * simpleEmu: 1.995 + * if supplied, the code that can be used to generate all 1.996 + * functions for all types. 1.997 + * 1.998 + * Example for 'normalize': 1.999 + * 1.1000 + * $(type) $(func)_emu($(args)) { 1.1001 + * return value / length(value); 1.1002 + * } 1.1003 + * 1.1004 + * gridRes: (optional) 1.1005 + * The resolution of the mesh to generate. The default is a 1.1006 + * 1x1 grid but many vertex shaders need a higher resolution 1.1007 + * otherwise the only values passed in are the 4 corners 1.1008 + * which often have the same value. 1.1009 + * 1.1010 + * tests: 1.1011 + * The code for each test. It is assumed the tests are for 1.1012 + * float, vec2, vec3, vec4 in that order. 1.1013 + * 1.1014 + * tolerance: (optional) 1.1015 + * Allow some tolerance in the comparisons. The tolerance is applied to 1.1016 + * both vertex and fragment shaders. The default tolerance is 0, meaning 1.1017 + * the values have to be identical. 1.1018 + * 1.1019 + * fragmentTolerance: (optional) 1.1020 + * Specify a tolerance which only applies to fragment shaders. The 1.1021 + * fragment-only tolerance will override the shared tolerance for 1.1022 + * fragment shaders if both are specified. Fragment shaders usually 1.1023 + * use mediump float precision so they sometimes require higher tolerance 1.1024 + * than vertex shaders which use highp by default. 1.1025 + */ 1.1026 + runFeatureTest: runFeatureTest, 1.1027 + 1.1028 + /* 1.1029 + * Runs a bunch of GLSL tests using the passed in parameters 1.1030 + * 1.1031 + * The parameters are: 1.1032 + * 1.1033 + * tests: 1.1034 + * Array of tests. For each test the following parameters are expected 1.1035 + * 1.1036 + * name: 1.1037 + * some description of the test 1.1038 + * reference: 1.1039 + * parameters for the reference shader (see below) 1.1040 + * test: 1.1041 + * parameters for the test shader (see below) 1.1042 + * 1.1043 + * The parameter for the reference and test shaders are 1.1044 + * 1.1045 + * shader: the GLSL for the shader 1.1046 + * subs: any substitutions you wish to define for the shader. 1.1047 + * 1.1048 + * Each shader is created from a basic template that 1.1049 + * defines an input and an output. You can see the 1.1050 + * templates at the top of this file. The input and output 1.1051 + * change depending on whether or not we are generating 1.1052 + * a vertex or fragment shader. 1.1053 + * 1.1054 + * All this code function does is a bunch of string substitutions. 1.1055 + * A substitution is defined by $(name). If name is found in 1.1056 + * the 'subs' parameter it is replaced. 4 special names exist. 1.1057 + * 1.1058 + * 'input' the input to your GLSL. Always a vec4. All change 1.1059 + * from 0 to 1 over the quad to be drawn. 1.1060 + * 1.1061 + * 'output' the output color. Also a vec4 1.1062 + * 1.1063 + * 'emu' a place to insert extra stuff 1.1064 + * 'extra' a place to insert extra stuff. 1.1065 + * 1.1066 + * You can think of the templates like this 1.1067 + * 1.1068 + * $(extra) 1.1069 + * $(emu) 1.1070 + * 1.1071 + * void main() { 1.1072 + * // do math to calculate input 1.1073 + * ... 1.1074 + * 1.1075 + * $(shader) 1.1076 + * } 1.1077 + * 1.1078 + * Your shader first has any subs you provided applied as well 1.1079 + * as 'input' and 'output' 1.1080 + * 1.1081 + * It is then inserted into the template which is also provided 1.1082 + * with your subs. 1.1083 + * 1.1084 + * gridRes: (optional) 1.1085 + * The resolution of the mesh to generate. The default is a 1.1086 + * 1x1 grid but many vertex shaders need a higher resolution 1.1087 + * otherwise the only values passed in are the 4 corners 1.1088 + * which often have the same value. 1.1089 + * 1.1090 + * tolerance: (optional) 1.1091 + * Allow some tolerance in the comparisons. The tolerance is applied to 1.1092 + * both vertex and fragment shaders. The default tolerance is 0, meaning 1.1093 + * the values have to be identical. 1.1094 + * 1.1095 + * fragmentTolerance: (optional) 1.1096 + * Specify a tolerance which only applies to fragment shaders. The 1.1097 + * fragment-only tolerance will override the shared tolerance for 1.1098 + * fragment shaders if both are specified. Fragment shaders usually 1.1099 + * use mediump float precision so they sometimes require higher tolerance 1.1100 + * than vertex shaders which use highp. 1.1101 + */ 1.1102 + runBasicTest: runBasicTest, 1.1103 + 1.1104 + /** 1.1105 + * Runs a bunch of GLSL tests using the passed in parameters. The 1.1106 + * expected results are computed as a reference image in JavaScript 1.1107 + * instead of on the GPU. The parameters are: 1.1108 + * 1.1109 + * feature: 1.1110 + * the name of the function being tested (eg, sin, dot, 1.1111 + * normalize) 1.1112 + * 1.1113 + * testFunc: 1.1114 + * The prototype of function to be tested not including the 1.1115 + * return type. 1.1116 + * 1.1117 + * args: 1.1118 + * The arguments to the function 1.1119 + * 1.1120 + * gridRes: (optional) 1.1121 + * The resolution of the mesh to generate. The default is a 1.1122 + * 1x1 grid but many vertex shaders need a higher resolution 1.1123 + * otherwise the only values passed in are the 4 corners 1.1124 + * which often have the same value. 1.1125 + * 1.1126 + * tests: 1.1127 + * Array of tests. It is assumed the tests are for float, vec2, 1.1128 + * vec3, vec4 in that order. For each test the following 1.1129 + * parameters are expected: 1.1130 + * 1.1131 + * source: the GLSL source code for the tests 1.1132 + * 1.1133 + * generator: a JavaScript function taking four parameters 1.1134 + * which evaluates the same function as the GLSL source, 1.1135 + * returning its result as a newly allocated array. 1.1136 + * 1.1137 + * tolerance: (optional) a per-test tolerance. 1.1138 + * 1.1139 + * extra: (optional) 1.1140 + * Extra GLSL code inserted at the top of each test's shader. 1.1141 + * 1.1142 + * tolerance: (optional) 1.1143 + * Allow some tolerance in the comparisons. The tolerance is applied to 1.1144 + * both vertex and fragment shaders. The default tolerance is 0, meaning 1.1145 + * the values have to be identical. 1.1146 + * 1.1147 + * fragmentTolerance: (optional) 1.1148 + * Specify a tolerance which only applies to fragment shaders. The 1.1149 + * fragment-only tolerance will override the shared tolerance for 1.1150 + * fragment shaders if both are specified. Fragment shaders usually 1.1151 + * use mediump float precision so they sometimes require higher tolerance 1.1152 + * than vertex shaders which use highp. 1.1153 + */ 1.1154 + runReferenceImageTest: runReferenceImageTest, 1.1155 + 1.1156 + none: false 1.1157 +}; 1.1158 + 1.1159 +}()); 1.1160 +