summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js1132
1 files changed, 1132 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js
new file mode 100644
index 0000000000..fa9666de56
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js
@@ -0,0 +1,1132 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('modules.shared.glsShaderLibraryCase');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase;
+var tcuTestCase = framework.common.tcuTestCase;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+var gluDrawUtil = framework.opengl.gluDrawUtil;
+
+ /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_WIDTH = 128;
+ /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_HEIGHT = 128;
+
+/**
+ * Shader compilation expected result enum
+ * @enum {number}
+ */
+glsShaderLibraryCase.expectResult = {
+ EXPECT_PASS: 0,
+ EXPECT_COMPILE_FAIL: 1,
+ EXPECT_LINK_FAIL: 2,
+ EXPECT_COMPILE_LINK_FAIL: 3,
+ EXPECT_VALIDATION_FAIL: 4,
+ EXPECT_BUILD_SUCCESSFUL: 5
+};
+
+/**
+ * Test case type
+ * @enum {number}
+ */
+glsShaderLibraryCase.caseType = {
+ CASETYPE_COMPLETE: 0, //!< Has all shaders specified separately.
+ CASETYPE_VERTEX_ONLY: 1, //!< "Both" case, vertex shader sub case.
+ CASETYPE_FRAGMENT_ONLY: 2 //!< "Both" case, fragment shader sub case.
+};
+
+/**
+ * glsShaderLibraryCase.BeforeDrawValidator target type enum
+ * @enum {number}
+ */
+glsShaderLibraryCase.targetType = {
+ PROGRAM: 0,
+ PIPELINE: 1
+};
+
+/**
+ * Shader case type enum
+ * @enum {number}
+ */
+glsShaderLibraryCase.shaderCase = {
+ STORAGE_INPUT: 0,
+ STORAGE_OUTPUT: 1,
+ STORAGE_UNIFORM: 2
+};
+
+/**
+ * Checks if shader uses in/out qualifiers depending on the version
+ * @param {string} version
+ * @return {boolean} version
+ */
+glsShaderLibraryCase.usesShaderInoutQualifiers = function(version) {
+ switch (version) {
+ case '100':
+ case '130':
+ case '140':
+ case '150':
+ return false;
+
+ default:
+ return true;
+ }
+};
+
+/**
+ * Checks if version supports fragment highp precision
+ * @param {string} version
+ * @return {boolean} version ,True when is different from version 100
+ */
+glsShaderLibraryCase.supportsFragmentHighp = function(version) {
+ return version !== '100';
+};
+
+/**
+ * This functions builds a matching vertex shader for a 'both' case, when
+ * the fragment shader is being tested.
+ * We need to build attributes and varyings for each 'input'.
+ * @param { {values:Array}} valueBlock
+ * @return {string} res
+ */
+glsShaderLibraryCase.genVertexShader = function(valueBlock) {
+ /** @type {string} */ var res = '';
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute';
+ /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying';
+
+ res += '#version ' + state.currentTest.spec.targetVersion + '\n';
+ res += 'precision highp float;\n';
+ res += 'precision highp int;\n';
+ res += '\n';
+ res += vtxIn + ' highp vec4 dEQP_Position;\n';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ var val = valueBlock.values[ndx];
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+ res += vtxIn + ' ' + floatType + ' a_' + val.valueName + ';\n';
+
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ res += vtxOut + ' ' + floatType + ' ' + val.valueName + ';\n';
+ else
+ res += vtxOut + ' ' + floatType + ' v_' + val.valueName + ';\n';
+ }
+ }
+ res += '\n';
+
+ // Main function.
+ // - gl_Position = dEQP_Position;
+ // - for each input: write attribute directly to varying
+ res += 'void main()\n';
+ res += ' {\n';
+ res += '\tgl_Position = dEQP_Position;\n';
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ var val = valueBlock.values[ndx];
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ /** @type {string} */ var name = val.valueName;
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ res += '\t' + name + ' = a_' + name + ';\n';
+ else
+ res += '\tv_' + name + ' = a_' + name + ';\n';
+ }
+ }
+
+ res += '}\n';
+ return res;
+};
+
+/**
+ * @param { {values:Array}} valueBlock
+ * @param {boolean} useFloatTypes
+ * @return {string} stream
+ */
+glsShaderLibraryCase.genCompareFunctions = function(valueBlock, useFloatTypes) {
+ var cmpTypeFound = {};
+ /** @type {string} */ var stream = '';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT)
+ cmpTypeFound[gluShaderUtil.getDataTypeName(val.dataType)] = true;
+
+ }
+ if (useFloatTypes) {
+ if (cmpTypeFound['bool']) stream += 'bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n';
+ if (cmpTypeFound['bvec2']) stream += 'bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n';
+ if (cmpTypeFound['bvec3']) stream += 'bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n';
+ if (cmpTypeFound['bvec4']) stream += 'bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n';
+ if (cmpTypeFound['int']) stream += 'bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n';
+ if (cmpTypeFound['ivec2']) stream += 'bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n';
+ if (cmpTypeFound['ivec3']) stream += 'bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n';
+ if (cmpTypeFound['ivec4']) stream += 'bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n';
+ if (cmpTypeFound['uint']) stream += 'bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n';
+ if (cmpTypeFound['uvec2']) stream += 'bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n';
+ if (cmpTypeFound['uvec3']) stream += 'bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n';
+ if (cmpTypeFound['uvec4']) stream += 'bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n';
+ } else {
+ if (cmpTypeFound['bool']) stream += 'bool isOk (bool a, bool b) { return (a == b); }\n';
+ if (cmpTypeFound['bvec2']) stream += 'bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n';
+ if (cmpTypeFound['bvec3']) stream += 'bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n';
+ if (cmpTypeFound['bvec4']) stream += 'bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n';
+ if (cmpTypeFound['int']) stream += 'bool isOk (int a, int b) { return (a == b); }\n';
+ if (cmpTypeFound['ivec2']) stream += 'bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n';
+ if (cmpTypeFound['ivec3']) stream += 'bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n';
+ if (cmpTypeFound['ivec4']) stream += 'bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n';
+ if (cmpTypeFound['uint']) stream += 'bool isOk (uint a, uint b) { return (a == b); }\n';
+ if (cmpTypeFound['uvec2']) stream += 'bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n';
+ if (cmpTypeFound['uvec3']) stream += 'bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n';
+ if (cmpTypeFound['uvec4']) stream += 'bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n';
+ }
+
+ if (cmpTypeFound['float'])
+ stream += 'bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n';
+ if (cmpTypeFound['vec2'])
+ stream += 'bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n';
+ if (cmpTypeFound['vec3'])
+ stream += 'bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n';
+ if (cmpTypeFound['vec4'])
+ stream += 'bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n';
+
+ if (cmpTypeFound['mat2'])
+ stream += 'bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n';
+ if (cmpTypeFound['mat2x3'])
+ stream += 'bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n';
+ if (cmpTypeFound['mat2x4'])
+ stream += 'bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n';
+ if (cmpTypeFound['mat3x2'])
+ stream += 'bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n';
+ if (cmpTypeFound['mat3'])
+ stream += 'bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n';
+ if (cmpTypeFound['mat3x4'])
+ stream += 'bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n';
+ if (cmpTypeFound['mat4x2'])
+ stream += 'bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n';
+ if (cmpTypeFound['mat4x3'])
+ stream += 'bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n';
+ if (cmpTypeFound['mat4'])
+ stream += 'bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n';
+
+ return stream;
+};
+
+/**
+ * @param {string} dstVec4Var
+ * @param { {values:Array}} valueBlock
+ * @param {string} nonFloatNamePrefix
+ * @param {?string=} checkVarName
+ * @return {string} output
+ */
+glsShaderLibraryCase.genCompareOp = function(dstVec4Var, valueBlock, nonFloatNamePrefix, checkVarName) {
+
+ /** @type {boolean} */ var isFirstOutput = true;
+ /** @type {string} */ var output = '';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var valueName = val.valueName;
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ // Check if we're only interested in one variable (then skip if not the right one).
+ if (checkVarName && (valueName !== checkVarName))
+ continue;
+
+ // Prefix.
+ if (isFirstOutput) {
+ output += 'bool RES = ';
+ isFirstOutput = false;
+ } else
+ output += 'RES = RES && ';
+
+ // Generate actual comparison.
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ output += 'isOk(' + valueName + ', ref_' + valueName + ', 0.05);\n';
+ else
+ output += 'isOk(' + nonFloatNamePrefix + valueName + ', ref_' + valueName + ');\n';
+ }
+ // \note Uniforms are already declared in shader.
+ }
+
+ if (isFirstOutput)
+ output += dstVec4Var + ' = vec4(1.0);\n'; // \todo [petri] Should we give warning if not expect-failure case?
+ else
+ output += dstVec4Var + ' = vec4(RES, RES, RES, 1.0);\n';
+
+ return output;
+};
+
+/**
+ * @param { {values:Array}} valueBlock
+ * @return {string} shader
+ */
+glsShaderLibraryCase.genFragmentShader = function(valueBlock) {
+ /** @type {string} */ var shader = '';
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute';
+ /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying';
+ /** @type {boolean} */ var customColorOut = usesInout;
+ /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying';
+ /** @type {string} */ var prec = glsShaderLibraryCase.supportsFragmentHighp(state.currentTest.spec.targetVersion) ? 'highp' : 'mediump';
+
+ shader += '#version ' + state.currentTest.spec.targetVersion + '\n';
+
+ shader += 'precision ' + prec + ' float;\n';
+ shader += 'precision ' + prec + ' int;\n';
+ shader += '\n';
+
+ if (customColorOut) {
+ shader += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+ shader += '\n';
+ }
+
+ shader += glsShaderLibraryCase.genCompareFunctions(valueBlock, true);
+ shader += '\n';
+
+ // Declarations (varying, reference for each output).
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+ /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType);
+
+ if (val.storageType == glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ shader += fragIn + ' ' + floatType + ' ' + val.valueName + ';\n';
+ else
+ shader += fragIn + ' ' + floatType + ' v_' + val.valueName + ';\n';
+
+ shader += 'uniform ' + refType + ' ref_' + val.valueName + ';\n';
+ }
+ }
+
+ shader += '\n';
+ shader += 'void main()\n';
+ shader += ' {\n';
+
+ shader += '\t';
+ shader += glsShaderLibraryCase.genCompareOp(customColorOut ? 'dEQP_FragColor' : 'gl_FragColor', valueBlock, 'v_', null);
+
+ shader += '}\n';
+ return shader;
+};
+
+glsShaderLibraryCase.caseRequirement = (function() {
+
+/**
+ * @constructor
+ */
+var CaseRequirement = function() {
+
+/**
+ * @param {number} shaderType
+ * @return {boolean}
+ */
+ this.isAffected = function(shaderType) {
+ for (var i = 0; i < this.shaderTypes.length; i++)
+ if (this.shaderTypes[i] === shaderType)
+ return true;
+ return false;
+ };
+
+ this.checkRequirements = function(gl) {
+ if (this.type === requirementType.EXTENSION) {
+ var extns = gl.getSupportedExtensions();
+ for (var i = 0; i < extns.length; i++)
+ for (var j = 0; j < this.requirements.length; j++)
+ if (extns[i] === this.requirements[j]) {
+ this.supportedExtension = this.requirements[j];
+ return true;
+ }
+ if (this.requirements.length === 1)
+ throw Error('Test requires extension of ' + this.requirements[0]);
+ else
+ throw Error('Test requires any extension of ' + this.requirements);
+ } else if (this.type === requirementType.IMPLEMENTATION_LIMIT) {
+ var value = gl.getParameter(this.enumName);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Failed to read parameter ' + this.enumName, false, true);
+
+ if (!(value > this.referenceValue))
+ throw Error('Test requires ' + this.enumName + ' (' + value + ') > ' + this.referenceValue);
+ }
+ };
+
+ this.getSupportedExtension = function() {
+ return this.supportedExtension;
+ };
+
+};
+
+var createAnyExtensionRequirement = function(requirements, shaderTypes) {
+ var cr = new CaseRequirement();
+ cr.type = requirementType.EXTENSION;
+ cr.requirements = requirements;
+ cr.shaderTypes = shaderTypes;
+ return cr;
+};
+
+var createLimitRequirement = function(enumName, ref) {
+ var cr = new CaseRequirement();
+ cr.type = requirementType.IMPLEMENTATION_LIMIT;
+ cr.enumName = enumName;
+ cr.referenceValue = ref;
+};
+
+/**
+ * @enum {number}
+ */
+var requirementType = {
+ EXTENSION: 0,
+ IMPLEMENTATION_LIMIT: 1
+};
+
+return {
+ createAnyExtensionRequirement: createAnyExtensionRequirement,
+ createLimitRequirement: createLimitRequirement,
+ requirementType: requirementType
+};
+
+}());
+
+/** Specialize a shader only for the vertex test case.
+ * @param {string} baseCode
+ * @param {number} shaderType
+ * @param {Array<Object>} requirements
+ * @return {string} resultBuf
+ */
+glsShaderLibraryCase.injectExtensionRequirements = function(baseCode, shaderType, requirements) {
+/**
+ * @param {Array<Object>} requirements
+ * @param {number} shaderType
+ * @return {string} buf
+ */
+ var generateExtensionStatements = function(requirements, shaderType) {
+ /** @type {string} */ var buf = '';
+
+ if (requirements)
+ for (var ndx = 0; ndx < requirements.length; ndx++)
+ if (requirements[ndx].type === glsShaderLibraryCase.caseRequirement.requirementType.EXTENSION &&
+ requirements[ndx].isAffected(shaderType))
+ buf += '#extension ' + requirements[ndx].getSupportedExtension() + ' : require\n';
+
+ return buf;
+ };
+
+ /** @type {string} */ var extensions = generateExtensionStatements(requirements, shaderType);
+
+ if (extensions.length === 0)
+ return baseCode;
+
+ /** @type {Array<string>} */ var splitLines = baseCode.split('\n');
+ /** @type {boolean} */ var firstNonPreprocessorLine = true;
+ /** @type {string} */ var resultBuf = '';
+
+ for (var i = 0; i < splitLines.length; i++) {
+ /** @const @type {boolean} */ var isPreprocessorDirective = (splitLines[i].match(/^\s*#/) !== null);
+
+ if (!isPreprocessorDirective && firstNonPreprocessorLine) {
+ firstNonPreprocessorLine = false;
+ resultBuf += extensions;
+ }
+
+ resultBuf += splitLines[i] + '\n';
+ }
+
+ return resultBuf;
+};
+
+/** Specialize a shader for the vertex shader test case.
+ * @param {string} src
+ * @param { {values:Array}} valueBlock
+ * @return {string} withExt
+ */
+glsShaderLibraryCase.specializeVertexShader = function(src, valueBlock) {
+ /** @type {string} */ var decl = '';
+ /** @type {string} */ var setup = '';
+ /** @type {string} */ var output = '';
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute';
+ /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying';
+
+ // Output (write out position).
+ output += 'gl_Position = dEQP_Position;\n';
+
+ // Declarations (position + attribute for each input, varying for each output).
+ decl += vtxIn + ' highp vec4 dEQP_Position;\n';
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var valueName = val.valueName;
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+ /** @type {string} */ var dataTypeName = gluShaderUtil.getDataTypeName(val.dataType);
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') {
+ decl += vtxIn + ' ' + floatType + ' ' + valueName + ';\n';
+ } else {
+ decl += vtxIn + ' ' + floatType + ' a_' + valueName + ';\n';
+ setup += dataTypeName + ' ' + valueName + ' = ' + dataTypeName + '(a_' + valueName + ');\n';
+ }
+ } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ decl += vtxOut + ' ' + floatType + ' ' + valueName + ';\n';
+ else {
+ decl += vtxOut + ' ' + floatType + ' v_' + valueName + ';\n';
+ decl += dataTypeName + ' ' + valueName + ';\n';
+
+ output += 'v_' + valueName + ' = ' + floatType + '(' + valueName + ');\n';
+ }
+ }
+ }
+
+ /** @type {string} */
+ var baseSrc = src
+ .replace(/\$\{DECLARATIONS\}/g, decl)
+ .replace(/\$\{DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' '))
+ .replace(/\$\{SETUP\}/g, setup)
+ .replace(/\$\{OUTPUT\}/g, output)
+ .replace(/\$\{POSITION_FRAG_COLOR\}/g, 'gl_Position');
+
+ /** @type {string} */
+ var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.VERTEX, state.currentTest.spec.requirements);
+
+ return withExt;
+};
+
+/** Specialize a shader only for the vertex test case.
+ * @param {string} src
+ * @param { {values:Array}} valueBlock
+ * @return {string} withExt
+ */
+glsShaderLibraryCase.specializeVertexOnly = function(src, valueBlock) {
+ /** @type {string} */ var decl = '';
+ /** @type {string} */ var setup = '';
+ /** @type {string} */ var output = '';
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute';
+
+ // Output (write out position).
+ output += 'gl_Position = dEQP_Position;\n';
+
+ // Declarations (position + attribute for each input, varying for each output).
+ decl += vtxIn + ' highp vec4 dEQP_Position;\n';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var valueName = val.valueName;
+ /** @type {string} */ var type = gluShaderUtil.getDataTypeName(val.dataType);
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') {
+ decl += vtxIn + ' ' + type + ' ' + valueName + ';\n';
+ } else {
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+
+ decl += vtxIn + ' ' + floatType + ' a_' + valueName + ';\n';
+ setup += type + ' ' + valueName + ' = ' + type + '(a_' + valueName + ');\n';
+ }
+ } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM &&
+ !val.valueName.match('\\.'))
+ decl += 'uniform ' + type + ' ' + valueName + ';\n';
+ }
+
+ /** @type {string} */
+ var baseSrc = src
+ .replace(/\$\{VERTEX_DECLARATIONS\}/g, decl)
+ .replace(/\$\{VERTEX_DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' '))
+ .replace(/\$\{VERTEX_SETUP\}/g, setup)
+ .replace(/\$\{VERTEX_OUTPUT\}/g, output);
+
+ /** @type {string} */
+ var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.VERTEX, state.currentTest.spec.requirements);
+
+ return withExt;
+};
+
+/** Specialize a shader for the fragment shader test case.
+ * @param {string} src
+ * @param { {values:Array}} valueBlock
+ * @return {string} withExt
+ */
+glsShaderLibraryCase.specializeFragmentShader = function(src, valueBlock) {
+ /** @type {string} */ var decl = '';
+ /** @type {string} */ var setup = '';
+ /** @type {string} */ var output = '';
+
+ /** @type {Object} */ var state = tcuTestCase.runner;
+
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {boolean} */ var customColorOut = usesInout;
+ /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying';
+ /** @type {string} */ var fragColor = customColorOut ? 'dEQP_FragColor' : 'gl_FragColor';
+
+ decl += glsShaderLibraryCase.genCompareFunctions(valueBlock, false);
+ output += glsShaderLibraryCase.genCompareOp(fragColor, valueBlock, '', null);
+
+ if (customColorOut)
+ decl += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var valueName = val.valueName;
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+ /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType);
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float')
+ decl += fragIn + ' ' + floatType + ' ' + valueName + ';\n';
+ else {
+ decl += fragIn + ' ' + floatType + ' v_' + valueName + ';\n';
+ var offset = gluShaderUtil.isDataTypeIntOrIVec(val.dataType) ? ' * 1.0025' : ''; // \todo [petri] bit of a hack to avoid errors in chop() due to varying interpolation
+ setup += refType + ' ' + valueName + ' = ' + refType + '(v_' + valueName + offset + ');\n';
+ }
+ } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ decl += 'uniform ' + refType + ' ref_' + valueName + ';\n';
+ decl += refType + ' ' + valueName + ';\n';
+ }
+ }
+
+ /* \todo [2010-04-01 petri] Check all outputs. */
+
+ /** @type {string} */
+ var baseSrc = src
+ .replace(/\$\{DECLARATIONS\}/g, decl)
+ .replace(/\$\{DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' '))
+ .replace(/\$\{SETUP\}/g, setup)
+ .replace(/\$\{OUTPUT\}/g, output)
+ .replace(/\$\{POSITION_FRAG_COLOR\}/g, fragColor);
+
+ /** @type {string} */
+ var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.FRAGMENT, state.currentTest.spec.requirements);
+
+ return withExt;
+};
+
+/** Specialize a shader only for the fragment test case.
+ * @param {string} src
+ * @param { {values:Array}} valueBlock
+ * @return {string} withExt
+ */
+glsShaderLibraryCase.specializeFragmentOnly = function(src, valueBlock) {
+ /** @type {string} */ var decl = '';
+ /** @type {string} */ var output = '';
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion);
+ /** @type {boolean} */ var customColorOut = usesInout;
+ /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying';
+ /** @type {string} */ var fragColor = customColorOut ? 'dEQP_FragColor' : 'gl_FragColor';
+
+ decl += glsShaderLibraryCase.genCompareFunctions(valueBlock, false);
+ output += glsShaderLibraryCase.genCompareOp(fragColor, valueBlock, '', null);
+
+ if (customColorOut)
+ decl += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+
+ for (var ndx = 0; ndx < valueBlock.values.length; ndx++) {
+ /** @type {Array} */ var val = valueBlock.values[ndx];
+ /** @type {string} */ var valueName = val.valueName;
+ /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType);
+ /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType);
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ decl += 'uniform ' + refType + ' ref_' + valueName + ';\n';
+ decl += refType + ' ' + valueName + ';\n';
+ } else if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM &&
+ !valueName.match('\\.'))
+ decl += 'uniform ' + refType + ' ' + valueName + ';\n';
+ }
+
+ /** @type {string} */
+ var baseSrc = src
+ .replace(/\$\{FRAGMENT_DECLARATIONS\}/g, decl)
+ .replace(/\$\{FRAGMENT_DECLARATIONS:single-line\}/g, decl.replace(/\n/g, ' '))
+ .replace(/\$\{FRAGMENT_OUTPUT\}/g, output)
+ .replace(/\$\{FRAG_COLOR\}/g, fragColor);
+
+ /** @type {string} */
+ var withExt = glsShaderLibraryCase.injectExtensionRequirements(baseSrc, gluShaderProgram.shaderType.FRAGMENT, state.currentTest.spec.requirements);
+
+ return withExt;
+};
+
+/**
+ * Is tessellation present
+ * @return {boolean} True if tessellation is present
+ */
+glsShaderLibraryCase.isTessellationPresent = function() {
+ /* TODO: GLES 3.1: implement */
+ return false;
+};
+
+glsShaderLibraryCase.setUniformValue = function(gl, pipelinePrograms, name, val, arrayNdx) {
+ /** @type {boolean} */ var foundAnyMatch = false;
+
+ for (var programNdx = 0; programNdx < pipelinePrograms.length; ++programNdx) {
+ /** @const @type {WebGLUniformLocation} */ var loc = gl.getUniformLocation(pipelinePrograms[programNdx], name);
+ /** @const @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(val.dataType);
+ /** @const @type {number} */ var elemNdx = (val.arrayLength === 1) ? (0) : (arrayNdx * scalarSize);
+
+ if (!loc)
+ continue;
+
+ foundAnyMatch = true;
+
+ gl.useProgram(pipelinePrograms[programNdx]);
+
+ /** @type {Array} */ var element = val.elements.slice(elemNdx, elemNdx + scalarSize);
+ switch (val.dataType) {
+ case gluShaderUtil.DataType.FLOAT: gl.uniform1fv(loc, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_VEC2: gl.uniform2fv(loc, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_VEC3: gl.uniform3fv(loc, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_VEC4: gl.uniform4fv(loc, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT2: gl.uniformMatrix2fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT3: gl.uniformMatrix3fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT4: gl.uniformMatrix4fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.INT: gl.uniform1iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.INT_VEC2: gl.uniform2iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.INT_VEC3: gl.uniform3iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.INT_VEC4: gl.uniform4iv(loc, new Int32Array(element)); break;
+
+ /** TODO: What type should be used for bool uniforms? */
+ case gluShaderUtil.DataType.BOOL: gl.uniform1iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.BOOL_VEC2: gl.uniform2iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.BOOL_VEC3: gl.uniform3iv(loc, new Int32Array(element)); break;
+ case gluShaderUtil.DataType.BOOL_VEC4: gl.uniform4iv(loc, new Int32Array(element)); break;
+
+ case gluShaderUtil.DataType.UINT: gl.uniform1uiv(loc, new Uint32Array(element)); break;
+ case gluShaderUtil.DataType.UINT_VEC2: gl.uniform2uiv(loc, new Uint32Array(element)); break;
+ case gluShaderUtil.DataType.UINT_VEC3: gl.uniform3uiv(loc, new Uint32Array(element)); break;
+ case gluShaderUtil.DataType.UINT_VEC4: gl.uniform4uiv(loc, new Uint32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, false, new Float32Array(element)); break;
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, false, new Float32Array(element)); break;
+
+ default:
+ testFailed('Unknown data type ' + val.dataType);
+ }
+ }
+
+ if (!foundAnyMatch)
+ bufferedLogToConsole('WARNING // Uniform \"' + name + '\" location is not valid, location = -1. Cannot set value to the uniform.');
+};
+
+/**
+ * Evaluates pixels, if they are white, black or there is any unexpected result
+ * @param {gluDrawUtil.Surface} surface
+ * @param {number} minX
+ * @param {number} maxX
+ * @param {number} minY
+ * @param {number} maxY
+ * @return {boolean} True if tessellation is present
+ */
+glsShaderLibraryCase.checkPixels = function(surface, minX, maxX, minY, maxY) {
+ /** @type {boolean} */ var allWhite = true;
+ /** @type {boolean} */ var allBlack = true;
+ /** @type {boolean} */ var anyUnexpected = false;
+
+ assertMsgOptions((maxX > minX) && (maxY > minY), 'glsShaderLibraryCase.checkPixels sanity check', false, true);
+
+ for (var y = minY; y <= maxY; y++) {
+ for (var x = minX; x <= maxX; x++) {
+ /** @type {number} */ var pixel = surface.getPixelUintRGB8(x, y);
+ /** @type {boolean} */ var isWhite = (pixel == 0xFFFFFF);
+ /** @type {boolean} */ var isBlack = (pixel == 0x000000);
+
+ allWhite = allWhite && isWhite;
+ allBlack = allBlack && isBlack;
+ anyUnexpected = anyUnexpected || (!isWhite && !isBlack);
+
+ // Early terminate as soon as we know the check hasn't passed
+ if (!allWhite && !allBlack)
+ break;
+ }
+ }
+
+ if (!allWhite) {
+ if (anyUnexpected)
+ testFailed('WARNING: expecting all rendered pixels to be white or black, but got other colors as well!');
+ else if (!allBlack)
+ testFailed('WARNING: got inconsistent results over the image, when all pixels should be the same color!');
+
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Initialize a test case
+ */
+glsShaderLibraryCase.init = function() {
+/** @type {Object} */ var state = tcuTestCase.runner;
+/** @type {Object} */ var test = state.currentTest;
+
+ bufferedLogToConsole('Processing ' + test.fullName());
+
+ if (!test.spec.valueBlockList.length)
+ test.spec.valueBlockList.push(glsShaderLibraryCase.genValueBlock());
+ /** @type { {values:Array}} */ var valueBlock = test.spec.valueBlockList[0];
+
+ if (test.spec.requirements)
+ for (var ndx = 0; ndx < test.spec.requirements.length; ++ndx)
+ test.spec.requirements[ndx].checkRequirements();
+
+ /** @type {Array<gluShaderProgram.ShaderInfo>} */ var sources = [];
+
+ if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_COMPLETE) {
+ /** @type {string} */ var vertex = glsShaderLibraryCase.specializeVertexOnly(test.spec.vertexSource, valueBlock);
+ /** @type {string} */ var fragment = glsShaderLibraryCase.specializeFragmentOnly(test.spec.fragmentSource, valueBlock);
+ sources.push(gluShaderProgram.genVertexSource(vertex));
+ sources.push(gluShaderProgram.genFragmentSource(fragment));
+ } else if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_VERTEX_ONLY) {
+ sources.push(gluShaderProgram.genVertexSource(glsShaderLibraryCase.specializeVertexShader(test.spec.vertexSource, valueBlock)));
+ sources.push(gluShaderProgram.genFragmentSource(glsShaderLibraryCase.genFragmentShader(valueBlock)));
+ } else if (test.spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY) {
+ sources.push(gluShaderProgram.genVertexSource(glsShaderLibraryCase.genVertexShader(valueBlock)));
+ sources.push(gluShaderProgram.genFragmentSource(glsShaderLibraryCase.specializeFragmentShader(test.spec.fragmentSource, valueBlock)));
+ }
+
+ test.programs = [];
+ test.programs.push({
+ programSources: {
+ sources: sources
+ }
+ }
+ );
+
+};
+
+/**
+ * Execute a test case
+ * @return {boolean} True if test case passed
+ */
+glsShaderLibraryCase.execute = function() {
+ /** @const @type {number} */ var quadSize = 1.0;
+ /** @const @type {Array<number>} */
+ var s_positions = [
+ -quadSize, -quadSize, 0.0, 1.0,
+ -quadSize, +quadSize, 0.0, 1.0,
+ +quadSize, -quadSize, 0.0, 1.0,
+ +quadSize, +quadSize, 0.0, 1.0
+ ];
+
+ /** @const @type {Array<number>} */
+ var s_indices = [
+ 0, 1, 2,
+ 1, 3, 2
+ ];
+
+ var wtu = WebGLTestUtils;
+ /** @type {WebGL2RenderingContext} */ var gl = wtu.create3DContext('canvas');
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ /** @type {Object} */ var test = state.currentTest;
+ /** @type {Object} */ var spec = test.spec;
+
+ // Compute viewport.
+ /* TODO: original code used random number generator to compute viewport, we use whole canvas */
+ /** @const @type {number} */ var width = Math.min(canvas.width, glsShaderLibraryCase.VIEWPORT_WIDTH);
+ /** @const @type {number} */ var height = Math.min(canvas.height, glsShaderLibraryCase.VIEWPORT_HEIGHT);
+ /** @const @type {number} */ var viewportX = 0;
+ /** @const @type {number} */ var viewportY = 0;
+ /** @const @type {number} */ var numVerticesPerDraw = 4;
+ /** @const @type {boolean} */ var tessellationPresent = glsShaderLibraryCase.isTessellationPresent();
+
+ /** @type {boolean} */ var allCompilesOk = true;
+ /** @type {boolean} */ var allLinksOk = true;
+ /** @type {?string} */ var failReason = null;
+
+ /** @type {number} */ var vertexProgramID = -1;
+ /** @type {Array<WebGLProgram>} */ var pipelineProgramIDs = [];
+ /** @type {Array<gluShaderProgram.ShaderProgram>} */ var programs = [];
+ var programPipeline;
+
+ // Set the name of the current test so testFailedOptions/testPassedOptions can use it.
+ setCurrentTestName(test.fullName());
+ debug('Start testcase: ' + test.fullName());
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Start testcase: ' + test.fullName(), false, true);
+
+ /** @type {gluShaderProgram.ShaderProgram} */ var program = new gluShaderProgram.ShaderProgram(gl, test.programs[0].programSources);
+
+ vertexProgramID = program.getProgram();
+ pipelineProgramIDs.push(program.getProgram());
+ programs.push(program);
+
+ // Check that compile/link results are what we expect.
+
+ for (var i = 0; i < program.shaders.length; i++) {
+ if (!program.shaders[i].info.compileOk)
+ allCompilesOk = false;
+ }
+
+ if (!program.getProgramInfo().linkOk)
+ allLinksOk = false;
+
+ switch (spec.expectResult) {
+ case glsShaderLibraryCase.expectResult.EXPECT_PASS:
+ case glsShaderLibraryCase.expectResult.EXPECT_VALIDATION_FAIL:
+ case glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL:
+ if (!allCompilesOk)
+ failReason = 'expected shaders to compile and link properly, but failed to compile.';
+ else if (!allLinksOk)
+ failReason = 'expected shaders to compile and link properly, but failed to link.';
+ break;
+
+ case glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL:
+ if (allCompilesOk && !allLinksOk)
+ failReason = 'expected compilation to fail, but shaders compiled and link failed.';
+ else if (allCompilesOk)
+ failReason = 'expected compilation to fail, but shaders compiled correctly.';
+ break;
+
+ case glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL:
+ if (!allCompilesOk)
+ failReason = 'expected linking to fail, but unable to compile.';
+ else if (allLinksOk)
+ failReason = 'expected linking to fail, but passed.';
+ break;
+
+ case glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL:
+ if (allCompilesOk && allLinksOk)
+ failReason = 'expected compile or link to fail, but passed.';
+ break;
+
+ default:
+ testFailedOptions('Unknown expected result', true);
+ return false;
+ }
+
+ if (failReason != null) {
+ // \todo [2010-06-07 petri] These should be handled in the test case?
+
+ // If implementation parses shader at link time, report it as quality warning.
+ if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL && allCompilesOk && !allLinksOk)
+ bufferedLogToConsole('Quality warning: implementation parses shader at link time: ' + failReason);
+ else {
+ bufferedLogToConsole('ERROR: ' + failReason);
+ testFailedOptions(failReason, true);
+ }
+ return false;
+ }
+
+ // Return if compile/link expected to fail.
+ if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL ||
+ spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL ||
+ spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL ||
+ spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL) {
+ if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL) {
+ testPassedOptions('Compile/link is expected to succeed', true);
+ } else {
+ testPassedOptions('Compile/link is expected to fail', true);
+ }
+ setCurrentTestName('');
+ return (failReason === null);
+ }
+
+ // Setup viewport.
+ gl.viewport(viewportX, viewportY, width, height);
+
+ // Start using program
+ gl.useProgram(vertexProgramID);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'glUseProgram()', false, true);
+
+ // Fetch location for positions positions.
+ /** @type {number} */ var positionLoc = gl.getAttribLocation(vertexProgramID, 'dEQP_Position');
+ if (positionLoc === -1) {
+ testFailedOptions("no location found for attribute 'dEQP_Position'", true);
+ return false;
+ }
+
+ // Iterate all value blocks.
+ for (var blockNdx = 0; blockNdx < spec.valueBlockList.length; blockNdx++) {
+ /** @type { {values:Array}} */ var block = spec.valueBlockList[blockNdx];
+
+ // always render at least one pass even if there is no input/output data
+ /** @const @type {number} */ var numRenderPasses = Math.max(block.arrayLength, 1);
+
+ // Iterate all array sub-cases.
+ for (var arrayNdx = 0; arrayNdx < numRenderPasses; arrayNdx++) {
+ /** @const @type {number} */ var numValues = block.values.length;
+ /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
+ /** @type {number} */ var attribValueNdx = 0;
+ /** @type {number} */ var postDrawError;
+
+ vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, positionLoc, 4, numVerticesPerDraw, s_positions));
+
+ // Collect VA pointer for inputs
+ for (var valNdx = 0; valNdx < numValues; valNdx++) {
+ var val = block.values[valNdx];
+ /** @const @type {string} */ var valueName = val.valueName;
+ /** @const @type {gluShaderUtil.DataType} */ var dataType = val.dataType;
+ /** @const @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(val.dataType);
+
+ if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) {
+ // Replicate values four times.
+ /** @type {Array} */ var scalars = [];
+
+ for (var repNdx = 0; repNdx < numVerticesPerDraw; repNdx++)
+ for (var ndx = 0; ndx < scalarSize; ndx++)
+ scalars[repNdx * scalarSize + ndx] = val.elements[arrayNdx * scalarSize + ndx];
+
+ // Attribute name prefix.
+ /** @type {string} */ var attribPrefix = '';
+ // \todo [2010-05-27 petri] Should latter condition only apply for vertex cases (or actually non-fragment cases)?
+ if ((spec.caseType === glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY) || (gluShaderUtil.getDataTypeScalarType(dataType) !== 'float'))
+ attribPrefix = 'a_';
+
+ // Input always given as attribute.
+ /** @type {string} */ var attribName = attribPrefix + valueName;
+ /** @type {number} */ var attribLoc = gl.getAttribLocation(vertexProgramID, attribName);
+ if (attribLoc === -1) {
+ bufferedLogToConsole("Warning: no location found for attribute '" + attribName + "'");
+ continue;
+ }
+
+ if (gluShaderUtil.isDataTypeMatrix(dataType)) {
+ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(dataType);
+ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(dataType);
+
+ assertMsgOptions(scalarSize === numCols * numRows, 'Matrix size sanity check', false, true);
+
+ for (var i = 0; i < numCols; i++)
+ vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, attribLoc + i, numRows, numVerticesPerDraw, scalars, scalarSize * 4, i * numRows * 4));
+ } else
+ vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, attribLoc, scalarSize, numVerticesPerDraw, scalars));
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set vertex attrib array', false, true);
+ }
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'before set uniforms', false, true);
+
+ // set uniform values for outputs (refs).
+ for (var valNdx = 0; valNdx < numValues; valNdx++) {
+ /** @type {Array} */ var val1 = block.values[valNdx];
+ /** @type {string} */ var valueName1 = val1.valueName;
+
+ if (val1.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) {
+ // Set reference value.
+ glsShaderLibraryCase.setUniformValue(gl, pipelineProgramIDs, 'ref_' + valueName1, val1, arrayNdx);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set reference uniforms', false, true);
+ } else if (val1.storageType === glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM) {
+ glsShaderLibraryCase.setUniformValue(gl, pipelineProgramIDs, valueName1, val1, arrayNdx);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set uniforms', false, true);
+ }
+ }
+
+ // Clear.
+ gl.clearColor(0.125, 0.25, 0.5, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'clear buffer', false, true);
+
+ // Use program or pipeline
+ if (spec.separatePrograms)
+ gl.useProgram(null);
+ else
+ gl.useProgram(vertexProgramID);
+
+ // Draw.
+ // if (tessellationPresent) {
+ // gl.patchParameteri(gl.PATCH_VERTICES, 3);
+ // assertMsgOptions(gl.getError() === gl.NO_ERROR, 'set patchParameteri(PATCH_VERTICES, 3)', false, true);
+ // }
+
+ gluDrawUtil.draw(gl, vertexProgramID, vertexArrays, gluDrawUtil.triangles(s_indices));
+
+ postDrawError = gl.getError();
+
+ if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_PASS) {
+ /** @type {gluDrawUtil.Surface} */ var surface = new gluDrawUtil.Surface();
+ /** @const @type {number} */ var w = s_positions[3];
+ /** @const @type {number} */ var minY = Math.ceil(((-quadSize / w) * 0.5 + 0.5) * height + 1.0);
+ /** @const @type {number} */ var maxY = Math.floor(((+quadSize / w) * 0.5 + 0.5) * height - 0.5);
+ /** @const @type {number} */ var minX = Math.ceil(((-quadSize / w) * 0.5 + 0.5) * width + 1.0);
+ /** @const @type {number} */ var maxX = Math.floor(((+quadSize / w) * 0.5 + 0.5) * width - 0.5);
+
+ assertMsgOptions(postDrawError === gl.NO_ERROR, 'draw', false, true);
+
+ surface.readSurface(gl, viewportX, viewportY, width, height);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'read pixels', false, true);
+
+ if (!glsShaderLibraryCase.checkPixels(surface, minX, maxX, minY, maxY)) {
+ testFailedOptions((
+ 'INCORRECT RESULT for (value block ' + (blockNdx + 1) +
+ ' of ' + spec.valueBlockList.length + ', sub-case ' +
+ (arrayNdx + 1) + ' of ' + block.arrayLength + '):'
+ ), true);
+
+ /* TODO: Port */
+ /*
+ log << TestLog::Message << "Failing shader input/output values:" << TestLog::EndMessage;
+ dumpValues(block, arrayNdx);
+
+ // Dump image on failure.
+ log << TestLog::Image("Result", "Rendered result image", surface);
+
+ */
+ gl.useProgram(null);
+
+ return false;
+ }
+ } else if (spec.expectResult === glsShaderLibraryCase.expectResult.EXPECT_VALIDATION_FAIL) {
+ /** TODO: GLES 3.1: Implement */
+ testFailedOptions('Unsupported test case', true);
+ }
+ }
+ }
+ gl.useProgram(null);
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, '', true, true);
+ setCurrentTestName('');
+
+ return true;
+};
+
+glsShaderLibraryCase.runTestCases = function() {
+/** @type {Object} */ var state = tcuTestCase.runner;
+ if (state.next()) {
+ try {
+ glsShaderLibraryCase.init();
+ glsShaderLibraryCase.execute();
+ } catch (err) {
+ bufferedLogToConsole(err);
+ }
+ tcuTestCase.runner.runCallback(glsShaderLibraryCase.runTestCases);
+ } else
+ tcuTestCase.runner.terminate();
+
+};
+
+glsShaderLibraryCase.genValueBlock = function() {
+ return {
+ /** @type {Array} */ values: [],
+ /** @type {number} */ arrayLength: 0
+ };
+};
+
+});