| <!-- |
| 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. |
| --> |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>WebGL uniform packing restrctions Conformance Test</title> |
| <link rel="stylesheet" href="../../../resources/js-test-style.css"/> |
| <link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/> |
| <script src="../../../js/js-test-pre.js"></script> |
| <script src="../../../js/webgl-test-utils.js"></script> |
| <script src="../../../js/glsl-conformance-test.js"></script> |
| </head> |
| <body> |
| <div id="description"></div> |
| <div id="console"></div> |
| <canvas id="example" width="2" height="2"> </canvas> |
| <script id="vshader" type="x-shader/x-vertex"> |
| attribute vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| </script> |
| <script id="fshader" type="x-shader/x-vertex"> |
| precision mediump float; |
| varying vec4 v_varying; |
| void main() |
| { |
| gl_FragColor = v_varying; |
| } |
| </script> |
| <script id="vshaderArrayTest" type="x-shader/x-vertex"> |
| attribute vec4 a_position; |
| varying vec4 v_varying; |
| uniform $(type) u_uniform[$(numTestType)]; |
| void main() |
| { |
| v_varying = $(result); |
| gl_Position = a_position; |
| } |
| </script> |
| <script id="fshaderArrayTest" type="x-shader/x-fragment"> |
| precision mediump float; |
| uniform $(type) u_uniform[$(numTestType)]; |
| void main() |
| { |
| gl_FragColor = $(result); |
| } |
| </script> |
| <script id="vshaderUniformTest" type="x-shader/x-fragment"> |
| attribute vec4 a_position; |
| varying vec4 v_varying; |
| $(uniforms) |
| void main() |
| { |
| $(code) |
| v_varying = $(result); |
| gl_Position = a_position; |
| } |
| </script> |
| <script id="fshaderUniformTest" type="x-shader/x-fragment"> |
| precision mediump float; |
| $(uniforms) |
| void main() |
| { |
| $(code) |
| gl_FragColor = $(result); |
| } |
| </script> |
| <script> |
| "use strict"; |
| description(); |
| debug(""); |
| var wtu = WebGLTestUtils; |
| var gl = wtu.create3DContext("example"); |
| |
| var uniformTypes = [ |
| { type: "bool", componentsPerRow: 1, rows: 1, fType: "float", uniToF: "float(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0, 0, 0)"}, |
| { type: "float", componentsPerRow: 1, rows: 1, fType: "float", uniToF: "u_uniform$(id)$(index)", fToVec4: "vec4($(f), 0, 0, 0)"}, |
| { type: "int", componentsPerRow: 1, rows: 1, fType: "float", uniToF: "float(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0, 0, 0)"}, |
| { type: "vec2", componentsPerRow: 2, rows: 1, fType: "vec2", uniToF: "u_uniform$(id)$(index)", fToVec4: "vec4($(f), 0, 0)"}, |
| { type: "ivec2", componentsPerRow: 2, rows: 1, fType: "vec2", uniToF: "vec2(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0, 0)"}, |
| { type: "bvec2", componentsPerRow: 2, rows: 1, fType: "vec2", uniToF: "vec2(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0, 0)"}, |
| { type: "vec3", componentsPerRow: 3, rows: 1, fType: "vec3", uniToF: "u_uniform$(id)$(index)", fToVec4: "vec4($(f), 0)"}, |
| { type: "ivec3", componentsPerRow: 3, rows: 1, fType: "vec3", uniToF: "vec3(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0)"}, |
| { type: "bvec3", componentsPerRow: 3, rows: 1, fType: "vec3", uniToF: "vec3(u_uniform$(id)$(index))", fToVec4: "vec4($(f), 0)"}, |
| { type: "vec4", componentsPerRow: 4, rows: 1, fType: "vec4", uniToF: "u_uniform$(id)$(index)", fToVec4: "$(f)"}, |
| { type: "ivec4", componentsPerRow: 4, rows: 1, fType: "vec4", uniToF: "vec4(u_uniform$(id)$(index))", fToVec4: "$(f)"}, |
| { type: "bvec4", componentsPerRow: 4, rows: 1, fType: "vec4", uniToF: "vec4(u_uniform$(id)$(index))", fToVec4: "$(f)"}, |
| // Yes, the spec says mat2 takes 4 columns, 2 rows. |
| { type: "mat2", componentsPerRow: 4, rows: 2, fType: "vec2", uniToF: "vec2(u_uniform$(id)$(index)[0])", fToVec4: "vec4($(f), 0, 0)"}, |
| { type: "mat3", componentsPerRow: 3, rows: 3, fType: "vec3", uniToF: "vec3(u_uniform$(id)$(index)[0])", fToVec4: "vec4($(f), 0)"}, |
| { type: "mat4", componentsPerRow: 4, rows: 4, fType: "vec4", uniToF: "vec4(u_uniform$(id)$(index)[0])", fToVec4: "$(f)"}, |
| // Samplers generally have more restrictive limits. |
| // { type: "sampler2D", componentsPerRow: 1, rows: 1, code: "vec4(texture2D(u_uniform[$(index)], vec2(0, 0)))", }, |
| // { type: "samplerCube", componentsPerRow: 1, rows: 1, code: "vec4(textureCube(u_uniform[$(index)], vec3(0, 0, 0)))", }, |
| ]; |
| |
| var vBaseSource = wtu.getScript("vshader"); |
| var fBaseSource = wtu.getScript("fshader"); |
| var vArrayTestSource = wtu.getScript("vshaderArrayTest"); |
| var fArrayTestSource = wtu.getScript("fshaderArrayTest"); |
| var vUniformTestSource = wtu.getScript("vshaderUniformTest"); |
| var fUniformTestSource = wtu.getScript("fshaderUniformTest"); |
| |
| var tests = []; |
| var shaderTypes = [ |
| { type: "vertex", |
| // For tests that expect failure which shader might fail. |
| vertExpectation: false, |
| fragExpectation: true, |
| vertArrayTest: vArrayTestSource, |
| fragArrayTest: fBaseSource, |
| vertUniformTest: vUniformTestSource, |
| fragUniformTest: fBaseSource, |
| maxVectors: gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS), |
| minVectors: 127, // GLSL ES 1.0.17 Appendix A.7 and A.8. Reserve one row for constants in the code, hence 128 - 1. |
| }, |
| { type: "fragment", |
| // For tests that expect failure which shader might fail. |
| vertExpectation: true, |
| fragExpectation: false, |
| vertArrayTest: vBaseSource, |
| fragArrayTest: fArrayTestSource, |
| vertUniformTest: vBaseSource, |
| fragUniformTest: fUniformTestSource, |
| maxVectors: gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS), |
| minVectors: 15, // GLSL ES 1.0.17 Appendix A.8 - minimum value of gl_maxFragmentUniformVectors is 16. Again, reserve a row for constants. |
| }, |
| ]; |
| for (var ss = 0; ss < shaderTypes.length; ++ss) { |
| var shaderType = shaderTypes[ss]; |
| debug("max " + shaderType.type + ": " + shaderType.maxVectors); |
| for (var ii = 0; ii < uniformTypes.length; ++ii) { |
| var info = uniformTypes[ii]; |
| wtu.log("checking: " + info.type); |
| // Compute the maximum amount of this type allowed in a single array. |
| var maxInArray = Math.floor(shaderType.maxVectors / info.rows); |
| // Compute the minimum required to work in a single array. |
| var minVars = Math.floor(shaderType.minVectors / info.rows); |
| // Compute the maximum allowed as single elements |
| var maxPerRow = Math.floor(4 / info.componentsPerRow); |
| var maxPacked = Math.floor(shaderType.maxVectors * maxPerRow / info.rows); |
| |
| // Test array[1] of the type |
| var uniToF = wtu.replaceParams(info.uniToF, {id: "", index: "[0]"}); |
| var vec4 = wtu.replaceParams(info.fToVec4, {f: uniToF}); |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertArrayTest, {numTestType: 1, result: vec4}, info), |
| vShaderSuccess: true, |
| fShaderSource: wtu.replaceParams(shaderType.fragArrayTest, {numTestType: 1, result: vec4}, info), |
| fShaderSuccess: true, |
| linkSuccess: true, |
| passMsg: shaderType.type + " shader with uniform array of " + info.type + " with 1 element should succeed", |
| }); |
| |
| // Note: We can't test an array filling all uniform space as actual GL drivers are |
| // only required to be able to do the minimum number. After that it can fail for |
| // multiple reasons, including uniform registers being reserved for the implementation's |
| // own use. Constants also take up uniform registers. |
| |
| // Test required number of uniforms |
| var uniToF = wtu.replaceParams(info.uniToF, {id: "", index: "[" + (minVars - 1) + "]"}); |
| var vec4 = wtu.replaceParams(info.fToVec4, {f: uniToF}); |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertArrayTest, {numTestType: minVars, result: vec4}, info), |
| vShaderSuccess: true, |
| fShaderSource: wtu.replaceParams(shaderType.fragArrayTest, {numTestType: minVars, result: vec4}, info), |
| fShaderSuccess: true, |
| linkSuccess: true, |
| passMsg: shaderType.type + " shader with uniform array of " + info.type + " with " + minVars + " elements (the minimum required) should succeed", |
| }); |
| |
| // Test array[max + 1] accessing last element. WebGL requires this to fail. |
| var uniToF = wtu.replaceParams(info.uniToF, {id: "", index: "[" + maxInArray + "]"}); |
| var vec4 = wtu.replaceParams(info.fToVec4, {f: uniToF}); |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertArrayTest, {numTestType: maxInArray + 1, result: vec4}, info), |
| vShaderSuccess: shaderType.vertExpectation, |
| fShaderSource: wtu.replaceParams(shaderType.fragArrayTest, {numTestType: maxInArray + 1, result: vec4}, info), |
| fShaderSuccess: shaderType.fragExpectation, |
| linkSuccess: false, |
| passMsg: shaderType.type + " shader with uniform array of " + info.type + " with " + (maxInArray + 1) + " elements (one past maximum) accessing last element should fail", |
| }); |
| |
| // Test array[max + 1] accessing first element. WebGL requires this to fail but ES allows truncating array. |
| var uniToF = wtu.replaceParams(info.uniToF, {id: "", index: "[0]"}); |
| var vec4 = wtu.replaceParams(info.fToVec4, {f: uniToF}); |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertArrayTest, {numTestType: maxInArray + 1, result: vec4}, info), |
| vShaderSuccess: shaderType.vertExpectation, |
| fShaderSource: wtu.replaceParams(shaderType.fragArrayTest, {numTestType: maxInArray + 1, result: vec4}, info), |
| fShaderSuccess: shaderType.fragExpectation, |
| linkSuccess: false, |
| passMsg: shaderType.type + " shader with uniform array of " + info.type + " with " + (maxInArray + 1) + " elements (one past maximum) accessing first element should fail", |
| }); |
| |
| // Note: We can't test max uniforms as actual GL drivers are only required to be able |
| // to do the minimum number. After that it can fail for multiple reasons, including |
| // uniform registers being reserved for the implementation's own use or also instruction |
| // space limitations. Strictly speaking, guaranteed supported length of a shader |
| // executable is defined by the GLES2 conformance tests according to GLSL ES 1.0.17 |
| // Appendix A.2. This does not give us an exact limit: this test only aims to fit within |
| // instruction space limits imposed by existing GLES2 compliant hardware. |
| |
| var generateCode = function(numVars) { |
| var uniforms = []; |
| var sumTerms = []; |
| for (var uu = 0; uu < numVars; ++uu) { |
| uniforms.push(" uniform " + info.type + " u_uniform" + uu + ";"); |
| sumTerms.push(wtu.replaceParams(info.uniToF, {id: uu, index: ""})); |
| } |
| return { |
| uniforms: uniforms.join("\n"), |
| code: info.fType + " sum = " + sumTerms.join(" + \n ") + ";", |
| result: wtu.replaceParams(info.fToVec4, {f: 'sum'}) |
| }; |
| }; |
| |
| // Test max+1 uniforms of type. |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertUniformTest, generateCode(maxPacked + 1), info), |
| vShaderSuccess: shaderType.vertExpectation, |
| fShaderSource: wtu.replaceParams(shaderType.fragUniformTest, generateCode(maxPacked + 1), info), |
| fShaderSuccess: shaderType.fragExpectation, |
| linkSuccess: false, |
| passMsg: shaderType.type + " shader with " + (maxPacked + 1) + " uniforms of " + info.type + " (one past maximum) should fail", |
| }); |
| |
| // Test required uniforms of type. |
| tests.push({ |
| vShaderSource: wtu.replaceParams(shaderType.vertUniformTest, generateCode(minVars), info), |
| vShaderSuccess: true, |
| fShaderSource: wtu.replaceParams(shaderType.fragUniformTest, generateCode(minVars), info), |
| fShaderSuccess: true, |
| linkSuccess: true, |
| passMsg: shaderType.type + " shader with " + minVars + " uniforms of " + info.type + " (the minimum required) should succeed", |
| }); |
| } |
| } |
| GLSLConformanceTester.runTests(tests); |
| var successfullyParsed = true; |
| </script> |
| </body> |
| </html> |
| |