summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js247
1 files changed, 247 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
new file mode 100644
index 0000000000..1202b7868c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
@@ -0,0 +1,247 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+NoOverOptimizeOnUniformArrayTester = (function(){
+
+var vshader = [
+ "attribute vec4 a_position;",
+ "void main()",
+ "{",
+ " gl_Position = a_position;",
+ "}"
+].join('\n');
+
+var fshader_max = [
+ "precision mediump float;",
+ "uniform vec4 colora[$(maxUniformVectors)];",
+ "void main()",
+ "{",
+ " gl_FragColor = vec4(colora[$(usedUniformVector)]);",
+ "}"
+].join('\n');
+
+var fshader_max_ab_ab = [
+ "precision mediump float;",
+ "uniform vec4 $(decl1);",
+ "uniform vec4 $(decl2);",
+ "void main()",
+ "{",
+ "gl_FragColor = vec4($(usage1) + $(usage2));",
+ "}"
+].join('\n');
+
+// MaxInt32 is 2^32-1. We need +1 of that to test overflow conditions
+var MaxInt32PlusOne = 4294967296;
+
+function setupTests(gl) {
+ var tests = [];
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+
+ // This test is to test drivers the have bugs related to optimizing
+ // an array of uniforms when only 1 of those uniforms is used.
+ tests.push({
+ desc: "using last element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: maxUniformVectors - 1,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+ tests.push({
+ desc: "using first element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: 0,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+
+ // Generate test shaders. We're trying to force the driver to
+ // overflow from 1 array into the next if it optimizes. So for example if it was C
+ //
+ // int big[4];
+ // int little[1];
+ // big[5] = 124;
+ //
+ // Would end up setting little[0] instead of big. Some drivers optimize
+ // where if you only use say 'big[3]' it will actually only allocate just 1 element
+ // for big.
+ //
+ // But, some drivers have a bug where the fact that they optimized big to 1 element
+ // does not get passed down to glUniform so when setting the uniform 'big[3]' they
+ // overwrite memory.
+ //
+ // If the driver crashes, yea. We found a bug. We can block the driver.
+ // Otherwise we try various combinations so that setting 'little[0]' first
+ // and then setting all elements of 'big' we hope it will overwrite 'little[0]'
+ // which will show the bug and again we can block the driver.
+ //
+ // We don't know how the driver will order, in memory, the various uniforms
+ // or for that matter we don't even know if they will be contiguous in memory
+ // but to hopefully expose any bugs we try various combinations.
+ //
+ // It could be the compiler orders uniforms alphabetically.
+ // It could be it orders them in order of declaration.
+ // It could be it orders them in order of usage.
+ //
+ // We also test using only first element of big or just the last element of big.
+ //
+ for (var nameOrder = 0; nameOrder < 2; ++nameOrder) {
+ var name1 = nameOrder ? "colora" : "colorb";
+ var name2 = nameOrder ? "colorb" : "colora";
+ for (var last = 0; last < 2; ++last) {
+ var usedUniformVector = last ? maxUniformVectors - 2 : 0;
+ for (var declOrder = 0; declOrder < 2; ++declOrder) {
+ var bigName = declOrder ? name1 : name2;
+ var littleName = declOrder ? name2 : name1;
+ var decl1 = bigName + "[" + (maxUniformVectors - 1) + "]";
+ var decl2 = littleName + "[1]";
+ if (declOrder) {
+ var t = decl1;
+ decl1 = decl2;
+ decl2 = t;
+ }
+ for (var usageOrder = 0; usageOrder < 2; ++usageOrder) {
+ var usage1 = bigName + "[" + usedUniformVector + "]";
+ var usage2 = littleName + "[0]";
+ if (usageOrder) {
+ var t = usage1;
+ usage1 = usage2;
+ usage2 = t;
+ }
+ var fSrc = wtu.replaceParams(fshader_max_ab_ab, {
+ decl1: decl1,
+ decl2: decl2,
+ usage1: usage1,
+ usage2: usage2,
+ });
+ var desc = "testing: " + name1 + ":" + name2 + " using " + (last ? "last" : "first") +
+ " creating uniforms " + decl1 + " " + decl2 + " and accessing " + usage1 + " " + usage2;
+ tests.push({
+ desc: desc,
+ maxUniformVectors: maxUniformVectors - 1,
+ usedUniformVector: usedUniformVector,
+ source: fSrc,
+ color: [0, 0, 0, 1],
+ arrayName: bigName,
+ extraName: littleName,
+ });
+ }
+ }
+ }
+ }
+ return tests;
+};
+
+function testUniformOptimizationIssues(test) {
+ debug("");
+ debug(test.desc);
+ var fshader = test.source;
+ if (!fshader) {
+ fshader = wtu.replaceParams(fshader_max, test);
+ }
+
+ var consoleElem = document.getElementById("console");
+ wtu.addShaderSource(
+ consoleElem, "vertex shader", vshader);
+ wtu.addShaderSource(
+ consoleElem, "fragment shader", fshader);
+
+ var program = wtu.loadProgram(gl, vshader, fshader);
+ gl.useProgram(program);
+
+ var colorbLocation = gl.getUniformLocation(program, test.extraName + "[0]");
+ if (colorbLocation) {
+ gl.uniform4fv(colorbLocation, [0, 1, 0, 0]);
+ }
+
+ // Ensure that requesting an array uniform past MaxInt32PlusOne returns no uniform
+ var nameMaxInt32PlusOne = test.arrayName + "[" + (test.usedUniformVector + MaxInt32PlusOne) + "]";
+ assertMsg(gl.getUniformLocation(program, nameMaxInt32PlusOne) === null,
+ "Requesting " + nameMaxInt32PlusOne + " uniform should return a null uniform location");
+
+ // Set just the used uniform
+ var name = test.arrayName + "[" + test.usedUniformVector + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ gl.uniform4fv(uniformLocation, test.color);
+ wtu.setupIndexedQuad(gl, 1);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Set all the unused uniforms
+ var locations = [];
+ var allRequiredUniformLocationsQueryable = true;
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var name = test.arrayName + "[" + ii + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ locations.push(uniformLocation);
+ if (ii == test.usedUniformVector) {
+ continue;
+ }
+ // Locations > usedUnformVector may not exist.
+ // Locations <= usedUniformVector MUST exist.
+ if (ii <= test.usedUniformVector && (uniformLocation === undefined || uniformLocation === null)) {
+ allRequiredUniformLocationsQueryable = false;
+ }
+ gl.uniform4fv(uniformLocation, [1, 0, 0, 1]);
+ }
+ if (allRequiredUniformLocationsQueryable) {
+ testPassed("allRequiredUniformLocationsQueryable is true.");
+ }
+ else {
+ testFailed("allRequiredUniformLocationsQueryable should be true. Was false.");
+ }
+ var positionLoc = gl.getAttribLocation(program, "a_position");
+ wtu.setupIndexedQuad(gl, 1, positionLoc);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Check we can read & write each uniform.
+ // Note: uniforms past test.usedUniformVector might not exist.
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ gl.uniform4fv(locations[ii], [ii + 4, ii + 2, ii + 3, ii + 1]);
+ }
+
+ var kEpsilon = 0.01;
+ var isSame = function(v1, v2) {
+ return Math.abs(v1 - v2) < kEpsilon;
+ };
+
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var location = locations[ii];
+ if (location) {
+ var value = gl.getUniform(program, locations[ii]);
+ if (!isSame(value[0], ii + 4) ||
+ !isSame(value[1], ii + 2) ||
+ !isSame(value[2], ii + 3) ||
+ !isSame(value[3], ii + 1)) {
+ testFailed("location: " + ii + " was not correct value");
+ break;
+ }
+ }
+ }
+}
+
+function runOneTest(gl, test) {
+ testUniformOptimizationIssues(test);
+};
+
+function runTests(gl, tests) {
+ debug("");
+ debug("Test drivers don't over optimize unused array elements");
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ runOneTest(gl, tests[ii]);
+ }
+};
+
+return {
+ setupTests : setupTests,
+ runTests : runTests
+};
+
+}());