content/canvas/test/webgl-conformance/conformance/resources/glsl-generator.js

changeset 0
6474c204b198
     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 +

mercurial