summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/modules
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/modules')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsAttributeLocationTests.js1477
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js1068
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTests.js5415
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTestsUnitTests.js2819
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsDrawTests.js3452
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboCompletenessTests.js961
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboUtil.js1413
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsLifetimeTests.js1118
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsRandomUniformBlockCase.js282
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsSamplerObjectTest.js1148
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js735
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js1114
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js1132
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderRenderCase.js1200
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsStateQuery.js367
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js2642
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js2451
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsVertexArrayTests.js2534
18 files changed, 31328 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsAttributeLocationTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsAttributeLocationTests.js
new file mode 100644
index 000000000..5ba033ffc
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsAttributeLocationTests.js
@@ -0,0 +1,1477 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL (ES) Module
+ * -----------------------------------------------
+ *
+ * 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.
+ *
+ *//*!
+ * \file
+ * \brief Attribute location tests
+ *//*--------------------------------------------------------------------*/
+
+'use strict';
+goog.provide('modules.shared.glsAttributeLocationTests');
+goog.require('framework.common.tcuStringTemplate');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+ var glsAttributeLocationTests = modules.shared.glsAttributeLocationTests;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var tcuStringTemplate = framework.common.tcuStringTemplate;
+
+ /**
+ * @param {Array<number>} bindings
+ * @param {string} attrib
+ * @return {number}
+ */
+ glsAttributeLocationTests.getBoundLocation = function(bindings, attrib) {
+ return (bindings[attrib] === undefined ? glsAttributeLocationTests.LocationEnum.UNDEF : bindings[attrib]);
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {Array<number>} bindings
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.hasAttributeAliasing = function(attributes, bindings) {
+ /** @type {Array<boolean>} */ var reservedSpaces = [];
+
+ /** @type {number} */ var location;
+ /** @type {number} */ var size;
+
+ for (var attribNdx = 0; attribNdx < attributes.length; attribNdx++) {
+ location = glsAttributeLocationTests.getBoundLocation(bindings, attributes[attribNdx].getName());
+ size = attributes[attribNdx].getType().getLocationSize();
+
+ if (location != glsAttributeLocationTests.LocationEnum.UNDEF) {
+
+ for (var i = 0; i < size; i++) {
+ if (reservedSpaces[location + i])
+ return true;
+ reservedSpaces[location + i] = true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.getMaxAttributeLocations = function() {
+ /** @type {number} */ var maxAttribs;
+ maxAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
+ return maxAttribs;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateAttributeDefinitions = function(attributes) {
+ /** @type {string} */ var src = '';
+
+ for (var i = 0; i < attributes.length; i++) {
+ if (attributes[i].getLayoutLocation() != glsAttributeLocationTests.LocationEnum.UNDEF)
+ src += ('layout(location = ' + attributes[i].getLayoutLocation() + ') ');
+
+ src += '${VTX_INPUT} mediump ';
+ src += (attributes[i].getType().getName() + ' ');
+ src += attributes[i].getName();
+ src += (attributes[i].getArraySize() != glsAttributeLocationTests.ArrayEnum.NOT ?
+ '[' + attributes[i].getArraySize() + ']' : '');
+ src += ';\n';
+ }
+
+ return src;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateConditionUniformDefinitions = function(attributes) {
+ /** @type {string} */ var src = '';
+ /** @type {Array<string>} */ var conditions = [];
+
+ for (var i = 0; i < attributes.length; i++) {
+ if (attributes[i].getCondition().notEquals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER)) &&
+ attributes[i].getCondition().notEquals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS)))
+ if (conditions.indexOf(attributes[i].getCondition().getName()) == -1)
+ conditions.push(attributes[i].getCondition().getName());
+ }
+
+ for (var i = 0; i < conditions.length; i++)
+ src += ('uniform mediump float u_' + conditions[i] + ';\n');
+
+ return src;
+ };
+
+ /**
+ * @param {glsAttributeLocationTests.Attribute} attrib
+ * @param {number=} id
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateToVec4Expression = function(attrib, id) {
+ /** @type {string} */ var src = '';
+ id = id === undefined ? -1 : id;
+
+ /** @type {string} */
+ var variableName = (attrib.getName() + (attrib.getArraySize() != glsAttributeLocationTests.ArrayEnum.NOT ? '[' + id + ']' : ''));
+
+ switch (attrib.getType().getGLTypeEnum()) {
+ case gl.INT_VEC2:
+ case gl.UNSIGNED_INT_VEC2:
+ case gl.FLOAT_VEC2:
+ src += ('vec4(' + variableName + '.xy, ' + variableName + '.yx)');
+ break;
+
+ case gl.INT_VEC3:
+ case gl.UNSIGNED_INT_VEC3:
+ case gl.FLOAT_VEC3:
+ src += ('vec4(' + variableName + '.xyz, ' + variableName + '.x)');
+ break;
+
+ default:
+ src += ('vec4(' + variableName + ')');
+ break;
+ }
+
+ return src;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateOutputCode = function(attributes) {
+ /** @type {string} */ var src = '';
+
+ for (var i = 0; i < attributes.length; i++) {
+ if (attributes[i].getCondition().equals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER))) {
+ src += '\tif (0 != 0)\n\t{\n';
+
+ if (attributes[i].getArraySize() == glsAttributeLocationTests.ArrayEnum.NOT)
+ src += ('\t\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i]) + ';\n');
+ else {
+ for (var j = 0; j < attributes[i].getArraySize(); i++)
+ src += ('\t\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i], j) + ';\n');
+ }
+
+ src += '\t}\n';
+ } else if (attributes[i].getCondition().equals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS))) {
+ if (attributes[i].getArraySize() == glsAttributeLocationTests.ArrayEnum.NOT)
+ src += ('\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i]) + ';\n');
+ else {
+ for (var j = 0; j < attributes[i].getArraySize(); j++)
+ src += ('\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i], j) + ';\n');
+ }
+ } else {
+ src += ('\tif (u_' + attributes[i].getCondition().getName() + (attributes[i].getCondition().getNegate() ? ' != ' : ' == ') + '0.0)\n');
+ src += '\t{\n';
+
+ if (attributes[i].getArraySize() == glsAttributeLocationTests.ArrayEnum.NOT)
+ src += ('\t\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i]) + ';\n');
+ else {
+ for (var j = 0; j < attributes[i].getArraySize(); i++)
+ src += ('\t\tcolor += ' + glsAttributeLocationTests.generateToVec4Expression(attributes[i], j) + ';\n');
+ }
+
+ src += '\t}\n';
+ }
+ }
+
+ return src;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateVertexShaderTemplate = function(attributes) {
+ /** @type {string} */ var src = '';
+
+ src = '${VERSION}\n' +
+ '${VTX_OUTPUT} mediump vec4 v_color;\n' +
+ glsAttributeLocationTests.generateAttributeDefinitions(attributes) +
+ '\n' +
+ glsAttributeLocationTests.generateConditionUniformDefinitions(attributes) +
+ '\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ '\tmediump vec4 color = vec4(0.0);\n' +
+ '\n' +
+ glsAttributeLocationTests.generateOutputCode(attributes) +
+ '\n' +
+ '\tv_color = color;\n' +
+ '\tgl_Position = color;\n' +
+ '}\n';
+
+ return src;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {boolean} attributeAliasing
+ * @return {string}
+ */
+ glsAttributeLocationTests.createVertexShaderSource = function(attributes, attributeAliasing) {
+ // \note On GLES only GLSL #version 100 supports aliasing
+ /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl);
+ glslVersion = attributeAliasing ? gluShaderUtil.GLSLVersion.V100_ES : glslVersion;
+ /** @type {boolean} */ var usesInOutQualifiers = gluShaderUtil.glslVersionUsesInOutQualifiers(glslVersion);
+ /** @type {string} */ var vertexShaderTemplate = glsAttributeLocationTests.generateVertexShaderTemplate(attributes);
+
+ /** @type {Array<string>} */ var parameters = [];
+
+ parameters['VERSION'] = gluShaderUtil.getGLSLVersionDeclaration(glslVersion);
+ parameters['VTX_OUTPUT'] = usesInOutQualifiers ? 'out' : 'varying';
+ parameters['VTX_INPUT'] = usesInOutQualifiers ? 'in' : 'attribute';
+ parameters['FRAG_INPUT'] = usesInOutQualifiers ? 'in' : 'varying';
+ parameters['FRAG_OUTPUT_VAR'] = usesInOutQualifiers ? 'dEQP_FragColor' : 'gl_FragColor';
+ parameters['FRAG_OUTPUT_DECLARATION'] = usesInOutQualifiers ? 'layout(location=0) out mediump vec4 dEQP_FragColor;' : '';
+
+ return tcuStringTemplate.specialize(vertexShaderTemplate, parameters);
+ };
+
+ /**
+ * @param {boolean} attributeAliasing
+ * @return {string}
+ */
+ glsAttributeLocationTests.createFragmentShaderSource = function(attributeAliasing) {
+ /** @type {string} */ var fragmentShaderSource = '';
+ fragmentShaderSource = '${VERSION}\n' +
+ '${FRAG_OUTPUT_DECLARATION}\n' +
+ '${FRAG_INPUT} mediump vec4 v_color;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ '\t${FRAG_OUTPUT_VAR} = v_color;\n' +
+ '}\n';
+
+ // \note On GLES only GLSL #version 100 supports aliasing
+ /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl);
+ glslVersion = attributeAliasing ? gluShaderUtil.GLSLVersion.V100_ES : glslVersion;
+ /** @type {boolean} */ var usesInOutQualifiers = gluShaderUtil.glslVersionUsesInOutQualifiers(glslVersion);
+
+ /** @type {Array<string>} */ var parameters = [];
+
+ parameters['VERSION'] = gluShaderUtil.getGLSLVersionDeclaration(glslVersion);
+ parameters['VTX_OUTPUT'] = usesInOutQualifiers ? 'out' : 'varying';
+ parameters['VTX_INPUT'] = usesInOutQualifiers ? 'in' : 'attribute';
+ parameters['FRAG_INPUT'] = usesInOutQualifiers ? 'in' : 'varying';
+ parameters['FRAG_OUTPUT_VAR'] = usesInOutQualifiers ? 'dEQP_FragColor' : 'gl_FragColor';
+ parameters['FRAG_OUTPUT_DECLARATION'] = usesInOutQualifiers ? 'layout(location=0) out mediump vec4 dEQP_FragColor;' : '';
+
+ return tcuStringTemplate.specialize(fragmentShaderSource, parameters);
+ };
+
+ glsAttributeLocationTests.logProgram = function(program) {
+ var programLinkOk = /** @type {boolean} */ (gl.getProgramParameter(program, gl.LINK_STATUS));
+ /**@type{string} */ var programInfoLog = gl.getProgramInfoLog(program);
+ /**@type{string} */ var log = 'Program Link Info: ' + programInfoLog +
+ 'Link result: ' + (programLinkOk ? 'Ok' : 'Fail');
+
+ bufferedLogToConsole(log);
+ };
+
+ glsAttributeLocationTests.logAttributes = function(attributes) {
+ /**@type{string} */ var log;
+ for (var i = 0; i < attributes.length; i++) {
+
+ log = 'Type: ' + attributes[i].getType().getName() +
+ ', Name: ' + attributes[i].getName() +
+ (attributes[i].getLayoutLocation() != glsAttributeLocationTests.LocationEnum.UNDEF ? ', Layout location ' + attributes[i].getLayoutLocation() : '');
+
+ bufferedLogToConsole(log);
+ }
+ };
+
+ /**
+ * @param {string} vertexShaderSource
+ * @param {string} vertexShaderInfoLog
+ * @param {boolean} vertexCompileOk
+ * @param {string} fragmentShaderSource
+ * @param {string} fragmentShaderInfoLog
+ * @param {boolean} fragmentCompileOk
+ */
+ glsAttributeLocationTests.logShaders = function(vertexShaderSource, vertexShaderInfoLog, vertexCompileOk, fragmentShaderSource, fragmentShaderInfoLog, fragmentCompileOk) {
+
+ /**@type{string} */ var log;
+ log = '\nVertex Shader Info: ' +
+ vertexShaderSource +
+ '\nInfo Log: ' +
+ vertexShaderInfoLog +
+ '\nCompilation result: ' + (vertexCompileOk ? 'Ok' : 'Failed') +
+
+ '\nFragment Shader Info: ' +
+ fragmentShaderSource +
+ '\nInfo Log: ' +
+ fragmentShaderInfoLog +
+ '\nCompilation result: ' + (fragmentCompileOk ? 'Ok' : 'Failed');
+
+ bufferedLogToConsole(log);
+ };
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.checkActiveAttribQuery = function(program, attributes) {
+ /** @type {number} */ var activeAttribCount = 0;
+ /** @type {Array<string>} */ var activeAttributes = [];
+ /** @type {boolean} */ var isOk = true;
+ /** @type {string} */ var log;
+
+ activeAttribCount = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES));
+
+ /** @type {glsAttributeLocationTests.Attribute} */ var attrib;
+ /** @type {boolean} */ var isActive;
+ /** @type {WebGLActiveInfo} */ var activeInfo;
+
+ for (var activeAttribNdx = 0; activeAttribNdx < activeAttribCount; activeAttribNdx++) {
+
+ activeInfo = gl.getActiveAttrib(program, activeAttribNdx);
+
+ log = 'glGetActiveAttrib(program' +
+ '\nindex= ' + activeAttribNdx +
+ '\nsize= ' + activeInfo.size +
+ '\ntype= ' + activeInfo.type +
+ '\nname= ' + activeInfo.name;
+
+ bufferedLogToConsole(log);
+
+ /** @type {boolean} */ var found = false;
+
+ for (var attribNdx = 0; attribNdx < attributes.length; attribNdx++) {
+ attrib = attributes[attribNdx];
+
+ if (attrib.getName() == activeInfo.name) {
+ if (activeInfo.type != attrib.getType().getGLTypeEnum()) {
+
+ log = 'Error: Wrong type ' + attrib.getType().getGLTypeEnum() +
+ ' expected= ' + activeInfo.type;
+ bufferedLogToConsole(log);
+
+ isOk = false;
+ }
+
+ if (attrib.getArraySize() == glsAttributeLocationTests.ArrayEnum.NOT) {
+ if (activeInfo.size != 1) {
+
+ bufferedLogToConsole('Error: Wrong size ' + activeInfo.size + ' expected 1');
+ isOk = false;
+ }
+ } else {
+ if (activeInfo.size != attrib.getArraySize()) {
+ bufferedLogToConsole('Error: Wrong size ' + activeInfo.size + ' expected ' + attrib.getArraySize());
+
+ isOk = false;
+ }
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ log = 'Error: Unknown attribute ' + activeInfo.name + ' returned= by glGetActiveAttrib().';
+ bufferedLogToConsole(log);
+
+ isOk = false;
+ }
+
+ activeAttributes.push(activeInfo.name);
+ }
+
+ for (var attribNdx = 0; attribNdx < attributes.length; attribNdx++) {
+ attrib = attributes[attribNdx];
+ isActive = attrib.getCondition().notEquals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER));
+
+ if (isActive) {
+ if (activeAttributes.indexOf(attrib.getName()) == -1) {
+
+ bufferedLogToConsole('Error: Active attribute ' + attrib.getName() + 'wasn\'t returned by glGetActiveAttrib().');
+ isOk = false;
+ }
+ } else {
+ if (activeAttributes[attrib.getName()] === undefined)
+ bufferedLogToConsole('Note: Inactive attribute ' + attrib.getName() + 'was returned by glGetActiveAttrib().');
+ }
+ }
+
+ return isOk;
+ };
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {Array<number>} bindings
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.checkAttribLocationQuery = function(program, attributes, bindings) {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {string} */ var log;
+
+ for (var attribNdx = 0; attribNdx < attributes.length; attribNdx++) {
+ /** @type {glsAttributeLocationTests.Attribute} */ var attrib = attributes[attribNdx];
+ /** @type {number} */ var expectedLocation = (attrib.getLayoutLocation() != glsAttributeLocationTests.LocationEnum.UNDEF ? attrib.getLayoutLocation() : glsAttributeLocationTests.getBoundLocation(bindings, attrib.getName()));
+ var location = /** @type {number} */ (gl.getAttribLocation(program, attrib.getName()));
+
+ if (attrib.getCondition().equals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER)) && location != -1)
+ bufferedLogToConsole('Note: Inactive attribute with location.');
+
+ if (attrib.getCondition().notEquals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER)) && expectedLocation != glsAttributeLocationTests.LocationEnum.UNDEF && expectedLocation != location)
+ bufferedLogToConsole('Error: Invalid attribute location.');
+
+ isOk = (attrib.getCondition().equals(glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.NEVER)) || expectedLocation == glsAttributeLocationTests.LocationEnum.UNDEF || expectedLocation == location);
+ }
+
+ return isOk;
+ };
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {Array<number>} bindings
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.checkQuery = function(program, attributes, bindings) {
+ /** @type {boolean} */ var isOk = glsAttributeLocationTests.checkActiveAttribQuery(program, attributes);
+
+ if (!glsAttributeLocationTests.checkAttribLocationQuery(program, attributes, bindings))
+ isOk = false;
+
+ return isOk;
+ };
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {boolean} attributeAliasing
+ * @return {Object}
+ */
+ glsAttributeLocationTests.createAndAttachShaders = function(program, attributes, attributeAliasing) {
+ /** @type {string} */ var vertexShaderSource = glsAttributeLocationTests.createVertexShaderSource(attributes, attributeAliasing);
+ /** @type {string} */ var fragmentShaderSource = glsAttributeLocationTests.createFragmentShaderSource(attributeAliasing);
+
+ /** @type {WebGLShader} */ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ /** @type {WebGLShader} */ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+
+ gl.shaderSource(vertexShader, vertexShaderSource);
+ gl.shaderSource(fragmentShader, fragmentShaderSource);
+
+ gl.compileShader(vertexShader);
+ gl.compileShader(fragmentShader);
+
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+
+ var vertexShaderCompileOk = /** @type {boolean} */ (gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS));
+ var fragmentShaderCompileOk = /** @type {boolean} */ (gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
+
+ // log shaders
+ glsAttributeLocationTests.logShaders(vertexShaderSource, gl.getShaderInfoLog(vertexShader),
+ vertexShaderCompileOk,
+ fragmentShaderSource, gl.getShaderInfoLog(fragmentShader),
+ fragmentShaderCompileOk);
+
+ assertMsgOptions(vertexShaderCompileOk, 'vertex Shader compile failed', false, true);
+ assertMsgOptions(fragmentShaderCompileOk, 'fragment Shader compile failed', false, true);
+
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+
+ return {first: vertexShader, second: fragmentShader};
+
+ };
+
+ /**
+ * @param {WebGLProgram} program
+ * @param {Array<glsAttributeLocationTests.Bind>} binds
+ */
+ glsAttributeLocationTests.bindAttributes = function(program, binds) {
+ for (var i = 0; i < binds.length; i++) {
+ bufferedLogToConsole('Bind attribute: ' + binds[i].getAttributeName() + ' to ' + binds[i].getLocation());
+ gl.bindAttribLocation(program, binds[i].getLocation(), binds[i].getAttributeName());
+ }
+ };
+
+ /**
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ * @return {string}
+ */
+ glsAttributeLocationTests.generateTestName = function(type, arraySize) {
+ return type.getName() + (arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? '_array_' + arraySize : '');
+ };
+
+ /**
+ * @constructor
+ * @param {string} name
+ * @param {number} locationSize
+ * @param {number} typeEnum
+ */
+ glsAttributeLocationTests.AttribType = function(name, locationSize, typeEnum) {
+ /** @type {string} */ this.m_name = name;
+ /** @type {number} */ this.m_locationSize = locationSize;
+ /** @type {number} */ this.m_glTypeEnum = typeEnum;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsAttributeLocationTests.AttribType.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.AttribType.prototype.getLocationSize = function() {
+ return this.m_locationSize;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.AttribType.prototype.getGLTypeEnum = function() {
+ return this.m_glTypeEnum;
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsAttributeLocationTests.ConstCond = {
+ ALWAYS: 0,
+ NEVER: 1
+ };
+
+ /**
+ * @constructor
+ * @param {string} name
+ * @param {boolean=} negate
+ */
+ glsAttributeLocationTests.Cond = function(name, negate) {
+ /** @type {boolean} */ this.m_negate = negate === undefined ? false : negate;
+ /** @type {string} */ this.m_name = name;
+ };
+
+ /**
+ * @param {glsAttributeLocationTests.ConstCond} cond
+ * @return {glsAttributeLocationTests.Cond}
+ */
+ glsAttributeLocationTests.NewCondWithEnum = function(cond) {
+ var condObj = new glsAttributeLocationTests.Cond('', false);
+ condObj.m_name = '__always__';
+ condObj.m_negate = (cond != glsAttributeLocationTests.ConstCond.NEVER);
+
+ return condObj;
+ };
+
+ /**
+ * @param {glsAttributeLocationTests.Cond} other
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.Cond.prototype.equals = function(other) {
+ return (this.m_negate == other.m_negate && this.m_name == other.m_name);
+ };
+
+ /**
+ * @param {glsAttributeLocationTests.Cond} other
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.Cond.prototype.notEquals = function(other) {
+ return (!this.equals(other));
+ };
+
+ /**
+ * @return {string}
+ */
+ glsAttributeLocationTests.Cond.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsAttributeLocationTests.Cond.prototype.getNegate = function() {
+ return this.m_negate;
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsAttributeLocationTests.LocationEnum = {
+ UNDEF: -1
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsAttributeLocationTests.ArrayEnum = {
+ NOT: -1
+ };
+
+ /**
+ * @constructor
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {string} name
+ * @param {number=} layoutLocation
+ * @param {glsAttributeLocationTests.Cond=} cond
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.Attribute = function(type, name, layoutLocation, cond, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {string} */ this.m_name = name;
+ /** @type {number} */ this.m_layoutLocation = layoutLocation === undefined ? glsAttributeLocationTests.LocationEnum.UNDEF : layoutLocation;
+ /** @type {glsAttributeLocationTests.Cond} */ this.m_cond = cond === undefined ?
+ glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS) : cond;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ };
+
+ /**
+ * @return {glsAttributeLocationTests.AttribType}
+ */
+ glsAttributeLocationTests.Attribute.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsAttributeLocationTests.Attribute.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.Attribute.prototype.getLayoutLocation = function() {
+ return this.m_layoutLocation;
+ };
+
+ /**
+ * @return {glsAttributeLocationTests.Cond}
+ */
+ glsAttributeLocationTests.Attribute.prototype.getCondition = function() {
+ return this.m_cond;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.Attribute.prototype.getArraySize = function() {
+ return this.m_arraySize;
+ };
+
+ /**
+ * @constructor
+ * @param {string} attribute
+ * @param {number} location
+ */
+ glsAttributeLocationTests.Bind = function(attribute, location) {
+ /** @type {string} */ this.m_attribute = attribute;
+ /** @type {number} */ this.m_location = location;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsAttributeLocationTests.Bind.prototype.getAttributeName = function() {
+ return this.m_attribute;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsAttributeLocationTests.Bind.prototype.getLocation = function() {
+ return this.m_location;
+ };
+
+ /**
+ * @param {Array<glsAttributeLocationTests.Attribute>} attributes
+ * @param {Array<glsAttributeLocationTests.Bind>} preAttachBind
+ * @param {Array<glsAttributeLocationTests.Bind>} preLinkBind
+ * @param {Array<glsAttributeLocationTests.Bind>} postLinkBind
+ * @param {boolean} relink
+ * @param {boolean=} reattach
+ * @param {Array<glsAttributeLocationTests.Attribute>=} reattachAttributes
+ */
+ glsAttributeLocationTests.runTest = function(attributes, preAttachBind, preLinkBind, postLinkBind, relink, reattach, reattachAttributes) {
+ reattach = reattach === undefined ? false : reattach;
+ reattachAttributes = reattachAttributes === undefined ? [] : reattachAttributes;
+
+ try {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {Array<number>} */ var activeBindings = [];
+
+ for (var bindNdx = 0; bindNdx < preAttachBind.length; bindNdx++)
+ activeBindings[preAttachBind[bindNdx].getAttributeName()] = preAttachBind[bindNdx].getLocation();
+
+ for (var bindNdx = 0; bindNdx < preLinkBind.length; bindNdx++)
+ activeBindings[preLinkBind[bindNdx].getAttributeName()] = preLinkBind[bindNdx].getLocation();
+
+ glsAttributeLocationTests.logAttributes(attributes);
+
+ /** @type {WebGLProgram} */ var program = gl.createProgram();
+
+ if (!preAttachBind.length == 0)
+ glsAttributeLocationTests.bindAttributes(program, preAttachBind);
+
+ /** @type {*} */ var shaders = glsAttributeLocationTests.createAndAttachShaders(program, attributes, glsAttributeLocationTests.hasAttributeAliasing(attributes, activeBindings));
+
+ if (!preLinkBind.length == 0)
+ glsAttributeLocationTests.bindAttributes(program, preLinkBind);
+
+ gl.linkProgram(program);
+
+ assertMsgOptions(gl.getProgramParameter(program, gl.LINK_STATUS) == true, 'link program failed', false, true);
+
+ glsAttributeLocationTests.logProgram(program);
+
+ if (!glsAttributeLocationTests.checkQuery(program, attributes, activeBindings))
+ isOk = false;
+
+ if (!postLinkBind.length == 0) {
+ glsAttributeLocationTests.bindAttributes(program, postLinkBind);
+
+ if (!glsAttributeLocationTests.checkQuery(program, attributes, activeBindings))
+ isOk = false;
+ }
+
+ if (relink) {
+ gl.linkProgram(program);
+
+ assertMsgOptions(gl.getProgramParameter(program, gl.LINK_STATUS) == true, 'link program failed', false, true);
+
+ glsAttributeLocationTests.logProgram(program);
+
+ for (var bindNdx = 0; bindNdx < postLinkBind.length; bindNdx++)
+ activeBindings[postLinkBind[bindNdx].getAttributeName()] = postLinkBind[bindNdx].getLocation();
+
+ if (!glsAttributeLocationTests.checkQuery(program, attributes, activeBindings))
+ isOk = false;
+ }
+
+ if (reattach) {
+ gl.detachShader(program, shaders.first);
+ gl.detachShader(program, shaders.second);
+
+ glsAttributeLocationTests.createAndAttachShaders(program, reattachAttributes, glsAttributeLocationTests.hasAttributeAliasing(reattachAttributes, activeBindings));
+
+ gl.linkProgram(program);
+
+ assertMsgOptions(gl.getProgramParameter(program, gl.LINK_STATUS) == true, 'link program failed', false, true);
+
+ glsAttributeLocationTests.logProgram(program);
+
+ if (!glsAttributeLocationTests.checkQuery(program, reattachAttributes, activeBindings))
+ isOk = false;
+ }
+
+ gl.deleteProgram(program);
+
+ assertMsgOptions(isOk, '', true, true);
+
+ } catch (e) {
+ if (program)
+ gl.deleteProgram(program);
+
+ throw e;
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.BindAttributeTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.BindAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindAttributeTest.prototype.constructor = glsAttributeLocationTests.BindAttributeTest;
+
+ glsAttributeLocationTests.BindAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_0', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.BindMaxAttributesTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.BindMaxAttributesTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindMaxAttributesTest.prototype.constructor = glsAttributeLocationTests.BindMaxAttributesTest;
+
+ glsAttributeLocationTests.BindMaxAttributesTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {number} */ var ndx = 0;
+
+ bufferedLogToConsole('MAX_VERTEX_ATTRIBS: ' + maxAttributes);
+
+ for (var loc = maxAttributes - (arrayElementCount * this.m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * this.m_type.getLocationSize())) {
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_' + ndx, glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ bindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.BindHoleAttributeTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.BindHoleAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindHoleAttributeTest.prototype.constructor = glsAttributeLocationTests.BindHoleAttributeTest;
+
+ glsAttributeLocationTests.BindHoleAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 0));
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_1', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ /** @type {number} */ var ndx = 2;
+ for (var loc = 1 + this.m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++) {
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx));
+ bindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PreAttachBindAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'pre_attach', 'pre_attach');
+ };
+
+ glsAttributeLocationTests.PreAttachBindAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PreAttachBindAttributeTest.prototype.constructor = glsAttributeLocationTests.PreAttachBindAttributeTest;
+
+ glsAttributeLocationTests.PreAttachBindAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {number} */ var ndx = 0;
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, bindings, noBindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PreLinkBindAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'pre_link', 'pre_link');
+ };
+
+ glsAttributeLocationTests.PreLinkBindAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PreLinkBindAttributeTest.prototype.constructor = glsAttributeLocationTests.PreLinkBindAttributeTest;
+
+ glsAttributeLocationTests.PreLinkBindAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {number} */ var ndx = 0;
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, bindings, noBindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PostLinkBindAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'post_link', 'post_link');
+ };
+
+ glsAttributeLocationTests.PostLinkBindAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PostLinkBindAttributeTest.prototype.constructor = glsAttributeLocationTests.PostLinkBindAttributeTest;
+
+ glsAttributeLocationTests.PostLinkBindAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, noBindings, bindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.BindReattachAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'reattach', 'reattach');
+ };
+
+ glsAttributeLocationTests.BindReattachAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindReattachAttributeTest.prototype.constructor = glsAttributeLocationTests.BindReattachAttributeTest;
+
+ glsAttributeLocationTests.BindReattachAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec2 = new glsAttributeLocationTests.AttribType('vec2', 1, gl.FLOAT_VEC2);
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var reattachAttributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 1));
+ bindings.push(new glsAttributeLocationTests.Bind('a_1', 1));
+
+ reattachAttributes.push(new glsAttributeLocationTests.Attribute(vec2, 'a_1'));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false, true, reattachAttributes);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.LocationAttributeTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.LocationAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.LocationAttributeTest.prototype.constructor = glsAttributeLocationTests.LocationAttributeTest;
+
+ glsAttributeLocationTests.LocationAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_0', 3, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, noBindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.LocationMaxAttributesTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.LocationMaxAttributesTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.LocationMaxAttributesTest.prototype.constructor = glsAttributeLocationTests.LocationMaxAttributesTest;
+
+ glsAttributeLocationTests.LocationMaxAttributesTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {number} */ var ndx = 0;
+
+ bufferedLogToConsole('MAX_VERTEX_ATTRIBS: ' + maxAttributes);
+
+ for (var loc = maxAttributes - (arrayElementCount * this.m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * this.m_type.getLocationSize())) {
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_' + ndx, loc, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, noBindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.LocationHoleAttributeTest = function(type, arraySize) {
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.LocationHoleAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.LocationHoleAttributeTest.prototype.constructor = glsAttributeLocationTests.LocationHoleAttributeTest;
+
+ glsAttributeLocationTests.LocationHoleAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0', 0));
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_1', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ /** @type {number} */ var ndx = 2;
+ for (var loc = 1 + this.m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++) {
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx, loc));
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, noBindings, noBindings, false);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.MixedAttributeTest = function(type, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.MixedAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedAttributeTest.prototype.constructor = glsAttributeLocationTests.MixedAttributeTest;
+
+ glsAttributeLocationTests.MixedAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_0', 3, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 4));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.MixedMaxAttributesTest = function(type, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.MixedMaxAttributesTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedMaxAttributesTest.prototype.constructor = glsAttributeLocationTests.MixedMaxAttributesTest;
+
+ glsAttributeLocationTests.MixedMaxAttributesTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {number} */ var ndx = 0;
+
+ bufferedLogToConsole('MAX_VERTEX_ATTRIBS: ' + maxAttributes);
+
+ for (var loc = maxAttributes - (arrayElementCount * this.m_type.getLocationSize()); loc >= 0; loc -= (arrayElementCount * this.m_type.getLocationSize())) {
+ if ((ndx % 2) != 0)
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_' + ndx, loc, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ else {
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_' + ndx, glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+ bindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+ }
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.MixedHoleAttributeTest = function(type, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.MixedHoleAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedHoleAttributeTest.prototype.constructor = glsAttributeLocationTests.MixedHoleAttributeTest;
+
+ glsAttributeLocationTests.MixedHoleAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 0));
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_1', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ /** @type {number} */ var ndx = 2;
+ for (var loc = 1 + this.m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++) {
+ if ((ndx % 2) != 0)
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx, loc));
+ else {
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx, loc));
+ bindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+ }
+ ndx++;
+ }
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.BindRelinkAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'relink', 'relink');
+ };
+
+ glsAttributeLocationTests.BindRelinkAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindRelinkAttributeTest.prototype.constructor = glsAttributeLocationTests.BindRelinkAttributeTest;
+
+ glsAttributeLocationTests.BindRelinkAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var preLinkBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var postLinkBindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_1'));
+
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 5));
+
+ postLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 6));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, preLinkBindings, postLinkBindings, true);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.BindRelinkHoleAttributeTest = function(type, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.BindRelinkHoleAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.BindRelinkHoleAttributeTest.prototype.constructor = glsAttributeLocationTests.BindRelinkHoleAttributeTest;
+
+ glsAttributeLocationTests.BindRelinkHoleAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var preLinkBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var postLinkBindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 0));
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_1', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ /** @type {number} */ var ndx = 2;
+ for (var loc = 1 + this.m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++) {
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+
+ ndx++;
+ }
+
+ postLinkBindings.push(new glsAttributeLocationTests.Bind('a_2', 1));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, preLinkBindings, postLinkBindings, true);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsAttributeLocationTests.AttribType} type
+ * @param {number=} arraySize
+ */
+ glsAttributeLocationTests.MixedRelinkHoleAttributeTest = function(type, arraySize) {
+ /** @type {glsAttributeLocationTests.AttribType} */ this.m_type = type;
+ /** @type {number} */ this.m_arraySize = arraySize === undefined ? glsAttributeLocationTests.ArrayEnum.NOT : arraySize;
+ tcuTestCase.DeqpTest.call(this, glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize), glsAttributeLocationTests.generateTestName(this.m_type, this.m_arraySize));
+ };
+
+ glsAttributeLocationTests.MixedRelinkHoleAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedRelinkHoleAttributeTest.prototype.constructor = glsAttributeLocationTests.MixedRelinkHoleAttributeTest;
+
+ glsAttributeLocationTests.MixedRelinkHoleAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations();
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1);
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var preLinkBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var postLinkBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0'));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 0));
+
+ attributes.push(new glsAttributeLocationTests.Attribute(this.m_type, 'a_1', glsAttributeLocationTests.LocationEnum.UNDEF, glsAttributeLocationTests.NewCondWithEnum(glsAttributeLocationTests.ConstCond.ALWAYS), this.m_arraySize));
+
+ /** @type {number} */ var ndx = 2;
+ for (var loc = 1 + this.m_type.getLocationSize() * arrayElementCount; loc < maxAttributes; loc++) {
+ if ((ndx % 2) != 0)
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx, loc));
+ else {
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_' + ndx));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_' + ndx, loc));
+
+ }
+ ndx++;
+ }
+
+ postLinkBindings.push(new glsAttributeLocationTests.Bind('a_2', 1));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, preLinkBindings, postLinkBindings, true);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PreAttachMixedAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'pre_attach', 'pre_attach');
+ };
+
+ glsAttributeLocationTests.PreAttachMixedAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PreAttachMixedAttributeTest.prototype.constructor = glsAttributeLocationTests.PreAttachMixedAttributeTest;
+
+ glsAttributeLocationTests.PreAttachMixedAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0', 1));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, bindings, noBindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PreLinkMixedAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'pre_link', 'pre_link');
+ };
+
+ glsAttributeLocationTests.PreLinkMixedAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PreLinkMixedAttributeTest.prototype.constructor = glsAttributeLocationTests.PreLinkMixedAttributeTest;
+
+ glsAttributeLocationTests.PreLinkMixedAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0', 1));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.PostLinkMixedAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'post_link', 'post_link');
+ };
+
+ glsAttributeLocationTests.PostLinkMixedAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.PostLinkMixedAttributeTest.prototype.constructor = glsAttributeLocationTests.PostLinkMixedAttributeTest;
+
+ glsAttributeLocationTests.PostLinkMixedAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4), 'a_0', 1));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, noBindings, bindings, false);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.MixedReattachAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'reattach', 'reattach');
+ };
+
+ glsAttributeLocationTests.MixedReattachAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedReattachAttributeTest.prototype.constructor = glsAttributeLocationTests.MixedReattachAttributeTest;
+
+ glsAttributeLocationTests.MixedReattachAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec2 = new glsAttributeLocationTests.AttribType('vec2', 1, gl.FLOAT_VEC2);
+
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var bindings = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var reattachAttributes = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0', 2));
+ bindings.push(new glsAttributeLocationTests.Bind('a_0', 1));
+ bindings.push(new glsAttributeLocationTests.Bind('a_1', 1));
+
+ reattachAttributes.push(new glsAttributeLocationTests.Attribute(vec2, 'a_1'));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, bindings, noBindings, false, true, reattachAttributes);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+ glsAttributeLocationTests.MixedRelinkAttributeTest = function() {
+ tcuTestCase.DeqpTest.call(this, 'relink', 'relink');
+ };
+
+ glsAttributeLocationTests.MixedRelinkAttributeTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsAttributeLocationTests.MixedRelinkAttributeTest.prototype.constructor = glsAttributeLocationTests.MixedRelinkAttributeTest;
+
+ glsAttributeLocationTests.MixedRelinkAttributeTest.prototype.iterate = function() {
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var noBindings = [];
+ /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4);
+
+ /** @type {Array<glsAttributeLocationTests.Attribute>} */ var attributes = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var preLinkBindings = [];
+ /** @type {Array<glsAttributeLocationTests.Bind>} */ var postLinkBindings = [];
+
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_0', 1));
+ attributes.push(new glsAttributeLocationTests.Attribute(vec4, 'a_1'));
+
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 3));
+ preLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 5));
+
+ postLinkBindings.push(new glsAttributeLocationTests.Bind('a_0', 6));
+
+ glsAttributeLocationTests.runTest(attributes, noBindings, preLinkBindings, postLinkBindings, true);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js
new file mode 100644
index 000000000..446782b4b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js
@@ -0,0 +1,1068 @@
+/*-------------------------------------------------------------------------
+ * 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.glsBufferTestUtil');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.delibs.debase.deUtil');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+ var glsBufferTestUtil = modules.shared.glsBufferTestUtil;
+ var tcuImageCompare = framework.common.tcuImageCompare;
+ var tcuRGBA = framework.common.tcuRGBA;
+ var tcuSurface = framework.common.tcuSurface;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuTexture = framework.common.tcuTexture;
+ var gluShaderProgram = framework.opengl.gluShaderProgram;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var gluDrawUtil = framework.opengl.gluDrawUtil;
+ var deUtil = framework.delibs.debase.deUtil;
+ var deMath = framework.delibs.debase.deMath;
+ var deRandom = framework.delibs.debase.deRandom;
+ var deString = framework.delibs.debase.deString;
+
+ glsBufferTestUtil.VERIFY_QUAD_SIZE = 8; //!< Quad size in VertexArrayVerifier
+ glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW = 128; //!< Maximum number of lines per one draw in IndexArrayVerifier
+ glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128;
+ glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128;
+
+ // Helper functions.
+
+ /**
+ * @param {Uint8Array} ptr
+ * @param {number} numBytes
+ * @param {number} seed
+ */
+ glsBufferTestUtil.fillWithRandomBytes = function(ptr, numBytes, seed) {
+ var rnd = new deRandom.Random(seed);
+ for (var left = numBytes; left > 0; left--)
+ ptr[left - 1] = rnd.getInt();
+ };
+
+ /**
+ * @param {Uint8Array} resPtr
+ * @param {Uint8Array} refPtr
+ * @param {number} numBytes
+ * @return {boolean}
+ */
+ glsBufferTestUtil.compareByteArrays = function(resPtr, refPtr, numBytes) {
+ var isOk = true;
+ var maxSpanLen = 8;
+ var maxDiffSpans = 4;
+ var numDiffSpans = 0;
+ var diffSpanStart = -1;
+ var ndx = 0;
+
+ var log = 'Verification result: ';
+
+ for (; ndx < numBytes; ndx++) {
+ if (resPtr[ndx] != refPtr[ndx]) {
+ if (diffSpanStart < 0)
+ diffSpanStart = ndx;
+
+ isOk = false;
+ } else if (diffSpanStart >= 0) {
+ if (numDiffSpans < maxDiffSpans) {
+ var len = ndx - diffSpanStart;
+ var printLen = Math.min(len, maxSpanLen);
+
+ log += len + ' byte difference at offset ' + diffSpanStart + '\n' +
+ ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) +
+ ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen);
+ } else
+ log += '(output too long, truncated)';
+
+ numDiffSpans += 1;
+ diffSpanStart = -1;
+ }
+ }
+
+ if (diffSpanStart >= 0) {
+ if (numDiffSpans < maxDiffSpans) {
+ var len = ndx - diffSpanStart;
+ var printLen = Math.min(len, maxSpanLen);
+
+ log += len + ' byte difference at offset ' + diffSpanStart + '\n' +
+ ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) +
+ ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen);
+ } else
+ log += '(output too long, truncated)';
+ }
+
+ log += (isOk ? 'Verification passed.' : 'Verification FAILED!');
+
+ bufferedLogToConsole(log);
+
+ return isOk;
+ };
+
+ /**
+ * @param {number} target
+ * @return {string}
+ */
+ glsBufferTestUtil.getBufferTargetName = function(target) {
+ switch (target) {
+ case gl.ARRAY_BUFFER: return 'array';
+ case gl.COPY_READ_BUFFER: return 'copy_read';
+ case gl.COPY_WRITE_BUFFER: return 'copy_write';
+ case gl.ELEMENT_ARRAY_BUFFER: return 'element_array';
+ case gl.PIXEL_PACK_BUFFER: return 'pixel_pack';
+ case gl.PIXEL_UNPACK_BUFFER: return 'pixel_unpack';
+ //case gl.TEXTURE_BUFFER: return "texture"; //TODO: Unimplemented in WebGL 2. Remove?
+ case gl.TRANSFORM_FEEDBACK_BUFFER: return 'transform_feedback';
+ case gl.UNIFORM_BUFFER: return 'uniform';
+ default:
+ throw new Error('Invalid buffer target');
+ }
+ };
+
+ /**
+ * @param {number} hint
+ * @return {string}
+ */
+ glsBufferTestUtil.getUsageHintName = function(hint) {
+ switch (hint) {
+ case gl.STREAM_DRAW: return 'stream_draw';
+ case gl.STREAM_READ: return 'stream_read';
+ case gl.STREAM_COPY: return 'stream_copy';
+ case gl.STATIC_DRAW: return 'static_draw';
+ case gl.STATIC_READ: return 'static_read';
+ case gl.STATIC_COPY: return 'static_copy';
+ case gl.DYNAMIC_DRAW: return 'dynamic_draw';
+ case gl.DYNAMIC_READ: return 'dynamic_read';
+ case gl.DYNAMIC_COPY: return 'dynamic_copy';
+ default:
+ throw new Error('Invalid buffer usage hint');
+ }
+ };
+
+ // Base class for buffer cases.
+ // BufferCase
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ glsBufferTestUtil.BufferCase = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ /** @type {Array<WebGLBuffer>} */ this.m_allocatedBuffers = [];
+ };
+
+ glsBufferTestUtil.BufferCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsBufferTestUtil.BufferCase.prototype.constructor = glsBufferTestUtil.BufferCase;
+
+ /**
+ * init
+ */
+ glsBufferTestUtil.BufferCase.prototype.init = function() {};
+
+ /**
+ * deinit
+ */
+ glsBufferTestUtil.BufferCase.prototype.deinit = function() {
+ for (var ndx = 0; ndx < this.m_allocatedBuffers.length; ndx++)
+ this.deleteBuffer(this.m_allocatedBuffers[ndx]);
+ };
+
+ /**
+ * @return {WebGLBuffer}
+ */
+ glsBufferTestUtil.BufferCase.prototype.genBuffer = function() {
+ var buf = 0;
+ buf = gl.createBuffer();
+ if (buf != 0) {
+ try {
+ deUtil.dePushUniqueToArray(this.m_allocatedBuffers, buf);
+ }
+ catch (err) {
+ gl.deleteBuffer(buf);
+ throw err;
+ }
+ }
+ return buf;
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ */
+ glsBufferTestUtil.BufferCase.prototype.deleteBuffer = function(buffer) {
+ gl.deleteBuffer(buffer);
+ this.m_allocatedBuffers.splice(this.m_allocatedBuffers.indexOf(buffer), 1);
+ };
+
+ glsBufferTestUtil.BufferCase.prototype.checkError = function() {
+ /** @type {number} */ var err = gl.getError();
+ if (err != gl.NO_ERROR)
+ throw new TestFailedException('Got ' + WebGLTestUtils.glEnumToString(gl, err));
+ };
+
+ // Reference buffer.
+
+ /**
+ * @constructor
+ */
+ glsBufferTestUtil.ReferenceBuffer = function() {
+ /** @type {ArrayBuffer} */ this.m_data;
+ };
+
+ /**
+ * @param {number=} offset
+ * @return {Uint8Array}
+ */
+ glsBufferTestUtil.ReferenceBuffer.prototype.getPtr = function(offset) {
+ offset = offset ? offset : 0; return new Uint8Array(this.m_data, offset);
+ };
+
+ /**
+ * @param {number} numBytes
+ */
+ glsBufferTestUtil.ReferenceBuffer.prototype.setSize = function(numBytes) {
+ this.m_data = new ArrayBuffer(numBytes);
+ };
+
+ /**
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ */
+ glsBufferTestUtil.ReferenceBuffer.prototype.setData = function(numBytes, bytes) {
+ this.setSize(numBytes);
+ var dst = new Uint8Array(this.m_data);
+ dst.set(bytes.subarray(numBytes));
+ };
+
+ /**
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ */
+ glsBufferTestUtil.ReferenceBuffer.prototype.setSubData = function(offset, numBytes, bytes) {
+ assertMsgOptions(deMath.deInBounds32(offset, 0, this.m_data.byteLength) && deMath.deInRange32(offset + numBytes, offset, this.m_data.byteLength),
+ 'Parameters not in buffer bounds or range', false, true);
+ var dst = new Uint8Array(this.m_data, offset);
+ dst.set(bytes.subarray(offset, offset + numBytes));
+ };
+
+ // Buffer writer system.
+
+ /**
+ * @enum {number}
+ */
+ glsBufferTestUtil.WriteType = {
+ BUFFER_SUB_DATA: 0,
+ BUFFER_WRITE_MAP: 1,
+ TRANSFORM_FEEDBACK: 2,
+ PIXEL_PACK: 3
+ };
+
+ /**
+ * @param {glsBufferTestUtil.WriteType} write
+ * @return {string}
+ */
+ glsBufferTestUtil.getWriteTypeDescription = function(write) {
+ /** @type {Array<string>} */ var s_desc = [
+ 'gl.bufferSubData()',
+ 'gl.mapBufferRange()',
+ 'transform feedback',
+ 'gl.readPixels() into PBO binding'
+ ];
+ return /** @type {string} */ (deUtil.getArrayElement(s_desc, write));
+ };
+
+ // BufferWriterBase
+
+ /**
+ * @constructor
+ */
+ glsBufferTestUtil.BufferWriterBase = function() {};
+
+ /**
+ * //Meant to be overriden
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferWriterBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); };
+
+ /**
+ * //Meant to be overriden
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferWriterBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); };
+
+ /**
+ * //Meant to be overriden
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ */
+ glsBufferTestUtil.BufferWriterBase.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { throw new Error('Must be overriden'); };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ * @param {number} targetHint
+ */
+ glsBufferTestUtil.BufferWriterBase.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) {
+ this.writeNoTarget(buffer, offset, numBytes, bytes);
+ };
+
+ // BufferWriter
+
+ /**
+ * @constructor
+ * @param {glsBufferTestUtil.WriteType} writeType
+ */
+ glsBufferTestUtil.BufferWriter = function(writeType) {
+ /** @type {glsBufferTestUtil.BufferWriterBase} */ this.m_writer = null;
+ switch (writeType) {
+ case glsBufferTestUtil.WriteType.BUFFER_SUB_DATA: this.m_writer = new glsBufferTestUtil.BufferSubDataWriter(); break;
+ default:
+ testFailed('Unsupported writer');
+ }
+ };
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferWriter.prototype.getMinSize = function() {return this.m_writer.getMinSize();};
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferWriter.prototype.getAlignment = function() {return this.m_writer.getAlignment();};
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ */
+ glsBufferTestUtil.BufferWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) {
+ assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
+ assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
+ assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
+ return this.m_writer.writeNoTarget(buffer, offset, numBytes, bytes);
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ * @param {number} targetHint
+ */
+ glsBufferTestUtil.BufferWriter.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) {
+ assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
+ assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
+ assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
+ return this.m_writer.write(buffer, offset, numBytes, bytes, targetHint);
+ };
+
+ // BufferSubDataWriter
+
+ /**
+ * @constructor
+ * @extends {glsBufferTestUtil.BufferWriterBase}
+ */
+ glsBufferTestUtil.BufferSubDataWriter = function() {
+ glsBufferTestUtil.BufferWriterBase.call(this);
+ };
+
+ glsBufferTestUtil.BufferSubDataWriter.prototype = Object.create(glsBufferTestUtil.BufferWriterBase.prototype);
+ glsBufferTestUtil.BufferSubDataWriter.prototype.constructor = glsBufferTestUtil.BufferSubDataWriter;
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferSubDataWriter.prototype.getMinSize = function() { return 1; };
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferSubDataWriter.prototype.getAlignment = function() { return 1; };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ */
+ glsBufferTestUtil.BufferSubDataWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) {
+ this.write(buffer, offset, numBytes, bytes, gl.ARRAY_BUFFER);
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {Uint8Array} bytes
+ * @param {number} target
+ */
+ glsBufferTestUtil.BufferSubDataWriter.prototype.write = function(buffer, offset, numBytes, bytes, target) {
+ gl.bindBuffer(target, buffer);
+ gl.bufferSubData(target, offset, bytes);
+ gl.bindBuffer(target, null);
+ };
+
+ // Buffer verifier system.
+
+ /**
+ * @enum {number}
+ */
+ glsBufferTestUtil.VerifyType = {
+ AS_VERTEX_ARRAY: 0,
+ AS_INDEX_ARRAY: 1,
+ AS_UNIFORM_BUFFER: 2,
+ AS_PIXEL_UNPACK_BUFFER: 3,
+ BUFFER_READ_MAP: 4
+ };
+
+ /**
+ * @param {glsBufferTestUtil.VerifyType} verify
+ * @return {string}
+ */
+ glsBufferTestUtil.getVerifyTypeDescription = function(verify) {
+ /** @type {Array<string>} */ var s_desc =
+ [
+ 'rendering as vertex data',
+ 'rendering as index data',
+ 'reading in shader as uniform buffer data',
+ 'using as PBO and uploading to texture',
+ 'reading back using glMapBufferRange()'
+ ];
+
+ return /** @type {string} */ (deUtil.getArrayElement(s_desc, verify));
+ };
+
+ /**
+ * @constructor
+ */
+ glsBufferTestUtil.BufferVerifierBase = function() {};
+
+ /**
+ * //Meant to be overriden
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferVerifierBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); };
+
+ /**
+ * //Meant to be overriden
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferVerifierBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} reference
+ * @param {number} offset
+ * @param {number} numBytes
+ * @return {boolean}
+ */
+ glsBufferTestUtil.BufferVerifierBase.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) {
+ throw new Error('Must be overriden');
+ };
+
+ /**
+ * //Meant to be overriden
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} reference
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {number} targetHint
+ * @return {boolean}
+ */
+ glsBufferTestUtil.BufferVerifierBase.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) {
+ //In WebGL 2, ELEMENT_ARRAY_BUFFER and TRANSFORM_FEEDBACK_BUFFER cannot be rebound to a different
+ //type of buffer, so, let's copy their data to an ARRAY BUFFER and pass that one instead to be verified.
+ var wasReadBufferCreated = false;
+ try {
+ if (targetHint == gl.ELEMENT_ARRAY_BUFFER || targetHint == gl.TRANSFORM_FEEDBACK_BUFFER) {
+ var readBuffer = new Uint8Array(offset + numBytes);
+ gl.getBufferSubData(targetHint, 0, readBuffer);
+ buffer = gl.createBuffer();
+
+ wasReadBufferCreated = true;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, readBuffer, gl.STATIC_DRAW);
+ }
+
+ var result = this.verifyNoTarget(buffer, reference, offset, numBytes);
+
+ if (wasReadBufferCreated)
+ gl.deleteBuffer(buffer);
+
+ return result;
+ } catch (err) {
+ if (wasReadBufferCreated)
+ gl.deleteBuffer(buffer);
+ throw err;
+ }
+ };
+
+ // BufferVerifier
+
+ /**
+ * @constructor
+ * @param {glsBufferTestUtil.VerifyType} verifyType
+ */
+ glsBufferTestUtil.BufferVerifier = function(verifyType) {
+ /** @type {glsBufferTestUtil.BufferVerifierBase} */ this.m_verifier = null;
+ switch (verifyType) {
+ case glsBufferTestUtil.VerifyType.AS_VERTEX_ARRAY: this.m_verifier = new glsBufferTestUtil.VertexArrayVerifier(); break;
+ case glsBufferTestUtil.VerifyType.AS_INDEX_ARRAY: this.m_verifier = new glsBufferTestUtil.IndexArrayVerifier(); break;
+ default:
+ testFailed('Unsupported verifier type');
+ }
+ };
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferVerifier.prototype.getMinSize = function() { return this.m_verifier.getMinSize(); };
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.BufferVerifier.prototype.getAlignment = function() { return this.m_verifier.getAlignment(); };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} reference
+ * @param {number} numBytes
+ * @return {boolean}
+ */
+ glsBufferTestUtil.BufferVerifier.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) {
+ assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
+ assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
+ assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
+ return this.m_verifier.verifyNoTarget(buffer, reference, offset, numBytes);
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} reference
+ * @param {number} offset
+ * @param {number} numBytes
+ * @param {number} targetHint
+ * @return {boolean}
+ */
+ glsBufferTestUtil.BufferVerifier.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) {
+ assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
+ assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
+ assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
+ return this.m_verifier.verify(buffer, reference, offset, numBytes, targetHint);
+ };
+
+ // VertexArrayVerifier
+
+ /**
+ * @constructor
+ * @extends {glsBufferTestUtil.BufferVerifierBase}
+ */
+ glsBufferTestUtil.VertexArrayVerifier = function() {
+ glsBufferTestUtil.BufferVerifierBase.call(this);
+ /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
+ this.m_posLoc = 0;
+ this.m_byteVecLoc = 0;
+ /** @type {WebGLVertexArrayObject} */ this.m_vao = null;
+
+ /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl);
+
+ assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'Unsupported GLSL version', false, true);
+
+ this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(
+ gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
+ 'in highp vec2 a_position;\n' +
+ 'in mediump vec3 a_byteVec;\n' +
+ 'out mediump vec3 v_byteVec;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' gl_Position = vec4(a_position, 0.0, 1.0);\n' +
+ ' v_byteVec = a_byteVec;\n' +
+ '}\n',
+
+ gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
+ 'in mediump vec3 v_byteVec;\n' +
+ 'layout(location = 0) out mediump vec4 o_color;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' o_color = vec4(v_byteVec, 1.0);\n' +
+ '}\n'
+ ));
+
+ if (!this.m_program.isOk()) {
+ testFailed('Compile failed');
+ }
+
+ this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
+ this.m_byteVecLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_byteVec');
+
+ this.m_vao = gl.createVertexArray();
+ this.m_positionBuf = gl.createBuffer();
+ this.m_indexBuf = gl.createBuffer();
+ };
+
+ glsBufferTestUtil.VertexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype);
+ glsBufferTestUtil.VertexArrayVerifier.prototype.constructor = glsBufferTestUtil.VertexArrayVerifier;
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.VertexArrayVerifier.prototype.getMinSize = function() { return 3 * 4; };
+
+ /**
+ * @return {number}
+ */
+ glsBufferTestUtil.VertexArrayVerifier.prototype.getAlignment = function() { return 1; };
+
+ /**
+ * deinit
+ */
+ glsBufferTestUtil.VertexArrayVerifier.prototype.deinit = function() {
+ if (this.m_vao) gl.deleteVertexArray(this.m_vao);
+ if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf);
+ if (this.m_indexBuf) gl.deleteBuffer(this.m_indexBuf);
+ };
+
+ /**
+ * @param {number} gridSizeX
+ * @param {number} gridSizeY
+ * @return {Array<number>}
+ */
+ glsBufferTestUtil.computePositions = function(gridSizeX, gridSizeY) {
+ var positions = [];
+
+ for (var y = 0; y < gridSizeY; y++)
+ for (var x = 0; x < gridSizeX; x++) {
+ /** @type {number} */ var sx0 = (x + 0) / gridSizeX;
+ /** @type {number} */ var sy0 = (y + 0) / gridSizeY;
+ /** @type {number} */ var sx1 = (x + 1) / gridSizeX;
+ /** @type {number} */ var sy1 = (y + 1) / gridSizeY;
+ /** @type {number} */ var fx0 = 2.0 * sx0 - 1.0;
+ /** @type {number} */ var fy0 = 2.0 * sy0 - 1.0;
+ /** @type {number} */ var fx1 = 2.0 * sx1 - 1.0;
+ /** @type {number} */ var fy1 = 2.0 * sy1 - 1.0;
+ /** @type {number} */ var baseNdx = (y * gridSizeX + x) * 8;
+
+ positions[baseNdx + 0] = fx0; positions[baseNdx + 1] = fy0;
+ positions[baseNdx + 2] = fx0; positions[baseNdx + 3] = fy1;
+ positions[baseNdx + 4] = fx1; positions[baseNdx + 5] = fy0;
+ positions[baseNdx + 6] = fx1; positions[baseNdx + 7] = fy1;
+ }
+
+ return positions;
+ };
+
+ /**
+ * @param {number} gridSizeX
+ * @param {number} gridSizeY
+ * @return {Uint16Array}
+ */
+ glsBufferTestUtil.computeIndices = function(gridSizeX, gridSizeY) {
+ var indices = new Uint16Array(3 * 2 * gridSizeX * gridSizeY);
+
+ for (var quadNdx = 0; quadNdx < gridSizeX * gridSizeY; quadNdx++) {
+ /** @type {number} */ var v00 = quadNdx * 4 + 0;
+ /** @type {number} */ var v01 = quadNdx * 4 + 1;
+ /** @type {number} */ var v10 = quadNdx * 4 + 2;
+ /** @type {number} */ var v11 = quadNdx * 4 + 3;
+
+ assertMsgOptions(v11 < (1 << 16), 'Vertex index value won\'t fit into a 16-bit number', false, true);
+
+ indices[quadNdx * 6 + 0] = v10;
+ indices[quadNdx * 6 + 1] = v00;
+ indices[quadNdx * 6 + 2] = v01;
+
+ indices[quadNdx * 6 + 3] = v10;
+ indices[quadNdx * 6 + 4] = v01;
+ indices[quadNdx * 6 + 5] = v11;
+ }
+
+ return indices;
+ };
+
+ /**
+ * @param {Uint8Array} ptr
+ * @param {number} vtxNdx
+ * @return {Array<number>}
+ */
+ glsBufferTestUtil.fetchVtxColor = function(ptr, vtxNdx) {
+ return new tcuRGBA.RGBA([
+ ptr[vtxNdx * 3 + 0],
+ ptr[vtxNdx * 3 + 1],
+ ptr[vtxNdx * 3 + 2],
+ 255]).toVec();
+ };
+
+ /**
+ * @param {tcuSurface.Surface} dst
+ * @param {number} numQuads
+ * @param {number} rowLength
+ * @param {Uint8Array} inPtr
+ */
+ glsBufferTestUtil.renderQuadGridReference = function(dst, numQuads, rowLength, inPtr) {
+ dst.setSize(rowLength * glsBufferTestUtil.VERIFY_QUAD_SIZE, (Math.floor(numQuads / rowLength) + (numQuads % rowLength != 0 ? 1 : 0)) * glsBufferTestUtil.VERIFY_QUAD_SIZE);
+
+ /** @type {tcuTexture.PixelBufferAccess} */ var dstAccess = dst.getAccess();
+ dstAccess.clear([0, 0, 0, 1.0]);
+
+ for (var quadNdx = 0; quadNdx < numQuads; quadNdx++) {
+ /** @type {number} */ var x0 = (quadNdx % rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE;
+ /** @type {number} */ var y0 = Math.floor(quadNdx / rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE;
+ /** @type {Array<number>} */ var v00 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 0);
+ /** @type {Array<number>} */ var v10 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 1);
+ /** @type {Array<number>} */ var v01 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 2);
+ /** @type {Array<number>} */ var v11 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 3);
+
+ for (var y = 0; y < glsBufferTestUtil.VERIFY_QUAD_SIZE; y++)
+ for (var x = 0; x < glsBufferTestUtil.VERIFY_QUAD_SIZE; x++) {
+ /** @type {number} */ var fx = (x + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE;
+ /** @type {number} */ var fy = (y + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE;
+
+ /** @type {boolean} */ var tri = fx + fy <= 1.0;
+ /** @type {number} */ var tx = tri ? fx : (1.0 - fx);
+ /** @type {number} */ var ty = tri ? fy : (1.0 - fy);
+ /** @type {Array<number>} */ var t0 = tri ? v00 : v11;
+ /** @type {Array<number>} */ var t1 = tri ? v01 : v10;
+ /** @type {Array<number>} */ var t2 = tri ? v10 : v01;
+ /** @type {Array<number>} */ var color = deMath.add(
+ deMath.add(t0, deMath.scale(deMath.subtract(t1, t0), tx)),
+ deMath.scale(deMath.subtract(t2, t0), ty)
+ );
+
+ dstAccess.setPixel(color, x0 + x, y0 + y);
+ }
+ }
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} refPtr
+ * @param {number} offset
+ * @param {number} numBytes
+ * @return {boolean}
+ */
+ glsBufferTestUtil.VertexArrayVerifier.prototype.verifyNoTarget = function(buffer, refPtr, offset, numBytes) {
+ var numBytesInVtx = 3;
+ var numBytesInQuad = numBytesInVtx * 4;
+ var maxQuadsX = Math.min(128, Math.floor(gl.drawingBufferWidth / glsBufferTestUtil.VERIFY_QUAD_SIZE));
+ var maxQuadsY = Math.min(128, Math.floor(gl.drawingBufferHeight / glsBufferTestUtil.VERIFY_QUAD_SIZE));
+ var maxQuadsPerBatch = maxQuadsX * maxQuadsY;
+ var numVerified = 0;
+ var program = this.m_program.getProgram();
+ /** @type {tcuRGBA.RGBA} */ var threshold = /*TODO: renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);*/ new tcuRGBA.RGBA([3, 3, 3, 3]);
+ var isOk = true;
+
+ /** @type {Array<number>} */ var positions = [];
+ /** @type {Uint16Array} */var indices;
+
+ /** @type {tcuSurface.Surface} */ var rendered = new tcuSurface.Surface();
+ /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface();
+
+ // Can't render full quad with smaller buffers.
+ assertMsgOptions(numBytes >= numBytesInQuad, 'Number of bytes must be bigger than number of bytes per quad', false, true);
+
+ positions = glsBufferTestUtil.computePositions(maxQuadsX, maxQuadsY);
+ indices = glsBufferTestUtil.computeIndices(maxQuadsX, maxQuadsY);
+
+ // Reset buffer bindings.
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
+
+ // Setup rendering state.
+ gl.viewport(0, 0, maxQuadsX * glsBufferTestUtil.VERIFY_QUAD_SIZE, maxQuadsY * glsBufferTestUtil.VERIFY_QUAD_SIZE);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.useProgram(program);
+ gl.bindVertexArray(this.m_vao);
+
+ // Upload positions
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(this.m_posLoc);
+ gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
+
+ // Upload indices
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_indexBuf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
+
+ gl.enableVertexAttribArray(this.m_byteVecLoc);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+ while (numVerified < numBytes) {
+ /** @type {number} */ var numRemaining = numBytes - numVerified;
+ var isLeftoverBatch = numRemaining < numBytesInQuad;
+ /** @type {number} */ var numBytesToVerify = isLeftoverBatch ? numBytesInQuad : Math.min(maxQuadsPerBatch * numBytesInQuad, numRemaining - numRemaining % numBytesInQuad);
+ /** @type {number} */ var curOffset = isLeftoverBatch ? (numBytes - numBytesInQuad) : numVerified;
+ /** @type {number} */ var numQuads = Math.floor(numBytesToVerify / numBytesInQuad);
+ /** @type {number} */ var numCols = Math.min(maxQuadsX, numQuads);
+ /** @type {number} */ var numRows = Math.floor(numQuads / maxQuadsX) + (numQuads % maxQuadsX != 0 ? 1 : 0);
+ /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1);
+
+ assertMsgOptions(numBytesToVerify > 0 && numBytesToVerify % numBytesInQuad == 0, 'Bytes to verify must be greater than zero and must be a multiple of the bytes per quad', false, true);
+ assertMsgOptions(deMath.deInBounds32(curOffset, 0, numBytes), 'Offset out of bounds', false, true);
+ assertMsgOptions(deMath.deInRange32(curOffset + numBytesToVerify, curOffset, numBytes), 'Range of bytes to verify outside of bounds', false, true);
+
+ // Render batch.
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.vertexAttribPointer(this.m_byteVecLoc, 3, gl.UNSIGNED_BYTE, true, 0, offset + curOffset);
+ gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_SHORT, 0);
+
+ glsBufferTestUtil.renderQuadGridReference(reference, numQuads, numCols, refPtr.subarray(offset + curOffset));
+
+ rendered.setSize(numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE);
+ rendered.readViewport(gl, [0, 0, numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE]);
+
+ if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, reference, rendered, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) {
+ isOk = false;
+ break;
+ }
+
+ numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
+ }
+
+ gl.bindVertexArray(null);
+
+ return isOk;
+ };
+
+ // IndexArrayVerifier
+
+ /**
+ * @constructor
+ * @extends {glsBufferTestUtil.BufferVerifierBase}
+ */
+ glsBufferTestUtil.IndexArrayVerifier = function() {
+ glsBufferTestUtil.BufferVerifierBase.call(this);
+
+ this.m_program = null;
+ this.m_posLoc = 0;
+ this.m_colorLoc = 0;
+
+ /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.GLSLVersion.V300_ES;
+
+ assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'GLSL version not supported', false, true);
+
+ this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(
+ gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
+ 'in highp vec2 a_position;\n' +
+ 'in mediump vec3 a_color;\n' +
+ 'out mediump vec3 v_color;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' gl_Position = vec4(a_position, 0.0, 1.0);\n' +
+ ' v_color = a_color;\n' +
+ '}\n',
+
+ gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
+ 'in mediump vec3 v_color;\n' +
+ 'layout(location = 0) out mediump vec4 o_color;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' o_color = vec4(v_color, 1.0);\n' +
+ '}\n'));
+
+ if (!this.m_program.isOk()) {
+ testFailed('Compile failed');
+ }
+
+ this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
+ this.m_colorLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_color');
+
+ this.m_vao = gl.createVertexArray();
+ this.m_positionBuf = gl.createBuffer();
+ this.m_colorBuf = gl.createBuffer();
+ };
+
+ glsBufferTestUtil.IndexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype);
+ glsBufferTestUtil.IndexArrayVerifier.prototype.constructor = glsBufferTestUtil.IndexArrayVerifier;
+
+ /**
+ * deinit
+ */
+ glsBufferTestUtil.IndexArrayVerifier.prototype.deinit = function() {
+ if (this.m_vao) gl.deleteVertexArray(this.m_vao);
+ if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf);
+ if (this.m_colorBuf) gl.deleteBuffer(this.m_colorBuf);
+ };
+
+ /**
+ * @return {Array<number>}
+ */
+ glsBufferTestUtil.computeIndexVerifierPositions = function() {
+ var numPosX = 16;
+ var numPosY = 16;
+
+ var dst = [];
+
+ for (var y = 0; y < numPosY; y++) {
+ for (var x = 0; x < numPosX; x++) {
+ var xf = x / (numPosX - 1);
+ var yf = y / (numPosY - 1);
+
+ var offset = 2 * (y * numPosX + x);
+ dst[offset] = 2.0 * xf - 1.0;
+ dst[offset + 1] = 2.0 * yf - 1.0;
+ }
+ }
+
+ return dst;
+ };
+
+ /**
+ * @return {Array<number>}
+ */
+ glsBufferTestUtil.computeIndexVerifierColors = function() {
+ /** @type {number} */ var numColors = 256;
+ /** @type {number} */ var minVal = 0.1;
+ /** @type {number} */ var maxVal = 0.5;
+ var rnd = new deRandom.Random(0xabc231);
+
+ var dst = [];
+
+ for (var i = 0; i < numColors; ++i) {
+ dst[3 * i] = rnd.getFloat(minVal, maxVal);
+ dst[3 * i + 1] = rnd.getFloat(minVal, maxVal);
+ dst[3 * i + 2] = rnd.getFloat(minVal, maxVal);
+ }
+
+ return dst;
+ };
+
+ /**
+ * @param {Array<number>} dst
+ * @param {Array<number>} src
+ * @param {Uint8Array} indices
+ * @param {number} numIndices
+ */
+ glsBufferTestUtil.execVertexFetch = function(dst, src, indices, numIndices) {
+ for (var i = 0; i < numIndices; ++i)
+ dst[i] = src[indices[i]];
+ };
+
+ /**
+ * @param {WebGLBuffer} buffer
+ * @param {Uint8Array} refPtr
+ * @param {number} offset
+ * @param {number} numBytes
+ * @return {boolean}
+ */
+ glsBufferTestUtil.IndexArrayVerifier.prototype.verify = function(buffer, refPtr, offset, numBytes) {
+ var viewportW = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, gl.drawingBufferWidth);
+ var viewportH = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, gl.drawingBufferHeight);
+ var minBytesPerBatch = 2;
+ /** @type {tcuRGBA.RGBA} */ var threshold = new tcuRGBA.RGBA([0, 0, 0, 0]);
+
+ var positions = [];
+ var colors = [];
+
+ var fetchedPos = [];
+ var fetchedColor = [];
+
+ /** @type {tcuSurface.Surface} */ var indexBufferImg = new tcuSurface.Surface(viewportW, viewportH);
+ /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(viewportW, viewportH);
+
+ var numVerified = 0;
+ var isOk = true;
+
+ positions = glsBufferTestUtil.computeIndexVerifierPositions();
+ colors = glsBufferTestUtil.computeIndexVerifierColors();
+
+ // Reset buffer bindings.
+ gl.bindVertexArray(this.m_vao);
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
+
+ // Setup rendering state.
+ gl.viewport(0, 0, viewportW, viewportH);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.useProgram(this.m_program.getProgram());
+ gl.enableVertexAttribArray(this.m_posLoc);
+ gl.enableVertexAttribArray(this.m_colorLoc);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE);
+ gl.blendEquation(gl.FUNC_ADD);
+
+ while (numVerified < numBytes) {
+ var numRemaining = numBytes - numVerified;
+ var isLeftoverBatch = numRemaining < minBytesPerBatch;
+ var numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : Math.min(glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW + 1, numRemaining);
+ var curOffset = isLeftoverBatch ? (numBytes - minBytesPerBatch) : numVerified;
+ /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1);
+
+ // Step 1: Render using index buffer.
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STREAM_DRAW);
+ gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STREAM_DRAW);
+ gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0);
+
+ gl.drawElements(gl.LINE_STRIP, numBytesToVerify, gl.UNSIGNED_BYTE, offset + curOffset);
+ indexBufferImg.readViewport(gl);
+
+ // Step 2: Do manual fetch and render without index buffer.
+ glsBufferTestUtil.execVertexFetch(fetchedPos, positions, refPtr.subarray(offset + curOffset), numBytesToVerify);
+ glsBufferTestUtil.execVertexFetch(fetchedColor, colors, refPtr.subarray(offset + curOffset), numBytesToVerify);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedPos), gl.STREAM_DRAW);
+ gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedColor), gl.STREAM_DRAW);
+ gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0);
+
+ gl.drawArrays(gl.LINE_STRIP, 0, numBytesToVerify);
+ referenceImg.readViewport(gl, [0, 0, viewportW, viewportH]);
+
+ if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, referenceImg, indexBufferImg, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) {
+ isOk = false;
+ break;
+ }
+
+ numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
+ }
+
+ gl.bindVertexArray(null);
+
+ return isOk;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTests.js
new file mode 100644
index 000000000..4dc3be70f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTests.js
@@ -0,0 +1,5415 @@
+/*-------------------------------------------------------------------------
+ * 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.glsBuiltinPrecisionTests');
+goog.require('framework.common.tcuFloatFormat');
+goog.require('framework.common.tcuInterval');
+goog.require('framework.common.tcuMatrix');
+goog.require('framework.common.tcuMatrixUtil');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.delibs.debase.deUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluVarType');
+goog.require('framework.opengl.simplereference.sglrGLContext');
+goog.require('modules.shared.glsBuiltinPrecisionTestsUnitTests');
+goog.require('modules.shared.glsShaderExecUtil');
+
+goog.scope(function() {
+
+ var glsBuiltinPrecisionTests = modules.shared.glsBuiltinPrecisionTests;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var gluShaderProgram = framework.opengl.gluShaderProgram;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var tcuInterval = framework.common.tcuInterval;
+ var tcuFloatFormat = framework.common.tcuFloatFormat;
+ var deRandom = framework.delibs.debase.deRandom;
+ var glsShaderExecUtil = modules.shared.glsShaderExecUtil;
+ var sglrGLContext = framework.opengl.simplereference.sglrGLContext;
+ var deMath = framework.delibs.debase.deMath;
+ var deUtil = framework.delibs.debase.deUtil;
+ var gluVarType = framework.opengl.gluVarType;
+ var tcuMatrix = framework.common.tcuMatrix;
+ var tcuMatrixUtil = framework.common.tcuMatrixUtil;
+ var ref = modules.shared.glsBuiltinPrecisionTestsUnitTests.cppreference;
+ var referenceComparison = modules.shared.glsBuiltinPrecisionTestsUnitTests.referenceComparison;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+var setParentClass = function(child, parent) {
+ child.prototype = Object.create(parent.prototype);
+ child.prototype.constructor = child;
+};
+
+ /** @typedef {(tcuInterval.Interval|Array<tcuInterval.Interval>|tcuMatrix.Matrix)} */
+ glsBuiltinPrecisionTests.Intervals;
+
+ /** @typedef {(number|Array<number>|tcuMatrix.Matrix)} */
+ glsBuiltinPrecisionTests.Value;
+
+ /** @typedef {(string)} */
+ glsBuiltinPrecisionTests.Typename;
+
+ //Change to true for WebGL unit testing
+ var enableUnittests = false;
+
+ /**
+ * @param {number} value
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.isFloat = function(value) {
+ return value % 1 !== 0;
+ };
+
+ /**
+ * @constructor
+ * @param {string} R
+ * @param {string=} P0
+ * @param {string=} P1
+ * @param {string=} P2
+ * @param {string=} P3
+ */
+ glsBuiltinPrecisionTests.Signature = function(R, P0, P1, P2, P3) {
+ this.Ret = R;
+ this.Arg0 = P0 === undefined ? 'void' : P0;
+ this.Arg1 = P1 === undefined ? 'void' : P1;
+ this.Arg2 = P2 === undefined ? 'void' : P2;
+ this.Arg3 = P3 === undefined ? 'void' : P3;
+ };
+
+ /** @typedef {Array<glsBuiltinPrecisionTests.FuncBase>} */
+ glsBuiltinPrecisionTests.FuncSet;
+
+ /**
+ * @constructor
+ * @template T
+ * @param {T} A0
+ * @param {T} A1
+ * @param {T} A2
+ * @param {T} A3
+ */
+ glsBuiltinPrecisionTests.Tuple4 = function(A0, A1, A2, A3) {
+ this.a = A0;
+ this.b = A1;
+ this.c = A2;
+ this.d = A3;
+ };
+
+ /**
+ * @typedef {!glsBuiltinPrecisionTests.Tuple4<string>}
+ */
+ glsBuiltinPrecisionTests.ParamNames;
+
+ /**
+ * Returns true for all other types except Void
+ * @param {string} typename
+ */
+ glsBuiltinPrecisionTests.isTypeValid = function(typename) {
+ if (typename === 'void')
+ return false;
+ return true;
+ };
+
+ /**
+ * Returns true for all other types except Void
+ * @param {*} In
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.numInputs = function(In) {
+ return (!glsBuiltinPrecisionTests.isTypeValid(In.In0) ? 0 :
+ !glsBuiltinPrecisionTests.isTypeValid(In.In1) ? 1 :
+ !glsBuiltinPrecisionTests.isTypeValid(In.In2) ? 2 :
+ !glsBuiltinPrecisionTests.isTypeValid(In.In3) ? 3 :
+ 4);
+ };
+
+ /**
+ * Returns true for all other types except Void
+ * @param {*} Out
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.numOutputs = function(Out) {
+ return (!glsBuiltinPrecisionTests.isTypeValid(Out.Out0) ? 0 :
+ !glsBuiltinPrecisionTests.isTypeValid(Out.Out1) ? 1 :
+ 2);
+ };
+
+ /**
+ * @constructor
+ * @param {glsBuiltinPrecisionTests.Typename=} In0_
+ * @param {glsBuiltinPrecisionTests.Typename=} In1_
+ * @param {glsBuiltinPrecisionTests.Typename=} In2_
+ * @param {glsBuiltinPrecisionTests.Typename=} In3_
+ */
+ glsBuiltinPrecisionTests.InTypes = function(In0_, In1_, In2_, In3_) {
+ this.In0 = In0_ === undefined ? 'void' : In0_;
+ this.In1 = In1_ === undefined ? 'void' : In1_;
+ this.In2 = In2_ === undefined ? 'void' : In2_;
+ this.In3 = In3_ === undefined ? 'void' : In3_;
+ };
+
+ /**
+ * @constructor
+ * @param {glsBuiltinPrecisionTests.Typename=} Out0_
+ * @param {glsBuiltinPrecisionTests.Typename=} Out1_
+ */
+ glsBuiltinPrecisionTests.OutTypes = function(Out0_, Out1_) {
+ this.Out0 = Out0_ === undefined ? 'void' : Out0_;
+ this.Out1 = Out1_ === undefined ? 'void' : Out1_;
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.Environment = function() {
+ /** @type {Object} */ this.m_map = {};
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Variable} variable
+ * @param {*} value
+ */
+ glsBuiltinPrecisionTests.Environment.prototype.bind = function(variable, value) {
+ this.m_map[variable.getName()] = value;
+ };
+
+ /**
+ * @param {*} variable
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.Environment.prototype.lookup = function(variable) {
+ if (variable instanceof glsBuiltinPrecisionTests.Variable)
+ return this.m_map[variable.getName()];
+
+ throw new Error('Invalid lookup input: ' + variable);
+ };
+
+ /**
+ * @constructor
+ * @param {tcuFloatFormat.FloatFormat} format_
+ * @param {gluShaderUtil.precision} floatPrecision_
+ * @param {glsBuiltinPrecisionTests.Environment} env_
+ * @param {number=} callDepth_
+ */
+ glsBuiltinPrecisionTests.EvalContext = function(format_, floatPrecision_, env_, callDepth_) {
+ this.format = format_;
+ this.floatPrecision = floatPrecision_;
+ this.env = env_;
+ this.callDepth = callDepth_ === undefined ? 0 : callDepth_;
+ };
+
+ /**
+ * @param {string} typename typename
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {glsBuiltinPrecisionTests.Intervals} value
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.convert = function(typename, fmt, value) {
+ var traits = glsBuiltinPrecisionTests.Traits.traitsFactory(typename);
+
+ if (value instanceof Array) {
+ var ret = [];
+ for (var i = 0; i < value.length; i++)
+ ret.push(traits.doConvert(fmt, value[i]));
+ return ret;
+ }
+
+ if (value instanceof tcuMatrix.Matrix) {
+ var ret = new tcuMatrix.Matrix(value.rows, value.cols);
+ for (var i = 0; i < value.rows; i++)
+ for (var j = 0; j < value.cols; j++)
+ ret.set(i, j, traits.doConvert(fmt, value.get(i, j)));
+ return ret;
+ }
+
+ return traits.doConvert(fmt, value);
+ };
+
+ /**
+ * Returns true if every element of `ival` contains the corresponding element of `value`.
+ * @param {string} typename typename
+ * @param {glsBuiltinPrecisionTests.Intervals} ival
+ * @param {*} value
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.contains = function(typename, ival, value) {
+ var traits = glsBuiltinPrecisionTests.Traits.traitsFactory(typename);
+ var contains = true;
+
+ if (value instanceof Array) {
+ for (var i = 0; i < value.length; i++)
+ contains &= traits.doContains(ival[i], value[i]);
+ return contains;
+ }
+
+ if (value instanceof tcuMatrix.Matrix) {
+ for (var i = 0; i < value.rows; i++)
+ for (var j = 0; j < value.cols; j++)
+ contains &= traits.doContains(ival.get(i, j), value.get(i, j));
+ return contains;
+ }
+
+ return traits.doContains(ival, value);
+ };
+
+ /**
+ * @param {string} typename typename
+ * @param {glsBuiltinPrecisionTests.Intervals} ival0
+ * @param {glsBuiltinPrecisionTests.Intervals} ival1
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.union = function(typename, ival0, ival1) {
+ var traits = glsBuiltinPrecisionTests.Traits.traitsFactory(typename);
+
+ if (ival0 instanceof Array) {
+ var ret = [];
+ for (var i = 0; i < ival0.length; i++)
+ ret.push(traits.doUnion(ival0[i], ival1[i]));
+ return ret;
+ }
+
+ if (ival0 instanceof tcuMatrix.Matrix) {
+ var ret = new tcuMatrix.Matrix(ival0.rows, ival0.cols);
+ for (var i = 0; i < ival0.rows; i++)
+ for (var j = 0; j < ival0.cols; j++)
+ ret.set(i, j, traits.doUnion(ival0.get(i, j), ival1.get(i, j)));
+ return ret;
+ }
+
+ return traits.doUnion(ival0, ival1);
+ };
+
+ /**
+ * @param {string} typename
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.Traits = function(typename) {
+ this.typename = typename;
+ this.rows = 1;
+ this.cols = 1;
+ };
+
+ glsBuiltinPrecisionTests.Traits.prototype.isScalar = function() {
+ return this.rows == 1 && this.cols == 1;
+ };
+
+ glsBuiltinPrecisionTests.Traits.prototype.isVector = function() {
+ return this.rows > 0 && this.cols == 1;
+ };
+
+ glsBuiltinPrecisionTests.Traits.prototype.isMatrix = function() {
+ return this.rows > 0 && this.cols > 1;
+ };
+
+ /**
+ * @param {string=} typename
+ */
+ glsBuiltinPrecisionTests.Traits.traitsFactory = function(typename) {
+ switch (typename) {
+ case 'boolean' : return new glsBuiltinPrecisionTests.TraitsBool();
+ case 'float' : case 'vec2' : case 'vec3' : case 'vec4' :
+ case 'mat2' : case 'mat2x3' : case 'mat2x4' :
+ case 'mat3x2' : case 'mat3' : case 'mat3x4' :
+ case 'mat4x2' : case 'mat4x3' : case 'mat4' :
+ return new glsBuiltinPrecisionTests.TraitsFloat(typename);
+ case 'int' : return new glsBuiltinPrecisionTests.TraitsInt();
+ case 'void' : return new glsBuiltinPrecisionTests.TraitsVoid();
+ default:
+ throw new Error('Invalid typename:' + typename);
+ }
+ };
+
+ glsBuiltinPrecisionTests.round = function(typename, fmt, value) {
+ var traits = glsBuiltinPrecisionTests.Traits.traitsFactory(typename);
+
+ if (value instanceof Array) {
+ var ret = [];
+ for (var i = 0; i < value.length; i++)
+ ret.push(traits.doRound(fmt, value[i]));
+ return ret;
+ }
+
+ if (value instanceof tcuMatrix.Matrix) {
+ var ret = new tcuMatrix.Matrix(value.rows, value.cols);
+ for (var i = 0; i < value.rows; i++)
+ for (var j = 0; j < value.cols; j++)
+ ret.set(i, j, traits.doRound(fmt, value.get(i, j)));
+ return ret;
+ }
+
+ return traits.doRound(fmt, value);
+ };
+
+ /**
+ * cast the input typed array to correct type
+ * @param {string} typename
+ * @param {goog.TypedArray} input
+ * @return {goog.TypedArray}
+ */
+ glsBuiltinPrecisionTests.cast = function(typename, input) {
+ var traits = glsBuiltinPrecisionTests.Traits.traitsFactory(typename);
+ return traits.doCast(input);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Traits}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid = function() {
+ glsBuiltinPrecisionTests.Traits.call(this, 'void');
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.TraitsVoid, glsBuiltinPrecisionTests.Traits);
+
+ /**
+ * @param {*} value
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doMakeIVal = function(value) {
+ return new tcuInterval.Interval();
+ };
+
+ /**
+ * @param {*} value1
+ * @param {*} value2
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doUnion = function(value1, value2) {
+ return new tcuInterval.Interval();
+ };
+
+ /**
+ * @param {*} value
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doContains = function(value) {
+ return true;
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {tcuInterval.Interval} ival
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doConvert = function(fmt, ival) {
+ return new tcuInterval.Interval();
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {*} ival
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doRound = function(fmt, ival) {
+ return new tcuInterval.Interval();
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {*} ival
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doPrintIVal = function(fmt, ival) {
+ return '()';
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {*} value
+ */
+ glsBuiltinPrecisionTests.TraitsVoid.prototype.doPrintValue = function(fmt, value) {
+ return '()';
+ };
+
+ glsBuiltinPrecisionTests.dataTypeSize = function(detailedType) {
+ var size = [1, 1];
+ switch (detailedType) {
+ case 'vec2' : size[0] = 2; break;
+ case 'vec3' : size[0] = 3; break;
+ case 'vec4' : size[0] = 4; break;
+ case 'mat2' : size = [2 , 2]; break;
+ case 'mat2x3' : size = [3 , 2]; break;
+ case 'mat2x4' : size = [4 , 2]; break;
+
+ case 'mat3x2' : size = [2 , 3]; break;
+ case 'mat3' : size = [3 , 3]; break;
+ case 'mat3x4' : size = [4 , 3]; break;
+
+ case 'mat4x2' : size = [2 , 4]; break;
+ case 'mat4x3' : size = [3 , 4]; break;
+ case 'mat4' : size = [4 , 4]; break;
+ }
+ return size;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Traits}
+ * @param {string} typename
+ * @param {string=} detailedType
+ */
+ glsBuiltinPrecisionTests.ScalarTraits = function(typename, detailedType) {
+ glsBuiltinPrecisionTests.Traits.call(this, typename);
+ var size = glsBuiltinPrecisionTests.dataTypeSize(detailedType);
+ this.rows = size[0];
+ this.cols = size[1];
+
+ /** type{tcuInterval.Interval} */ this.iVal;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ScalarTraits, glsBuiltinPrecisionTests.Traits);
+
+ glsBuiltinPrecisionTests.ScalarTraits.prototype = Object.create(glsBuiltinPrecisionTests.Traits.prototype);
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.constructor = glsBuiltinPrecisionTests.ScalarTraits;
+
+ /**
+ * @param {*} value
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.doMakeIVal = function(value) {
+ // Thankfully all scalar types have a well-defined conversion to `double`,
+ // hence Interval can represent their ranges without problems.
+ return new tcuInterval.Interval(/** @type {number} */ (value));
+ };
+
+ /**
+ * @param {tcuInterval.Interval} a
+ * @param {tcuInterval.Interval} b
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.doUnion = function(a, b) {
+ return a.operatorOrBinary(b);
+ };
+
+ /**
+ * @param {tcuInterval.Interval} a
+ * @param {number} value
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.doContains = function(a, value) {
+ return a.contains(new tcuInterval.Interval(value));
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {tcuInterval.Interval} ival
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.doConvert = function(fmt, ival) {
+ return fmt.convert(ival);
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {number} value
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.ScalarTraits.prototype.doRound = function(fmt, value) {
+ return fmt.roundOut(new tcuInterval.Interval(value), false);//TODO cast to double
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ScalarTraits}
+ * @param {string} detailedType
+ */
+ glsBuiltinPrecisionTests.TraitsFloat = function(detailedType) {
+ glsBuiltinPrecisionTests.ScalarTraits.call(this, 'float', detailedType);
+ };
+
+ glsBuiltinPrecisionTests.TraitsFloat.prototype = Object.create(glsBuiltinPrecisionTests.ScalarTraits.prototype);
+ glsBuiltinPrecisionTests.TraitsFloat.prototype.constructor = glsBuiltinPrecisionTests.TraitsFloat;
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {tcuInterval.Interval} ival
+ */
+ glsBuiltinPrecisionTests.TraitsFloat.prototype.doPrintIVal = function(fmt, ival) {
+ return fmt.intervalToHex(ival);
+ };
+
+ /**
+ * @param {goog.TypedArray} input
+ * @return {goog.TypedArray}
+ */
+ glsBuiltinPrecisionTests.TraitsFloat.prototype.doCast = function(input) {
+ return new Float32Array(input.buffer);
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {number} value
+ */
+ glsBuiltinPrecisionTests.TraitsFloat.prototype.doPrintValue = function(fmt, value) {
+ return fmt.floatToHex(value);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ScalarTraits}
+ */
+ glsBuiltinPrecisionTests.TraitsBool = function() {
+ glsBuiltinPrecisionTests.ScalarTraits.call(this, 'boolean');
+ };
+
+ glsBuiltinPrecisionTests.TraitsBool.prototype = Object.create(glsBuiltinPrecisionTests.ScalarTraits.prototype);
+ glsBuiltinPrecisionTests.TraitsBool.prototype.constructor = glsBuiltinPrecisionTests.TraitsBool;
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {tcuInterval.Interval} ival
+ */
+ glsBuiltinPrecisionTests.TraitsBool.prototype.doPrintIVal = function(fmt, ival) {
+ /** type{string} */ var os = '{';
+ var ifalse = new tcuInterval.Interval(0);
+ var itrue = new tcuInterval.Interval(1);
+ if (ival.contains(ifalse))
+ os += 'false';
+ if (ival.contains(ifalse) && ival.contains(itrue))
+ os += ', ';
+ if (ival.contains(itrue))
+ os += 'true';
+ os += '}';
+ return os;
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {boolean} value
+ */
+ glsBuiltinPrecisionTests.TraitsBool.prototype.doPrintValue = function(fmt, value) {
+ return value ? 'true' : 'false';
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ScalarTraits}
+ */
+ glsBuiltinPrecisionTests.TraitsInt = function() {
+ glsBuiltinPrecisionTests.ScalarTraits.call(this, 'int');
+ };
+
+ glsBuiltinPrecisionTests.TraitsInt.prototype = Object.create(glsBuiltinPrecisionTests.ScalarTraits.prototype);
+ glsBuiltinPrecisionTests.TraitsInt.prototype.constructor = glsBuiltinPrecisionTests.TraitsInt;
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {tcuInterval.Interval} ival
+ */
+ glsBuiltinPrecisionTests.TraitsInt.prototype.doPrintIVal = function(fmt, ival) {
+ return '[' + (ival.lo()) + ', ' + (ival.hi()) + ']';
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {number} value
+ */
+ glsBuiltinPrecisionTests.TraitsInt.prototype.doPrintValue = function(fmt, value) {
+ return value.toString(10);
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.Statement = function() {
+
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.execute = function(ctx) {
+ this.doExecute(ctx);
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.print = function() {
+ return this.doPrint();
+ };
+
+ glsBuiltinPrecisionTests.Statement.prototype.toString = function() {
+ return this.print();
+ };
+
+ /**
+ * Output the functions that this expression refers to
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ *
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.getUsedFuncs = function(dst) {
+ this.doGetUsedFuncs(dst);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.doExecute = function(ctx) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.doPrint = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * Output the functions that this expression refers to
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ *
+ */
+ glsBuiltinPrecisionTests.Statement.prototype.doGetUsedFuncs = function(dst) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Statement}
+ * @param {glsBuiltinPrecisionTests.Variable} variable
+ * @param {glsBuiltinPrecisionTests.Expr} value
+ * @param {boolean} isDeclaration
+ */
+ glsBuiltinPrecisionTests.VariableStatement = function(variable, value, isDeclaration) {
+ this.m_variable = variable;
+ this.m_value = value;
+ this.m_isDeclaration = isDeclaration;
+
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.VariableStatement, glsBuiltinPrecisionTests.Statement);
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ */
+ glsBuiltinPrecisionTests.VariableStatement.prototype.doExecute = function(ctx) {
+ ctx.env.bind(this.m_variable, this.m_value.evaluate(ctx));
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.VariableStatement.prototype.doPrint = function() {
+ var v = this.m_variable;
+ var os = '';
+ if (this.m_isDeclaration)
+ os += gluVarType.declareVariable(gluVarType.getVarTypeOf(v.typename),
+ v.getName());
+ else
+ os += v.getName();
+
+ os += ' = ' + this.m_value.printExpr() + ';\n';
+
+ return os;
+ };
+
+ /**
+ * Output the functions that this expression refers to
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ *
+ */
+ glsBuiltinPrecisionTests.VariableStatement.prototype.doGetUsedFuncs = function(dst) {
+ this.m_value.getUsedFuncs(dst);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Variable} variable
+ * @param {glsBuiltinPrecisionTests.Expr} definiens
+ * @return {glsBuiltinPrecisionTests.VariableStatement}
+ */
+ glsBuiltinPrecisionTests.variableDeclaration = function(variable, definiens) {
+ return new glsBuiltinPrecisionTests.VariableStatement(variable, definiens, true);
+ };
+
+ /**
+ * @param {string} typename
+ * @param {string} name
+ * @param {glsBuiltinPrecisionTests.ExpandContext} ctx
+ * @param {glsBuiltinPrecisionTests.Expr} expr
+ * @return {glsBuiltinPrecisionTests.Variable}
+ */
+ glsBuiltinPrecisionTests.bindExpression = function(typename, name, ctx, expr) {
+ var variable = ctx.genSym(typename, name);
+ ctx.addStatement(glsBuiltinPrecisionTests.variableDeclaration(variable, expr));
+ return variable;
+ };
+
+ /**
+ * Common base class for all expressions regardless of their type.
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.ExprBase = function() {};
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.ExprBase.prototype.printExpr = function() {
+ return this.doPrintExpr();
+ };
+
+ glsBuiltinPrecisionTests.ExprBase.prototype.toString = function() {
+ return this.printExpr();
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.ExprBase.prototype.doPrintExpr = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * Output the functions that this expression refers to
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ *
+ */
+ glsBuiltinPrecisionTests.ExprBase.prototype.getUsedFuncs = function(/*FuncSet&*/ dst) {
+ this.doGetUsedFuncs(dst);
+ };
+
+ /**
+ * Output the functions that this expression refers to
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ *
+ */
+ glsBuiltinPrecisionTests.ExprBase.prototype.doGetUsedFuncs = function(/*FuncSet&*/ dst) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * Type-specific operations for an expression representing type typename.
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ExprBase}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.Expr = function(typename) {
+ glsBuiltinPrecisionTests.ExprBase.call(this);
+ this.typename = typename;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Expr, glsBuiltinPrecisionTests.ExprBase);
+
+ /**
+ * Type-specific operations for an expression representing type typename.
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ */
+ glsBuiltinPrecisionTests.Expr.prototype.evaluate = function(ctx) {
+ return this.doEvaluate(ctx);
+ };
+
+ /**
+ * Type-specific operations for an expression representing type typename.
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ */
+ glsBuiltinPrecisionTests.Expr.prototype.doEvaluate = function(ctx) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Expr}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ * @param {string=} name
+ */
+ glsBuiltinPrecisionTests.Variable = function(typename, name) {
+ glsBuiltinPrecisionTests.Expr.call(this, typename);
+ /** @type {string} */ this.m_name = name || '<undefined>';
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Variable, glsBuiltinPrecisionTests.Expr);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Variable.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Variable.prototype.doPrintExpr = function() {
+ return this.m_name;
+ };
+
+ glsBuiltinPrecisionTests.Variable.prototype.toString = function() {
+ return this.doPrintExpr();
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @return {*}
+ */
+ glsBuiltinPrecisionTests.Variable.prototype.doEvaluate = function(ctx) {
+ return ctx.env.lookup(this);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Variable}
+ * @param {*=} t
+ */
+ glsBuiltinPrecisionTests.Void = function(t) {
+ glsBuiltinPrecisionTests.Variable.call(this, 'void');
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Void, glsBuiltinPrecisionTests.Variable);
+
+ glsBuiltinPrecisionTests.Void.prototype.doEvaluate = function(ctx) {
+ return undefined;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Variable}
+ * @param {number} value
+ */
+ glsBuiltinPrecisionTests.Constant = function(value) {
+ glsBuiltinPrecisionTests.Variable.call(this, 'float');
+ this.m_value = value;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Constant, glsBuiltinPrecisionTests.Variable);
+
+ glsBuiltinPrecisionTests.Constant.prototype.doEvaluate = function(ctx) {
+ return new tcuInterval.Interval(this.m_value);
+ };
+
+ /**
+ * @constructor
+ * @param {*} typename
+ */
+ glsBuiltinPrecisionTests.DefaultSampling = function(typename) {
+ this.typename = typename;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Expr}
+ * @param {glsBuiltinPrecisionTests.Variable} vector
+ * @param {number} index
+ */
+ glsBuiltinPrecisionTests.VectorVariable = function(vector, index) {
+ glsBuiltinPrecisionTests.Expr.call(this, vector.typename);
+ this.m_vector = vector;
+ this.m_index = index;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.VectorVariable, glsBuiltinPrecisionTests.Expr);
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.VectorVariable.prototype.doEvaluate = function(ctx) {
+ var tmp = this.m_vector.doEvaluate(ctx);
+ return tmp[this.m_index];
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Expr}
+ * @param {glsBuiltinPrecisionTests.Variable} matrix
+ * @param {number} row
+ * @param {number} col
+ */
+ glsBuiltinPrecisionTests.MatrixVariable = function(matrix, row, col) {
+ glsBuiltinPrecisionTests.Expr.call(this, matrix.typename);
+ this.m_matrix = matrix;
+ this.m_row = row;
+ this.m_col = col;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.MatrixVariable, glsBuiltinPrecisionTests.Expr);
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.MatrixVariable.prototype.doEvaluate = function(ctx) {
+ var tmp = this.m_matrix.doEvaluate(ctx);
+ return tmp.get(this.m_row, this.m_col);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Expr}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @param {glsBuiltinPrecisionTests.Expr=} arg0
+ * @param {glsBuiltinPrecisionTests.Expr=} arg1
+ * @param {glsBuiltinPrecisionTests.Expr=} arg2
+ * @param {glsBuiltinPrecisionTests.Expr=} arg3
+ */
+ glsBuiltinPrecisionTests.Apply = function(typename, func, arg0, arg1, arg2, arg3) {
+ glsBuiltinPrecisionTests.Expr.call(this, typename);
+ this.m_func = func;
+ /** @type {glsBuiltinPrecisionTests.Tuple4} */ this.m_args;
+ if (arg0 instanceof glsBuiltinPrecisionTests.Tuple4)
+ this.m_args = /** @type {glsBuiltinPrecisionTests.Tuple4} */ (arg0);
+ else {
+ this.m_args = new glsBuiltinPrecisionTests.Tuple4(arg0 || new glsBuiltinPrecisionTests.Void(),
+ arg1 || new glsBuiltinPrecisionTests.Void(),
+ arg2 || new glsBuiltinPrecisionTests.Void(),
+ arg3 || new glsBuiltinPrecisionTests.Void());
+ }
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Apply, glsBuiltinPrecisionTests.Expr);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Apply.prototype.doPrintExpr = function() {
+ var args = [this.m_args.a, this.m_args.b, this.m_args.c, this.m_args.d];
+ return this.m_func.print(args);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.Apply.prototype.doEvaluate = function(ctx) {
+ var debug = false;
+
+ if (debug) {
+ glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level = glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level || 0;
+ var level = glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level;
+ glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level++;
+ var name = this.m_func.constructor.toString();
+ name = name.replace(/[\s\S]*glsBuiltinPrecisionTests\./m, '').replace(/\.call[\s\S]*/m, '');
+ if (this.m_func.getName)
+ name += ' ' + this.m_func.getName();
+ console.log('<' + level + '> Function ' + name);
+ }
+
+ var a = this.m_args.a.evaluate(ctx);
+ var b = this.m_args.b.evaluate(ctx);
+ var c = this.m_args.c.evaluate(ctx);
+ var d = this.m_args.d.evaluate(ctx);
+ var retVal = this.m_func.applyFunction(ctx, a, b, c, d);
+
+ if (debug) {
+ console.log('<' + level + '> a: ' + a);
+ console.log('<' + level + '> b: ' + b);
+ console.log('<' + level + '> returning: ' + retVal);
+ glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level--;
+ }
+ return retVal;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @param {glsBuiltinPrecisionTests.Expr=} arg0
+ * @param {glsBuiltinPrecisionTests.Expr=} arg1
+ * @param {glsBuiltinPrecisionTests.Expr=} arg2
+ * @param {glsBuiltinPrecisionTests.Expr=} arg3
+ */
+ var app = function(func, arg0, arg1, arg2, arg3) {
+ return new glsBuiltinPrecisionTests.Apply('float', func, arg0, arg1, arg2, arg3);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ */
+ glsBuiltinPrecisionTests.Apply.prototype.doGetUsedFuncs = function(dst) {
+ this.m_func.getUsedFuncs(dst);
+ this.m_args.a.getUsedFuncs(dst);
+ this.m_args.b.getUsedFuncs(dst);
+ this.m_args.c.getUsedFuncs(dst);
+ this.m_args.d.getUsedFuncs(dst);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Apply}
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @param {glsBuiltinPrecisionTests.Expr=} arg0
+ * @param {glsBuiltinPrecisionTests.Expr=} arg1
+ * @param {glsBuiltinPrecisionTests.Expr=} arg2
+ * @param {glsBuiltinPrecisionTests.Expr=} arg3
+ */
+ glsBuiltinPrecisionTests.ApplyScalar = function(func, arg0, arg1, arg2, arg3) {
+ glsBuiltinPrecisionTests.Apply.call(this, 'float', func, arg0, arg1, arg2, arg3);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ApplyScalar, glsBuiltinPrecisionTests.Apply);
+
+ glsBuiltinPrecisionTests.ApplyScalar.prototype.doEvaluate = function(ctx) {
+ var debug = false;
+
+ if (debug) {
+ glsBuiltinPrecisionTests.ApplyScalar.prototype.doEvaluate.level = glsBuiltinPrecisionTests.ApplyScalar.prototype.doEvaluate.level || 0;
+ var level = glsBuiltinPrecisionTests.ApplyScalar.prototype.doEvaluate.level;
+ glsBuiltinPrecisionTests.ApplyScalar.prototype.doEvaluate.level++;
+ var name = this.m_func.constructor.toString();
+ name = name.replace(/[\s\S]*glsBuiltinPrecisionTests\./m, '').replace(/\.call[\s\S]*/m, '');
+ if (this.m_func.getName)
+ name += ' ' + this.m_func.getName();
+ console.log('scalar<' + level + '> Function ' + name);
+ }
+
+ var a = this.m_args.a.evaluate(ctx);
+ var b = this.m_args.b.evaluate(ctx);
+ var c = this.m_args.c.evaluate(ctx);
+ var d = this.m_args.d.evaluate(ctx);
+ if (a instanceof Array) {
+ var ret = [];
+ for (var i = 0; i < a.length; i++) {
+ var p0 = a instanceof Array ? a[i] : a;
+ var p1 = b instanceof Array ? b[i] : b;
+ var p2 = c instanceof Array ? c[i] : c;
+ var p3 = d instanceof Array ? d[i] : d;
+ ret.push(this.m_func.applyFunction(ctx, p0, p1, p2, p3));
+ }
+ return ret;
+ }
+
+ var retVal = this.m_func.applyFunction(ctx, a, b, c, d);
+
+ if (debug) {
+ console.log('scalar<' + level + '> a: ' + a);
+ console.log('scalar<' + level + '> b: ' + b);
+ console.log('scalar<' + level + '> return1: ' + ret);
+ console.log('scalar<' + level + '> return2: ' + retVal);
+ glsBuiltinPrecisionTests.Apply.prototype.doEvaluate.level--;
+ }
+
+ return retVal;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Apply}
+ */
+ glsBuiltinPrecisionTests.ApplyVar = function(typename, func, arg0, arg1, arg2, arg3) {
+ glsBuiltinPrecisionTests.Apply.call(this, typename, func, arg0, arg1, arg2, arg3);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ApplyVar, glsBuiltinPrecisionTests.Apply);
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.ApplyVar.prototype.doEvaluate = function(ctx) {
+ return this.m_func.applyFunction(ctx,
+ ctx.env.lookup(this.m_args.a), ctx.env.lookup(this.m_args.b),
+ ctx.env.lookup(this.m_args.c), ctx.env.lookup(this.m_args.d),
+ [this.m_args.a.getName(), this.m_args.b.getName(),
+ this.m_args.c.getName(), this.m_args.d.getName()]);
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.FuncBase = function() {};
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.getName = function() {
+ return '';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.getRequiredExtension = function() {
+ return '';
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.print = function(args) {
+ return '';
+ };
+
+ /**
+ * Index of output parameter, or -1 if none of the parameters is output.
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.getOutParamIndex = function() {
+ return -1;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.printDefinition = function() {
+ return this.doPrintDefinition();
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.doPrintDefinition = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * typedef set<const FuncBase*> FuncSet;
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.getUsedFuncs = function(dst) {
+ this.doGetUsedFuncs(dst);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ */
+ glsBuiltinPrecisionTests.FuncBase.prototype.doGetUsedFuncs = function(dst) {};
+
+ /*************************************/
+ /**
+ * \brief Function objects.
+ *
+ * Each Func object represents a GLSL function. It can be applied to interval
+ * arguments, and it returns the an interval that is a conservative
+ * approximation of the image of the GLSL function over the argument
+ * intervals. That is, it is given a set of possible arguments and it returns
+ * the set of possible values.
+ *
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncBase}
+ * @param {glsBuiltinPrecisionTests.Signature} Sig_ template <typename Sig_>
+ */
+ glsBuiltinPrecisionTests.Func = function(Sig_) {
+ glsBuiltinPrecisionTests.FuncBase.call(this);
+ this.Sig = Sig_;
+ this.Ret = this.Sig.Ret;
+ this.Arg0 = this.Sig.Arg0;
+ this.Arg1 = this.Sig.Arg1;
+ this.Arg2 = this.Sig.Arg2;
+ this.Arg3 = this.Sig.Arg3;
+ };
+
+ glsBuiltinPrecisionTests.Func.prototype = Object.create(glsBuiltinPrecisionTests.FuncBase.prototype);
+ glsBuiltinPrecisionTests.Func.prototype.constructor = glsBuiltinPrecisionTests.Func;
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Func.prototype.print = function(args) {
+ return this.doPrint(args);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Intervals=} Iarg0
+ * @param {glsBuiltinPrecisionTests.Intervals=} Iarg1
+ * @param {glsBuiltinPrecisionTests.Intervals=} Iarg2
+ * @param {glsBuiltinPrecisionTests.Intervals=} Iarg3
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.Func.prototype.applyFunction = function(ctx, Iarg0, Iarg1, Iarg2, Iarg3, variablenames) {
+ return this.applyArgs(ctx, new glsBuiltinPrecisionTests.Tuple4(Iarg0, Iarg1, Iarg2, Iarg3), variablenames);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} args
+ * @return {glsBuiltinPrecisionTests.Intervals}
+ */
+ glsBuiltinPrecisionTests.Func.prototype.applyArgs = function(ctx, args, variablenames) {
+ return this.doApply(ctx, args, variablenames);
+ };
+
+ /**
+ * @return {glsBuiltinPrecisionTests.ParamNames}
+ */
+ glsBuiltinPrecisionTests.Func.prototype.getParamNames = function() {
+ return this.doGetParamNames();
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Func.prototype.doPrint = function(args) {
+ /** type{string} */ var os = this.getName() + '(';
+
+ // TODO: fix the generics
+ for (var i = 0; i < args.length; i++)
+ if (glsBuiltinPrecisionTests.isTypeValid(args[i].typename)) {
+ if (i != 0)
+ os += ', ';
+ os += args[i];
+ }
+
+ os += ')';
+
+ return os;
+ };
+
+ /**
+ * @return {glsBuiltinPrecisionTests.ParamNames} args
+ */
+ glsBuiltinPrecisionTests.Func.prototype.doGetParamNames = function() {
+ /** @type {glsBuiltinPrecisionTests.ParamNames} */ var names = new glsBuiltinPrecisionTests.Tuple4('a', 'b', 'c', 'd');
+ return names;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Func}
+ * @param {glsBuiltinPrecisionTests.Signature} Sig template <typename Sig>
+ *
+ */
+ glsBuiltinPrecisionTests.PrimitiveFunc = function(Sig) {
+ glsBuiltinPrecisionTests.Func.call(this, Sig);
+ this.Ret = Sig.Ret;
+ };
+
+ glsBuiltinPrecisionTests.PrimitiveFunc.prototype = Object.create(glsBuiltinPrecisionTests.Func.prototype);
+ glsBuiltinPrecisionTests.PrimitiveFunc.prototype.constructor = glsBuiltinPrecisionTests.PrimitiveFunc;
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {string} typename
+ *
+ */
+ glsBuiltinPrecisionTests.Cond = function(typename) {
+ var sig = new glsBuiltinPrecisionTests.Signature(typename, 'boolean', typename, typename);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Cond, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ glsBuiltinPrecisionTests.Cond.prototype.getName = function() {
+ return '_cond';
+ };
+
+ glsBuiltinPrecisionTests.Cond.prototype.doPrint = function(args) {
+ var str = '(' + args[0] + ' ? ' + args[1] + ' : ' + args[2] + ')';
+ return str;
+ };
+
+ glsBuiltinPrecisionTests.Cond.prototype.doApply = function(ctx, iargs) {
+ var ret;
+ if (glsBuiltinPrecisionTests.contains(this.Sig.Arg0, iargs.a, 1))
+ ret = iargs.b;
+ if (glsBuiltinPrecisionTests.contains(this.Sig.Arg0, iargs.a, 0)) {
+ if (ret)
+ ret = glsBuiltinPrecisionTests.union(this.Sig.Ret, ret, iargs.c);
+ else
+ ret = iargs.c;
+ }
+ if (ret)
+ return ret;
+ return new tcuInterval.Interval();
+ };
+
+ /**
+ * If multipleInputs is false, GenVec duplicates first input to proper size
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {number} size
+ * @param {boolean=} multipleInputs
+ */
+ glsBuiltinPrecisionTests.GenVec = function(size, multipleInputs) {
+ var vecName = glsBuiltinPrecisionTests.sizeToName(size);
+ var p = [
+ size >= 1 ? 'float' : undefined,
+ size >= 2 ? 'float' : undefined,
+ size >= 3 ? 'float' : undefined,
+ size >= 4 ? 'float' : undefined
+ ];
+ var sig = new glsBuiltinPrecisionTests.Signature(vecName, p[0], p[1], p[2], p[3]);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ this.size = size;
+ this.vecName = vecName;
+ this.multipleInputs = multipleInputs || false;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.GenVec, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ glsBuiltinPrecisionTests.GenVec.prototype.getName = function() {
+ return this.vecName;
+ };
+
+ glsBuiltinPrecisionTests.GenVec.prototype.doApply = function(ctx, iargs) {
+ if (this.size == 1)
+ return iargs.a;
+
+ var ret = this.multipleInputs ?
+ [iargs.a, iargs.b, iargs.c, iargs.d] :
+ [iargs.a, iargs.a, iargs.a, iargs.a];
+
+ return ret.slice(0, this.size);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.GenMat = function(rows, cols) {
+ var name = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', rows, cols);
+ var vecName = glsBuiltinPrecisionTests.sizeToName(rows);
+ var p = [
+ cols >= 1 ? vecName : undefined,
+ cols >= 2 ? vecName : undefined,
+ cols >= 3 ? vecName : undefined,
+ cols >= 4 ? vecName : undefined
+ ];
+ var sig = new glsBuiltinPrecisionTests.Signature(name, p[0], p[1], p[2], p[3]);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ this.rows = rows;
+ this.cols = cols;
+ this.name = name;
+ this.vecName = vecName;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.GenMat, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ glsBuiltinPrecisionTests.GenMat.prototype.getName = function() {
+ return this.name;
+ };
+
+ glsBuiltinPrecisionTests.GenMat.prototype.doApply = function(ctx, iargs) {
+ var ret = new tcuMatrix.Matrix(this.rows, this.cols);
+ var inputs = [iargs.a, iargs.b, iargs.c, iargs.d];
+
+ for (var i = 0; i < this.rows; i++)
+ for (var j = 0; j < this.cols; j++)
+ ret.set(i, j, inputs[j][i]);
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {string} typename
+ *
+ */
+ glsBuiltinPrecisionTests.CompareOperator = function(typename) {
+ var sig = new glsBuiltinPrecisionTests.Signature('boolean', typename, typename);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.CompareOperator, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ glsBuiltinPrecisionTests.CompareOperator.prototype.doPrint = function(args) {
+ var str = '(' + args[0] + this.getSymbol() + args[1] + ')';
+ return str;
+ };
+
+ glsBuiltinPrecisionTests.CompareOperator.prototype.doApply = function(ctx, iargs) {
+ var arg0 = iargs.a;
+ var arg1 = iargs.b;
+
+ var ret = new tcuInterval.Interval();
+
+ if (this.canSucceed(arg0, arg1))
+ ret = new tcuInterval.Interval(1);
+ if (this.canFail(arg0, arg1))
+ ret.operatorOrAssignBinary(new tcuInterval.Interval(0));
+
+ return ret;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CompareOperator.prototype.getSymbol = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.CompareOperator.prototype.canSucceed = function(arg0, arg1) {
+ throw new Error('Virtual function. Please override.');
+ };
+ /**
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @return {boolean}
+ */
+ glsBuiltinPrecisionTests.CompareOperator.prototype.canFail = function(arg0, arg1) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CompareOperator}
+ * @param {string} typename
+ *
+ */
+ glsBuiltinPrecisionTests.LessThan = function(typename) {
+ glsBuiltinPrecisionTests.CompareOperator.call(this, typename);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.LessThan, glsBuiltinPrecisionTests.CompareOperator);
+
+ glsBuiltinPrecisionTests.LessThan.prototype.getSymbol = function() {
+ return '<';
+ };
+
+ glsBuiltinPrecisionTests.LessThan.prototype.canSucceed = function(a, b) {
+ return (a.lo() < b.hi());
+ };
+
+ glsBuiltinPrecisionTests.LessThan.prototype.canFail = function(a, b) {
+ return !(a.hi() < b.lo());
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ *
+ */
+ glsBuiltinPrecisionTests.FloatFunc1 = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ };
+
+ glsBuiltinPrecisionTests.FloatFunc1.prototype = Object.create(glsBuiltinPrecisionTests.PrimitiveFunc.prototype);
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.constructor = glsBuiltinPrecisionTests.FloatFunc1;
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ return this.applyMonotone(ctx, a);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} iarg0
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.applyMonotone = function(ctx, iarg0) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y) {
+ x = x || 0;
+ return this.applyPoint(ctx, x);
+ };
+ ret = tcuInterval.applyMonotone1(iarg0, body.bind(this));
+
+ ret.operatorOrAssignBinary(this.innerExtrema(ctx, iarg0));
+
+ ret.operatorAndAssignBinary(this.getCodomain().operatorOrBinary(new tcuInterval.Interval(NaN)));
+
+ return ctx.format.convert(ret);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.innerExtrema = function(ctx, iargs) {
+ return new tcuInterval.Interval(); // empty interval, i.e. no extrema
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} arg0
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.applyPoint = function(ctx, arg0) {
+ var exact = this.applyExact(arg0);
+ var prec = this.precision(ctx, exact, arg0);
+
+ var a = new tcuInterval.Interval(exact);
+ var b = tcuInterval.withNumbers(-prec, prec);
+ return tcuInterval.Interval.operatorSum(a, b);
+ };
+
+ /**
+ * @param {number} x
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.applyExact = function(x) {
+ throw new Error('Internal error. Cannot apply');
+ };
+
+ /**
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.getCodomain = function() {
+ return tcuInterval.unbounded(true);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc1.prototype.precision = function(ctx, x, y) {
+ return 0;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc1}
+ */
+ glsBuiltinPrecisionTests.Negate = function() {
+ glsBuiltinPrecisionTests.FloatFunc1.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Negate, glsBuiltinPrecisionTests.FloatFunc1);
+
+ glsBuiltinPrecisionTests.Negate.prototype.getName = function() {
+ return '_negate';
+ };
+
+ glsBuiltinPrecisionTests.Negate.prototype.doPrint = function(args) {
+ return '-' + args[0];
+ };
+
+ glsBuiltinPrecisionTests.Negate.prototype.precision = function(ctx, ret, x) {
+ return 0;
+ };
+ glsBuiltinPrecisionTests.Negate.prototype.applyExact = function(x) {
+ return -x;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc1}
+ */
+ glsBuiltinPrecisionTests.InverseSqrt = function() {
+ glsBuiltinPrecisionTests.FloatFunc1.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.InverseSqrt, glsBuiltinPrecisionTests.FloatFunc1);
+
+ glsBuiltinPrecisionTests.InverseSqrt.prototype.getName = function() {
+ return 'inversesqrt';
+ };
+
+ glsBuiltinPrecisionTests.InverseSqrt.prototype.precision = function(ctx, ret, x) {
+ if (x <= 0)
+ return NaN;
+ return ctx.format.ulp(ret, 2.0);
+ };
+
+ glsBuiltinPrecisionTests.InverseSqrt.prototype.applyExact = function(x) {
+ return 1 / Math.sqrt(x);
+ };
+
+ glsBuiltinPrecisionTests.InverseSqrt.prototype.getCodomain = function() {
+ return tcuInterval.withNumbers(0, Infinity);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc1}
+ */
+ glsBuiltinPrecisionTests.Round = function() {
+ glsBuiltinPrecisionTests.FloatFunc1.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Round, glsBuiltinPrecisionTests.FloatFunc1);
+
+ glsBuiltinPrecisionTests.Round.prototype.getName = function() {
+ return 'round';
+ };
+
+ glsBuiltinPrecisionTests.Round.prototype.precision = function(ctx, ret, x) {
+ return 0;
+ };
+
+ glsBuiltinPrecisionTests.Round.prototype.applyPoint = function(ctx, x) {
+ var truncated = Math.trunc(x);
+ var fract = x - truncated;
+ var ret = new tcuInterval.Interval();
+
+ // When x is inf or -inf, truncated would be inf or -inf too. Then fract
+ // would be NaN (inf - inf). While in native c code, it would be 0 (inf) or -0 (-inf).
+ // This behavior in JS differs from that in native c code.
+ if (Math.abs(fract) <= 0.5 || isNaN(fract))
+ ret.operatorOrAssignBinary(new tcuInterval.Interval(truncated));
+ if (Math.abs(fract) >= 0.5)
+ ret.operatorOrAssignBinary(new tcuInterval.Interval(truncated + deMath.deSign(fract)));
+
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc1}
+ * @param {string} name
+ * @param {tcuInterval.DoubleFunc1} func
+ */
+ glsBuiltinPrecisionTests.CFloatFunc1 = function(name, func) {
+ glsBuiltinPrecisionTests.FloatFunc1.call(this);
+ /** @type {string} */ this.m_name = name;
+ /** @type {tcuInterval.DoubleFunc1} */this.m_func = func;
+ };
+
+ glsBuiltinPrecisionTests.CFloatFunc1.prototype = Object.create(glsBuiltinPrecisionTests.FloatFunc1.prototype);
+ glsBuiltinPrecisionTests.CFloatFunc1.prototype.constructor = glsBuiltinPrecisionTests.CFloatFunc1;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CFloatFunc1.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @param {number} x
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.CFloatFunc1.prototype.applyExact = function(x) {
+ return this.m_func(x);
+ };
+
+ /**
+ * PrimitiveFunc<Signature<float, float, float> >
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2 = function() {
+ /** @type {glsBuiltinPrecisionTests.Signature} */ var Sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float');
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, Sig);
+ };
+
+ glsBuiltinPrecisionTests.FloatFunc2.prototype = Object.create(glsBuiltinPrecisionTests.PrimitiveFunc.prototype);
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.constructor = glsBuiltinPrecisionTests.FloatFunc2;
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ var b = /** @type {tcuInterval.Interval} */ (iargs.b);
+ return this.applyMonotone(ctx, a, b);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} xi
+ * @param {tcuInterval.Interval} yi
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.applyMonotone = function(ctx, xi, yi) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y) {
+ x = x || 0;
+ y = y || 0;
+ return this.applyPoint(ctx, x, y);
+ };
+ ret = tcuInterval.applyMonotone2(xi, yi, body.bind(this));
+
+ ret.operatorOrAssignBinary(this.innerExtrema(ctx, xi, yi));
+
+ ret.operatorAndAssignBinary(this.getCodomain().operatorOrBinary(new tcuInterval.Interval(NaN)));
+
+ return ctx.format.convert(ret);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} xi
+ * @param {tcuInterval.Interval} yi
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.innerExtrema = function(ctx, xi, yi) {
+ return new tcuInterval.Interval(); // empty interval, i.e. no extrema
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} x
+ * @param {number} y
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.applyPoint = function(ctx, x, y) {
+ /** @type {number} */ var exact = this.applyExact(x, y);
+ var prec = this.precision(ctx, exact, x, y);
+
+ var a = new tcuInterval.Interval(exact);
+ var b = tcuInterval.withNumbers(-prec, prec);
+ return tcuInterval.Interval.operatorSum(a, b);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.applyExact = function(x, y) {
+ throw new Error('Virtual function. Please override');
+ };
+
+ /**
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.getCodomain = function() {
+ return tcuInterval.unbounded(true);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} ret
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc2.prototype.precision = function(ctx, ret, x, y) {
+ throw new Error('Virtual function. Please override');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc2}
+ * @param {string} name
+ * @param {tcuInterval.DoubleFunc2} func
+ */
+ glsBuiltinPrecisionTests.CFloatFunc2 = function(name, func) {
+ glsBuiltinPrecisionTests.FloatFunc2.call(this);
+ /** @type {string} */ this.m_name = name;
+ /** @type {tcuInterval.DoubleFunc2} */ this.m_func = func;
+ };
+
+ glsBuiltinPrecisionTests.CFloatFunc2.prototype = Object.create(glsBuiltinPrecisionTests.FloatFunc2.prototype);
+ glsBuiltinPrecisionTests.CFloatFunc2.prototype.constructor = glsBuiltinPrecisionTests.CFloatFunc2;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CFloatFunc2.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.CFloatFunc2.prototype.applyExact = function(x, y) {
+ return this.m_func(x, y);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc2}
+ */
+ glsBuiltinPrecisionTests.InfixOperator = function() {
+ glsBuiltinPrecisionTests.FloatFunc2.call(this);
+ };
+
+ glsBuiltinPrecisionTests.InfixOperator.prototype = Object.create(glsBuiltinPrecisionTests.FloatFunc2.prototype);
+ glsBuiltinPrecisionTests.InfixOperator.prototype.constructor = glsBuiltinPrecisionTests.InfixOperator;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.InfixOperator.prototype.getSymbol = function() {
+ glsBuiltinPrecisionTests.FloatFunc2.call(this);
+ return '';
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.InfixOperator.prototype.doPrint = function(args) {
+ return '(' + args[0] + ' ' + this.getSymbol() + ' ' + args[1] + ')';
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} x
+ * @param {number} y
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.InfixOperator.prototype.applyPoint = function(ctx, x, y) {
+ /** @type {number} */ var exact = this.applyExact(x, y);
+
+ // Allow either representable number on both sides of the exact value,
+ // but require exactly representable values to be preserved.
+ return ctx.format.roundOut(new tcuInterval.Interval(exact), isFinite(x) && isFinite(y));
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.InfixOperator.prototype.precision = function(ctx, x, y, z) {
+ return 0;
+ };
+
+ /**
+ * Signature<float, float, float, float>
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3 = function() {
+ /** @type {glsBuiltinPrecisionTests.Signature} */ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float', 'float');
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ };
+
+ glsBuiltinPrecisionTests.FloatFunc3.prototype = Object.create(glsBuiltinPrecisionTests.PrimitiveFunc.prototype);
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.constructor = glsBuiltinPrecisionTests.FloatFunc3;
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ var b = /** @type {tcuInterval.Interval} */ (iargs.b);
+ var c = /** @type {tcuInterval.Interval} */ (iargs.c);
+ var retVal = this.applyMonotone(ctx, a, b, c);
+ return retVal;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} xi
+ * @param {tcuInterval.Interval} yi
+ * @param {tcuInterval.Interval} zi
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.applyMonotone = function(ctx, xi, yi, zi) {
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @param {number=} z
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y, z) {
+ x = x || 0;
+ y = y || 0;
+ z = z || 0;
+ return this.applyPoint(ctx, x, y, z);
+ };
+ var ret = tcuInterval.applyMonotone3(xi, yi, zi, body.bind(this));
+ var retVal;
+
+ ret.operatorOrAssignBinary(this.innerExtrema(ctx, xi, yi, zi));
+
+ ret.operatorAndAssignBinary(this.getCodomain().operatorOrBinary(new tcuInterval.Interval(NaN)));
+
+ retVal = ctx.format.convert(ret);
+ return retVal;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} xi
+ * @param {tcuInterval.Interval} yi
+ * @param {tcuInterval.Interval} zi
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.innerExtrema = function(ctx, xi, yi, zi) {
+ return new tcuInterval.Interval(); // empty interval, i.e. no extrema
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.applyPoint = function(ctx, x, y, z) {
+ /** @type {number} */ var exact = this.applyExact(x, y, z);
+ /** @type {number} */ var prec = this.precision(ctx, exact, x, y, z);
+
+ var a = new tcuInterval.Interval(exact);
+ var b = tcuInterval.withNumbers(-prec, prec);
+ return tcuInterval.Interval.operatorSum(a, b);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.applyExact = function(x, y, z) {
+ throw new Error('Virtual function. Please override');
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {number} result
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.precision = function(ctx, result, x, y, z) {
+ throw new Error('Virtual function. Please override');
+ };
+
+ /**
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.FloatFunc3.prototype.getCodomain = function() {
+ return tcuInterval.unbounded(true);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FloatFunc3}
+ */
+ glsBuiltinPrecisionTests.Clamp = function() {
+ glsBuiltinPrecisionTests.FloatFunc3.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Clamp, glsBuiltinPrecisionTests.FloatFunc3);
+
+ glsBuiltinPrecisionTests.Clamp.prototype.getName = function() {
+ return 'clamp';
+ };
+
+ glsBuiltinPrecisionTests.Clamp.prototype.applyExact = function(x, minVal, maxVal) {
+ var debug = false;
+ var retVal;
+
+ retVal = deMath.clamp(x, minVal, maxVal);
+ if (debug) {
+ console.log('> minVal: ' + minVal);
+ console.log('> maxVal: ' + maxVal);
+ console.log('> x: ' + x);
+ console.log('> ret: ' + retVal);
+ }
+ return retVal;
+
+ };
+
+ glsBuiltinPrecisionTests.Clamp.prototype.precision = function(ctx, result, x, minVal, maxVal) {
+ var debug = false;
+ var retVal;
+
+ retVal = minVal > maxVal ? NaN : 0;
+
+ if (debug) {
+ console.log('precision> minVal: ' + minVal);
+ console.log('precision> maxVal: ' + maxVal);
+ console.log('precision> x: ' + x);
+ console.log('precision> ret: ' + retVal);
+ }
+
+ return retVal;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.InfixOperator}
+ */
+ glsBuiltinPrecisionTests.Add = function() {
+ glsBuiltinPrecisionTests.InfixOperator.call(this);
+ };
+
+ glsBuiltinPrecisionTests.Add.prototype = Object.create(glsBuiltinPrecisionTests.InfixOperator.prototype);
+ glsBuiltinPrecisionTests.Add.prototype.constructor = glsBuiltinPrecisionTests.Add;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Add.prototype.getName = function() {
+ return 'add';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Add.prototype.getSymbol = function() {
+ return '+';
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.Add.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ var b = /** @type {tcuInterval.Interval} */ (iargs.b);
+ // Fast-path for common case
+ if (iargs.a.isOrdinary() && iargs.b.isOrdinary()) {
+ /** type{tcuInterval.Interval} */ var ret;
+ ret = tcuInterval.setIntervalBounds(
+ function(dummy) {
+ return iargs.a.lo() + iargs.b.lo();
+ },
+ function(dummy) {
+ return iargs.a.hi() + iargs.b.hi();
+ });
+ return ctx.format.convert(ctx.format.roundOut(ret, true));
+ }
+ return this.applyMonotone(ctx, a, b);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.Add.prototype.applyExact = function(x, y) {
+ return x + y;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.InfixOperator}
+ */
+ glsBuiltinPrecisionTests.Sub = function() {
+ glsBuiltinPrecisionTests.InfixOperator.call(this);
+ };
+
+ glsBuiltinPrecisionTests.Sub.prototype = Object.create(glsBuiltinPrecisionTests.InfixOperator.prototype);
+ glsBuiltinPrecisionTests.Sub.prototype.constructor = glsBuiltinPrecisionTests.Sub;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Sub.prototype.getName = function() {
+ return 'sub';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Sub.prototype.getSymbol = function() {
+ return '-';
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.Sub.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ var b = /** @type {tcuInterval.Interval} */ (iargs.b);
+ var retVal;
+
+ // Fast-path for common case
+ if (iargs.a.isOrdinary() && iargs.b.isOrdinary()) {
+ /** type{tcuInterval.Interval} */ var ret;
+ ret = tcuInterval.setIntervalBounds(
+ function(dummy) {
+ return iargs.a.lo() - iargs.b.hi();
+ },
+ function(dummy) {
+ return iargs.a.hi() - iargs.b.lo();
+ });
+ return ctx.format.convert(ctx.format.roundOut(ret, true));
+ }
+ retVal = this.applyMonotone(ctx, a, b);
+ return retVal;
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.Sub.prototype.applyExact = function(x, y) {
+ return x - y;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.InfixOperator}
+ */
+ glsBuiltinPrecisionTests.Mul = function() {
+ glsBuiltinPrecisionTests.InfixOperator.call(this);
+ };
+
+ glsBuiltinPrecisionTests.Mul.prototype = Object.create(glsBuiltinPrecisionTests.InfixOperator.prototype);
+ glsBuiltinPrecisionTests.Mul.prototype.constructor = glsBuiltinPrecisionTests.Mul;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Mul.prototype.getName = function() {
+ return 'mul';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Mul.prototype.getSymbol = function() {
+ return '*';
+ };
+
+ glsBuiltinPrecisionTests.isNegative = function(n) {
+ return ((n = +n) || 1 / n) < 0;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.Mul.prototype.doApply = function(ctx, iargs) {
+ var a = /** @type {tcuInterval.Interval} */ (iargs.a);
+ var b = /** @type {tcuInterval.Interval} */ (iargs.b);
+ // Fast-path for common case
+ if (iargs.a.isOrdinary() && iargs.b.isOrdinary()) {
+ /** type{tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+ if (glsBuiltinPrecisionTests.isNegative(a.hi())) {
+ a = a.operatorNegative();
+ b = b.operatorNegative();
+ }
+ if (a.lo() >= 0 && b.lo() >= 0) {
+ ret = tcuInterval.setIntervalBounds(
+ function(dummy) {
+ return iargs.a.lo() * iargs.b.lo();
+ },
+ function(dummy) {
+ return iargs.a.hi() * iargs.b.hi();
+ });
+ return ctx.format.convert(ctx.format.roundOut(ret, true));
+ }
+ if (a.lo() >= 0 && b.hi() <= 0) {
+ ret = tcuInterval.setIntervalBounds(
+ function(dummy) {
+ return iargs.a.hi() * iargs.b.lo();
+ },
+ function(dummy) {
+ return iargs.a.lo() * iargs.b.hi();
+ });
+ return ctx.format.convert(ctx.format.roundOut(ret, true));
+ }
+ }
+
+ return this.applyMonotone(ctx, a, b);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.Mul.prototype.applyExact = function(x, y) {
+ return x * y;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} xi
+ * @param {tcuInterval.Interval} yi
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.Mul.prototype.innerExtrema = function(ctx, xi, yi) {
+ if (((xi.contains(tcuInterval.NEGATIVE_INFINITY) || xi.contains(tcuInterval.POSITIVE_INFINITY)) && yi.contains(tcuInterval.ZERO)) ||
+ ((yi.contains(tcuInterval.NEGATIVE_INFINITY) || yi.contains(tcuInterval.POSITIVE_INFINITY)) && xi.contains(tcuInterval.ZERO)))
+ return new tcuInterval.Interval(NaN);
+
+ return new tcuInterval.Interval(); // empty interval, i.e. no extrema
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.InfixOperator}
+ */
+ glsBuiltinPrecisionTests.Div = function() {
+ glsBuiltinPrecisionTests.InfixOperator.call(this);
+ };
+
+ glsBuiltinPrecisionTests.Div.prototype = Object.create(glsBuiltinPrecisionTests.InfixOperator.prototype);
+ glsBuiltinPrecisionTests.Div.prototype.constructor = glsBuiltinPrecisionTests.Div;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Div.prototype.getName = function() {
+ return 'div';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Div.prototype.getSymbol = function() {
+ return '/';
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {tcuInterval.Interval} nom
+ * @param {tcuInterval.Interval} den
+ * @return {tcuInterval.Interval}
+ */
+ glsBuiltinPrecisionTests.Div.prototype.innerExtrema = function(ctx, nom, den) {
+ var ret = new tcuInterval.Interval();
+ if (den.contains(tcuInterval.ZERO)) {
+ if (nom.contains(tcuInterval.ZERO))
+ ret.operatorOrAssignBinary(tcuInterval.NAN);
+ if (nom.lo() < 0 || nom.hi() > 0.0)
+ ret.operatorOrAssignBinary(tcuInterval.unbounded());
+ }
+
+ return ret;
+ };
+
+ glsBuiltinPrecisionTests.Div.prototype.precision = function(ctx, ret, nom, den) {
+ var fmt = ctx.format;
+
+ // \todo [2014-03-05 lauri] Check that the limits in GLSL 3.10 are actually correct.
+ // For now, we assume that division's precision is 2.5 ULP when the value is within
+ // [2^MINEXP, 2^MAXEXP-1]
+
+ if (den === 0)
+ return 0; // Result must be exactly inf
+ else if (deMath.deInBounds32(Math.abs(den),
+ deMath.deLdExp(1, fmt.getMinExp()),
+ deMath.deLdExp(1, fmt.getMaxExp() - 1)))
+ return fmt.ulp(ret, 2.5);
+ else
+ return Infinity; // Can be any number, but must be a number.
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.Div.prototype.applyExact = function(x, y) {
+ return x / y;
+ };
+
+ glsBuiltinPrecisionTests.Div.prototype.applyPoint = function(ctx, x, y) {
+ var ret = glsBuiltinPrecisionTests.FloatFunc2.prototype.applyPoint.call(this, ctx, x, y);
+ if (isFinite(x) && isFinite(y) && y != 0) {
+ var dst = ctx.format.convert(ret);
+ if (dst.contains(tcuInterval.NEGATIVE_INFINITY)) {
+ ret.operatorOrAssignBinary(-ctx.format.getMaxValue());
+ }
+ if (dst.contains(tcuInterval.POSITIVE_INFINITY)) {
+ ret.operatorOrAssignBinary(+ctx.format.getMaxValue());
+ }
+ }
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ */
+ glsBuiltinPrecisionTests.CompWiseFunc = function(typename, Sig) {
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, Sig);
+ this.typename = typename;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.CompWiseFunc, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CompWiseFunc.prototype.getName = function() {
+ return this.doGetScalarFunc().getName();
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CompWiseFunc.prototype.doPrint = function(args) {
+ return this.doGetScalarFunc().print(args);
+ };
+
+ /**
+ * @return {glsBuiltinPrecisionTests.Func}
+ */
+ glsBuiltinPrecisionTests.CompWiseFunc.prototype.doGetScalarFunc = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CompWiseFunc}
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.CompMatFuncBase = function(rows, cols) {
+ var name = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', rows, cols);
+ glsBuiltinPrecisionTests.CompWiseFunc.call(this, 'float', new glsBuiltinPrecisionTests.Signature(name, name, name));
+ this.rows = rows;
+ this.cols = cols;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.CompMatFuncBase, glsBuiltinPrecisionTests.CompWiseFunc);
+
+ glsBuiltinPrecisionTests.CompMatFuncBase.prototype.doApply = function(ctx, iargs) {
+ var ret = new tcuMatrix.Matrix(this.rows, this.cols);
+ var fun = this.doGetScalarFunc();
+
+ for (var row = 0; row < this.rows; ++row)
+ for (var col = 0; col < this.cols; ++col)
+ ret.set(row, col, fun.applyFunction(ctx,
+ iargs.a.get(row, col),
+ iargs.b.get(row, col)));
+
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CompMatFuncBase}
+ * @param {function(new:glsBuiltinPrecisionTests.Func)} F
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.CompMatFunc = function(F, rows, cols) {
+ glsBuiltinPrecisionTests.CompMatFuncBase.call(this, rows, cols);
+ this.m_function = F;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.CompMatFunc, glsBuiltinPrecisionTests.CompMatFuncBase);
+
+ /**
+ * @return {glsBuiltinPrecisionTests.Func}
+ */
+ glsBuiltinPrecisionTests.CompMatFunc.prototype.doGetScalarFunc = function() {
+ return new this.m_function();
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Mul}
+ */
+ glsBuiltinPrecisionTests.ScalarMatrixCompMult = function() {
+ glsBuiltinPrecisionTests.Mul.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ScalarMatrixCompMult, glsBuiltinPrecisionTests.Mul);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.ScalarMatrixCompMult.prototype.getName = function() {
+ return 'matrixCompMult';
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.ScalarMatrixCompMult.prototype.doPrint = function(args) {
+ return glsBuiltinPrecisionTests.Func.prototype.doPrint.call(this, args);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CompMatFunc}
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.MatrixCompMult = function(rows, cols) {
+ glsBuiltinPrecisionTests.CompMatFunc.call(this, glsBuiltinPrecisionTests.ScalarMatrixCompMult, rows, cols);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.MatrixCompMult, glsBuiltinPrecisionTests.CompMatFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.OuterProduct = function(rows, cols) {
+ var name = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', rows, cols);
+ var sig = new glsBuiltinPrecisionTests.Signature(name, 'vec' + rows, 'vec' + cols);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ this.rows = rows;
+ this.cols = cols;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.OuterProduct, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.OuterProduct.prototype.getName = function() {
+ return 'outerProduct';
+ };
+
+ glsBuiltinPrecisionTests.OuterProduct.prototype.doApply = function(ctx, iargs) {
+ var ret = new tcuMatrix.Matrix(this.rows, this.cols);
+ var mul = new glsBuiltinPrecisionTests.Mul();
+
+ for (var row = 0; row < this.rows; ++row) {
+ for (var col = 0; col < this.cols; ++col)
+ ret.set(row, col, mul.applyFunction(ctx, iargs.a[row], iargs.b[col]));
+ }
+
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.Transpose = function(rows, cols) {
+ var nameRet = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', rows, cols);
+ var nameParam = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', cols, rows);
+ var sig = new glsBuiltinPrecisionTests.Signature(nameRet, nameParam);
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ this.rows = rows;
+ this.cols = cols;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Transpose, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.Transpose.prototype.getName = function() {
+ return 'transpose';
+ };
+
+ glsBuiltinPrecisionTests.Transpose.prototype.doApply = function(ctx, iargs) {
+ var ret = new tcuMatrix.Matrix(this.rows, this.cols);
+
+ for (var row = 0; row < this.rows; ++row)
+ for (var col = 0; col < this.cols; ++col)
+ ret.set(row, col, iargs.a.get(col, row));
+
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @param {*} In
+ */
+ glsBuiltinPrecisionTests.Inputs = function(In) {
+ // vector<typename In::In0> in0;
+ // vector<typename In::In1> in1;
+ // vector<typename In::In2> in2;
+ // vector<typename In::In3> in3;
+ this.in0 = [];
+ this.in1 = [];
+ this.in2 = [];
+ this.in3 = [];
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @param {*} Out
+ */
+ glsBuiltinPrecisionTests.Outputs = function(size, Out) {
+ // Outputs (size_t size) : out0(size), out1(size) {}
+ this.out0 = [];
+ this.out1 = [];
+ };
+
+ /**
+ * @constructor
+ * @param {*} In
+ * @param {*} Out
+ */
+ glsBuiltinPrecisionTests.Variables = function(In, Out) {
+ this.in0 = new glsBuiltinPrecisionTests.Variable(In.In0);
+ this.in1 = new glsBuiltinPrecisionTests.Variable(In.In1);
+ this.in2 = new glsBuiltinPrecisionTests.Variable(In.In2);
+ this.in3 = new glsBuiltinPrecisionTests.Variable(In.In3);
+ this.out0 = new glsBuiltinPrecisionTests.Variable(Out.Out0);
+ this.out1 = new glsBuiltinPrecisionTests.Variable(Out.Out1);
+ };
+
+ /**
+ * @constructor
+ * @param {function(new:glsBuiltinPrecisionTests.Func)} F
+ * @return {glsBuiltinPrecisionTests.GenFuncs}
+ */
+ glsBuiltinPrecisionTests.makeVectorizedFuncs = function(F) {
+ return new glsBuiltinPrecisionTests.GenFuncs(
+ new F(),
+ new glsBuiltinPrecisionTests.VectorizedFunc(new F(), 2),
+ new glsBuiltinPrecisionTests.VectorizedFunc(new F(), 3),
+ new glsBuiltinPrecisionTests.VectorizedFunc(new F(), 4));
+ };
+
+ /**
+ * @constructor
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.Sampling = function(typename) {
+ this.typename = typename;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ * @param {number=} size
+ * @return {glsBuiltinPrecisionTests.Sampling}
+ */
+ glsBuiltinPrecisionTests.SamplingFactory = function(typename, size) {
+ if (size > 1)
+ return new glsBuiltinPrecisionTests.DefaultSamplingVector(typename, size);
+ switch (typename) {
+ case 'vec4' : return new glsBuiltinPrecisionTests.DefaultSamplingVector('float', 4);
+ case 'vec3' : return new glsBuiltinPrecisionTests.DefaultSamplingVector('float', 3);
+ case 'vec2' : return new glsBuiltinPrecisionTests.DefaultSamplingVector('float', 2);
+ case 'boolean' : return new glsBuiltinPrecisionTests.DefaultSamplingBool(typename);
+ case 'float' : return new glsBuiltinPrecisionTests.DefaultSamplingFloat(typename);
+ case 'mat2': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 2, 2);
+ case 'mat2x3': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 3, 2);
+ case 'mat2x4': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 4, 2);
+ case 'mat3x2': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 2, 3);
+ case 'mat3': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 3, 3);
+ case 'mat3x4': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 4, 3);
+ case 'mat4x2': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 2, 4);
+ case 'mat4x3': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 3, 4);
+ case 'mat4': return new glsBuiltinPrecisionTests.DefaultSamplingMatrix('float', 4, 4);
+ case 'int' : return new glsBuiltinPrecisionTests.DefaultSamplingInt(typename);
+ }
+ return new glsBuiltinPrecisionTests.DefaultSamplingVoid(typename);
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {Array<*>} arr
+ */
+ glsBuiltinPrecisionTests.Sampling.prototype.genFixeds = function(fmt, arr) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {gluShaderUtil.precision} precision
+ * @param {deRandom.Random} random
+ * @return {*}
+ */
+ glsBuiltinPrecisionTests.Sampling.prototype.genRandom = function(fmt, precision, random) {
+ return 0;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.Sampling.prototype.getWeight = function() {
+ return 0;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingVoid = function(typename) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingVoid.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingVoid.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingVoid;
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {Array<number>} dst
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingVoid.prototype.genFixeds = function(fmt, dst) {
+ dst.push(NaN);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingBool = function(typename) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingBool.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingBool.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingBool;
+
+ /**
+ * @param {tcuFloatFormat.FloatFormat} fmt
+ * @param {Array<Boolean>} dst
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingBool.prototype.genFixeds = function(fmt, dst) {
+ dst.push(true);
+ dst.push(false);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingInt = function(typename) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingInt;
+
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype.genRandom = function(fmt, prec, rnd) {
+ /** @type {number} */ var exp = rnd.getInt(0, this.getNumBits(prec) - 2);
+ /** @type {number} */ var sign = rnd.getBool() ? -1 : 1;
+
+ return sign * rnd.getInt(0, 1 << exp);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype.genFixeds = function(fmt, dst) {
+ dst.push(0);
+ dst.push(-1);
+ dst.push(1);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype.getWeight = function() {
+ return 1.0;
+ };
+
+ /**
+ * @param {gluShaderUtil.precision} prec
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingInt.prototype.getNumBits = function(prec) {
+ switch (prec) {
+ case gluShaderUtil.precision.PRECISION_LOWP: return 8;
+ case gluShaderUtil.precision.PRECISION_MEDIUMP: return 16;
+ case gluShaderUtil.precision.PRECISION_HIGHP: return 32;
+ default:
+ throw new Error('Invalid precision: ' + prec);
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingFloat = function(typename) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingFloat.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingFloat.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingFloat;
+
+ glsBuiltinPrecisionTests.DefaultSamplingFloat.prototype.genRandom = function(format, prec, rnd) {
+ /** type{number} */ var minExp = format.getMinExp();
+ /** type{number} */ var maxExp = format.getMaxExp();
+ /** type{boolean} */ var haveSubnormal = format.hasSubnormal() != tcuFloatFormat.YesNoMaybe.NO;
+
+ // Choose exponent so that the cumulative distribution is cubic.
+ // This makes the probability distribution quadratic, with the peak centered on zero.
+ /** type{number} */ var minRoot = deMath.deCbrt(minExp - 0.5 - (haveSubnormal ? 1.0 : 0.0));
+ /** type{number} */ var maxRoot = deMath.deCbrt(maxExp + 0.5);
+ /** type{number} */ var fractionBits = format.getFractionBits();
+ /** type{number} */ var exp = deMath.rint(Math.pow(rnd.getFloat(minRoot, maxRoot),
+ 3.0));
+ /** type{number} */ var base = 0.0; // integral power of two
+ /** type{number} */ var quantum = 0.0; // smallest representable difference in the binade
+ /** type{number} */ var significand = 0.0; // Significand.
+
+ // DE_ASSERT(fractionBits < std::numeric_limits<float>::digits);
+
+ // Generate some occasional special numbers
+ switch (rnd.getInt(0, 64)) {
+ case 0: return 0;
+ case 1: return Number.POSITIVE_INFINITY;
+ case 2: return Number.NEGATIVE_INFINITY;
+ case 3: return NaN;
+ default: break;
+ }
+
+ if (exp >= minExp) {
+ // Normal number
+ base = deMath.deFloatLdExp(1.0, exp);
+ quantum = deMath.deFloatLdExp(1.0, exp - fractionBits);
+ } else {
+ // Subnormal
+ base = 0.0;
+ quantum = deMath.deFloatLdExp(1.0, minExp - fractionBits);
+ }
+
+ switch (rnd.getInt(0, 16)) {
+ // The highest number in this binade, significand is all bits one.
+ case 0:
+ significand = base - quantum;
+ break;
+ // Significand is one.
+ case 1:
+ significand = quantum;
+ break;
+ // Significand is zero.
+ case 2:
+ significand = 0.0;
+ break;
+ // Random (evenly distributed) significand.
+ default: {
+ /** type{number} */ var intFraction = rnd.getInt() & ((1 << fractionBits) - 1);
+ significand = intFraction * quantum;
+ }
+ }
+
+ // Produce positive numbers more often than negative.
+ return (rnd.getInt(0, 3) == 0 ? -1.0 : 1.0) * (base + significand);
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingFloat.prototype.genFixeds = function(format, dst) {
+ /** @type {number} */ var minExp = format.getMinExp();
+ /** @type {number} */ var maxExp = format.getMaxExp();
+ /** @type {number} */ var fractionBits = format.getFractionBits();
+ /** @type {number} */ var minQuantum = deMath.deFloatLdExp(1.0, minExp - fractionBits);
+ /** @type {number} */ var minNormalized = deMath.deFloatLdExp(1.0, minExp);
+ /** @type {number} */ var maxQuantum = deMath.deFloatLdExp(1.0, maxExp - fractionBits);
+
+ // If unit testing is enabled, include exact numbers
+ if (enableUnittests) {
+ dst.push(0.2);
+ dst.push(0.5);
+ }
+
+ // NaN
+ dst.push(NaN);
+ // Zero
+ dst.push(0.0);
+
+ for (var sign = -1; sign <= 1; sign += 2) {
+ // Smallest subnormal
+ dst.push(sign * minQuantum);
+
+ // Largest subnormal
+ dst.push(sign * (minNormalized - minQuantum));
+
+ // Smallest normalized
+ dst.push(sign * minNormalized);
+
+ // Next smallest normalized
+ dst.push(sign * (minNormalized + minQuantum));
+
+ dst.push(sign * 0.5);
+ dst.push(sign * 1.0);
+ dst.push(sign * 2.0);
+
+ // Largest number
+ dst.push(sign * (deMath.deFloatLdExp(1.0, maxExp) +
+ (deMath.deFloatLdExp(1.0, maxExp) - maxQuantum)));
+
+ dst.push(sign * Number.POSITIVE_INFINITY);
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ * @param {number} size
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingVector = function(typename, size) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ this.size = size;
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingVector.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingVector.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingVector;
+
+ glsBuiltinPrecisionTests.DefaultSamplingVector.prototype.genRandom = function(fmt, prec, rnd) {
+ /** @type {Array<*>} */ var ret = [];
+
+ for (var ndx = 0; ndx < this.size; ++ndx)
+ ret[ndx] = glsBuiltinPrecisionTests.SamplingFactory(this.typename).genRandom(fmt, prec, rnd);
+
+ return ret;
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingVector.prototype.genFixeds = function(fmt, dst) {
+ /** @type {Array<*>} */ var scalars = [];
+
+ glsBuiltinPrecisionTests.SamplingFactory(this.typename).genFixeds(fmt, scalars);
+
+ for (var scalarNdx = 0; scalarNdx < scalars.length; ++scalarNdx) {
+ var value = [];
+ for (var i = 0; i < this.size; i++)
+ value[i] = scalars[scalarNdx];
+ dst.push(value);
+ }
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingVector.prototype.getWeight = function() {
+ return Math.pow(glsBuiltinPrecisionTests.SamplingFactory(this.typename).getWeight(), this.size);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Sampling}
+ * @param {glsBuiltinPrecisionTests.Typename} typename
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix = function(typename, rows, cols) {
+ glsBuiltinPrecisionTests.Sampling.call(this, typename);
+ this.rows = rows;
+ this.cols = cols;
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix.prototype = Object.create(glsBuiltinPrecisionTests.Sampling.prototype);
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix.prototype.constructor = glsBuiltinPrecisionTests.DefaultSamplingMatrix;
+
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix.prototype.genRandom = function(fmt, prec, rnd) {
+ /** @type {tcuMatrix.Matrix} */ var ret = new tcuMatrix.Matrix(this.rows, this.cols);
+ var sampler = glsBuiltinPrecisionTests.SamplingFactory(this.typename);
+
+ for (var rowNdx = 0; rowNdx < this.rows; ++rowNdx)
+ for (var colNdx = 0; colNdx < this.cols; ++colNdx)
+ ret.set(rowNdx, colNdx, sampler.genRandom(fmt, prec, rnd));
+
+ return ret;
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix.prototype.genFixeds = function(fmt, dst) {
+ /** @type {Array<number>} */ var scalars = [];
+
+ glsBuiltinPrecisionTests.SamplingFactory(this.typename).genFixeds(fmt, scalars);
+
+ for (var scalarNdx = 0; scalarNdx < scalars.length; ++scalarNdx)
+ dst.push(new tcuMatrix.Matrix(this.rows, this.cols, scalars[scalarNdx]));
+
+ if (this.cols == this.rows) {
+ var mat = new tcuMatrix.Matrix(this.rows, this.cols, 0);
+ var x = 1;
+ mat.set(0, 0, x);
+ for (var ndx = 0; ndx < this.cols; ++ndx) {
+ mat.set(this.cols - 1 - ndx, ndx, x);
+ x *= 2;
+ }
+ dst.push(mat);
+ }
+ };
+
+ glsBuiltinPrecisionTests.DefaultSamplingMatrix.prototype.getWeight = function() {
+ return Math.pow(glsBuiltinPrecisionTests.SamplingFactory(this.typename).getWeight(), this.rows * this.cols);
+ };
+
+ /**
+ * @constructor
+ * @param {number=} size
+ * @param {glsBuiltinPrecisionTests.InTypes} In
+ */
+ glsBuiltinPrecisionTests.Samplings = function(In, size) {
+ this.in0 = glsBuiltinPrecisionTests.SamplingFactory(In.In0, size);
+ this.in1 = glsBuiltinPrecisionTests.SamplingFactory(In.In1, size);
+ this.in2 = glsBuiltinPrecisionTests.SamplingFactory(In.In2, size);
+ this.in3 = glsBuiltinPrecisionTests.SamplingFactory(In.In3, size);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.InTypes} In
+ * @param {number=} size
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Samplings}
+ */
+ glsBuiltinPrecisionTests.DefaultSamplings = function(In, size) {
+ glsBuiltinPrecisionTests.Samplings.call(this, In, size);
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsBuiltinPrecisionTests.Context} context
+ * @param {string} name
+ * @param {string} extension
+ */
+ glsBuiltinPrecisionTests.PrecisionCase = function(context, name, extension) {
+ /** @type {string} */ this.m_extension = extension === undefined ? '' : extension;
+ /** @type {glsBuiltinPrecisionTests.Context} */ this.m_ctx = context;
+ /** @type {*} */ this.m_status;
+ /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(1234); // (0xdeadbeefu + context.testContext.getCommandLine().getBaseSeed())
+ tcuTestCase.DeqpTest.call(this, name, extension);
+ };
+
+ glsBuiltinPrecisionTests.PrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsBuiltinPrecisionTests.PrecisionCase.prototype.constructor = glsBuiltinPrecisionTests.PrecisionCase;
+
+ /**
+ * @return {tcuFloatFormat.FloatFormat}
+ */
+ glsBuiltinPrecisionTests.PrecisionCase.prototype.getFormat = function() {
+ return this.m_ctx.floatFormat;
+ };
+
+ /**
+ * Return an output value extracted from flat array
+ * @param {goog.NumberArray} output
+ * @param {number} index Index of the element to extract
+ * @param {*} reference Reference for type informaion
+ * @return {glsBuiltinPrecisionTests.Value}
+ */
+ glsBuiltinPrecisionTests.getOutput = function(output, index, reference) {
+ if (reference instanceof Array) {
+ var ret = [];
+ var size = reference.length;
+ for (var i = 0; i < size; i++)
+ ret[i] = output[size * index + i];
+ return ret;
+ }
+ if (reference instanceof tcuMatrix.Matrix) {
+ var ret = new tcuMatrix.Matrix(reference.rows, reference.cols);
+ var size = reference.rows * reference.cols;
+ for (var i = 0; i < reference.rows; i++)
+ for (var j = 0; j < reference.cols; j++)
+ ret.set(i, j, output[size * index + j * reference.rows + i]);
+ return ret;
+ }
+
+ return output[index];
+ };
+ /**
+ * @param {glsBuiltinPrecisionTests.Variables} variables Variables<In, Out>
+ * @param {glsBuiltinPrecisionTests.Inputs} inputs Inputs<In>
+ * @param {glsBuiltinPrecisionTests.Statement} stmt
+ */
+ glsBuiltinPrecisionTests.PrecisionCase.prototype.testStatement = function(variables, inputs, stmt) {
+ /** @type {tcuFloatFormat.FloatFormat} */ var fmt = this.getFormat();
+ /** @type {number} */ var inCount = glsBuiltinPrecisionTests.numInputs(this.In);
+ /** @type {number} */ var outCount = glsBuiltinPrecisionTests.numOutputs(this.Out);
+ /** @type {number} */ var numValues = (inCount > 0) ? inputs.in0.length : 1;
+ /** @type {tcuFloatFormat.FloatFormat} */ var highpFmt = this.m_ctx.highpFormat;
+ var outputs = [];
+ /** @type {number} */ var maxMsgs = 100;
+ /** @type {number} */ var numErrors = 0;
+ /** @type {glsShaderExecUtil.ShaderSpec} */ var spec = new glsShaderExecUtil.ShaderSpec();
+ /** @type {glsBuiltinPrecisionTests.Environment} */ var env = new glsBuiltinPrecisionTests.Environment(); // Hoisted out of the inner loop for optimization.
+
+ switch (inCount) {
+ case 4: DE_ASSERT(inputs.in3.length == numValues);
+ case 3: DE_ASSERT(inputs.in2.length == numValues);
+ case 2: DE_ASSERT(inputs.in1.length == numValues);
+ case 1: DE_ASSERT(inputs.in0.length == numValues);
+ default: break;
+ }
+ if (enableUnittests)
+ numValues = 2;
+
+ // TODO: Fix logging
+ //Print out the statement and its definitions
+ // bufferedLogToConsole("Statement: " + stmt);
+ // var funcInfo = ''
+ // var funcs = {};
+ // stmt.getUsedFuncs(funcs);
+ // for (var key in funcs) {
+ // var func = funcs[key];
+ // funcInfo += func.printDefinition();
+ // };
+ // if (funcInfo.length > 0)
+ // bufferedLogToConsole('Reference definitions:' + funcInfo);
+
+ // Initialize ShaderSpec from precision, variables and statement.
+
+ spec.globalDeclarations = 'precision ' + gluShaderUtil.getPrecisionName(this.m_ctx.precision) + ' float;\n';
+
+ if (this.m_extension.length > 0)
+ spec.globalDeclarations += '#extension ' + this.m_extension + ' : require\n';
+
+ spec.inputs = [];
+
+ switch (inCount) {
+ case 4: spec.inputs[3] = this.makeSymbol(variables.in3);
+ case 3: spec.inputs[2] = this.makeSymbol(variables.in2);
+ case 2: spec.inputs[1] = this.makeSymbol(variables.in1);
+ case 1: spec.inputs[0] = this.makeSymbol(variables.in0);
+ default: break;
+ }
+
+ spec.outputs = [];
+
+ switch (outCount) {
+ case 2: spec.outputs[1] = this.makeSymbol(variables.out1);
+ case 1: spec.outputs[0] = this.makeSymbol(variables.out0);
+ default: break;
+ }
+
+ spec.source = stmt;
+
+ if (enableUnittests == false) {
+ // Run the shader with inputs.
+ /** @type {glsShaderExecUtil.ShaderExecutor} */
+ var executor = glsShaderExecUtil.createExecutor(this.m_ctx.shaderType, spec);
+ /** @type {Array<*>} */ var inputArr =
+ [
+ tcuMatrixUtil.flatten(inputs.in0), tcuMatrixUtil.flatten(inputs.in1), tcuMatrixUtil.flatten(inputs.in2), tcuMatrixUtil.flatten(inputs.in3)
+ ];
+
+ // executor.log(log());
+ if (!executor.isOk())
+ testFailed('Shader compilation failed');
+
+ executor.useProgram();
+ var outputArray = executor.execute(numValues, inputArr);
+
+ switch (outCount) {
+ case 2:
+ outputs[1] = glsBuiltinPrecisionTests.cast(this.Out.Out1, outputArray[1]);
+ case 1:
+ outputs[0] = glsBuiltinPrecisionTests.cast(this.Out.Out0, outputArray[0]);
+ default: break;
+ }
+ }
+
+ // Initialize environment with dummy values so we don't need to bind in inner loop.
+
+ var in0 = new tcuInterval.Interval();
+ var in1 = new tcuInterval.Interval();
+ var in2 = new tcuInterval.Interval();
+ var in3 = new tcuInterval.Interval();
+ var reference0 = new tcuInterval.Interval();
+ var reference1 = new tcuInterval.Interval();
+
+ env.bind(variables.in0, in0);
+ env.bind(variables.in1, in1);
+ env.bind(variables.in2, in2);
+ env.bind(variables.in3, in3);
+ env.bind(variables.out0, reference0);
+ env.bind(variables.out1, reference1);
+
+ // For each input tuple, compute output reference interval and compare
+ // shader output to the reference.
+ for (var valueNdx = 0; valueNdx < numValues; valueNdx++) {
+ /** @type {boolean} */ var result = true;
+ var value0, value1;
+ var msg = '';
+
+ var in0_ = glsBuiltinPrecisionTests.convert(this.Arg0, fmt, glsBuiltinPrecisionTests.round(this.Arg0, fmt, inputs.in0[valueNdx]));
+ var in1_ = glsBuiltinPrecisionTests.convert(this.Arg1, fmt, glsBuiltinPrecisionTests.round(this.Arg1, fmt, inputs.in1[valueNdx]));
+ var in2_ = glsBuiltinPrecisionTests.convert(this.Arg2, fmt, glsBuiltinPrecisionTests.round(this.Arg2, fmt, inputs.in2[valueNdx]));
+ var in3_ = glsBuiltinPrecisionTests.convert(this.Arg3, fmt, glsBuiltinPrecisionTests.round(this.Arg3, fmt, inputs.in3[valueNdx]));
+
+ env.bind(variables.in0, in0_);
+ env.bind(variables.in1, in1_);
+ env.bind(variables.in2, in2_);
+ env.bind(variables.in3, in3_);
+
+ stmt.execute(new glsBuiltinPrecisionTests.EvalContext(fmt, this.m_ctx.precision, env));
+
+ switch (outCount) {
+ case 2:
+ reference1 = glsBuiltinPrecisionTests.convert(this.Out.Out1, highpFmt, env.lookup(variables.out1));
+ if (enableUnittests)
+ result = referenceComparison(reference1, valueNdx + outCount - 1, this.m_ctx.floatFormat);
+ else {
+ value1 = glsBuiltinPrecisionTests.getOutput(outputs[1], valueNdx, reference1);
+ if (!glsBuiltinPrecisionTests.contains(this.Out.Out1, reference1, value1)) {
+ msg = 'Shader output 1 (' + value1 + ') is outside acceptable range: ' + reference1;
+ result = false;
+ }
+ }
+ case 1:
+ reference0 = glsBuiltinPrecisionTests.convert(this.Out.Out0, highpFmt, env.lookup(variables.out0));
+ if (enableUnittests)
+ result = referenceComparison(reference0, valueNdx + outCount - 1, this.m_ctx.floatFormat);
+ else {
+ value0 = glsBuiltinPrecisionTests.getOutput(outputs[0], valueNdx, reference0);
+ if (!glsBuiltinPrecisionTests.contains(this.Out.Out0, reference0, value0)) {
+ msg = 'Shader output 0 (' + value0 + ') is outside acceptable range: ' + reference0;
+ result = false;
+ }
+ }
+ default: break;
+ }
+
+ if (!result)
+ ++numErrors;
+
+ if (!result && numErrors <= maxMsgs) {
+ /** @type {string} */ var builder = '';
+
+ builder += (result ? 'Passed' : 'Failed') + '\n' + msg + '\n sample:\n' + valueNdx;
+
+ if (inCount > 0) {
+ builder += '\t' + variables.in0.getName() + ' = ' +
+ inputs.in0[valueNdx] + '\n';
+ }
+
+ if (inCount > 1) {
+ builder += '\t' + variables.in1.getName() + ' = ' +
+ inputs.in1[valueNdx] + '\n';
+ }
+
+ if (inCount > 2) {
+ builder += '\t' + variables.in2.getName() + ' = ' +
+ inputs.in2[valueNdx] + '\n';
+ }
+
+ if (inCount > 3) {
+ builder += '\t' + variables.in3.getName() + ' = ' +
+ inputs.in3[valueNdx] + '\n';
+ }
+
+ if (enableUnittests == false) {
+ if (outCount > 0) {
+ builder += '\t' + variables.out0.getName() + ' = ' +
+ value0 + '\n' +
+ '\tExpected range: ' +
+ reference0 + '\n';
+ }
+
+ if (outCount > 1) {
+ builder += '\t' + variables.out1.getName() + ' = ' +
+ value1 + '\n' +
+ '\tExpected range: ' +
+ reference1 + '\n';
+ }
+ }
+ bufferedLogToConsole(builder);
+ }
+ }
+
+ if (numErrors > maxMsgs) {
+ bufferedLogToConsole('(Skipped ' + (numErrors - maxMsgs) + ' messages.)');
+ }
+
+ if (numErrors == 0) {
+ testPassed('All ' + numValues + ' inputs passed.');
+ } else {
+ testFailed('' + numErrors + '/' + numValues + ' inputs failed.');
+ }
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Variable} variable Variable<typename>
+ * @return {glsShaderExecUtil.Symbol}
+ */
+ glsBuiltinPrecisionTests.PrecisionCase.prototype.makeSymbol = function(variable) {
+ var v = variable;
+ return new glsShaderExecUtil.Symbol(v.getName(), gluVarType.getVarTypeOf(v.typename, this.m_size, this.m_ctx.precision));
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Tuple4}
+ * @param {*} in0
+ * @param {*} in1
+ * @param {*} in2
+ * @param {*} in3
+ */
+ glsBuiltinPrecisionTests.InTuple = function(in0, in1, in2, in3) {
+ glsBuiltinPrecisionTests.Tuple4.call(this, in0, in1, in2, in3);
+ };
+
+ glsBuiltinPrecisionTests.InTuple.prototype = Object.create(glsBuiltinPrecisionTests.Tuple4.prototype);
+ glsBuiltinPrecisionTests.InTuple.prototype.constructor = glsBuiltinPrecisionTests.InTuple;
+
+ /**
+ * @param {*} In
+ * @param {glsBuiltinPrecisionTests.Samplings} samplings Samplings<In>
+ * @param {tcuFloatFormat.FloatFormat} floatFormat
+ * @param {gluShaderUtil.precision} intPrecision
+ * @param {number} numSamples
+ * @param {deRandom.Random} rnd
+ * @return {glsBuiltinPrecisionTests.Inputs}
+ */
+ glsBuiltinPrecisionTests.generateInputs = function(In, samplings, floatFormat, intPrecision, numSamples, rnd) {
+ /*Inputs<In>*/ var ret = new glsBuiltinPrecisionTests.Inputs(In);
+ /*Inputs<In>*/ var fixedInputs = new glsBuiltinPrecisionTests.Inputs(In);
+ // set<InTuple<In>, InputLess<InTuple<In> > > seenInputs;
+ /** @type {Array<glsBuiltinPrecisionTests.InTuple,glsBuiltinPrecisionTests.InputLess>} */
+ var seenInputs = [];
+
+ samplings.in0.genFixeds(floatFormat, fixedInputs.in0);
+ samplings.in1.genFixeds(floatFormat, fixedInputs.in1);
+ samplings.in2.genFixeds(floatFormat, fixedInputs.in2);
+ samplings.in3.genFixeds(floatFormat, fixedInputs.in3);
+
+ for (var ndx0 = 0; ndx0 < fixedInputs.in0.length; ++ndx0) {
+ for (var ndx1 = 0; ndx1 < fixedInputs.in1.length; ++ndx1) {
+ for (var ndx2 = 0; ndx2 < fixedInputs.in2.length; ++ndx2) {
+ for (var ndx3 = 0; ndx3 < fixedInputs.in3.length; ++ndx3) {
+ var tuple = new glsBuiltinPrecisionTests.InTuple(fixedInputs.in0[ndx0],
+ fixedInputs.in1[ndx1],
+ fixedInputs.in2[ndx2],
+ fixedInputs.in3[ndx3]);
+
+ seenInputs.push(tuple);
+ ret.in0.push(tuple.a);
+ ret.in1.push(tuple.b);
+ ret.in2.push(tuple.c);
+ ret.in3.push(tuple.d);
+ }
+ }
+ }
+ }
+
+ for (var ndx = 0; ndx < numSamples; ++ndx) {
+ var in0 = samplings.in0.genRandom(floatFormat, intPrecision, rnd);
+ var in1 = samplings.in1.genRandom(floatFormat, intPrecision, rnd);
+ var in2 = samplings.in2.genRandom(floatFormat, intPrecision, rnd);
+ var in3 = samplings.in3.genRandom(floatFormat, intPrecision, rnd);
+ var tuple = new glsBuiltinPrecisionTests.InTuple(in0, in1, in2, in3);
+
+ // if (de::contains(seenInputs, tuple))
+ // continue;
+
+ seenInputs.push(tuple);
+ ret.in0.push(in0);
+ ret.in1.push(in1);
+ ret.in2.push(in2);
+ ret.in3.push(in3);
+ }
+
+ return ret;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrecisionCase}
+ * @param {string} name
+ * @param {glsBuiltinPrecisionTests.FuncBase} func
+ */
+ glsBuiltinPrecisionTests.FuncCaseBase = function(context, name, func) {
+ glsBuiltinPrecisionTests.PrecisionCase.call(this, context, name, func.getRequiredExtension());
+ };
+
+ glsBuiltinPrecisionTests.FuncCaseBase.prototype = Object.create(glsBuiltinPrecisionTests.PrecisionCase.prototype);
+ glsBuiltinPrecisionTests.FuncCaseBase.prototype.constructor = glsBuiltinPrecisionTests.FuncCaseBase;
+
+ glsBuiltinPrecisionTests.FuncCaseBase.prototype.iterate = function() {
+
+ assertMsgOptions(!(this.m_extension !== undefined && this.m_extension.trim() !== '') &&
+ !sglrGLContext.isExtensionSupported(gl, this.m_extension),
+ 'Unsupported extension: ' + this.m_extension, false, true);
+
+ this.runTest();
+
+ // m_status.setTestContextResult(m_testCtx);
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncCaseBase}
+ * @param {glsBuiltinPrecisionTests.Context} context
+ * @param {string} name
+ * @param {glsBuiltinPrecisionTests.Func} func
+ */
+ glsBuiltinPrecisionTests.InOutFuncCase = function(context, name, func) {
+ glsBuiltinPrecisionTests.FuncCaseBase.call(this, context, name, func);
+ this.Sig = func.Sig;
+ this.m_func = func;
+ this.Ret = func.Sig.Ret;
+ this.Arg0 = func.Sig.Arg0;
+ this.Arg1 = func.Sig.Arg1;
+ this.Arg2 = func.Sig.Arg2;
+ this.Arg3 = func.Sig.Arg3;
+ this.In = new glsBuiltinPrecisionTests.InTypes(this.Arg0, this.Arg2, this.Arg3);
+ this.Out = new glsBuiltinPrecisionTests.OutTypes(this.Ret, this.Arg1);
+ this.m_size = this.m_func.m_size;
+ };
+
+ glsBuiltinPrecisionTests.InOutFuncCase.prototype = Object.create(glsBuiltinPrecisionTests.FuncCaseBase.prototype);
+ glsBuiltinPrecisionTests.InOutFuncCase.prototype.constructor = glsBuiltinPrecisionTests.InOutFuncCase;
+
+ /**
+ * Samplings<In>
+ * @return {glsBuiltinPrecisionTests.Samplings}
+ */
+ glsBuiltinPrecisionTests.InOutFuncCase.prototype.getSamplings = function() {
+ return new glsBuiltinPrecisionTests.DefaultSamplings(this.In, this.m_size);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Signature} Sig_
+ */
+ glsBuiltinPrecisionTests.InOutFuncCase.prototype.runTest = function(Sig_) {
+ /** @type {glsBuiltinPrecisionTests.Inputs} */ var inputs = (glsBuiltinPrecisionTests.generateInputs(
+ this.In,
+ this.getSamplings(),
+ this.m_ctx.floatFormat,
+ this.m_ctx.precision,
+ this.m_ctx.numRandoms,
+ this.m_rnd));
+
+ var variables = new glsBuiltinPrecisionTests.Variables(this.In, this.Out);
+ // Variables<In, Out> variables;
+ //
+ variables.out0 = new glsBuiltinPrecisionTests.Variable(this.Out.Out0, 'out0');
+ variables.out1 = new glsBuiltinPrecisionTests.Variable(this.Arg1, 'out1');
+ variables.in0 = new glsBuiltinPrecisionTests.Variable(this.Arg0, 'in0');
+ variables.in1 = new glsBuiltinPrecisionTests.Variable(this.Arg2, 'in1');
+ variables.in2 = new glsBuiltinPrecisionTests.Variable(this.Arg3, 'in2');
+ variables.in3 = new glsBuiltinPrecisionTests.Variable('void', 'in3');
+
+ var expr = glsBuiltinPrecisionTests.applyVar(this.m_func,
+ variables.in0, variables.out1,
+ variables.in1, variables.in2);
+ var stmt = glsBuiltinPrecisionTests.variableAssignment(variables.out0, expr);
+
+ this.testStatement(variables, inputs, stmt);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncCaseBase}
+ * @param {glsBuiltinPrecisionTests.Context} context
+ * @param {string} name
+ * @param {glsBuiltinPrecisionTests.Func} func
+ */
+ glsBuiltinPrecisionTests.FuncCase = function(context, name, func) {
+ glsBuiltinPrecisionTests.FuncCaseBase.call(this, context, name, func);
+ this.Sig = func.Sig;
+ this.m_func = func;
+ this.Ret = func.Sig.Ret;
+ this.Arg0 = func.Sig.Arg0;
+ this.Arg1 = func.Sig.Arg1;
+ this.Arg2 = func.Sig.Arg2;
+ this.Arg3 = func.Sig.Arg3;
+ this.In = new glsBuiltinPrecisionTests.InTypes(this.Arg0, this.Arg1, this.Arg2, this.Arg3);
+ this.Out = new glsBuiltinPrecisionTests.OutTypes(this.Ret);
+ this.m_size = this.m_func.m_size;
+ };
+
+ glsBuiltinPrecisionTests.FuncCase.prototype = Object.create(glsBuiltinPrecisionTests.FuncCaseBase.prototype);
+ glsBuiltinPrecisionTests.FuncCase.prototype.constructor = glsBuiltinPrecisionTests.FuncCase;
+
+ /**
+ * Samplings<In>
+ * @return {glsBuiltinPrecisionTests.Samplings}
+ */
+ glsBuiltinPrecisionTests.FuncCase.prototype.getSamplings = function() {
+ return new glsBuiltinPrecisionTests.DefaultSamplings(this.In, this.m_size);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Signature} Sig_
+ */
+ glsBuiltinPrecisionTests.FuncCase.prototype.runTest = function(Sig_) {
+ /** @type {glsBuiltinPrecisionTests.Inputs} */ var inputs = (glsBuiltinPrecisionTests.generateInputs(
+ this.In,
+ this.getSamplings(),
+ this.m_ctx.floatFormat,
+ this.m_ctx.precision,
+ this.m_ctx.numRandoms,
+ this.m_rnd));
+
+ var variables = new glsBuiltinPrecisionTests.Variables(this.In, this.Out);
+ // Variables<In, Out> variables;
+ //
+ variables.out0 = new glsBuiltinPrecisionTests.Variable(this.Ret, 'out0');
+ variables.out1 = new glsBuiltinPrecisionTests.Variable('void', 'out1');
+ variables.in0 = new glsBuiltinPrecisionTests.Variable(this.Arg0, 'in0');
+ variables.in1 = new glsBuiltinPrecisionTests.Variable(this.Arg1, 'in1');
+ variables.in2 = new glsBuiltinPrecisionTests.Variable(this.Arg2, 'in2');
+ variables.in3 = new glsBuiltinPrecisionTests.Variable(this.Arg3, 'in3');
+
+ var expr = glsBuiltinPrecisionTests.applyVar(this.m_func,
+ variables.in0, variables.in1,
+ variables.in2, variables.in3);
+ var stmt = glsBuiltinPrecisionTests.variableAssignment(variables.out0, expr);
+
+ this.testStatement(variables, inputs, stmt);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @param {glsBuiltinPrecisionTests.Variable} arg0
+ * @param {glsBuiltinPrecisionTests.Variable} arg1
+ * @param {glsBuiltinPrecisionTests.Variable} arg2
+ * @param {glsBuiltinPrecisionTests.Variable} arg3
+ * @return {glsBuiltinPrecisionTests.ApplyVar}
+ */
+ glsBuiltinPrecisionTests.applyVar = function(func, arg0, arg1, arg2, arg3) {
+ return new glsBuiltinPrecisionTests.ApplyVar(func.Sig, func, arg0, arg1, arg2, arg3);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Variable} variable
+ * @param {glsBuiltinPrecisionTests.ApplyVar} value
+ * @param {boolean} isDeclaration
+ */
+ glsBuiltinPrecisionTests.variableStatement = function(variable, value, isDeclaration) {
+ return new glsBuiltinPrecisionTests.VariableStatement(variable, value, isDeclaration);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Variable} variable
+ * @param {glsBuiltinPrecisionTests.ApplyVar} value
+ */
+ glsBuiltinPrecisionTests.variableAssignment = function(variable, value) {
+ return glsBuiltinPrecisionTests.variableStatement(variable, value, false);
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.CaseFactories = function() {};
+
+ /**
+ * @return {Array<glsBuiltinPrecisionTests.CaseFactory>}
+ */
+ glsBuiltinPrecisionTests.CaseFactories.prototype.getFactories = function() {};
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CaseFactories}
+ */
+ glsBuiltinPrecisionTests.BuiltinFuncs = function() {
+ /** @type {Array<glsBuiltinPrecisionTests.CaseFactory>} */ this.m_factories = [];
+ };
+
+ glsBuiltinPrecisionTests.BuiltinFuncs.prototype = Object.create(glsBuiltinPrecisionTests.CaseFactories.prototype);
+ glsBuiltinPrecisionTests.BuiltinFuncs.prototype.constructor = glsBuiltinPrecisionTests.BuiltinFuncs;
+
+ /**
+ * @return {Array<glsBuiltinPrecisionTests.CaseFactory>}
+ */
+ glsBuiltinPrecisionTests.BuiltinFuncs.prototype.getFactories = function() {
+ return this.m_factories.slice();
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.CaseFactory} fact
+ */
+ glsBuiltinPrecisionTests.BuiltinFuncs.prototype.addFactory = function(fact) {
+ this.m_factories.push(fact);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} context
+ * @param {string} name
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @return {glsBuiltinPrecisionTests.PrecisionCase}
+ */
+ glsBuiltinPrecisionTests.createFuncCase = function(context, name, func) {
+ switch (func.getOutParamIndex()) {
+ case -1:
+ return new glsBuiltinPrecisionTests.FuncCase(context, name, func);
+ case 1:
+ return new glsBuiltinPrecisionTests.InOutFuncCase(context, name, func);
+ default:
+ throw new Error(!'Impossible');
+ }
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.CaseFactory = function() {};
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CaseFactory.prototype.getName = function() {
+ return '';
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.CaseFactory.prototype.getDesc = function() {
+ return '';
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ */
+ glsBuiltinPrecisionTests.CaseFactory.prototype.createCase = function(ctx) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CaseFactory}
+ * @param {glsBuiltinPrecisionTests.Func} func
+ */
+ glsBuiltinPrecisionTests.SimpleFuncCaseFactory = function(func) {
+ glsBuiltinPrecisionTests.CaseFactory.call(this);
+ this.m_func = func;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.SimpleFuncCaseFactory, glsBuiltinPrecisionTests.CaseFactory);
+
+ glsBuiltinPrecisionTests.SimpleFuncCaseFactory.prototype.getName = function() {
+ return this.m_func.getName().toLowerCase();
+ };
+
+ glsBuiltinPrecisionTests.SimpleFuncCaseFactory.prototype.getDesc = function() {
+ return "Function '" + this.getName() + "'";
+ };
+
+ glsBuiltinPrecisionTests.SimpleFuncCaseFactory.prototype.createCase = function(ctx) {
+ return glsBuiltinPrecisionTests.createFuncCase(ctx, ctx.name, this.m_func);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CaseFactory}
+ */
+ glsBuiltinPrecisionTests.FuncCaseFactory = function() {
+ glsBuiltinPrecisionTests.CaseFactory.call(this);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.FuncCaseFactory, glsBuiltinPrecisionTests.CaseFactory);
+
+ glsBuiltinPrecisionTests.FuncCaseFactory.prototype.getFunc = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ glsBuiltinPrecisionTests.FuncCaseFactory.prototype.getName = function() {
+ return this.getFunc().getName().toLowerCase();
+ };
+
+ glsBuiltinPrecisionTests.FuncCaseFactory.prototype.getDesc = function() {
+ return "Function '" + this.getFunc().getName() + "'";
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncCaseFactory}
+ */
+ glsBuiltinPrecisionTests.TemplateFuncCaseFactory = function(genF) {
+ glsBuiltinPrecisionTests.FuncCaseFactory.call(this);
+ this.m_genF = genF;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.TemplateFuncCaseFactory, glsBuiltinPrecisionTests.FuncCaseFactory);
+
+ glsBuiltinPrecisionTests.TemplateFuncCaseFactory.prototype.getFunc = function() {
+ return new this.m_genF(1);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ */
+ glsBuiltinPrecisionTests.TemplateFuncCaseFactory.prototype.createCase = function(ctx) {
+ var group = tcuTestCase.newTest(ctx.name, ctx.name);
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'scalar', new this.m_genF(1)));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec2', new this.m_genF(2)));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec3', new this.m_genF(3)));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec4', new this.m_genF(4)));
+
+ return group;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncCaseFactory}
+ */
+ glsBuiltinPrecisionTests.MatrixFuncCaseFactory = function(genF) {
+ glsBuiltinPrecisionTests.FuncCaseFactory.call(this);
+ this.m_genF = genF;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.MatrixFuncCaseFactory, glsBuiltinPrecisionTests.FuncCaseFactory);
+
+ glsBuiltinPrecisionTests.MatrixFuncCaseFactory.prototype.getFunc = function() {
+ return new this.m_genF(2, 2);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ */
+ glsBuiltinPrecisionTests.MatrixFuncCaseFactory.prototype.createCase = function(ctx) {
+ var group = tcuTestCase.newTest(ctx.name, ctx.name);
+ this.addCase(ctx, group, 2, 2);
+ this.addCase(ctx, group, 3, 2);
+ this.addCase(ctx, group, 4, 2);
+ this.addCase(ctx, group, 2, 3);
+ this.addCase(ctx, group, 3, 3);
+ this.addCase(ctx, group, 4, 3);
+ this.addCase(ctx, group, 2, 4);
+ this.addCase(ctx, group, 3, 4);
+ this.addCase(ctx, group, 4, 4);
+
+ return group;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ * @param {tcuTestCase.DeqpTest} group
+ * @param {number} rows
+ * @param {number} cols
+ */
+ glsBuiltinPrecisionTests.MatrixFuncCaseFactory.prototype.addCase = function(ctx, group, rows, cols) {
+ var name = glsBuiltinPrecisionTests.dataTypeNameOfMatrix('float', rows, cols);
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, name, new this.m_genF(rows, cols)));
+ };
+
+ glsBuiltinPrecisionTests.dataTypeNameOfMatrix = function(typename, rows, cols) {
+ switch (typename) {
+ case 'float':
+ if (rows === cols)
+ return 'mat' + rows;
+ else
+ return 'mat' + cols + 'x' + rows;
+ }
+ throw new Error('Invalid arguments (' + typename + ', ' + rows + ', ' + cols + ')');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.FuncCaseFactory}
+ */
+ glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory = function(genF) {
+ glsBuiltinPrecisionTests.FuncCaseFactory.call(this);
+ this.m_genF = genF;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory, glsBuiltinPrecisionTests.FuncCaseFactory);
+
+ glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory.prototype.getFunc = function() {
+ return new this.m_genF(2);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ */
+ glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory.prototype.createCase = function(ctx) {
+ var group = tcuTestCase.newTest(ctx.name, ctx.name);
+
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'mat2', new this.m_genF(2)));
+ return group;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ * @param {glsBuiltinPrecisionTests.Func} scalarFunc
+ * @param {number=} size
+ */
+ glsBuiltinPrecisionTests.GenFunc = function(scalarFunc, size) {
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, scalarFunc.Sig);
+ this.m_func = scalarFunc;
+ this.m_size = size;
+ };
+
+ glsBuiltinPrecisionTests.GenFunc.prototype = Object.create(glsBuiltinPrecisionTests.PrimitiveFunc.prototype);
+ glsBuiltinPrecisionTests.GenFunc.prototype.constructor = glsBuiltinPrecisionTests.GenFunc;
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.getName = function() {
+ return this.m_func.getName();
+ };
+
+ /**
+ * @return {number}
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.getOutParamIndex = function() {
+ return this.m_func.getOutParamIndex();
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.getRequiredExtension = function() {
+ return this.m_func.getRequiredExtension();
+ };
+
+ /**
+ * @param {Array<glsBuiltinPrecisionTests.ExprBase>} args
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.doPrint = function(args) {
+ return this.m_func.print(args);
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.EvalContext} ctx
+ * @param {glsBuiltinPrecisionTests.Tuple4} iargs
+ * @return {*}
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.doApply = function(ctx, iargs) {
+ /** @type {Array<*>} */ var ret = [];
+
+ if (this.m_size > 1) {
+ for (var ndx = 0; ndx < this.m_size; ++ndx) {
+ var a = iargs.a === undefined ? undefined : iargs.a[ndx];
+ var b = iargs.b === undefined ? undefined : iargs.b[ndx];
+ var c = iargs.c === undefined ? undefined : iargs.c[ndx];
+ var d = iargs.d === undefined ? undefined : iargs.d[ndx];
+ ret[ndx] = this.m_func.applyFunction(ctx, a, b, c, d);
+ }
+ } else
+ ret[0] = this.m_func.applyFunction(ctx, iargs.a, iargs.b, iargs.c, iargs.d);
+
+ return ret;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.FuncSet} dst
+ */
+ glsBuiltinPrecisionTests.GenFunc.prototype.doGetUsedFuncs = function(dst) {
+ this.m_func.getUsedFuncs(dst);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.GenFunc}
+ * @param {glsBuiltinPrecisionTests.Func} func
+ * @param {number} size
+ */
+ glsBuiltinPrecisionTests.VectorizedFunc = function(func, size) {
+ glsBuiltinPrecisionTests.GenFunc.call(this, func, size);
+ };
+
+ glsBuiltinPrecisionTests.VectorizedFunc.prototype = Object.create(glsBuiltinPrecisionTests.GenFunc.prototype);
+ glsBuiltinPrecisionTests.VectorizedFunc.prototype.constructor = glsBuiltinPrecisionTests.VectorizedFunc;
+
+ /**
+ * @constructor
+ * @param {glsBuiltinPrecisionTests.Func} func_
+ * @param {glsBuiltinPrecisionTests.GenFunc} func2_
+ * @param {glsBuiltinPrecisionTests.GenFunc} func3_
+ * @param {glsBuiltinPrecisionTests.GenFunc} func4_
+ */
+ glsBuiltinPrecisionTests.GenFuncs = function(func_, func2_, func3_, func4_) {
+ this.func = func_;
+ this.func2 = func2_;
+ this.func3 = func3_;
+ this.func4 = func4_;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CaseFactory}
+ * @param {glsBuiltinPrecisionTests.GenFuncs} funcs
+ * @param {string} name
+ */
+ glsBuiltinPrecisionTests.GenFuncCaseFactory = function(funcs, name) {
+ glsBuiltinPrecisionTests.CaseFactory.call(this);
+ this.m_funcs = funcs;
+ this.m_name = name;
+ };
+
+ glsBuiltinPrecisionTests.GenFuncCaseFactory.prototype = Object.create(glsBuiltinPrecisionTests.CaseFactory.prototype);
+ glsBuiltinPrecisionTests.GenFuncCaseFactory.prototype.constructor = glsBuiltinPrecisionTests.GenFuncCaseFactory;
+
+ /**
+ * @param {glsBuiltinPrecisionTests.Context} ctx
+ * @return {tcuTestCase.DeqpTest}
+ */
+ glsBuiltinPrecisionTests.GenFuncCaseFactory.prototype.createCase = function(ctx) {
+ /** @type {tcuTestCase.DeqpTest} */
+ var group = tcuTestCase.newTest(ctx.name, ctx.name);
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'scalar', this.m_funcs.func));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec2', this.m_funcs.func2));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec3', this.m_funcs.func3));
+ group.addChild(glsBuiltinPrecisionTests.createFuncCase(ctx, 'vec4', this.m_funcs.func4));
+
+ return group;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.GenFuncCaseFactory.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsBuiltinPrecisionTests.GenFuncCaseFactory.prototype.getDesc = function() {
+ return "Function '" + this.m_funcs.func.getName() + "'";
+ };
+
+ /**
+ * @constructor
+ * @param {string} name_
+ * @param {tcuFloatFormat.FloatFormat} floatFormat_
+ * @param {tcuFloatFormat.FloatFormat} highpFormat_
+ * @param {gluShaderUtil.precision} precision_
+ * @param {gluShaderProgram.shaderType} shaderType_
+ * @param {number} numRandoms_
+ */
+ glsBuiltinPrecisionTests.Context = function(name_, floatFormat_, highpFormat_, precision_, shaderType_, numRandoms_) {
+ /** @type {string} */ this.name = name_;
+ /** @type {tcuFloatFormat.FloatFormat} */ this.floatFormat = floatFormat_;
+ /** @type {tcuFloatFormat.FloatFormat} */ this.highpFormat = highpFormat_;
+ /** @type {gluShaderUtil.precision} */ this.precision = precision_;
+ /** @type {gluShaderProgram.shaderType} */ this.shaderType = shaderType_;
+ /** @type {number} */ this.numRandoms = numRandoms_;
+ };
+
+ /**
+ * @constructor
+ * @param {tcuFloatFormat.FloatFormat} highp_
+ * @param {tcuFloatFormat.FloatFormat} mediump_
+ * @param {tcuFloatFormat.FloatFormat} lowp_
+ * @param {Array<gluShaderProgram.shaderType>} shaderTypes_
+ * @param {number} numRandoms_
+ */
+ glsBuiltinPrecisionTests.PrecisionTestContext = function(highp_, mediump_, lowp_, shaderTypes_, numRandoms_) {
+ /** @type {Array<gluShaderProgram.shaderType>} */ this.shaderTypes = shaderTypes_;
+ /** @type {Array<tcuFloatFormat.FloatFormat>} */ this.formats = [];
+ this.formats[gluShaderUtil.precision.PRECISION_HIGHP] = highp_;
+ this.formats[gluShaderUtil.precision.PRECISION_MEDIUMP] = mediump_;
+ this.formats[gluShaderUtil.precision.PRECISION_LOWP] = lowp_;
+ /** @type {number} */ this.numRandoms = numRandoms_;
+ };
+
+ /**
+ * \brief Simple incremental counter.
+ *
+ * This is used to make sure that different ExpandContexts will not produce
+ * overlapping temporary names.
+ * @constructor
+ *
+ */
+ glsBuiltinPrecisionTests.Counter = function() {
+ this.m_count = 0;
+ };
+
+ glsBuiltinPrecisionTests.Counter.prototype.get = function() {
+ return this.m_count++;
+ };
+
+ /**
+ * @constructor
+ */
+ glsBuiltinPrecisionTests.ExpandContext = function(counter) {
+ this.m_counter = counter;
+ this.m_statements = [];
+ };
+
+ /**
+ * @param {string} typename
+ * @param {string} baseName
+ * @return {glsBuiltinPrecisionTests.Variable}
+ */
+ glsBuiltinPrecisionTests.ExpandContext.prototype.genSym = function(typename, baseName) {
+ return new glsBuiltinPrecisionTests.Variable(typename, baseName + this.m_counter.get());
+ };
+
+ glsBuiltinPrecisionTests.ExpandContext.prototype.addStatement = function(/*const StatementP&*/ stmt) {
+ this.m_statements.push(stmt);
+ };
+
+ glsBuiltinPrecisionTests.ExpandContext.prototype.getStatements = function() {
+ return this.m_statements;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Func}
+ * @param {glsBuiltinPrecisionTests.Signature} Sig_ template <typename Sig_>
+ */
+ glsBuiltinPrecisionTests.DerivedFunc = function(Sig_) {
+ glsBuiltinPrecisionTests.Func.call(this, Sig_);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.DerivedFunc, glsBuiltinPrecisionTests.Func);
+
+ glsBuiltinPrecisionTests.DerivedFunc.prototype.doPrintDefinition = function() {
+ var os = '';
+ var paramNames = this.getParamNames();
+
+ this.initialize();
+
+ os += this.Ret + ' ' + this.getName() +
+ '(';
+ if (glsBuiltinPrecisionTests.isTypeValid(this.Arg0))
+ os += this.Arg0 + ' ' + paramNames.a;
+ if (glsBuiltinPrecisionTests.isTypeValid(this.Arg1))
+ os += ', ' + this.Arg1 + ' ' + paramNames.b;
+ if (glsBuiltinPrecisionTests.isTypeValid(this.Arg2))
+ os += ', ' + this.Arg2 + ' ' + paramNames.c;
+ if (glsBuiltinPrecisionTests.isTypeValid(this.Arg3))
+ os += ', ' + this.Arg3 + ' ' + paramNames.d;
+ os += ')\n{\n';
+
+ for (var ndx = 0; ndx < this.m_body.length; ++ndx)
+ os += this.m_body[ndx];
+ os += 'return ' + this.m_ret + ';\n';
+ os += '}\n';
+
+ return os;
+ };
+
+ glsBuiltinPrecisionTests.DerivedFunc.prototype.doApply = function(ctx, args) {
+ var funEnv = new glsBuiltinPrecisionTests.Environment();
+ this.initialize();
+
+ funEnv.bind(this.m_var0, args.a);
+ funEnv.bind(this.m_var1, args.b);
+ funEnv.bind(this.m_var2, args.c);
+ funEnv.bind(this.m_var3, args.d);
+
+ var funCtx = new glsBuiltinPrecisionTests.EvalContext(ctx.format, ctx.floatPrecision, funEnv, ctx.callDepth);
+
+ for (var ndx = 0; ndx < this.m_body.length; ++ndx)
+ this.m_body[ndx].execute(funCtx);
+
+ var ret = this.m_ret.evaluate(funCtx);
+
+ // \todo [lauri] Store references instead of values in environment
+ args.a = funEnv.lookup(this.m_var0);
+ args.b = funEnv.lookup(this.m_var1);
+ args.c = funEnv.lookup(this.m_var2);
+ args.d = funEnv.lookup(this.m_var3);
+
+ return ret;
+ };
+
+ glsBuiltinPrecisionTests.DerivedFunc.prototype.initialize = function() {
+ if (!this.m_ret) {
+ var paramNames = this.getParamNames();
+ var symCounter = new glsBuiltinPrecisionTests.Counter();
+ var ctx = new glsBuiltinPrecisionTests.ExpandContext(symCounter);
+
+ this.m_var0 = new glsBuiltinPrecisionTests.Variable(this.Arg0, paramNames.a);
+ this.m_var1 = new glsBuiltinPrecisionTests.Variable(this.Arg1, paramNames.b);
+ this.m_var2 = new glsBuiltinPrecisionTests.Variable(this.Arg2, paramNames.c);
+ this.m_var3 = new glsBuiltinPrecisionTests.Variable(this.Arg3, paramNames.d);
+ var args = new glsBuiltinPrecisionTests.Tuple4(this.m_var0,
+ this.m_var1, this.m_var2, this.m_var3);
+
+ this.m_ret = this.doExpand(ctx, args);
+ this.m_body = ctx.getStatements();
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.Func}
+ * @param {glsBuiltinPrecisionTests.Signature} Sig_ template <typename Sig_>
+ */
+ glsBuiltinPrecisionTests.Alternatives = function(Sig_) {
+ glsBuiltinPrecisionTests.Func.call(this, Sig_);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Alternatives,glsBuiltinPrecisionTests.Func);
+
+ glsBuiltinPrecisionTests.Alternatives.prototype.getName = function() {
+ return 'alternatives';
+ };
+
+ glsBuiltinPrecisionTests.Alternatives.prototype.doPrintDefinition = function() {};
+
+ glsBuiltinPrecisionTests.Alternatives.prototype.doGetUsedFuncs = function(dst) {};
+
+ glsBuiltinPrecisionTests.Alternatives.prototype.doApply = function(ctx,args) {
+ return glsBuiltinPrecisionTests.union(this.Sig.Ret,args.a,args.b);
+ };
+
+ glsBuiltinPrecisionTests.Alternatives.prototype.doPrint = function(args) {
+ return '{' + args[0] + '|' + args[1] + '}';
+ };
+
+ glsBuiltinPrecisionTests.sizeToName = function(size) {
+ switch (size) {
+ case 4: return 'vec4';
+ case 3: return 'vec3';
+ case 2: return 'vec2';
+ }
+ return 'float';
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Dot = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature('float', name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Dot, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Dot.prototype.getName = function() {
+ return 'dot';
+ };
+
+ glsBuiltinPrecisionTests.Dot.prototype.doExpand = function(ctx, args) {
+ if (this.m_inputSize > 1) {
+ var val = app(new glsBuiltinPrecisionTests.Mul(),
+ new glsBuiltinPrecisionTests.VectorVariable(args.a, 0), new glsBuiltinPrecisionTests.VectorVariable(args.b, 0));
+ for (var i = 1; i < this.m_inputSize; i++) {
+ var tmp = new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Mul(),
+ new glsBuiltinPrecisionTests.VectorVariable(args.a, i), new glsBuiltinPrecisionTests.VectorVariable(args.b, i));
+ val = app(new glsBuiltinPrecisionTests.Add(), val, tmp);
+ }
+ return val;
+ } else {
+ // args.a * args.b
+ var ret = app(new glsBuiltinPrecisionTests.Mul(), args.a, args.b);
+ return ret;
+ }
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Length = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature('float', name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Length, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Length.prototype.getName = function() {
+ return 'length';
+ };
+
+ glsBuiltinPrecisionTests.Length.prototype.doExpand = function(ctx, args) {
+ //sqrt(dot(args.a, args.a));
+ var v0 = app(new glsBuiltinPrecisionTests.Dot(this.m_inputSize), args.a, args.a);
+ var v1 = app(new glsBuiltinPrecisionTests.Sqrt(), v0);
+ return v1;
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Distance = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature('float', name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Distance, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Distance.prototype.getName = function() {
+ return 'distance';
+ };
+
+ glsBuiltinPrecisionTests.Distance.prototype.doExpand = function(ctx, args) {
+ //length(args.a - args.b);
+ var v0 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sub(), args.a, args.b);
+ var v1 = app(new glsBuiltinPrecisionTests.Length(this.m_inputSize), v0);
+ return v1;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Cross = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('vec3', 'vec3', 'vec3');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = 3;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Cross, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Cross.prototype.getName = function() {
+ return 'cross';
+ };
+
+ glsBuiltinPrecisionTests.Cross.prototype.doExpand = function(ctx, args) {
+ // vec3(x.a[1] * x.b[2] - x.b[1] * x.a[2],
+ // x.a[2] * x.b[0] - x.b[2] * x.a[0],
+ // x.a[0] * x.b[1] - x.b[0] * x.a[1]);
+ var a = [], b = [];
+ for (var i = 0; i < this.m_inputSize; i++) {
+ a[i] = new glsBuiltinPrecisionTests.VectorVariable(args.a, i);
+ b[i] = new glsBuiltinPrecisionTests.VectorVariable(args.b, i);
+ }
+ var v0 = app(new glsBuiltinPrecisionTests.Mul(), a[1], b[2]);
+ var v1 = app(new glsBuiltinPrecisionTests.Mul(), b[1], a[2]);
+ var v2 = app(new glsBuiltinPrecisionTests.Sub(), v0, v1);
+
+ var v3 = app(new glsBuiltinPrecisionTests.Mul(), a[2], b[0]);
+ var v4 = app(new glsBuiltinPrecisionTests.Mul(), b[2], a[0]);
+ var v5 = app(new glsBuiltinPrecisionTests.Sub(), v3, v4);
+
+ var v6 = app(new glsBuiltinPrecisionTests.Mul(), a[0], b[1]);
+ var v7 = app(new glsBuiltinPrecisionTests.Mul(), b[0], a[1]);
+ var v8 = app(new glsBuiltinPrecisionTests.Sub(), v6, v7);
+
+ var v9 = app(new glsBuiltinPrecisionTests.GenVec(this.m_inputSize, true), v2, v5, v8);
+ return v9;
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Normalize = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature(name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Normalize, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Normalize.prototype.getName = function() {
+ return 'normalize';
+ };
+
+ glsBuiltinPrecisionTests.Normalize.prototype.doExpand = function(ctx, args) {
+ //args.a / length<Size>(args.a);
+ var v0 = app(new glsBuiltinPrecisionTests.Length(this.m_inputSize), args.a);
+ var v1 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Div(), args.a, v0);
+ return v1;
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.FaceForward = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature(name, name, name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ this.typename = name;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.FaceForward, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.FaceForward.prototype.getName = function() {
+ return 'faceforward';
+ };
+
+ glsBuiltinPrecisionTests.FaceForward.prototype.doExpand = function(ctx, args) {
+ //cond(dot(args.c, args.b) < constant(0.0f), args.a, -args.a);
+ var zero = new glsBuiltinPrecisionTests.Constant(0);
+ var v0 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Negate(), args.a);
+ var v1 = app(new glsBuiltinPrecisionTests.Dot(this.m_inputSize), args.c, args.b);
+ var v2 = app(new glsBuiltinPrecisionTests.LessThan('float'), v1, zero);
+ var v3 = app(new glsBuiltinPrecisionTests.Cond(this.typename), v2, args.a, v0);
+ return v3;
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Reflect = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature(name, name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Reflect, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Reflect.prototype.getName = function() {
+ return 'reflect';
+ };
+
+ glsBuiltinPrecisionTests.Reflect.prototype.doExpand = function(ctx, args) {
+ //args.a - (args.b * dot(args.b, args.a) * constant(2.0f));
+ var two = new glsBuiltinPrecisionTests.Constant(2);
+ var v0 = app(new glsBuiltinPrecisionTests.Dot(this.m_inputSize), args.b, args.a);
+ var v1 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), args.b, v0);
+ var v2 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), v1, two);
+ var v3 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sub(), args.a, v2);
+ return v3;
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Refract = function(size) {
+ var name = glsBuiltinPrecisionTests.sizeToName(size);
+ var sig = new glsBuiltinPrecisionTests.Signature(name, name, name, 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ this.m_inputSize = size;
+ this.typename = name;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Refract, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Refract.prototype.getName = function() {
+ return 'refract';
+ };
+
+ glsBuiltinPrecisionTests.Refract.prototype.doExpand = function(ctx, args) {
+ var i = args.a;
+ var n = args.b;
+ var eta = args.c;
+ var zero = new glsBuiltinPrecisionTests.Constant(0);
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ // dotNI = dot(n, i)
+ var v0 = app(new glsBuiltinPrecisionTests.Dot(this.m_inputSize), n, i);
+ var dotNI = glsBuiltinPrecisionTests.bindExpression('float', 'dotNI', ctx, v0);
+ // k = 1 - eta * eta * (1 - dotNI * dotNI)
+ var v1 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), dotNI, dotNI);
+ var v2 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sub(), one, v1);
+ var v3 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), eta, eta);
+ var v4 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), v3, v2);
+ var v5 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sub(), one, v4);
+ var k = glsBuiltinPrecisionTests.bindExpression('float', 'k', ctx, v5);
+
+ // i * eta - n * (eta * dotNI + sqrt(k))
+ var v6 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), eta, dotNI);
+ var v7 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sqrt(), k);
+ var v8 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Add(), v6, v7);
+ var v9 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), n, v8);
+ var v10 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Mul(), i, eta);
+ var v11 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.Sub(), v10, v9);
+
+ var v12 = new glsBuiltinPrecisionTests.ApplyScalar(new glsBuiltinPrecisionTests.LessThan('float'), k, zero);
+
+ var zeroVector = app(new glsBuiltinPrecisionTests.GenVec(this.m_inputSize), zero);
+ var v13 = app(new glsBuiltinPrecisionTests.Cond(this.typename), v12, zeroVector, v11);
+ return v13;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Radians = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Radians, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Radians.prototype.getName = function() {
+ return 'radians';
+ };
+
+ glsBuiltinPrecisionTests.Radians.prototype.doExpand = function(ctx, args) {
+ var val = app(new glsBuiltinPrecisionTests.Div(),
+ new glsBuiltinPrecisionTests.Constant(Math.PI),
+ new glsBuiltinPrecisionTests.Constant(180));
+ return new glsBuiltinPrecisionTests.Apply('float',
+ new glsBuiltinPrecisionTests.Mul(),
+ val,
+ args.a);
+
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Degrees = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Degrees, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Degrees.prototype.getName = function() {
+ return 'degrees';
+ };
+
+ glsBuiltinPrecisionTests.Degrees.prototype.doExpand = function(ctx, args) {
+ var val = app(new glsBuiltinPrecisionTests.Div(),
+ new glsBuiltinPrecisionTests.Constant(180),
+ new glsBuiltinPrecisionTests.Constant(Math.PI));
+ return new glsBuiltinPrecisionTests.Apply('float',
+ new glsBuiltinPrecisionTests.Mul(),
+ val,
+ args.a);
+
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Sinh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Sinh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Sinh.prototype.getName = function() {
+ return 'sinh';
+ };
+
+ glsBuiltinPrecisionTests.Sinh.prototype.doExpand = function(ctx, args) {
+ // (exp(x) - exp(-x)) / constant(2.0f)
+ var x = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Exp(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Negate(), x);
+ var v2 = app(new glsBuiltinPrecisionTests.Exp(), v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Sub(), v0, v2);
+ var v4 = new glsBuiltinPrecisionTests.Constant(2);
+ var v5 = new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Div, v3, v4);
+ return v5;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Cosh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Cosh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Cosh.prototype.getName = function() {
+ return 'cosh';
+ };
+
+ glsBuiltinPrecisionTests.Cosh.prototype.doExpand = function(ctx, args) {
+ // (exp(x) + exp(-x)) / constant(2.0f)
+ var x = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Exp(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Negate(), x);
+ var v2 = app(new glsBuiltinPrecisionTests.Exp(), v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Add(), v0, v2);
+ var v4 = new glsBuiltinPrecisionTests.Constant(2);
+ var v5 = new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Div, v3, v4);
+ return v5;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Tanh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Tanh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Tanh.prototype.getName = function() {
+ return 'tanh';
+ };
+
+ glsBuiltinPrecisionTests.Tanh.prototype.doExpand = function(ctx, args) {
+ // sinh(x) / cosh(x)
+ var x = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Sinh(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Cosh(), x);
+ var v2 = new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Div, v0, v1);
+ return v2;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.ASinh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ASinh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.ASinh.prototype.getName = function() {
+ return 'asinh';
+ };
+
+ glsBuiltinPrecisionTests.ASinh.prototype.doExpand = function(ctx, args) {
+ // log(x + sqrt(x * x + constant(1.0f)))
+ var x = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Mul(), x, x);
+ var v1 = new glsBuiltinPrecisionTests.Constant(1);
+ var v2 = app(new glsBuiltinPrecisionTests.Add(), v0, v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Sqrt(), v2);
+ var v4 = app(new glsBuiltinPrecisionTests.Add(), x, v3);
+ var v5 = app(new glsBuiltinPrecisionTests.Log(), v4);
+ return v5;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.ACosh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ACosh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.ACosh.prototype.getName = function() {
+ return 'acosh';
+ };
+
+ glsBuiltinPrecisionTests.ACosh.prototype.doExpand = function(ctx, args) {
+ // log(x + sqrt((x + constant(1.0f)) * (x - constant(1.0f))))
+ var x = args.a;
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ var v0 = app(new glsBuiltinPrecisionTests.Add(), x, one);
+ var v1 = app(new glsBuiltinPrecisionTests.Sub(), x, one);
+ var v2 = app(new glsBuiltinPrecisionTests.Mul(), v0, v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Sqrt(), v2);
+ var v4 = app(new glsBuiltinPrecisionTests.Add(), x, v3);
+ var v5 = app(new glsBuiltinPrecisionTests.Log(), v4);
+ return v5;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.ATanh = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ATanh, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.ATanh.prototype.getName = function() {
+ return 'atanh';
+ };
+
+ glsBuiltinPrecisionTests.ATanh.prototype.doExpand = function(ctx, args) {
+ // constant(0.5f) * log((constant(1.0f) + x) / (constant(1.0f) - x))
+ var x = args.a;
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ var half = new glsBuiltinPrecisionTests.Constant(0.5);
+ var v0 = app(new glsBuiltinPrecisionTests.Add(), one, x);
+ var v1 = app(new glsBuiltinPrecisionTests.Sub(), one, x);
+ var v2 = app(new glsBuiltinPrecisionTests.Div(), v0, v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Log(), v2);
+ var v4 = app(new glsBuiltinPrecisionTests.Mul(), half, v3);
+ return v4;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Sqrt = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Sqrt, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Sqrt.prototype.getName = function() {
+ return 'sqrt';
+ };
+
+ glsBuiltinPrecisionTests.Sqrt.prototype.doExpand = function(ctx, args) {
+ // constant(1.0f) / app<InverseSqrt>(x)
+ var x = args.a;
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ var v0 = app(new glsBuiltinPrecisionTests.InverseSqrt(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Div(), one, v0);
+ return v1;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Fract = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Fract, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Fract.prototype.getName = function() {
+ return 'fract';
+ };
+
+ glsBuiltinPrecisionTests.Fract.prototype.doExpand = function(ctx, args) {
+ // x - floor(x)
+ var x = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Floor(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Sub(), x, v0);
+ return v1;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Mod = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Mod, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Mod.prototype.getName = function() {
+ return 'mod';
+ };
+
+ glsBuiltinPrecisionTests.Mod.prototype.doExpand = function(ctx, args) {
+ // x - y * floor(x/y)
+ var x = args.a;
+ var y = args.b;
+ var v0 = app(new glsBuiltinPrecisionTests.Div(), x, y);
+ var v1 = app(new glsBuiltinPrecisionTests.Floor(), v0);
+ var v2 = app(new glsBuiltinPrecisionTests.Mul(), y, v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Sub(), x, v2);
+ return v3;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PrimitiveFunc}
+ */
+ glsBuiltinPrecisionTests.Modf = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float');
+ glsBuiltinPrecisionTests.PrimitiveFunc.call(this, sig);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Modf, glsBuiltinPrecisionTests.PrimitiveFunc);
+
+ glsBuiltinPrecisionTests.Modf.prototype.getName = function() {
+ return 'modf';
+ };
+
+ glsBuiltinPrecisionTests.Modf.prototype.doApply = function(ctx, iargs, variablenames) {
+ var intPart;
+ var func1 = function(x) {
+ intPart = Math.trunc(x);
+ return x - intPart;
+ };
+ var func2 = function(x) {
+ return Math.trunc(x);
+ };
+
+ var fracIV = tcuInterval.applyMonotone1p(func1, iargs.a);
+ var wholeIV = tcuInterval.applyMonotone1p(func2, iargs.a);
+
+ if (!iargs.a.isFinite()) {
+ // Behavior on modf(Inf) not well-defined, allow anything as a fractional part
+ // See Khronos bug 13907
+ fracIV.operatorOrAssignBinary(tcuInterval.NAN);
+ }
+
+ ctx.env.m_map[variablenames[1]] = wholeIV;
+ return fracIV;
+ };
+
+ glsBuiltinPrecisionTests.Modf.prototype.getOutParamIndex = function() {
+ return 1;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Mix = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Mix, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Mix.prototype.getName = function() {
+ return 'mix';
+ };
+
+ glsBuiltinPrecisionTests.Mix.prototype.operation1 = function(ctx, args) {
+ // (x * (constant(1.0f) - a)) + y * a
+ var x = args.a;
+ var y = args.b;
+ var a = args.c;
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ var v0 = app(new glsBuiltinPrecisionTests.Sub(), one, a);
+ var v1 = app(new glsBuiltinPrecisionTests.Mul(), x, v0);
+ var v2 = app(new glsBuiltinPrecisionTests.Mul(), y, a);
+ var v3 = app(new glsBuiltinPrecisionTests.Add(), v1, v2);
+ return v3;
+ };
+
+ glsBuiltinPrecisionTests.Mix.prototype.operation2 = function(ctx, args) {
+ // x + (y - x) * a
+ var x = args.a;
+ var y = args.b;
+ var a = args.c;
+ var v0 = app(new glsBuiltinPrecisionTests.Sub(), y, x);
+ var v1 = app(new glsBuiltinPrecisionTests.Mul(), a, v0);
+ var v2 = app(new glsBuiltinPrecisionTests.Add(), x, v1);
+ return v2;
+ };
+
+ glsBuiltinPrecisionTests.Mix.prototype.doExpand = function(ctx, args){
+ return app(new glsBuiltinPrecisionTests.Alternatives(this.Sig), this.operation1(ctx, args), this.operation2(ctx, args), new glsBuiltinPrecisionTests.Void(), new glsBuiltinPrecisionTests.Void());
+ }
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.SmoothStep = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.SmoothStep, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.SmoothStep.prototype.getName = function() {
+ return 'smoothstep';
+ };
+
+ glsBuiltinPrecisionTests.SmoothStep.prototype.doExpand = function(ctx, args) {
+ var edge0 = args.a;
+ var edge1 = args.b;
+ var x = args.c;
+ var zero = new glsBuiltinPrecisionTests.Constant(0);
+ var one = new glsBuiltinPrecisionTests.Constant(1);
+ //clamp((x - edge0) / (edge1 - edge0), constant(0.0f), constant(1.0f));
+ var v0 = app(new glsBuiltinPrecisionTests.Sub(), x, edge0);
+ var v1 = app(new glsBuiltinPrecisionTests.Sub(), edge1, edge0);
+ var v2 = app(new glsBuiltinPrecisionTests.Div(), v0, v1);
+ var v3 = app(new glsBuiltinPrecisionTests.Clamp(), v2, zero, one);
+ var t = glsBuiltinPrecisionTests.bindExpression('float', 't', ctx, v3);
+ //(t * t * (constant(3.0f) - constant(2.0f) * t))
+ var two = new glsBuiltinPrecisionTests.Constant(2);
+ var three = new glsBuiltinPrecisionTests.Constant(3);
+ var v4 = app(new glsBuiltinPrecisionTests.Mul(), v3, v3);
+ var v5 = app(new glsBuiltinPrecisionTests.Mul(), two, v3);
+ var v6 = app(new glsBuiltinPrecisionTests.Sub(), three, v5);
+ var v7 = app(new glsBuiltinPrecisionTests.Mul(), v4, v6);
+ return v7;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Pow = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Pow, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Pow.prototype.getName = function() {
+ return 'pow';
+ };
+
+ glsBuiltinPrecisionTests.Pow.prototype.doExpand = function(ctx, args) {
+ // exp2(y * log2(x))
+ var x = args.a;
+ var y = args.b;
+ var v0 = app(new glsBuiltinPrecisionTests.Log2(), x);
+ var v1 = app(new glsBuiltinPrecisionTests.Mul(), y, v0);
+ var v2 = app(new glsBuiltinPrecisionTests.Exp2(), v1);
+ return v2;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.ExpFunc = function(name, func) {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, name, func);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ExpFunc, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.ExpFunc.prototype.getCodomain = function() {
+ return tcuInterval.withNumbers(0, Infinity);
+ };
+
+ glsBuiltinPrecisionTests.ExpFunc.prototype.precision = function(ctx, ret, x) {
+ switch (ctx.floatPrecision) {
+ case gluShaderUtil.precision.PRECISION_HIGHP:
+ return ctx.format.ulp(ret, 3.0 + 2.0 * Math.abs(x));
+ case gluShaderUtil.precision.PRECISION_MEDIUMP:
+ return ctx.format.ulp(ret, 2.0 + 2.0 * Math.abs(x));
+ case gluShaderUtil.precision.PRECISION_LOWP:
+ return ctx.format.ulp(ret, 2.0);
+ default:
+ throw new Error(!'Impossible');
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ExpFunc}
+ */
+ glsBuiltinPrecisionTests.Exp = function() {
+ glsBuiltinPrecisionTests.ExpFunc.call(this, 'exp', Math.exp);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Exp, glsBuiltinPrecisionTests.ExpFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ExpFunc}
+ */
+ glsBuiltinPrecisionTests.Exp2 = function() {
+ /**
+ * @param {number} x
+ * @return {number}
+ */
+ var exp2 = function(x) {
+ return Math.exp(x * Math.LN2);
+ };
+ glsBuiltinPrecisionTests.ExpFunc.call(this, 'exp2', exp2);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Exp2, glsBuiltinPrecisionTests.ExpFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.LogFunc = function(name, func) {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, name, func);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.LogFunc, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.LogFunc.prototype.precision = function(ctx, ret, x) {
+ if (x <= 0)
+ return NaN;
+ switch (ctx.floatPrecision) {
+ case gluShaderUtil.precision.PRECISION_HIGHP:
+ return (0.5 <= x && x <= 2.0) ? deMath.deLdExp(1.0, -21) : ctx.format.ulp(ret, 3.0);
+ case gluShaderUtil.precision.PRECISION_MEDIUMP:
+ return (0.5 <= x && x <= 2.0) ? deMath.deLdExp(1.0, -7) : ctx.format.ulp(ret, 2.0);
+ case gluShaderUtil.precision.PRECISION_LOWP:
+ return ctx.format.ulp(ret, 2.0);
+ default:
+ throw new Error(!'Impossible');
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.LogFunc}
+ */
+ glsBuiltinPrecisionTests.Log = function() {
+ glsBuiltinPrecisionTests.LogFunc.call(this, 'log', Math.log);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Log, glsBuiltinPrecisionTests.LogFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.LogFunc}
+ */
+ glsBuiltinPrecisionTests.Log2 = function() {
+ glsBuiltinPrecisionTests.LogFunc.call(this, 'log2', Math.log2);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Log2, glsBuiltinPrecisionTests.LogFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.PreciseFunc1 = function(name, func) {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, name, func);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.PreciseFunc1, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.PreciseFunc1.prototype.precision = function(ctx, ret, x) {
+ return 0;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.Abs = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'abs', Math.abs);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Abs, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.Sign = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'sign', Math.sign);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Sign, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.Floor = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'floor', Math.floor);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Floor, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.RoundEven = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'roundEven', deMath.rint);
+ };
+ setParentClass(glsBuiltinPrecisionTests.RoundEven, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.Ceil = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'ceil', Math.ceil);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Ceil, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc1}
+ */
+ glsBuiltinPrecisionTests.Trunc = function() {
+ glsBuiltinPrecisionTests.PreciseFunc1.call(this, 'trunc', Math.trunc);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Trunc, glsBuiltinPrecisionTests.PreciseFunc1);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc2}
+ */
+ glsBuiltinPrecisionTests.PreciseFunc2 = function(name, func) {
+ glsBuiltinPrecisionTests.CFloatFunc2.call(this, name, func);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.PreciseFunc2, glsBuiltinPrecisionTests.CFloatFunc2);
+
+ glsBuiltinPrecisionTests.PreciseFunc2.prototype.precision = function(ctx, ret, x, y) {
+ return 0;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc2}
+ */
+ glsBuiltinPrecisionTests.Min = function() {
+ glsBuiltinPrecisionTests.PreciseFunc2.call(this, 'min', Math.min);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Min, glsBuiltinPrecisionTests.PreciseFunc2);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc2}
+ */
+ glsBuiltinPrecisionTests.Max = function() {
+ glsBuiltinPrecisionTests.PreciseFunc2.call(this, 'max', Math.max);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Max, glsBuiltinPrecisionTests.PreciseFunc2);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.PreciseFunc2}
+ */
+ glsBuiltinPrecisionTests.Step = function() {
+ /**
+ * @param {number} edge
+ * @param {number} x
+ * return number
+ */
+ var step = function(edge, x) {
+ return x < edge ? 0.0 : 1.0;
+ };
+ glsBuiltinPrecisionTests.PreciseFunc2.call(this, 'step', step);
+ };
+ setParentClass(glsBuiltinPrecisionTests.Step, glsBuiltinPrecisionTests.PreciseFunc2);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.TrigFunc = function(name, func, loEx, hiEx) {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, name, func);
+ this.m_loExtremum = loEx;
+ this.m_hiExtremum = hiEx;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.TrigFunc, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.TrigFunc.prototype.innerExtrema = function(ctx, angle) {
+ var lo = angle.lo();
+ var hi = angle.hi();
+ var loSlope = this.doGetSlope(lo);
+ var hiSlope = this.doGetSlope(hi);
+
+ // Detect the high and low values the function can take between the
+ // interval endpoints.
+ if (angle.length() >= 2.0 * Math.PI) {
+ // The interval is longer than a full cycle, so it must get all possible values.
+ return this.m_hiExtremum.operatorOrBinary(this.m_loExtremum);
+ } else if (loSlope == 1 && hiSlope == -1) {
+ // The slope can change from positive to negative only at the maximum value.
+ return this.m_hiExtremum;
+ } else if (loSlope == -1 && hiSlope == 1) {
+ // The slope can change from negative to positive only at the maximum value.
+ return this.m_loExtremum;
+ } else if (loSlope == hiSlope &&
+ deMath.deSign(this.applyExact(hi) - this.applyExact(lo)) * loSlope == -1) {
+ // The slope has changed twice between the endpoints, so both extrema are included.
+ return this.m_hiExtremum.operatorOrBinary(this.m_loExtremum);
+ }
+
+ return new tcuInterval.Interval();
+ };
+
+ glsBuiltinPrecisionTests.TrigFunc.prototype.getCodomain = function() {
+ // Ensure that result is always within [-1, 1], or NaN (for +-inf)
+ var v = tcuInterval.withIntervals(new tcuInterval.Interval(-1), new tcuInterval.Interval(1));
+ return v.operatorOrBinary(tcuInterval.NAN);
+ };
+
+ glsBuiltinPrecisionTests.TrigFunc.prototype.precision = function(ctx, ret, arg) {
+ if (ctx.floatPrecision == gluShaderUtil.precision.PRECISION_HIGHP) {
+ // Use precision from OpenCL fast relaxed math
+ if (-Math.PI <= arg && arg <= Math.PI) {
+ return deMath.deLdExp(1.0, -11);
+ } else {
+ // "larger otherwise", let's pick |x| * 2^-12 , which is slightly over
+ // 2^-11 at x == pi.
+ return deMath.deLdExp(Math.abs(arg), -12);
+ }
+ } else if (ctx.floatPrecision == gluShaderUtil.precision.PRECISION_MEDIUMP) {
+ if (-Math.PI <= arg && arg <= Math.PI) {
+ // from OpenCL half-float extension specification
+ return ctx.format.ulp(ret, 2.0);
+ } else {
+ // |x| * 2^-10 , slightly larger than 2 ULP at x == pi
+ return deMath.deLdExp(Math.abs(arg), -10);
+ }
+ } else {
+ // from OpenCL half-float extension specification
+ return ctx.format.ulp(ret, 2.0);
+ }
+ };
+
+ /**
+ * @param {number} angle
+ * @return number
+ */
+ glsBuiltinPrecisionTests.TrigFunc.prototype.doGetSlope = function(angle) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.TrigFunc}
+ */
+ glsBuiltinPrecisionTests.Sin = function() {
+ glsBuiltinPrecisionTests.TrigFunc.call(this, 'sin', Math.sin, new tcuInterval.Interval(-1), new tcuInterval.Interval(1));
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Sin, glsBuiltinPrecisionTests.TrigFunc);
+
+ glsBuiltinPrecisionTests.Sin.prototype.doGetSlope = function(angle) {
+ return deMath.deSign(Math.cos(angle));
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.TrigFunc}
+ */
+ glsBuiltinPrecisionTests.Cos = function() {
+ glsBuiltinPrecisionTests.TrigFunc.call(this, 'cos', Math.cos, new tcuInterval.Interval(-1), new tcuInterval.Interval(1));
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Cos, glsBuiltinPrecisionTests.TrigFunc);
+
+ glsBuiltinPrecisionTests.Cos.prototype.doGetSlope = function(angle) {
+ return -deMath.deSign(Math.sin(angle));
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Tan = function() {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'float');
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Tan, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Tan.prototype.getName = function() {
+ return 'tan';
+ };
+
+ glsBuiltinPrecisionTests.Tan.prototype.doExpand = function(ctx, args) {
+ // sin(x) * (constant(1.0f) / cos(x)
+ var x = args.a;
+ var sin = app(new glsBuiltinPrecisionTests.Sin(), x);
+ var cos = app(new glsBuiltinPrecisionTests.Cos(), x);
+ var expr = app(new glsBuiltinPrecisionTests.Div(),
+ new glsBuiltinPrecisionTests.Constant(1),
+ cos);
+
+ expr = new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Mul(),
+ sin,
+ expr);
+ return expr;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.ASin = function() {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, 'asin', Math.asin);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ASin, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.ASin.prototype.precision = function(ctx, ret, x) {
+ if (!deMath.deInBounds32(x, -1.0, 1.0))
+ return NaN;
+
+ if (ctx.floatPrecision == gluShaderUtil.precision.PRECISION_HIGHP) {
+ // Absolute error of 2^-11
+ return deMath.deLdExp(1.0, -11);
+ } else {
+ // Absolute error of 2^-8
+ return deMath.deLdExp(1.0, -8);
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc1}
+ */
+ glsBuiltinPrecisionTests.ArcTrigFunc = function(name, func, precisionULPs, domain, coddomain) {
+ glsBuiltinPrecisionTests.CFloatFunc1.call(this, name, func);
+ this.m_precision = precisionULPs;
+ this.m_domain = domain;
+ this.m_codomain = coddomain;
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ArcTrigFunc, glsBuiltinPrecisionTests.CFloatFunc1);
+
+ glsBuiltinPrecisionTests.ArcTrigFunc.prototype.precision = function(ctx, ret, x) {
+ if (!this.m_domain.contains(new tcuInterval.Interval(x)))
+ return NaN;
+
+ if (ctx.floatPrecision == gluShaderUtil.precision.PRECISION_HIGHP) {
+ // Use OpenCL's precision
+ return ctx.format.ulp(ret, this.m_precision);
+ } else {
+ // Use OpenCL half-float spec
+ return ctx.format.ulp(ret, 2.0);
+ }
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ArcTrigFunc}
+ */
+ glsBuiltinPrecisionTests.ACos = function() {
+ glsBuiltinPrecisionTests.ArcTrigFunc.call(this, 'acos', Math.acos, 4096.0,
+ tcuInterval.withNumbers(-1, 1),
+ tcuInterval.withNumbers(0, Math.PI));
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ACos, glsBuiltinPrecisionTests.ArcTrigFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.ArcTrigFunc}
+ */
+ glsBuiltinPrecisionTests.ATan = function() {
+ glsBuiltinPrecisionTests.ArcTrigFunc.call(this, 'atan', Math.atan, 4096.0,
+ tcuInterval.unbounded(),
+ tcuInterval.withNumbers(-Math.PI * 0.5, Math.PI * 0.5));
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ATan, glsBuiltinPrecisionTests.ArcTrigFunc);
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.CFloatFunc2}
+ */
+ glsBuiltinPrecisionTests.ATan2 = function() {
+ glsBuiltinPrecisionTests.CFloatFunc2.call(this, 'atan', Math.atan2);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.ATan2, glsBuiltinPrecisionTests.CFloatFunc2);
+
+ glsBuiltinPrecisionTests.ATan2.prototype.innerExtrema = function(ctx, xi, yi) {
+ var ret = new tcuInterval.Interval();
+
+ if (yi.contains(tcuInterval.ZERO)) {
+ if (xi.contains(tcuInterval.ZERO))
+ ret.operatorOrAssignBinary(tcuInterval.NAN);
+ if (xi.intersects(tcuInterval.withNumbers(-Infinity, 0)))
+ ret.operatorOrAssignBinary(tcuInterval.withNumbers(-Math.PI, Math.PI));
+ }
+
+ if (ctx.format.hasInf() != tcuFloatFormat.YesNoMaybe.YES && (!yi.isFinite() || !xi.isFinite())) {
+ // Infinities may not be supported, allow anything, including NaN
+ ret.operatorOrAssignBinary(tcuInterval.NAN);
+ }
+
+ return ret;
+ };
+
+ glsBuiltinPrecisionTests.ATan2.prototype.precision = function(ctx, ret, x, y) {
+ if (ctx.floatPrecision == gluShaderUtil.precision.PRECISION_HIGHP)
+ return ctx.format.ulp(ret, 4096.0);
+ else
+ return ctx.format.ulp(ret, 2.0);
+ };
+
+ /**
+ * @constructor
+ * @param {number} size
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.DeterminantBase = function(size) {
+ var sig = new glsBuiltinPrecisionTests.Signature('float', 'mat' + size);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.DeterminantBase, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.DeterminantBase.prototype.getName = function() {
+ return 'determinant';
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DeterminantBase}
+ */
+ glsBuiltinPrecisionTests.Determinant = function() {
+ // TODO: Support sizes 3 and 4
+ this.size = 2;
+ glsBuiltinPrecisionTests.DeterminantBase.call(this, this.size);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Determinant, glsBuiltinPrecisionTests.DeterminantBase);
+
+ glsBuiltinPrecisionTests.Determinant.prototype.doExpand = function(ctx, args) {
+ // mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]
+ var elem0_0 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 0, 0);
+ var elem0_1 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 0, 1);
+ var elem1_0 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 1, 0);
+ var elem1_1 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 1, 1);
+
+ var val0 = app(new glsBuiltinPrecisionTests.Mul(), elem0_0, elem1_1);
+ var val1 = app(new glsBuiltinPrecisionTests.Mul(), elem0_1, elem1_0);
+ return new glsBuiltinPrecisionTests.Apply('float', new glsBuiltinPrecisionTests.Sub(), val0, val1);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsBuiltinPrecisionTests.DerivedFunc}
+ */
+ glsBuiltinPrecisionTests.Inverse = function() {
+ this.size = 2;
+ var name = 'mat' + this.size;
+ var sig = new glsBuiltinPrecisionTests.Signature(name, name);
+ glsBuiltinPrecisionTests.DerivedFunc.call(this, sig);
+ };
+
+ setParentClass(glsBuiltinPrecisionTests.Inverse, glsBuiltinPrecisionTests.DerivedFunc);
+
+ glsBuiltinPrecisionTests.Inverse.prototype.getName = function() {
+ return 'inverse';
+ };
+
+ glsBuiltinPrecisionTests.Inverse.prototype.doExpand = function(ctx, args) {
+ var mat = args.a;
+ var v0 = app(new glsBuiltinPrecisionTests.Determinant(), mat);
+ var det = glsBuiltinPrecisionTests.bindExpression('float', 'det', ctx, v0);
+
+ var elem0_0 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 0, 0);
+ var elem0_1 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 0, 1);
+ var elem1_0 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 1, 0);
+ var elem1_1 = new glsBuiltinPrecisionTests.MatrixVariable(args.a, 1, 1);
+
+ var result0_0 = app(new glsBuiltinPrecisionTests.Div(), elem1_1, det);
+ var result0_1 = app(new glsBuiltinPrecisionTests.Div(), elem0_1, det);
+ result0_1 = app(new glsBuiltinPrecisionTests.Negate(), result0_1);
+ var result1_0 = app(new glsBuiltinPrecisionTests.Div(), elem1_0, det);
+ result1_0 = app(new glsBuiltinPrecisionTests.Negate(), result1_0);
+ var result1_1 = app(new glsBuiltinPrecisionTests.Div(), elem0_0, det);
+
+ var col0 = app(new glsBuiltinPrecisionTests.GenVec(this.size, true), result0_0, result1_0);
+ var col1 = app(new glsBuiltinPrecisionTests.GenVec(this.size, true), result0_1, result1_1);
+ var ret = app(new glsBuiltinPrecisionTests.GenMat(this.size, this.size), col0, col1);
+
+ return ret;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.PrecisionTestContext} ctx
+ * @param {glsBuiltinPrecisionTests.CaseFactory} factory
+ * @return {tcuTestCase.DeqpTest}
+ */
+ glsBuiltinPrecisionTests.createFuncGroup = function(ctx, factory) {
+ /** @type {tcuTestCase.DeqpTest} */ var group = tcuTestCase.newTest(factory.getName(), factory.getDesc());
+
+ for (var precNdx in gluShaderUtil.precision) {
+ /** @type {gluShaderUtil.precision} */ var precision = gluShaderUtil.precision[precNdx];
+ /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(precision);
+ /** @type {tcuFloatFormat.FloatFormat} */ var fmt = ctx.formats[precision];
+ /** @type {tcuFloatFormat.FloatFormat} */ var highpFmt = ctx.formats[gluShaderUtil.precision.PRECISION_HIGHP];
+
+ for (var shaderNdx in ctx.shaderTypes) {
+ /** @type {gluShaderProgram.shaderType} */ var shaderType = ctx.shaderTypes[shaderNdx];
+ /** @type {string} */ var shaderName = gluShaderProgram.getShaderTypeName(shaderType);
+ /** @type {string} */ var name = precName + '_' + shaderName;
+ /** @type {glsBuiltinPrecisionTests.Context} */ var caseCtx = new glsBuiltinPrecisionTests.Context(name, fmt, highpFmt,
+ precision, shaderType, ctx.numRandoms);
+
+ group.addChild(factory.createCase(caseCtx));
+ }
+ }
+
+ return group;
+ };
+
+ /**
+ * @param {glsBuiltinPrecisionTests.CaseFactories} cases
+ * @param {Array<gluShaderProgram.shaderType>} shaderTypes
+ * @param {tcuTestCase.DeqpTest} dstGroup
+ */
+ glsBuiltinPrecisionTests.addBuiltinPrecisionTests = function(cases, shaderTypes, dstGroup) {
+ /** @type {tcuFloatFormat.FloatFormat} */ var highp = new tcuFloatFormat.FloatFormat(-126, 127, 23, true,
+ tcuFloatFormat.YesNoMaybe.MAYBE, // subnormals
+ tcuFloatFormat.YesNoMaybe.YES, // infinities
+ tcuFloatFormat.YesNoMaybe.MAYBE); // NaN
+ // \todo [2014-04-01 lauri] Check these once Khronos bug 11840 is resolved.
+ /** @type {tcuFloatFormat.FloatFormat} */ var mediump = new tcuFloatFormat.FloatFormat(-13, 13, 9, false);
+ // A fixed-point format is just a floating point format with a fixed
+ // exponent and support for subnormals.
+ /** @type {tcuFloatFormat.FloatFormat} */ var lowp = new tcuFloatFormat.FloatFormat(0, 0, 7, false, tcuFloatFormat.YesNoMaybe.YES);
+ /** @type {glsBuiltinPrecisionTests.PrecisionTestContext} */ var ctx = new glsBuiltinPrecisionTests.PrecisionTestContext(highp, mediump, lowp,
+ shaderTypes, 16384);
+
+ for (var ndx = 0; ndx < cases.getFactories().length; ++ndx)
+ dstGroup.addChild(glsBuiltinPrecisionTests.createFuncGroup(ctx, cases.getFactories()[ndx]));
+ };
+
+ /**
+ * @param {function(new:glsBuiltinPrecisionTests.Func)} F
+ * @param {glsBuiltinPrecisionTests.CaseFactories} funcs
+ * @param {string=} name
+ */
+ glsBuiltinPrecisionTests.addScalarFactory = function(F, funcs, name) {
+ if (name === undefined)
+ name = (new F()).getName();
+
+ funcs.addFactory(new glsBuiltinPrecisionTests.GenFuncCaseFactory(glsBuiltinPrecisionTests.makeVectorizedFuncs(F), name));
+ };
+
+ /**
+ * @param {function(new:glsBuiltinPrecisionTests.Func)} F
+ */
+ glsBuiltinPrecisionTests.createSimpleFuncCaseFactory = function(F) {
+ return new glsBuiltinPrecisionTests.SimpleFuncCaseFactory(new F());
+ };
+
+ /**
+ * @param {number} caseId test case Id
+ * @return {glsBuiltinPrecisionTests.CaseFactories}
+ */
+ glsBuiltinPrecisionTests.createES3BuiltinCases = function(caseId) {
+ /** @type {glsBuiltinPrecisionTests.CaseFactories} */ var funcs = new glsBuiltinPrecisionTests.BuiltinFuncs();
+
+ switch (caseId) {
+ case 0: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Add, funcs); break;
+ case 1: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Sub, funcs); break;
+ case 2: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Mul, funcs); break;
+ case 3: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Div, funcs); break;
+ case 4: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Radians, funcs); break;
+ case 5: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Degrees, funcs); break;
+ case 6: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Sin, funcs); break;
+ case 7: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Cos, funcs); break;
+ case 8: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Tan, funcs); break;
+ case 9: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ASin, funcs); break;
+ case 10: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ACos, funcs); break;
+ case 11: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ATan, funcs); break;
+ case 12: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ATan2, funcs, 'atan2'); break;
+ case 13: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Sinh, funcs); break;
+ case 14: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Cosh, funcs); break;
+ case 15: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Tanh, funcs); break;
+ case 16: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ASinh, funcs); break;
+ case 17: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ACosh, funcs); break;
+ case 18: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.ATanh, funcs); break;
+ case 19: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Pow, funcs); break;
+ case 20: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Exp, funcs); break;
+ case 21: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Exp2, funcs); break;
+ case 22: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Log, funcs); break;
+ case 23: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Log2, funcs); break;
+ case 24: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Sqrt, funcs); break;
+ case 25: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.InverseSqrt, funcs); break;
+ case 26: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Abs, funcs); break;
+ case 27: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Sign, funcs); break;
+ case 28: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Floor, funcs); break;
+ case 29: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Trunc, funcs); break;
+ case 30: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Round, funcs); break;
+ case 31: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.RoundEven, funcs); break;
+ case 32: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Ceil, funcs); break;
+ case 33: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Fract, funcs); break;
+ case 34: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Mod, funcs); break;
+ case 35: funcs.addFactory(glsBuiltinPrecisionTests.createSimpleFuncCaseFactory(glsBuiltinPrecisionTests.Modf)); break;
+ case 36: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Min, funcs); break;
+ case 37: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Max, funcs); break;
+ case 38: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Mix, funcs); break;
+ case 39: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Step, funcs); break;
+ case 40: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.SmoothStep, funcs); break;
+ case 41: glsBuiltinPrecisionTests.addScalarFactory(glsBuiltinPrecisionTests.Clamp, funcs); break;
+ case 42: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Length)); break;
+ case 43: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Distance)); break;
+ case 44: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Dot)); break;
+ case 45: funcs.addFactory(glsBuiltinPrecisionTests.createSimpleFuncCaseFactory(glsBuiltinPrecisionTests.Cross)); break;
+ case 46: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Normalize)); break;
+ case 47: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.FaceForward)); break;
+ case 48: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Reflect)); break;
+ case 49: funcs.addFactory(new glsBuiltinPrecisionTests.TemplateFuncCaseFactory(glsBuiltinPrecisionTests.Refract)); break;
+ case 50: funcs.addFactory(new glsBuiltinPrecisionTests.MatrixFuncCaseFactory(glsBuiltinPrecisionTests.MatrixCompMult)); break;
+ case 51: funcs.addFactory(new glsBuiltinPrecisionTests.MatrixFuncCaseFactory(glsBuiltinPrecisionTests.OuterProduct)); break;
+ case 52: funcs.addFactory(new glsBuiltinPrecisionTests.MatrixFuncCaseFactory(glsBuiltinPrecisionTests.Transpose)); break;
+ case 53: funcs.addFactory(new glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory(glsBuiltinPrecisionTests.Determinant)); break;
+ case 54: funcs.addFactory(new glsBuiltinPrecisionTests.SquareMatrixFuncCaseFactory(glsBuiltinPrecisionTests.Inverse)); break;
+ default: break;
+ }
+
+ return funcs;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTestsUnitTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTestsUnitTests.js
new file mode 100644
index 000000000..e8df9d28e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTestsUnitTests.js
@@ -0,0 +1,2819 @@
+'use strict';
+goog.provide('modules.shared.glsBuiltinPrecisionTestsUnitTests');
+goog.require('framework.common.tcuInterval');
+goog.require('framework.common.tcuMatrix');
+
+goog.scope(function() {
+
+ modules.shared.glsBuiltinPrecisionTestsUnitTests.cppreference = [];
+ var tcuInterval = framework.common.tcuInterval;
+ var glsBuiltinPrecisionTestsUnitTests = modules.shared.glsBuiltinPrecisionTestsUnitTests;
+ var tcuMatrix = framework.common.tcuMatrix;
+
+ var ref = modules.shared.glsBuiltinPrecisionTestsUnitTests.cppreference;
+ref.push({testName: 'precision.add.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625, false, 0.390625, 0.40625]});
+ref.push({testName: 'precision.add.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125, false, 0.695313, 0.703125]});
+ref.push({testName: 'precision.add.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391, false, 0.399902, 0.400391]});
+ref.push({testName: 'precision.add.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195, false, 0.699219, 0.700195]});
+ref.push({testName: 'precision.add.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.add.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.add.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7, false, 0.7, 0.7]});
+ref.push({testName: 'precision.sub.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.sub.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875, false, -0.304688, -0.296875]});
+ref.push({testName: 'precision.sub.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.sub.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805, false, -0.300293, -0.299805]});
+ref.push({testName: 'precision.sub.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.sub.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.sub.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3, false, -0.3, -0.3]});
+ref.push({testName: 'precision.mul.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.mul.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.mul.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.mul.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.mul.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.mul.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.mul.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.div.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.div.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061, false, 0.996338, 1.0061]});
+ref.push({testName: 'precision.div.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611, false, 0.398682, 0.401611]});
+ref.push({testName: 'precision.div.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.div.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.div.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.div.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.div.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4, false, 0.4, 0.4]});
+ref.push({testName: 'precision.radians.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.radians.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952, false, 0.00347137, 0.00350952]});
+ref.push({testName: 'precision.radians.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738, false, 0.00868225, 0.0087738]});
+ref.push({testName: 'precision.radians.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.radians.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066, false, 0.00349066, 0.00349066]});
+ref.push({testName: 'precision.radians.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665, false, 0.00872664, 0.00872665]});
+ref.push({testName: 'precision.degrees.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.degrees.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156, false, 11.4219, 11.5156]});
+ref.push({testName: 'precision.degrees.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75, false, 28.5625, 28.75]});
+ref.push({testName: 'precision.degrees.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592, false, 11.4592, 11.4592]});
+ref.push({testName: 'precision.degrees.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479, false, 28.6479, 28.6479]});
+ref.push({testName: 'precision.sin.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356, false, 0.178448, 0.217356]});
+ref.push({testName: 'precision.sin.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051, false, 0.463801, 0.495051]});
+ref.push({testName: 'precision.sin.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349, false, 0.198133, 0.199349]});
+ref.push({testName: 'precision.sin.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402, false, 0.478449, 0.480402]});
+ref.push({testName: 'precision.sin.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.sin.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158, false, 0.198181, 0.199158]});
+ref.push({testName: 'precision.sin.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914, false, 0.478937, 0.479914]});
+ref.push({testName: 'precision.cos.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612, false, 0.963816, 0.996612]});
+ref.push({testName: 'precision.cos.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208, false, 0.861958, 0.893208]});
+ref.push({testName: 'precision.cos.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029, false, 0.978075, 0.982029]});
+ref.push({testName: 'precision.cos.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536, false, 0.875629, 0.879536]});
+ref.push({testName: 'precision.cos.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.cos.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555, false, 0.979578, 0.980555]});
+ref.push({testName: 'precision.cos.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071, false, 0.877094, 0.878071]});
+ref.push({testName: 'precision.tan.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.tan.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834, false, 0.200684, 0.204834]});
+ref.push({testName: 'precision.tan.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758, false, 0.541016, 0.551758]});
+ref.push({testName: 'precision.tan.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.tan.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331, false, 0.202111, 0.20331]});
+ref.push({testName: 'precision.tan.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163, false, 0.545443, 0.547163]});
+ref.push({testName: 'precision.asin.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173, false, 0.180951, 0.220173]});
+ref.push({testName: 'precision.asin.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224, false, 0.507974, 0.539224]});
+ref.push({testName: 'precision.asin.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046, false, 0.20082, 0.202046]});
+ref.push({testName: 'precision.asin.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552, false, 0.521646, 0.525552]});
+ref.push({testName: 'precision.asin.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.asin.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358, false, 0.201358, 0.201358]});
+ref.push({testName: 'precision.asin.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599, false, 0.523599, 0.523599]});
+ref.push({testName: 'precision.acos.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985, false, 1.35062, 1.38985]});
+ref.push({testName: 'precision.acos.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282, false, 1.03157, 1.06282]});
+ref.push({testName: 'precision.acos.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339, false, 1.36533, 1.37339]});
+ref.push({testName: 'precision.acos.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511, false, 1.04329, 1.0511]});
+ref.push({testName: 'precision.acos.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.acos.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944, false, 1.36944, 1.36944]});
+ref.push({testName: 'precision.acos.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472, false, 1.0472, 1.0472]});
+ref.push({testName: 'precision.atan2.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628, false, 0.750168, 0.820628]});
+ref.push({testName: 'precision.atan2.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508, false, 0.356773, 0.401508]});
+ref.push({testName: 'precision.atan2.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961, false, 0.782835, 0.787961]});
+ref.push({testName: 'precision.atan2.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182, false, 0.379446, 0.38182]});
+ref.push({testName: 'precision.atan2.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398, false, 0.785398, 0.785398]});
+ref.push({testName: 'precision.atan2.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507, false, 0.380506, 0.380507]});
+ref.push({testName: 'precision.atan.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024, false, 0.177259, 0.216024]});
+ref.push({testName: 'precision.atan.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273, false, 0.448023, 0.479273]});
+ref.push({testName: 'precision.atan.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072, false, 0.19686, 0.198072]});
+ref.push({testName: 'precision.atan.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624, false, 0.462671, 0.464624]});
+ref.push({testName: 'precision.atan.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.atan.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396, false, 0.197395, 0.197396]});
+ref.push({testName: 'precision.atan.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648, false, 0.463647, 0.463648]});
+ref.push({testName: 'precision.sinh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sinh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688, false, 0.197144, 0.205688]});
+ref.push({testName: 'precision.sinh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809, false, 0.51416, 0.528809]});
+ref.push({testName: 'precision.sinh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336, false, 0.201336, 0.201336]});
+ref.push({testName: 'precision.sinh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096, false, 0.521095, 0.521096]});
+ref.push({testName: 'precision.cosh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.cosh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027, false, 1.01074, 1.03027]});
+ref.push({testName: 'precision.cosh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377, false, 1.11816, 1.1377]});
+ref.push({testName: 'precision.cosh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007, false, 1.02007, 1.02007]});
+ref.push({testName: 'precision.cosh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763, false, 1.12763, 1.12763]});
+ref.push({testName: 'precision.tanh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.tanh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113, false, 0.19074, 0.204113]});
+ref.push({testName: 'precision.tanh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146, false, 0.450711, 0.474146]});
+ref.push({testName: 'precision.tanh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376, false, 0.197375, 0.197376]});
+ref.push({testName: 'precision.tanh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118, false, 0.462116, 0.462118]});
+ref.push({testName: 'precision.asinh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.asinh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619, false, 0.183582, 0.213619]});
+ref.push({testName: 'precision.asinh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521, false, 0.468033, 0.494521]});
+ref.push({testName: 'precision.asinh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691, false, 0.198689, 0.198691]});
+ref.push({testName: 'precision.asinh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213, false, 0.481211, 0.481213]});
+ref.push({testName: 'precision.acosh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.acosh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.atanh.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984, false, 0.196289, 0.208984]});
+ref.push({testName: 'precision.atanh.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711, false, 0.544922, 0.553711]});
+ref.push({testName: 'precision.atanh.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733, false, 0.202732, 0.202733]});
+ref.push({testName: 'precision.atanh.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306, false, 0.549306, 0.549306]});
+ref.push({testName: 'precision.pow.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566, false, 0, 0.782566]});
+ref.push({testName: 'precision.pow.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834, false, 0, 0.51834]});
+ref.push({testName: 'precision.pow.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633, false, 0.720704, 0.728633]});
+ref.push({testName: 'precision.pow.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783, false, 0.443535, 0.450783]});
+ref.push({testName: 'precision.pow.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.pow.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478, false, 0.724779, 0.72478]});
+ref.push({testName: 'precision.pow.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.exp.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085, false, 1.20007, 1.24085]});
+ref.push({testName: 'precision.exp.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435, false, 1.6331, 1.66435]});
+ref.push({testName: 'precision.exp.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633, false, 1.21666, 1.22633]});
+ref.push({testName: 'precision.exp.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458, false, 1.64286, 1.65458]});
+ref.push({testName: 'precision.exp.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.exp.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214, false, 1.2214, 1.2214]});
+ref.push({testName: 'precision.exp.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872, false, 1.64872, 1.64872]});
+ref.push({testName: 'precision.log.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831, false, -1.64878, -1.57831]});
+ref.push({testName: 'precision.log.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522, false, -0.708772, -0.677522]});
+ref.push({testName: 'precision.log.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456, false, -1.61359, -1.60456]});
+ref.push({testName: 'precision.log.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335, false, -0.70096, -0.685335]});
+ref.push({testName: 'precision.log.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.log.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944, false, -1.60944, -1.60944]});
+ref.push({testName: 'precision.log.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147, false, -0.693148, -0.693147]});
+ref.push({testName: 'precision.exp2.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681, false, 1.12935, 1.16681]});
+ref.push({testName: 'precision.exp2.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.exp2.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354, false, 1.14397, 1.15354]});
+ref.push({testName: 'precision.exp2.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007, false, 1.40835, 1.42007]});
+ref.push({testName: 'precision.exp2.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487, false, 1.1487, 1.1487]});
+ref.push({testName: 'precision.exp2.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.log2.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219, false, -Infinity, -1.99219]});
+ref.push({testName: 'precision.log2.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375, false, -1.01563, -0.984375]});
+ref.push({testName: 'precision.log2.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271, false, -2.33009, -2.31271]});
+ref.push({testName: 'precision.log2.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188, false, -1.00781, -0.992188]});
+ref.push({testName: 'precision.log2.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1, false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.log2.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193, false, -2.32193, -2.32193]});
+ref.push({testName: 'precision.log2.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -1, -1, false, -1, -1, false, -1, -1, false, -1, -1]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222, false, 0.444382, 0.450222]});
+ref.push({testName: 'precision.sqrt.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507, false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.sqrt.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214, false, 0.447213, 0.447214]});
+ref.push({testName: 'precision.sqrt.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107, false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity, false, 1.99219, Infinity]});
+ref.push({testName: 'precision.inversesqrt.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984, false, 1.39859, 1.42984]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415, false, 2.22716, 2.24415]});
+ref.push({testName: 'precision.inversesqrt.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812, false, 1.41031, 1.41812]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607, false, 2.23607, 2.23607]});
+ref.push({testName: 'precision.inversesqrt.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421, false, 1.41421, 1.41421]});
+ref.push({testName: 'precision.abs.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.abs.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.abs.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.abs.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.abs.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.sign.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.sign.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.floor.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.floor.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.trunc.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.round.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.round.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.round.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.round.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.roundeven.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.ceil.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.ceil.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.fract.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.fract.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.fract.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.fract.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.fract.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.mod.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.mod.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195, false, -0.000244141, 0.200195]});
+ref.push({testName: 'precision.mod.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mod.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2, false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 0.2, false, 0, 0.2, false, 0, 0.2, false, 0, 0.2]});
+ref.push({testName: 'precision.mod.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.modf.lowp_vertex', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.lowp_vertex', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.modf.lowp_vertex', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.lowp_vertex', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.modf.lowp_fragment', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.lowp_fragment', input: '0.2, (), (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.modf.lowp_fragment', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.lowp_fragment', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.modf.mediump_vertex', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.mediump_vertex', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.modf.mediump_vertex', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.mediump_vertex', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.modf.mediump_fragment', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.mediump_fragment', input: '0.2, (), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.modf.mediump_fragment', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.mediump_fragment', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.modf.highp_vertex', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.highp_vertex', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.modf.highp_vertex', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.highp_vertex', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.modf.highp_fragment', input: '0.2, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.highp_fragment', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.modf.highp_fragment', input: '0.5, (), (), ()', reference: [false, 0, 0]});
+ref.push({testName: 'precision.modf.highp_fragment', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.min.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.min.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.min.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.min.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.max.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.max.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.max.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.max.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.clamp.lowp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.clamp.mediump_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.clamp.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.clamp.highp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.clamp.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.lowp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938, false, 0.179688, 0.210938]});
+ref.push({testName: 'precision.mix.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125, false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.mix.mediump_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684, false, 0.199707, 0.200684]});
+ref.push({testName: 'precision.mix.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.mix.highp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.mix.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2, false, 0.2, 0.2]});
+ref.push({testName: 'precision.step.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0, 1, false, 0, 1, false, 0, 1, false, 0, 1]});
+ref.push({testName: 'precision.step.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.step.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 1, 1, false, 1, 1, false, 1, 1, false, 1, 1]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity, true, -Infinity, Infinity]});
+ref.push({testName: 'precision.smoothstep.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, 0, 3, false, 0, 3, false, 0, 3, false, 0, 3]});
+ref.push({testName: 'precision.length.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.length.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.198712, 0.201489]});
+ref.push({testName: 'precision.length.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.497805, 0.50342]});
+ref.push({testName: 'precision.length.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.280921, 0.285045]});
+ref.push({testName: 'precision.length.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.length.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.344072, 0.349095]});
+ref.push({testName: 'precision.length.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.860664, 0.871406]});
+ref.push({testName: 'precision.length.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.397121, 0.403285]});
+ref.push({testName: 'precision.length.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.995609, 1.00684]});
+ref.push({testName: 'precision.length.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.198712, 0.201489]});
+ref.push({testName: 'precision.length.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.497805, 0.50342]});
+ref.push({testName: 'precision.length.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.280921, 0.285045]});
+ref.push({testName: 'precision.length.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.702718, 0.711507]});
+ref.push({testName: 'precision.length.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.344072, 0.349095]});
+ref.push({testName: 'precision.length.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.860664, 0.871406]});
+ref.push({testName: 'precision.length.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.397121, 0.403285]});
+ref.push({testName: 'precision.length.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.995609, 1.00684]});
+ref.push({testName: 'precision.length.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.length.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.length.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.282843, 0.282843]});
+ref.push({testName: 'precision.length.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.length.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.34641, 0.34641]});
+ref.push({testName: 'precision.length.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.866025, 0.866026]});
+ref.push({testName: 'precision.length.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.length.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.length.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.length.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.5, 0.5]});
+ref.push({testName: 'precision.length.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.282843, 0.282843]});
+ref.push({testName: 'precision.length.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707107, 0.707107]});
+ref.push({testName: 'precision.length.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.34641, 0.34641]});
+ref.push({testName: 'precision.length.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.866025, 0.866026]});
+ref.push({testName: 'precision.length.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.length.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.distance.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.297819, 0.302277]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.421276, 0.427394]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.515672, 0.524075]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.595637, 0.604962]});
+ref.push({testName: 'precision.distance.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.297819, 0.302277]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.421276, 0.427394]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.515672, 0.524075]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.595637, 0.604962]});
+ref.push({testName: 'precision.distance.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.3, 0.3]});
+ref.push({testName: 'precision.distance.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.424264, 0.424264]});
+ref.push({testName: 'precision.distance.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.519615, 0.519615]});
+ref.push({testName: 'precision.distance.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.6, 0.6]});
+ref.push({testName: 'precision.distance.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.3, 0.3]});
+ref.push({testName: 'precision.distance.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.424264, 0.424264]});
+ref.push({testName: 'precision.distance.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.519615, 0.519615]});
+ref.push({testName: 'precision.distance.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [true, -Infinity, Infinity]});
+ref.push({testName: 'precision.distance.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.6, 0.6]});
+ref.push({testName: 'precision.dot.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.dot.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.0625, 0.09375]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.09375, 0.140625]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.28125, 0.304688]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.125, 0.1875]});
+ref.push({testName: 'precision.dot.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.375, 0.40625]});
+ref.push({testName: 'precision.dot.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.dot.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.0625, 0.09375]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1875, 0.203125]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.09375, 0.140625]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.28125, 0.304688]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.125, 0.1875]});
+ref.push({testName: 'precision.dot.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.375, 0.40625]});
+ref.push({testName: 'precision.dot.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.dot.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.0799561, 0.0802002]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.119873, 0.120361]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.299805, 0.300293]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.159668, 0.160645]});
+ref.push({testName: 'precision.dot.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.399414, 0.400391]});
+ref.push({testName: 'precision.dot.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.dot.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.0799561, 0.0802002]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.119873, 0.120361]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.299805, 0.300293]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.159668, 0.160645]});
+ref.push({testName: 'precision.dot.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.399414, 0.400391]});
+ref.push({testName: 'precision.dot.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.dot.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.dot.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.08, 0.08]});
+ref.push({testName: 'precision.dot.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.dot.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.12, 0.12]});
+ref.push({testName: 'precision.dot.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.3, 0.3]});
+ref.push({testName: 'precision.dot.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.16, 0.16]});
+ref.push({testName: 'precision.dot.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.dot.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.dot.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.dot.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.08, 0.08]});
+ref.push({testName: 'precision.dot.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.2, 0.2]});
+ref.push({testName: 'precision.dot.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.12, 0.12]});
+ref.push({testName: 'precision.dot.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.3, 0.3]});
+ref.push({testName: 'precision.dot.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.16, 0.16]});
+ref.push({testName: 'precision.dot.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.4, 0.4]});
+ref.push({testName: 'precision.cross.lowp_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.015625, 0.015625, false, -0.015625, 0.015625, false, -0.015625, 0.015625]});
+ref.push({testName: 'precision.cross.lowp_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.cross.lowp_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.015625, 0.015625, false, -0.015625, 0.015625, false, -0.015625, 0.015625]});
+ref.push({testName: 'precision.cross.lowp_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125, false, -0.0078125, 0.0078125]});
+ref.push({testName: 'precision.cross.mediump_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207]});
+ref.push({testName: 'precision.cross.mediump_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207]});
+ref.push({testName: 'precision.cross.mediump_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207]});
+ref.push({testName: 'precision.cross.mediump_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207, false, -0.00012207, 0.00012207]});
+ref.push({testName: 'precision.cross.highp_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -3.72529e-009, 3.72529e-009, false, -3.72529e-009, 3.72529e-009, false, -3.72529e-009, 3.72529e-009]});
+ref.push({testName: 'precision.cross.highp_vertex', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.cross.highp_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, -3.72529e-009, 3.72529e-009, false, -3.72529e-009, 3.72529e-009, false, -3.72529e-009, 3.72529e-009]});
+ref.push({testName: 'precision.cross.highp_fragment', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.normalize.lowp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.lowp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.normalize.mediump_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 0.989926, 1.01235]});
+ref.push({testName: 'precision.normalize.mediump_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 0.990765, 1.00929]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.699031, 0.71508, false, 0.699031, 0.71508]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.700293, 0.713965, false, 0.700293, 0.713965]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.570329, 0.584282, false, 0.570329, 0.584282, false, 0.570329, 0.584282]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.571344, 0.583388, false, 0.571344, 0.583388, false, 0.571344, 0.583388]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.494586, 0.506559, false, 0.494586, 0.506559, false, 0.494586, 0.506559, false, 0.494586, 0.506559]});
+ref.push({testName: 'precision.normalize.mediump_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.495383, 0.504646, false, 0.495383, 0.504646, false, 0.495383, 0.504646, false, 0.495383, 0.504646]});
+ref.push({testName: 'precision.normalize.mediump_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 0.989926, 1.01235]});
+ref.push({testName: 'precision.normalize.mediump_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 0.990765, 1.00929]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.699031, 0.71508, false, 0.699031, 0.71508]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.700293, 0.713965, false, 0.700293, 0.713965]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.570329, 0.584282, false, 0.570329, 0.584282, false, 0.570329, 0.584282]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.571344, 0.583388, false, 0.571344, 0.583388, false, 0.571344, 0.583388]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.494586, 0.506559, false, 0.494586, 0.506559, false, 0.494586, 0.506559, false, 0.494586, 0.506559]});
+ref.push({testName: 'precision.normalize.mediump_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.495383, 0.504646, false, 0.495383, 0.504646, false, 0.495383, 0.504646, false, 0.495383, 0.504646]});
+ref.push({testName: 'precision.normalize.highp_vertex.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.normalize.highp_vertex.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.707106, 0.707107, false, 0.707106, 0.707107]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707106, 0.707107, false, 0.707106, 0.707107]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.57735, 0.577351, false, 0.57735, 0.577351, false, 0.57735, 0.577351]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.57735, 0.577351, false, 0.57735, 0.577351, false, 0.57735, 0.577351]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.normalize.highp_vertex.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.normalize.highp_fragment.scalar', input: '0.2, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.normalize.highp_fragment.scalar', input: '0.5, (), (), ()', reference: [false, 1, 1]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec2', input: 'vec2(0.2, 0.2), (), (), ()', reference: [false, 0.707106, 0.707107, false, 0.707106, 0.707107]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec2', input: 'vec2(0.5, 0.5), (), (), ()', reference: [false, 0.707106, 0.707107, false, 0.707106, 0.707107]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.57735, 0.577351, false, 0.57735, 0.577351, false, 0.57735, 0.577351]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec3', input: 'vec3(0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.57735, 0.577351, false, 0.57735, 0.577351, false, 0.57735, 0.577351]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.normalize.highp_fragment.vec4', input: 'vec4(0.5, 0.5, 0.5, 0.5), (), (), ()', reference: [false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5, false, 0.5, 0.5]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313, false, -0.203125, -0.195313]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951, false, -0.200195, -0.199951]});
+ref.push({testName: 'precision.faceforward.highp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), vec2(0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.faceforward.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.reflect.lowp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.164063, 0.203125]});
+ref.push({testName: 'precision.reflect.lowp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0859375, 0.109375]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.148438, 0.1875, false, 0.148438, 0.1875]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.0078125, 0.015625, false, -0.0078125, 0.015625]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.132813, 0.171875, false, 0.132813, 0.171875, false, 0.132813, 0.171875]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.117188, -0.078125, false, -0.117188, -0.078125, false, -0.117188, -0.078125]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.117188, 0.15625, false, 0.117188, 0.15625, false, 0.117188, 0.15625, false, 0.117188, 0.15625]});
+ref.push({testName: 'precision.reflect.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.210938, -0.171875, false, -0.210938, -0.171875, false, -0.210938, -0.171875, false, -0.210938, -0.171875]});
+ref.push({testName: 'precision.reflect.lowp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.164063, 0.203125]});
+ref.push({testName: 'precision.reflect.lowp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0859375, 0.109375]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.148438, 0.1875, false, 0.148438, 0.1875]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.0078125, 0.015625, false, -0.0078125, 0.015625]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.132813, 0.171875, false, 0.132813, 0.171875, false, 0.132813, 0.171875]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.117188, -0.078125, false, -0.117188, -0.078125, false, -0.117188, -0.078125]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.117188, 0.15625, false, 0.117188, 0.15625, false, 0.117188, 0.15625, false, 0.117188, 0.15625]});
+ref.push({testName: 'precision.reflect.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.210938, -0.171875, false, -0.210938, -0.171875, false, -0.210938, -0.171875, false, -0.210938, -0.171875]});
+ref.push({testName: 'precision.reflect.mediump_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.183838, 0.184326]});
+ref.push({testName: 'precision.reflect.mediump_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0998535, 0.10022]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.167725, 0.168457, false, 0.167725, 0.168457]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.151611, 0.152344, false, 0.151611, 0.152344, false, 0.151611, 0.152344]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.100342, -0.0996094, false, -0.100342, -0.0996094, false, -0.100342, -0.0996094]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.135498, 0.136475, false, 0.135498, 0.136475, false, 0.135498, 0.136475, false, 0.135498, 0.136475]});
+ref.push({testName: 'precision.reflect.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.200439, -0.199219, false, -0.200439, -0.199219, false, -0.200439, -0.199219, false, -0.200439, -0.199219]});
+ref.push({testName: 'precision.reflect.mediump_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.183838, 0.184326]});
+ref.push({testName: 'precision.reflect.mediump_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.0998535, 0.10022]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.167725, 0.168457, false, 0.167725, 0.168457]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, -0.000244141, 0.000244141, false, -0.000244141, 0.000244141]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.151611, 0.152344, false, 0.151611, 0.152344, false, 0.151611, 0.152344]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.100342, -0.0996094, false, -0.100342, -0.0996094, false, -0.100342, -0.0996094]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.135498, 0.136475, false, 0.135498, 0.136475, false, 0.135498, 0.136475, false, 0.135498, 0.136475]});
+ref.push({testName: 'precision.reflect.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.200439, -0.199219, false, -0.200439, -0.199219, false, -0.200439, -0.199219, false, -0.200439, -0.199219]});
+ref.push({testName: 'precision.reflect.highp_vertex.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.184, 0.184]});
+ref.push({testName: 'precision.reflect.highp_vertex.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.168, 0.168, false, 0.168, 0.168]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.152, 0.152, false, 0.152, 0.152, false, 0.152, 0.152]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.1, -0.1, false, -0.1, -0.1, false, -0.1, -0.1]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.136, 0.136, false, 0.136, 0.136, false, 0.136, 0.136, false, 0.136, 0.136]});
+ref.push({testName: 'precision.reflect.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.reflect.highp_fragment.scalar', input: '0.2, 0.2, (), ()', reference: [false, 0.184, 0.184]});
+ref.push({testName: 'precision.reflect.highp_fragment.scalar', input: '0.2, 0.5, (), ()', reference: [false, 0.1, 0.1]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.168, 0.168, false, 0.168, 0.168]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.152, 0.152, false, 0.152, 0.152, false, 0.152, 0.152]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, -0.1, -0.1, false, -0.1, -0.1, false, -0.1, -0.1]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.136, 0.136, false, 0.136, 0.136, false, 0.136, 0.136, false, 0.136, 0.136]});
+ref.push({testName: 'precision.reflect.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2, false, -0.2, -0.2]});
+ref.push({testName: 'precision.refract.lowp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.lowp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.refract.mediump_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.159424, -0.155762]});
+ref.push({testName: 'precision.refract.mediump_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.0787354, -0.0756836]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -0.161377, -0.157471, false, -0.161377, -0.157471]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -0.0828857, -0.079834, false, -0.0828857, -0.079834]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.162842, -0.158936, false, -0.162842, -0.158936, false, -0.162842, -0.158936]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0872803, -0.0842285, false, -0.0872803, -0.0842285, false, -0.0872803, -0.0842285]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.164551, -0.1604, false, -0.164551, -0.1604, false, -0.164551, -0.1604, false, -0.164551, -0.1604]});
+ref.push({testName: 'precision.refract.mediump_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789]});
+ref.push({testName: 'precision.refract.mediump_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.159424, -0.155762]});
+ref.push({testName: 'precision.refract.mediump_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.0787354, -0.0756836]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -0.161377, -0.157471, false, -0.161377, -0.157471]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -0.0828857, -0.079834, false, -0.0828857, -0.079834]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.162842, -0.158936, false, -0.162842, -0.158936, false, -0.162842, -0.158936]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0872803, -0.0842285, false, -0.0872803, -0.0842285, false, -0.0872803, -0.0842285]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.164551, -0.1604, false, -0.164551, -0.1604, false, -0.164551, -0.1604, false, -0.164551, -0.1604]});
+ref.push({testName: 'precision.refract.mediump_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789, false, -0.0914307, -0.0883789]});
+ref.push({testName: 'precision.refract.highp_vertex.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.157566, -0.157566]});
+ref.push({testName: 'precision.refract.highp_vertex.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.0772513, -0.0772512]});
+ref.push({testName: 'precision.refract.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -0.159185, -0.159185, false, -0.159185, -0.159185]});
+ref.push({testName: 'precision.refract.highp_vertex.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -0.0813898, -0.0813897, false, -0.0813898, -0.0813897]});
+ref.push({testName: 'precision.refract.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.160818, -0.160818, false, -0.160818, -0.160818, false, -0.160818, -0.160818]});
+ref.push({testName: 'precision.refract.highp_vertex.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0856203, -0.0856202, false, -0.0856203, -0.0856202, false, -0.0856203, -0.0856202]});
+ref.push({testName: 'precision.refract.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.162464, -0.162464, false, -0.162464, -0.162464, false, -0.162464, -0.162464, false, -0.162464, -0.162464]});
+ref.push({testName: 'precision.refract.highp_vertex.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425]});
+ref.push({testName: 'precision.refract.highp_fragment.scalar', input: '0.2, 0.2, 0.2, ()', reference: [false, -0.157566, -0.157566]});
+ref.push({testName: 'precision.refract.highp_fragment.scalar', input: '0.2, 0.2, 0.5, ()', reference: [false, -0.0772513, -0.0772512]});
+ref.push({testName: 'precision.refract.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.2, ()', reference: [false, -0.159185, -0.159185, false, -0.159185, -0.159185]});
+ref.push({testName: 'precision.refract.highp_fragment.vec2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), 0.5, ()', reference: [false, -0.0813898, -0.0813897, false, -0.0813898, -0.0813897]});
+ref.push({testName: 'precision.refract.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.160818, -0.160818, false, -0.160818, -0.160818, false, -0.160818, -0.160818]});
+ref.push({testName: 'precision.refract.highp_fragment.vec3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0856203, -0.0856202, false, -0.0856203, -0.0856202, false, -0.0856203, -0.0856202]});
+ref.push({testName: 'precision.refract.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.2, ()', reference: [false, -0.162464, -0.162464, false, -0.162464, -0.162464, false, -0.162464, -0.162464, false, -0.162464, -0.162464]});
+ref.push({testName: 'precision.refract.highp_fragment.vec4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), 0.5, ()', reference: [false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425, false, -0.0899426, -0.0899425]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.matrixcompmult.lowp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.matrixcompmult.mediump_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.2, 0), vec2(0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), mat2(vec2(0.5, 0), vec2(0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2x3', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat2x4', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3x2', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat3x4', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4x2', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4x3', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), ()', reference: [false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.04, 0.04]});
+ref.push({testName: 'precision.matrixcompmult.highp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), ()', reference: [false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875, false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.outerproduct.lowp_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563, false, 0.09375, 0.101563]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001, false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.outerproduct.mediump_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098, false, 0.0999756, 0.100098]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_vertex.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2', input: 'vec2(0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2x3', input: 'vec3(0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat2x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec2(0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3x2', input: 'vec2(0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3', input: 'vec3(0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat3x4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec3(0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4x2', input: 'vec2(0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4x3', input: 'vec3(0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.2, 0.2, 0.2, 0.2), (), ()', reference: [false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04, false, 0.04, 0.04]});
+ref.push({testName: 'precision.outerproduct.highp_fragment.mat4', input: 'vec4(0.2, 0.2, 0.2, 0.2), vec4(0.5, 0.5, 0.5, 0.5), (), ()', reference: [false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1, false, 0.1, 0.1]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_vertex.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.195313, 0.203125]});
+ref.push({testName: 'precision.transpose.lowp_fragment.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_vertex.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.199951, 0.200195]});
+ref.push({testName: 'precision.transpose.mediump_fragment.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_vertex.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2x3', input: 'mat3x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2x3', input: 'mat3x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2x4', input: 'mat4x2(vec2(0.2, 0), vec2(0, 0.2), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat2x4', input: 'mat4x2(vec2(0.5, 0), vec2(0, 0.5), vec2(0, 0), vec2(0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3x2', input: 'mat2x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3x2', input: 'mat2x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3', input: 'mat3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3', input: 'mat3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3x4', input: 'mat4x3(vec3(0.2, 0, 0), vec3(0, 0.2, 0), vec3(0, 0, 0.2), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat3x4', input: 'mat4x3(vec3(0.5, 0, 0), vec3(0, 0.5, 0), vec3(0, 0, 0.5), vec3(0, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4x2', input: 'mat2x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4x2', input: 'mat2x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4x3', input: 'mat3x4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4x3', input: 'mat3x4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4', input: 'mat4(vec4(0.2, 0, 0, 0), vec4(0, 0.2, 0, 0), vec4(0, 0, 0.2, 0), vec4(0, 0, 0, 0.2)), (), (), ()', reference: [false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.2, 0.2]});
+ref.push({testName: 'precision.transpose.highp_fragment.mat4', input: 'mat4(vec4(0.5, 0, 0, 0), vec4(0, 0.5, 0, 0), vec4(0, 0, 0.5, 0), vec4(0, 0, 0, 0.5)), (), (), ()', reference: [false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5, false, 0, 0, false, 0, 0, false, 0, 0, false, 0, 0, false, 0.5, 0.5]});
+ref.push({testName: 'precision.determinant.lowp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.determinant.lowp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.determinant.lowp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.03125, 0.046875]});
+ref.push({testName: 'precision.determinant.lowp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.determinant.mediump_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.determinant.mediump_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.determinant.mediump_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.039978, 0.0401001]});
+ref.push({testName: 'precision.determinant.mediump_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.determinant.highp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.determinant.highp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.determinant.highp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 0.04, 0.04]});
+ref.push({testName: 'precision.determinant.highp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 0.25, 0.25]});
+ref.push({testName: 'precision.inverse.lowp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.inverse.lowp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.inverse.lowp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.inverse.lowp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity, false, -Infinity, Infinity]});
+ref.push({testName: 'precision.inverse.mediump_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 4.96677, 5.02716, false, -5.96046e-007, 5.96046e-007, false, -5.96046e-007, 5.96046e-007, false, 4.96677, 5.02716]});
+ref.push({testName: 'precision.inverse.mediump_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 1.99512, 2.00488, false, -5.96046e-007, 5.96046e-007, false, -5.96046e-007, 5.96046e-007, false, 1.99512, 2.00488]});
+ref.push({testName: 'precision.inverse.mediump_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 4.96677, 5.02716, false, -5.96046e-007, 5.96046e-007, false, -5.96046e-007, 5.96046e-007, false, 4.96677, 5.02716]});
+ref.push({testName: 'precision.inverse.mediump_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 1.99512, 2.00488, false, -5.96046e-007, 5.96046e-007, false, -5.96046e-007, 5.96046e-007, false, 1.99512, 2.00488]});
+ref.push({testName: 'precision.inverse.highp_vertex.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 5, 5, false, -2.8026e-045, 2.8026e-045, false, -2.8026e-045, 2.8026e-045, false, 5, 5]});
+ref.push({testName: 'precision.inverse.highp_vertex.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 2, 2, false, -2.8026e-045, 2.8026e-045, false, -2.8026e-045, 2.8026e-045, false, 2, 2]});
+ref.push({testName: 'precision.inverse.highp_fragment.mat2', input: 'mat2(vec2(0.2, 0), vec2(0, 0.2)), (), (), ()', reference: [false, 5, 5, false, -2.8026e-045, 2.8026e-045, false, -2.8026e-045, 2.8026e-045, false, 5, 5]});
+ref.push({testName: 'precision.inverse.highp_fragment.mat2', input: 'mat2(vec2(0.5, 0), vec2(0, 0.5)), (), (), ()', reference: [false, 2, 2, false, -2.8026e-045, 2.8026e-045, false, -2.8026e-045, 2.8026e-045, false, 2, 2]});
+
+ glsBuiltinPrecisionTestsUnitTests.plainArray = function(input) {
+ var ret = [];
+
+ if (input instanceof tcuInterval.Interval) {
+ var i = 0;
+ ret[i] = input.m_hasNaN;
+ i++;
+ ret[i] = input.m_lo;
+ i++;
+ ret[i] = input.m_hi;
+ return ret;
+ }
+
+ if (input instanceof tcuMatrix.Matrix) {
+ for (var i = 0, l = 0; i < input.cols; i++)
+ for (var j = 0; j < input.rows; j++, l++) {
+ ret[l] = input.matrix[i][j].m_hasNaN;
+ l++;
+ ret[l] = input.matrix[i][j].m_lo;
+ l++;
+ ret[l] = input.matrix[i][j].m_hi;
+ }
+ return ret;
+ }
+
+ if (input instanceof Array) {
+ var size = input.length;
+ for (var i = 0, j = 0; j < size; j++, i++) {
+ ret[i] = input[j].m_hasNaN;
+ i++;
+ ret[i] = input[j].m_lo;
+ i++;
+ ret[i] = input[j].m_hi;
+ }
+ return ret;
+ }
+ return ret;
+ };
+
+ glsBuiltinPrecisionTestsUnitTests.Compare = function(num1, num2, diff) {
+ if (isFinite(num1))
+ if (Math.abs(Math.abs(num1) - Math.abs(num2)) <= diff)
+ return true;
+ else
+ return false;
+ else
+ if (isFinite(num2))
+ return false;
+ else
+ return true;
+ };
+
+ glsBuiltinPrecisionTestsUnitTests.referenceComparison = function(reference, index, precision) {
+ if (index > 1)
+ return true;
+
+ var testName = _currentTestName;
+ var message1 = '';
+ var ref1 = glsBuiltinPrecisionTestsUnitTests.plainArray(reference);
+ var a = ref.length;
+ var len;
+ var ref_len = ref1.length;
+ var cpp_nan;
+ var ref_nan;
+ var ref_lo;
+ var ref_hi;
+ var cpp_lo;
+ var cpp_hi;
+ var str;
+ var retVal1;
+ var retVal2;
+ var varfix = Math.max(0.0001, precision.ulp(0, 2));
+ var error = false;
+
+ for (var i = 0; i < a; i++) {
+ str = ref[i].testName;
+
+ if (testName == str) {
+ len = ref[i].reference.length;
+
+ if (len != ref_len)
+ return false;
+
+ for (var j = 0; j < len; j++) {
+ cpp_nan = ref[i + index].reference[j];
+ ref_nan = ref1[j];
+ j++;
+ cpp_lo = ref[i + index].reference[j];
+ ref_lo = ref1[j];
+ j++;
+ cpp_hi = ref[i + index].reference[j];
+ ref_hi = ref1[j];
+
+ if (ref_nan == cpp_nan) {
+ retVal1 = glsBuiltinPrecisionTestsUnitTests.Compare(ref_lo, cpp_lo, varfix);
+ retVal2 = glsBuiltinPrecisionTestsUnitTests.Compare(ref_hi, ref_hi, varfix);
+
+ if ((retVal1 != true) || (retVal2 != true)) {
+ message1 = 'Error: ' + varfix;
+ bufferedLogToConsole(message1);
+ message1 = 'C++ Reference values: ' + cpp_nan + ', ' + cpp_lo + ', ' + cpp_hi;
+ bufferedLogToConsole(message1);
+ message1 = 'JS values: ' + ref_nan + ', ' + ref_lo + ', ' + ref_hi;
+ bufferedLogToConsole(message1);
+ error = true;
+ }
+ }
+ }
+ if (error)
+ return false;
+ else
+ return true;
+ }
+ }
+ return true;
+ };
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsDrawTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsDrawTests.js
new file mode 100644
index 000000000..eb7a4b293
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsDrawTests.js
@@ -0,0 +1,3452 @@
+/*-------------------------------------------------------------------------
+ * 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.glsDrawTests');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluStrUtil');
+goog.require('framework.opengl.simplereference.sglrGLContext');
+goog.require('framework.opengl.simplereference.sglrReferenceContext');
+goog.require('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.referencerenderer.rrFragmentOperations');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrShadingContext');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+goog.require('framework.referencerenderer.rrVertexPacket');
+
+goog.scope(function() {
+
+ var glsDrawTests = modules.shared.glsDrawTests;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuRGBA = framework.common.tcuRGBA;
+ var tcuFloat = framework.common.tcuFloat;
+ var tcuPixelFormat = framework.common.tcuPixelFormat;
+ var tcuSurface = framework.common.tcuSurface;
+ var tcuImageCompare = framework.common.tcuImageCompare;
+ var tcuTextureUtil = framework.common.tcuTextureUtil;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var gluStrUtil = framework.opengl.gluStrUtil;
+ var sglrGLContext = framework.opengl.simplereference.sglrGLContext;
+ var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext;
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var deMath = framework.delibs.debase.deMath;
+ var deRandom = framework.delibs.debase.deRandom;
+ var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var rrShadingContext = framework.referencerenderer.rrShadingContext;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrVertexPacket = framework.referencerenderer.rrVertexPacket;
+
+ /** @const {number} */ glsDrawTests.MAX_RENDER_TARGET_SIZE = 512;
+
+ // Utils
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Target} target
+ * @return {number}
+ */
+ glsDrawTests.targetToGL = function(target) {
+ assertMsgOptions(target != null, 'Target is null', false, true);
+
+ var targets = [
+ gl.ELEMENT_ARRAY_BUFFER, // TARGET_ELEMENT_ARRAY = 0,
+ gl.ARRAY_BUFFER // TARGET_ARRAY,
+ ];
+
+ return targets[target];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Usage} usage
+ * @return {number}
+ */
+ glsDrawTests.usageToGL = function(usage) {
+ assertMsgOptions(usage != null, 'Usage is null', false, true);
+
+ var usages = [
+ gl.DYNAMIC_DRAW, // USAGE_DYNAMIC_DRAW = 0,
+ gl.STATIC_DRAW, // USAGE_STATIC_DRAW,
+ gl.STREAM_DRAW, // USAGE_STREAM_DRAW,
+
+ gl.STREAM_READ, // USAGE_STREAM_READ,
+ gl.STREAM_COPY, // USAGE_STREAM_COPY,
+
+ gl.STATIC_READ, // USAGE_STATIC_READ,
+ gl.STATIC_COPY, // USAGE_STATIC_COPY,
+
+ gl.DYNAMIC_READ, // USAGE_DYNAMIC_READ,
+ gl.DYNAMIC_COPY // USAGE_DYNAMIC_COPY,
+ ];
+ assertMsgOptions(usages.length == Object.keys(glsDrawTests.DrawTestSpec.Usage).length,
+ 'Amount of usage gl vlaues is different from amount of usages', false, true);
+
+ return usages[usage];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {number}
+ */
+ glsDrawTests.inputTypeToGL = function(type) {
+ assertMsgOptions(type != null, 'Input type is null', false, true);
+
+ var types = [
+ gl.FLOAT, // INPUTTYPE_FLOAT = 0,
+ gl.BYTE, // INPUTTYPE_BYTE,
+ gl.SHORT, // INPUTTYPE_SHORT,
+ gl.UNSIGNED_BYTE, // INPUTTYPE_UNSIGNED_BYTE,
+ gl.UNSIGNED_SHORT, // INPUTTYPE_UNSIGNED_SHORT,
+
+ gl.INT, // INPUTTYPE_INT,
+ gl.UNSIGNED_INT, // INPUTTYPE_UNSIGNED_INT,
+ gl.HALF_FLOAT, // INPUTTYPE_HALF,
+ gl.UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
+ gl.INT_2_10_10_10_REV // INPUTTYPE_INT_2_10_10_10,
+ ];
+ assertMsgOptions(types.length == Object.keys(glsDrawTests.DrawTestSpec.InputType).length,
+ 'Amount of gl input types is different from amount of input types', false, true);
+
+ return types[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {string}
+ */
+ glsDrawTests.outputTypeToGLType = function(type) {
+ assertMsgOptions(type != null, 'Output type is null', false, true);
+
+ var types = [
+ 'float', // OUTPUTTYPE_FLOAT = 0,
+ 'vec2', // OUTPUTTYPE_VEC2,
+ 'vec3', // OUTPUTTYPE_VEC3,
+ 'vec4', // OUTPUTTYPE_VEC4,
+
+ 'int', // OUTPUTTYPE_INT,
+ 'uint', // OUTPUTTYPE_UINT,
+
+ 'ivec2', // OUTPUTTYPE_IVEC2,
+ 'ivec3', // OUTPUTTYPE_IVEC3,
+ 'ivec4', // OUTPUTTYPE_IVEC4,
+
+ 'uvec2', // OUTPUTTYPE_UVEC2,
+ 'uvec3', // OUTPUTTYPE_UVEC3,
+ 'uvec4' // OUTPUTTYPE_UVEC4,
+ ];
+ assertMsgOptions(types.length == Object.keys(glsDrawTests.DrawTestSpec.OutputType).length,
+ 'Amount of output type names is different than amount of output types', false, true);
+
+ return types[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitive
+ * @return {number}
+ */
+ glsDrawTests.primitiveToGL = function(primitive) {
+ var primitives = [
+ gl.POINTS, // PRIMITIVE_POINTS = 0,
+ gl.TRIANGLES, // PRIMITIVE_TRIANGLES,
+ gl.TRIANGLE_FAN, // PRIMITIVE_TRIANGLE_FAN,
+ gl.TRIANGLE_STRIP, // PRIMITIVE_TRIANGLE_STRIP,
+ gl.LINES, // PRIMITIVE_LINES
+ gl.LINE_STRIP, // PRIMITIVE_LINE_STRIP
+ gl.LINE_LOOP
+ ];
+ assertMsgOptions(primitives.length == Object.keys(glsDrawTests.DrawTestSpec.Primitive).length,
+ 'Amount of gl primitive values is different than amount of primitives', false, true);
+
+ return primitives[primitive];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} indexType
+ * @return {number}
+ */
+ glsDrawTests.indexTypeToGL = function(indexType) {
+ var indexTypes = [
+ gl.UNSIGNED_BYTE, // INDEXTYPE_BYTE = 0,
+ gl.UNSIGNED_SHORT, // INDEXTYPE_SHORT,
+ gl.UNSIGNED_INT // INDEXTYPE_INT,
+ ];
+ assertMsgOptions(indexTypes.length == Object.keys(glsDrawTests.DrawTestSpec.IndexType).length,
+ 'Amount of gl index types is different than amount of index types', false, true);
+
+ return indexTypes[indexType];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} indexType
+ * @return {?glsDrawTests.DrawTestSpec.InputType}
+ */
+ glsDrawTests.indexTypeToInputType = function(indexType) {
+ var inputTypes = [
+ glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE, // INDEXTYPE_BYTE = 0,
+ glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT, // INDEXTYPE_SHORT,
+ glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT // INDEXTYPE_INT,
+ ];
+ assertMsgOptions(inputTypes.length == Object.keys(glsDrawTests.DrawTestSpec.IndexType).length,
+ 'Amount of relevant input types is different than amount of index types', false, true);
+
+ return inputTypes[indexType];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {boolean}
+ */
+ glsDrawTests.inputTypeIsFloatType = function(type) {
+ if (type == glsDrawTests.DrawTestSpec.InputType.FLOAT)
+ return true;
+ if (type == glsDrawTests.DrawTestSpec.InputType.HALF)
+ return true;
+ return false;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {boolean}
+ */
+ glsDrawTests.outputTypeIsFloatType = function(type) {
+ if (type == glsDrawTests.DrawTestSpec.OutputType.FLOAT ||
+ type == glsDrawTests.DrawTestSpec.OutputType.VEC2 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.VEC3 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.VEC4)
+ return true;
+
+ return false;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {boolean}
+ */
+ glsDrawTests.outputTypeIsIntType = function(type) {
+ if (type == glsDrawTests.DrawTestSpec.OutputType.INT ||
+ type == glsDrawTests.DrawTestSpec.OutputType.IVEC2 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.IVEC3 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.IVEC4)
+ return true;
+
+ return false;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {boolean}
+ */
+ glsDrawTests.outputTypeIsUintType = function(type) {
+ if (type == glsDrawTests.DrawTestSpec.OutputType.UINT ||
+ type == glsDrawTests.DrawTestSpec.OutputType.UVEC2 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.UVEC3 ||
+ type == glsDrawTests.DrawTestSpec.OutputType.UVEC4)
+ return true;
+
+ return false;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitive
+ * @param {number} primitiveCount
+ * @return {number}
+ */
+ glsDrawTests.getElementCount = function(primitive, primitiveCount) {
+ switch (primitive) {
+ case glsDrawTests.DrawTestSpec.Primitive.POINTS: return primitiveCount;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLES: return primitiveCount * 3;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_FAN: return primitiveCount + 2;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_STRIP: return primitiveCount + 2;
+ case glsDrawTests.DrawTestSpec.Primitive.LINES: return primitiveCount * 2;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_STRIP: return primitiveCount + 1;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_LOOP: return (primitiveCount == 1) ? (2) : (primitiveCount);
+ default:
+ throw new Error('Invalid primitive');
+ }
+ };
+
+ //MethodInfo
+
+ /**
+ * @typedef {{indexed: boolean, instanced: boolean, ranged: boolean, first: boolean}}
+ */
+ glsDrawTests.MethodInfo = {
+ /** @type {boolean} */ indexed: false,
+ /** @type {boolean} */ instanced: false,
+ /** @type {boolean} */ ranged: false,
+ /** @type {boolean} */ first: false
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.DrawMethod} method
+ * @return {glsDrawTests.MethodInfo}
+ */
+ glsDrawTests.getMethodInfo = function(method) {
+ /** @type {Array<glsDrawTests.MethodInfo>} */ var infos = [{
+ indexed: false, instanced: false, ranged: false, first: true //!< DRAWMETHOD_DRAWARRAYS,
+ },{
+ indexed: false, instanced: true, ranged: false, first: true //!< DRAWMETHOD_DRAWARRAYS_INSTANCED,
+ },{
+ indexed: true, instanced: false, ranged: false, first: false //!< DRAWMETHOD_DRAWELEMENTS,
+ },{
+ indexed: true, instanced: false, ranged: true, first: false //!< DRAWMETHOD_DRAWELEMENTS_RANGED,
+ },{
+ indexed: true, instanced: true, ranged: false, first: false //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
+ }
+ ];
+
+ assertMsgOptions(infos.length == Object.keys(glsDrawTests.DrawTestSpec.DrawMethod).length,
+ 'Number of info names', false, true);
+ assertMsgOptions(method < infos.length, 'Invalid method', false, true);
+ return /** @type {glsDrawTests.MethodInfo} */ (infos[method]);
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec} a
+ * @param {glsDrawTests.DrawTestSpec} b
+ * @return {boolean}
+ */
+ glsDrawTests.checkSpecsShaderCompatible = function(a, b) {
+ // Only the attributes matter
+ if (a.attribs.length != b.attribs.length)
+ return false;
+
+ for (var ndx = 0; ndx < a.attribs.length; ++ndx) {
+ // Only the output type (== shader input type) matters and the usage in the shader.
+
+ if (a.attribs[ndx].additionalPositionAttribute != b.attribs[ndx].additionalPositionAttribute)
+ return false;
+
+ // component counts need not to match
+ if (glsDrawTests.outputTypeIsFloatType(a.attribs[ndx].outputType) && glsDrawTests.outputTypeIsFloatType(b.attribs[ndx].outputType))
+ continue;
+ if (glsDrawTests.outputTypeIsIntType(a.attribs[ndx].outputType) && glsDrawTests.outputTypeIsIntType(b.attribs[ndx].outputType))
+ continue;
+ if (glsDrawTests.outputTypeIsUintType(a.attribs[ndx].outputType) && glsDrawTests.outputTypeIsUintType(b.attribs[ndx].outputType))
+ continue;
+
+ return false;
+ }
+
+ return true;
+ };
+
+ // generate random vectors in a way that does not depend on argument evaluation order
+
+ /**
+ * @param {deRandom.Random} random
+ * @return {Array<number>}
+ */
+ glsDrawTests.generateRandomVec4 = function(random) {
+ /** @type {Array<number>} */ var retVal = [];
+
+ for (var i = 0; i < 4; ++i)
+ retVal[i] = random.getFloat();
+
+ return retVal;
+ };
+
+ /**
+ * @param {deRandom.Random} random
+ * @return {Array<number>}
+ */
+ glsDrawTests.generateRandomIVec4 = function(random) {
+ /** @type {Array<number>} */ var retVal = [];
+
+ for (var i = 0; i < 4; ++i)
+ retVal[i] = random.getInt();
+
+ return retVal;
+ };
+
+ /**
+ * @param {deRandom.Random} random
+ * @return {Array<number>}
+ */
+ glsDrawTests.generateRandomUVec4 = function(random) {
+ /** @type {Array<number>} */ var retVal = [];
+
+ for (var i = 0; i < 4; ++i)
+ retVal[i] = Math.abs(random.getInt());
+
+ return retVal;
+ };
+
+ //GLValue
+
+ /**
+ * glsDrawTests.GLValue class
+ * @constructor
+ */
+ glsDrawTests.GLValue = function() {
+ /** @type {goog.NumberArray} */ this.m_value = [0];
+ /** @type {?glsDrawTests.DrawTestSpec.InputType} */ this.m_type;
+ };
+
+ /**
+ * @param {goog.TypedArray} dst
+ * @param {glsDrawTests.GLValue} val
+ */
+ glsDrawTests.copyGLValueToArray = function(dst, val) {
+ /** @type {Uint8Array} */ var dst8 = new Uint8Array(dst.buffer).subarray(dst.byteOffset, dst.byteOffset + dst.byteLength);
+ /** @type {Uint8Array} */ var val8 = new Uint8Array(val.m_value.buffer); // TODO: Fix encapsulation issue
+ dst8.set(val8);
+ };
+
+ /**
+ * @param {goog.TypedArray} dst
+ * @param {goog.TypedArray} src
+ */
+ glsDrawTests.copyArray = function(dst, src) {
+ /** @type {Uint8Array} */ var dst8 = new Uint8Array(dst.buffer).subarray(dst.byteOffset, dst.byteOffset + dst.byteLength);
+ /** @type {Uint8Array} */ var src8 = new Uint8Array(src.buffer).subarray(src.byteOffset, src.byteOffset + src.byteLength);
+ dst8.set(src8);
+ };
+
+ /**
+ * typeToTypedArray function. Determines which type of array will store the value, and stores it.
+ * @param {number} value
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ */
+ glsDrawTests.GLValue.typeToTypedArray = function(value, type) {
+ var array;
+
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ array = new Float32Array(1);
+ break;
+
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ array = new Int8Array(1);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ array = new Int16Array(1);
+ break;
+
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ array = new Uint8Array(1);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ array = new Uint16Array(1);
+ break;
+
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ array = new Int32Array(1);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ array = new Uint32Array(1);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ array = new Uint16Array(1);
+ value = glsDrawTests.GLValue.floatToHalf(value);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10:
+ array = new Uint32Array(1);
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10:
+ array = new Int32Array(1);
+ break;
+ default:
+ throw new Error('glsDrawTests.GLValue.typeToTypedArray - Invalid InputType');
+ }
+
+ array[0] = value;
+ return array;
+ };
+
+ /**
+ * glsDrawTests.GLValue.create
+ * @param {number} value
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ */
+ glsDrawTests.GLValue.create = function(value, type) {
+ var v = new glsDrawTests.GLValue();
+ v.m_value = glsDrawTests.GLValue.typeToTypedArray(value, type);
+ v.m_type = type;
+ return v;
+ };
+
+ /**
+ * glsDrawTests.GLValue.halfToFloat
+ * @param {number} value
+ * @return {number}
+ */
+ glsDrawTests.GLValue.halfToFloat = function(value) {
+ return tcuFloat.halfFloatToNumberNoDenorm(value);
+ };
+
+ /**
+ * @param {number} f
+ * @return {number}
+ */
+ glsDrawTests.GLValue.floatToHalf = function(f) {
+ // No denorm support.
+ return tcuFloat.numberToHalfFloatNoDenorm(f);
+ };
+
+ /**
+ * glsDrawTests.GLValue.getMaxValue
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.getMaxValue = function(type) {
+ var value = 0;
+
+ assertMsgOptions(type >= 0 && type < Object.keys(glsDrawTests.DrawTestSpec.InputType).length,
+ 'Invalid type for GLValue', false, true);
+
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ value = 127;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ value = 127;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ value = 32760;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ value = 255;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ value = 65530;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ value = 2147483647;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ value = 4294967295;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ value = 256;
+ break;
+ default: //For any other valid type, return 0
+ value = 0;
+ }
+
+ return glsDrawTests.GLValue.create(value, type);
+ };
+
+ /**
+ * glsDrawTests.GLValue.getMinValue
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.getMinValue = function(type) {
+ var value = 0;
+
+ assertMsgOptions(type >= 0 && type < Object.keys(glsDrawTests.DrawTestSpec.InputType).length,
+ 'Invalid type for GLValue', false, true);
+
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ value = -127;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ value = -127;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ value = -32760;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ value = 0;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ value = 0;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ value = -2147483647;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ value = 0;
+ break;
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ value = -256;
+ break;
+ default: //For any other valid type, return 0
+ value = 0;
+ }
+
+ return glsDrawTests.GLValue.create(value, type);
+ };
+
+ /**
+ * glsDrawTests.GLValue.getRandom
+ * @param {deRandom.Random} rnd
+ * @param {glsDrawTests.GLValue} min
+ * @param {glsDrawTests.GLValue} max
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.getRandom = function(rnd, min, max) {
+ assertMsgOptions(min.getType() == max.getType(), 'Min and max types differ', false, true);
+
+ var minv = min.interpret();
+ var maxv = max.interpret();
+ var type = min.getType();
+ var value;
+
+ if (maxv < minv)
+ return min;
+
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.InputType.HALF: {
+ return glsDrawTests.GLValue.create(minv + rnd.getFloat() * (maxv - minv), type);
+ break;
+ }
+
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT: {
+ return glsDrawTests.GLValue.create(minv + rnd.getInt() % (maxv - minv), type);
+ break;
+ }
+
+ default:
+ throw new Error('glsDrawTests.GLValue.getRandom - Invalid input type');
+ break;
+ }
+ };
+
+ // Minimum difference required between coordinates
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.minValue = function(type) {
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ return glsDrawTests.GLValue.create(4, type);
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ return glsDrawTests.GLValue.create(4 * 256, type);
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ return glsDrawTests.GLValue.create(4 * 2, type);
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ return glsDrawTests.GLValue.create(4 * 16777216, type);
+
+ default:
+ throw new Error('glsDrawTests.GLValue.minValue - Invalid input type');
+ }
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} val
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.abs = function(val) {
+ var type = val.getType();
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ return glsDrawTests.GLValue.create(0x7FFF & val.getValue(), type);
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ return glsDrawTests.GLValue.create(0x7F & val.getValue(), type);
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ return val;
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ return glsDrawTests.GLValue.create(Math.abs(val.interpret()), type);
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ return glsDrawTests.GLValue.create(0x7FFFFFFF & val.getValue(), type);
+ default:
+ throw new Error('glsDrawTests.GLValue.abs - Invalid input type');
+ }
+ };
+
+ /**
+ * @return {?glsDrawTests.DrawTestSpec.InputType}
+ */
+ glsDrawTests.GLValue.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /**
+ * glsDrawTests.GLValue.toFloat
+ * @return {number}
+ */
+ glsDrawTests.GLValue.prototype.toFloat = function() {
+ return this.interpret();
+ };
+
+ /**
+ * glsDrawTests.GLValue.getValue
+ * @return {number}
+ */
+ glsDrawTests.GLValue.prototype.getValue = function() {
+ return this.m_value[0];
+ };
+
+ /**
+ * interpret function. Returns the m_value as a quantity so arithmetic operations can be performed on it
+ * Only some types require this.
+ * @return {number}
+ */
+ glsDrawTests.GLValue.prototype.interpret = function() {
+ if (this.m_type == glsDrawTests.DrawTestSpec.InputType.HALF)
+ return glsDrawTests.GLValue.halfToFloat(this.m_value[0]);
+
+ return this.m_value[0];
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.add = function(other) {
+ return glsDrawTests.GLValue.create(this.interpret() + other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.mul = function(other) {
+ return glsDrawTests.GLValue.create(this.interpret() * other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.div = function(other) {
+ return glsDrawTests.GLValue.create(this.interpret() / other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.sub = function(other) {
+ return glsDrawTests.GLValue.create(this.interpret() - other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.addToSelf = function(other) {
+ this.m_value[0] = this.interpret() + other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.subToSelf = function(other) {
+ this.m_value[0] = this.interpret() - other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.mulToSelf = function(other) {
+ this.m_value[0] = this.interpret() * other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {glsDrawTests.GLValue}
+ */
+ glsDrawTests.GLValue.prototype.divToSelf = function(other) {
+ this.m_value[0] = this.interpret() / other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {boolean}
+ */
+ glsDrawTests.GLValue.prototype.equals = function(other) {
+ return this.m_value[0] == other.getValue();
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {boolean}
+ */
+ glsDrawTests.GLValue.prototype.lessThan = function(other) {
+ return this.interpret() < other.interpret();
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {boolean}
+ */
+ glsDrawTests.GLValue.prototype.greaterThan = function(other) {
+ return this.interpret() > other.interpret();
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {boolean}
+ */
+ glsDrawTests.GLValue.prototype.lessOrEqualThan = function(other) {
+ return this.interpret() <= other.interpret();
+ };
+
+ /**
+ * @param {glsDrawTests.GLValue} other
+ * @return {boolean}
+ */
+ glsDrawTests.GLValue.prototype.greaterOrEqualThan = function(other) {
+ return this.interpret() >= other.interpret();
+ };
+
+ // AttriuteArray
+
+ /**
+ * AttributeArray
+ * @constructor
+ * @param {?glsDrawTests.DrawTestSpec.Storage} storage
+ * @param {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} context
+ */
+ glsDrawTests.AttributeArray = function(storage, context) {
+ /** @type {?glsDrawTests.DrawTestSpec.Storage} */ this.m_storage = storage;
+ /** @type {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} */ this.m_ctx = context;
+ /** @type {WebGLBuffer|sglrReferenceContext.DataBuffer|null} */ this.m_glBuffer;
+
+ /** @type {number} */ this.m_size = 0;
+ /** @type {Uint8Array} */ this.m_data; //NOTE: Used in unsupported user storage
+ /** @type {number} */ this.m_componentCount;
+ /** @type {boolean} */ this.m_bound = false;
+ /** @type {glsDrawTests.DrawTestSpec.Target} */ this.m_target = glsDrawTests.DrawTestSpec.Target.ARRAY;
+ /** @type {?glsDrawTests.DrawTestSpec.InputType} */ this.m_inputType = glsDrawTests.DrawTestSpec.InputType.FLOAT;
+ /** @type {?glsDrawTests.DrawTestSpec.OutputType} */ this.m_outputType = glsDrawTests.DrawTestSpec.OutputType.VEC4;
+ /** @type {boolean} */ this.m_normalize = false;
+ /** @type {number} */ this.m_stride = 0;
+ /** @type {number} */ this.m_offset = 0;
+ /** @type {Array<number>} */ this.m_defaultAttrib;
+ /** @type {number} */ this.m_instanceDivisor = 0;
+ /** @type {boolean} */ this.m_isPositionAttr = false;
+
+ if (this.m_storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ this.m_glBuffer = this.m_ctx.createBuffer();
+ }
+ };
+
+ /** @return {number} */ glsDrawTests.AttributeArray.prototype.getComponentCount = function() {return this.m_componentCount;};
+
+ /** @return {?glsDrawTests.DrawTestSpec.Target} */ glsDrawTests.AttributeArray.prototype.getTarget = function() {return this.m_target;};
+
+ /** @return {?glsDrawTests.DrawTestSpec.InputType} */ glsDrawTests.AttributeArray.prototype.getInputType = function() {return this.m_inputType;};
+
+ /** @return {?glsDrawTests.DrawTestSpec.OutputType} */ glsDrawTests.AttributeArray.prototype.getOutputType = function() {return this.m_outputType;};
+
+ /** @return {?glsDrawTests.DrawTestSpec.Storage} */ glsDrawTests.AttributeArray.prototype.getStorageType = function() {return this.m_storage;};
+
+ /** @return {boolean} */ glsDrawTests.AttributeArray.prototype.getNormalized = function() {return this.m_normalize;};
+
+ /** @return {number} */ glsDrawTests.AttributeArray.prototype.getStride = function() {return this.m_stride;};
+
+ /** @return {boolean} */ glsDrawTests.AttributeArray.prototype.isBound = function() {return this.m_bound;};
+
+ /** @return {boolean} */ glsDrawTests.AttributeArray.prototype.isPositionAttribute = function() {return this.m_isPositionAttr;};
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Target} target
+ * @param {number} size
+ * @param {goog.TypedArray} ptr
+ * @param {?glsDrawTests.DrawTestSpec.Usage} usage
+ */
+ glsDrawTests.AttributeArray.prototype.data = function(target, size, ptr, usage) {
+ this.m_size = size;
+ this.m_target = target;
+
+ if (this.m_storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsDrawTests.targetToGL(target), this.m_glBuffer);
+ this.m_ctx.bufferData(glsDrawTests.targetToGL(target), ptr, glsDrawTests.usageToGL(usage));
+ } else
+ throw new Error('Wrong storage type');
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Target} target
+ * @param {number} offset
+ * @param {number} size
+ * @param {goog.TypedArray} ptr
+ */
+ glsDrawTests.AttributeArray.prototype.subdata = function(target, offset, size, ptr) {
+ this.m_target = target;
+
+ if (this.m_storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsDrawTests.targetToGL(target), this.m_glBuffer);
+
+ this.m_ctx.bufferSubData(glsDrawTests.targetToGL(target), offset, size, ptr);
+ } else
+ throw new Error('Wrong storage type');
+ };
+
+ /**
+ * @param {boolean} bound
+ * @param {number} offset
+ * @param {number} size
+ * @param {?glsDrawTests.DrawTestSpec.InputType} inputType
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} outType
+ * @param {boolean} normalized
+ * @param {number} stride
+ * @param {number} instanceDivisor
+ * @param {Array<number>} defaultAttrib
+ * @param {boolean} isPositionAttr
+ */
+ glsDrawTests.AttributeArray.prototype.setupArray = function(bound, offset, size, inputType, outType,
+ normalized, stride, instanceDivisor, defaultAttrib, isPositionAttr) {
+ this.m_componentCount = size;
+ this.m_bound = bound;
+ this.m_inputType = inputType;
+ this.m_outputType = outType;
+ this.m_normalize = normalized;
+ this.m_stride = stride;
+ this.m_offset = offset;
+ this.m_defaultAttrib = defaultAttrib;
+ this.m_instanceDivisor = instanceDivisor;
+ this.m_isPositionAttr = isPositionAttr;
+ };
+
+ /**
+ * @param {number} loc (32-bit)
+ */
+ glsDrawTests.AttributeArray.prototype.bindAttribute = function(loc) {
+ if (!this.isBound()) {
+ /** @type {Array<number>} */ var attr = this.m_defaultAttrib;
+ switch (this.m_inputType) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT: {
+ switch (this.m_componentCount) {
+ case 1: this.m_ctx.vertexAttrib1f(loc, attr[0]); break;
+ case 2: this.m_ctx.vertexAttrib2f(loc, attr[0], attr[1]); break;
+ case 3: this.m_ctx.vertexAttrib3f(loc, attr[0], attr[1], attr[2]); break;
+ case 4: this.m_ctx.vertexAttrib4f(loc, attr[0], attr[1], attr[2], attr[3]); break;
+ default: throw new Error('Invalid component count'); break;
+ }
+ break;
+ }
+ case glsDrawTests.DrawTestSpec.InputType.INT: {
+ this.m_ctx.vertexAttribI4i(loc, attr[0], attr[1], attr[2], attr[3]);
+ break;
+ }
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT: {
+ this.m_ctx.vertexAttribI4ui(loc, attr[0], attr[1], attr[2], attr[3]);
+ break;
+ }
+ default:
+ throw new Error('Invalid input type');
+ break;
+ }
+ } else {
+ /** @type {Uint8Array} */ var basePtr = null;
+
+ if (this.m_storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsDrawTests.targetToGL(this.m_target), this.m_glBuffer);
+
+ basePtr = null;
+ } else
+ throw new Error('Invalid storage type');
+
+ if (!glsDrawTests.inputTypeIsFloatType(this.m_inputType)) {
+ // Input is not float type
+
+ if (glsDrawTests.outputTypeIsFloatType(this.m_outputType)) {
+ var size = this.m_componentCount;
+
+ // Output type is float type
+ this.m_ctx.vertexAttribPointer(loc, size, glsDrawTests.inputTypeToGL(this.m_inputType), this.m_normalize, this.m_stride, this.m_offset);
+ } else {
+ // Output type is int type
+ this.m_ctx.vertexAttribIPointer(loc, this.m_componentCount, glsDrawTests.inputTypeToGL(this.m_inputType), this.m_stride, this.m_offset);
+ }
+ } else {
+ // Input type is float type
+
+ // Output type must be float type
+ assertMsgOptions(glsDrawTests.outputTypeIsFloatType(this.m_outputType), 'Output type is not float', false, true);
+
+ this.m_ctx.vertexAttribPointer(loc, this.m_componentCount, glsDrawTests.inputTypeToGL(this.m_inputType), this.m_normalize,
+ this.m_stride, this.m_offset);
+ }
+
+ if (this.m_instanceDivisor)
+ this.m_ctx.vertexAttribDivisor(loc, this.m_instanceDivisor);
+ }
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Target} target
+ */
+ glsDrawTests.AttributeArray.prototype.bindIndexArray = function(target) {
+ if (this.m_storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsDrawTests.targetToGL(target), this.m_glBuffer);
+ }
+ };
+
+ // DrawTestShaderProgram
+
+ /**
+ * @constructor
+ * @extends {sglrShaderProgram.ShaderProgram}
+ * @param {Array<glsDrawTests.AttributeArray>} arrays
+ */
+ glsDrawTests.DrawTestShaderProgram = function(arrays) {
+ sglrShaderProgram.ShaderProgram.call(this, this.createProgramDeclaration(arrays));
+
+ this.m_componentCount = [];
+ this.m_isCoord = [];
+ this.m_attrType = [];
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ this.m_componentCount[arrayNdx] = this.getComponentCount(arrays[arrayNdx].getOutputType());
+ this.m_isCoord[arrayNdx] = arrays[arrayNdx].isPositionAttribute();
+ this.m_attrType[arrayNdx] = this.mapOutputType(arrays[arrayNdx].getOutputType());
+ }
+ };
+
+ glsDrawTests.DrawTestShaderProgram.prototype = Object.create(sglrShaderProgram.ShaderProgram.prototype);
+ glsDrawTests.DrawTestShaderProgram.prototype.constructor = glsDrawTests.DrawTestShaderProgram;
+
+ /**
+ * @param {Array<number>} color
+ * @param {goog.NumberArray} attribValue
+ * @param {number} numComponents
+ * @return {Array<number>}
+ */
+ glsDrawTests.calcShaderColor = function(color, attribValue, numComponents) {
+ switch (numComponents) {
+ case 1:
+ color[0] = deMath.scale(color, attribValue[0])[0];
+ break;
+
+ case 2:
+ color[0] = color[0] * attribValue[0];
+ color[1] = color[1] * attribValue[1];
+ break;
+
+ case 3:
+ color[0] = color[0] * attribValue[0];
+ color[1] = color[1] * attribValue[1];
+ color[2] = color[2] * attribValue[2];
+ break;
+
+ case 4:
+ color[0] = color[0] * attribValue[0] * attribValue[3];
+ color[1] = color[1] * attribValue[1] * attribValue[3];
+ color[2] = color[2] * attribValue[2] * attribValue[3];
+ break;
+
+ default:
+ throw new Error('Invalid component count');
+ }
+
+ return color;
+ };
+
+ /**
+ * @param {Array<number>} coord
+ * @param {goog.NumberArray} attribValue
+ * @param {number} numComponents
+ * @return {Array<number>}
+ */
+ glsDrawTests.calcShaderCoord = function(coord, attribValue, numComponents) {
+ switch (numComponents) {
+ case 1:
+
+ coord = deMath.add(coord, [attribValue[0], attribValue[0]]);
+ coord[0] = coord[0];
+ coord[1] = coord[1];
+ break;
+ case 2:
+ coord = deMath.add(coord, [attribValue[0], attribValue[1]]);
+ coord[0] = coord[0];
+ coord[1] = coord[1];
+ break;
+ case 3:
+ coord = deMath.add(coord, [attribValue[0] + attribValue[2], attribValue[1]]);
+ coord[0] = coord[0];
+ coord[1] = coord[1];
+ coord[2] = coord[2];
+ break;
+ case 4:
+ coord = deMath.add(coord, [attribValue[0] + attribValue[2], attribValue[1] + attribValue[3]]);
+ coord[0] = coord[0];
+ coord[1] = coord[1];
+ coord[2] = coord[2];
+ coord[3] = coord[3];
+ break;
+
+ default:
+ throw new Error('Invalid component count');
+ }
+
+ return coord;
+ };
+
+ /**
+ * @param {Array<rrVertexAttrib.VertexAttrib>} inputs
+ * @param {Array<rrVertexPacket.VertexPacket>} packets
+ * @param {number} numPackets
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) {
+ var u_coordScale = this.getUniformByName('u_coordScale').value;
+ var u_colorScale = this.getUniformByName('u_colorScale').value;
+
+ for (var packetNdx = 0; packetNdx < numPackets; ++packetNdx) {
+ var varyingLocColor = 0;
+
+ /** @type {rrVertexPacket.VertexPacket} */ var packet = packets[packetNdx];
+
+ // Calc output color
+ /** @type {Array<number>} */ var coord = [0.0, 0.0];
+ /** @type {Array<number>} */ var color = [1.0, 1.0, 1.0];
+
+ for (var attribNdx = 0; attribNdx < this.m_attrType.length; attribNdx++) {
+ var numComponents = this.m_componentCount[attribNdx];
+ /** @type {boolean} */ var isCoord = this.m_isCoord[attribNdx];
+
+ var attrib = rrVertexAttrib.readVertexAttrib(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx, this.m_attrType[attribNdx]);
+
+ if (isCoord) {
+ coord = glsDrawTests.calcShaderCoord(
+ coord,
+ attrib,
+ numComponents
+ );
+ } else {
+ color = glsDrawTests.calcShaderColor(
+ color,
+ attrib,
+ numComponents
+ );
+ }
+ }
+
+ // Transform position
+ packet.position = [u_coordScale * coord[0], u_coordScale * coord[1], 1.0, 1.0];
+ packet.pointSize = 1.0;
+
+ // Pass color to FS
+ packet.outputs[varyingLocColor] = deMath.add(deMath.scale([u_colorScale * color[0], u_colorScale * color[1], u_colorScale * color[2], 1.0], 0.5), [0.5, 0.5, 0.5, 0.5]);
+ }
+ };
+
+ /**
+ * @param {Array<rrFragmentOperations.Fragment>} packets
+ * @param {rrShadingContext.FragmentShadingContext} context
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.shadeFragments = function(packets, context) {
+ var varyingLocColor = 0;
+
+ for (var packetNdx = 0; packetNdx < packets.length; ++packetNdx) {
+ /** @type {rrFragmentOperations.Fragment} */ var packet = packets[packetNdx];
+ packet.value = rrShadingContext.readVarying(packet, context, varyingLocColor);
+ }
+ };
+
+ /**
+ * @param {Array<glsDrawTests.AttributeArray>} arrays
+ * @return {string}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.genVertexSource = function(arrays) {
+ /** @type {Array<string>}*/ var params;
+ var vertexShaderTmpl = '';
+
+ params = this.generateShaderParams();
+
+ vertexShaderTmpl += params['VTX_HDR'];
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ vertexShaderTmpl += params['VTX_IN'] + ' highp ' + glsDrawTests.outputTypeToGLType(arrays[arrayNdx].getOutputType()) + ' a_' + arrayNdx + ';\n';
+ }
+
+ vertexShaderTmpl +=
+ 'uniform highp float u_coordScale;\n' +
+ 'uniform highp float u_colorScale;\n' +
+ params['VTX_OUT'] + ' ' + params['COL_PRECISION'] + ' vec4 v_color;\n' +
+ 'void main(void)\n' +
+ '{\n' +
+ '\tgl_PointSize = 1.0;\n' +
+ '\thighp vec2 coord = vec2(0.0, 0.0);\n' +
+ '\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n';
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ var isPositionAttr = arrays[arrayNdx].isPositionAttribute();
+
+ if (isPositionAttr) {
+ switch (arrays[arrayNdx].getOutputType()) {
+ case glsDrawTests.DrawTestSpec.OutputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.OutputType.INT:
+ case glsDrawTests.DrawTestSpec.OutputType.UINT:
+ vertexShaderTmpl +=
+ '\tcoord += vec2(float(a_' + arrayNdx + '), float(a_' + arrayNdx + '));\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC2:
+ vertexShaderTmpl +=
+ '\tcoord += vec2(a_' + arrayNdx + '.xy);\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC3:
+ vertexShaderTmpl +=
+ '\tcoord += vec2(a_' + arrayNdx + '.xy);\n' +
+ '\tcoord.x += float(a_' + arrayNdx + '.z);\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC4:
+ vertexShaderTmpl +=
+ '\tcoord += vec2(a_' + arrayNdx + '.xy);\n' +
+ '\tcoord += vec2(a_' + arrayNdx + '.zw);\n';
+ break;
+
+ default:
+ throw new Error('Invalid output type');
+ break;
+ }
+ } else {
+ switch (arrays[arrayNdx].getOutputType()) {
+ case glsDrawTests.DrawTestSpec.OutputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.OutputType.INT:
+ case glsDrawTests.DrawTestSpec.OutputType.UINT:
+ vertexShaderTmpl +=
+ '\tcolor = color * float(a_' + arrayNdx + ');\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC2:
+ vertexShaderTmpl +=
+ '\tcolor.rg = color.rg * vec2(a_' + arrayNdx + '.xy);\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC3:
+ vertexShaderTmpl +=
+ '\tcolor = color.rgb * vec3(a_' + arrayNdx + '.xyz);\n';
+ break;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC4:
+ vertexShaderTmpl +=
+ '\tcolor = color.rgb * vec3(a_' + arrayNdx + '.xyz) * float(a_' + arrayNdx + '.w);\n';
+ break;
+
+ default:
+ throw new Error('Invalid output type');
+ break;
+ }
+ }
+ }
+
+ vertexShaderTmpl +=
+ '\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n' +
+ '\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n' +
+ '}\n';
+
+ return vertexShaderTmpl;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.genFragmentSource = function() {
+ /** @type {Array<string>} */ var params;
+
+ params = this.generateShaderParams();
+
+ var fragmentShaderTmpl = params['FRAG_HDR'] +
+ params['FRAG_IN'] + ' ' + params['COL_PRECISION'] + ' vec4 v_color;\n' +
+ 'void main(void)\n' +
+ '{\n' +
+ '\t' + params['FRAG_COLOR'] + '= v_color;\n' +
+ '}\n';
+
+ return fragmentShaderTmpl;
+ };
+
+ /**
+ * @return {Array<string>}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.generateShaderParams = function() {
+ /** @type {Array<string>} */ var params = [];
+ if (gluShaderUtil.isGLSLVersionSupported(gl, gluShaderUtil.GLSLVersion.V300_ES)) {
+ params['VTX_IN'] = 'in';
+ params['VTX_OUT'] = 'out';
+ params['FRAG_IN'] = 'in';
+ params['FRAG_COLOR'] = 'dEQP_FragColor';
+ params['VTX_HDR'] = '#version 300 es\n';
+ params['FRAG_HDR'] = '#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+ params['COL_PRECISION'] = 'mediump';
+ } else if (gluShaderUtil.isGLSLVersionSupported(gl, gluShaderUtil.GLSLVersion.V100_ES)) {
+ params['VTX_IN'] = 'attribute';
+ params['VTX_OUT'] = 'varying';
+ params['FRAG_IN'] = 'varying';
+ params['FRAG_COLOR'] = 'gl_FragColor';
+ params['VTX_HDR'] = '';
+ params['FRAG_HDR'] = '';
+ params['COL_PRECISION'] = 'mediump';
+ } else
+ throw new Error('Invalid GL version');
+
+ return params;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {rrGenericVector.GenericVecType}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.mapOutputType = function(type) {
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.OutputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.OutputType.VEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.VEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.VEC4:
+ return rrGenericVector.GenericVecType.FLOAT;
+
+ case glsDrawTests.DrawTestSpec.OutputType.INT:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC4:
+ return rrGenericVector.GenericVecType.INT32;
+
+ case glsDrawTests.DrawTestSpec.OutputType.UINT:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC4:
+ return rrGenericVector.GenericVecType.UINT32;
+
+ default:
+ throw new Error('Invalid output type');
+ }
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {number}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.getComponentCount = function(type) {
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.OutputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.OutputType.INT:
+ case glsDrawTests.DrawTestSpec.OutputType.UINT:
+ return 1;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC2:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC2:
+ return 2;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC3:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC3:
+ return 3;
+
+ case glsDrawTests.DrawTestSpec.OutputType.VEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.IVEC4:
+ case glsDrawTests.DrawTestSpec.OutputType.UVEC4:
+ return 4;
+
+ default:
+ throw new Error('Invalid output type');
+ }
+ };
+
+ /**
+ * @param {Array<glsDrawTests.AttributeArray>} arrays
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ glsDrawTests.DrawTestShaderProgram.prototype.createProgramDeclaration = function(arrays) {
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var decl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++)
+ decl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('a_' + arrayNdx, this.mapOutputType(arrays[arrayNdx].getOutputType())));
+
+ decl.pushVertexToFragmentVarying(new sglrShaderProgram.VertexToFragmentVarying(rrGenericVector.GenericVecType.FLOAT));
+ decl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ decl.pushVertexSource(new sglrShaderProgram.VertexSource(this.genVertexSource(arrays)));
+ decl.pushFragmentSource(new sglrShaderProgram.FragmentSource(this.genFragmentSource()));
+
+ decl.pushUniform(new sglrShaderProgram.Uniform('u_coordScale', gluShaderUtil.DataType.FLOAT));
+ decl.pushUniform(new sglrShaderProgram.Uniform('u_colorScale', gluShaderUtil.DataType.FLOAT));
+
+ return decl;
+ };
+
+ /**
+ * @typedef {glsDrawTests.RandomArrayGenerator}
+ */
+ glsDrawTests.RandomArrayGenerator = {};
+
+ /**
+ * @param {goog.TypedArray} data
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @param {deRandom.Random} rnd
+ * @param {glsDrawTests.GLValue} min
+ * @param {glsDrawTests.GLValue} max
+ */
+ glsDrawTests.RandomArrayGenerator.setData = function(data, type, rnd, min, max) {
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ case glsDrawTests.DrawTestSpec.InputType.SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT:
+ case glsDrawTests.DrawTestSpec.InputType.BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE:
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ case glsDrawTests.DrawTestSpec.InputType.HALF:
+ glsDrawTests.copyGLValueToArray(data, glsDrawTests.GLValue.getRandom(rnd, min, max));
+ break;
+ default:
+ throw new Error('Invalid input type');
+ }
+ };
+
+ /**
+ * createBasicArray
+ * @param {number} seed
+ * @param {number} elementCount
+ * @param {number} componentCount
+ * @param {number} offset
+ * @param {number} stride
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @param {number} first
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitive
+ * @param {?goog.TypedArray} indices
+ * @param {number} indexSize
+ * @return {goog.TypedArray}
+ */
+ glsDrawTests.RandomArrayGenerator.createArray = function(seed, elementCount, componentCount, offset, stride, type, first, primitive, indices, indexSize) {
+ assertMsgOptions(componentCount >= 1 && componentCount <= 4, 'Unacceptable number of components', false, true);
+
+ /** @type {glsDrawTests.GLValue} */ var min = glsDrawTests.GLValue.getMinValue(type);
+ /** @type {glsDrawTests.GLValue} */ var max = glsDrawTests.GLValue.getMaxValue(type);
+
+ var packed = type == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10 ||
+ type == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10;
+ /** @type {number} */ var limit10 = (1 << 10);
+ /** @type {number} */ var limit2 = (1 << 2);
+
+
+ /** @type {number} */ var componentSize = glsDrawTests.DrawTestSpec.inputTypeSize(type);
+ /** @type {number} */ var elementSize = componentSize * componentCount;
+ /** @type {number} */ var bufferSize = offset + Math.max(elementCount * stride, elementCount * elementSize);
+
+ var data = new ArrayBuffer(bufferSize);
+ var writePtr = new Uint8Array(data, offset);
+
+ var previousComponentsFloat = [0, 0, 0, 0];
+ var rnd = new deRandom.Random(seed);
+
+ for (var vertexNdx = 0; vertexNdx < elementCount; vertexNdx++) {
+ var components = [];
+
+ for (var componentNdx = 0; componentNdx < componentCount; componentNdx++) {
+ var getRandomComponent = function() {
+ // For packed formats we can't use GLValue
+ if (packed) {
+ if (componentNdx == 3) {
+ return rnd.getInt() % limit2;
+ } else {
+ return rnd.getInt() % limit10;
+ }
+ } else {
+ return glsDrawTests.GLValue.getRandom(rnd, min, max);
+ }
+ };
+
+ var component = getRandomComponent();
+ var componentFloat = (component instanceof glsDrawTests.GLValue) ? component.toFloat() : component;
+
+ // Try to not create vertex near previous
+ if (vertexNdx != 0 && Math.abs(componentFloat - previousComponentsFloat[componentNdx]) < min.toFloat()) {
+ // Too close, try again (but only once)
+ component = getRandomComponent();
+ componentFloat = (component instanceof glsDrawTests.GLValue) ? component.toFloat() : component;
+ }
+
+ components.push(component);
+ previousComponentsFloat[componentNdx] = componentFloat;
+ }
+
+ if (packed) {
+ var packedValue = deMath.binaryOp(
+ deMath.shiftLeft(/** @type {Array<number>} */ (components)[3], 30), deMath.binaryOp(
+ deMath.shiftLeft(/** @type {Array<number>} */ (components)[2], 20), deMath.binaryOp(
+ deMath.shiftLeft(/** @type {Array<number>} */ (components)[1], 10), /** @type {Array<number>} */ (components)[0], deMath.BinaryOp.OR
+ ), deMath.BinaryOp.OR
+ ), deMath.BinaryOp.OR
+ );
+ glsDrawTests.copyArray(writePtr, new Uint32Array([packedValue]));
+ } else {
+ for (var componentNdx = 0; componentNdx < componentCount; componentNdx++) {
+ glsDrawTests.copyGLValueToArray(writePtr.subarray(componentNdx * componentSize), components[componentNdx]);
+ }
+ }
+
+ writePtr = writePtr.subarray(stride);
+ }
+
+ return new Uint8Array(data);
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} elementCount
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} type
+ * @param {number} offset
+ * @param {number} min
+ * @param {number} max
+ * @return {goog.TypedArray}
+ */
+ glsDrawTests.RandomArrayGenerator.generateIndices = function(seed, elementCount, type, offset, min, max) {
+ return glsDrawTests.RandomArrayGenerator.createIndices(seed, elementCount, offset, min, max, type);
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} elementCount
+ * @param {number} offset
+ * @param {number} min
+ * @param {number} max
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} type
+ * @return {goog.TypedArray}
+ */
+ glsDrawTests.RandomArrayGenerator.createIndices = function(seed, elementCount, offset, min, max, type) {
+ /** @type {number}*/ var elementSize = glsDrawTests.DrawTestSpec.indexTypeSize(type);
+ /** @type {number}*/ var bufferSize = offset + elementCount * elementSize;
+
+ var data = new ArrayBuffer(bufferSize);
+ var writePtr = new Uint8Array(data).subarray(offset);
+
+ var rnd = new deRandom.Random(seed);
+
+ /* TODO: get limits for given index type --> if (min < 0 || min > std::numeric_limits<T>::max() ||
+ max < 0 || max > std::numeric_limits<T>::max() ||
+ min > max)
+ DE_ASSERT(!"Invalid range");*/
+
+ // JS refrast requires shuffled unique keys
+ var keys = [];
+ for (var key = 0; key < elementCount; key++)
+ keys.push(glsDrawTests.GLValue.create(key, glsDrawTests.indexTypeToInputType(type)));
+
+ for (var elementNdx = 0; elementNdx < elementCount; ++elementNdx) {
+ var randomkey = rnd.getInt(0, keys.length - 1);
+ var ndx = keys[randomkey];
+
+ keys.splice(randomkey, 1);
+
+ glsDrawTests.copyArray(
+ writePtr.subarray(elementSize * elementNdx),
+ new Uint8Array(ndx.m_value.buffer)
+ );
+ }
+
+ return new Uint8Array(data);
+ };
+
+ /**
+ * @param {number} seed
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {Array<number>}
+ */
+ glsDrawTests.RandomArrayGenerator.generateAttributeValue = function(seed, type) {
+ var random = new deRandom.Random(seed);
+
+ switch (type) {
+ case glsDrawTests.DrawTestSpec.InputType.FLOAT:
+ return glsDrawTests.generateRandomVec4(random);
+
+ case glsDrawTests.DrawTestSpec.InputType.INT:
+ return glsDrawTests.generateRandomIVec4(random);
+
+ case glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT:
+ return glsDrawTests.generateRandomUVec4(random);
+
+ default:
+ throw new Error('Invalid attribute type');
+ }
+ };
+
+ // AttributePack
+
+ /**
+ * @param {sglrReferenceContext.ReferenceContext | sglrGLContext.GLContext} drawContext
+ * @param {Array<number>} screenSize (2 positive elements in array)
+ * @param {boolean} useVao
+ * @param {boolean} logEnabled
+ * @constructor
+ */
+ glsDrawTests.AttributePack = function(drawContext, screenSize, useVao, logEnabled) {
+ /** @type {sglrReferenceContext.ReferenceContext | sglrGLContext.GLContext} */ this.m_ctx = drawContext;
+
+ /** @type {Array<glsDrawTests.AttributeArray>} */ this.m_arrays = [];
+ /** @type {sglrShaderProgram.ShaderProgram} */ this.m_program;
+ /** @type {tcuSurface.Surface} */ this.m_screen = new tcuSurface.Surface(screenSize[0], screenSize[1]);
+ /** @type {boolean} */ this.m_useVao = useVao;
+ /** @type {boolean} */ this.m_logEnabled = logEnabled;
+ /** @type {WebGLProgram | sglrShaderProgram.ShaderProgram | null} */ this.m_programID = null;
+ /** @type {WebGLVertexArrayObject|sglrReferenceContext.VertexArray|null} */ this.m_vaoID = null;
+
+ if (this.m_useVao)
+ this.m_vaoID = this.m_ctx.createVertexArray();
+ };
+
+ /**
+ * @return {tcuSurface.Surface}
+ */
+ glsDrawTests.AttributePack.prototype.getSurface = function() {
+ return this.m_screen;
+ };
+
+ /**
+ * @param {number} i
+ * @return {glsDrawTests.AttributeArray}
+ */
+ glsDrawTests.AttributePack.prototype.getArray = function(i) {
+ return this.m_arrays[i];
+ };
+
+ /**
+ * @return number
+ */
+ glsDrawTests.AttributePack.prototype.getArrayCount = function() {
+ return this.m_arrays.length;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Storage} storage
+ */
+ glsDrawTests.AttributePack.prototype.newArray = function(storage) {
+ this.m_arrays.push(new glsDrawTests.AttributeArray(storage, this.m_ctx));
+ };
+
+ /**
+ * clearArrays
+ */
+ glsDrawTests.AttributePack.prototype.clearArrays = function() {
+ this.m_arrays.length = 0;
+ };
+
+ /**
+ * updateProgram
+ */
+ glsDrawTests.AttributePack.prototype.updateProgram = function() {
+ if (this.m_programID)
+ this.m_ctx.deleteProgram(this.m_programID);
+
+ this.m_program = new glsDrawTests.DrawTestShaderProgram(this.m_arrays);
+ this.m_programID = this.m_ctx.createProgram(this.m_program);
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitive
+ * @param {?glsDrawTests.DrawTestSpec.DrawMethod} drawMethod
+ * @param {number} firstVertex
+ * @param {number} vertexCount
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} indexType
+ * @param {number} indexOffset
+ * @param {number} rangeStart
+ * @param {number} rangeEnd
+ * @param {number} instanceCount
+ * @param {number} coordScale
+ * @param {number} colorScale
+ * @param {glsDrawTests.AttributeArray} indexArray
+ */
+ glsDrawTests.AttributePack.prototype.render = function(primitive, drawMethod, firstVertex, vertexCount, indexType,
+ indexOffset, rangeStart, rangeEnd, instanceCount, coordScale, colorScale, indexArray) {
+ assertMsgOptions(this.m_program != null, 'Program is null', false, true);
+ assertMsgOptions(this.m_programID != null, 'No context created program', false, true);
+
+ this.m_ctx.viewport(0, 0, this.m_screen.getWidth(), this.m_screen.getHeight());
+ this.m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
+ this.m_ctx.clear(gl.COLOR_BUFFER_BIT);
+
+ this.m_ctx.useProgram(this.m_programID);
+
+ this.m_ctx.uniform1f(this.m_ctx.getUniformLocation(this.m_programID, 'u_coordScale'), coordScale);
+ this.m_ctx.uniform1f(this.m_ctx.getUniformLocation(this.m_programID, 'u_colorScale'), colorScale);
+
+ if (this.m_useVao)
+ this.m_ctx.bindVertexArray(this.m_vaoID);
+
+ if (indexArray)
+ indexArray.bindIndexArray(glsDrawTests.DrawTestSpec.Target.ELEMENT_ARRAY);
+
+ for (var arrayNdx = 0; arrayNdx < this.m_arrays.length; arrayNdx++) {
+ var attribName = '';
+ attribName += 'a_' + arrayNdx;
+
+ var loc = this.m_ctx.getAttribLocation(this.m_programID, attribName);
+
+ if (this.m_arrays[arrayNdx].isBound())
+ this.m_ctx.enableVertexAttribArray(loc);
+
+ this.m_arrays[arrayNdx].bindAttribute(loc);
+ }
+
+ if (drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS)
+ this.m_ctx.drawArrays(glsDrawTests.primitiveToGL(primitive), firstVertex, vertexCount);
+ else if (drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS_INSTANCED)
+ this.m_ctx.drawArraysInstanced(glsDrawTests.primitiveToGL(primitive), firstVertex, vertexCount, instanceCount);
+ else if (drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS)
+ this.m_ctx.drawElements(glsDrawTests.primitiveToGL(primitive), vertexCount, glsDrawTests.indexTypeToGL(indexType), indexOffset);
+ else if (drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_RANGED)
+ this.m_ctx.drawRangeElements(glsDrawTests.primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, glsDrawTests.indexTypeToGL(indexType), indexOffset);
+ else if (drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_INSTANCED)
+ this.m_ctx.drawElementsInstanced(glsDrawTests.primitiveToGL(primitive), vertexCount, glsDrawTests.indexTypeToGL(indexType), indexOffset, instanceCount);
+ else
+ throw new Error('Invalid draw method');
+
+ for (var arrayNdx = 0; arrayNdx < this.m_arrays.length; arrayNdx++) {
+ if (this.m_arrays[arrayNdx].isBound()) {
+ var attribName = '';
+ attribName += 'a_' + arrayNdx;
+
+ var loc = this.m_ctx.getAttribLocation(this.m_programID, attribName);
+
+ this.m_ctx.disableVertexAttribArray(loc);
+ }
+ }
+
+ if (this.m_useVao)
+ this.m_ctx.bindVertexArray(null);
+
+ this.m_ctx.useProgram(null);
+ this.m_screen.readViewport(this.m_ctx, [0 , 0, this.m_screen.getWidth(), this.m_screen.getHeight()]);
+ };
+
+ // DrawTestSpec
+
+ /**
+ * @constructor
+ */
+ glsDrawTests.DrawTestSpec = function() {
+ /** @type {?glsDrawTests.DrawTestSpec.Primitive} */ this.primitive = null;
+ /** @type {number} */ this.primitiveCount = 0; //!< number of primitives to draw (per instance)
+
+ /** @type {?glsDrawTests.DrawTestSpec.DrawMethod} */ this.drawMethod = null;
+ /** @type {?glsDrawTests.DrawTestSpec.IndexType} */ this.indexType = null; //!< used only if drawMethod = DrawElements*
+ /** @type {number} */ this.indexPointerOffset = 0; //!< used only if drawMethod = DrawElements*
+ /** @type {?glsDrawTests.DrawTestSpec.Storage} */ this.indexStorage = null; //!< used only if drawMethod = DrawElements*
+ /** @type {number} */ this.first = 0; //!< used only if drawMethod = DrawArrays*
+ /** @type {number} */ this.indexMin = 0; //!< used only if drawMethod = Draw*Ranged
+ /** @type {number} */ this.indexMax = 0; //!< used only if drawMethod = Draw*Ranged
+ /** @type {number} */ this.instanceCount = 0; //!< used only if drawMethod = Draw*Instanced or Draw*Indirect
+ /** @type {number} */ this.indirectOffset = 0; //!< used only if drawMethod = Draw*Indirect
+ /** @type {number} */ this.baseVertex = 0; //!< used only if drawMethod = DrawElementsIndirect or *BaseVertex
+
+ /** @type {Array<glsDrawTests.DrawTestSpec.AttributeSpec>} */ this.attribs = [];
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Target} target
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.targetToString = function(target) {
+ assertMsgOptions(target != null, 'Target is null', false, true);
+
+ var targets = [
+ 'element_array', // TARGET_ELEMENT_ARRAY = 0,
+ 'array' // TARGET_ARRAY,
+ ];
+ assertMsgOptions(targets.length == Object.keys(glsDrawTests.DrawTestSpec.Target).length,
+ 'The amount of target names is different than the amount of targets', false, true);
+
+ return targets[target];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.inputTypeToString = function(type) {
+ assertMsgOptions(type != null, 'Type is null', false, true);
+
+ var types = [
+ 'float', // INPUTTYPE_FLOAT = 0,
+
+ 'byte', // INPUTTYPE_BYTE,
+ 'short', // INPUTTYPE_SHORT,
+
+ 'unsigned_byte', // INPUTTYPE_UNSIGNED_BYTE,
+ 'unsigned_short', // INPUTTYPE_UNSIGNED_SHORT,
+
+ 'int', // INPUTTYPE_INT,
+ 'unsigned_int', // INPUTTYPE_UNSIGNED_INT,
+ 'half', // INPUTTYPE_HALF,
+ 'unsigned_int2_10_10_10', // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
+ 'int2_10_10_10' // INPUTTYPE_INT_2_10_10_10,
+ ];
+ assertMsgOptions(types.length == Object.keys(glsDrawTests.DrawTestSpec.InputType).length,
+ 'The amount of type names is different than the amount of types', false, true);
+
+ return types[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} type
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.outputTypeToString = function(type) {
+ assertMsgOptions(type != null, 'Type is null', false, true);
+
+ var types = [
+ 'float', // OUTPUTTYPE_FLOAT = 0,
+ 'vec2', // OUTPUTTYPE_VEC2,
+ 'vec3', // OUTPUTTYPE_VEC3,
+ 'vec4', // OUTPUTTYPE_VEC4,
+
+ 'int', // OUTPUTTYPE_INT,
+ 'uint', // OUTPUTTYPE_UINT,
+
+ 'ivec2', // OUTPUTTYPE_IVEC2,
+ 'ivec3', // OUTPUTTYPE_IVEC3,
+ 'ivec4', // OUTPUTTYPE_IVEC4,
+
+ 'uvec2', // OUTPUTTYPE_UVEC2,
+ 'uvec3', // OUTPUTTYPE_UVEC3,
+ 'uvec4' // OUTPUTTYPE_UVEC4,
+ ];
+ assertMsgOptions(types.length == Object.keys(glsDrawTests.DrawTestSpec.OutputType).length,
+ 'The amount of type names is different than the amount of types', false, true);
+
+ return types[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Usage} usage
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.usageTypeToString = function(usage) {
+ assertMsgOptions(usage != null, 'Usage is null', false, true);
+
+ var usages = [
+ 'dynamic_draw', // USAGE_DYNAMIC_DRAW = 0,
+ 'static_draw', // USAGE_STATIC_DRAW,
+ 'stream_draw', // USAGE_STREAM_DRAW,
+
+ 'stream_read', // USAGE_STREAM_READ,
+ 'stream_copy', // USAGE_STREAM_COPY,
+
+ 'static_read', // USAGE_STATIC_READ,
+ 'static_copy', // USAGE_STATIC_COPY,
+
+ 'dynamic_read', // USAGE_DYNAMIC_READ,
+ 'dynamic_copy' // USAGE_DYNAMIC_COPY,
+ ];
+ assertMsgOptions(usages.length == Object.keys(glsDrawTests.DrawTestSpec.Usage).length,
+ 'The amount of usage names is different than the amount of usages', false, true);
+
+ return usages[usage];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Storage} storage
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.storageToString = function(storage) {
+ assertMsgOptions(storage != null, 'Storage is null', false, true);
+
+ var storages = [
+ 'user_ptr', // STORAGE_USER = 0,
+ 'buffer' // STORAGE_BUFFER,
+ ];
+ assertMsgOptions(storages.length == Object.keys(glsDrawTests.DrawTestSpec.Storage).length,
+ 'The amount of storage names is different than the amount of storages', false, true);
+
+ return storages[storage];
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec.Primitive} primitive
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.primitiveToString = function(primitive) {
+ assertMsgOptions(primitive != null, 'Primitive is null', false, true);
+
+ var primitives = [
+ 'points', // PRIMITIVE_POINTS ,
+ 'triangles', // PRIMITIVE_TRIANGLES,
+ 'triangle_fan', // PRIMITIVE_TRIANGLE_FAN,
+ 'triangle_strip', // PRIMITIVE_TRIANGLE_STRIP,
+ 'lines', // PRIMITIVE_LINES
+ 'line_strip', // PRIMITIVE_LINE_STRIP
+ 'line_loop'
+ ];
+ assertMsgOptions(primitives.length == Object.keys(glsDrawTests.DrawTestSpec.Primitive).length,
+ 'The amount of primitive names is different than the amount of primitives', false, true);
+
+ return primitives[primitive];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} type
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.indexTypeToString = function(type) {
+ assertMsgOptions(type != null, 'Index type is null', false, true);
+
+ var indexTypes = [
+ 'byte', // INDEXTYPE_BYTE = 0,
+ 'short', // INDEXTYPE_SHORT,
+ 'int' // INDEXTYPE_INT,
+ ];
+ assertMsgOptions(indexTypes.length == Object.keys(glsDrawTests.DrawTestSpec.IndexType).length,
+ 'The amount of index type names is different than the amount of index types', false, true);
+
+ return indexTypes[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.DrawMethod} method
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.drawMethodToString = function(method) {
+ assertMsgOptions(method != null, 'Method is null', false, true);
+
+ var methods = [
+ 'draw_arrays', //!< DRAWMETHOD_DRAWARRAYS
+ 'draw_arrays_instanced', //!< DRAWMETHOD_DRAWARRAYS_INSTANCED
+ 'draw_elements', //!< DRAWMETHOD_DRAWELEMENTS
+ 'draw_range_elements', //!< DRAWMETHOD_DRAWELEMENTS_RANGED
+ 'draw_elements_instanced' //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
+ ];
+ assertMsgOptions(methods.length == Object.keys(glsDrawTests.DrawTestSpec.DrawMethod).length,
+ 'The amount of method names is different than the amount of methods', false, true);
+
+ return methods[method];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} type
+ * @return {number}
+ */
+ glsDrawTests.DrawTestSpec.inputTypeSize = function(type) {
+ assertMsgOptions(type != null, 'Input type is null', false, true);
+
+ var size = [
+ 4, // INPUTTYPE_FLOAT = 0,
+
+ 1, // INPUTTYPE_BYTE,
+ 2, // INPUTTYPE_SHORT,
+
+ 1, // INPUTTYPE_UNSIGNED_BYTE,
+ 2, // INPUTTYPE_UNSIGNED_SHORT,
+
+ 4, // INPUTTYPE_INT,
+ 4, // INPUTTYPE_UNSIGNED_INT,
+ 2, // INPUTTYPE_HALF,
+ 4 / 4, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
+ 4 / 4 // INPUTTYPE_INT_2_10_10_10,
+ ];
+ assertMsgOptions(size.length == Object.keys(glsDrawTests.DrawTestSpec.InputType).length,
+ 'The amount of type names is different than the amount of types', false, true);
+
+ return size[type];
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.IndexType} type
+ * @return {number}
+ */
+ glsDrawTests.DrawTestSpec.indexTypeSize = function(type) {
+ assertMsgOptions(type != null, 'Type is null', false, true);
+
+ var size = [
+ 1, // INDEXTYPE_BYTE,
+ 2, // INDEXTYPE_SHORT,
+ 4 // INDEXTYPE_INT,
+ ];
+ assertMsgOptions(size.length == Object.keys(glsDrawTests.DrawTestSpec.IndexType).length,
+ 'The amount of type names is different than the amount of types', false, true);
+
+ return size[type];
+ };
+
+ /**
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.prototype.getName = function() {
+ /** @type {glsDrawTests.MethodInfo} */ var methodInfo = glsDrawTests.getMethodInfo(this.drawMethod);
+ /** @type {boolean} */ var hasFirst = methodInfo.first;
+ /** @type {boolean} */ var instanced = methodInfo.instanced;
+ /** @type {boolean} */ var ranged = methodInfo.ranged;
+ /** @type {boolean} */ var indexed = methodInfo.indexed;
+
+ var name = '';
+
+ for (var ndx = 0; ndx < this.attribs.length; ++ndx) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec}*/ var attrib = this.attribs[ndx];
+
+ if (this.attribs.length > 1)
+ name += 'attrib' + ndx + '_';
+
+ if (ndx == 0 || attrib.additionalPositionAttribute)
+ name += 'pos_';
+ else
+ name += 'col_';
+
+ if (attrib.useDefaultAttribute) {
+ name += 'non_array_' +
+ glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType)) + '_' +
+ attrib.componentCount + '_' +
+ glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + '_';
+ } else {
+ name += glsDrawTests.DrawTestSpec.storageToString(attrib.storage) + '_' +
+ attrib.offset + '_' +
+ attrib.stride + '_' +
+ glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType));
+ if (attrib.inputType != glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10 && attrib.inputType != glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10)
+ name += attrib.componentCount;
+ name += '_' +
+ (attrib.normalize ? 'normalized_' : '') +
+ glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + '_' +
+ glsDrawTests.DrawTestSpec.usageTypeToString(attrib.usage) + '_' +
+ attrib.instanceDivisor + '_';
+ }
+ }
+
+ if (indexed)
+ name += 'index_' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + '_' +
+ glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + '_' +
+ 'offset' + this.indexPointerOffset + '_';
+ if (hasFirst)
+ name += 'first' + this.first + '_';
+ if (ranged)
+ name += 'ranged_' + this.indexMin + '_' + this.indexMax + '_';
+ if (instanced)
+ name += 'instances' + this.instanceCount + '_';
+
+ switch (this.primitive) {
+ case glsDrawTests.DrawTestSpec.Primitive.POINTS:
+ name += 'points_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLES:
+ name += 'triangles_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_FAN:
+ name += 'triangle_fan_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_STRIP:
+ name += 'triangle_strip_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINES:
+ name += 'lines_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_STRIP:
+ name += 'line_strip_';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_LOOP:
+ name += 'line_loop_';
+ break;
+ default:
+ throw new Error('Invalid primitive');
+ break;
+ }
+
+ name += this.primitiveCount;
+
+ return name;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.prototype.getDesc = function() {
+ var desc = '';
+
+ for (var ndx = 0; ndx < this.attribs.length; ++ndx) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var attrib = this.attribs[ndx];
+
+ if (attrib.useDefaultAttribute) {
+ desc += 'Attribute ' + ndx + ': default, ' + ((ndx == 0 || attrib.additionalPositionAttribute) ? ('position ,') : ('color ,')) +
+ 'input datatype ' + glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType)) + ', ' +
+ 'input component count ' + attrib.componentCount + ', ' +
+ 'used as ' + glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + ', ';
+ } else {
+ desc += 'Attribute ' + ndx + ': ' + ((ndx == 0 || attrib.additionalPositionAttribute) ? ('position ,') : ('color ,')) +
+ 'Storage in ' + glsDrawTests.DrawTestSpec.storageToString(attrib.storage) + ', ' +
+ 'stride ' + attrib.stride + ', ' +
+ 'input datatype ' + glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType)) + ', ' +
+ 'input component count ' + attrib.componentCount + ', ' +
+ (attrib.normalize ? 'normalized, ' : '') +
+ 'used as ' + glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + ', ' +
+ 'instance divisor ' + attrib.instanceDivisor + ', ';
+ }
+ }
+
+ if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS) {
+ desc += 'drawArrays(), ' +
+ 'first ' + this.first + ', ';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS_INSTANCED) {
+ desc += 'drawArraysInstanced(), ' +
+ 'first ' + this.first + ', ' +
+ 'instance count ' + this.instanceCount + ', ';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS) {
+ desc += 'drawElements(), ' +
+ 'index type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + ', ' +
+ 'index storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + ', ' +
+ 'index offset ' + this.indexPointerOffset + ', ';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_RANGED) {
+ desc += 'drawElementsRanged(), ' +
+ 'index type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + ', ' +
+ 'index storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + ', ' +
+ 'index offset ' + this.indexPointerOffset + ', ' +
+ 'range start ' + this.indexMin + ', ' +
+ 'range end ' + this.indexMax + ', ';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_INSTANCED) {
+ desc += 'drawElementsInstanced(), ' +
+ 'index type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + ', ' +
+ 'index storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + ', ' +
+ 'index offset ' + this.indexPointerOffset + ', ' +
+ 'instance count ' + this.instanceCount + ', ';
+ } else
+ throw new Error('Invalid draw method');
+
+ desc += this.primitiveCount;
+
+ switch (this.primitive) {
+ case glsDrawTests.DrawTestSpec.Primitive.POINTS:
+ desc += 'points';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLES:
+ desc += 'triangles';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_FAN:
+ desc += 'triangles (fan)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_STRIP:
+ desc += 'triangles (strip)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINES:
+ desc += 'lines';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_STRIP:
+ desc += 'lines (strip)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_LOOP:
+ desc += 'lines (loop)';
+ break;
+ default:
+ throw new Error('Invalid primitive');
+ break;
+ }
+
+ return desc;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsDrawTests.DrawTestSpec.prototype.getMultilineDesc = function() {
+ var desc = '';
+
+ for (var ndx = 0; ndx < this.attribs.length; ++ndx) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var attrib = this.attribs[ndx];
+
+ if (attrib.useDefaultAttribute) {
+ desc += 'Attribute ' + ndx + ': default, ' + ((ndx == 0 || attrib.additionalPositionAttribute) ? ('position\n') : ('color\n')) +
+ '\tinput datatype ' + glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType)) + '\n' +
+ '\tinput component count ' + attrib.componentCount + '\n' +
+ '\tused as ' + glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + '\n';
+ } else {
+ desc += 'Attribute ' + ndx + ': ' + ((ndx == 0 || attrib.additionalPositionAttribute) ? ('position\n') : ('color\n')) +
+ '\tStorage in ' + glsDrawTests.DrawTestSpec.storageToString(attrib.storage) + '\n' +
+ '\tstride ' + attrib.stride + '\n' +
+ '\tinput datatype ' + glsDrawTests.DrawTestSpec.inputTypeToString(/** @type {?glsDrawTests.DrawTestSpec.InputType} */ (attrib.inputType)) + '\n' +
+ '\tinput component count ' + attrib.componentCount + '\n' +
+ (attrib.normalize ? '\tnormalized\n' : '') +
+ '\tused as ' + glsDrawTests.DrawTestSpec.outputTypeToString(attrib.outputType) + '\n' +
+ '\tinstance divisor ' + attrib.instanceDivisor + '\n';
+ }
+ }
+
+ if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS) {
+ desc += 'drawArrays()\n' +
+ '\tfirst ' + this.first + '\n';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWARRAYS_INSTANCED) {
+ desc += 'drawArraysInstanced()\n' +
+ '\tfirst ' + this.first + '\n' +
+ '\tinstance count ' + this.instanceCount + '\n';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS) {
+ desc += 'drawElements()\n' +
+ '\tindex type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + '\n' +
+ '\tindex storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + '\n' +
+ '\tindex offset ' + this.indexPointerOffset + '\n';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_RANGED) {
+ desc += 'drawElementsRanged()\n' +
+ '\tindex type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + '\n' +
+ '\tindex storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + '\n' +
+ '\tindex offset ' + this.indexPointerOffset + '\n' +
+ '\trange start ' + this.indexMin + '\n' +
+ '\trange end ' + this.indexMax + '\n';
+ } else if (this.drawMethod == glsDrawTests.DrawTestSpec.DrawMethod.DRAWELEMENTS_INSTANCED) {
+ desc += 'drawElementsInstanced()\n' +
+ '\tindex type ' + glsDrawTests.DrawTestSpec.indexTypeToString(this.indexType) + '\n' +
+ '\tindex storage in ' + glsDrawTests.DrawTestSpec.storageToString(this.indexStorage) + '\n' +
+ '\tindex offset ' + this.indexPointerOffset + '\n' +
+ '\tinstance count ' + this.instanceCount + '\n';
+ } else
+ throw new Error('Invalid draw method');
+
+ desc += '\t' + this.primitiveCount + ' ';
+
+ switch (this.primitive) {
+ case glsDrawTests.DrawTestSpec.Primitive.POINTS:
+ desc += 'points';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLES:
+ desc += 'triangles';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_FAN:
+ desc += 'triangles (fan)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_STRIP:
+ desc += 'triangles (strip)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINES:
+ desc += 'lines';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_STRIP:
+ desc += 'lines (strip)';
+ break;
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_LOOP:
+ desc += 'lines (loop)';
+ break;
+ default:
+ throw new Error('Invalid primitive');
+ break;
+ }
+
+ desc += '\n';
+
+ return desc;
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.Target = {
+ ELEMENT_ARRAY: 0,
+ ARRAY: 1
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.InputType = {
+ FLOAT: 0,
+
+ BYTE: 1,
+ SHORT: 2,
+
+ UNSIGNED_BYTE: 3,
+ UNSIGNED_SHORT: 4,
+
+ INT: 5,
+ UNSIGNED_INT: 6,
+ HALF: 7,
+ UNSIGNED_INT_2_10_10_10: 8,
+ INT_2_10_10_10: 9
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.OutputType = {
+ FLOAT: 0,
+ VEC2: 1,
+ VEC3: 2,
+ VEC4: 3,
+
+ INT: 4,
+ UINT: 5,
+
+ IVEC2: 6,
+ IVEC3: 7,
+ IVEC4: 8,
+
+ UVEC2: 9,
+ UVEC3: 10,
+ UVEC4: 11
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.Usage = {
+ DYNAMIC_DRAW: 0,
+ STATIC_DRAW: 1,
+ STREAM_DRAW: 2,
+
+ STREAM_READ: 3,
+ STREAM_COPY: 4,
+
+ STATIC_READ: 5,
+ STATIC_COPY: 6,
+
+ DYNAMIC_READ: 7,
+ DYNAMIC_COPY: 8
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.Storage = {
+ USER: 0,
+ BUFFER: 1
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.Primitive = {
+ POINTS: 0,
+ TRIANGLES: 1,
+ TRIANGLE_FAN: 2,
+ TRIANGLE_STRIP: 3,
+ LINES: 4,
+ LINE_STRIP: 5,
+ LINE_LOOP: 6
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.IndexType = {
+ BYTE: 0,
+ SHORT: 1,
+ INT: 2
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.DrawMethod = {
+ DRAWARRAYS: 0,
+ DRAWARRAYS_INSTANCED: 1,
+ DRAWELEMENTS: 2,
+ DRAWELEMENTS_RANGED: 3,
+ DRAWELEMENTS_INSTANCED: 4
+ };
+
+ /**
+ * @enum {number}
+ */
+ glsDrawTests.DrawTestSpec.CompatibilityTestType = {
+ NONE: 0,
+ UNALIGNED_OFFSET: 1,
+ UNALIGNED_STRIDE: 2
+ };
+
+ /**
+ * @return {number}
+ */
+ glsDrawTests.DrawTestSpec.prototype.hash = function() {
+ // Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior).
+ /** @type {glsDrawTests.MethodInfo} */ var methodInfo = glsDrawTests.getMethodInfo(this.drawMethod);
+ /** @type {boolean} */ var arrayed = methodInfo.first;
+ /** @type {boolean} */ var instanced = methodInfo.instanced;
+ /** @type {boolean} */ var ranged = methodInfo.ranged;
+ /** @type {boolean} */ var indexed = methodInfo.indexed;
+
+ /** @type {number} */ var indexHash = (!indexed) ? (0) : (this.indexType + 10 * this.indexPointerOffset + 100 * this.indexStorage);
+ /** @type {number} */ var arrayHash = (!arrayed) ? (0) : (this.first);
+ /** @type {number} */ var indexRangeHash = (!ranged) ? (0) : (this.indexMin + 10 * this.indexMax);
+ /** @type {number} */ var instanceHash = (!instanced) ? (0) : (this.instanceCount);
+ /** @type {number} */ var basicHash = this.primitive + 10 * this.primitiveCount + 100 * this.drawMethod;
+
+ return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * this.attribs.length + 19 * this.primitiveCount;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsDrawTests.DrawTestSpec.prototype.valid = function() {
+ assertMsgOptions(this.primitive != null, 'Primitive is null', false, true);
+ assertMsgOptions(this.drawMethod != null, 'Draw method is null', false, true);
+
+ var methodInfo = glsDrawTests.getMethodInfo(this.drawMethod);
+
+ if (methodInfo.ranged) {
+ var maxIndexValue = 0;
+ if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.BYTE)
+ maxIndexValue = glsDrawTests.GLValue.getMaxValue(glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE).interpret();
+ else if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.SHORT)
+ maxIndexValue = glsDrawTests.GLValue.getMaxValue(glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT).interpret();
+ else if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.INT)
+ maxIndexValue = glsDrawTests.GLValue.getMaxValue(glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT).interpret();
+ else
+ throw new Error('Invalid index type');
+
+ if (this.indexMin > this.indexMax)
+ return false;
+ if (this.indexMin < 0 || this.indexMax < 0)
+ return false;
+ if (this.indexMin > maxIndexValue || this.indexMax > maxIndexValue)
+ return false;
+ }
+
+ if (methodInfo.first && this.first < 0)
+ return false;
+
+ return true;
+ };
+
+ /**
+ * @return {glsDrawTests.DrawTestSpec.CompatibilityTestType}
+ */
+ glsDrawTests.DrawTestSpec.prototype.isCompatibilityTest = function() {
+ var methodInfo = glsDrawTests.getMethodInfo(this.drawMethod);
+
+ var bufferAlignmentBad = false;
+ var strideAlignmentBad = false;
+
+ // Attribute buffer alignment
+ for (var ndx = 0; ndx < this.attribs.length; ++ndx)
+ if (!this.attribs[ndx].isBufferAligned())
+ bufferAlignmentBad = true;
+
+ // Attribute stride alignment
+ for (var ndx = 0; ndx < this.attribs.length; ++ndx)
+ if (!this.attribs[ndx].isBufferStrideAligned())
+ strideAlignmentBad = true;
+
+ // Index buffer alignment
+ if (methodInfo.indexed) {
+ if (this.indexStorage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ var indexSize = 0;
+ if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.BYTE)
+ indexSize = 1;
+ else if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.SHORT)
+ indexSize = 2;
+ else if (this.indexType == glsDrawTests.DrawTestSpec.IndexType.INT)
+ indexSize = 4;
+ else
+ throw new Error('');
+
+ if (this.indexPointerOffset % indexSize != 0)
+ bufferAlignmentBad = true;
+ }
+ }
+
+ // \note combination bad alignment & stride is treated as bad offset
+ if (bufferAlignmentBad)
+ return glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_OFFSET;
+ else if (strideAlignmentBad)
+ return glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_STRIDE;
+ else
+ return glsDrawTests.DrawTestSpec.CompatibilityTestType.NONE;
+ };
+
+ // DrawTestSpec.AttributeSpec
+
+ /**
+ * @constructor
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec = function() {
+ /** @type {?glsDrawTests.DrawTestSpec.InputType} */ this.inputType = null;
+ /** @type {?glsDrawTests.DrawTestSpec.OutputType} */ this.outputType = null;
+ /** @type {?glsDrawTests.DrawTestSpec.Storage} */ this.storage = glsDrawTests.DrawTestSpec.Storage.BUFFER; //Always BUFFER in WebGL up to 2
+ /** @type {?glsDrawTests.DrawTestSpec.Usage} */ this.usage = null;
+ /** @type {number} */ this.componentCount = 0;
+ /** @type {number} */ this.offset = 0;
+ /** @type {number} */ this.stride = 0;
+ /** @type {boolean} */ this.normalize = false;
+ /** @type {number} */ this.instanceDivisor = 0; //!< used only if drawMethod = Draw*Instanced
+ /** @type {boolean} */ this.useDefaultAttribute = false;
+
+ /** @type {boolean} */ this.additionalPositionAttribute = false; //!< treat this attribute as position attribute. Attribute at index 0 is alway treated as such. False by default
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} inputType
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} outputType
+ * @param {?glsDrawTests.DrawTestSpec.Storage} storage
+ * @param {?glsDrawTests.DrawTestSpec.Usage} usage
+ * @param {number} componentCount
+ * @param {number} offset
+ * @param {number} stride
+ * @param {boolean} normalize
+ * @param {number} instanceDivisor
+ * @return {glsDrawTests.DrawTestSpec.AttributeSpec}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.createAttributeArray = function(inputType, outputType, storage, usage, componentCount,
+ offset, stride, normalize, instanceDivisor) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var spec;
+
+ spec.inputType = inputType;
+ spec.outputType = outputType;
+ spec.storage = storage;
+ spec.usage = usage;
+ spec.componentCount = componentCount;
+ spec.offset = offset;
+ spec.stride = stride;
+ spec.normalize = normalize;
+ spec.instanceDivisor = instanceDivisor;
+
+ spec.useDefaultAttribute = false;
+
+ return spec;
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.InputType} inputType
+ * @param {?glsDrawTests.DrawTestSpec.OutputType} outputType
+ * @param {number} componentCount
+ * @return {glsDrawTests.DrawTestSpec.AttributeSpec}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.createDefaultAttribute = function(inputType, outputType, componentCount) {
+ assertMsgOptions(inputType == glsDrawTests.DrawTestSpec.InputType.INT || inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT || inputType == glsDrawTests.DrawTestSpec.InputType.FLOAT, 'Invalid input type', false, true);
+ assertMsgOptions(inputType == glsDrawTests.DrawTestSpec.InputType.FLOAT || componentCount == 4, 'If not float, input type should have 4 components', false, true);
+
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var spec;
+
+ spec.inputType = inputType;
+ spec.outputType = outputType;
+ spec.storage = glsDrawTests.DrawTestSpec.Storage.BUFFER; //Always BUFFER in WebGL up to 2
+ spec.usage = null;
+ spec.componentCount = componentCount;
+ spec.offset = 0;
+ spec.stride = 0;
+ spec.normalize = false;
+ spec.instanceDivisor = 0;
+
+ spec.useDefaultAttribute = true;
+
+ return spec;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.prototype.hash = function() {
+ if (this.useDefaultAttribute) {
+ return 1 * this.inputType + 7 * this.outputType + 13 * this.componentCount;
+ } else {
+ return 1 * this.inputType + 2 * this.outputType + 3 * this.storage + 5 * this.usage + 7 * this.componentCount + 11 * this.offset + 13 * this.stride + 17 * (this.normalize ? 0 : 1) + 19 * this.instanceDivisor;
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.prototype.valid = function(/*ctxType*/) {
+ /** @type {boolean} */ var inputTypeFloat = this.inputType == glsDrawTests.DrawTestSpec.InputType.FLOAT || this.inputType == glsDrawTests.DrawTestSpec.InputType.HALF;
+ /** @type {boolean} */ var inputTypeUnsignedInteger = this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_BYTE || this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_SHORT || this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT || this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10;
+ /** @type {boolean} */ var inputTypeSignedInteger = this.inputType == glsDrawTests.DrawTestSpec.InputType.BYTE || this.inputType == glsDrawTests.DrawTestSpec.InputType.SHORT || this.inputType == glsDrawTests.DrawTestSpec.InputType.INT || this.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10;
+ /** @type {boolean} */ var inputTypePacked = this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10 || this.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10;
+
+ /** @type {boolean} */ var outputTypeFloat = this.outputType == glsDrawTests.DrawTestSpec.OutputType.FLOAT || this.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC2 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC3 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC4;
+ /** @type {boolean} */ var outputTypeSignedInteger = this.outputType == glsDrawTests.DrawTestSpec.OutputType.INT || this.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC2 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC3 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC4;
+ /** @type {boolean} */ var outputTypeUnsignedInteger = this.outputType == glsDrawTests.DrawTestSpec.OutputType.UINT || this.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC2 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC3 || this.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC4;
+
+ if (this.useDefaultAttribute) {
+ if (this.inputType != glsDrawTests.DrawTestSpec.InputType.INT && this.inputType != glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT && this.inputType != glsDrawTests.DrawTestSpec.InputType.FLOAT)
+ return false;
+
+ if (this.inputType != glsDrawTests.DrawTestSpec.InputType.FLOAT && this.componentCount != 4)
+ return false;
+
+ // no casting allowed (undefined results)
+ if (this.inputType == glsDrawTests.DrawTestSpec.InputType.INT && !outputTypeSignedInteger)
+ return false;
+ if (this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT && !outputTypeUnsignedInteger)
+ return false;
+ }
+
+ if (inputTypePacked && this.componentCount != 4)
+ return false;
+
+ // Invalid conversions:
+
+ // float -> [u]int
+ if (inputTypeFloat && !outputTypeFloat)
+ return false;
+
+ // uint -> int (undefined results)
+ if (inputTypeUnsignedInteger && outputTypeSignedInteger)
+ return false;
+
+ // int -> uint (undefined results)
+ if (inputTypeSignedInteger && outputTypeUnsignedInteger)
+ return false;
+
+ // packed -> non-float (packed formats are converted to floats)
+ if (inputTypePacked && !outputTypeFloat)
+ return false;
+
+ // Invalid normalize. Normalize is only valid if output type is float
+ if (this.normalize && !outputTypeFloat)
+ return false;
+
+ return true;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.prototype.isBufferAligned = function() {
+ var inputTypePacked = this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10 || this.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10;
+
+ // Buffer alignment, offset is a multiple of underlying data type size?
+ if (this.storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ var dataTypeSize = glsDrawTests.DrawTestSpec.inputTypeSize(this.inputType);
+ if (inputTypePacked)
+ dataTypeSize = 4;
+
+ if (this.offset % dataTypeSize != 0)
+ return false;
+ }
+
+ return true;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsDrawTests.DrawTestSpec.AttributeSpec.prototype.isBufferStrideAligned = function() {
+ var inputTypePacked = this.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10 || this.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10;
+
+ // Buffer alignment, offset is a multiple of underlying data type size?
+ if (this.storage == glsDrawTests.DrawTestSpec.Storage.BUFFER) {
+ var dataTypeSize = glsDrawTests.DrawTestSpec.inputTypeSize(this.inputType);
+ if (inputTypePacked)
+ dataTypeSize = 4;
+
+ if (this.stride % dataTypeSize != 0)
+ return false;
+ }
+
+ return true;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {glsDrawTests.DrawTestSpec} spec
+ * @param {string} name
+ * @param {string} desc
+ */
+ glsDrawTests.DrawTest = function(spec, name, desc) {
+ tcuTestCase.DeqpTest.call(this, name, desc, spec);
+
+ /** @type {WebGL2RenderingContext} */ this.m_renderCtx = gl;
+ /** @type {tcuPixelFormat.PixelFormat} */ this.m_pixelformat = new tcuPixelFormat.PixelFormat(
+ /** @type {number} */ (gl.getParameter(gl.RED_BITS)), /** @type {number} */ (gl.getParameter(gl.GREEN_BITS)),
+ /** @type {number} */ (gl.getParameter(gl.BLUE_BITS)), /** @type {number} */ (gl.getParameter(gl.ALPHA_BITS))
+ );
+
+ /** @type {sglrReferenceContext.ReferenceContextBuffers} */ this.m_refBuffers = null;
+ /** @type {sglrReferenceContext.ReferenceContext} */ this.m_refContext = null;
+ /** @type {sglrGLContext.GLContext} */ this.m_glesContext = null;
+
+ /** @type {glsDrawTests.AttributePack} */ this.m_glArrayPack = null;
+ /** @type {glsDrawTests.AttributePack} */ this.m_rrArrayPack = null;
+
+ /** @type {number} */ this.m_maxDiffRed = -1;
+ /** @type {number} */ this.m_maxDiffGreen = -1;
+ /** @type {number} */ this.m_maxDiffBlue = -1;
+
+ /** @type {Array<glsDrawTests.DrawTestSpec>} */ this.m_specs = [];
+ /** @type {Array<string>} */this.m_iteration_descriptions = [];
+ /** @type {number} */ this.m_iteration = 0;
+
+ if (spec)
+ this.addIteration(spec);
+ };
+
+ glsDrawTests.DrawTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsDrawTests.DrawTest.prototype.constructor = glsDrawTests.DrawTest;
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec} spec
+ * @param {string=} description
+ */
+ glsDrawTests.DrawTest.prototype.addIteration = function(spec, description) {
+ // Validate spec
+ /** @type {boolean} */ var validSpec = spec.valid();
+
+ if (!validSpec)
+ return;
+
+ this.m_specs.push(spec);
+
+ if (description)
+ this.m_iteration_descriptions.push(description);
+ else
+ this.m_iteration_descriptions.push('');
+ };
+
+ /**
+ * init
+ */
+ glsDrawTests.DrawTest.prototype.init = function() {
+ var renderTargetWidth = Math.min(glsDrawTests.MAX_RENDER_TARGET_SIZE, gl.canvas.width);
+ var renderTargetHeight = Math.min(glsDrawTests.MAX_RENDER_TARGET_SIZE, gl.canvas.height);
+ /** @type {sglrReferenceContext.ReferenceContextLimits} */ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ /** @type {boolean} */ var useVao = true;
+
+ this.m_glesContext = new sglrGLContext.GLContext(gl);
+
+ assertMsgOptions(this.m_specs.length > 0, 'Specs is empty', false, true);
+
+ this.m_refBuffers = new sglrReferenceContext.ReferenceContextBuffers(this.m_pixelformat, 0, 0, renderTargetWidth, renderTargetHeight);
+ this.m_refContext = new sglrReferenceContext.ReferenceContext(limits, this.m_refBuffers.getColorbuffer(), this.m_refBuffers.getDepthbuffer(), this.m_refBuffers.getStencilbuffer());
+
+ this.m_glArrayPack = new glsDrawTests.AttributePack(this.m_glesContext, [renderTargetWidth, renderTargetHeight], useVao, true);
+ this.m_rrArrayPack = new glsDrawTests.AttributePack(this.m_refContext, [renderTargetWidth, renderTargetHeight], useVao, false);
+
+ this.m_maxDiffRed = Math.ceil(256.0 * (15.0 / (1 << this.m_pixelformat.redBits)));
+ this.m_maxDiffGreen = Math.ceil(256.0 * (15.0 / (1 << this.m_pixelformat.greenBits)));
+ this.m_maxDiffBlue = Math.ceil(256.0 * (15.0 / (1 << this.m_pixelformat.blueBits)));
+ };
+
+ /**
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsDrawTests.DrawTest.prototype.iterate = function() {
+ var specNdx = Math.floor(this.m_iteration / 2);
+ var drawStep = (this.m_iteration % 2) == 0;
+ var compareStep = (this.m_iteration % 2) == 1;
+ /** @type {tcuTestCase.IterateResult} */ var iterateResult = (this.m_iteration + 1 == this.m_specs.length * 2) ? (tcuTestCase.IterateResult.STOP) : (tcuTestCase.IterateResult.CONTINUE);
+ /** @type {glsDrawTests.DrawTestSpec} */ var spec = this.m_specs[specNdx];
+ var updateProgram = (this.m_iteration == 0) || (drawStep && !glsDrawTests.checkSpecsShaderCompatible(this.m_specs[specNdx], this.m_specs[specNdx - 1])); // try to use the same shader in all iterations
+
+ if (drawStep && this.m_specs.length != 1)
+ debug('Iteration ' + specNdx + ' of ' + (this.m_specs.length - 1) + ': ' + this.m_iteration_descriptions[specNdx]);
+
+ this.m_iteration++;
+
+ if (drawStep) {
+ /** @type {glsDrawTests.MethodInfo} */ var methodInfo = glsDrawTests.getMethodInfo(spec.drawMethod);
+ /** @type {boolean} */ var indexed = methodInfo.indexed;
+ /** @type {boolean} */ var instanced = methodInfo.instanced;
+ /** @type {boolean} */ var ranged = methodInfo.ranged;
+ /** @type {boolean} */ var hasFirst = methodInfo.first;
+
+ /** @type {number} */ var primitiveElementCount = glsDrawTests.getElementCount(spec.primitive, spec.primitiveCount); // !< elements to be drawn
+ /** @type {number} */ var indexMin = (ranged) ? (spec.indexMin) : (0);
+ /** @type {number} */ var firstAddition = (hasFirst) ? (spec.first) : (0);
+ /** @type {number} */ var elementCount = primitiveElementCount + indexMin + firstAddition; // !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements)
+ /** @type {number} */ var maxElementIndex = primitiveElementCount + indexMin + firstAddition - 1;
+ /** @type {number} */ var indexMax = Math.max(0, (ranged) ? (deMath.clamp(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex));
+ /** @type {number} */ var coordScale = this.getCoordScale(spec);
+ /** @type {number} */ var colorScale = this.getColorScale(spec);
+
+ /** @type {Array<number>} */ var nullAttribValue = [];
+
+ // Log info
+ bufferedLogToConsole(spec.getMultilineDesc());
+
+ // Data
+ this.m_glArrayPack.clearArrays();
+ this.m_rrArrayPack.clearArrays();
+
+ // indices
+ /** @type {number} */ var seed;
+ /** @type {number} */ var indexElementSize;
+ /** @type {number} */ var indexArraySize;
+ /** @type {goog.TypedArray} */ var indexArray;
+ /** @type {goog.TypedArray} */ var indexPointer;
+
+ /** @type {glsDrawTests.AttributeArray}*/ var glArray;
+ /** @type {glsDrawTests.AttributeArray}*/ var rrArray;
+
+ if (indexed) {
+ seed = spec.hash();
+ indexElementSize = glsDrawTests.DrawTestSpec.indexTypeSize(spec.indexType);
+ indexArraySize = spec.indexPointerOffset + indexElementSize * elementCount;
+ indexArray = glsDrawTests.RandomArrayGenerator.generateIndices(seed, elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax);
+ indexPointer = indexArray.subarray(spec.indexPointerOffset);
+
+ glArray = new glsDrawTests.AttributeArray(spec.indexStorage, this.m_glesContext);
+ rrArray = new glsDrawTests.AttributeArray(spec.indexStorage, this.m_refContext);
+
+ glArray.data(glsDrawTests.DrawTestSpec.Target.ELEMENT_ARRAY, indexArraySize, indexArray, glsDrawTests.DrawTestSpec.Usage.STATIC_DRAW);
+ rrArray.data(glsDrawTests.DrawTestSpec.Target.ELEMENT_ARRAY, indexArraySize, indexArray, glsDrawTests.DrawTestSpec.Usage.STATIC_DRAW);
+
+ indexArray = null;
+ }
+
+ // attributes
+ for (var attribNdx = 0; attribNdx < spec.attribs.length; attribNdx++) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var attribSpec = spec.attribs[attribNdx];
+ var isPositionAttr = (attribNdx == 0) || (attribSpec.additionalPositionAttribute);
+
+ if (attribSpec.useDefaultAttribute) {
+ seed = 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx;
+ /** @type {Array<number>} */ var attribValue = glsDrawTests.RandomArrayGenerator.generateAttributeValue(seed, attribSpec.inputType);
+
+ // changed USER for BUFFER in JS version
+ this.m_glArrayPack.newArray(glsDrawTests.DrawTestSpec.Storage.BUFFER);
+ this.m_rrArrayPack.newArray(glsDrawTests.DrawTestSpec.Storage.BUFFER);
+
+ this.m_glArrayPack.getArray(attribNdx).setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr);
+ this.m_rrArrayPack.getArray(attribNdx).setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr);
+ } else {
+ seed = attribSpec.hash() + 100 * spec.hash() + attribNdx;
+ /** @type {number} */ var elementSize = attribSpec.componentCount * glsDrawTests.DrawTestSpec.inputTypeSize(attribSpec.inputType);
+ /** @type {number} */ var stride = (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride);
+ /** @type {number} */ var evaluatedElementCount = (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount);
+ /** @type {number} */ var referencedElementCount = (ranged) ? (Math.max(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount);
+ /** @type {number} */ var bufferSize = attribSpec.offset + stride * (referencedElementCount - 1) + elementSize;
+ /** @type {goog.TypedArray} */ var data = glsDrawTests.RandomArrayGenerator.createArray(
+ seed,
+ referencedElementCount,
+ attribSpec.componentCount,
+ attribSpec.offset,
+ stride,
+ attribSpec.inputType,
+ indexed ? 0 : spec.first,
+ spec.primitive,
+ indexed ? indexPointer : null,
+ indexElementSize
+ );
+
+ this.m_glArrayPack.newArray(attribSpec.storage);
+ this.m_rrArrayPack.newArray(attribSpec.storage);
+
+ this.m_glArrayPack.getArray(attribNdx).data(glsDrawTests.DrawTestSpec.Target.ARRAY, bufferSize, data, attribSpec.usage);
+ this.m_rrArrayPack.getArray(attribNdx).data(glsDrawTests.DrawTestSpec.Target.ARRAY, bufferSize, data, attribSpec.usage);
+
+ this.m_glArrayPack.getArray(attribNdx).setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr);
+ this.m_rrArrayPack.getArray(attribNdx).setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr);
+
+ data = null;
+ }
+ }
+
+ // Shader program
+ if (updateProgram) {
+ this.m_glArrayPack.updateProgram();
+ this.m_rrArrayPack.updateProgram();
+ }
+
+ /** @type {glsDrawTests.DrawTestSpec.CompatibilityTestType} */ var ctype;
+
+ // Draw
+ try {
+ // indices
+ if (indexed) {
+ this.m_glArrayPack.render(spec.primitive, spec.drawMethod, 0, primitiveElementCount, spec.indexType, spec.indexPointerOffset, spec.indexMin, spec.indexMax, spec.instanceCount, coordScale, colorScale, glArray);
+ this.m_rrArrayPack.render(spec.primitive, spec.drawMethod, 0, primitiveElementCount, spec.indexType, spec.indexPointerOffset, spec.indexMin, spec.indexMax, spec.instanceCount, coordScale, colorScale, rrArray);
+ } else {
+ this.m_glArrayPack.render(spec.primitive, spec.drawMethod, spec.first, primitiveElementCount, null, 0, 0, 0, spec.instanceCount, coordScale, colorScale, null);
+ this.m_rrArrayPack.render(spec.primitive, spec.drawMethod, spec.first, primitiveElementCount, null, 0, 0, 0, spec.instanceCount, coordScale, colorScale, null);
+ }
+ } catch (err) {
+ if (err instanceof wtu.GLErrorException) {
+ // GL Errors are ok if the mode is not properly aligned
+ ctype = spec.isCompatibilityTest();
+
+ bufferedLogToConsole('Got error: ' + err.message);
+
+ if (ctype == glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_OFFSET)
+ checkMessage(false, 'Failed to draw with unaligned buffers.');
+ else if (ctype == glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_STRIDE)
+ checkMessage(false, 'Failed to draw with unaligned stride.');
+ else
+ throw err;
+ }
+ }
+ } else if (compareStep) {
+ if (!this.compare(spec.primitive)) {
+ ctype = spec.isCompatibilityTest();
+
+ if (ctype == glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_OFFSET)
+ checkMessage(false, 'Failed to draw with unaligned buffers.');
+ else if (ctype == glsDrawTests.DrawTestSpec.CompatibilityTestType.UNALIGNED_STRIDE)
+ checkMessage(false, 'Failed to draw with unaligned stride.');
+ else
+ testFailedOptions('Image comparison failed.', false);
+ return iterateResult;
+ }
+ } else {
+ testFailedOptions('Image comparison failed.', false);
+ return tcuTestCase.IterateResult.STOP;
+ }
+
+ if (iterateResult == tcuTestCase.IterateResult.STOP)
+ testPassed('');
+
+ return iterateResult;
+ };
+
+ /**
+ * @enum {number} PrimitiveClass
+ */
+ glsDrawTests.PrimitiveClass = {
+ POINT: 0,
+ LINE: 1,
+ TRIANGLE: 2
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitiveType
+ * @return {glsDrawTests.PrimitiveClass}
+ */
+ glsDrawTests.getDrawPrimitiveClass = function(primitiveType) {
+ switch (primitiveType) {
+ case glsDrawTests.DrawTestSpec.Primitive.POINTS:
+ return glsDrawTests.PrimitiveClass.POINT;
+
+ case glsDrawTests.DrawTestSpec.Primitive.LINES:
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_STRIP:
+ case glsDrawTests.DrawTestSpec.Primitive.LINE_LOOP:
+ return glsDrawTests.PrimitiveClass.LINE;
+
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLES:
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_FAN:
+ case glsDrawTests.DrawTestSpec.Primitive.TRIANGLE_STRIP:
+ return glsDrawTests.PrimitiveClass.TRIANGLE;
+
+ default:
+ throw new Error('Invalid primitive type');
+ }
+ };
+
+ /**
+ * @param {number} c1
+ * @param {number} c2
+ * @param {Array<number>} threshold
+ * @return {boolean}
+ */
+ glsDrawTests.compareUintRGB8 = function(c1, c2, threshold) {
+ return (Math.abs(((c1 >> 16) & 0xff) - ((c2 >> 16) & 0xff)) <= threshold[0] && // Red
+ Math.abs(((c1 >> 8) & 0xff) - ((c2 >> 8) & 0xff)) <= threshold[1] && // Green
+ Math.abs((c1 & 0xff) - (c2 & 0xff)) <= threshold[2]); // Blue
+ };
+
+ /**
+ * @param {number} c1
+ * @param {number} c2
+ * @param {number} c3
+ * @param {number} renderTargetDifference
+ * @return {boolean}
+ */
+ glsDrawTests.isEdgeTripletComponent = function(c1, c2, c3, renderTargetDifference) {
+ /** @type {number} */ var roundingDifference = 2 * renderTargetDifference; // src and dst pixels rounded to different directions
+ /** @type {number} */ var d1 = c2 - c1;
+ /** @type {number} */ var d2 = c3 - c2;
+ /** @type {number} */ var rampDiff = Math.abs(d2 - d1);
+
+ return rampDiff > roundingDifference;
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} c1
+ * @param {tcuRGBA.RGBA} c2
+ * @param {tcuRGBA.RGBA} c3
+ * @param {Array<number>} renderTargetThreshold
+ * @return {boolean}
+ */
+ glsDrawTests.isEdgeTriplet = function(c1, c2, c3, renderTargetThreshold) {
+ // black (background color) and non-black is always an edge
+ /** @type {boolean} */ var b1 = c1 == 0x000000;
+ /** @type {boolean} */ var b2 = c2 == 0x000000;
+ /** @type {boolean} */ var b3 = c3 == 0x000000;
+
+ // both pixels with coverage and pixels without coverage
+ if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true)
+ return true;
+ // all black
+ if (b1 && b2 && b3)
+ return false;
+ // all with coverage
+ assertMsgOptions(!b1 && !b2 && !b3, 'All colors with coverage', false, true);
+
+ // Color is always linearly interpolated => component values change nearly linearly
+ // in any constant direction on triangle hull. (df/dx ~= C).
+
+ // Edge detection (this function) is run against the reference image
+ // => no dithering to worry about
+
+ return glsDrawTests.isEdgeTripletComponent((c1 >> 16) && 0xff, (c2 >> 16) && 0xff, (c3 >> 16) && 0xff, renderTargetThreshold[0]) ||
+ glsDrawTests.isEdgeTripletComponent((c1 >> 8) && 0xff, (c2 >> 8) && 0xff, (c3 >> 8) && 0xff, renderTargetThreshold[1]) ||
+ glsDrawTests.isEdgeTripletComponent(c1 && 0xff, c2 && 0xff, c3 && 0xff, renderTargetThreshold[2]);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {tcuSurface.Surface} ref
+ * @param {Array<number>} renderTargetThreshold
+ * @return {boolean}
+ */
+ glsDrawTests.pixelNearEdge = function(x, y, ref, renderTargetThreshold) {
+ // should not be called for edge pixels
+ assertMsgOptions(x >= 1 && x <= ref.getWidth() - 2, 'The pixel was on the edge', false, true);
+ assertMsgOptions(y >= 1 && y <= ref.getHeight() - 2, 'The pixel was on the edge', false, true);
+
+ // horizontal
+
+ /** @type {number} */ var c1;
+ /** @type {number} */ var c2;
+ /** @type {number} */ var c3;
+
+ for (var dy = -1; dy < 2; ++dy) {
+ c1 = ref.getPixelUintRGB8(x - 1, y + dy);
+ c2 = ref.getPixelUintRGB8(x, y + dy);
+ c3 = ref.getPixelUintRGB8(x + 1, y + dy);
+ if (glsDrawTests.isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
+ return true;
+ }
+
+ // vertical
+
+ for (var dx = -1; dx < 2; ++dx) {
+ c1 = ref.getPixelUintRGB8(x + dx, y - 1);
+ c2 = ref.getPixelUintRGB8(x + dx, y);
+ c3 = ref.getPixelUintRGB8(x + dx, y + 1);
+ if (glsDrawTests.isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {number} c
+ * @return {number}
+ */
+ glsDrawTests.getVisualizationGrayscaleColorUintRGB8 = function(c) {
+ // make triangle coverage and error pixels obvious by converting coverage to grayscale
+ if (c == 0x000000)
+ return 0;
+ else
+ return 50 + Math.floor((((c >> 16) & 0xff) + ((c >> 8) & 0xff) + (c & 0xff)) / 8);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {tcuSurface.Surface} target
+ * @return {boolean}
+ */
+ glsDrawTests.pixelNearLineIntersection = function(x, y, target) {
+ // should not be called for edge pixels
+ assertMsgOptions(x >= 1 && x <= target.getWidth() - 2, 'Pixel is in the edge', false, true);
+ assertMsgOptions(y >= 1 && y <= target.getHeight() - 2, 'Pixel is in the edge', false, true);
+
+ var coveredPixels = 0;
+
+ for (var dy = -1; dy < 2; dy++)
+ for (var dx = -1; dx < 2; dx++) {
+ var targetCoverage = target.getPixelUintRGB8(x + dx, y + dy);
+ if (targetCoverage) {
+ ++coveredPixels;
+
+ // A single thin line cannot have more than 3 covered pixels in a 3x3 area
+ if (coveredPixels >= 4)
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ // search 3x3 are for matching color
+ /**
+ * @param {tcuSurface.Surface} target
+ * @param {number} x
+ * @param {number} y
+ * @param {tcuRGBA.RGBA} color
+ * @param {Array<number>} compareThreshold
+ * @return {boolean}
+ */
+ glsDrawTests.pixelNeighborhoodContainsColor = function(target, x, y, color, compareThreshold) {
+ // should not be called for edge pixels
+ assertMsgOptions(x >= 1 && x <= target.getWidth() - 2, 'Pixel is in the edge', false, true);
+ assertMsgOptions(y >= 1 && y <= target.getHeight() - 2, 'Pixel is in the edge', false, true);
+
+ for (var dy = -1; dy < 2; dy++)
+ for (var dx = -1; dx < 2; dx++) {
+ if (glsDrawTests.compareUintRGB8(color, target.getPixelUintRGB8(x + dx, y + dy), compareThreshold))
+ return true;
+ }
+
+ return false;
+ };
+
+ // search 3x3 are for matching coverage (coverage == (color != background color))
+ /**
+ * @param {tcuSurface.Surface} target
+ * @param {number} x
+ * @param {number} y
+ * @param {boolean} coverage
+ * @return {boolean}
+ */
+ glsDrawTests.pixelNeighborhoodContainsCoverage = function(target, x, y, coverage) {
+ // should not be called for edge pixels
+ assertMsgOptions(x >= 1 && x <= target.getWidth() - 2, 'Pixel is in the edge', false, true);
+ assertMsgOptions(y >= 1 && y <= target.getHeight() - 2, 'Pixel is in the edge', false, true);
+
+ for (var dy = -1; dy < 2; dy++)
+ for (var dx = -1; dx < 2; dx++) {
+ var targetCmpCoverage = target.getPixelUintRGB8(x + dx, y + dy) != 0x000000; // Pixel is not black
+ if (targetCmpCoverage == coverage)
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {string} imageSetName
+ * @param {string} imageSetDesc
+ * @param {tcuSurface.Surface} reference
+ * @param {tcuSurface.Surface} result
+ * @param {Array<number>} compareThreshold
+ * @param {Array<number>} renderTargetThreshold
+ * @param {number} maxAllowedInvalidPixels
+ * @return {boolean}
+ */
+ glsDrawTests.edgeRelaxedImageCompare = function(imageSetName, imageSetDesc, reference, result, compareThreshold, renderTargetThreshold, maxAllowedInvalidPixels) {
+ assertMsgOptions(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight(), 'Reference and result images have different dimensions', false, true);
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ /** @type {Array<number>} */ var errorColor = [255, 0, 0, 255];
+ /** @type {number} */ var width = reference.getWidth();
+ /** @type {number} */ var height = reference.getHeight();
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height);
+ /** @type {number} */ var numFailingPixels = 0;
+
+ // clear errormask edges which would otherwise be transparent
+
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, 0, 0, width, 1, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, height - 1, 0, width, 1, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, 0, 0, 1, height, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), width - 1, 0, 0, 1, height, 1).clear(green);
+
+ // skip edge pixels since coverage on edge cannot be verified
+
+ for (var y = 1; y < height - 1; ++y)
+ for (var x = 1; x < width - 1; ++x) {
+ /** @type {number} */ var refPixel = reference.getPixelUintRGB8(x, y);
+ /** @type {number} */ var screenPixel = result.getPixelUintRGB8(x, y);
+ /** @type {boolean} */ var isOkReferencePixel = glsDrawTests.pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold); // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
+ /** @type {boolean} */ var isOkScreenPixel = glsDrawTests.pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold); // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
+
+ if (isOkScreenPixel && isOkReferencePixel) {
+ // pixel valid, write greenish pixels to make the result image easier to read
+ /** @type {number} */ var grayscaleValue = glsDrawTests.getVisualizationGrayscaleColorUintRGB8(screenPixel);
+ errorMask.getAccess().setPixel([grayscaleValue / 255, 1, grayscaleValue / 255, 1], x, y);
+ } else if (!glsDrawTests.pixelNearEdge(x, y, reference, renderTargetThreshold)) {
+ // non-edge pixel values must be within threshold of the reference values
+ errorMask.getAccess().setPixel(deMath.scale(errorColor, 1 / 255), x, y);
+ ++numFailingPixels;
+ } else {
+ // we are on/near an edge, verify only coverage (coverage == not background colored)
+ /** @type {boolean} */ var referenceCoverage = refPixel != 0x000000; // Not black
+ /** @type {boolean} */ var screenCoverage = screenPixel != 0x000000; // Not black
+ /** @type {boolean} */ var isOkReferenceCoverage = glsDrawTests.pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel
+ /** @type {boolean} */ var isOkScreenCoverage = glsDrawTests.pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel
+
+ if (isOkScreenCoverage && isOkReferenceCoverage) {
+ // pixel valid, write greenish pixels to make the result image easier to read
+ var grayscaleValue = glsDrawTests.getVisualizationGrayscaleColorUintRGB8(screenPixel);
+ errorMask.getAccess().setPixel([grayscaleValue / 255, 1, grayscaleValue / 255, 1], x, y);
+ } else {
+ // coverage does not match
+ errorMask.getAccess().setPixel(deMath.scale(errorColor, 1 / 255), x, y);
+ ++numFailingPixels;
+ }
+ }
+ }
+
+ bufferedLogToConsole(
+ 'Comparing images:</br>' +
+ '<span> </span>allowed deviation in pixel positions = 1</br>' +
+ '<span> </span>number of allowed invalid pixels = ' + maxAllowedInvalidPixels + '</br>' +
+ '<span> </span>number of invalid pixels = ' + numFailingPixels
+ );
+
+ if (numFailingPixels > maxAllowedInvalidPixels) {
+ debug('Image comparison failed. Color threshold = (' + compareThreshold[0] + ', ' + compareThreshold[1] + ', ' + compareThreshold[2] + ')');
+ tcuImageCompare.displayImages(result.getAccess(), reference.getAccess(), errorMask.getAccess());
+
+ return false;
+ } else {
+ return true;
+ }
+ };
+
+ /**
+ * @param {string} imageSetName
+ * @param {string} imageSetDesc
+ * @param {tcuSurface.Surface} reference
+ * @param {tcuSurface.Surface} result
+ * @param {Array<number>} compareThreshold
+ * @param {number} maxAllowedInvalidPixels
+ * @return {boolean}
+ */
+ glsDrawTests.intersectionRelaxedLineImageCompare = function(imageSetName, imageSetDesc, reference, result, compareThreshold, maxAllowedInvalidPixels) {
+ assertMsgOptions(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight(), 'Reference and result images have different dimensions', false, true);
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ /** @type {Array<number>} */ var errorColor = [255, 0, 0, 255];
+ var width = reference.getWidth();
+ var height = reference.getHeight();
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height);
+ /** @type {number} */ var numFailingPixels = 0;
+
+ // clear errormask edges which would otherwise be transparent
+
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, 0, 0, width, 1, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, height - 1, 0, width, 1, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), 0, 0, 0, 1, height, 1).clear(green);
+ tcuTextureUtil.getSubregion(errorMask.getAccess(), width - 1, 0, 0, 1, height, 1).clear(green);
+
+ // skip edge pixels since coverage on edge cannot be verified
+
+ for (var y = 1; y < height - 1; ++y)
+ for (var x = 1; x < width - 1; ++x) {
+ /** @type {number} */ var refPixel = reference.getPixelUintRGB8(x, y);
+ /** @type {number} */ var screenPixel = result.getPixelUintRGB8(x, y);
+ /** @type {boolean} */ var isOkScreenPixel = glsDrawTests.pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold); // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
+ /** @type {boolean} */ var isOkReferencePixel = glsDrawTests.pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold); // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
+
+ /** @type {number} */ var grayscaleValue;
+
+ if (isOkScreenPixel && isOkReferencePixel) {
+ // pixel valid, write greenish pixels to make the result image easier to read
+ grayscaleValue = glsDrawTests.getVisualizationGrayscaleColorUintRGB8(screenPixel);
+ errorMask.getAccess().setPixel([grayscaleValue / 255, 1, grayscaleValue / 255, 1], x, y);
+ } else if (!glsDrawTests.pixelNearLineIntersection(x, y, reference) &&
+ !glsDrawTests.pixelNearLineIntersection(x, y, result)) {
+ // non-intersection pixel values must be within threshold of the reference values
+ errorMask.getAccess().setPixel(deMath.scale(errorColor, 1 / 255), x, y);
+ ++numFailingPixels;
+ } else {
+ // pixel is near a line intersection
+ // we are on/near an edge, verify only coverage (coverage == not background colored)
+ /** @type {boolean} */ var referenceCoverage = refPixel != 0x000000; // Not Black
+ /** @type {boolean} */ var screenCoverage = screenPixel != 0x000000; // Not Black
+ /** @type {boolean} */ var isOkScreenCoverage = glsDrawTests.pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel
+ /** @type {boolean} */ var isOkReferenceCoverage = glsDrawTests.pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel
+
+ if (isOkScreenCoverage && isOkReferenceCoverage) {
+ // pixel valid, write greenish pixels to make the result image easier to read
+ grayscaleValue = glsDrawTests.getVisualizationGrayscaleColorUintRGB8(screenPixel);
+ errorMask.getAccess().setPixel([grayscaleValue / 255, 1, grayscaleValue / 255, 1], x, y);
+ } else {
+ // coverage does not match
+ errorMask.getAccess().setPixel(deMath.scale(errorColor, 1 / 255), x, y);
+ ++numFailingPixels;
+ }
+ }
+ }
+
+ bufferedLogToConsole(
+ 'Comparing images:</br>' +
+ '<span> </span>allowed deviation in pixel positions = 1</br>' +
+ '<span> </span>number of allowed invalid pixels = ' + maxAllowedInvalidPixels + '</br>' +
+ '<span> </span>number of invalid pixels = ' + numFailingPixels
+ );
+
+ if (numFailingPixels > maxAllowedInvalidPixels) {
+ debug('Image comparison failed. Color threshold = (' + compareThreshold[0] + ', ' + compareThreshold[1] + ', ' + compareThreshold[2] + ')');
+ tcuImageCompare.displayImages(result.getAccess(), reference.getAccess(), errorMask.getAccess());
+
+ return false;
+ } else {
+ return true;
+ }
+ };
+
+ /**
+ * @param {?glsDrawTests.DrawTestSpec.Primitive} primitiveType
+ * @return {boolean}
+ */
+ glsDrawTests.DrawTest.prototype.compare = function(primitiveType) {
+ /** @type {tcuSurface.Surface} */ var ref = this.m_rrArrayPack.getSurface();
+ /** @type {tcuSurface.Surface} */ var screen = this.m_glArrayPack.getSurface();
+
+ if (/** @type {number} */ (gl.getParameter(gl.SAMPLES)) > 1) {
+ // \todo [mika] Improve compare when using multisampling
+ bufferedLogToConsole('Warning: Comparision of result from multisample render targets are not as strict as without multisampling. Might produce false positives!');
+ return tcuImageCompare.fuzzyCompare('Compare Results', 'Compare Results', ref.getAccess(), screen.getAccess(), 0.3, tcuImageCompare.CompareLogMode.RESULT);
+ } else {
+ /** @type {glsDrawTests.PrimitiveClass} */ var primitiveClass = glsDrawTests.getDrawPrimitiveClass(primitiveType);
+
+ switch (primitiveClass) {
+ case glsDrawTests.PrimitiveClass.POINT: {
+ // Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels
+ /**@type {number} */ var maxAllowedInvalidPixelsWithPoints = 0;
+ return tcuImageCompare.intThresholdPositionDeviationErrorThresholdCompare(
+ 'CompareResult',
+ 'Result of rendering',
+ ref.getAccess(),
+ screen.getAccess(),
+ [this.m_maxDiffRed, this.m_maxDiffGreen, this.m_maxDiffBlue, 256],
+ [1, 1, 0], //!< 3x3 search kernel
+ true, //!< relax comparison on the image boundary
+ maxAllowedInvalidPixelsWithPoints //!< error threshold
+ );
+ }
+
+ case glsDrawTests.PrimitiveClass.LINE: {
+ // Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce
+ // false negatives in such pixels if for example the pixel in question is overdrawn by another line in the
+ // reference image but not in the resultin image. Relax comparison near line intersection points (areas) and
+ // compare only coverage, not color, in such pixels
+ /**@type {number} */ var maxAllowedInvalidPixelsWithLines = 15; // line are allowed to have a few bad pixels
+ return glsDrawTests.intersectionRelaxedLineImageCompare(
+ 'CompareResult',
+ 'Result of rendering',
+ ref,
+ screen,
+ [this.m_maxDiffRed, this.m_maxDiffGreen, this.m_maxDiffBlue],
+ maxAllowedInvalidPixelsWithLines
+ );
+ }
+
+ case glsDrawTests.PrimitiveClass.TRIANGLE: {
+ // Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels
+ // where there could be potential overlapping since the pixels might be covered by one triangle in the
+ // reference image and by the other in the result image. Relax comparsion near primitive edges and
+ // compare only coverage, not color, in such pixels.
+ /** @type {number} */ var maxAllowedInvalidPixelsWithTriangles = 10;
+
+ /* TODO: Implement
+ var renderTargetThreshold = //TODO: get color threshold from the pixel format --> m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz();
+ */
+
+ /** @type {Array<number>} */ var renderTargetThreshold = [3, 3, 3, 3];
+
+ return glsDrawTests.edgeRelaxedImageCompare(
+ 'CompareResult',
+ 'Result of rendering',
+ ref,
+ screen,
+ [this.m_maxDiffRed, this.m_maxDiffGreen, this.m_maxDiffBlue],
+ renderTargetThreshold,
+ maxAllowedInvalidPixelsWithTriangles
+ );
+ }
+
+ default:
+ throw new Error('Invalid primitive class');
+ }
+ }
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec} spec
+ * @return {number}
+ */
+ glsDrawTests.DrawTest.prototype.getCoordScale = function(spec) {
+ var maxValue = 1.0;
+
+ for (var arrayNdx = 0; arrayNdx < spec.attribs.length; arrayNdx++) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var attribSpec = spec.attribs[arrayNdx];
+ /** @type {boolean} */ var isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
+ /** @type {number} */ var attrMaxValue = 0;
+
+ if (!isPositionAttr)
+ continue;
+
+ if (attribSpec.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10) {
+ if (attribSpec.normalize)
+ attrMaxValue += 1.0;
+ else
+ attrMaxValue += 1024.0;
+ } else if (attribSpec.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10) {
+ if (attribSpec.normalize)
+ attrMaxValue += 1.0;
+ else
+ attrMaxValue += 512.0;
+ } else {
+ var max = glsDrawTests.GLValue.getMaxValue(attribSpec.inputType).getValue();
+
+ attrMaxValue += (attribSpec.normalize && !glsDrawTests.inputTypeIsFloatType(attribSpec.inputType)) ? (1.0) : (max * 1.1);
+ }
+
+ if (attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC3 || attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC4 ||
+ attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC3 || attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC4 ||
+ attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC3 || attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC4)
+ attrMaxValue *= 2;
+
+ maxValue += attrMaxValue;
+ }
+
+ return 1.0 / maxValue;
+ };
+
+ /**
+ * @param {glsDrawTests.DrawTestSpec} spec
+ * @return {number}
+ */
+ glsDrawTests.DrawTest.prototype.getColorScale = function(spec) {
+ var colorScale = 1.0;
+
+ for (var arrayNdx = 1; arrayNdx < spec.attribs.length; arrayNdx++) {
+ /** @type {glsDrawTests.DrawTestSpec.AttributeSpec} */ var attribSpec = spec.attribs[arrayNdx];
+ /** @type {boolean} */ var isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
+
+ if (isPositionAttr)
+ continue;
+
+ if (attribSpec.inputType == glsDrawTests.DrawTestSpec.InputType.UNSIGNED_INT_2_10_10_10) {
+ if (!attribSpec.normalize)
+ colorScale *= 1.0 / 1024.0;
+ } else if (attribSpec.inputType == glsDrawTests.DrawTestSpec.InputType.INT_2_10_10_10) {
+ if (!attribSpec.normalize)
+ colorScale *= 1.0 / 512.0;
+ } else {
+ var max = glsDrawTests.GLValue.getMaxValue(attribSpec.inputType).toFloat();
+
+ colorScale *= (attribSpec.normalize && !glsDrawTests.inputTypeIsFloatType(attribSpec.inputType) ? 1.0 : (1.0 / max));
+ if (attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.VEC4 ||
+ attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.UVEC4 ||
+ attribSpec.outputType == glsDrawTests.DrawTestSpec.OutputType.IVEC4)
+ colorScale *= (attribSpec.normalize && !glsDrawTests.inputTypeIsFloatType(attribSpec.inputType) ? 1.0 : 1.0 / max);
+ }
+ }
+
+ return colorScale;
+ };
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboCompletenessTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboCompletenessTests.js
new file mode 100644
index 000000000..c0f59c209
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboCompletenessTests.js
@@ -0,0 +1,961 @@
+'use strict';
+goog.provide('modules.shared.glsFboCompletenessTests');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluObjectWrapper');
+goog.require('framework.opengl.gluStrUtil');
+goog.require('modules.shared.glsFboUtil');
+
+goog.scope(function() {
+
+ var glsFboCompletenessTests = modules.shared.glsFboCompletenessTests;
+ var glsFboUtil = modules.shared.glsFboUtil;
+ var gluObjectWrapper = framework.opengl.gluObjectWrapper;
+ var gluStrUtil = framework.opengl.gluStrUtil;
+ var tcuTestCase = framework.common.tcuTestCase;
+
+ /**
+ * @param {WebGL2RenderingContext} gl
+ */
+ glsFboCompletenessTests.initGlDependents = function(gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ // The following extensions are applicable both to ES2 and ES3.
+ /**
+ * OES_depth_texture
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesDepthTextureFormats = [
+ glsFboUtil.formatkey(gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT),
+ glsFboUtil.formatkey(gl.DEPTH_COMPONENT, gl.UNSIGNED_INT)
+ ];
+
+ /**
+ * OES_packed_depth_stencil
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesPackedDepthStencilSizedFormats = [
+ gl.DEPTH24_STENCIL8
+ ];
+
+ /**
+ * s_oesPackedDepthStencilTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesPackedDepthStencilTexFormats = [
+ glsFboUtil.formatkey(gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8)
+ ];
+
+ /**
+ * OES_required_internalformat
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRequiredInternalFormatColorFormats = [
+ // Same as ES2 RBO formats, plus RGBA8 (even without OES_rgb8_rgba8)
+ gl.RGB5_A1, gl.RGBA8, gl.RGBA4, gl.RGB565
+ ];
+
+ /**
+ * s_oesRequiredInternalFormatDepthFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRequiredInternalFormatDepthFormats = [
+ gl.DEPTH_COMPONENT16
+ ];
+
+ /**
+ * EXT_color_buffer_half_float
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extColorBufferHalfFloatFormats = [
+ gl.RGBA16F, gl.RGB16F, gl.RG16F, gl.R16F
+ ];
+
+ /**
+ * s_oesDepth24SizedFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesDepth24SizedFormats = [
+ gl.DEPTH_COMPONENT24
+ ];
+
+ /**
+ * s_oesDepth32SizedFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesDepth32SizedFormats = [
+ gl['DEPTH_COMPONENT32']
+ ];
+
+ /**
+ * s_oesRgb8Rgba8RboFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRgb8Rgba8RboFormats = [
+ gl.RGB8, gl.RGBA8
+ ];
+
+ /**
+ * s_oesRequiredInternalFormatRgb8ColorFormat
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRequiredInternalFormatRgb8ColorFormat = [
+ gl.RGB8
+ ];
+
+ /**
+ * s_extTextureType2101010RevFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extTextureType2101010RevFormats = [
+ glsFboUtil.formatkey(gl.RGBA, gl.UNSIGNED_INT_2_10_10_10_REV),
+ glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_INT_2_10_10_10_REV)
+ ];
+
+ /**
+ * s_oesRequiredInternalFormat10bitColorFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRequiredInternalFormat10bitColorFormats = [
+ gl.RGB10_A2, gl['RGB10']
+ ];
+
+ /**
+ * s_extTextureRgRboFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extTextureRgRboFormats = [
+ gl.R8, gl.RG8
+ ];
+
+ /**
+ * s_extTextureRgTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extTextureRgTexFormats = [
+ glsFboUtil.formatkey(gl.RED, gl.UNSIGNED_BYTE),
+ glsFboUtil.formatkey(gl.RG, gl.UNSIGNED_BYTE)
+ ];
+
+ /**
+ * s_extTextureRgFloatTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extTextureRgFloatTexFormats = [
+ glsFboUtil.formatkey(gl.RED, gl.FLOAT),
+ glsFboUtil.formatkey(gl.RG, gl.FLOAT)
+ ];
+
+ /**
+ * s_extTextureRgHalfFloatTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extTextureRgHalfFloatTexFormats = [
+ glsFboUtil.formatkey(gl.RED, gl['HALF_FLOAT_OES']),
+ glsFboUtil.formatkey(gl.RG, gl['HALF_FLOAT_OES'])
+ ];
+
+ /**
+ * s_nvPackedFloatRboFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_nvPackedFloatRboFormats = [
+ gl.R11F_G11F_B10F
+ ];
+
+ /**
+ * s_nvPackedFloatTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_nvPackedFloatTexFormats = [
+ glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_INT_10F_11F_11F_REV)
+ ];
+
+ /**
+ * s_extSrgbRboFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extSrgbRboFormats = [
+ gl.SRGB8_ALPHA8
+ ];
+
+ /**
+ * s_extSrgbRenderableTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extSrgbRenderableTexFormats = [
+ glsFboUtil.formatkey(gl['SRGB_ALPHA'], gl.UNSIGNED_BYTE)
+ ];
+
+ /**
+ * s_extSrgbNonRenderableTexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_extSrgbNonRenderableTexFormats = [
+ glsFboUtil.formatkey(gl.SRGB, gl.UNSIGNED_BYTE),
+ gl.SRGB8
+ ];
+
+ /**
+ * s_nvSrgbFormatsRboFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_nvSrgbFormatsRboFormats = [
+ gl.SRGB8
+ ];
+
+ /**
+ * s_nvSrgbFormatsTextureFormats
+ * The extension does not actually require any unsized format
+ * to be renderable. However, the renderablility of unsized
+ * SRGB,UBYTE internalformat-type pair is implied.
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_nvSrgbFormatsTextureFormats = [
+ gl.SRGB8,
+ glsFboUtil.formatkey(gl.SRGB, gl.UNSIGNED_BYTE)
+ ];
+
+ /**
+ * s_oesRgb8Rgba8TexFormats
+ * @type {Array<number>}
+ */
+ glsFboCompletenessTests.s_oesRgb8Rgba8TexFormats = [
+ glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_BYTE),
+ glsFboUtil.formatkey(gl.RGBA, gl.UNSIGNED_BYTE)
+ ];
+
+ var fmt = glsFboUtil.FormatFlags;
+
+ /**
+ * s_esExtFormats
+ * @type {Array<glsFboUtil.FormatExtEntry>}
+ */
+ glsFboCompletenessTests.s_esExtFormats = [
+ new glsFboUtil.FormatExtEntry(
+ 'OES_depth_texture',
+ fmt.REQUIRED_RENDERABLE | fmt.DEPTH_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesDepthTextureFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_packed_depth_stencil',
+ fmt.REQUIRED_RENDERABLE | fmt.DEPTH_RENDERABLE | fmt.STENCIL_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesPackedDepthStencilSizedFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_packed_depth_stencil OES_required_internalformat',
+ fmt.DEPTH_RENDERABLE | fmt.STENCIL_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesPackedDepthStencilTexFormats)
+ ),
+
+ // \todo [2013-12-10 lauri] Find out if OES_texture_half_float is really a
+ // requirement on ES3 also. Or is color_buffer_half_float applicatble at
+ // all on ES3, since there's also EXT_color_buffer_float?
+ new glsFboUtil.FormatExtEntry(
+ 'OES_texture_half_float EXT_color_buffer_half_float',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extColorBufferHalfFloatFormats)
+ ),
+
+ // OES_required_internalformat doesn't actually specify that these are renderable,
+ // since it was written against ES 1.1.
+ new glsFboUtil.FormatExtEntry(
+ 'OES_required_internalformat',
+ // Allow but don't require RGBA8 to be color-renderable if
+ // OES_rgb8_rgba8 is not present.
+ fmt.COLOR_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRequiredInternalFormatColorFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_required_internalformat',
+ fmt.DEPTH_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRequiredInternalFormatDepthFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_rg',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extTextureRgRboFormats)
+ ),
+
+ // These are not specified to be color-renderable, but the wording is
+ // exactly as ambiguous as the wording in the ES2 spec.
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_rg',
+ fmt.REQUIRED_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extTextureRgTexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_rg OES_texture_float',
+ fmt.REQUIRED_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extTextureRgFloatTexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_rg OES_texture_half_float',
+ fmt.REQUIRED_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extTextureRgHalfFloatTexFormats)
+ ),
+
+ // Some Tegra drivers report gl.EXT_packed_float even for ES. Treat it as
+ // a synonym for the NV_ version.
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_packed_float',
+ fmt.REQUIRED_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_nvPackedFloatTexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_packed_float EXT_color_buffer_half_float',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_nvPackedFloatRboFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_sRGB',
+ fmt.COLOR_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extSrgbRenderableTexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_sRGB',
+ fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extSrgbNonRenderableTexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_sRGB',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extSrgbRboFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'NV_sRGB_formats',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_nvSrgbFormatsRboFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'NV_sRGB_formats',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_nvSrgbFormatsTextureFormats)
+ ),
+
+ // In Khronos bug 7333 discussion, the consensus is that these texture
+ // formats, at least, should be color-renderable. Still, that cannot be
+ // found in any extension specs, so only allow it, not require it.
+ new glsFboUtil.FormatExtEntry(
+ 'OES_rgb8_rgba8',
+ fmt.COLOR_RENDERABLE | fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRgb8Rgba8TexFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_rgb8_rgba8',
+ fmt.REQUIRED_RENDERABLE | fmt.COLOR_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRgb8Rgba8RboFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_rgb8_rgba8 OES_required_internalformat',
+ fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRequiredInternalFormatRgb8ColorFormat)
+ ),
+
+ // The depth-renderability of the depth RBO formats is not explicitly
+ // spelled out, but all renderbuffer formats are meant to be renderable.
+ new glsFboUtil.FormatExtEntry(
+ 'OES_depth24',
+ fmt.REQUIRED_RENDERABLE | fmt.DEPTH_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesDepth24SizedFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_depth24 OES_required_internalformat OES_depth_texture',
+ fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesDepth24SizedFormats)
+ ),
+
+ new glsFboUtil.FormatExtEntry(
+ 'OES_depth32',
+ fmt.REQUIRED_RENDERABLE | fmt.DEPTH_RENDERABLE | fmt.RENDERBUFFER_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesDepth32SizedFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'OES_depth32 OES_required_internalformat OES_depth_texture',
+ fmt.TEXTURE_VALID,
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesDepth32SizedFormats)
+ ),
+
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_type_2_10_10_10_REV',
+ fmt.TEXTURE_VALID, // explicitly unrenderable
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_extTextureType2101010RevFormats)
+ ),
+ new glsFboUtil.FormatExtEntry(
+ 'EXT_texture_type_2_10_10_10_REV OES_required_internalformat',
+ fmt.TEXTURE_VALID, // explicitly unrenderable
+ glsFboUtil.rangeArray(glsFboCompletenessTests.s_oesRequiredInternalFormat10bitColorFormats)
+ )
+ ];
+
+ }; // initGlDependents ----------------------------------------
+
+ /**
+ * @constructor
+ * @param {null} testCtx
+ * @param {WebGLRenderingContextBase} renderCtx
+ * @param {glsFboUtil.CheckerFactory} factory
+ */
+ glsFboCompletenessTests.Context = function(testCtx, renderCtx, factory) {
+
+ this.m_testCtx = testCtx;
+ this.m_renderCtx = renderCtx;
+ this.m_ctxFormats = new glsFboUtil.FormatDB();
+ this.m_minFormats = new glsFboUtil.FormatDB();
+ this.m_maxFormats = new glsFboUtil.FormatDB();
+ this.m_verifier = new glsFboUtil.FboVerifier(this.m_ctxFormats, factory);
+ this.m_haveMultiColorAtts = false;
+
+ // FormatExtEntries
+ var extRange = glsFboUtil.rangeArray(glsFboCompletenessTests.s_esExtFormats);
+ this.addExtFormats(extRange);
+
+ };
+
+ // RenderContext&
+ glsFboCompletenessTests.Context.prototype.getRenderContext = function() {
+ return this.m_renderCtx;
+ };
+
+ // TestContext&
+ glsFboCompletenessTests.Context.prototype.getTestContext = function() {
+ return this.m_testCtx;
+ };
+
+ // const FboVerifier&
+ glsFboCompletenessTests.Context.prototype.getVerifier = function() {
+ return this.m_verifier;
+ };
+
+ // const FormatDB&
+ glsFboCompletenessTests.Context.prototype.getMinFormats = function() {
+ return this.m_minFormats;
+ };
+
+ // const FormatDB&
+ glsFboCompletenessTests.Context.prototype.getCtxFormats = function() {
+ return this.m_ctxFormats;
+ };
+
+ // bool
+ glsFboCompletenessTests.Context.prototype.haveMultiColorAtts = function() {
+ return this.m_haveMultiColorAtts;
+ };
+
+ glsFboCompletenessTests.Context.prototype.setHaveMulticolorAtts = function(have) {
+ this.m_haveMultiColorAtts = (have == true);
+ };
+
+ glsFboCompletenessTests.Context.prototype.addFormats = function(fmtRange) {
+ glsFboUtil.addFormats(this.m_minFormats, fmtRange);
+ glsFboUtil.addFormats(this.m_ctxFormats, fmtRange);
+ glsFboUtil.addFormats(this.m_maxFormats, fmtRange);
+ };
+ glsFboCompletenessTests.Context.prototype.addExtFormats = function(extRange) {
+ glsFboUtil.addExtFormats(this.m_ctxFormats, extRange, this.m_renderCtx);
+ glsFboUtil.addExtFormats(this.m_maxFormats, extRange, this.m_renderCtx);
+ };
+
+ glsFboCompletenessTests.Context.prototype.createRenderableTests = function(gl) {
+
+ /** @type {tcuTestCase.DeqpTest} */
+ var renderableTests = tcuTestCase.newTest('renderable', 'Tests for support of renderable image formats');
+ /** @type {tcuTestCase.DeqpTest} */
+ var rbRenderableTests = tcuTestCase.newTest('renderbuffer', 'Tests for renderbuffer formats');
+ /** @type {tcuTestCase.DeqpTest} */
+ var texRenderableTests = tcuTestCase.newTest('texture', 'Tests for texture formats');
+
+ var attPoints = [
+ [gl.DEPTH_ATTACHMENT, 'depth', 'Tests for depth attachments'],
+ [gl.STENCIL_ATTACHMENT, 'stencil', 'Tests for stencil attachments'],
+ [gl.COLOR_ATTACHMENT0, 'color0', 'Tests for color attachments']
+ ];
+
+ // At each attachment point, iterate through all the possible formats to
+ // detect both false positives and false negatives.
+ var rboFmts = this.m_maxFormats.getFormats(glsFboUtil.FormatFlags.ANY_FORMAT);
+ var texFmts = this.m_maxFormats.getFormats(glsFboUtil.FormatFlags.ANY_FORMAT);
+
+ for (var i = 0, l_attPoints = attPoints.length; i < l_attPoints; ++i) {
+ var rbAttTests = tcuTestCase.newTest(attPoints[i][1], attPoints[i][2]);
+ var texAttTests = tcuTestCase.newTest(attPoints[i][1], attPoints[i][2]);
+
+ for (var j = 0, l_rboFmts = rboFmts.length; j < l_rboFmts; ++j) {
+ var params = glsFboCompletenessTests.renderableParams(
+ attPoints[i][0], gl.RENDERBUFFER, rboFmts[j]
+ );
+ rbAttTests.addChild(
+ new glsFboCompletenessTests.RenderableTest(
+ glsFboCompletenessTests.renderableParams.getName(params),
+ glsFboCompletenessTests.renderableParams.getDescription(params),
+ this, params
+ )
+ );
+ }
+ rbRenderableTests.addChild(rbAttTests);
+
+ for (var j = 0, l_texFmts = texFmts.length; j < l_texFmts; ++j) {
+ var params = glsFboCompletenessTests.renderableParams(
+ attPoints[i][0], gl.TEXTURE, texFmts[j]
+ );
+ texAttTests.addChild(
+ new glsFboCompletenessTests.RenderableTest(
+ glsFboCompletenessTests.renderableParams.getName(params),
+ glsFboCompletenessTests.renderableParams.getDescription(params),
+ this, params
+ )
+ );
+ }
+ texRenderableTests.addChild(texAttTests);
+
+ }
+ renderableTests.addChild(rbRenderableTests);
+ renderableTests.addChild(texRenderableTests);
+
+ return renderableTests;
+ };
+
+ glsFboCompletenessTests.Context.prototype.createAttachmentTests = function(gl) {
+
+ var attCombTests = tcuTestCase.newTest('attachment_combinations', 'Tests for attachment combinations');
+
+ var s_bufTypes = [gl.NONE, gl.RENDERBUFFER, gl.TEXTURE];
+ var ls_bufTypes = s_bufTypes.length;
+
+ for (var col0 = 0; col0 < ls_bufTypes; ++col0)
+ for (var coln = 0; coln < ls_bufTypes; ++coln)
+ for (var dep = 0; dep < ls_bufTypes; ++dep)
+ for (var stc = 0; stc < ls_bufTypes; ++stc) {
+ var params = glsFboCompletenessTests.attachmentParams(
+ s_bufTypes[col0], s_bufTypes[coln], s_bufTypes[dep], s_bufTypes[stc]
+ );
+ attCombTests.addChild(new glsFboCompletenessTests.AttachmentTest(
+ glsFboCompletenessTests.attachmentParams.getName(params),
+ glsFboCompletenessTests.attachmentParams.getDescription(params),
+ this, params
+ ));
+ }
+ return attCombTests;
+ };
+
+ glsFboCompletenessTests.Context.prototype.createSizeTests = function(gl) {
+
+ var sizeTests = tcuTestCase.newTest('size', 'Tests for attachment sizes');
+
+ sizeTests.addChild(new glsFboCompletenessTests.EmptyImageTest(
+ 'zero', 'Test for zero-sized image attachment', this
+ ));
+
+ return sizeTests;
+
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} desc
+ * @param {Object} params
+ */
+ glsFboCompletenessTests.TestBase = function(name, desc, params) {
+ tcuTestCase.DeqpTest.call(this, name, desc);
+ this.m_params = params;
+ };
+ glsFboCompletenessTests.TestBase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsFboCompletenessTests.TestBase.prototype.constructor = glsFboCompletenessTests.TestBase;
+
+ glsFboCompletenessTests.TestBase.prototype.getContext = function() {
+ return tcuTestCase.runner;
+ };
+
+ // GLenum attPoint, GLenum bufType
+ /**
+ * @param {number} attPoint
+ * @param {number} bufType
+ * @param {WebGLRenderingContextBase=} gl
+ */
+ glsFboCompletenessTests.TestBase.prototype.getDefaultFormat = function(attPoint, bufType, gl) {
+ gl = gl || window.gl;
+
+ if (bufType == gl.NONE) {
+ return glsFboUtil.ImageFormat.none();
+ }
+
+ // Prefer a standard format, if there is one, but if not, use a format
+ // provided by an extension.
+ var formats = this.m_ctx.getMinFormats().getFormats(
+ glsFboUtil.formatFlag(attPoint, gl) | glsFboUtil.formatFlag(bufType, gl)
+ );
+
+ if (!formats.length) {
+ formats = this.m_ctx.getCtxFormats().getFormats(
+ glsFboUtil.formatFlag(attPoint, gl) | glsFboUtil.formatFlag(bufType, gl)
+ );
+ }
+ if (!formats.length) {
+ throw new Error('Unsupported attachment kind for attachment point');
+ }
+
+ return formats[0];
+
+ };
+
+ /**
+ * @param {number} bufType
+ * @param {glsFboUtil.ImageFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {glsFboUtil.FboBuilder} builder
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {glsFboUtil.Image}
+ */
+ glsFboCompletenessTests.makeImage = function(bufType, format, width, height, builder, gl) {
+ gl = gl || window.gl;
+ var image = 0;
+ switch (bufType) {
+ case gl.NONE:
+ return null;
+ break;
+ case gl.RENDERBUFFER:
+ image = /** @type {glsFboUtil.Renderbuffer}*/(builder.makeConfig(glsFboUtil.Renderbuffer));
+ break;
+ case gl.TEXTURE:
+ image = /** @type {glsFboUtil.Texture2D}*/(builder.makeConfig(glsFboUtil.Texture2D));
+ break;
+ default:
+ throw new Error('Impossible case');
+ }
+ image.internalFormat = format;
+ image.width = width;
+ image.height = height;
+ return image;
+ };
+
+ /**
+ * @param {number} bufType
+ * @param {glsFboUtil.ImageFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {glsFboUtil.FboBuilder} builder
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {glsFboUtil.Attachment}
+ */
+ glsFboCompletenessTests.makeAttachment = function(bufType, format, width, height, builder, gl) {
+ gl = gl || window.gl;
+ var cfg = glsFboCompletenessTests.makeImage(bufType, format, width, height, builder, gl);
+ if (cfg == null) return null;
+
+ /** @type {glsFboUtil.Attachment} */ var att = null;
+ var img = 0;
+
+ var mask = glsFboUtil.Config.s_types.RENDERBUFFER | glsFboUtil.Config.s_types.TEXTURE_2D;
+
+ switch (cfg.type & mask) {
+ case glsFboUtil.Config.s_types.RENDERBUFFER:
+ img = builder.glCreateRbo(/** @type {glsFboUtil.Renderbuffer} */(cfg));
+ att = /** @type {glsFboUtil.RenderbufferAttachment} */ (builder.makeConfig(glsFboUtil.RenderbufferAttachment));
+ break;
+ case glsFboUtil.Config.s_types.TEXTURE_2D:
+ img = builder.glCreateTexture(/** @type {glsFboUtil.Texture2D} */(cfg));
+ att = /** @type {glsFboUtil.TextureFlatAttachment} */ (builder.makeConfig(glsFboUtil.TextureFlatAttachment));
+ att.texTarget = gl.TEXTURE_2D;
+ break;
+ default:
+ throw new Error('Unsupported config.');
+ }
+ att.imageName = img;
+ return att;
+ };
+
+ //GLenum target, GLenum bufType, ImageFormat format, GLsizei width, GLsizei height, FboBuilder& builder, webglctx
+ /**
+ * @param {number} target
+ * @param {number} bufType
+ * @param {glsFboUtil.ImageFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {glsFboUtil.FboBuilder} builder
+ * @param {WebGL2RenderingContext} gl
+ */
+ glsFboCompletenessTests.TestBase.prototype.attachTargetToNew = function(
+ target, bufType, format, width, height, builder, gl
+ ) {
+ var imgFmt = format;
+ if (imgFmt.format == gl.NONE)
+ imgFmt = this.getDefaultFormat(target, bufType, gl);
+ var att = glsFboCompletenessTests.makeAttachment(bufType, imgFmt, width, height, builder, gl);
+ builder.glAttach(target, att);
+ };
+
+ /**
+ * @param {number} status
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {string}
+ */
+ glsFboCompletenessTests.statusName = function(status, gl) {
+ gl = gl || window.gl;
+
+ var errorName = gluStrUtil.getErrorName(status);
+ if (status != gl.NO_ERROR && errorName != '')
+ return errorName + ' (during FBO initialization)';
+
+ var fbStatusName = gluStrUtil.getFramebufferStatusName(status);
+ if (fbStatusName != '')
+ return fbStatusName;
+
+ return 'unknown value (' + status + ')';
+ };
+
+ glsFboCompletenessTests.TestBase.prototype.iterate = function() {
+ var gl = window.gl;
+
+ var fbo = new gluObjectWrapper.Framebuffer(gl);
+ var builder = new glsFboUtil.FboBuilder(fbo.get(), gl.FRAMEBUFFER, gl);
+ var ret = this.build(builder, gl);
+ var statuses = this.m_ctx.getVerifier().validStatusCodes(builder, gl);
+
+ var errorCode = builder.getError();
+ if (errorCode != gl.NO_ERROR) {
+ bufferedLogToConsole('Received ' + gluStrUtil.getErrorName(errorCode) + ' (during FBO initialization).');
+ if (statuses.isErrorCodeValid(errorCode))
+ testPassed();
+ else if (statuses.isErrorCodeRequired(gl.NO_ERROR))
+ testFailedOptions('Excepted no error but got ' + gluStrUtil.getErrorName(errorCode), true);
+ else
+ testFailedOptions('Got wrong error code', true);
+ } else {
+ var fboStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ var validStatus = statuses.isFBOStatusValid(fboStatus);
+ bufferedLogToConsole('Received ' + gluStrUtil.getFramebufferStatusName(fboStatus));
+ if (!validStatus) {
+ if (fboStatus == gl.FRAMEBUFFER_COMPLETE) {
+ testFailedOptions('Framebuffer checked as complete, expected incomplete', true);
+ } else if (statuses.isFBOStatusRequired(gl.FRAMEBUFFER_COMPLETE)) {
+ testFailedOptions('Framebuffer checked as incomplete, expected complete', true);
+ } else {
+ // An incomplete status is allowed, but not _this_ incomplete status.
+ testFailedOptions('Framebuffer checked as incomplete, but with wrong status', true);
+ }
+ } else if (fboStatus != gl.FRAMEBUFFER_COMPLETE && statuses.isFBOStatusValid(gl.FRAMEBUFFER_COMPLETE)) {
+ testPassedOptions('Warning: framebuffer object could have checked as complete but did not.', true);
+ } else {
+ // pass
+ testPassed();
+ }
+ }
+ builder.deinit();
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ glsFboCompletenessTests.formatName = function(format, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid GL object');
+
+ var s = gluStrUtil.getPixelFormatName(format.format).substr(3).toLowerCase();
+
+ if (format.unsizedType != gl.NONE)
+ s += '_' + gluStrUtil.getTypeName(format.unsizedType).substr(3).toLowerCase();
+
+ return s;
+ };
+ glsFboCompletenessTests.formatDesc = function(format, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid GL object');
+
+ var s = gluStrUtil.getPixelFormatName(format.format);
+
+ if (format.unsizedType != gl.NONE)
+ s += ' with type ' + gluStrUtil.getTypeName(format.unsizedType);
+
+ return s;
+ };
+
+ /**
+ * @typedef {{attPoint: number, bufType: number, format: glsFboUtil.ImageFormat}}
+ */
+ glsFboCompletenessTests.renderableParamsT;
+
+ /**
+ * @param {number} attPoint
+ * @param {number} bufType
+ * @param {glsFboUtil.ImageFormat} format
+ * @return {glsFboCompletenessTests.renderableParamsT}
+ */
+ glsFboCompletenessTests.renderableParams = function(attPoint, bufType, format) {
+ var ret = {
+ attPoint: attPoint,
+ bufType: bufType,
+ format: format
+ };
+ return ret;
+ };
+ /**
+ * @param {glsFboCompletenessTests.renderableParamsT} params
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {string}
+ */
+ glsFboCompletenessTests.renderableParams.getName = function(params, gl) {
+ return glsFboCompletenessTests.formatName(params.format, gl);
+ };
+ /**
+ * @param {glsFboCompletenessTests.renderableParamsT} params
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {string}
+ */
+ glsFboCompletenessTests.renderableParams.getDescription = function(params, gl) {
+ return glsFboCompletenessTests.formatDesc(params.format, gl);
+ };
+
+ /**
+ * @constructor
+ * @extends {glsFboCompletenessTests.TestBase}
+ * @param {string} name
+ * @param {string} desc
+ * @param {glsFboCompletenessTests.Context} ctx
+ * @param {glsFboCompletenessTests.renderableParamsT} params
+ */
+ glsFboCompletenessTests.RenderableTest = function(name, desc, ctx, params) {
+ glsFboCompletenessTests.TestBase.call(this, name, desc, params);
+ this.m_ctx = ctx;
+ };
+ glsFboCompletenessTests.RenderableTest.prototype = Object.create(glsFboCompletenessTests.TestBase.prototype);
+ glsFboCompletenessTests.RenderableTest.prototype.constructor = glsFboCompletenessTests.RenderableTest;
+
+ glsFboCompletenessTests.RenderableTest.prototype.build = function(builder, gl) {
+ this.attachTargetToNew(this.m_params.attPoint, this.m_params.bufType, this.m_params.format, 64, 64, builder, gl);
+ return true;
+ };
+
+ glsFboCompletenessTests.attTypeName = function(bufType, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid GL object');
+ switch (bufType) {
+ case gl.NONE: return 'none';
+ case gl.RENDERBUFFER: return 'rbo';
+ case gl.TEXTURE: return 'tex';
+ default: break;
+ }
+ throw new Error('Impossible case');
+ };
+
+ /**
+ * @typedef {{color0Kind: number, colornKind: number, depthKind: number, stencilKind: number}}
+ */
+ glsFboCompletenessTests.attachmentParamsT;
+
+ /**
+ * @param {number} color0Kind
+ * @param {number} colornKind
+ * @param {number} depthKind
+ * @param {number} stencilKind
+ * @return {glsFboCompletenessTests.attachmentParamsT}
+ */
+ glsFboCompletenessTests.attachmentParams = function(color0Kind, colornKind, depthKind, stencilKind) {
+ var ret = {
+ color0Kind: color0Kind,
+ colornKind: colornKind,
+ depthKind: depthKind,
+ stencilKind: stencilKind
+ };
+ return ret;
+ };
+ /**
+ * @param {glsFboCompletenessTests.attachmentParamsT} params
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {string}
+ */
+ glsFboCompletenessTests.attachmentParams.getName = function(params, gl) {
+ return (glsFboCompletenessTests.attTypeName(params.color0Kind, gl) + '_' +
+ glsFboCompletenessTests.attTypeName(params.colornKind, gl) + '_' +
+ glsFboCompletenessTests.attTypeName(params.depthKind, gl) + '_' +
+ glsFboCompletenessTests.attTypeName(params.stencilKind, gl));
+ };
+ /**
+ * @param {glsFboCompletenessTests.attachmentParamsT} params
+ * @return {string}
+ */
+ glsFboCompletenessTests.attachmentParams.getDescription = glsFboCompletenessTests.attachmentParams.getName;
+
+ /**
+ * @constructor
+ * @extends {glsFboCompletenessTests.TestBase}
+ * @param {string} name
+ * @param {string} desc
+ * @param {glsFboCompletenessTests.Context} ctx
+ * @param {glsFboCompletenessTests.attachmentParamsT} params
+ */
+ glsFboCompletenessTests.AttachmentTest = function(name, desc, ctx, params) {
+ glsFboCompletenessTests.TestBase.call(this, name, desc, params);
+ this.m_ctx = ctx;
+ };
+ glsFboCompletenessTests.AttachmentTest.prototype = Object.create(glsFboCompletenessTests.TestBase.prototype);
+ glsFboCompletenessTests.AttachmentTest.prototype.constructor = glsFboCompletenessTests.AttachmentTest;
+
+ glsFboCompletenessTests.AttachmentTest.prototype.makeDepthAndStencil = function(builder, gl) {
+
+ /** @type {glsFboUtil.Attachment} */
+ var att = null;
+
+ if (this.m_params.stencilKind == this.m_params.depthKind) {
+ // If there is a common stencil+depth -format, try to use a common
+ // image for both attachments.
+ var flags = glsFboUtil.FormatFlags.DEPTH_RENDERABLE |
+ glsFboUtil.FormatFlags.STENCIL_RENDERABLE |
+ glsFboUtil.formatFlag(this.m_params.stencilKind, gl);
+
+ var formats = this.m_ctx.getMinFormats().getFormats(flags);
+ if (formats.length) {
+ var format = formats[0];
+ att = glsFboCompletenessTests.makeAttachment(this.m_params.depthKind, format, 64, 64, builder, gl);
+ builder.glAttach(gl.DEPTH_ATTACHMENT, att);
+ builder.glAttach(gl.STENCIL_ATTACHMENT, att);
+ return;
+ }
+ }
+ // Either the kinds were separate, or a suitable format was not found.
+ // Create separate images.
+ this.attachTargetToNew(gl.STENCIL_ATTACHMENT, this.m_params.stencilKind,
+ glsFboUtil.ImageFormat.none(), 64, 64, builder, gl);
+ this.attachTargetToNew(gl.DEPTH_ATTACHMENT, this.m_params.depthKind,
+ glsFboUtil.ImageFormat.none(), 64, 64, builder, gl);
+ };
+
+ glsFboCompletenessTests.AttachmentTest.prototype.build = function(builder, gl) {
+
+ this.attachTargetToNew(gl.COLOR_ATTACHMENT0, this.m_params.color0Kind,
+ glsFboUtil.ImageFormat.none(), 64, 64, builder, gl);
+
+ if (this.m_params.colornKind != gl.NONE) {
+ if (this.m_ctx.haveMultiColorAtts())
+ throw new Error('Multiple attachments not supported');
+ var maxAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+
+ for (var i = 1; i < maxAttachments; ++i) {
+ this.attachTargetToNew(gl.COLOR_ATTACHMENT0 + i, this.m_params.colornKind,
+ glsFboUtil.ImageFormat.none(), 64, 64, builder, gl);
+ }
+ }
+
+ this.makeDepthAndStencil(builder, gl);
+
+ return true;
+ };
+
+ /**
+ * @constructor
+ * @extends {glsFboCompletenessTests.TestBase}
+ * @param {string} name
+ * @param {string} desc
+ * @param {glsFboCompletenessTests.Context} ctx
+ */
+ glsFboCompletenessTests.EmptyImageTest = function(name, desc, ctx) {
+ glsFboCompletenessTests.TestBase.call(this, name, desc, null);
+ this.m_ctx = ctx;
+ };
+ glsFboCompletenessTests.EmptyImageTest.prototype = Object.create(glsFboCompletenessTests.TestBase.prototype);
+ glsFboCompletenessTests.EmptyImageTest.prototype.constructor = glsFboCompletenessTests.EmptyImageTest;
+
+ glsFboCompletenessTests.EmptyImageTest.prototype.build = function(builder, gl) {
+ this.attachTargetToNew(gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER,
+ glsFboUtil.ImageFormat.none(), 0, 0, builder, gl);
+ return true;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboUtil.js
new file mode 100644
index 000000000..86d05891f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboUtil.js
@@ -0,0 +1,1413 @@
+/*-------------------------------------------------------------------------
+ * 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.glsFboUtil');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.opengl.gluStrUtil');
+
+goog.scope(function() {
+
+ var glsFboUtil = modules.shared.glsFboUtil;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var gluStrUtil = framework.opengl.gluStrUtil;
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * @constructor
+ * @template KeyT
+ * @template ValueT
+ * @param {function(!KeyT, !KeyT):boolean} comparefnc
+ */
+ glsFboUtil.Map = function(comparefnc) {
+ /** @type {Array<{first: !KeyT, second: ValueT}>} */
+ this.store = [];
+ this.compare = comparefnc;
+ this.length = 0;
+ };
+
+ /**
+ * @param {number} num1
+ * @param {number} num2
+ * @return {boolean}
+ */
+ glsFboUtil.Map.compareNumber = function(num1, num2) {
+ return num1 < num2;
+ };
+
+ /**
+ * @param {!KeyT} key
+ * @param {ValueT} value
+ * @return {{first: !KeyT, second: ValueT}}
+ */
+ glsFboUtil.Map.prototype.pair = function(key, value) {
+ return {
+ first: key,
+ second: value
+ };
+ };
+
+ /**
+ * @protected
+ * @param {!KeyT} key
+ * @return {number}
+ */
+ glsFboUtil.Map.prototype.findInsertionPoint = function(key) {
+ var /** @type {number} */i, /** @type {number} */length;
+ for (i = 0, length = this.store.length; i < length; ++i) {
+ if (!this.compare(key, this.store[i].first)) break;
+ }
+ return i;
+ };
+
+ /**
+ * index should be a value returned from findInsertionPoint.
+ * returns true if the compare function returns false reflexively
+ * (i.e. no matter the order in which the keys are passed as arguments).
+ * @protected
+ * @param {!KeyT} key
+ * @param {number} index
+ * @return {boolean}
+ */
+ glsFboUtil.Map.prototype.foundIndexMatches = function(key, index) {
+ return (
+ this.store[index] !== undefined &&
+ !this.compare(this.store[index].first, key)
+ );
+ };
+
+ /**
+ * @param {!KeyT} key
+ * @return {boolean}
+ */
+ glsFboUtil.Map.prototype.isset = function(key) {
+ return this.foundIndexMatches(key, this.findInsertionPoint(key));
+ };
+
+ /**
+ * @param {!KeyT} key
+ * @param {ValueT} value
+ */
+ glsFboUtil.Map.prototype.set = function(key, value) {
+ var index = this.findInsertionPoint(key);
+ if (this.foundIndexMatches(key, index)) {
+ this.store[index].second = value;
+ } else {
+ this.store.splice(index, 0, this.pair(key, value));
+ ++this.length;
+ }
+ };
+
+ /**
+ * @param {!KeyT} key
+ * @return {?ValueT}
+ */
+ glsFboUtil.Map.prototype.remove = function(key) {
+ var index = this.findInsertionPoint(key);
+ /** @type {?ValueT} */ var ret = null;
+ if (this.foundIndexMatches(key, index)) {
+ ret = this.store[index].second;
+ this.store.splice(index, 1);
+ --this.length;
+ }
+ return ret;
+ };
+
+ /**
+ * @param {KeyT} key
+ * @return {?{first: KeyT, second: ValueT}}
+ */
+ glsFboUtil.Map.prototype.get = function(key) {
+ var index = this.findInsertionPoint(key);
+ if (this.foundIndexMatches(key, index)) return this.store[index];
+ return null;
+ };
+
+ /**
+ * @param {KeyT} key
+ * @return {?ValueT}
+ */
+ glsFboUtil.Map.prototype.getValue = function(key) {
+ var index = this.findInsertionPoint(key);
+ if (this.foundIndexMatches(key, index)) return this.store[index].second;
+ return null;
+ };
+
+ /**
+ * @param {!KeyT} key
+ * @param {ValueT} fallback
+ * @return {ValueT}
+ */
+ glsFboUtil.Map.prototype.lookupDefault = function(key, fallback) {
+ var index = this.findInsertionPoint(key);
+ if (this.foundIndexMatches(key, index)) return this.store[index].second;
+ return fallback;
+ };
+
+ /**
+ * @param {number} index
+ * @return {{first: KeyT, second: ValueT}|undefined}
+ */
+ glsFboUtil.Map.prototype.getIndex = function(index) {
+ return this.store[index];
+ };
+
+ /**
+ * Use the callback to set the value to be identified by key.
+ * If a value is already identified by the key, it will be passed to the callback
+ * @param {!KeyT} key
+ * @param {function(ValueT=):!ValueT} callback
+ */
+ glsFboUtil.Map.prototype.transform = function(key, callback) {
+ var index = this.findInsertionPoint(key);
+ if (this.foundIndexMatches(key, index)) {
+ this.store[index].second = callback(this.store[index].second);
+ } else {
+ this.store.splice(index, 0, this.pair(key, callback()));
+ ++this.length;
+ }
+ };
+
+ /**
+ * removed all elements from the Map
+ */
+ glsFboUtil.Map.prototype.clear = function() {
+ this.store.splice(0, this.length);
+ this.length = 0;
+ };
+
+ /**
+ * @constructor
+ */
+ glsFboUtil.FormatDB = function() {
+ this.m_map = /** @type {glsFboUtil.Map<glsFboUtil.ImageFormat,number>} */(
+ new glsFboUtil.Map(glsFboUtil.ImageFormat.lessthan)
+ );
+ };
+
+ /**
+ * @param {glsFboUtil.ImageFormat} format
+ * @param {number} newFlags
+ */
+ glsFboUtil.FormatDB.prototype.addFormat = function(format, newFlags) {
+ this.m_map.transform(format, function(flags) {
+ return flags | newFlags;
+ });
+ };
+
+ /**
+ * @param {number} requirements
+ * @return {Array<glsFboUtil.ImageFormat>}
+ */
+ glsFboUtil.FormatDB.prototype.getFormats = function(requirements) {
+ /** @type {Array<glsFboUtil.ImageFormat>} */ var ret = [];
+ for (var i = 0; i < this.m_map.length; ++i) {
+ var pair = this.m_map.getIndex(i);
+ if ((pair.second & requirements) == requirements)
+ ret.push(pair.first);
+ }
+
+ return ret;
+ };
+
+ /**
+ * @param {glsFboUtil.ImageFormat} format
+ * @param {number} fallback
+ * @return {number}
+ */
+ glsFboUtil.FormatDB.prototype.getFormatInfo = function(format, fallback) {
+ return this.m_map.lookupDefault(format, fallback);
+ };
+
+ /**
+ * @param {Object} map
+ * @param {number} key
+ * @param {number} fallback
+ * @return {number}
+ */
+ glsFboUtil.lookupDefault = function(map, key, fallback) {
+ return (map[key] !== undefined) ? map[key] : fallback;
+ };
+
+ /**
+ * @param {Array<number>} array
+ * @param {number} item
+ * @return {boolean}
+ */
+ glsFboUtil.contains = function(array, item) {
+ var l = array.length;
+ for (var i = 0; i < l; ++i)
+ if (array[i] == item) return true;
+ return false;
+ };
+
+ /**
+ * @typedef {Array<(number | glsFboUtil.Range<number>)>}
+ */
+ glsFboUtil.formatT;
+
+ /**
+ * @param {glsFboUtil.FormatDB} db
+ * @param {glsFboUtil.Range<glsFboUtil.formatT>} stdFmts
+ */
+ glsFboUtil.addFormats = function(db, stdFmts) {
+ for (var set = stdFmts.reset(); set = stdFmts.current(); stdFmts.next()) {
+ for (var fmt = set[1].reset(); fmt = set[1].current(); set[1].next()) {
+ db.addFormat(glsFboUtil.formatKeyInfo(fmt), set[0]);
+ }
+ }
+ };
+
+ /**
+ * @param {glsFboUtil.FormatDB} db
+ * @param {glsFboUtil.Range} extFmts
+ * @param {WebGLRenderingContextBase=} gl
+ * @throws {Error}
+ */
+ glsFboUtil.addExtFormats = function(db, extFmts, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+ var extensions = gl.getSupportedExtensions();
+
+ // loop through the range, looking at the extentions.
+ for (var ext = extFmts.reset(); ext = extFmts.current(); extFmts.next()) {
+ var tokens = ext.extensions.split(/\s+/);
+
+ var supported = function() {
+ for (var i = 0, l = tokens.length; i < l; ++i)
+ if (extensions.indexOf(tokens[i]) === -1) return false;
+ return true;
+ }();
+
+ if (supported) {
+ for (var format = ext.formats.reset(); format = ext.formats.current(); ext.formats.next()) {
+ db.addFormat(glsFboUtil.formatKeyInfo(format), ext.flags);
+ }
+ }
+
+ }
+
+ };
+
+ /**
+ * @param {number} glenum
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {number}
+ * @throws {Error}
+ */
+ glsFboUtil.formatFlag = function(glenum, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ switch (glenum) {
+ case gl.NONE:
+ return glsFboUtil.FormatFlags.ANY_FORMAT;
+ case gl.RENDERBUFFER:
+ return glsFboUtil.FormatFlags.RENDERBUFFER_VALID;
+ case gl.TEXTURE:
+ return glsFboUtil.FormatFlags.TEXTURE_VALID;
+ case gl.STENCIL_ATTACHMENT:
+ return glsFboUtil.FormatFlags.STENCIL_RENDERABLE;
+ case gl.DEPTH_ATTACHMENT:
+ return glsFboUtil.FormatFlags.DEPTH_RENDERABLE;
+ default:
+ if (glenum < gl.COLOR_ATTACHMENT0 || glenum > gl.COLOR_ATTACHMENT15) {
+ throw new Error('glenum out of range');
+ }
+ }
+ return glsFboUtil.FormatFlags.COLOR_RENDERABLE;
+ };
+
+ /**
+ * Remove value from array
+ * @param {Array} array
+ * @param {number} value
+ */
+ glsFboUtil.remove_from_array = function(array, value) {
+ var index = 0;
+ while ((index = array.indexOf(value)) != -1) {
+ array.splice(index, 1);
+ }
+ };
+
+ /**
+ * glsFboUtil.FormatExtEntry
+ * @constructor
+ * @struct
+ * @param {string=} extensions
+ * @param {number=} flags
+ * @param {glsFboUtil.Range=} formats
+ */
+ glsFboUtil.FormatExtEntry = function(extensions, flags, formats) {
+ this.extensions = null;
+ this.flags = null;
+ this.formats = null;
+
+ if (extensions !== undefined) {
+ this.extensions = extensions;
+ if (flags !== undefined) {
+ this.flags = flags;
+ if (formats !== undefined)
+ this.formats = formats;
+ }
+ }
+
+ };
+
+ /**
+ * glsFboUtil.Range
+ * @constructor
+ * @struct
+ * @template T
+ * @param {Array<T>} array
+ * @param {number=} begin
+ * @param {number=} end
+ */
+ glsFboUtil.Range = function(array, begin, end) {
+ // @private
+ this.m_begin = (begin === undefined ? 0 : begin);
+ // @private
+ this.m_end = end || array.length;
+ /**
+ * @private
+ * @type {Array<T>}
+ */
+ this.m_array = array;
+ // @private
+ this.m_index = this.m_begin;
+ };
+
+ /**
+ * @return {Array<T>}
+ */
+ glsFboUtil.Range.prototype.array = function() {
+ return this.m_array;
+ };
+
+ /**
+ * @return {number}
+ */
+ glsFboUtil.Range.prototype.begin = function() {
+ return this.m_begin;
+ };
+
+ /** *generated by script*
+ * @return {number}
+ */
+ glsFboUtil.Range.prototype.end = function() {
+ return this.m_end;
+ };
+
+ /**
+ * Returns the current pointer index as well as the current object
+ * @param {number} id
+ * @return {{first: number, second: T}}
+ */
+ glsFboUtil.Range.prototype.get = function(id) {
+ return {
+ first: id,
+ second: this.m_array[id]
+ };
+ };
+
+ /**
+ * Sets the internal pointer to the beginning of the range, and returns the first object.
+ * @return {T}
+ */
+ glsFboUtil.Range.prototype.reset = function() {
+ this.m_index = this.m_begin;
+ return this.current();
+ };
+
+ /**
+ * returns the current object within the specified range. The internal pointer is unaltered.
+ * @return {T}
+ */
+ glsFboUtil.Range.prototype.current = function() {
+ return this.m_index < this.m_end ? this.m_array[this.m_index] : null;
+ };
+
+ /**
+ * Increments the internal pointer
+ */
+ glsFboUtil.Range.prototype.next = function() {
+ ++this.m_index;
+ };
+
+ /**
+ * glsFboUtil.rangeArray
+ * replaces the macro GLS_ARRAY_RANGE
+ * Creates a new Range object from the specified array, spanning the whole array.
+ * @template T
+ * @param {Array<T>} array
+ * @return {glsFboUtil.Range<T>}
+ */
+ glsFboUtil.rangeArray = function(array) {
+ return new glsFboUtil.Range(array);
+ };
+
+ /**
+ * @constructor
+ * @struct
+ * @param {number=} format
+ * @param {number=} unsizedType
+ */
+ glsFboUtil.ImageFormat = function(format, unsizedType) {
+ this.format = format || 0;
+ //! Type if format is unsized, gl.NONE if sized.
+ this.unsizedType = unsizedType || 0;
+
+ };
+
+ /**
+ * @param {!glsFboUtil.ImageFormat} obj1
+ * @param {!glsFboUtil.ImageFormat} obj2
+ * @return {boolean}
+ */
+ glsFboUtil.ImageFormat.lessthan = function(obj1, obj2) {
+ return (
+ (obj1.format < obj2.format) ||
+ (obj1.format == obj2.format && obj1.unsizedType < obj2.unsizedType)
+ );
+ };
+
+ /**
+ * Sets the object's parameters to gl.NONE
+ */
+ glsFboUtil.ImageFormat.prototype.none = function() {
+ this.format = 0;
+ this.unsizedType = 0;
+ };
+
+ /**
+ * @return {glsFboUtil.ImageFormat}
+ */
+ glsFboUtil.ImageFormat.none = function() {
+ var obj = new glsFboUtil.ImageFormat();
+ obj.none();
+ return obj;
+ };
+
+ // where key is a FormatKey, and a FormatKey is a unsigned 32bit int.
+
+ /**
+ * @param {number} key
+ * @return {glsFboUtil.ImageFormat}
+ */
+ glsFboUtil.formatKeyInfo = function(key) {
+ return new glsFboUtil.ImageFormat(
+ (key & 0x0000ffff),
+ (key & 0xffff0000) >>> 16
+ );
+ };
+
+ /**
+ * glsFboUtil.Config Class.
+ * @constructor
+ */
+ glsFboUtil.Config = function() {
+ this.type = glsFboUtil.Config.s_types.CONFIG;
+ this.target = glsFboUtil.Config.s_target.NONE;
+ };
+ /**
+ * @enum {number}
+ */
+ glsFboUtil.Config.s_target = {
+ NONE: 0,
+ RENDERBUFFER: 0x8D41,
+ TEXTURE_2D: 0x0DE1,
+ TEXTURE_CUBE_MAP: 0x8513,
+ TEXTURE_3D: 0x806F,
+ TEXTURE_2D_ARRAY: 0x8C1A,
+
+ FRAMEBUFFER: 0x8D40
+ };
+
+ // the c++ uses dynamic casts to determain if an object inherits from a
+ // given class. Here, each class' constructor assigns a bit to obj.type.
+ // look for the bit to see if an object inherits that class.
+
+ /**
+ * @enum
+ */
+ glsFboUtil.Config.s_types = {
+ CONFIG: 0x000001,
+
+ IMAGE: 0x000010,
+ RENDERBUFFER: 0x000020,
+ TEXTURE: 0x000040,
+ TEXTURE_FLAT: 0x000080,
+ TEXTURE_2D: 0x000100,
+ TEXTURE_CUBE_MAP: 0x000200,
+ TEXTURE_LAYERED: 0x000400,
+ TEXTURE_3D: 0x000800,
+ TEXTURE_2D_ARRAY: 0x001000,
+
+ ATTACHMENT: 0x010000,
+ ATT_RENDERBUFFER: 0x020000,
+ ATT_TEXTURE: 0x040000,
+ ATT_TEXTURE_FLAT: 0x080000,
+ ATT_TEXTURE_LAYER: 0x100000,
+
+ UNUSED: 0xFFE0E00E
+ };
+
+ /**
+ * glsFboUtil.Image Class.
+ * @constructor
+ * @extends {glsFboUtil.Config}
+ */
+ glsFboUtil.Image = function() {
+ glsFboUtil.Config.call(this);
+ this.type |= glsFboUtil.Config.s_types.IMAGE;
+ this.width = 0;
+ this.height = 0;
+ this.internalFormat = new glsFboUtil.ImageFormat();
+ };
+
+ /**
+ * glsFboUtil.Renderbuffer Class.
+ * @constructor
+ * @extends {glsFboUtil.Image}
+ */
+ glsFboUtil.Renderbuffer = function() {
+ glsFboUtil.Image.call(this);
+ this.type |= glsFboUtil.Config.s_types.RENDERBUFFER;
+ this.target = glsFboUtil.Config.s_target.RENDERBUFFER;
+ this.numSamples = 0;
+ };
+
+ /**
+ * glsFboUtil.Texture Class.
+ * @constructor
+ * @extends {glsFboUtil.Image}
+ */
+ glsFboUtil.Texture = function() {
+ glsFboUtil.Image.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE;
+ this.numLevels = 1;
+ };
+
+ /**
+ * glsFboUtil.TextureFlat Class.
+ * @constructor
+ * @extends {glsFboUtil.Texture}
+ */
+ glsFboUtil.TextureFlat = function() {
+ glsFboUtil.Texture.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_FLAT;
+ };
+
+ /**
+ * glsFboUtil.Texture2D Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureFlat}
+ */
+ glsFboUtil.Texture2D = function() {
+ glsFboUtil.TextureFlat.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_2D;
+ this.target = glsFboUtil.Config.s_target.TEXTURE_2D;
+ };
+
+ /**
+ * glsFboUtil.TextureCubeMap Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureFlat}
+ */
+ glsFboUtil.TextureCubeMap = function() {
+ glsFboUtil.TextureFlat.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP;
+ this.target = glsFboUtil.Config.s_target.TEXTURE_CUBE_MAP;
+ };
+
+ /**
+ * glsFboUtil.TextureLayered Class.
+ * @constructor
+ * @extends {glsFboUtil.Texture}
+ */
+ glsFboUtil.TextureLayered = function() {
+ glsFboUtil.Texture.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_LAYERED;
+ this.numLayers = 1;
+ };
+
+ /**
+ * glsFboUtil.Texture3D Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureLayered}
+ */
+ glsFboUtil.Texture3D = function() {
+ glsFboUtil.TextureLayered.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_3D;
+ this.target = glsFboUtil.Config.s_target.TEXTURE_3D;
+ };
+
+ /**
+ * glsFboUtil.Texture2DArray Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureLayered}
+ */
+ glsFboUtil.Texture2DArray = function() {
+ glsFboUtil.TextureLayered.call(this);
+ this.type |= glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY;
+ this.target = glsFboUtil.Config.s_target.TEXTURE_2D_ARRAY;
+ };
+
+ /**
+ * glsFboUtil.Attachment Class.
+ * @constructor
+ * @extends {glsFboUtil.Config}
+ */
+ glsFboUtil.Attachment = function() {
+ glsFboUtil.Config.call(this);
+
+ this.type |= glsFboUtil.Config.s_types.ATTACHMENT;
+
+ /** @type {glsFboUtil.Config.s_target} */
+ this.target = glsFboUtil.Config.s_target.FRAMEBUFFER;
+
+ /** @type {WebGLObject} */
+ this.imageName = null;
+ };
+
+ /**
+ * this function is declared, but has no definition/is unused in the c++
+ * @param {number} attPoint
+ * @param {number} image
+ * @param {number} vfr
+ */
+ glsFboUtil.Attachment.prototype.isComplete = function(attPoint, image, vfr) { };
+
+ /**
+ * glsFboUtil.RenderBufferAttachments Class.
+ * @constructor
+ * @extends {glsFboUtil.Attachment}
+ */
+ glsFboUtil.RenderbufferAttachment = function() {
+ glsFboUtil.Attachment.call(this);
+ this.type |= glsFboUtil.Config.s_types.ATT_RENDERBUFFER;
+ this.renderbufferTarget = glsFboUtil.Config.s_target.RENDERBUFFER;
+ };
+ glsFboUtil.RenderbufferAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
+ glsFboUtil.RenderbufferAttachment.prototype.constructor = glsFboUtil.RenderbufferAttachment;
+
+ /**
+ * glsFboUtil.TextureAttachment Class.
+ * @constructor
+ * @extends {glsFboUtil.Attachment}
+ */
+ glsFboUtil.TextureAttachment = function() {
+ glsFboUtil.Attachment.call(this);
+ this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE;
+ this.level = 0;
+ };
+ glsFboUtil.TextureAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
+ glsFboUtil.TextureAttachment.prototype.constructor = glsFboUtil.TextureAttachment;
+
+ /**
+ * glsFboUtil.TextureFlatAttachment Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureAttachment}
+ */
+ glsFboUtil.TextureFlatAttachment = function() {
+ glsFboUtil.TextureAttachment.call(this);
+ this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT;
+ this.texTarget = glsFboUtil.Config.s_target.NONE;
+ };
+ glsFboUtil.TextureFlatAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
+ glsFboUtil.TextureFlatAttachment.prototype.constructor = glsFboUtil.TextureFlatAttachment;
+
+ /**
+ * glsFboUtil.TextureLayerAttachment Class.
+ * @constructor
+ * @extends {glsFboUtil.TextureAttachment}
+ */
+ glsFboUtil.TextureLayerAttachment = function() {
+ glsFboUtil.TextureAttachment.call(this);
+ this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER;
+ this.layer = 0;
+ };
+ glsFboUtil.TextureLayerAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
+ glsFboUtil.TextureLayerAttachment.prototype.constructor = glsFboUtil.TextureLayerAttachment;
+
+ // these are a collection of helper functions for creating various gl textures.
+ glsFboUtil.glsup = function() {
+
+ var glInit = function(cfg, gl) {
+ if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D) != 0) {
+ glInitFlat(cfg, glTarget(cfg, gl), gl);
+
+ } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP) != 0) {
+ for (var i = gl.TEXTURE_CUBE_MAP_NEGATIVE_X; i <= gl.TEXTURE_CUBE_MAP_POSITIVE_Z; ++i)
+ glInitFlat(cfg, i, gl);
+ } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_3D) != 0) {
+ glInitLayered(cfg, 2, gl);
+
+ } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY) != 0) {
+ glInitLayered(cfg, 1, gl);
+ }
+ };
+
+ var glInitFlat = function(cfg, target, gl) {
+ var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
+ var w = cfg.width;
+ var h = cfg.height;
+ for (var level = 0; level < cfg.numLevels; ++level) {
+ gl.texImage2D(
+ target, level, cfg.internalFormat.format,
+ w, h, 0, format.format, format.dataType, null
+ );
+ w = Math.max(1, w / 2);
+ h = Math.max(1, h / 2);
+ }
+ };
+
+ var glInitLayered = function(cfg, depth_divider, gl) {
+ var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
+ var w = cfg.width;
+ var h = cfg.height;
+ var depth = cfg.numLayers;
+ for (var level = 0; level < cfg.numLevels; ++level) {
+ gl.texImage3D(
+ glTarget(cfg, gl), level, cfg.internalFormat.format,
+ w, h, depth, 0, format.format, format.dataType, null
+ );
+ w = Math.max(1, w / 2);
+ h = Math.max(1, h / 2);
+ depth = Math.max(1, depth / depth_divider);
+ }
+ };
+
+ var glCreate = function(cfg, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER) {
+ var ret = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, ret);
+
+ if (cfg.numSamples == 0) {
+ gl.renderbufferStorage(
+ gl.RENDERBUFFER,
+ cfg.internalFormat.format,
+ cfg.width, cfg.height
+ );
+ } else {
+ gl.renderbufferStorageMultisample(
+ gl.RENDERBUFFER,
+ cfg.numSamples,
+ cfg.internalFormat.format,
+ cfg.width, cfg.height
+ );
+ }
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+
+ } else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE) {
+ var ret = gl.createTexture();
+ gl.bindTexture(glTarget(cfg, gl), ret);
+ glInit(cfg, gl);
+ gl.bindTexture(glTarget(cfg, gl), null);
+
+ } else {
+ throw new Error('Impossible image type');
+ }
+ return ret;
+ };
+
+ var glTarget = function(cfg, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+ var mask = (
+ glsFboUtil.Config.s_types.RENDERBUFFER |
+ glsFboUtil.Config.s_types.TEXTURE_2D |
+ glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP |
+ glsFboUtil.Config.s_types.TEXTURE_3D |
+ glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY
+ );
+ switch (cfg.type & mask) {
+ case glsFboUtil.Config.s_types.RENDERBUFFER: return gl.RENDERBUFFER;
+ case glsFboUtil.Config.s_types.TEXTURE_2D: return gl.TEXTURE_2D;
+ case glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP: return gl.TEXTURE_CUBE_MAP;
+ case glsFboUtil.Config.s_types.TEXTURE_3D: return gl.TEXTURE_3D;
+ case glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY: return gl.TEXTURE_2D_ARRAY;
+ default: break;
+ }
+ throw new Error('Impossible image type.');
+ };
+
+ var glDelete = function(cfg, img, gl) {
+ if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER)
+ gl.deleteRenderbuffer(img);
+ else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE)
+ gl.deleteTexture(img);
+ else
+ throw new Error('Impossible image type');
+ };
+
+ return {
+ create: glCreate,
+ remove: glDelete
+ };
+
+ }();
+
+ /** *generated by script*
+ * @param {number} img
+ * @return {number}
+ */
+ glsFboUtil.imageNumSamples = function(img) {
+ return (img.numSamples != undefined) ? img.numSamples : 0;
+ };
+
+ /** *generated by script*
+ * @param {glsFboUtil.Attachment} att
+ * @param {number} attPoint
+ * @param {WebGLRenderingContextBase=} gl
+ * @throws {Error}
+ */
+ glsFboUtil.attachAttachment = function(att, attPoint, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ var mask = (
+ glsFboUtil.Config.s_types.ATT_RENDERBUFFER |
+ glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT |
+ glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER
+ );
+
+ switch (att.type & mask) {
+ case glsFboUtil.Config.s_types.ATT_RENDERBUFFER:
+ gl.framebufferRenderbuffer(
+ att.target, attPoint, att.renderbufferTarget, /** @type {WebGLRenderbuffer} */(att.imageName)
+ );
+ break;
+ case glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT:
+ gl.framebufferTexture2D(
+ att.target, attPoint, att.texTarget, /** @type {WebGLTexture} */(att.imageName), att.level
+ );
+ break;
+ case glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER:
+ gl.framebufferTextureLayer(
+ att.target, attPoint, /** @type {WebGLTexture} */(att.imageName), att.level, att.layer
+ );
+ break;
+ default:
+ throw new Error('Impossible attachment type');
+ }
+
+ };
+
+ /** *generated by script*
+ * @param {glsFboUtil.Attachment} att
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {number}
+ * @throws {Error}
+ */
+ glsFboUtil.attachmentType = function(att, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ if (att.type & glsFboUtil.Config.s_types.ATT_RENDERBUFFER) {
+ return gl.RENDERBUFFER;
+ }
+ if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) {
+ return gl.TEXTURE;
+ }
+ throw new Error('Impossible attachment type.');
+
+ };
+
+ /**
+ * @param {glsFboUtil.Attachment} att
+ * @return {number}
+ * @throws {Error}
+ */
+ glsFboUtil.textureLayer = function(att) {
+ if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT) return 0;
+ if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER) return att.layer;
+ throw new Error('Impossible attachment type.');
+ };
+
+ /**
+ * @param {glsFboUtil.Checker} cctx
+ * @param {glsFboUtil.Attachment} att
+ * @param {number} attPoint
+ * @param {glsFboUtil.Image} image
+ * @param {glsFboUtil.FormatDB} db
+ * @param {WebGLRenderingContextBase=} gl
+ * @throws {Error}
+ */
+ glsFboUtil.checkAttachmentCompleteness = function(cctx, att, attPoint, image, db, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ // GLES2 4.4.5 / GLES3 4.4.4, "glsFboUtil.Framebuffer attachment completeness"
+ if (
+ (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) &&
+ (image.type & glsFboUtil.Config.s_types.TEXTURE_LAYERED)
+ ) {
+ // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
+ // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
+ // three-dimensional texture, then the value of
+ // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
+ // of the texture.
+ //
+ // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
+ // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
+ // two-dimensional array texture, then the value of
+ // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
+ // number of layers in the texture.
+ cctx.addFBOStatus(
+ glsFboUtil.textureLayer(att) < image.numLayers,
+ gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+ );
+ }
+
+ // "The width and height of image are non-zero."
+ cctx.addFBOStatus(
+ image.width > 0 && image.height > 0,
+ gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+ );
+
+ // Check for renderability
+ var flags = db.getFormatInfo(image.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
+
+ // If the format does not have the proper renderability flag, the
+ // completeness check _must_ fail.
+ cctx.addFBOStatus(
+ (flags & glsFboUtil.formatFlag(attPoint)) != 0,
+ gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+ );
+
+ // If the format is only optionally renderable, the completeness check _can_ fail.
+ cctx.addPotentialFBOStatus(
+ (flags & glsFboUtil.FormatFlags.REQUIRED_RENDERABLE) != 0,
+ gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
+ );
+
+ };
+
+ // replaces GLS_UNSIZED_FORMATKEY
+
+ /**
+ * All params and return types for this function are 32 bit
+ * @param {number} format
+ * @param {number} type
+ * @return {number}
+ */
+ glsFboUtil.formatkey = function(format, type) {
+ // The formatkey value should be 32-bit unsigned int.
+ return ((type << 16) >>> 0 | format) & 0xFFFFFFFF;
+ };
+
+ /**
+ * @enum
+ */
+ glsFboUtil.FormatFlags = {
+ ANY_FORMAT: 0x00,
+ COLOR_RENDERABLE: 0x01,
+ DEPTH_RENDERABLE: 0x02,
+ STENCIL_RENDERABLE: 0x04,
+ RENDERBUFFER_VALID: 0x08,
+ TEXTURE_VALID: 0x10,
+ REQUIRED_RENDERABLE: 0x20 //< Without this, renderability is allowed, not required.
+ };
+
+ /**
+ * A framebuffer configuration
+ * @constructor
+ * @param {WebGLRenderingContextBase=} gl
+ */
+ glsFboUtil.Framebuffer = function(gl) {
+ this.m_gl = gl || window.gl;
+ this.fbid = 0;
+
+ var fbidCompare = function(obj1, obj2) {
+ return obj1._fbid < obj2._fbid;
+ };
+
+ this.attachments = /** @type {glsFboUtil.Map<number,glsFboUtil.Attachment>} */(
+ new glsFboUtil.Map(glsFboUtil.Map.compareNumber)
+ );
+ this.textures = /** @type {glsFboUtil.Map<Object,glsFboUtil.Texture>} */(
+ new glsFboUtil.Map(fbidCompare)
+ );
+ this.rbos = /** @type {glsFboUtil.Map<Object,glsFboUtil.Renderbuffer>} */(
+ new glsFboUtil.Map(fbidCompare)
+ );
+ };
+
+ /**
+ * @param {number} attPoint
+ * @param {glsFboUtil.Attachment} att
+ */
+ glsFboUtil.Framebuffer.prototype.attach = function(attPoint, att) {
+ if (!att) {
+ this.attachments.remove(attPoint);
+ } else {
+ this.attachments.set(attPoint, att);
+ }
+ };
+
+ /**
+ * @param {WebGLTexture} texName
+ * @param {glsFboUtil.Texture} texCfg
+ */
+ glsFboUtil.Framebuffer.prototype.setTexture = function(texName, texCfg) {
+ texName._fbid = this.fbid++;
+ this.textures.set(texName, texCfg);
+ };
+
+ /**
+ * @param {WebGLRenderbuffer} rbName
+ * @param {glsFboUtil.Renderbuffer} rbCfg
+ */
+ glsFboUtil.Framebuffer.prototype.setRbo = function(rbName, rbCfg) {
+ rbName._fbid = this.fbid++;
+ this.rbos.set(rbName, rbCfg);
+ };
+
+ /**
+ * @param {number} type
+ * @param {WebGLObject} imgName
+ * @return {glsFboUtil.Image}
+ * @throws {Error}
+ */
+ glsFboUtil.Framebuffer.prototype.getImage = function(type, imgName) {
+ switch (type) {
+ case this.m_gl.TEXTURE: return this.textures.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
+ case this.m_gl.RENDERBUFFER: return this.rbos.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
+ default: break;
+ }
+ throw new Error('Bad image type.');
+ };
+
+ /**
+ * @constructor
+ * @extends {glsFboUtil.Framebuffer}
+ * @param {WebGLFramebuffer} fbo
+ * @param {number} target
+ * @param {WebGLRenderingContextBase=} gl
+ */
+ glsFboUtil.FboBuilder = function(fbo, target, gl) {
+ glsFboUtil.Framebuffer.call(this, gl);
+
+ this.m_gl = gl || window.gl;
+ this.m_target = target;
+ this.m_configs = [];
+ this.m_error = this.m_gl.NO_ERROR;
+
+ this.m_gl.bindFramebuffer(this.m_target, fbo);
+
+ };
+
+ glsFboUtil.FboBuilder.prototype = Object.create(glsFboUtil.Framebuffer.prototype);
+ glsFboUtil.FboBuilder.prototype.constructor = glsFboUtil.FboBuilder;
+
+ glsFboUtil.FboBuilder.prototype.deinit = function() {
+
+ var pair;
+ for (var i = 0; i < this.textures.length; ++i) {
+ pair = this.textures.getIndex(i);
+ glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
+ }
+ this.textures.clear();
+
+ for (var i = 0; i < this.rbos.length; ++i) {
+ pair = this.rbos.getIndex(i);
+ glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
+ }
+ this.rbos.clear();
+
+ this.m_gl.bindFramebuffer(this.m_target, null);
+/*
+ for (var i = 0 ; i < this.m_configs.length ; ++i) {
+ delete this.m_configs[i];
+ }
+//*/
+ };
+
+ /**
+ * @param {number} attPoint
+ * @param {glsFboUtil.Attachment} att
+ */
+ glsFboUtil.FboBuilder.prototype.glAttach = function(attPoint, att) {
+ if (!att) {
+ this.m_gl.framebufferRenderbuffer(this.m_target, attPoint, this.m_gl.RENDERBUFFER, null);
+ } else {
+ glsFboUtil.attachAttachment(att, attPoint, this.m_gl);
+ }
+ this.checkError();
+ this.attach(attPoint, att);
+ };
+
+ /**
+ * @param {glsFboUtil.Texture} texCfg
+ * @return {WebGLTexture}
+ */
+ glsFboUtil.FboBuilder.prototype.glCreateTexture = function(texCfg) {
+ var texName = glsFboUtil.glsup.create(texCfg, this.m_gl);
+ this.checkError();
+ this.setTexture(texName, texCfg);
+ return texName;
+ };
+
+ /** *generated by script*
+ * @param {glsFboUtil.Renderbuffer} rbCfg
+ * @return {WebGLRenderbuffer}
+ */
+ glsFboUtil.FboBuilder.prototype.glCreateRbo = function(rbCfg) {
+ var rbName = glsFboUtil.glsup.create(rbCfg, this.m_gl);
+ this.checkError();
+ this.setRbo(rbName, rbCfg);
+ return rbName;
+ };
+
+ /**
+ * @param {function(new:glsFboUtil.Config)} Definition
+ * @return {glsFboUtil.Config}
+ */
+ glsFboUtil.FboBuilder.prototype.makeConfig = function(Definition) {
+ var cfg = new Definition();
+ this.m_configs.push(cfg);
+ return cfg;
+ };
+
+ /**
+ */
+ glsFboUtil.FboBuilder.prototype.checkError = function() {
+ var error = this.m_gl.getError();
+ if (error != this.m_gl.NO_ERROR && this.m_error == this.m_gl.NO_ERROR) {
+ this.m_error = error;
+ }
+ };
+
+ /** *generated by script*
+ * @return {number}
+ */
+ glsFboUtil.FboBuilder.prototype.getError = function() {
+ return this.m_error;
+ };
+
+ glsFboUtil.isFramebufferStatus = function(fboStatus) {
+ return gluStrUtil.getFramebufferStatusName(fboStatus) != '';
+ }
+
+ glsFboUtil.isErrorCode = function(errorCode) {
+ return gluStrUtil.getErrorName(errorCode) != '';
+ }
+
+ /**
+ * @typedef {funcion(): glsFboUtil.ValidStatusCodes}
+ */
+ glsFboUtil.ValidStatusCodes = function() {
+ this.m_errorCodes = [];
+ this.m_errorStatusCodes = [];
+ this.m_allowComplete = false;
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.isFBOStatusValid = function(fboStatus) {
+ if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
+ return this.m_allowComplete;
+ else {
+ for(var ndx = 0; ndx < this.m_errorStatusCodes.length; ++ndx) {
+ if (this.m_errorStatusCodes[ndx] == fboStatus)
+ return true;
+ }
+ return false;
+ }
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.isFBOStatusRequired = function(fboStatus) {
+ if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
+ return this.m_allowComplete && this.m_errorStatusCodes.length == 0;
+ else
+ // fboStatus is the only allowed error status and succeeding is forbidden
+ return !this.m_allowComplete && this.m_errorStatusCodes.length == 1 && this.m_errorStatusCodes[0] == fboStatus;
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.isErrorCodeValid = function(errorCode) {
+ if (errorCode == gl.NO_ERROR)
+ return this.m_errorCodes.length == 0;
+ else {
+ // rule violation exists?
+ for (var ndx = 0; ndx < this.m_errorCodes.length; ++ndx) {
+ if (this.m_errorCodes[ndx] == errorCode)
+ return true;
+ }
+ return false;
+ }
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.isErrorCodeRequired = function(errorCode) {
+ if (this.m_errorCodes.length == 0 && errorCode == gl.NO_ERROR)
+ return true;
+ else
+ // only this error code listed
+ return this.m_errorCodes.length == 1 && merrorCodes[0] == errorCode;
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.addErrorCode = function(error) {
+ DE_ASSERT(glsFboUtil.isErrorCode(error));
+ DE_ASSERT(error != gl.NO_ERROR)
+ this.m_errorCodes.push(error);
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.addFBOErrorStatus = function(status) {
+ DE_ASSERT(glsFboUtil.isFramebufferStatus(status));
+ DE_ASSERT(status != gl.FRAMEBUFFER_COMPLETE)
+ this.m_errorStatusCodes.push(status);
+ };
+
+ glsFboUtil.ValidStatusCodes.prototype.setAllowComplete = function(b) {
+ this.m_allowComplete = b;
+ };
+
+ /**
+ * @typedef {function(): glsFboUtil.Checker}
+ */
+ glsFboUtil.CheckerFactory;
+
+ /**
+ * @constructor
+ * @param {WebGLRenderingContextBase=} gl
+ * @throws {Error}
+ */
+ glsFboUtil.Checker = function(gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ this.m_statusCodes = new glsFboUtil.ValidStatusCodes();
+ this.m_statusCodes.setAllowComplete(true);
+
+ if (typeof(this.check) != 'function')
+ throw new Error('Constructor called on virtual class: glsFboUtil.Checker');
+ };
+
+ /**
+ * @param {boolean} condition
+ * @param {number} error
+ */
+ glsFboUtil.Checker.prototype.addGLError = function(condition, error) {
+ if (!condition) {
+ this.m_statusCodes.addErrorCode(error);
+ this.m_statusCodes.setAllowComplete(false);
+ }
+ };
+
+ /**
+ * @param {boolean} condition
+ * @param {number} error
+ */
+ glsFboUtil.Checker.prototype.addPotentialGLError = function(condition, error) {
+ if (!condition) {
+ this.m_statusCodes.addErrorCode(error);
+ }
+ };
+
+ /**
+ * @param {boolean} condition
+ * @param {number} status
+ */
+ glsFboUtil.Checker.prototype.addFBOStatus = function(condition, status) {
+ if (!condition) {
+ this.m_statusCodes.addFBOErrorStatus(status);
+ this.m_statusCodes.setAllowComplete(false);
+ }
+ };
+
+ /**
+ * @param {boolean} condition
+ * @param {number} status
+ */
+ glsFboUtil.Checker.prototype.addPotentialFBOStatus = function(condition, status) {
+ if (!condition) {
+ this.m_statusCodes.addFBOErrorStatus(status);
+ }
+ };
+
+ /**
+ * @return {Array<number>}
+ */
+ glsFboUtil.Checker.prototype.getStatusCodes = function () {
+ return this.m_statusCodes;
+ };
+
+ /**
+ * @param {glsFboUtil.ImageFormat} imgFormat
+ * @param {WebGLRenderingContextBase=} gl
+ * @return {gluTextureUtil.TransferFormat}
+ * @throws {Error}
+ */
+ glsFboUtil.transferImageFormat = function(imgFormat, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+ if (imgFormat.unsizedType == gl.NONE)
+ return gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(imgFormat.format));
+ else
+ return new gluTextureUtil.TransferFormat(imgFormat.format, imgFormat.unsizedType);
+ };
+
+ // FormatDB, CheckerFactory
+
+ /**
+ * @constructor
+ * @param {glsFboUtil.FormatDB} formats
+ * @param {glsFboUtil.CheckerFactory} factory
+ */
+ glsFboUtil.FboVerifier = function(formats, factory) {
+ this.m_formats = formats;
+ this.m_factory = factory;
+ };
+ // config::Framebuffer
+ glsFboUtil.FboVerifier.prototype.validStatusCodes = function(cfg, gl) {
+ if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
+
+ /** @type {glsFboUtil.Checker} */
+ var cctx = this.m_factory();
+
+ for (var id = 0; id < cfg.textures.length; ++id) {
+ var flags = this.m_formats.getFormatInfo(cfg.textures.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
+ var textureIsValid = (flags & glsFboUtil.FormatFlags.TEXTURE_VALID) != 0;
+ cctx.addGLError(textureIsValid, gl.INVALID_ENUM);
+ cctx.addGLError(textureIsValid, gl.INVALID_OPERATION);
+ cctx.addGLError(textureIsValid, gl.INVALID_VALUE);
+ }
+
+ for (var id = 0; id < cfg.rbos.length; ++id) {
+ var flags = this.m_formats.getFormatInfo(cfg.rbos.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
+ var rboIsValid = (flags & glsFboUtil.FormatFlags.RENDERBUFFER_VALID) != 0;
+ cctx.addGLError(rboIsValid, gl.INVALID_ENUM);
+ }
+
+ var count = 0;
+ for (var index = 0; index < cfg.attachments.length; ++index) {
+ var attPoint = cfg.attachments.getIndex(index).first;
+ var att = cfg.attachments.getIndex(index).second;
+ /** @type {glsFboUtil.Image}*/
+ var image = cfg.getImage(glsFboUtil.attachmentType(att, gl), att.imageName);
+ glsFboUtil.checkAttachmentCompleteness(cctx, att, attPoint, image, this.m_formats, gl);
+ cctx.check(attPoint, att, image);
+ ++count;
+ }
+
+ // "There is at least one image attached to the framebuffer."
+ // TODO: support XXX_framebuffer_no_attachments
+ cctx.addFBOStatus(count > 0, gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
+
+ return cctx.getStatusCodes();
+
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsLifetimeTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsLifetimeTests.js
new file mode 100644
index 000000000..427a3a4fc
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsLifetimeTests.js
@@ -0,0 +1,1118 @@
+/*-------------------------------------------------------------------------
+ * 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.glsLifetimeTests');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuStringTemplate');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('modules.shared.glsTextureTestUtil');
+
+goog.scope(function() {
+var glsLifetimeTests = modules.shared.glsLifetimeTests;
+var tcuStringTemplate = framework.common.tcuStringTemplate;
+var tcuSurface = framework.common.tcuSurface;
+var deRandom = framework.delibs.debase.deRandom;
+var glsTextureTestUtil = modules.shared.glsTextureTestUtil;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+var tcuTestCase = framework.common.tcuTestCase;
+var tcuImageCompare = framework.common.tcuImageCompare;
+
+/** @const */ var VIEWPORT_SIZE = 128;
+/** @const */ var FRAMEBUFFER_SIZE = 128;
+
+var setParentClass = function(child, parent) {
+ child.prototype = Object.create(parent.prototype);
+ child.prototype.constructor = child;
+};
+
+/** @const */ var s_vertexShaderSrc =
+ '#version 100\n' +
+ 'attribute vec2 pos;\n' +
+ 'void main()\n' +
+ '{\n' +
+ ' gl_Position = vec4(pos.xy, 0.0, 1.0);\n' +
+ '}\n';
+
+/** @const */ var s_fragmentShaderSrc =
+ '#version 100\n' +
+ 'void main()\n' +
+ '{\n' +
+ ' gl_FragColor = vec4(1.0);\n' +
+ '}\n';
+
+/**
+ * @constructor
+ * @extends {gluShaderProgram.Shader}
+ * @param {gluShaderProgram.shaderType} type
+ * @param {string} src
+ */
+glsLifetimeTests.CheckedShader = function(type, src) {
+ gluShaderProgram.Shader.call(this, gl, type);
+ this.setSources(src);
+ this.compile();
+ assertMsgOptions(this.getCompileStatus() === true, 'Failed to compile shader', false, true);
+};
+
+setParentClass(glsLifetimeTests.CheckedShader, gluShaderProgram.Shader);
+
+/**
+ * @constructor
+ * @extends {gluShaderProgram.Program}
+ * @param {WebGLShader} vtxShader
+ * @param {WebGLShader} fragShader
+ */
+glsLifetimeTests.CheckedProgram = function(vtxShader, fragShader) {
+ gluShaderProgram.Program.call(this, gl);
+ this.attachShader(vtxShader);
+ this.attachShader(fragShader);
+ this.link();
+ assertMsgOptions(this.info.linkOk === true, 'Failed to link program', false, true);
+};
+
+setParentClass(glsLifetimeTests.CheckedProgram, gluShaderProgram.Program);
+
+/**
+ * @constructor
+ */
+glsLifetimeTests.Binder = function() {
+};
+
+/**
+ * @param {WebGLObject} obj
+ */
+glsLifetimeTests.Binder.prototype.bind = function(obj) { throw new Error('Virtual function'); };
+
+/**
+ * @return {WebGLObject}
+ */
+glsLifetimeTests.Binder.prototype.getBinding = function() { throw new Error('Virtual function'); };
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Binder}
+ * @param {?function(number, ?)} bindFunc
+ * @param {number} bindTarget
+ * @param {number} bindingParam
+ */
+glsLifetimeTests.SimpleBinder = function(bindFunc, bindTarget, bindingParam) {
+ glsLifetimeTests.Binder.call(this);
+ this.m_bindFunc = bindFunc;
+ this.m_bindTarget = bindTarget;
+ this.m_bindingParam = bindingParam;
+};
+
+setParentClass(glsLifetimeTests.SimpleBinder, glsLifetimeTests.Binder);
+
+glsLifetimeTests.SimpleBinder.prototype.bind = function(obj) {
+ this.m_bindFunc.call(gl, this.m_bindTarget, obj);
+};
+
+glsLifetimeTests.SimpleBinder.prototype.getBinding = function() {
+ return /** @type {WebGLObject} */ (gl.getParameter(this.m_bindingParam));
+};
+
+/**
+ * @constructor
+ */
+glsLifetimeTests.Type = function() {
+};
+
+/**
+ * Create a type
+ * @return {WebGLObject}
+ */
+glsLifetimeTests.Type.prototype.gen = function() { throw new Error('Virtual function'); };
+
+/**
+ * Destroy a type
+ * @param {WebGLObject} obj
+ */
+glsLifetimeTests.Type.prototype.release = function(obj) { throw new Error('Virtual function'); };
+
+/**
+ * Is object valid
+ * @param {WebGLObject} obj
+ */
+glsLifetimeTests.Type.prototype.exists = function(obj) { throw new Error('Virtual function'); };
+
+/**
+ * Is object flagged for deletion
+ * @param {WebGLObject} obj
+ */
+glsLifetimeTests.Type.prototype.isDeleteFlagged = function(obj) { return false; };
+
+/**
+ * @return {glsLifetimeTests.Binder}
+ */
+glsLifetimeTests.Type.prototype.binder = function() { return null; };
+
+/**
+ * @return {string}
+ */
+glsLifetimeTests.Type.prototype.getName = function() { throw new Error('Virtual function'); };
+
+/**
+ * Is the object unbound automatically when it is deleted?
+ * @return {boolean}
+ */
+glsLifetimeTests.Type.prototype.nameLingers = function() { return false; };
+
+/**
+ * Does 'create' creates the object fully?
+ * If not, the object is created at bound time
+ * @return {boolean}
+ */
+glsLifetimeTests.Type.prototype.genCreates = function() { return false; };
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Type}
+ * @param {string} name
+ * @param {function(): WebGLObject} genFunc
+ * @param {function(?)} deleteFunc
+ * @param {function(?): boolean} existsFunc
+ * @param {glsLifetimeTests.Binder} binder
+ * @param {boolean=} genCreates
+ */
+glsLifetimeTests.SimpleType = function(name, genFunc, deleteFunc, existsFunc, binder, genCreates) {
+ glsLifetimeTests.Type.call(this);
+ this.m_getName = name;
+ this.m_genFunc = genFunc;
+ this.m_deleteFunc = deleteFunc;
+ this.m_existsFunc = existsFunc;
+ this.m_binder = binder;
+ this.m_genCreates = genCreates || false;
+};
+
+setParentClass(glsLifetimeTests.SimpleType, glsLifetimeTests.Type);
+
+glsLifetimeTests.SimpleType.prototype.gen = function() { return this.m_genFunc.call(gl); };
+
+glsLifetimeTests.SimpleType.prototype.release = function(obj) { return this.m_deleteFunc.call(gl, obj); };
+
+glsLifetimeTests.SimpleType.prototype.exists = function(obj) { return this.m_existsFunc.call(gl, obj); };
+
+glsLifetimeTests.SimpleType.prototype.binder = function() { return this.m_binder; };
+
+glsLifetimeTests.SimpleType.prototype.getName = function() { return this.m_getName; };
+
+glsLifetimeTests.SimpleType.prototype.genCreates = function() { return this.m_genCreates; };
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Type}
+ */
+glsLifetimeTests.ProgramType = function() {
+ glsLifetimeTests.Type.call(this);
+};
+
+setParentClass(glsLifetimeTests.ProgramType, glsLifetimeTests.Type);
+
+glsLifetimeTests.ProgramType.prototype.gen = function() { return gl.createProgram(); };
+
+glsLifetimeTests.ProgramType.prototype.release = function(obj) { return gl.deleteProgram(/** @type {WebGLProgram} */ (obj)); };
+
+glsLifetimeTests.ProgramType.prototype.exists = function(obj) { return gl.isProgram(/** @type {WebGLProgram} */ (obj)); };
+
+glsLifetimeTests.ProgramType.prototype.getName = function() { return 'program'; };
+
+glsLifetimeTests.ProgramType.prototype.genCreates = function() { return true; };
+
+glsLifetimeTests.ProgramType.prototype.nameLingers = function() { return true; };
+
+glsLifetimeTests.ProgramType.prototype.isDeleteFlagged = function(obj) { return gl.getProgramParameter(/** @type {WebGLProgram} */ (obj), gl.DELETE_STATUS); };
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Type}
+ */
+glsLifetimeTests.ShaderType = function() {
+ glsLifetimeTests.Type.call(this);
+};
+
+setParentClass(glsLifetimeTests.ShaderType, glsLifetimeTests.Type);
+
+glsLifetimeTests.ShaderType.prototype.gen = function() { return gl.createShader(gl.FRAGMENT_SHADER); };
+
+glsLifetimeTests.ShaderType.prototype.release = function(obj) { return gl.deleteShader(/** @type {WebGLShader} */ (obj)); };
+
+glsLifetimeTests.ShaderType.prototype.exists = function(obj) { return gl.isShader(/** @type {WebGLShader} */ (obj)); };
+
+glsLifetimeTests.ShaderType.prototype.getName = function() { return 'shader'; };
+
+glsLifetimeTests.ShaderType.prototype.genCreates = function() { return true; };
+
+glsLifetimeTests.ShaderType.prototype.nameLingers = function() { return true; };
+
+glsLifetimeTests.ShaderType.prototype.isDeleteFlagged = function(obj) { return gl.getShaderParameter(/** @type {WebGLShader} */ (obj), gl.DELETE_STATUS); };
+
+/**
+ * @constructor
+ * @param {glsLifetimeTests.Type} elementType
+ * @param {glsLifetimeTests.Type} containerType
+ */
+glsLifetimeTests.Attacher = function(elementType, containerType) {
+ this.m_elementType = elementType;
+ this.m_containerType = containerType;
+};
+
+/**
+ * @param {number} seed
+ * @param {WebGLObject} obj
+ */
+glsLifetimeTests.Attacher.prototype.initAttachment = function(seed, obj) { throw new Error('Virtual function'); };
+
+/**
+ * @param {WebGLObject} element
+ * @param {WebGLObject} target
+ */
+glsLifetimeTests.Attacher.prototype.attach = function(element, target) { throw new Error('Virtual function'); };
+
+/**
+ * @param {WebGLObject} element
+ * @param {WebGLObject} target
+ */
+glsLifetimeTests.Attacher.prototype.detach = function(element, target) { throw new Error('Virtual function'); };
+glsLifetimeTests.Attacher.prototype.canAttachDeleted = function() { return true; };
+
+/**
+ * @return {glsLifetimeTests.Type}
+ */
+glsLifetimeTests.Attacher.prototype.getElementType = function() { return this.m_elementType; };
+
+/**
+ * @return {glsLifetimeTests.Type}
+ */
+glsLifetimeTests.Attacher.prototype.getContainerType = function() { return this.m_containerType; };
+
+/**
+ * @constructor
+ */
+glsLifetimeTests.InputAttacher = function(attacher) {
+ this.m_attacher = attacher;
+};
+
+glsLifetimeTests.InputAttacher.prototype.getAttacher = function() { return this.m_attacher; };
+
+/**
+ * @param {WebGLObject} container
+ * @param {tcuSurface.Surface} dst
+ */
+glsLifetimeTests.InputAttacher.prototype.drawContainer = function(container, dst) { throw new Error('Virtual function'); };
+
+/**
+ * @constructor
+ */
+glsLifetimeTests.OutputAttacher = function(attacher) {
+ this.m_attacher = attacher;
+};
+
+glsLifetimeTests.OutputAttacher.prototype.getAttacher = function() { return this.m_attacher; };
+
+/**
+ * @param {number} seed
+ * @param {WebGLObject} container
+ */
+glsLifetimeTests.OutputAttacher.prototype.setupContainer = function(seed, container) { throw new Error('Virtual function'); };
+
+/**
+ * @param {WebGLObject} attachment
+ * @param {tcuSurface.Surface} dst
+ */
+glsLifetimeTests.OutputAttacher.prototype.drawAttachment = function(attachment, dst) { throw new Error('Virtual function'); };
+
+/**
+ * @constructor
+ */
+glsLifetimeTests.Types = function() {
+ /** @type {Array<glsLifetimeTests.Type>} */ this.m_types = [];
+ /** @type {Array<glsLifetimeTests.Attacher>} */ this.m_attachers = [];
+ /** @type {Array<glsLifetimeTests.InputAttacher>} */ this.m_inAttachers = [];
+ /** @type {Array<glsLifetimeTests.OutputAttacher>} */ this.m_outAttachers = [];
+};
+
+/**
+ * @return {glsLifetimeTests.ProgramType}
+ */
+glsLifetimeTests.Types.prototype.getProgramType = function() { throw new Error('Virtual function'); };
+
+glsLifetimeTests.Types.prototype.getTypes = function() { return this.m_types; };
+
+glsLifetimeTests.Types.prototype.getAttachers = function() { return this.m_attachers; };
+
+glsLifetimeTests.Types.prototype.getInputAttachers = function() { return this.m_inAttachers; };
+
+glsLifetimeTests.Types.prototype.getOutputAttachers = function() { return this.m_outAttachers; };
+
+/**
+ * @param {number} seed
+ * @param {WebGLFramebuffer} fbo
+ */
+glsLifetimeTests.setupFbo = function(seed, fbo) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+
+ if (seed == 0) {
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ } else {
+ var rnd = new deRandom.Random(seed);
+ var width = rnd.getInt(0, FRAMEBUFFER_SIZE);
+ var height = rnd.getInt(0, FRAMEBUFFER_SIZE);
+ var x = rnd.getInt(0, FRAMEBUFFER_SIZE - width);
+ var y = rnd.getInt(0, FRAMEBUFFER_SIZE - height);
+ var r1 = rnd.getFloat();
+ var g1 = rnd.getFloat();
+ var b1 = rnd.getFloat();
+ var a1 = rnd.getFloat();
+ var r2 = rnd.getFloat();
+ var g2 = rnd.getFloat();
+ var b2 = rnd.getFloat();
+ var a2 = rnd.getFloat();
+
+ gl.clearColor(r1, g1, b1, a1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.scissor(x, y, width, height);
+ gl.enable(gl.SCISSOR_TEST);
+ gl.clearColor(r2, g2, b2, a2);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.disable(gl.SCISSOR_TEST);
+ }
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+};
+
+/**
+ * @param {{x: number, y:number, width: number, height: number}} rect
+ * @param {tcuSurface.Surface} dst
+ */
+glsLifetimeTests.readRectangle = function(rect, dst) {
+ dst.readViewport(gl, rect);
+};
+
+/**
+ * @param {WebGLFramebuffer} fbo
+ * @param {tcuSurface.Surface} dst
+ */
+glsLifetimeTests.drawFbo = function(fbo, dst) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ dst.readViewport(gl, [0, 0, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE]);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Attacher}
+ */
+glsLifetimeTests.FboAttacher = function(elementType, containerType) {
+ glsLifetimeTests.Attacher.call(this, elementType, containerType);
+};
+
+setParentClass(glsLifetimeTests.FboAttacher, glsLifetimeTests.Attacher);
+
+glsLifetimeTests.FboAttacher.prototype.initStorage = function() { throw new Error('Virtual function'); };
+
+glsLifetimeTests.FboAttacher.prototype.initAttachment = function(seed, element) {
+ var binder = this.getElementType().binder();
+ var fbo = gl.createFramebuffer();
+
+ binder.bind(element);
+ this.initStorage();
+ binder.bind(null);
+
+ this.attach(element, fbo);
+ glsLifetimeTests.setupFbo(seed, fbo);
+ this.detach(element, fbo);
+
+ gl.deleteFramebuffer(fbo);
+
+ bufferedLogToConsole('Drew to ' + this.getElementType().getName() + ' ' + element + ' with seed ' + seed + '.');
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.InputAttacher}
+ */
+glsLifetimeTests.FboInputAttacher = function(attacher) {
+ glsLifetimeTests.InputAttacher.call(this, attacher);
+};
+
+setParentClass(glsLifetimeTests.FboInputAttacher, glsLifetimeTests.InputAttacher);
+
+glsLifetimeTests.FboInputAttacher.prototype.drawContainer = function(obj, dst) {
+ var fbo = /** @type {WebGLFramebuffer} */ (obj);
+ glsLifetimeTests.drawFbo(fbo, dst);
+ bufferedLogToConsole('Read pixels from framebuffer ' + fbo + ' to output image.');
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.OutputAttacher}
+ */
+glsLifetimeTests.FboOutputAttacher = function(attacher) {
+ glsLifetimeTests.OutputAttacher.call(this, attacher);
+};
+
+setParentClass(glsLifetimeTests.FboOutputAttacher, glsLifetimeTests.OutputAttacher);
+
+glsLifetimeTests.FboOutputAttacher.prototype.setupContainer = function(seed, fbo) {
+ glsLifetimeTests.setupFbo(seed, /** @type {WebGLFramebuffer} */ (fbo));
+ bufferedLogToConsole('Drew to framebuffer ' + fbo + ' with seed ' + seed + '.');
+};
+
+glsLifetimeTests.FboOutputAttacher.prototype.drawAttachment = function(element, dst) {
+ var fbo = gl.createFramebuffer();
+ this.m_attacher.attach(element, fbo);
+ glsLifetimeTests.drawFbo(fbo, dst);
+ this.m_attacher.detach(element, fbo);
+ gl.deleteFramebuffer(fbo);
+ bufferedLogToConsole('Read pixels from ' + this.m_attacher.getElementType().getName() + ' ' + element + ' to output image.');
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.FboAttacher}
+ */
+glsLifetimeTests.TextureFboAttacher = function(elementType, containerType) {
+ glsLifetimeTests.FboAttacher.call(this, elementType, containerType);
+};
+
+setParentClass(glsLifetimeTests.TextureFboAttacher, glsLifetimeTests.FboAttacher);
+
+glsLifetimeTests.TextureFboAttacher.prototype.initStorage = function() {
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE, 0,
+ gl.RGBA, gl.UNSIGNED_SHORT_4_4_4_4, null);
+
+};
+
+glsLifetimeTests.TextureFboAttacher.prototype.attach = function(element, target) {
+ var texture = /** @type {WebGLTexture} */ (element);
+ var fbo = /** @type {WebGLFramebuffer} */ (target);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
+ gl.TEXTURE_2D, texture, 0);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+};
+
+glsLifetimeTests.TextureFboAttacher.prototype.detach = function(texture, target) {
+ var fbo = /** @type {WebGLFramebuffer} */ (target);
+ this.attach(null, fbo);
+};
+
+glsLifetimeTests.getFboAttachment = function(fbo, requiredType) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ var type = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
+ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ var name = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
+ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ var ret = type == requiredType ? name : null;
+ return ret;
+};
+
+glsLifetimeTests.TextureFboAttacher.prototype.getAttachment = function(fbo) {
+ return glsLifetimeTests.getFboAttachment(fbo, gl.TEXTURE);
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.FboAttacher}
+ */
+glsLifetimeTests.RboFboAttacher = function(elementType, containerType) {
+ glsLifetimeTests.FboAttacher.call(this, elementType, containerType);
+};
+
+setParentClass(glsLifetimeTests.RboFboAttacher, glsLifetimeTests.FboAttacher);
+
+glsLifetimeTests.RboFboAttacher.prototype.initStorage = function() {
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, FRAMEBUFFER_SIZE, FRAMEBUFFER_SIZE);
+
+};
+
+glsLifetimeTests.RboFboAttacher.prototype.attach = function(element, target) {
+ var rbo = /** @type {WebGLRenderbuffer} */ (element);
+ var fbo = /** @type {WebGLFramebuffer} */ (target);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+};
+
+glsLifetimeTests.RboFboAttacher.prototype.detach = function(rbo, target) {
+ var fbo = /** @type {WebGLFramebuffer} */ (target);
+ this.attach(null, fbo);
+};
+
+glsLifetimeTests.RboFboAttacher.prototype.getAttachment = function(fbo) {
+ return glsLifetimeTests.getFboAttachment(fbo, gl.RENDERBUFFER);
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Attacher}
+ */
+glsLifetimeTests.ShaderProgramAttacher = function(elementType, containerType) {
+ glsLifetimeTests.Attacher.call(this, elementType, containerType);
+};
+
+setParentClass(glsLifetimeTests.ShaderProgramAttacher, glsLifetimeTests.Attacher);
+
+glsLifetimeTests.ShaderProgramAttacher.prototype.initAttachment = function(seed, obj) {
+ var shader = /** @type {WebGLShader} */ (obj);
+ var s_fragmentShaderTemplate =
+ '#version 100\n' +
+ 'void main()\n' +
+ '{\n' +
+ ' gl_FragColor = vec4(${RED}, ${GREEN}, ${BLUE}, 1.0);\n' +
+ '}';
+
+ var rnd = new deRandom.Random(seed);
+ var params = [];
+ params['RED'] = rnd.getFloat().toString(10);
+ params['GREEN'] = rnd.getFloat().toString(10);
+ params['BLUE'] = rnd.getFloat().toString(10);
+
+ var source = tcuStringTemplate.specialize(s_fragmentShaderTemplate, params);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+ var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ assertMsgOptions(compileStatus === true, 'Failed to compile shader: ' + source, false, true);
+};
+
+glsLifetimeTests.ShaderProgramAttacher.prototype.attach = function(element, target) {
+ var shader = /** @type {WebGLShader} */ (element);
+ var program = /** @type {WebGLProgram} */ (target);
+ gl.attachShader(program, shader);
+};
+
+glsLifetimeTests.ShaderProgramAttacher.prototype.detach = function(element, target) {
+ var shader = /** @type {WebGLShader} */ (element);
+ var program = /** @type {WebGLProgram} */ (target);
+ gl.detachShader(program, shader);
+};
+
+glsLifetimeTests.ShaderProgramAttacher.prototype.getAttachment = function(program) {
+ var shaders = gl.getAttachedShaders(program);
+ for (var i = 0; i < shaders.length; i++) {
+ var shader = shaders[i];
+ var type = gl.getShaderParameter(shader, gl.SHADER_TYPE);
+ if (type === gl.FRAGMENT_SHADER)
+ return shader;
+ }
+ return null;
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.InputAttacher}
+ */
+glsLifetimeTests.ShaderProgramInputAttacher = function(attacher) {
+ glsLifetimeTests.InputAttacher.call(this, attacher);
+};
+
+setParentClass(glsLifetimeTests.ShaderProgramInputAttacher, glsLifetimeTests.InputAttacher);
+
+glsLifetimeTests.ShaderProgramInputAttacher.prototype.drawContainer = function(container, dst) {
+ var program = /** @type {WebGLProgram} */ (container);
+ var s_vertices = [-1.0, 0.0, 1.0, 1.0, 0.0, -1.0];
+ glsLifetimeTests.ShaderProgramInputAttacher.seed = glsLifetimeTests.ShaderProgramInputAttacher.seed || 0;
+ var vtxShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.VERTEX, s_vertexShaderSrc);
+ var viewport = new glsTextureTestUtil.RandomViewport(document.getElementById('canvas'), VIEWPORT_SIZE, VIEWPORT_SIZE, glsLifetimeTests.ShaderProgramInputAttacher.seed);
+
+ gl.attachShader(program, vtxShader.getShader());
+ gl.linkProgram(program);
+
+ var linkStatus = gl.getProgramParameter(program, gl.LINK_STATUS);
+ assertMsgOptions(linkStatus === true, 'Program link failed', false, true);
+
+ bufferedLogToConsole('Attached a temporary vertex shader and linked program ' + program);
+
+ gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+
+ bufferedLogToConsole('Positioned viewport randomly');
+
+ gl.useProgram(program);
+
+ var posLoc = gl.getAttribLocation(program, 'pos');
+ assertMsgOptions(posLoc >= 0, 'Could not find pos attribute', false, true);
+
+ var buf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(s_vertices), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(posLoc);
+ gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+
+ gl.disableVertexAttribArray(posLoc);
+ gl.deleteBuffer(buf);
+ bufferedLogToConsole('Drew a fixed triangle');
+
+ gl.useProgram(null);
+
+ glsLifetimeTests.readRectangle(viewport, dst);
+ bufferedLogToConsole('Copied viewport to output image');
+
+ gl.detachShader(program, vtxShader.getShader());
+ bufferedLogToConsole('Removed temporary vertex shader');
+};
+
+/**
+ * @constructor
+ * @extends {glsLifetimeTests.Types}
+ */
+glsLifetimeTests.ES2Types = function() {
+ glsLifetimeTests.Types.call(this);
+ this.m_bufferBind = new glsLifetimeTests.SimpleBinder(gl.bindBuffer, gl.ARRAY_BUFFER, gl.ARRAY_BUFFER_BINDING);
+ this.m_bufferType = new glsLifetimeTests.SimpleType('buffer', gl.createBuffer, gl.deleteBuffer, gl.isBuffer, this.m_bufferBind);
+ this.m_textureBind = new glsLifetimeTests.SimpleBinder(gl.bindTexture, gl.TEXTURE_2D, gl.TEXTURE_BINDING_2D);
+ this.m_textureType = new glsLifetimeTests.SimpleType('texture', gl.createTexture, gl.deleteTexture, gl.isTexture, this.m_textureBind);
+ this.m_rboBind = new glsLifetimeTests.SimpleBinder(gl.bindRenderbuffer, gl.RENDERBUFFER, gl.RENDERBUFFER_BINDING);
+ this.m_rboType = new glsLifetimeTests.SimpleType('renderbuffer', gl.createRenderbuffer, gl.deleteRenderbuffer, gl.isRenderbuffer, this.m_rboBind);
+ this.m_fboBind = new glsLifetimeTests.SimpleBinder(gl.bindFramebuffer, gl.FRAMEBUFFER, gl.FRAMEBUFFER_BINDING);
+ this.m_fboType = new glsLifetimeTests.SimpleType('framebuffer', gl.createFramebuffer, gl.deleteFramebuffer, gl.isFramebuffer, this.m_fboBind);
+ this.m_shaderType = new glsLifetimeTests.ShaderType();
+ this.m_programType = new glsLifetimeTests.ProgramType();
+ this.m_texFboAtt = new glsLifetimeTests.TextureFboAttacher(this.m_textureType, this.m_fboType);
+ this.m_texFboInAtt = new glsLifetimeTests.FboInputAttacher(this.m_texFboAtt);
+ this.m_texFboOutAtt = new glsLifetimeTests.FboOutputAttacher(this.m_texFboAtt);
+ this.m_rboFboAtt = new glsLifetimeTests.RboFboAttacher(this.m_rboType, this.m_fboType);
+ this.m_rboFboInAtt = new glsLifetimeTests.FboInputAttacher(this.m_rboFboAtt);
+ this.m_rboFboOutAtt = new glsLifetimeTests.FboOutputAttacher(this.m_rboFboAtt);
+ this.m_shaderAtt = new glsLifetimeTests.ShaderProgramAttacher(this.m_shaderType, this.m_programType);
+ this.m_shaderInAtt = new glsLifetimeTests.ShaderProgramInputAttacher(this.m_shaderAtt);
+
+ this.m_types.push(this.m_bufferType, this.m_textureType, this.m_rboType, this.m_fboType, this.m_shaderType, this.m_programType);
+ this.m_attachers.push(this.m_texFboAtt, this.m_rboFboAtt, this.m_shaderAtt);
+ this.m_inAttachers.push(this.m_texFboInAtt, this.m_rboFboInAtt, this.m_shaderInAtt);
+ this.m_outAttachers.push(this.m_texFboOutAtt, this.m_rboFboOutAtt);
+};
+
+setParentClass(glsLifetimeTests.ES2Types, glsLifetimeTests.Types);
+
+glsLifetimeTests.ES2Types.prototype.getProgramType = function() { return this.m_programType; };
+
+/**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ * @param {glsLifetimeTests.Type} type
+ * @param {function()} test
+ */
+glsLifetimeTests.LifeTest = function(name, description, type, test) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ this.m_type = type;
+ this.m_test = test;
+};
+
+setParentClass(glsLifetimeTests.LifeTest, tcuTestCase.DeqpTest);
+
+glsLifetimeTests.LifeTest.prototype.iterate = function() {
+ this.m_test();
+ return tcuTestCase.IterateResult.STOP;
+};
+
+/**
+ * @this {glsLifetimeTests.LifeTest}
+ */
+glsLifetimeTests.LifeTest.testGen = function() {
+ var obj = this.m_type.gen();
+ if (this.m_type.genCreates())
+ assertMsgOptions(this.m_type.exists(obj), "create* should have created an object, but didn't", false, true);
+ else
+ assertMsgOptions(!this.m_type.exists(obj), 'create* should not have created an object, but did', false, true);
+ this.m_type.release(obj);
+ testPassed();
+};
+
+/**
+ * @this {glsLifetimeTests.LifeTest}
+ */
+glsLifetimeTests.LifeTest.testDelete = function() {
+ var obj = this.m_type.gen();
+ this.m_type.release(obj);
+ assertMsgOptions(!this.m_type.exists(obj), 'Object still exists after deletion', false, true);
+ testPassed();
+};
+
+/**
+ * @this {glsLifetimeTests.LifeTest}
+ */
+glsLifetimeTests.LifeTest.testBind = function() {
+ var obj = this.m_type.gen();
+ this.m_type.binder().bind(obj);
+ var err = gl.getError();
+ assertMsgOptions(err == gl.NONE, 'Bind failed', false, true);
+ assertMsgOptions(this.m_type.exists(obj), 'Object does not exist after binding', false, true);
+ this.m_type.binder().bind(null);
+ this.m_type.release(obj);
+ testPassed();
+};
+
+/**
+ * @this {glsLifetimeTests.LifeTest}
+ */
+glsLifetimeTests.LifeTest.testDeleteBound = function() {
+ var obj = this.m_type.gen();
+ this.m_type.binder().bind(obj);
+ this.m_type.release(obj);
+ if (this.m_type.nameLingers()) {
+ assertMsgOptions(gl.getError() == gl.NONE, 'Deleting bound object failed', false, true);
+ assertMsgOptions(this.m_type.binder().getBinding() === obj, 'Deleting bound object did not retain binding', false, true);
+ assertMsgOptions(this.m_type.exists(obj), 'Deleting bound object made its name invalid', false, true);
+ assertMsgOptions(this.m_type.isDeleteFlagged(obj), 'Deleting bound object did not flag the object for deletion', false, true);
+ this.m_type.binder().bind(null);
+ } else {
+ assertMsgOptions(gl.getError() == gl.NONE, 'Deleting bound object failed', false, true);
+ assertMsgOptions(this.m_type.binder().getBinding() === null, 'Deleting bound object did not remove binding', false, true);
+ assertMsgOptions(!this.m_type.exists(obj), 'Deleting bound object did not make its name invalid', false, true);
+ }
+ assertMsgOptions(this.m_type.binder().getBinding() === null, "Unbinding didn't remove binding", false, true);
+ assertMsgOptions(!this.m_type.exists(obj), 'Name is still valid after deleting and unbinding', false, true);
+ testPassed();
+};
+
+/**
+ * @this {glsLifetimeTests.LifeTest}
+ */
+glsLifetimeTests.LifeTest.testDeleteUsed = function() {
+ var vtxShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.VERTEX, s_vertexShaderSrc);
+ var fragShader = new glsLifetimeTests.CheckedShader(gluShaderProgram.shaderType.FRAGMENT, s_fragmentShaderSrc);
+ var program = new glsLifetimeTests.CheckedProgram(vtxShader.getShader(), fragShader.getShader());
+ var programId = program.getProgram();
+ bufferedLogToConsole('Created and linked program ' + programId);
+ gl.useProgram(programId);
+
+ gl.deleteProgram(programId);
+ bufferedLogToConsole('Deleted program ' + programId);
+ assertMsgOptions(gl.isProgram(programId), 'Deleted current program', false, true);
+ var deleteFlagged = gl.getProgramParameter(programId, gl.DELETE_STATUS);
+ assertMsgOptions(deleteFlagged == true, 'Program object was not flagged as deleted', false, true);
+ gl.useProgram(null);
+ assertMsgOptions(!gl.isProgram(programId), 'Deleted program name still valid after being made non-current', false, true);
+ testPassed();
+};
+
+/**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ * @param {glsLifetimeTests.Attacher} attacher
+ * @param {function()} test
+ */
+glsLifetimeTests.AttachmentTest = function(name, description, attacher, test) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ this.m_attacher = attacher;
+ this.m_test = test;
+};
+
+setParentClass(glsLifetimeTests.AttachmentTest, tcuTestCase.DeqpTest);
+
+glsLifetimeTests.AttachmentTest.prototype.iterate = function() {
+ this.m_test();
+ return tcuTestCase.IterateResult.STOP;
+};
+
+/**
+ * @this {glsLifetimeTests.AttachmentTest}
+ */
+glsLifetimeTests.AttachmentTest.testDeletedNames = function() {
+ var getAttachment = function(attacher, container) {
+ var queriedAttachment = attacher.getAttachment(container);
+ bufferedLogToConsole('Result of query for ' + attacher.getElementType().getName() +
+ ' attached to ' + attacher.getContainerType().getName() + ' ' +
+ container + ': ' + queriedAttachment);
+ return queriedAttachment;
+ };
+
+ var elemType = this.m_attacher.getElementType();
+ var containerType = this.m_attacher.getContainerType();
+ var container = containerType.gen();
+
+ var element = elemType.gen();
+ this.m_attacher.initAttachment(0, element);
+ this.m_attacher.attach(element, container);
+ assertMsgOptions(getAttachment(this.m_attacher, container) == element,
+ 'Attachment not returned by query even before deletion.', false, true);
+
+ elemType.release(element);
+ // "Such a container or other context may continue using the object, and
+ // may still contain state identifying its name as being currently bound"
+ //
+ // We here interpret "may" to mean that whenever the container has a
+ // deleted object attached to it, a query will return that object's former
+ // name.
+ assertMsgOptions(getAttachment(this.m_attacher, container) == element,
+ 'Attachment name not returned by query after attachment was deleted.', false, true);
+
+ if (elemType.nameLingers())
+ assertMsgOptions(elemType.exists(element),
+ 'Attached object name no longer valid after deletion.', false, true);
+ else
+ assertMsgOptions(!elemType.exists(element),
+ 'Attached object name still valid after deletion.', false, true);
+
+ this.m_attacher.detach(element, container);
+ assertMsgOptions(getAttachment(this.m_attacher, container) == null,
+ 'Attachment name returned by query even after detachment.', false, true);
+ assertMsgOptions(!elemType.exists(element),
+ 'Deleted attached object name still usable after detachment.', false, true);
+ testPassed();
+};
+
+/**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ * @param {glsLifetimeTests.InputAttacher} attacher
+ */
+glsLifetimeTests.InputAttachmentTest = function(name, description, attacher) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ this.m_inputAttacher = attacher;
+};
+
+setParentClass(glsLifetimeTests.InputAttachmentTest, tcuTestCase.DeqpTest);
+
+glsLifetimeTests.InputAttachmentTest.prototype.iterate = function() {
+ var attacher = this.m_inputAttacher.getAttacher();
+ var containerType = attacher.getContainerType();
+ var elementType = attacher.getElementType();
+ var container = containerType.gen();
+
+ glsLifetimeTests.InputAttachmentTest.seed = glsLifetimeTests.InputAttachmentTest.seed || 0;
+ ++glsLifetimeTests.InputAttachmentTest.seed;
+ var rnd = new deRandom.Random(glsLifetimeTests.InputAttachmentTest.seed);
+ var refSeed = rnd.getInt();
+ var newSeed = rnd.getInt();
+
+ var refSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with refSeed-seeded attachment
+ var delSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with deleted refSeed attachment
+ var newSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with newSeed-seeded attachment
+
+ bufferedLogToConsole('Testing if writing to a newly created object modifies a deleted attachment');
+
+ bufferedLogToConsole('Writing to an original attachment');
+ var element = elementType.gen();
+
+ attacher.initAttachment(refSeed, element);
+ attacher.attach(element, container);
+ this.m_inputAttacher.drawContainer(container, refSurface);
+ // element gets deleted here
+ bufferedLogToConsole('Deleting attachment');
+ elementType.release(element);
+
+ bufferedLogToConsole('Writing to a new attachment after deleting the original');
+ var newElement = elementType.gen();
+
+ attacher.initAttachment(newSeed, newElement);
+
+ this.m_inputAttacher.drawContainer(container, delSurface);
+ attacher.detach(element, container);
+
+ attacher.attach(newElement, container);
+ this.m_inputAttacher.drawContainer(container, newSurface);
+ attacher.detach(newElement, container);
+ var surfacesMatch = tcuImageCompare.pixelThresholdCompare(
+ 'Reading from deleted',
+ 'Comparison result from reading from a container with a deleted attachment ' +
+ 'before and after writing to a fresh object.',
+ refSurface, delSurface, [0, 0, 0, 0]);
+
+ /* TODO: Add logging images */
+ // if (!surfacesMatch)
+ // log() << TestLog::Image("New attachment",
+ // "Container state after attached to the fresh object",
+ // newSurface);
+
+ assertMsgOptions(surfacesMatch,
+ 'Writing to a fresh object modified the container with a deleted attachment.', false, true);
+
+ testPassed();
+ return tcuTestCase.IterateResult.STOP;
+};
+
+/**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ * @param {glsLifetimeTests.OutputAttacher} attacher
+ */
+glsLifetimeTests.OutputAttachmentTest = function(name, description, attacher) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ this.m_outputAttacher = attacher;
+};
+
+setParentClass(glsLifetimeTests.OutputAttachmentTest, tcuTestCase.DeqpTest);
+
+glsLifetimeTests.OutputAttachmentTest.prototype.iterate = function() {
+ var attacher = this.m_outputAttacher.getAttacher();
+ var containerType = attacher.getContainerType();
+ var elementType = attacher.getElementType();
+ var container = containerType.gen();
+ glsLifetimeTests.InputAttachmentTest.seed = glsLifetimeTests.InputAttachmentTest.seed || 0;
+ ++glsLifetimeTests.InputAttachmentTest.seed;
+ var rnd = new deRandom.Random(glsLifetimeTests.InputAttachmentTest.seed);
+ var refSeed = rnd.getInt();
+ var newSeed = rnd.getInt();
+
+ var refSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with refSeed-seeded attachment
+ var delSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with deleted refSeed attachment
+ var newSurface = new tcuSurface.Surface(VIEWPORT_SIZE, VIEWPORT_SIZE); // Surface from drawing with newSeed-seeded attachment
+
+ bufferedLogToConsole('Testing if writing to a container with a deleted attachment ' +
+ 'modifies a newly created object');
+
+ bufferedLogToConsole('Writing to a container with an existing attachment');
+ var element = elementType.gen();
+
+ attacher.initAttachment(0, element);
+ attacher.attach(element, container);
+
+ // For reference purposes, make note of what refSeed looks like.
+ this.m_outputAttacher.setupContainer(refSeed, container);
+ // Since in WebGL, buffer bound to TRANSFORM_FEEDBACK_BUFFER can not be bound to other targets.
+ // Unfortunately, element will be bound again in drawAttachment() for drawing.
+ // Detach element from container before drawing, then reattach it after drawing.
+ attacher.detach(element, container);
+ this.m_outputAttacher.drawAttachment(element, refSurface);
+ attacher.attach(element, container);
+ elementType.release(element);
+
+ bufferedLogToConsole('Writing to a container after deletion of attachment');
+ var newElement = elementType.gen();
+ bufferedLogToConsole('Creating a new object ');
+
+ bufferedLogToConsole('Recording state of new object before writing to container');
+ attacher.initAttachment(newSeed, newElement);
+ this.m_outputAttacher.drawAttachment(newElement, newSurface);
+
+ bufferedLogToConsole('Writing to container');
+
+ // Now re-write refSeed to the container.
+ this.m_outputAttacher.setupContainer(refSeed, container);
+ // Does it affect the newly created attachment object?
+ this.m_outputAttacher.drawAttachment(newElement, delSurface);
+ attacher.detach(element, container);
+
+ var surfacesMatch = tcuImageCompare.pixelThresholdCompare(
+ 'Writing to deleted',
+ 'Comparison result from reading from a fresh object before and after ' +
+ 'writing to a container with a deleted attachment',
+ newSurface, delSurface, [0, 0, 0, 0]);
+
+ /* TODO: Add logging images */
+ // if (!surfacesMatch)
+ // log() << TestLog::Image(
+ // "Original attachment",
+ // "Result of container modification on original attachment before deletion.",
+ // refSurface);
+
+ assertMsgOptions(surfacesMatch,
+ 'Writing to container with deleted attachment modified a new object.', false, true);
+
+ testPassed();
+ return tcuTestCase.IterateResult.STOP;
+};
+
+glsLifetimeTests.createLifeTestGroup = function(spec, types) {
+ var group = tcuTestCase.newTest(spec.name, spec.name);
+
+ for (var i = 0; i < types.length; i++) {
+ var type = types[i];
+ var name = type.getName();
+ if (!spec.needBind || type.binder() != null)
+ group.addChild(new glsLifetimeTests.LifeTest(name, name, type, spec.func));
+ }
+
+ return group;
+};
+
+/**
+ * @param {tcuTestCase.DeqpTest} group
+ * @param {glsLifetimeTests.Types} types
+ */
+glsLifetimeTests.addTestCases = function(group, types) {
+ var attacherName = function(attacher) {
+ return attacher.getElementType().getName() + '_' + attacher.getContainerType().getName();
+ };
+
+ var s_lifeTests = [
+ /* Create */ { name: 'gen', func: glsLifetimeTests.LifeTest.testGen, needBind: false },
+ /* Delete */ { name: 'delete', func: glsLifetimeTests.LifeTest.testDelete, needBind: false },
+ /* Bind */ { name: 'bind', func: glsLifetimeTests.LifeTest.testBind, needBind: true },
+ /* Delete bound */ { name: 'delete_bound', func: glsLifetimeTests.LifeTest.testDeleteBound, needBind: true }
+ ];
+
+ s_lifeTests.forEach(function(spec) {
+ group.addChild(glsLifetimeTests.createLifeTestGroup(spec, types.getTypes()));
+ });
+
+ var delUsedGroup = tcuTestCase.newTest('delete_used', 'Delete current program');
+ group.addChild(delUsedGroup);
+
+ delUsedGroup.addChild(new glsLifetimeTests.LifeTest('program', 'program', types.getProgramType(),
+ glsLifetimeTests.LifeTest.testDeleteUsed));
+
+ var attGroup = tcuTestCase.newTest('attach', 'Attachment tests');
+ group.addChild(attGroup);
+
+ var nameGroup = tcuTestCase.newTest('deleted_name', 'Name of deleted attachment');
+ attGroup.addChild(nameGroup);
+
+ var atts = types.getAttachers();
+ for (var i = 0; i < atts.length; i++) {
+ var att = atts[i];
+ var name = attacherName(att);
+ nameGroup.addChild(new glsLifetimeTests.AttachmentTest(name, name, att,
+ glsLifetimeTests.AttachmentTest.testDeletedNames));
+ }
+
+ var inputGroup = tcuTestCase.newTest('deleted_input', 'Input from deleted attachment');
+ attGroup.addChild(inputGroup);
+
+ var inAtts = types.getInputAttachers();
+ for (var i = 0; i < inAtts.length; i++) {
+ var att = inAtts[i];
+ var name = attacherName(att.getAttacher());
+ inputGroup.addChild(new glsLifetimeTests.InputAttachmentTest(name, name, att));
+ }
+
+ var outputGroup = tcuTestCase.newTest('deleted_output', 'Output to deleted attachment');
+ attGroup.addChild(outputGroup);
+
+ var outAtts = types.getOutputAttachers();
+ for (var i = 0; i < outAtts.length; i++) {
+ var att = outAtts[i];
+ var name = attacherName(att.getAttacher());
+ outputGroup.addChild(new glsLifetimeTests.OutputAttachmentTest(name, name, att));
+ }
+
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsRandomUniformBlockCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsRandomUniformBlockCase.js
new file mode 100644
index 000000000..20b8dcd47
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsRandomUniformBlockCase.js
@@ -0,0 +1,282 @@
+/*-------------------------------------------------------------------------
+ * 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.glsRandomUniformBlockCase');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('modules.shared.glsUniformBlockCase');
+
+goog.scope(function() {
+
+ var glsRandomUniformBlockCase = modules.shared.glsRandomUniformBlockCase;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var glsUniformBlockCase = modules.shared.glsUniformBlockCase;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var deMath = framework.delibs.debase.deMath;
+ var deRandom = framework.delibs.debase.deRandom;
+
+ glsRandomUniformBlockCase.FeatureBits = {
+ FEATURE_VECTORS: (1 << 0),
+ FEATURE_MATRICES: (1 << 1),
+ FEATURE_ARRAYS: (1 << 2),
+ FEATURE_STRUCTS: (1 << 3),
+ FEATURE_NESTED_STRUCTS: (1 << 4),
+ FEATURE_INSTANCE_ARRAYS: (1 << 5),
+ FEATURE_VERTEX_BLOCKS: (1 << 6),
+ FEATURE_FRAGMENT_BLOCKS: (1 << 7),
+ FEATURE_SHARED_BLOCKS: (1 << 8),
+ FEATURE_UNUSED_UNIFORMS: (1 << 9),
+ FEATURE_UNUSED_MEMBERS: (1 << 10),
+ FEATURE_PACKED_LAYOUT: (1 << 11),
+ FEATURE_SHARED_LAYOUT: (1 << 12),
+ FEATURE_STD140_LAYOUT: (1 << 13),
+ FEATURE_MATRIX_LAYOUT: (1 << 14), //!< Matrix layout flags.
+ FEATURE_ARRAYS_OF_ARRAYS: (1 << 15)
+ };
+
+ /**
+ * glsRandomUniformBlockCase.RandomUniformBlockCase class
+ * @param {string} name
+ * @param {string} description
+ * @param {glsUniformBlockCase.BufferMode} bufferMode
+ * @param {number} features
+ * @param {number} seed
+ * @constructor
+ * @extends {glsUniformBlockCase.UniformBlockCase}
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase = function(name, description, bufferMode, features, seed) {
+ glsUniformBlockCase.UniformBlockCase.call(this, name, description, bufferMode);
+ this.m_features = features;
+ this.m_maxVertexBlocks = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_VERTEX_BLOCKS) ? 4 : 0);
+ this.m_maxFragmentBlocks = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_FRAGMENT_BLOCKS) ? 4 : 0);
+ this.m_maxSharedBlocks = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_SHARED_BLOCKS) ? 4 : 0);
+ this.m_maxInstances = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_INSTANCE_ARRAYS) ? 3 : 0);
+ this.m_maxArrayLength = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_ARRAYS) ? 8 : 0);
+ this.m_maxStructDepth = ((features & glsRandomUniformBlockCase.FeatureBits.FEATURE_STRUCTS) ? 2 : 0);
+ this.m_maxBlockMembers = 5;
+ this.m_maxStructMembers = 4;
+ this.m_seed = seed;
+ this.m_blockNdx = 1;
+ this.m_uniformNdx = 1;
+ this.m_structNdx = 1;
+ };
+
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype = Object.create(glsUniformBlockCase.UniformBlockCase.prototype);
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.constructor = glsRandomUniformBlockCase.RandomUniformBlockCase;
+
+ /**
+ * generateType
+ * @param {deRandom.Random} rnd
+ * @param {number} typeDepth
+ * @param {boolean} arrayOk
+ * @return {glsUniformBlockCase.VarType}
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.generateType = function(rnd, typeDepth, arrayOk) {
+ /** @type {number} */ var structWeight = 0.1;
+ /** @type {number} */ var arrayWeight = 0.1;
+ /** @type {number} */ var flags;
+
+ if (typeDepth < this.m_maxStructDepth && rnd.getFloat() < structWeight) {
+ /** @type {number} */ var unusedVtxWeight = 0.15;
+ /** @type {number} */ var unusedFragWeight = 0.15;
+ /** @type {boolean} */ var unusedOk = (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_UNUSED_MEMBERS) != 0;
+ /** @type {Array<glsUniformBlockCase.VarType>} */ var memberTypes = [];
+ /** @type {number} */ var numMembers = rnd.getInt(1, this.m_maxStructMembers);
+
+ // Generate members first so nested struct declarations are in correct order.
+ for (var ndx = 0; ndx < numMembers; ndx++)
+ memberTypes.push(this.generateType(rnd, typeDepth + 1, true));
+
+ /** @type {glsUniformBlockCase.StructType} */ var structType = this.m_interface.allocStruct('s' + this.genName('A'.charCodeAt(0), 'Z'.charCodeAt(0), this.m_structNdx));
+ this.m_structNdx += 1;
+
+ assertMsgOptions(this.m_blockNdx <= 'Z'.charCodeAt(0) - 'A'.charCodeAt(0), 'generateType', false, true);
+ for (var ndx = 0; ndx < numMembers; ndx++) {
+ flags = 0;
+
+ flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? glsUniformBlockCase.UniformFlags.UNUSED_VERTEX : 0;
+ flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT : 0;
+
+ structType.addMember('m' + ('A'.charCodeAt(0) + ndx), memberTypes[ndx], flags);
+ }
+
+ return glsUniformBlockCase.newVarTypeStruct(structType);
+ } else if (this.m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight) {
+ /** @type {boolean} */ var arraysOfArraysOk = (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_ARRAYS_OF_ARRAYS) != 0;
+ /** @type {number} */ var arrayLength = rnd.getInt(1, this.m_maxArrayLength);
+ /** @type {glsUniformBlockCase.VarType} */ var elementType = this.generateType(rnd, typeDepth, arraysOfArraysOk);
+ return glsUniformBlockCase.newVarTypeArray(elementType, arrayLength);
+ } else {
+ /** @type {Array<gluShaderUtil.DataType>} */ var typeCandidates = [];
+
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT);
+ typeCandidates.push(gluShaderUtil.DataType.INT);
+ typeCandidates.push(gluShaderUtil.DataType.UINT);
+ typeCandidates.push(gluShaderUtil.DataType.BOOL);
+
+ if (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_VECTORS) {
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_VEC2);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_VEC3);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_VEC4);
+ typeCandidates.push(gluShaderUtil.DataType.INT_VEC2);
+ typeCandidates.push(gluShaderUtil.DataType.INT_VEC3);
+ typeCandidates.push(gluShaderUtil.DataType.INT_VEC4);
+ typeCandidates.push(gluShaderUtil.DataType.UINT_VEC2);
+ typeCandidates.push(gluShaderUtil.DataType.UINT_VEC3);
+ typeCandidates.push(gluShaderUtil.DataType.UINT_VEC4);
+ typeCandidates.push(gluShaderUtil.DataType.BOOL_VEC2);
+ typeCandidates.push(gluShaderUtil.DataType.BOOL_VEC3);
+ typeCandidates.push(gluShaderUtil.DataType.BOOL_VEC4);
+ }
+
+ if (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_MATRICES) {
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT2);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT2X3);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT3X2);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT3);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT3X4);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT4X2);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT4X3);
+ typeCandidates.push(gluShaderUtil.DataType.FLOAT_MAT4);
+ }
+
+ /** @type {gluShaderUtil.DataType} */ var type = (rnd.choose(typeCandidates)[0]);
+ flags = 0;
+
+ if (!gluShaderUtil.isDataTypeBoolOrBVec(type)) {
+ // Precision.
+ /** @type {Array<number>} */ var precisionCandidates = [glsUniformBlockCase.UniformFlags.PRECISION_LOW, glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM, glsUniformBlockCase.UniformFlags.PRECISION_HIGH];
+ flags |= rnd.choose(precisionCandidates)[0];
+ }
+
+ return glsUniformBlockCase.newVarTypeBasic(type, flags);
+ }
+ };
+
+ /**
+ * genName
+ * @param {number} first
+ * @param {number} last
+ * @param {number} ndx
+ * @return {string}
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.genName = function(first, last, ndx) {
+ /** @type {string} */ var str = '';
+ /** @type {number} */ var alphabetLen = last - first + 1;
+
+ while (ndx > alphabetLen) {
+ str = String.fromCharCode(first + ((ndx - 1) % alphabetLen)) + str;
+ ndx = Math.floor((ndx - 1) / alphabetLen);
+ }
+
+ str = String.fromCharCode(first + (ndx % (alphabetLen + 1)) - 1) + str;
+
+ return str;
+ };
+
+ /**
+ * generateUniform
+ * @param {deRandom.Random} rnd
+ * @param {glsUniformBlockCase.UniformBlock} block
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.generateUniform = function(rnd, block) {
+ /** @type {number} */ var unusedVtxWeight = 0.15;
+ /** @type {number} */ var unusedFragWeight = 0.15;
+ /** @type {boolean} */ var unusedOk = (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_UNUSED_UNIFORMS) != 0;
+ /** @type {number} */ var flags = 0;
+ /** @type {string} */ var name = this.genName('a'.charCodeAt(0), 'z'.charCodeAt(0), this.m_uniformNdx);
+ /** @type {glsUniformBlockCase.VarType} */ var type = this.generateType(rnd, 0, true); //TODO: implement this.
+
+ flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? glsUniformBlockCase.UniformFlags.UNUSED_VERTEX : 0;
+ flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT : 0;
+
+ block.addUniform(new glsUniformBlockCase.Uniform(name, type, flags));
+
+ this.m_uniformNdx += 1;
+ };
+
+ /**
+ * generateBlock
+ * @param {deRandom.Random} rnd
+ * @param {number} layoutFlags
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.generateBlock = function(rnd, layoutFlags) {
+ assertMsgOptions(this.m_blockNdx <= 'z'.charCodeAt(0) - 'a'.charCodeAt(0), 'generateBlock', false, true);
+
+ /** @type {number} */ var instanceArrayWeight = 0.3;
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.allocBlock('Block' + String.fromCharCode('A'.charCodeAt(0) + this.m_blockNdx));
+ /** @type {number} */ var numInstances = (this.m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, this.m_maxInstances) : 0;
+ /** @type {number} */ var numUniforms = rnd.getInt(1, this.m_maxBlockMembers);
+
+ if (numInstances > 0)
+ block.setArraySize(numInstances);
+
+ if (numInstances > 0 || rnd.getBool())
+ block.setInstanceName('block' + String.fromCharCode('A'.charCodeAt(0) + this.m_blockNdx));
+
+ // Layout flag candidates.
+ /** @type {Array<number>} */ var layoutFlagCandidates = [];
+ layoutFlagCandidates.push(0);
+ if (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_PACKED_LAYOUT)
+ layoutFlagCandidates.push(glsUniformBlockCase.UniformFlags.LAYOUT_SHARED);
+ if ((this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_SHARED_LAYOUT) && ((layoutFlags & glsUniformBlockCase.UniformFlags.DECLARE_BOTH) != glsUniformBlockCase.UniformFlags.DECLARE_BOTH))
+ layoutFlagCandidates.push(glsUniformBlockCase.UniformFlags.LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage.
+ if (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_STD140_LAYOUT)
+ layoutFlagCandidates.push(glsUniformBlockCase.UniformFlags.LAYOUT_STD140);
+
+ layoutFlags |= rnd.choose(layoutFlagCandidates)[0]; //In Javascript, this function returns an array, so taking element 0.
+
+ if (this.m_features & glsRandomUniformBlockCase.FeatureBits.FEATURE_MATRIX_LAYOUT) {
+ /** @type {Array<number>}*/ var matrixCandidates = [0, glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR, glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR];
+ layoutFlags |= rnd.choose(matrixCandidates)[0];
+ }
+
+ block.setFlags(layoutFlags);
+
+ for (var ndx = 0; ndx < numUniforms; ndx++)
+ this.generateUniform(rnd, block);
+
+ this.m_blockNdx += 1;
+ };
+
+ /**
+ * Initializes the glsRandomUniformBlockCase.RandomUniformBlockCase
+ */
+ glsRandomUniformBlockCase.RandomUniformBlockCase.prototype.init = function() {
+ /** @type {deRandom.Random} */ var rnd = new deRandom.Random(this.m_seed);
+
+ /** @type {number} */ var numShared = this.m_maxSharedBlocks > 0 ? rnd.getInt(1, this.m_maxSharedBlocks) : 0;
+ /** @type {number} */ var numVtxBlocks = this.m_maxVertexBlocks - numShared > 0 ? rnd.getInt(1, this.m_maxVertexBlocks - numShared) : 0;
+ /** @type {number} */ var numFragBlocks = this.m_maxFragmentBlocks - numShared > 0 ? rnd.getInt(1, this.m_maxFragmentBlocks - numShared) : 0;
+
+ for (var ndx = 0; ndx < numShared; ndx++)
+ this.generateBlock(rnd, glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT);
+
+ for (var ndx = 0; ndx < numVtxBlocks; ndx++)
+ this.generateBlock(rnd, glsUniformBlockCase.UniformFlags.DECLARE_VERTEX);
+
+ for (var ndx = 0; ndx < numFragBlocks; ndx++)
+ this.generateBlock(rnd, glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT);
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsSamplerObjectTest.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsSamplerObjectTest.js
new file mode 100644
index 000000000..0d4030bd9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsSamplerObjectTest.js
@@ -0,0 +1,1148 @@
+/*-------------------------------------------------------------------------
+ * 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.glsSamplerObjectTest');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluTextureUtil');
+
+goog.scope(function() {
+
+var glsSamplerObjectTest = modules.shared.glsSamplerObjectTest;
+var tcuTestCase = framework.common.tcuTestCase;
+var deRandom = framework.delibs.debase.deRandom;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+var tcuTexture = framework.common.tcuTexture;
+var tcuSurface = framework.common.tcuSurface;
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+var tcuImageCompare = framework.common.tcuImageCompare;
+var gluDrawUtil = framework.opengl.gluDrawUtil;
+var gluTextureUtil = framework.opengl.gluTextureUtil;
+var deString = framework.delibs.debase.deString;
+
+ var DE_ASSERT = function(expression) {
+ if (!expression) throw new Error('Assert failed');
+ };
+
+ // glsSamplerObjectTest.TextureSamplerTest
+
+ /** @const @type {number} */ glsSamplerObjectTest.VIEWPORT_WIDTH = 128;
+ /** @const @type {number} */ glsSamplerObjectTest.VIEWPORT_HEIGHT = 128;
+
+ /** @const @type {number} */ glsSamplerObjectTest.TEXTURE2D_WIDTH = 32;
+ /** @const @type {number} */ glsSamplerObjectTest.TEXTURE2D_HEIGHT = 32;
+
+ /** @const @type {number} */ glsSamplerObjectTest.TEXTURE3D_WIDTH = 32;
+ /** @const @type {number} */ glsSamplerObjectTest.TEXTURE3D_HEIGHT = 32;
+ /** @const @type {number} */ glsSamplerObjectTest.TEXTURE3D_DEPTH = 32;
+
+ /** @const @type {number} */ glsSamplerObjectTest.CUBEMAP_SIZE = 32;
+
+ /** @const @type {Array<number>} */ glsSamplerObjectTest.s_positions = [
+ -1.0, -1.0,
+ 1.0, -1.0,
+ 1.0, 1.0,
+ 1.0, 1.0,
+ -1.0, 1.0,
+ -1.0, -1.0
+ ];
+
+ /** @const @type {Array<number>} */ glsSamplerObjectTest.s_positions3D = [
+ -1.0, -1.0, -1.0,
+ 1.0, -1.0, 1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ -1.0, 1.0, 1.0,
+ -1.0, -1.0, -1.0
+ ];
+
+ /** @const @type {Array<number>} */ glsSamplerObjectTest.s_positionsCube = [
+ -1.0, -1.0, -1.0, -0.5,
+ 1.0, -1.0, 1.0, -0.5,
+ 1.0, 1.0, 1.0, 0.5,
+ 1.0, 1.0, 1.0, 0.5,
+ -1.0, 1.0, -1.0, 0.5,
+ -1.0, -1.0, -1.0, -0.5
+ ];
+
+ /**
+ * @struct
+ * @constructor
+ */
+ glsSamplerObjectTest.SamplingState = function(minFilter, magFilter, wrapT, wrapS, wrapR, minLod, maxLod) {
+ /** @type {number} */ this.minFilter = minFilter;
+ /** @type {number} */ this.magFilter = magFilter;
+ /** @type {number} */ this.wrapT = wrapT;
+ /** @type {number} */ this.wrapS = wrapS;
+ /** @type {number} */ this.wrapR = wrapR;
+ /** @type {number} */ this.minLod = minLod;
+ /** @type {number} */ this.maxLod = maxLod;
+ };
+
+ /**
+ * @struct
+ * @param {string} name
+ * @param {string} desc
+ * @param {number} target
+ * @param {glsSamplerObjectTest.SamplingState} state1
+ * @param {glsSamplerObjectTest.SamplingState} state2
+ * @param {glsSamplerObjectTest.SamplingState=} state3
+ * @constructor
+ */
+ glsSamplerObjectTest.TestSpec = function(name, desc, target, state1, state2, state3) {
+ /** @type {string} */ this.name = name;
+ /** @type {string} */ this.desc = desc;
+ /** @type {number} */ this.target = target;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.textureState = state1;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.textureState2 = state3 !== undefined ? state2 : null; // merging TST and MTST structs
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.samplerState = state3 !== undefined ? state3 : state2;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @const @param {glsSamplerObjectTest.TestSpec} spec
+ */
+ glsSamplerObjectTest.TextureSamplerTest = function(spec) {
+ tcuTestCase.DeqpTest.call(this, spec.name, spec.desc);
+ /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
+ /** @type {number} */ this.m_target = spec.target;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.m_textureState = spec.textureState;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.m_samplerState = spec.samplerState;
+ /** @type {deRandom.Random} */ this.m_random = new deRandom.Random(deString.deStringHash(spec.name));
+ };
+
+ glsSamplerObjectTest.TextureSamplerTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsSamplerObjectTest.TextureSamplerTest.prototype.constructor = glsSamplerObjectTest.TextureSamplerTest;
+
+ /**
+ * @private
+ * @param {tcuSurface.Surface} textureRef
+ * @param {tcuSurface.Surface} samplerRef
+ * @param {number} x
+ * @param {number} y
+ */
+ glsSamplerObjectTest.TextureSamplerTest.prototype.renderReferences = function(textureRef, samplerRef, x, y) {
+ /** @type {WebGLTexture} */ var texture = glsSamplerObjectTest.TextureSamplerTest.createTexture(this.m_target);
+
+ gl.viewport(x, y, glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ gl.bindTexture(this.m_target, texture);
+
+ glsSamplerObjectTest.TextureSamplerTest.setTextureState(this.m_target, this.m_textureState);
+ this.render();
+ var texRef = textureRef.getAccess();
+ var texRefTransferFormat = gluTextureUtil.getTransferFormat(texRef.getFormat());
+ gl.readPixels(x, y, texRef.m_width, texRef.m_height, texRefTransferFormat.format, texRefTransferFormat.dataType, textureRef.m_pixels);
+
+ glsSamplerObjectTest.TextureSamplerTest.setTextureState(this.m_target, this.m_samplerState);
+ this.render();
+ var sampRef = samplerRef.getAccess();
+ var sampRefTransferFormat = gluTextureUtil.getTransferFormat(sampRef.getFormat());
+ gl.readPixels(x, y, sampRef.m_width, sampRef.m_height, sampRefTransferFormat.format, sampRefTransferFormat.dataType, samplerRef.m_pixels);
+
+ gl.deleteTexture(texture);
+ };
+
+ /**
+ * @private
+ * @param {tcuSurface.Surface} textureResult
+ * @param {tcuSurface.Surface} samplerResult
+ * @param {number} x
+ * @param {number} y
+ */
+ glsSamplerObjectTest.TextureSamplerTest.prototype.renderResults = function(textureResult, samplerResult, x, y) {
+ /** @type {WebGLTexture} */ var texture = glsSamplerObjectTest.TextureSamplerTest.createTexture(this.m_target);
+
+ gl.viewport(x, y, glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ var sampler = gl.createSampler();
+ DE_ASSERT(sampler != -1);
+
+ gl.bindSampler(0, sampler);
+
+ // First set sampler state
+ glsSamplerObjectTest.TextureSamplerTest.setSamplerState(this.m_samplerState, sampler);
+
+ // Set texture state
+ gl.bindTexture(this.m_target, texture);
+
+ glsSamplerObjectTest.TextureSamplerTest.setTextureState(this.m_target, this.m_textureState);
+ // Render using sampler
+ this.render();
+ var sampRes = samplerResult.getAccess();
+ var sampResTransferFormat = gluTextureUtil.getTransferFormat(sampRes.getFormat());
+ gl.readPixels(x, y, sampRes.m_width, sampRes.m_height, sampResTransferFormat.format, sampResTransferFormat.dataType, samplerResult.m_pixels);
+
+ // Render without sampler
+ gl.bindSampler(0, null);
+ gl.deleteSampler(sampler);
+
+ this.render();
+ var texRes = textureResult.getAccess();
+ var texResTransferFormat = gluTextureUtil.getTransferFormat(texRes.getFormat());
+ gl.readPixels(x, y, texRes.m_width, texRes.m_height, texResTransferFormat.format, texResTransferFormat.dataType, textureResult.m_pixels);
+
+ gl.deleteSampler(sampler);
+ gl.deleteTexture(texture);
+ };
+
+ /**
+ * @private
+ */
+ glsSamplerObjectTest.TextureSamplerTest.prototype.render = function() {
+ /** @type {WebGLUniformLocation} */ var samplerLoc;
+ /** @type {WebGLUniformLocation} */ var scaleLoc;
+
+ gl.useProgram(this.m_program.getProgram());
+
+ samplerLoc = gl.getUniformLocation(this.m_program.getProgram(), 'u_sampler');
+ DE_ASSERT(samplerLoc != null);
+
+ scaleLoc = gl.getUniformLocation(this.m_program.getProgram(), 'u_posScale');
+ DE_ASSERT(scaleLoc != null);
+
+ gl.clearColor(0.5, 0.5, 0.5, 1.0);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform1i(samplerLoc, 0);
+
+ gl.uniform1f(scaleLoc, 1.0);
+
+ /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays;
+ switch (this.m_target) {
+ case gl.TEXTURE_2D: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 2,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positions))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ case gl.TEXTURE_3D: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 3,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positions3D))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ case gl.TEXTURE_CUBE_MAP: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 4,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positionsCube))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @param {glsSamplerObjectTest.SamplingState} state
+ */
+ glsSamplerObjectTest.TextureSamplerTest.setTextureState = function(target, state) {
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, state.minFilter);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, state.magFilter);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, state.wrapS);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, state.wrapT);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_R, state.wrapR);
+ gl.texParameterf(target, gl.TEXTURE_MAX_LOD, state.maxLod);
+ gl.texParameterf(target, gl.TEXTURE_MIN_LOD, state.minLod);
+ };
+
+ /**
+ * @private
+ * @param {glsSamplerObjectTest.SamplingState} state
+ * @param {WebGLSampler} sampler
+ */
+ glsSamplerObjectTest.TextureSamplerTest.setSamplerState = function(state, sampler) {
+ gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, state.minFilter);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, state.magFilter);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, state.wrapS);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, state.wrapT);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_R, state.wrapR);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MAX_LOD, state.maxLod);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MIN_LOD, state.minLod);
+ };
+
+ /**
+ * @private
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.createTexture2D = function() {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.Texture2D} */ var refTexture = new tcuTexture.Texture2D(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.TEXTURE2D_WIDTH,
+ glsSamplerObjectTest.TEXTURE2D_HEIGHT);
+
+ refTexture.allocLevel(0);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+
+ texture = gl.createTexture();
+
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, refTexture.getWidth(), refTexture.getHeight(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevel(0).getDataPtr());
+
+ gl.generateMipmap(gl.TEXTURE_2D);
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.createTexture3D = function() {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.Texture3D} */ var refTexture = new tcuTexture.Texture3D(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.TEXTURE3D_WIDTH,
+ glsSamplerObjectTest.TEXTURE3D_HEIGHT,
+ glsSamplerObjectTest.TEXTURE3D_DEPTH);
+
+ refTexture.allocLevel(0);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+
+ texture = gl.createTexture();
+
+ gl.bindTexture(gl.TEXTURE_3D, texture);
+
+ gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, refTexture.getWidth(), refTexture.getHeight(), refTexture.getDepth(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevel(0).getDataPtr());
+
+ gl.generateMipmap(gl.TEXTURE_3D);
+
+ gl.bindTexture(gl.TEXTURE_3D, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.createTextureCube = function() {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.TextureCube} */ var refTexture = new tcuTexture.TextureCube(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.CUBEMAP_SIZE);
+
+ texture = gl.createTexture();
+
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z, 0);
+
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_X), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]);
+
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
+ // TODO: check internalFormat / format parameters in texImage2D (were RGBA8 and RGBA respectively)
+ for (var face in tcuTexture.CubeFace) {
+ /** @const @type {number} */ var target = gluTextureUtil.getGLCubeFace(tcuTexture.CubeFace[face]);
+ gl.texImage2D(target, 0, gl.RGBA, refTexture.getSize(), refTexture.getSize(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevelFace(0, tcuTexture.CubeFace[face]).getDataPtr());
+ }
+
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.createTexture = function(target) {
+ /** @type {WebGLTexture} */ var texture;
+ switch (target) {
+ case gl.TEXTURE_2D:
+ texture = glsSamplerObjectTest.TextureSamplerTest.createTexture2D();
+ break;
+
+ case gl.TEXTURE_3D:
+ texture = glsSamplerObjectTest.TextureSamplerTest.createTexture3D();
+ break;
+
+ case gl.TEXTURE_CUBE_MAP:
+ texture = glsSamplerObjectTest.TextureSamplerTest.createTextureCube();
+ break;
+
+ default:
+ throw new Error('Unsupported target: ' + WebGLTestUtils.glEnumToString(gl, target));
+ }
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @return {string}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.selectVertexShader = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ return '#version 300 es\n' +
+ 'in highp vec2 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position, 0.0, 1.0);\n' +
+ '}';
+
+ case gl.TEXTURE_3D:
+ return '#version 300 es\n' +
+ 'in highp vec3 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec3 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position.xy, 0.0, 1.0);\n' +
+ '}';
+
+ case gl.TEXTURE_CUBE_MAP:
+ return '#version 300 es\n' +
+ 'in highp vec4 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position.zw;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position.xy, 0.0, 1.0);\n' +
+ '}';
+
+ default:
+ DE_ASSERT(false);
+ return '';
+ }
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @return {string}
+ */
+ glsSamplerObjectTest.TextureSamplerTest.selectFragmentShader = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp sampler2D u_sampler;\n' +
+ 'in mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = texture(u_sampler, v_texCoord);\n' +
+ '}';
+
+ case gl.TEXTURE_3D:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp sampler3D u_sampler;\n' +
+ 'in mediump vec3 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = texture(u_sampler, v_texCoord);\n' +
+ '}';
+
+ case gl.TEXTURE_CUBE_MAP:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp samplerCube u_sampler;\n' +
+ 'in mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = texture(u_sampler, vec3(cos(3.14 * v_texCoord.y) * sin(3.14 * v_texCoord.x), sin(3.14 * v_texCoord.y), cos(3.14 * v_texCoord.y) * cos(3.14 * v_texCoord.x)));\n' +
+ '}';
+
+ default:
+ DE_ASSERT(false);
+ return '';
+ }
+ };
+
+ glsSamplerObjectTest.TextureSamplerTest.prototype.init = function() {
+ /** @const @type {string} */ var vertexShaderTemplate = glsSamplerObjectTest.TextureSamplerTest.selectVertexShader(this.m_target);
+ /** @const @type {string} */ var fragmentShaderTemplate = glsSamplerObjectTest.TextureSamplerTest.selectFragmentShader(this.m_target);
+
+ DE_ASSERT(!this.m_program);
+ this.m_program = new gluShaderProgram.ShaderProgram(gl,
+ gluShaderProgram.makeVtxFragSources(
+ vertexShaderTemplate,
+ fragmentShaderTemplate));
+
+ if (!this.m_program.isOk()) {
+ // tcu::TestLog& log = m_testCtx.getLog();
+ // log << *m_program;
+ throw new Error('Failed to compile shaders');
+ }
+ };
+
+ glsSamplerObjectTest.TextureSamplerTest.prototype.iterate = function() {
+ //tcu::TestLog& log = m_testCtx.getLog();
+
+ /** @type {tcuSurface.Surface} */ var textureRef = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+ /** @type {tcuSurface.Surface} */ var samplerRef = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ /** @type {tcuSurface.Surface} */ var textureResult = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+ /** @type {tcuSurface.Surface} */ var samplerResult = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ /** @type {number} */ var x = this.m_random.getInt(0, gl.drawingBufferWidth - glsSamplerObjectTest.VIEWPORT_WIDTH);
+ /** @type {number} */ var y = this.m_random.getInt(0, gl.drawingBufferHeight - glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ this.renderReferences(textureRef, samplerRef, x, y);
+ this.renderResults(textureResult, samplerResult, x, y);
+
+ /** @type {boolean} */ var isOk = tcuImageCompare.pixelThresholdCompare('Sampler render result', 'Result from rendering with sampler', samplerRef, samplerResult, [0, 0, 0, 0]);
+
+ if (!tcuImageCompare.pixelThresholdCompare('Texture render result', 'Result from rendering with texture state', textureRef, textureResult, [0, 0, 0, 0]))
+ isOk = false;
+
+ assertMsgOptions(isOk, '', true, false);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ // glsSamplerObjectTest.MultiTextureSamplerTest
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @const @param {glsSamplerObjectTest.TestSpec} spec
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest = function(spec) {
+ tcuTestCase.DeqpTest.call(this, spec.name, spec.desc);
+ /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
+ /** @type {number} */ this.m_target = spec.target;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.m_textureState1 = spec.textureState;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.m_textureState2 = spec.textureState2;
+ /** @type {glsSamplerObjectTest.SamplingState} */ this.m_samplerState = spec.samplerState;
+ /** @type {deRandom.Random} */ this.m_random = new deRandom.Random(deString.deStringHash(spec.name));
+ };
+
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.constructor = glsSamplerObjectTest.MultiTextureSamplerTest;
+
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.init = function() {
+ /** @type {string} */ var vertexShaderTemplate = glsSamplerObjectTest.MultiTextureSamplerTest.selectVertexShader(this.m_target);
+ /** @type {string} */ var fragmentShaderTemplate = glsSamplerObjectTest.MultiTextureSamplerTest.selectFragmentShader(this.m_target);
+
+ DE_ASSERT(!this.m_program);
+ this.m_program = new gluShaderProgram.ShaderProgram(gl,
+ gluShaderProgram.makeVtxFragSources(
+ vertexShaderTemplate,
+ fragmentShaderTemplate));
+ if (!this.m_program.isOk()) {
+ // tcu::TestLog& log = m_testCtx.getLog();
+ //
+ // log << *m_program;
+ throw new Error('Failed to compile shaders');
+ }
+ };
+
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.deinit = function() {
+ gl.activeTexture(gl.TEXTURE0);
+ }
+
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.iterate = function() {
+ //tcu::TestLog& log = m_testCtx.getLog();
+
+ /** @type {tcuSurface.Surface} */ var textureRef = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+ /** @type {tcuSurface.Surface} */ var samplerRef = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ /** @type {tcuSurface.Surface} */ var textureResult = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+ /** @type {tcuSurface.Surface} */ var samplerResult = new tcuSurface.Surface(glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ /** @type {number} */ var x = this.m_random.getInt(0, gl.drawingBufferWidth - glsSamplerObjectTest.VIEWPORT_WIDTH);
+ /** @type {number} */ var y = this.m_random.getInt(0, gl.drawingBufferHeight - glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ this.renderReferences(textureRef, samplerRef, x, y);
+ this.renderResults(textureResult, samplerResult, x, y);
+
+ /** @type {boolean} */ var isOk = tcuImageCompare.pixelThresholdCompare('Sampler render result', 'Result from rendering with sampler', samplerRef, samplerResult, [0, 0, 0, 0]);
+
+ if (!tcuImageCompare.pixelThresholdCompare('Texture render result', 'Result from rendering with texture state', textureRef, textureResult, [0, 0, 0, 0]))
+ isOk = false;
+
+ assertMsgOptions(isOk, '', true, false);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @private
+ * @param {tcuSurface.Surface} textureRef
+ * @param {tcuSurface.Surface} samplerRef
+ * @param {number} x
+ * @param {number} y
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.renderReferences = function(textureRef, samplerRef, x, y) {
+ /** @type {WebGLTexture} */ var texture1 = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture(this.m_target, 0);
+ /** @type {WebGLTexture} */ var texture2 = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture(this.m_target, 1);
+
+ gl.viewport(x, y, glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ // Generate texture rendering reference
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(this.m_target, texture1);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this.m_target, this.m_textureState1);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(this.m_target, texture2);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this.m_target, this.m_textureState2);
+
+ this.render();
+ var texRef = textureRef.getAccess();
+ var texRefTransferFormat = gluTextureUtil.getTransferFormat(texRef.getFormat());
+ gl.readPixels(x, y, texRef.m_width, texRef.m_height, texRefTransferFormat.format, texRefTransferFormat.dataType, textureRef.m_pixels);
+
+ // Generate sampler rendering reference
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(this.m_target, texture1);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this.m_target, this.m_samplerState);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(this.m_target, texture2);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this.m_target, this.m_samplerState);
+
+ this.render();
+ var sampRef = samplerRef.getAccess();
+ var sampRefTransferFormat = gluTextureUtil.getTransferFormat(sampRef.getFormat());
+ gl.readPixels(x, y, sampRef.m_width, sampRef.m_height, sampRefTransferFormat.format, sampRefTransferFormat.dataType, samplerRef.m_pixels);
+ };
+
+ /**
+ * @private
+ * @param {tcuSurface.Surface} textureResult
+ * @param {tcuSurface.Surface} samplerResult
+ * @param {number} x
+ * @param {number} y
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.renderResults = function(textureResult, samplerResult, x, y) {
+ /** @type {WebGLTexture} */ var texture1 = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture(this.m_target, 0);
+ /** @type {WebGLTexture} */ var texture2 = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture(this.m_target, 1);
+
+ gl.viewport(x, y, glsSamplerObjectTest.VIEWPORT_WIDTH, glsSamplerObjectTest.VIEWPORT_HEIGHT);
+
+ /** @type {WebGLSampler} */ var sampler = gl.createSampler();
+ DE_ASSERT(sampler != -1);
+
+ gl.bindSampler(0, sampler);
+ gl.bindSampler(1, sampler);
+
+ // First set sampler state
+ glsSamplerObjectTest.MultiTextureSamplerTest.setSamplerState(this.m_samplerState, sampler);
+
+ // Set texture state
+ gl.bindTexture(this.m_target, texture1);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this.m_target, this.m_textureState1);
+
+ gl.bindTexture(this.m_target, texture2);
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState(this. m_target, this.m_textureState2);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(this.m_target, texture1);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(this.m_target, texture2);
+
+ // Render using sampler
+ this.render();
+ var sampRes = samplerResult.getAccess();
+ var sampResTransferFormat = gluTextureUtil.getTransferFormat(sampRes.getFormat());
+ gl.readPixels(x, y, sampRes.m_width, sampRes.m_height, sampResTransferFormat.format, sampResTransferFormat.dataType, samplerResult.m_pixels);
+
+ gl.bindSampler(0, null);
+ gl.bindSampler(1, null);
+
+ this.render();
+ var texRes = textureResult.getAccess();
+ var texResTransferFormat = gluTextureUtil.getTransferFormat(texRes.getFormat());
+ gl.readPixels(x, y, texRes.m_width, texRes.m_height, texResTransferFormat.format, texResTransferFormat.dataType, textureResult.m_pixels);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(this.m_target, null);
+
+ gl.activeTexture(gl.TEXTURE1);
+ gl.bindTexture(this.m_target, null);
+
+ gl.deleteSampler(sampler);
+ gl.deleteTexture(texture1);
+ gl.deleteTexture(texture2);
+ };
+
+ glsSamplerObjectTest.MultiTextureSamplerTest.prototype.render = function() {
+
+ gl.useProgram(this.m_program.getProgram());
+
+ /** @type {WebGLUniformLocation} */ var samplerLoc1 = gl.getUniformLocation(this.m_program.getProgram(), 'u_sampler1');
+ DE_ASSERT(samplerLoc1 != -1);
+
+ /** @type {WebGLUniformLocation} */ var samplerLoc2 = gl.getUniformLocation(this.m_program.getProgram(), 'u_sampler2');
+ DE_ASSERT(samplerLoc2 != -1);
+
+ /** @type {WebGLUniformLocation} */ var scaleLoc = gl.getUniformLocation(this.m_program.getProgram(), 'u_posScale');
+ DE_ASSERT(scaleLoc != -1);
+
+ gl.clearColor(0.5, 0.5, 0.5, 1.0);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.uniform1i(samplerLoc1, 0);
+
+ gl.uniform1i(samplerLoc2, 1);
+
+ gl.uniform1f(scaleLoc, 1.0);
+
+ /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays;
+ switch (this.m_target) {
+ case gl.TEXTURE_2D: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 2,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positions))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ case gl.TEXTURE_3D: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 3,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positions3D))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ case gl.TEXTURE_CUBE_MAP: {
+ vertexArrays = [
+ gluDrawUtil.vabFromBindingPointAndArrayPointer(
+ gluDrawUtil.bindingPointFromName('a_position'),
+ new gluDrawUtil.VertexArrayPointer(
+ gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE,
+ 4,
+ 6,
+ 0,
+ glsSamplerObjectTest.s_positionsCube))
+ ];
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ gl.uniform1f(scaleLoc, 0.25);
+
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays, new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.TRIANGLES, 6));
+
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @param {glsSamplerObjectTest.SamplingState} state
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.setTextureState = function(target, state) {
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, state.minFilter);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, state.magFilter);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, state.wrapS);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, state.wrapT);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_R, state.wrapR);
+ gl.texParameterf(target, gl.TEXTURE_MAX_LOD, state.maxLod);
+ gl.texParameterf(target, gl.TEXTURE_MIN_LOD, state.minLod);
+ };
+
+ /**
+ * @private
+ * @param {glsSamplerObjectTest.SamplingState} state
+ * @param {WebGLSampler} sampler
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.setSamplerState = function(state, sampler) {
+ gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, state.minFilter);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, state.magFilter);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, state.wrapS);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, state.wrapT);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_R, state.wrapR);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MAX_LOD, state.maxLod);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MIN_LOD, state.minLod);
+ };
+
+ /**
+ * @private
+ * @param {number} id
+ * @return {WebGLTexture }
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.createTexture2D = function(id) {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.Texture2D} */ var refTexture = new tcuTexture.Texture2D(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.TEXTURE2D_WIDTH,
+ glsSamplerObjectTest.TEXTURE2D_HEIGHT);
+
+ refTexture.allocLevel(0);
+
+ texture = gl.createTexture();
+
+ switch (id) {
+ case 0:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.5, 0.5]);
+ break;
+
+ case 1:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 1.0, 1.0]);
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, refTexture.getWidth(), refTexture.getHeight(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevel(0).getDataPtr());
+
+ gl.generateMipmap(gl.TEXTURE_2D);
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} id
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.createTexture3D = function(id) {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.Texture3D} */ var refTexture = new tcuTexture.Texture3D(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.TEXTURE3D_WIDTH,
+ glsSamplerObjectTest.TEXTURE3D_HEIGHT,
+ glsSamplerObjectTest.TEXTURE3D_DEPTH);
+
+ refTexture.allocLevel(0);
+
+ texture = gl.createTexture();
+
+ switch (id) {
+ case 0:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.5, 0.5]);
+ break;
+
+ case 1:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevel(0), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 1.0, 1.0]);
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ gl.bindTexture(gl.TEXTURE_3D, texture);
+ // TODO: check internalFormat and format in texImage3D
+ gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, refTexture.getWidth(), refTexture.getHeight(), refTexture.getDepth(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevel(0).getDataPtr());
+
+ gl.generateMipmap(gl.TEXTURE_3D);
+
+ gl.bindTexture(gl.TEXTURE_3D, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} id
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.createTextureCube = function(id) {
+ /** @type {WebGLTexture} */ var texture = null;
+ /** @type {tcuTexture.TextureCube} */ var refTexture = new tcuTexture.TextureCube(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8),
+ glsSamplerObjectTest.CUBEMAP_SIZE);
+
+ texture = gl.createTexture();
+
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, 0);
+ refTexture.allocLevel(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z, 0);
+
+ switch (id) {
+ case 0:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_X), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z), [0.0, 0.0, 0.0, 0.0], [0.5, 0.5, 0.5, 0.5]);
+ break;
+
+ case 1:
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_X), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ tcuTextureUtil.fillWithComponentGradients(refTexture.getLevelFace(0, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z), [0.5, 0.5, 0.5, 0.5], [1.0, 1.0, 1.0, 1.0]);
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
+
+ for (var face in tcuTexture.CubeFace) {
+ /** @const @type {number} */ var target = gluTextureUtil.getGLCubeFace(tcuTexture.CubeFace[face]);
+ gl.texImage2D(target, 0, gl.RGBA, refTexture.getSize(), refTexture.getSize(), 0, gl.RGBA, gl.UNSIGNED_BYTE, refTexture.getLevelFace(0, tcuTexture.CubeFace[face]).getDataPtr());
+ }
+
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @param {number} id
+ * @return {WebGLTexture}
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.createTexture = function(target, id) {
+ /** @type {WebGLTexture} */ var texture;
+ switch (target) {
+ case gl.TEXTURE_2D:
+ texture = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture2D(id);
+ break;
+
+ case gl.TEXTURE_3D:
+ texture = glsSamplerObjectTest.MultiTextureSamplerTest.createTexture3D(id);
+ break;
+
+ case gl.TEXTURE_CUBE_MAP:
+ texture = glsSamplerObjectTest.MultiTextureSamplerTest.createTextureCube(id);
+ break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ return texture;
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @return {string}
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.selectVertexShader = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ return '#version 300 es\n' +
+ 'in highp vec2 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position, 0.0, 1.0);\n' +
+ '}';
+
+ case gl.TEXTURE_3D:
+ return '#version 300 es\n' +
+ 'in highp vec3 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec3 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position.xy, 0.0, 1.0);\n' +
+ '}';
+
+ case gl.TEXTURE_CUBE_MAP:
+ return '#version 300 es\n' +
+ 'in highp vec4 a_position;\n' +
+ 'uniform highp float u_posScale;\n' +
+ 'out mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\tv_texCoord = a_position.zw;\n' +
+ '\tgl_Position = vec4(u_posScale * a_position.xy, 0.0, 1.0);\n' +
+ '}';
+
+ default:
+ DE_ASSERT(false);
+ return '';
+ }
+ };
+
+ /**
+ * @private
+ * @param {number} target
+ * @return {string}
+ */
+ glsSamplerObjectTest.MultiTextureSamplerTest.selectFragmentShader = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp sampler2D u_sampler1;\n' +
+ 'uniform lowp sampler2D u_sampler2;\n' +
+ 'in mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = vec4(0.75, 0.75, 0.75, 1.0) * (texture(u_sampler1, v_texCoord) + texture(u_sampler2, v_texCoord));\n' +
+ '}';
+
+ break;
+
+ case gl.TEXTURE_3D:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp sampler3D u_sampler1;\n' +
+ 'uniform lowp sampler3D u_sampler2;\n' +
+ 'in mediump vec3 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = vec4(0.75, 0.75, 0.75, 1.0) * (texture(u_sampler1, v_texCoord) + texture(u_sampler2, v_texCoord));\n' +
+ '}';
+
+ case gl.TEXTURE_CUBE_MAP:
+ return '#version 300 es\nlayout(location = 0) out mediump vec4 o_color;\n' +
+ 'uniform lowp samplerCube u_sampler1;\n' +
+ 'uniform lowp samplerCube u_sampler2;\n' +
+ 'in mediump vec2 v_texCoord;\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ '\to_color = vec4(0.5, 0.5, 0.5, 1.0) * (texture(u_sampler1, vec3(cos(3.14 * v_texCoord.y) * sin(3.14 * v_texCoord.x), sin(3.14 * v_texCoord.y), cos(3.14 * v_texCoord.y) * cos(3.14 * v_texCoord.x)))' +
+ '+ texture(u_sampler2, vec3(cos(3.14 * v_texCoord.y) * sin(3.14 * v_texCoord.x), sin(3.14 * v_texCoord.y), cos(3.14 * v_texCoord.y) * cos(3.14 * v_texCoord.x))));\n' +
+ '}';
+
+ default:
+ DE_ASSERT(false);
+ return '';
+ }
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js
new file mode 100644
index 000000000..0241dd2de
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js
@@ -0,0 +1,735 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL (ES) Module
+ * -----------------------------------------------
+ *
+ * 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.
+ *
+ *//*!
+ * \file
+ * \brief Shader execution utilities.
+ *//*--------------------------------------------------------------------*/
+'use strict';
+goog.provide('modules.shared.glsShaderExecUtil');
+goog.require('framework.common.tcuMatrix');
+goog.require('framework.common.tcuMatrixUtil');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.opengl.gluVarType');
+
+goog.scope(function() {
+
+ var glsShaderExecUtil = modules.shared.glsShaderExecUtil;
+ var gluVarType = framework.opengl.gluVarType;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var gluShaderProgram = framework.opengl.gluShaderProgram;
+ var gluDrawUtil = framework.opengl.gluDrawUtil;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var tcuTexture = framework.common.tcuTexture;
+ var tcuMatrix = framework.common.tcuMatrix;
+ var tcuMatrixUtil = framework.common.tcuMatrixUtil;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ var setParentClass = function(child, parent) {
+ child.prototype = Object.create(parent.prototype);
+ child.prototype.constructor = child;
+ };
+
+ /**
+ * @constructor
+ * @param {string=} name
+ * @param {gluVarType.VarType=} varType
+ */
+ glsShaderExecUtil.Symbol = function(name, varType) {
+ name = name === undefined ? '<unnamed>' : name;
+ /** @type {string} */ this.name = name;
+ /** @type {gluVarType.VarType} */ this.varType = varType || null;
+ };
+
+ //! Complete shader specification.
+ /**
+ * @constructor
+ */
+ glsShaderExecUtil.ShaderSpec = function() {
+ /** @type {gluShaderUtil.GLSLVersion} */ this.version = gluShaderUtil.GLSLVersion.V300_ES; //!< Shader version.
+ /** @type {Array<glsShaderExecUtil.Symbol>} */ this.inputs = [];
+ /** @type {Array<glsShaderExecUtil.Symbol>} */ this.outputs = [];
+ /** @type {string} */ this.globalDeclarations = ''; //!< These are placed into global scope. Can contain uniform declarations for example.
+ /** @type {*} */ this.source; //!< Source snippet to be executed.
+ };
+
+ /**
+ * Base class for shader executor.
+ * @constructor
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ */
+ glsShaderExecUtil.ShaderExecutor = function(shaderSpec) {
+ /** @type {Array<glsShaderExecUtil.Symbol>} */ this.m_inputs = shaderSpec.inputs;
+ /** @type {Array<glsShaderExecUtil.Symbol>} */ this.m_outputs = shaderSpec.outputs;
+ };
+
+ glsShaderExecUtil.ShaderExecutor.prototype.useProgram = function() {
+ DE_ASSERT(this.isOk);
+ gl.useProgram(this.getProgram());
+ };
+
+ /**
+ * @return {boolean}
+ */
+ glsShaderExecUtil.ShaderExecutor.prototype.isOk = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @return {WebGLProgram}
+ */
+ glsShaderExecUtil.ShaderExecutor.prototype.getProgram = function() {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * @param {number} numValues
+ * @param {Array<Array<number>>} inputs
+ * @return {Array<goog.TypedArray>} outputs
+ */
+ glsShaderExecUtil.ShaderExecutor.prototype.execute = function(numValues, inputs) {
+ throw new Error('Virtual function. Please override.');
+ };
+
+ /**
+ * Base class for shader executor.
+ * @param {gluShaderProgram.shaderType} shaderType
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ * @return {glsShaderExecUtil.ShaderExecutor}
+ */
+ glsShaderExecUtil.createExecutor = function(shaderType, shaderSpec) {
+ switch (shaderType) {
+ case gluShaderProgram.shaderType.VERTEX: return new glsShaderExecUtil.VertexShaderExecutor(shaderSpec);
+ case gluShaderProgram.shaderType.FRAGMENT: return new glsShaderExecUtil.FragmentShaderExecutor(shaderSpec);
+ default:
+ throw new Error('Unsupported shader type: ' + shaderType);
+ }
+ };
+
+ /**
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ * @return {string}
+ */
+ glsShaderExecUtil.generateVertexShader = function(shaderSpec) {
+ /** @type {boolean} */ var usesInout = true;
+ /** @type {string} */ var in_ = usesInout ? 'in' : 'attribute';
+ /** @type {string} */ var out = usesInout ? 'out' : 'varying';
+ /** @type {string} */ var src = '';
+ /** @type {number} */ var vecSize;
+ /** @type {gluShaderUtil.DataType} */ var intBaseType;
+
+ src += '#version 300 es\n';
+
+ if (shaderSpec.globalDeclarations.length > 0)
+ src += (shaderSpec.globalDeclarations + '\n');
+
+ for (var i = 0; i < shaderSpec.inputs.length; ++i)
+ src += (in_ + ' ' + gluVarType.declareVariable(shaderSpec.inputs[i].varType, shaderSpec.inputs[i].name) + ';\n');
+
+ for (var i = 0; i < shaderSpec.outputs.length; i++) {
+ var output = shaderSpec.outputs[i];
+ DE_ASSERT(output.varType.isBasicType());
+
+ if (gluShaderUtil.isDataTypeBoolOrBVec(output.varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeScalarSize(output.varType.getBasicType());
+ intBaseType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT;
+ /** @type {gluVarType.VarType} */ var intType = new gluVarType.VarType().VarTypeBasic(intBaseType, gluShaderUtil.precision.PRECISION_HIGHP);
+
+ src += ('flat ' + out + ' ' + gluVarType.declareVariable(intType, 'o_' + output.name) + ';\n');
+ } else
+ src += ('flat ' + out + ' ' + gluVarType.declareVariable(output.varType, output.name) + ';\n');
+ }
+
+ src += '\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' gl_Position = vec4(0.0);\n' +
+ ' gl_PointSize = 1.0;\n\n';
+
+ // Declare necessary output variables (bools).
+ for (var i = 0; i < shaderSpec.outputs.length; i++) {
+ if (gluShaderUtil.isDataTypeBoolOrBVec(shaderSpec.outputs[i].varType.getBasicType()))
+ src += ('\t' + gluVarType.declareVariable(shaderSpec.outputs[i].varType, shaderSpec.outputs[i].name) + ';\n');
+ }
+
+ //Operation - indented to correct level.
+ // TODO: Add indenting
+ src += shaderSpec.source;
+
+ // Assignments to outputs.
+ for (var i = 0; i < shaderSpec.outputs.length; i++) {
+ if (gluShaderUtil.isDataTypeBoolOrBVec(output.varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeScalarSize(output.varType.getBasicType());
+ intBaseType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT;
+
+ src += ('\to_' + output.name + ' = ' + gluShaderUtil.getDataTypeName(intBaseType) + '(' + output.name + ');\n');
+ }
+ }
+
+ src += '}\n';
+
+ return src;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsShaderExecUtil.generateEmptyFragmentSource = function() {
+ /** @type {boolean} */ var customOut = true;
+ /** @type {string} */ var src;
+
+ src = '#version 300 es\n';
+
+ // \todo [2013-08-05 pyry] Do we need one dummy output?
+
+ src += 'void main (void)\n{\n';
+ if (!customOut)
+ src += ' gl.FragColor = vec4(0.0);\n';
+ src += '}\n';
+
+ return src;
+ };
+
+ /**
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ * @param {string} inputPrefix
+ * @param {string} outputPrefix
+ * @return {string}
+ */
+ glsShaderExecUtil.generatePassthroughVertexShader = function(shaderSpec, inputPrefix, outputPrefix) {
+ // flat qualifier is not present in earlier versions?
+ // DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
+
+ /** @type {string} */ var src;
+
+ src = '#version 300 es\n' +
+ 'in highp vec4 a_position;\n';
+
+ for (var i = 0; i < shaderSpec.inputs.length; i++) {
+ src += ('in ' + gluVarType.declareVariable(shaderSpec.inputs[i].varType, inputPrefix + shaderSpec.inputs[i].name) + ';\n' +
+ 'flat out ' + gluVarType.declareVariable(shaderSpec.inputs[i].varType, outputPrefix + shaderSpec.inputs[i].name) + ';\n');
+ }
+
+ src += '\nvoid main (void)\n{\n' +
+ ' gl_Position = a_position;\n' +
+ ' gl_PointSize = 1.0;\n';
+
+ for (var i = 0; i < shaderSpec.inputs.length; i++)
+ src += ('\t' + outputPrefix + shaderSpec.inputs[i].name + ' = ' + inputPrefix + shaderSpec.inputs[i].name + ';\n');
+
+ src += '}\n';
+
+ return src;
+ };
+
+ /**
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ * @param {boolean} useIntOutputs
+ * @param {*} outLocationMap
+ * @return {string}
+ */
+ glsShaderExecUtil.generateFragmentShader = function(shaderSpec, useIntOutputs, outLocationMap) {
+ /** @type {number} */ var vecSize;
+ /** @type {number} */ var numVecs;
+ /** @type {gluShaderUtil.DataType} */ var intBasicType;
+ /** @type {gluShaderUtil.DataType} */ var uintBasicType;
+ /** @type {gluVarType.VarType} */ var uintType;
+ /** @type {gluVarType.VarType} */ var intType;
+
+ /** @type {string} */ var src;
+ src = '#version 300 es\n';
+
+ if (!shaderSpec.globalDeclarations.length > 0)
+ src += (shaderSpec.globalDeclarations + '\n');
+
+ for (var i = 0; i < shaderSpec.inputs.length; i++)
+ src += ('flat in ' + gluVarType.declareVariable(shaderSpec.inputs[i].varType, shaderSpec.inputs[i].name) + ';\n');
+
+ for (var outNdx = 0; outNdx < shaderSpec.outputs.length; ++outNdx) {
+ /** @type {glsShaderExecUtil.Symbol} */ var output = shaderSpec.outputs[outNdx];
+ /** @type {number} */ var location = outLocationMap[output.name];
+ /** @type {string} */ var outVarName = 'o_' + output.name;
+ /** @type {gluVarType.VariableDeclaration} */ var decl = new gluVarType.VariableDeclaration(output.varType, outVarName, gluVarType.Storage.STORAGE_OUT, undefined, new gluVarType.Layout(location));
+
+ DE_ASSERT(output.varType.isBasicType());
+
+ if (useIntOutputs && gluShaderUtil.isDataTypeFloatOrVec(output.varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeScalarSize(output.varType.getBasicType());
+ uintBasicType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.UINT, vecSize) : gluShaderUtil.DataType.UINT;
+ uintType = gluVarType.newTypeBasic(uintBasicType, gluShaderUtil.precision.PRECISION_HIGHP);
+
+ decl.varType = uintType;
+ src += (decl + ';\n');
+ } else if (gluShaderUtil.isDataTypeBoolOrBVec(output.varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeScalarSize(output.varType.getBasicType());
+ intBasicType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT;
+ intType = gluVarType.newTypeBasic(intBasicType, gluShaderUtil.precision.PRECISION_HIGHP);
+
+ decl.varType = intType;
+ src += (decl + ';\n');
+ } else if (gluShaderUtil.isDataTypeMatrix(output.varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeMatrixNumRows(output.varType.getBasicType());
+ numVecs = gluShaderUtil.getDataTypeMatrixNumColumns(output.varType.getBasicType());
+ uintBasicType = gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.UINT, vecSize);
+ uintType = gluVarType.newTypeBasic(uintBasicType, gluShaderUtil.precision.PRECISION_HIGHP);
+
+ decl.varType = uintType;
+ for (var vecNdx = 0; vecNdx < numVecs; ++vecNdx) {
+ decl.name = outVarName + '_' + (vecNdx);
+ decl.layout.location = location + vecNdx;
+ src += (decl + ';\n');
+ }
+ } else //src += '';//glu::VariableDeclaration(output.varType, output.name, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, location) << ";\n";
+ src += new gluVarType.VariableDeclaration(output.varType, output.name, gluVarType.Storage.STORAGE_OUT, undefined, new gluVarType.Layout(location)) + ';\n';
+ }
+
+ src += '\nvoid main (void)\n{\n';
+
+ for (var i = 0; i < shaderSpec.outputs.length; i++) {
+ if ((useIntOutputs && gluShaderUtil.isDataTypeFloatOrVec(shaderSpec.outputs[i].varType.getBasicType())) ||
+ gluShaderUtil.isDataTypeBoolOrBVec(shaderSpec.outputs[i].varType.getBasicType()) ||
+ gluShaderUtil.isDataTypeMatrix(shaderSpec.outputs[i].varType.getBasicType()))
+ src += ('\t' + gluVarType.declareVariable(shaderSpec.outputs[i].varType, shaderSpec.outputs[i].name) + ';\n');
+ }
+
+ // Operation - indented to correct level.
+ // TODO: Add indenting
+ src += shaderSpec.source;
+ // {
+ // std::istringstream opSrc (shaderSpec.source);
+ // /** @type{number} */ var line;
+ //
+ // while (std::getline(opSrc, line))
+ // src += ('\t' << line << '\n');
+ // }
+
+ for (var i = 0; i < shaderSpec.outputs.length; i++) {
+ if (useIntOutputs && gluShaderUtil.isDataTypeFloatOrVec(shaderSpec.outputs[i].varType.getBasicType()))
+ src += (' o_' + shaderSpec.outputs[i].name + ' = floatBitsToUint(' + shaderSpec.outputs[i].name + ');\n');
+ else if (gluShaderUtil.isDataTypeMatrix(shaderSpec.outputs[i].varType.getBasicType())) {
+ numVecs = gluShaderUtil.getDataTypeMatrixNumColumns(shaderSpec.outputs[i].varType.getBasicType());
+
+ for (var vecNdx = 0; vecNdx < numVecs; ++vecNdx)
+ if (useIntOutputs)
+ src += ('\to_' + shaderSpec.outputs[i].name + '_' + vecNdx + ' = floatBitsToUint(' + shaderSpec.outputs[i].name + '[' + vecNdx + ']);\n');
+ else
+ src += ('\to_' + shaderSpec.outputs[i].name + '_' + vecNdx + ' = ' + shaderSpec.outputs[i].name + '[' + vecNdx + '];\n');
+ } else if (gluShaderUtil.isDataTypeBoolOrBVec(shaderSpec.outputs[i].varType.getBasicType())) {
+ vecSize = gluShaderUtil.getDataTypeScalarSize(shaderSpec.outputs[i].varType.getBasicType());
+ intBasicType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT;
+
+ src += ('\to_' + shaderSpec.outputs[i].name + ' = ' + gluShaderUtil.getDataTypeName(intBasicType) + '(' + shaderSpec.outputs[i].name + ');\n');
+ }
+ }
+
+ src += '}\n';
+
+ return src;
+ };
+
+ /**
+ * @param {Array<glsShaderExecUtil.Symbol>} outputs
+ * @return {gluShaderProgram.TransformFeedbackVaryings}
+ */
+ glsShaderExecUtil.getTFVaryings = function(outputs) {
+ var names = [];
+ for (var i = 0; i < outputs.length; i++) {
+ if (gluShaderUtil.isDataTypeBoolOrBVec(outputs[i].varType.getBasicType())) {
+ names.push('o_' + outputs[i].name);
+ } else {
+ names.push(outputs[i].name);
+ }
+ }
+ return new gluShaderProgram.TransformFeedbackVaryings(names);
+ };
+
+ // VertexProcessorExecutor (base class for vertex and geometry executors)
+
+ /**
+ * @constructor
+ * @extends {glsShaderExecUtil.ShaderExecutor}
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ * @param {gluShaderProgram.ProgramSources} sources
+ */
+ glsShaderExecUtil.VertexProcessorExecutor = function(shaderSpec, sources) {
+ sources.add(glsShaderExecUtil.getTFVaryings(shaderSpec.outputs));
+ sources.add(new gluShaderProgram.TransformFeedbackMode(gl.INTERLEAVED_ATTRIBS));
+ glsShaderExecUtil.ShaderExecutor.call(this, shaderSpec);
+ this.m_program = new gluShaderProgram.ShaderProgram(gl, sources);
+ };
+
+ setParentClass(glsShaderExecUtil.VertexProcessorExecutor, glsShaderExecUtil.ShaderExecutor);
+
+ /**
+ * @return {boolean}
+ */
+ glsShaderExecUtil.VertexProcessorExecutor.prototype.isOk = function() {
+ return this.m_program.isOk();
+ };
+
+ /**
+ * @return {WebGLProgram}
+ */
+ glsShaderExecUtil.VertexProcessorExecutor.prototype.getProgram = function() {
+ return this.m_program.getProgram();
+ };
+
+ /**
+ * @param {Array<*>} arr
+ * @return {number}
+ */
+ glsShaderExecUtil.computeTotalScalarSize = function(arr) {
+ /** @type {number} */ var size = 0;
+ for (var i = 0; i < arr.length; i++)
+ size += arr[i].varType.getScalarSize();
+ return size;
+ };
+
+ /**
+ * @param {Array<number>} ptr
+ * @param {number} colNdx
+ * @param {number} size Column size
+ * @return {Array<number>}
+ */
+ glsShaderExecUtil.getColumn = function(ptr, colNdx, size) {
+ var begin = colNdx * size;
+ var end = (colNdx + 1) * size;
+ return ptr.slice(begin, end);
+ };
+
+ glsShaderExecUtil.VertexProcessorExecutor.prototype.execute = function(numValues, inputs) {
+ /** @type {glsShaderExecUtil.Symbol} */ var symbol;
+ var outputs = [];
+ /** @type {boolean} */ var useTFObject = true;
+ /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
+ var transformFeedback = gl.createTransformFeedback();
+ var outputBuffer = gl.createBuffer();
+
+ /** @type {number} */ var outputBufferStride = glsShaderExecUtil.computeTotalScalarSize(this.m_outputs) * 4;
+
+ // Setup inputs.
+ for (var inputNdx = 0; inputNdx < this.m_inputs.length; inputNdx++) {
+ symbol = this.m_inputs[inputNdx];
+ /*const void* */var ptr = inputs[inputNdx];
+ /** @type {gluShaderUtil.DataType} */ var basicType = symbol.varType.getBasicType();
+ /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(basicType);
+
+ if (gluShaderUtil.isDataTypeFloatOrVec(basicType))
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding(symbol.name, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeIntOrIVec(basicType))
+ vertexArrays.push(gluDrawUtil.newInt32VertexArrayBinding(symbol.name, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeUintOrUVec(basicType))
+ vertexArrays.push(gluDrawUtil.newUint32VertexArrayBinding(symbol.name, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+ /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(basicType);
+ // A matrix consists of several (column-major) vectors. A buffer is created for
+ // every vector in gluDrawUtil.draw() below. Data in every buffer will be tightly
+ // packed. So the stride should be 0. This is different from the code in native
+ // deqp, which use only one buffer for a matrix, the data is interleaved.
+ /** @type {number} */ var stride = 0;
+
+ for (var colNdx = 0; colNdx < numCols; ++colNdx)
+ vertexArrays.push(gluDrawUtil.newFloatColumnVertexArrayBinding(symbol.name,
+ colNdx,
+ numRows,
+ numValues,
+ stride,
+ glsShaderExecUtil.getColumn(ptr, colNdx, numRows * numValues)));
+ } else
+ DE_ASSERT(false);
+ }
+
+ // Setup TF outputs.
+ if (useTFObject)
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transformFeedback);
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, outputBuffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, outputBufferStride * numValues, gl.STREAM_READ);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, outputBuffer);
+
+ // Draw with rasterization disabled.
+ gl.beginTransformFeedback(gl.POINTS);
+ gl.enable(gl.RASTERIZER_DISCARD);
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays,
+ new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.POINTS, numValues));
+ gl.disable(gl.RASTERIZER_DISCARD);
+ gl.endTransformFeedback();
+
+ // Read back data.
+ var result = new ArrayBuffer(outputBufferStride * numValues);
+ gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, new Uint8Array(result));
+ /** @type {number} */ var curOffset = 0; // Offset in buffer in bytes.
+
+ for (var outputNdx = 0; outputNdx < this.m_outputs.length; outputNdx++) {
+ symbol = this.m_outputs[outputNdx];
+ /** @type {number} */ var scalarSize = symbol.varType.getScalarSize();
+ var readPtr = new Uint8Array(result, curOffset);
+
+ if (scalarSize * 4 === outputBufferStride)
+ outputs[outputNdx] = readPtr;
+ else {
+ var dstPtr = new Uint8Array(scalarSize * numValues * 4);
+
+ for (var ndx = 0; ndx < numValues; ndx++)
+ for (var j = 0; j < scalarSize * 4; j++) {
+ dstPtr[scalarSize * 4 * ndx + j] = readPtr[ndx * outputBufferStride + j];
+ }
+ outputs[outputNdx] = dstPtr;
+ }
+ curOffset += scalarSize * 4;
+ }
+
+ if (useTFObject)
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
+
+ return outputs;
+ };
+
+ // VertexShaderExecutor
+
+ /**
+ * @constructor
+ * @extends {glsShaderExecUtil.VertexProcessorExecutor}
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ */
+ glsShaderExecUtil.VertexShaderExecutor = function(shaderSpec) {
+ var sources = gluShaderProgram.makeVtxFragSources(glsShaderExecUtil.generateVertexShader(shaderSpec),
+ glsShaderExecUtil.generateEmptyFragmentSource());
+ glsShaderExecUtil.VertexProcessorExecutor.call(this, shaderSpec, sources);
+ };
+
+ setParentClass(glsShaderExecUtil.VertexShaderExecutor, glsShaderExecUtil.VertexProcessorExecutor);
+
+ /**
+ * @constructor
+ * @extends {glsShaderExecUtil.ShaderExecutor}
+ * @param {glsShaderExecUtil.ShaderSpec} shaderSpec
+ */
+ glsShaderExecUtil.FragmentShaderExecutor = function(shaderSpec) {
+ glsShaderExecUtil.ShaderExecutor.call(this, shaderSpec);
+ /** @type {Array<glsShaderExecUtil.Symbol>} */ this.m_outLocationSymbols = [];
+ this.m_outLocationMap = glsShaderExecUtil.generateLocationMap(this.m_outputs, this.m_outLocationSymbols);
+ var sources = gluShaderProgram.makeVtxFragSources(glsShaderExecUtil.generatePassthroughVertexShader(shaderSpec, 'a_', ''),
+ glsShaderExecUtil.generateFragmentShader(shaderSpec, true, this.m_outLocationMap));
+ this.m_program = new gluShaderProgram.ShaderProgram(gl, sources);
+ };
+
+ setParentClass(glsShaderExecUtil.FragmentShaderExecutor, glsShaderExecUtil.ShaderExecutor);
+
+ /**
+ * @return {boolean}
+ */
+ glsShaderExecUtil.FragmentShaderExecutor.prototype.isOk = function() {
+ return this.m_program.isOk();
+ };
+
+ /**
+ * @return {WebGLProgram}
+ */
+ glsShaderExecUtil.FragmentShaderExecutor.prototype.getProgram = function() {
+ return this.m_program.getProgram();
+ };
+
+ /**
+ * @param {gluVarType.VarType} outputType
+ * @param {boolean} useIntOutputs
+ * @return {tcuTexture.TextureFormat}
+ */
+ glsShaderExecUtil.getRenderbufferFormatForOutput = function(outputType, useIntOutputs) {
+ var channelOrderMap = [
+ tcuTexture.ChannelOrder.R,
+ tcuTexture.ChannelOrder.RG,
+ tcuTexture.ChannelOrder.RGBA, // No RGB variants available.
+ tcuTexture.ChannelOrder.RGBA
+ ];
+
+ var basicType = outputType.getBasicType();
+ var numComps = gluShaderUtil.getDataTypeNumComponents(basicType);
+ var channelType;
+
+ switch (gluShaderUtil.getDataTypeScalarType(basicType)) {
+ case 'uint': channelType = tcuTexture.ChannelType.UNSIGNED_INT32; break;
+ case 'int': channelType = tcuTexture.ChannelType.SIGNED_INT32; break;
+ case 'bool': channelType = tcuTexture.ChannelType.SIGNED_INT32; break;
+ case 'float': channelType = useIntOutputs ? tcuTexture.ChannelType.UNSIGNED_INT32 : tcuTexture.ChannelType.FLOAT; break;
+ default:
+ throw new Error('Invalid output type ' + gluShaderUtil.getDataTypeScalarType(basicType));
+ }
+
+ return new tcuTexture.TextureFormat(channelOrderMap[numComps - 1], channelType);
+ };
+
+ glsShaderExecUtil.FragmentShaderExecutor.prototype.execute = function(numValues, inputs) {
+ /** @type {boolean} */ var useIntOutputs = true;
+ /** @type {glsShaderExecUtil.Symbol} */ var symbol;
+ var outputs = [];
+ var maxRenderbufferSize = /** @type {number} */ (gl.getParameter(gl.MAX_RENDERBUFFER_SIZE));
+ /** @type {number} */ var framebufferW = Math.min(maxRenderbufferSize, numValues);
+ /** @type {number} */ var framebufferH = Math.ceil(numValues / framebufferW);
+
+ var framebuffer = gl.createFramebuffer();
+ var renderbuffers = [];
+ for (var i = 0; i < this.m_outLocationSymbols.length; i++)
+ renderbuffers.push(gl.createRenderbuffer());
+
+ var vertexArrays = [];
+ var positions = [];
+
+ if (framebufferH > maxRenderbufferSize)
+ throw new Error('Value count is too high for maximum supported renderbuffer size');
+
+ // Compute positions - 1px points are used to drive fragment shading.
+ for (var valNdx = 0; valNdx < numValues; valNdx++) {
+ /** @type {number} */ var ix = valNdx % framebufferW;
+ /** @type {number} */ var iy = Math.floor(valNdx / framebufferW);
+ var fx = -1 + 2 * (ix + 0.5) / framebufferW;
+ var fy = -1 + 2 * (iy + 0.5) / framebufferH;
+
+ positions[2 * valNdx] = fx;
+ positions[2 * valNdx + 1] = fy;
+ }
+
+ // Vertex inputs.
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding('a_position', 2, numValues, 0, positions));
+
+ for (var inputNdx = 0; inputNdx < this.m_inputs.length; inputNdx++) {
+ symbol = this.m_inputs[inputNdx];
+ var attribName = 'a_' + symbol.name;
+ var ptr = inputs[inputNdx];
+ /** @type {gluShaderUtil.DataType} */ var basicType = symbol.varType.getBasicType();
+ /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(basicType);
+
+ if (gluShaderUtil.isDataTypeFloatOrVec(basicType))
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding(attribName, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeIntOrIVec(basicType))
+ vertexArrays.push(gluDrawUtil.newInt32VertexArrayBinding(attribName, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeUintOrUVec(basicType))
+ vertexArrays.push(gluDrawUtil.newUint32VertexArrayBinding(attribName, vecSize, numValues, 0, ptr));
+ else if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(basicType);
+ // A matrix consists of several (column-major) vectors. A buffer is created for
+ // every vector in gluDrawUtil.draw() below. Data in every buffer will be tightly
+ // packed. So the stride should be 0. This is different from the code in native
+ // deqp, which use only one buffer for a matrix, the data is interleaved.
+ var stride = 0;
+
+ for (var colNdx = 0; colNdx < numCols; ++colNdx)
+ vertexArrays.push(gluDrawUtil.newFloatColumnVertexArrayBinding(attribName,
+ colNdx,
+ numRows,
+ numValues,
+ stride,
+ glsShaderExecUtil.getColumn(ptr, colNdx, numRows * numValues)));
+ } else
+ DE_ASSERT(false);
+ }
+
+ // Construct framebuffer.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+
+ for (var outNdx = 0; outNdx < this.m_outLocationSymbols.length; ++outNdx) {
+ symbol = this.m_outLocationSymbols[outNdx];
+ var renderbuffer = renderbuffers[outNdx];
+ var format = gluTextureUtil.getInternalFormat(glsShaderExecUtil.getRenderbufferFormatForOutput(symbol.varType, useIntOutputs));
+
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, format, framebufferW, framebufferH);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + outNdx, gl.RENDERBUFFER, renderbuffer);
+ }
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
+
+ var drawBuffers = [];
+ for (var ndx = 0; ndx < this.m_outLocationSymbols.length; ndx++)
+ drawBuffers[ndx] = gl.COLOR_ATTACHMENT0 + ndx;
+ gl.drawBuffers(drawBuffers);
+
+ // Render
+ gl.viewport(0, 0, framebufferW, framebufferH);
+ gluDrawUtil.draw(gl, this.m_program.getProgram(), vertexArrays,
+ new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.POINTS, numValues));
+
+ // Read back pixels.
+
+ // \todo [2013-08-07 pyry] Some fast-paths could be added here.
+
+ for (var outNdx = 0; outNdx < this.m_outputs.length; ++outNdx) {
+ symbol = this.m_outputs[outNdx];
+ /** @type {number} */ var outSize = symbol.varType.getScalarSize();
+ /** @type {number} */ var outVecSize = gluShaderUtil.getDataTypeNumComponents(symbol.varType.getBasicType());
+ /** @type {number} */ var outNumLocs = gluShaderUtil.getDataTypeNumLocations(symbol.varType.getBasicType());
+ var format = glsShaderExecUtil.getRenderbufferFormatForOutput(symbol.varType, useIntOutputs);
+ var readFormat = new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, format.type);
+ var transferFormat = gluTextureUtil.getTransferFormat(readFormat);
+ /** @type {number} */ var outLocation = this.m_outLocationMap[symbol.name];
+ var tmpBuf = new tcuTexture.TextureLevel(readFormat, framebufferW, framebufferH);
+
+ for (var locNdx = 0; locNdx < outNumLocs; ++locNdx) {
+ gl.readBuffer(gl.COLOR_ATTACHMENT0 + outLocation + locNdx);
+ gl.readPixels(0, 0, framebufferW, framebufferH, transferFormat.format, transferFormat.dataType, tmpBuf.getAccess().getDataPtr());
+
+ if (outSize == 4 && outNumLocs == 1) {
+ outputs[outNdx] = new Uint8Array(tmpBuf.getAccess().getBuffer());
+ } else {
+ if (locNdx == 0)
+ outputs[outNdx] = new Uint32Array(numValues * outVecSize);
+ var srcPtr = new Uint32Array(tmpBuf.getAccess().getBuffer());
+ for (var valNdx = 0; valNdx < numValues; valNdx++) {
+ var srcOffset = valNdx * 4;
+ var dstOffset = outSize * valNdx + outVecSize * locNdx;
+ for (var j = 0; j < outVecSize; j++)
+ outputs[outNdx][dstOffset + j] = srcPtr[srcOffset + j];
+ }
+ }
+ }
+ }
+
+ // \todo [2013-08-07 pyry] Clear draw buffers & viewport?
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ return outputs;
+ };
+
+ glsShaderExecUtil.generateLocationMap = function(symbols, locationSymbols) {
+ var ret = [];
+ locationSymbols.length = 0;
+ var location = 0;
+
+ for (var i = 0; i < symbols.length; i++) {
+ var symbol = symbols[i];
+ var numLocations = gluShaderUtil.getDataTypeNumLocations(symbol.varType.getBasicType());
+ ret[symbol.name] = location;
+ location += numLocations;
+
+ for (var ndx = 0; ndx < numLocations; ++ndx)
+ locationSymbols.push(symbol);
+ }
+
+ return ret;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js
new file mode 100644
index 000000000..27f86e055
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js
@@ -0,0 +1,1114 @@
+/*-------------------------------------------------------------------------
+ * 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.glsShaderLibrary');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('modules.shared.glsShaderLibraryCase');
+
+goog.scope(function() {
+
+var glsShaderLibrary = modules.shared.glsShaderLibrary;
+var tcuTestCase = framework.common.tcuTestCase;
+var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+
+ glsShaderLibrary.generateTestCases = function() {
+ /** @type {glsShaderLibrary.Parser} */ var parser = new glsShaderLibrary.Parser();
+ try {
+ /** @type {Object} */ var state = tcuTestCase.runner;
+ var tree = parser.parse(state.testFile);
+ var rootTest = tcuTestCase.newTest(state.testName, 'Top level');
+ rootTest.setChildren(tree);
+ state.setRoot(rootTest);
+ }
+ catch (err) {
+ bufferedLogToConsole(err);
+ testFailed('Failed to parse shader test case file');
+ return false;
+ }
+ return true;
+ };
+
+ glsShaderLibrary.processTestFile = function() {
+ if (glsShaderLibrary.generateTestCases()) {
+ tcuTestCase.runner.runCallback(glsShaderLibraryCase.runTestCases);
+ } else {
+ tcuTestCase.runner.terminate();
+ }
+ };
+
+ glsShaderLibrary.isWhitespace = function(value) {
+ return /^[ \t\r\n]+$/.test(value);
+ };
+ glsShaderLibrary.isEOL = function(value) {
+ return /^[\r\n]+$/.test(value);
+ };
+ glsShaderLibrary.isAlpha = function(value) {
+ return /^[a-zA-Z]$/.test(value);
+ };
+ glsShaderLibrary.isNumeric = function(value) {
+ return /^[0-9]$/.test(value);
+ };
+ glsShaderLibrary.isCaseNameChar = function(value) {
+ return /^[a-zA-Z0-9_\-\.]$/.test(value);
+ };
+
+ /**
+ * Removes however many indents there are on the first line from all lines.
+ * @param {string} str
+ * @return {string} output
+ */
+ glsShaderLibrary.removeExtraIndentation = function(str) {
+ return glsShaderLibrary.removeExtraIndentationArray(
+ str.split(/\r\n|\r|\n/)
+ ).join('\n');
+ };
+
+ /**
+ * Returns an array of strings without indentation.
+ * @param {Array<string>} arr
+ * @return {Array<string>} output
+ */
+ glsShaderLibrary.removeExtraIndentationArray = function(arr) {
+ /** @type {Array<string>} */ var output = [];
+
+ if (arr.length) {
+
+ /** @type {number} */ var numIndentChars = 0;
+ for (var i = 0; i < arr[0].length && glsShaderLibrary.isWhitespace(arr[0].charAt(i)); ++i) {
+ numIndentChars += arr[0].charAt(i) === '\t' ? 4 : 1;
+ }
+
+ for (var i = 0; i < arr.length; ++i) {
+ /** @type {number} */ var removed = 0;
+ /** @type {number} */ var j;
+ // Some tests are indented inconsistently, so we have to check for non-whitespace characters here.
+ for (j = 0; removed < numIndentChars && j < arr[i].length && glsShaderLibrary.isWhitespace(arr[i].charAt(j)); ++j) {
+ removed += (arr[i].charAt(j) === '\t' ? 4 : 1);
+ }
+
+ output.push(arr[i].substr(j, arr[i].length - j));
+ }
+
+ }
+
+ return output;
+ };
+
+ glsShaderLibrary.de_assert = function(condition) {
+ if (!condition) {
+ throw Error();
+ }
+ };
+
+ /**
+ * @param {string} str
+ * @param {string} endstr end of string character
+ * @param {boolean=} trimFront trim leading whitespace
+ * @return {string} str
+ * @private
+ */
+ glsShaderLibrary.parseStringLiteralHelper = function(str, endstr, trimFront) {
+ trimFront = trimFront || false;
+
+ /** @type {number} */ var index_end = 0;
+ // isolate the string
+ do {
+ index_end = str.indexOf(endstr, index_end + 1);
+ } while (index_end >= 0 && str.charAt(index_end - 1) === '\\');
+
+ if (index_end <= 0) {
+ index_end = str.length;
+ }
+
+ // strip quotes, replace \n and \t with nl and tabs respectively
+ str = str.substr(endstr.length, index_end - endstr.length);
+ if (trimFront)
+ str = str.replace(/^\s*\n/, '');
+ var result = '';
+ var i = 0;
+ while (str[i] != undefined) {
+ if (str[i] == '\\') {
+ switch (str[i + 1]) {
+ case undefined:
+ break;
+ case 'n':
+ result += '\n';
+ break;
+ case 't':
+ result += '\t';
+ break;
+ default:
+ result += str[i + 1];
+ break;
+ }
+ i += 2;
+ } else {
+ result += str[i];
+ i++;
+ }
+ }
+ return result;
+
+ };
+
+ /**
+ * glsShaderLibrary.Parser class
+ * @constructor
+ */
+ glsShaderLibrary.Parser = function() {
+
+ /* data members */
+
+ /**
+ * The Token constants
+ * @enum {number}
+ */
+ var Token = {
+ TOKEN_INVALID: 0,
+ TOKEN_EOF: 1,
+ TOKEN_STRING: 2,
+ TOKEN_SHADER_SOURCE: 3,
+
+ TOKEN_INT_LITERAL: 4,
+ TOKEN_FLOAT_LITERAL: 5,
+
+ // identifiers
+ TOKEN_IDENTIFIER: 6,
+ TOKEN_TRUE: 7,
+ TOKEN_FALSE: 8,
+ TOKEN_DESC: 9,
+ TOKEN_EXPECT: 10,
+ TOKEN_GROUP: 11,
+ TOKEN_CASE: 12,
+ TOKEN_END: 13,
+ TOKEN_VALUES: 14,
+ TOKEN_BOTH: 15,
+ TOKEN_VERTEX: 26,
+ TOKEN_FRAGMENT: 17,
+ TOKEN_UNIFORM: 18,
+ TOKEN_INPUT: 19,
+ TOKEN_OUTPUT: 20,
+ TOKEN_FLOAT: 21,
+ TOKEN_FLOAT_VEC2: 22,
+ TOKEN_FLOAT_VEC3: 23,
+ TOKEN_FLOAT_VEC4: 24,
+ TOKEN_FLOAT_MAT2: 25,
+ TOKEN_FLOAT_MAT2X3: 26,
+ TOKEN_FLOAT_MAT2X4: 27,
+ TOKEN_FLOAT_MAT3X2: 28,
+ TOKEN_FLOAT_MAT3: 29,
+ TOKEN_FLOAT_MAT3X4: 30,
+ TOKEN_FLOAT_MAT4X2: 31,
+ TOKEN_FLOAT_MAT4X3: 32,
+ TOKEN_FLOAT_MAT4: 33,
+ TOKEN_INT: 34,
+ TOKEN_INT_VEC2: 35,
+ TOKEN_INT_VEC3: 36,
+ TOKEN_INT_VEC4: 37,
+ TOKEN_UINT: 38,
+ TOKEN_UINT_VEC2: 39,
+ TOKEN_UINT_VEC3: 40,
+ TOKEN_UINT_VEC4: 41,
+ TOKEN_BOOL: 42,
+ TOKEN_BOOL_VEC2: 43,
+ TOKEN_BOOL_VEC3: 44,
+ TOKEN_BOOL_VEC4: 45,
+ TOKEN_VERSION: 46,
+
+ // symbols
+ TOKEN_ASSIGN: 47,
+ TOKEN_PLUS: 48,
+ TOKEN_MINUS: 49,
+ TOKEN_COMMA: 50,
+ TOKEN_VERTICAL_BAR: 51,
+ TOKEN_SEMI_COLON: 52,
+ TOKEN_LEFT_PAREN: 53,
+ TOKEN_RIGHT_PAREN: 54,
+ TOKEN_LEFT_BRACKET: 55,
+ TOKEN_RIGHT_BRACKET: 56,
+ TOKEN_LEFT_BRACE: 57,
+ TOKEN_RIGHT_BRACE: 58,
+
+ TOKEN_LAST: 59
+ };
+
+ /** @type {string} */ var m_input = '';
+ /** @type {number} */ var m_curPtr = 0;
+ /** @type {number} */ var m_curToken;// = Token.TOKEN_INVALID;
+ /** @type {string} */ var m_curTokenStr = '';
+
+ /* function members */
+ this.parse = function(input) {
+
+ // initialise parser
+ m_input = input;
+ m_curPtr = 0;
+ m_curToken = Token.TOKEN_INVALID;
+ m_curTokenStr = '';
+ advanceToken();
+
+ /** @type {Array<tcuTestCase.DeqpTest>} */ var nodeList = [];
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_CASE) {
+ parseShaderCase(nodeList);
+ } else if (m_curToken === Token.TOKEN_GROUP) {
+ parseShaderGroup(nodeList);
+ } else if (m_curToken === Token.TOKEN_EOF) {
+ break;
+ } else {
+ // throw Error("invalid token encountered at main level: '" + m_curTokenStr + "'");
+ testFailed("invalid token encountered at main level: '" + m_curTokenStr + "'");
+ tcuTestCase.runner.terminate();
+ }
+
+ }
+
+ return nodeList;
+
+ };
+
+ /**
+ * ensures that the token exists
+ * otherwise it returns the corresponding token's name depending on enum number value
+ * @param {number} id
+ * @return {string} name
+ */
+ var resolveTokenName = function(id) {
+ for (var name in Token) {
+ if (Token[name] === id) return name;
+ }
+ return 'TOKEN_UNKNOWN';
+ };
+
+ /**
+ * Throws an error which contains the passed string
+ * @param {string} errorStr that contains an error to notify
+ * @return {string} error
+ */
+ var parseError = function(errorStr) {
+ // abort
+ throw 'glsShaderLibrary.Parser error: ' + errorStr + ' near ' + m_input.substr(m_curPtr, m_curPtr + 80);
+ };
+
+ /**
+ * Converts string into float
+ * @param {string} str
+ * @return {number}
+ */
+ var parseFloatLiteral = function(str) {
+ return parseFloat(str);
+ };
+
+ /**
+ * Converts string into integer
+ * @param {string} str
+ * @return {number}
+ */
+ var parseIntLiteral = function(str) {
+ return parseInt(str, 10);
+ };
+ var parseStringLiteral = function(str) {
+ /**
+ * @type {string}
+ * find delimitor
+ */ var endchar = str.substr(0, 1);
+ return glsShaderLibrary.parseStringLiteralHelper(str, endchar);
+ };
+ var parseShaderSource = function(str) {
+ // similar to parse literal, delimitors are two double quotes ("")
+ return glsShaderLibrary.removeExtraIndentation(
+ glsShaderLibrary.parseStringLiteralHelper(str, '""', true)
+ );
+ };
+
+ var advanceTokenWorker = function() {
+
+ // Skip old token
+ m_curPtr += m_curTokenStr.length;
+
+ // Reset token (for safety).
+ m_curToken = Token.TOKEN_INVALID;
+ m_curTokenStr = '';
+
+ // Eat whitespace & comments while they last.
+ for (;;) {
+
+ while (glsShaderLibrary.isWhitespace(m_input.charAt(m_curPtr))) ++m_curPtr;
+
+ // check for EOL comment
+ if (m_input.charAt(m_curPtr) === '#') {
+ // if m_input is to be an array of lines then this probably wont work very well
+ while (
+ m_curPtr < m_input.length &&
+ !glsShaderLibrary.isEOL(m_input.charAt(m_curPtr))
+ ) ++m_curPtr;
+ } else {
+ break;
+ }
+
+ }
+
+ if (m_curPtr >= m_input.length) {
+
+ m_curToken = Token.TOKEN_EOF;
+ m_curTokenStr = '<EOF>';
+
+ } else if (glsShaderLibrary.isAlpha(m_input.charAt(m_curPtr))) {
+
+ /** @type {number} */ var end = m_curPtr + 1;
+ while (glsShaderLibrary.isCaseNameChar(m_input.charAt(end))) ++end;
+
+ m_curTokenStr = m_input.substr(m_curPtr, end - m_curPtr);
+
+ m_curToken = (function() {
+ // consider reimplementing with a binary search
+ switch (m_curTokenStr) {
+ case 'true': return Token.TOKEN_TRUE;
+ case 'false': return Token.TOKEN_FALSE;
+ case 'desc': return Token.TOKEN_DESC;
+ case 'expect': return Token.TOKEN_EXPECT;
+ case 'group': return Token.TOKEN_GROUP;
+ case 'case': return Token.TOKEN_CASE;
+ case 'end': return Token.TOKEN_END;
+ case 'values': return Token.TOKEN_VALUES;
+ case 'both': return Token.TOKEN_BOTH;
+ case 'vertex': return Token.TOKEN_VERTEX;
+ case 'fragment': return Token.TOKEN_FRAGMENT;
+ case 'uniform': return Token.TOKEN_UNIFORM;
+ case 'input': return Token.TOKEN_INPUT;
+ case 'output': return Token.TOKEN_OUTPUT;
+ case 'float': return Token.TOKEN_FLOAT;
+ case 'vec2': return Token.TOKEN_FLOAT_VEC2;
+ case 'vec3': return Token.TOKEN_FLOAT_VEC3;
+ case 'vec4': return Token.TOKEN_FLOAT_VEC4;
+ case 'mat2': return Token.TOKEN_FLOAT_MAT2;
+ case 'mat2x3': return Token.TOKEN_FLOAT_MAT2X3;
+ case 'mat2x4': return Token.TOKEN_FLOAT_MAT2X4;
+ case 'mat3x2': return Token.TOKEN_FLOAT_MAT3X2;
+ case 'mat3': return Token.TOKEN_FLOAT_MAT3;
+ case 'mat3x4': return Token.TOKEN_FLOAT_MAT3X4;
+ case 'mat4x2': return Token.TOKEN_FLOAT_MAT4X2;
+ case 'mat4x3': return Token.TOKEN_FLOAT_MAT4X3;
+ case 'mat4': return Token.TOKEN_FLOAT_MAT4;
+ case 'int': return Token.TOKEN_INT;
+ case 'ivec2': return Token.TOKEN_INT_VEC2;
+ case 'ivec3': return Token.TOKEN_INT_VEC3;
+ case 'ivec4': return Token.TOKEN_INT_VEC4;
+ case 'uint': return Token.TOKEN_UINT;
+ case 'uvec2': return Token.TOKEN_UINT_VEC2;
+ case 'uvec3': return Token.TOKEN_UINT_VEC3;
+ case 'uvec4': return Token.TOKEN_UINT_VEC4;
+ case 'bool': return Token.TOKEN_BOOL;
+ case 'bvec2': return Token.TOKEN_BOOL_VEC2;
+ case 'bvec3': return Token.TOKEN_BOOL_VEC3;
+ case 'bvec4': return Token.TOKEN_BOOL_VEC4;
+ case 'version': return Token.TOKEN_VERSION;
+ default: return Token.TOKEN_IDENTIFIER;
+ }
+ }());
+
+ } else if (glsShaderLibrary.isNumeric(m_input.charAt(m_curPtr))) {
+
+ /** @type {number} */ var p = m_curPtr;
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ if (m_input.charAt(p) === '.') { // float
+
+ ++p;
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ if (m_input.charAt(p) === 'e' || m_input.charAt(p) === 'E') {
+
+ ++p;
+ if (m_input.charAt(p) === '+' || m_input.charAt(p) === '-') ++p;
+
+ glsShaderLibrary.de_assert(p < m_input.length && glsShaderLibrary.isNumeric(m_input.charAt(p)));
+ while (glsShaderLibrary.isNumeric(m_input.charAt(p))) ++p;
+
+ }
+
+ m_curToken = Token.TOKEN_FLOAT_LITERAL;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else {
+
+ m_curToken = Token.TOKEN_INT_LITERAL;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ }
+
+ } else if (m_input.charAt(m_curPtr) === '"' && m_input.charAt(m_curPtr + 1) === '"') { // shader source
+
+ var p = m_curPtr + 2;
+
+ while (m_input.charAt(p) != '"' || m_input.charAt(p + 1) != '"') {
+ glsShaderLibrary.de_assert(p < m_input.length);
+ if (m_input.charAt(p) === '\\') {
+ glsShaderLibrary.de_assert(p + 1 < m_input.length);
+ p += 2;
+ } else {
+ ++p;
+ }
+ }
+ p += 2;
+
+ m_curToken = Token.TOKEN_SHADER_SOURCE;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else if (m_input.charAt(m_curPtr) === '"' || m_input.charAt(m_curPtr) === "'") {
+
+ /** @type {string} */ var delimitor = m_input.charAt(m_curPtr);
+ var p = m_curPtr + 1;
+
+ while (m_input.charAt(p) != delimitor) {
+
+ glsShaderLibrary.de_assert(p < m_input.length);
+ if (m_input.charAt(p) === '\\') {
+ glsShaderLibrary.de_assert(p + 1 < m_input.length);
+ p += 2;
+ } else {
+ ++p;
+ }
+
+ }
+ ++p;
+
+ m_curToken = Token.TOKEN_STRING;
+ m_curTokenStr = m_input.substr(m_curPtr, p - m_curPtr);
+
+ } else {
+
+ m_curTokenStr = m_input.charAt(m_curPtr);
+ m_curToken = (function() {
+ // consider reimplementing with a binary search
+ switch (m_curTokenStr) {
+ case '=': return Token.TOKEN_ASSIGN;
+ case '+': return Token.TOKEN_PLUS;
+ case '-': return Token.TOKEN_MINUS;
+ case ',': return Token.TOKEN_COMMA;
+ case '|': return Token.TOKEN_VERTICAL_BAR;
+ case ';': return Token.TOKEN_SEMI_COLON;
+ case '(': return Token.TOKEN_LEFT_PAREN;
+ case ')': return Token.TOKEN_RIGHT_PAREN;
+ case '[': return Token.TOKEN_LEFT_BRACKET;
+ case ']': return Token.TOKEN_RIGHT_BRACKET;
+ case '{': return Token.TOKEN_LEFT_BRACE;
+ case '}': return Token.TOKEN_RIGHT_BRACE;
+
+ default: return Token.TOKEN_INVALID;
+ }
+ }());
+
+ }
+
+ };
+
+ /**
+ * @return {Object.<number, string, string>}
+ */
+ var advanceTokenTester = function(input, current_index) {
+ m_input = input;
+ m_curPtr = current_index;
+ m_curTokenStr = '';
+ advanceTokenWorker();
+ return {
+ /** @type {number} */ idType: m_curToken,
+ /** @type {string} */ name: resolveTokenName(m_curToken),
+ /** @type {string} */ value: m_curTokenStr
+ };
+ };
+
+ /**
+ * @param {Token=} tokenAssumed
+ */
+ var advanceToken = function(tokenAssumed) {
+ if (typeof(tokenAssumed) !== 'undefined') {
+ assumeToken(tokenAssumed);
+ }
+ advanceTokenWorker();
+ };
+ var assumeToken = function(token) {
+
+ if (m_curToken != token) {
+ // parse error
+ /** @type {string} */ var msg = "unexpected token '" + m_curTokenStr + "', expecting '" + getTokenName(token) + "'";
+ throw Error('Parse Error. ' + msg + ' near ' + m_curPtr + ' ...');
+ }
+ };
+ var mapDataTypeToken = function(token) {
+ switch (token) {
+ case Token.TOKEN_FLOAT: return gluShaderUtil.DataType.FLOAT;
+ case Token.TOKEN_FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT_VEC2;
+ case Token.TOKEN_FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT_VEC3;
+ case Token.TOKEN_FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT_VEC4;
+ case Token.TOKEN_FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT_MAT2;
+ case Token.TOKEN_FLOAT_MAT2X3: return gluShaderUtil.DataType.FLOAT_MAT2X3;
+ case Token.TOKEN_FLOAT_MAT2X4: return gluShaderUtil.DataType.FLOAT_MAT2X4;
+ case Token.TOKEN_FLOAT_MAT3X2: return gluShaderUtil.DataType.FLOAT_MAT3X2;
+ case Token.TOKEN_FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT_MAT3;
+ case Token.TOKEN_FLOAT_MAT3X4: return gluShaderUtil.DataType.FLOAT_MAT3X4;
+ case Token.TOKEN_FLOAT_MAT4X2: return gluShaderUtil.DataType.FLOAT_MAT4X2;
+ case Token.TOKEN_FLOAT_MAT4X3: return gluShaderUtil.DataType.FLOAT_MAT4X3;
+ case Token.TOKEN_FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT_MAT4;
+ case Token.TOKEN_INT: return gluShaderUtil.DataType.INT;
+ case Token.TOKEN_INT_VEC2: return gluShaderUtil.DataType.INT_VEC2;
+ case Token.TOKEN_INT_VEC3: return gluShaderUtil.DataType.INT_VEC3;
+ case Token.TOKEN_INT_VEC4: return gluShaderUtil.DataType.INT_VEC4;
+ case Token.TOKEN_UINT: return gluShaderUtil.DataType.UINT;
+ case Token.TOKEN_UINT_VEC2: return gluShaderUtil.DataType.UINT_VEC2;
+ case Token.TOKEN_UINT_VEC3: return gluShaderUtil.DataType.UINT_VEC3;
+ case Token.TOKEN_UINT_VEC4: return gluShaderUtil.DataType.UINT_VEC4;
+ case Token.TOKEN_BOOL: return gluShaderUtil.DataType.BOOL;
+ case Token.TOKEN_BOOL_VEC2: return gluShaderUtil.DataType.BOOL_VEC2;
+ case Token.TOKEN_BOOL_VEC3: return gluShaderUtil.DataType.BOOL_VEC3;
+ case Token.TOKEN_BOOL_VEC4: return gluShaderUtil.DataType.BOOL_VEC4;
+ default: return gluShaderUtil.DataType.INVALID;
+ }
+ };
+
+ /**
+ * Returns the corresponding token's name depending on enum number value
+ * @param {number} token
+ * @return {string}
+ */
+ var getTokenName = function(token) {
+ switch (token) {
+ case Token.TOKEN_INVALID: return '<invalid>';
+ case Token.TOKEN_EOF: return '<eof>';
+ case Token.TOKEN_STRING: return '<string>';
+ case Token.TOKEN_SHADER_SOURCE: return 'source';
+
+ case Token.TOKEN_INT_LITERAL: return '<int>';
+ case Token.TOKEN_FLOAT_LITERAL: return '<float>';
+
+ // identifiers
+ case Token.TOKEN_IDENTIFIER: return '<identifier>';
+ case Token.TOKEN_TRUE: return 'true';
+ case Token.TOKEN_FALSE: return 'false';
+ case Token.TOKEN_DESC: return 'desc';
+ case Token.TOKEN_EXPECT: return 'expect';
+ case Token.TOKEN_GROUP: return 'group';
+ case Token.TOKEN_CASE: return 'case';
+ case Token.TOKEN_END: return 'end';
+ case Token.TOKEN_VALUES: return 'values';
+ case Token.TOKEN_BOTH: return 'both';
+ case Token.TOKEN_VERTEX: return 'vertex';
+ case Token.TOKEN_FRAGMENT: return 'fragment';
+ case Token.TOKEN_UNIFORM: return 'uniform';
+ case Token.TOKEN_INPUT: return 'input';
+ case Token.TOKEN_OUTPUT: return 'output';
+ case Token.TOKEN_FLOAT: return 'float';
+ case Token.TOKEN_FLOAT_VEC2: return 'vec2';
+ case Token.TOKEN_FLOAT_VEC3: return 'vec3';
+ case Token.TOKEN_FLOAT_VEC4: return 'vec4';
+ case Token.TOKEN_FLOAT_MAT2: return 'mat2';
+ case Token.TOKEN_FLOAT_MAT2X3: return 'mat2x3';
+ case Token.TOKEN_FLOAT_MAT2X4: return 'mat2x4';
+ case Token.TOKEN_FLOAT_MAT3X2: return 'mat3x2';
+ case Token.TOKEN_FLOAT_MAT3: return 'mat3';
+ case Token.TOKEN_FLOAT_MAT3X4: return 'mat3x4';
+ case Token.TOKEN_FLOAT_MAT4X2: return 'mat4x2';
+ case Token.TOKEN_FLOAT_MAT4X3: return 'mat4x3';
+ case Token.TOKEN_FLOAT_MAT4: return 'mat4';
+ case Token.TOKEN_INT: return 'int';
+ case Token.TOKEN_INT_VEC2: return 'ivec2';
+ case Token.TOKEN_INT_VEC3: return 'ivec3';
+ case Token.TOKEN_INT_VEC4: return 'ivec4';
+ case Token.TOKEN_UINT: return 'uint';
+ case Token.TOKEN_UINT_VEC2: return 'uvec2';
+ case Token.TOKEN_UINT_VEC3: return 'uvec3';
+ case Token.TOKEN_UINT_VEC4: return 'uvec4';
+ case Token.TOKEN_BOOL: return 'bool';
+ case Token.TOKEN_BOOL_VEC2: return 'bvec2';
+ case Token.TOKEN_BOOL_VEC3: return 'bvec3';
+ case Token.TOKEN_BOOL_VEC4: return 'bvec4';
+
+ case Token.TOKEN_ASSIGN: return '=';
+ case Token.TOKEN_PLUS: return '+';
+ case Token.TOKEN_MINUS: return '-';
+ case Token.TOKEN_COMMA: return ',';
+ case Token.TOKEN_VERTICAL_BAR: return '|';
+ case Token.TOKEN_SEMI_COLON: return ';';
+ case Token.TOKEN_LEFT_PAREN: return '(';
+ case Token.TOKEN_RIGHT_PAREN: return ')';
+ case Token.TOKEN_LEFT_BRACKET: return '[';
+ case Token.TOKEN_RIGHT_BRACKET: return ']';
+ case Token.TOKEN_LEFT_BRACE: return ' {';
+ case Token.TOKEN_RIGHT_BRACE: return '}';
+
+ default: return '<unknown>';
+ }
+ };
+
+ /**
+ * @param {?gluShaderUtil.DataType} expectedDataType
+ * @param {Object} result
+ */
+ var parseValueElement = function(expectedDataType, result) {
+ /** @type {?string} */ var scalarType = null;
+ /** @type {number} */ var scalarSize = 0;
+ if (expectedDataType) {
+ scalarType = gluShaderUtil.getDataTypeScalarType(expectedDataType);
+ scalarSize = gluShaderUtil.getDataTypeScalarSize(expectedDataType);
+ }
+
+ /** @type {Array<number>} */ var elems = [];
+
+ if (scalarSize > 1) {
+ glsShaderLibrary.de_assert(mapDataTypeToken(m_curToken) === expectedDataType);
+ advanceToken(); // data type(float, vec2, etc.)
+ advanceToken(Token.TOKEN_LEFT_PAREN);
+ }
+
+ for (var i = 0; i < scalarSize; ++i) {
+ if (scalarType === 'float') {
+
+ /** @type {number} */ var signMult = 1.0;
+ if (m_curToken === Token.TOKEN_MINUS) {
+ signMult = -1.0;
+ advanceToken();
+ }
+
+ assumeToken(Token.TOKEN_FLOAT_LITERAL);
+ elems.push(signMult * parseFloatLiteral(m_curTokenStr));
+ advanceToken(Token.TOKEN_FLOAT_LITERAL);
+
+ } else if (scalarType === 'int' || scalarType === 'uint') {
+
+ var signMult = 1;
+ if (m_curToken === Token.TOKEN_MINUS) {
+ signMult = -1;
+ advanceToken();
+ }
+
+ assumeToken(Token.TOKEN_INT_LITERAL);
+ elems.push(signMult * parseIntLiteral(m_curTokenStr));
+ advanceToken(Token.TOKEN_INT_LITERAL);
+
+ } else {
+
+ glsShaderLibrary.de_assert(scalarType === 'bool');
+ elems.push(m_curToken === Token.TOKEN_TRUE);
+ if (m_curToken != Token.TOKEN_TRUE && m_curToken != Token.TOKEN_FALSE) {
+ throw Error('unexpected token, expecting bool: ' + m_curTokenStr);
+ }
+ advanceToken(); // true/false
+
+ }
+
+ if (i != (scalarSize - 1)) {
+ advanceToken(Token.TOKEN_COMMA);
+ }
+ }
+
+ if (scalarSize > 1) {
+ advanceToken(Token.TOKEN_RIGHT_PAREN);
+ }
+
+ for (var i = 0; i < elems.length; i++)
+ result.elements.push(elems[i]);
+
+ };
+
+ /**
+ * @param {Object.<Array, number>} valueBlock
+ */
+ var parseValue = function(valueBlock) {
+
+ /**
+ * @type {Object}
+ */
+ var result = {
+ /** @type {?gluShaderUtil.DataType} */ dataType: null,
+ /** @type {?glsShaderLibraryCase.shaderCase} */ storageType: null,
+ /** @type {?string} */ valueName: null,
+ /** @type {Array} */ elements: []
+ };
+
+ // parse storage
+ switch (m_curToken) {
+ case Token.TOKEN_UNIFORM:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_UNIFORM;
+ break;
+ case Token.TOKEN_INPUT:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_INPUT;
+ break;
+ case Token.TOKEN_OUTPUT:
+ result.storageType = glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT;
+ break;
+ default:
+ throw Error('unexpected token encountered when parsing value classifier');
+ break;
+ }
+ advanceToken();
+
+ // parse data type
+ result.dataType = mapDataTypeToken(m_curToken);
+ if (result.dataType === gluShaderUtil.DataType.INVALID) {
+ throw Error('unexpected token when parsing value data type: ' + m_curTokenStr);
+ }
+ advanceToken();
+
+ // parse value name
+ if (m_curToken === Token.TOKEN_IDENTIFIER) {
+ result.valueName = m_curTokenStr;
+ } else if (m_curToken === Token.TOKEN_STRING) {
+ result.valueName = parseStringLiteral(m_curTokenStr);
+ } else {
+ throw Error('unexpected token when parsing value name: ' + m_curTokenStr);
+ }
+ advanceToken();
+
+ // parse assignment operator.
+ advanceToken(Token.TOKEN_ASSIGN);
+
+ // parse actual value
+ if (m_curToken === Token.TOKEN_LEFT_BRACKET) { // value list
+ advanceToken(Token.TOKEN_LEFT_BRACKET);
+ result.arrayLength = 0;
+
+ for (;;) {
+ parseValueElement(result.dataType, result);
+ result.arrayLength += 1;
+
+ if (m_curToken === Token.TOKEN_RIGHT_BRACKET) {
+ break;
+ } else if (m_curToken === Token.TOKEN_VERTICAL_BAR) { // pipe?
+ advanceToken();
+ continue;
+ } else {
+ throw Error('unexpected token in value element array: ' + m_curTokenStr);
+ }
+ }
+
+ advanceToken(Token.TOKEN_RIGHT_BRACKET);
+
+ } else { // arrays, single elements
+ parseValueElement(result.dataType, result);
+ result.arrayLength = 1;
+ }
+
+ advanceToken(Token.TOKEN_SEMI_COLON);
+
+ valueBlock.values.push(result);
+
+ };
+
+ /**
+ * @param {Object.<Array, number>} valueBlock
+ */
+ var parseValueBlock = function(valueBlock) {
+
+ advanceToken(Token.TOKEN_VALUES);
+ advanceToken(Token.TOKEN_LEFT_BRACE);
+
+ for (;;) {
+ if (
+ m_curToken === Token.TOKEN_UNIFORM ||
+ m_curToken === Token.TOKEN_INPUT ||
+ m_curToken === Token.TOKEN_OUTPUT
+ ) {
+ parseValue(valueBlock);
+ } else if (m_curToken === Token.TOKEN_RIGHT_BRACE) {
+ break;
+ } else {
+ throw Error('unexpected( token when parsing a value block: ' + m_curTokenStr);
+ }
+ }
+
+ advanceToken(Token.TOKEN_RIGHT_BRACE);
+
+ /** @type {number} */ var arrayLength = 1;
+ // compute combined array length of value block.
+ for (var i = 0; i < valueBlock.values.length; ++i) {
+ if (valueBlock.values[i].arrayLength > 1) {
+ glsShaderLibrary.de_assert(arrayLength === 1 || arrayLength === valueBlock.values[i].arrayLength);
+ arrayLength = valueBlock.values[i].arrayLength;
+ }
+ }
+
+ valueBlock.arrayLength = arrayLength;
+
+ };
+
+ /**
+ * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
+ */
+ var parseShaderCase = function(shaderNodeList) {
+
+ // parse case
+ advanceToken(Token.TOKEN_CASE);
+
+ /**
+ * @type {string}
+ * parse case name
+ */
+ var caseName = m_curTokenStr;
+ advanceToken(); // \note [pyry] All token types are allowed here.
+
+ /**
+ * @type {Array<Object>}
+ * setup case
+ */
+ var valueBlockList = [];
+
+ /** TODO: Should the default version be defined elsewhere? */
+ /** @type {string} */ var version = '100';
+ /** @type {number} */ var expectResult = glsShaderLibraryCase.expectResult.EXPECT_PASS;
+ /** @type {string} */ var description;
+ /** @type {string} */ var bothSource = '';
+ /** @type {string} */ var vertexSource = '';
+ /** @type {string} */ var fragmentSource = '';
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_END) {
+
+ break;
+
+ } else if (m_curToken === Token.TOKEN_DESC) {
+
+ advanceToken();
+ assumeToken(Token.TOKEN_STRING);
+
+ description = parseStringLiteral(m_curTokenStr);
+ advanceToken();
+
+ } else if (m_curToken === Token.TOKEN_EXPECT) {
+
+ advanceToken();
+ assumeToken(Token.TOKEN_IDENTIFIER);
+
+ expectResult = (function(token) {
+ switch (token) {
+ case 'pass': return glsShaderLibraryCase.expectResult.EXPECT_PASS;
+ case 'compile_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_FAIL;
+ case 'link_fail': return glsShaderLibraryCase.expectResult.EXPECT_LINK_FAIL;
+ case 'compile_or_link_fail': return glsShaderLibraryCase.expectResult.EXPECT_COMPILE_LINK_FAIL;
+ case 'build_successful': return glsShaderLibraryCase.expectResult.EXPECT_BUILD_SUCCESSFUL;
+ default:
+ throw Error('invalid expected result value: ' + m_curTokenStr);
+ }
+ }(m_curTokenStr));
+
+ advanceToken();
+
+ } else if (m_curToken === Token.TOKEN_VALUES) {
+
+ /** @type {Object.<Array, number>} */ var block = glsShaderLibraryCase.genValueBlock();
+ parseValueBlock(block);
+ valueBlockList.push(block);
+
+ } else if (
+ m_curToken === Token.TOKEN_BOTH ||
+ m_curToken === Token.TOKEN_VERTEX ||
+ m_curToken === Token.TOKEN_FRAGMENT
+ ) {
+
+ /** @type {number} */ var token = m_curToken;
+ advanceToken();
+ assumeToken(Token.TOKEN_SHADER_SOURCE);
+ /** @type {string} */ var source = parseShaderSource(m_curTokenStr);
+
+ advanceToken();
+ switch (token) {
+ case Token.TOKEN_BOTH: bothSource = source; break;
+ case Token.TOKEN_VERTEX: vertexSource = source; break;
+ case Token.TOKEN_FRAGMENT: fragmentSource = source; break;
+ default: glsShaderLibrary.de_assert(false); break;
+ }
+
+ } else if (m_curToken === Token.TOKEN_VERSION) {
+
+ advanceToken();
+
+ /** @type {number} */ var versionNum = 0;
+ /** @type {string} */ var postfix = '';
+
+ assumeToken(Token.TOKEN_INT_LITERAL);
+ versionNum = parseIntLiteral(m_curTokenStr);
+ advanceToken();
+
+ if (m_curToken === Token.TOKEN_IDENTIFIER) {
+ postfix = m_curTokenStr;
+ advanceToken();
+ }
+
+ // TODO: need to fix these constants, we dont have glu
+ if (versionNum === 100 && postfix === 'es') version = '100';
+ else if (versionNum === 300 && postfix === 'es') version = '300 es';
+ else if (versionNum === 310 && postfix === 'es') version = '310 es';
+ else if (versionNum === 130) version = '130';
+ else if (versionNum === 140) version = '140';
+ else if (versionNum === 150) version = '150';
+ else if (versionNum === 330) version = '330';
+ else if (versionNum === 400) version = '400';
+ else if (versionNum === 410) version = '410';
+ else if (versionNum === 420) version = '420';
+ else if (versionNum === 430) version = '430';
+ else if (versionNum === 440) version = '440';
+ else if (versionNum === 450) version = '450';
+ else {
+ throw Error('Unknown GLSL version');
+ }
+
+ } else {
+ throw Error('unexpected token while parsing shader case: ' + m_curTokenStr);
+ }
+
+ }
+
+ advanceToken(Token.TOKEN_END); // case end
+
+ /**
+ * no ShaderCase yet?
+ * @param {?string} vert
+ * @param {?string} frag
+ * @param {glsShaderLibraryCase.caseType} type
+ * @return {Object}
+ */
+ var getShaderSpec = function(vert, frag, type) {
+ return {
+ /** @type {glsShaderLibraryCase.expectResult} */ expectResult: expectResult,
+ /** @type {glsShaderLibraryCase.caseType} */ caseType: type,
+ /** @type {Array<Object>} */ valueBlockList: valueBlockList,
+ /** @type {string} */ targetVersion: version,
+ /** @type {?string} */ vertexSource: vert,
+ /** @type {?string} */ fragmentSource: frag
+ };
+ };
+ getShaderSpec.bind(this);
+
+ if (bothSource.length) {
+
+ glsShaderLibrary.de_assert(!vertexSource);
+ glsShaderLibrary.de_assert(!fragmentSource);
+
+ shaderNodeList.push(tcuTestCase.newTest(caseName + '_vertex', description, getShaderSpec(bothSource, null,
+ glsShaderLibraryCase.caseType.CASETYPE_VERTEX_ONLY)));
+ shaderNodeList.push(tcuTestCase.newTest(caseName + '_fragment', description, getShaderSpec(null, bothSource,
+ glsShaderLibraryCase.caseType.CASETYPE_FRAGMENT_ONLY)));
+
+ } else {
+ glsShaderLibrary.de_assert(vertexSource);
+ glsShaderLibrary.de_assert(fragmentSource);
+
+ shaderNodeList.push(tcuTestCase.newTest(caseName, description, getShaderSpec(vertexSource, fragmentSource,
+ glsShaderLibraryCase.caseType.CASETYPE_COMPLETE)));
+ }
+ };
+
+ /**
+ * @param {Array<tcuTestCase.DeqpTest>} shaderNodeList
+ */
+ var parseShaderGroup = function(shaderNodeList) {
+
+ // parse 'case'
+ advanceToken(Token.TOKEN_GROUP);
+
+ /** @type {string}
+ * parse case name
+ */ var name = m_curTokenStr;
+ advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
+
+ // Parse description.
+ assumeToken(Token.TOKEN_STRING);
+ /** @type {string} */ var description = parseStringLiteral(m_curTokenStr);
+ advanceToken(Token.TOKEN_STRING);
+
+ /** @type {Array<tcuTestCase.DeqpTest>} */ var children = [];
+
+ for (;;) {
+
+ if (m_curToken === Token.TOKEN_END) {
+ break;
+ } else if (m_curToken === Token.TOKEN_GROUP) {
+ parseShaderGroup(children);
+ } else if (m_curToken === Token.TOKEN_CASE) {
+ parseShaderCase(children);
+ } else {
+ testFailed('unexpected token while parsing shader group: ' + m_curTokenStr);
+ tcuTestCase.runner.terminate();
+ }
+
+ }
+
+ advanceToken(Token.TOKEN_END); // group end
+
+ /** @type {tcuTestCase.DeqpTest} */ var groupNode = tcuTestCase.newTest(name, description, null);
+ groupNode.setChildren(children);
+
+ shaderNodeList.push(groupNode);
+
+ };
+
+ // uncomment to expose private functions
+ (function(obj) {
+ obj.priv = {
+ m_curPtr: m_curPtr,
+
+ parseError: parseError,
+ parseFloatLiteral: parseFloatLiteral,
+ parseIntLiteral: parseIntLiteral,
+ parseStringLiteral: parseStringLiteral,
+ parseShaderSource: parseShaderSource,
+ advanceTokenTester: advanceTokenTester,
+ assumeToken: assumeToken,
+ mapDataTypeToken: mapDataTypeToken,
+ getTokenName: getTokenName,
+
+ Token: Token,
+
+ parseValueElement: parseValueElement,
+ parseValue: parseValue,
+ parseValueBlock: parseValueBlock,
+ parseShaderCase: parseShaderCase,
+ parseShaderGroup: parseShaderGroup,
+
+ none: false
+ };
+ }(this));
+ //*/
+ };
+
+/**
+ * Parse the test file and execute the test cases
+ * @param {string} testName Name of the test file (without extension)
+ * @param {string} filter Optional filter. Common substring of the names of the tests that should be glsShaderLibrary.run.
+ */
+glsShaderLibrary.run = function(testName, filter) {
+ WebGLTestUtils.loadTextFileAsync(testName + '.test', function(success, content) {
+ if (success) {
+ tcuTestCase.runner.testFile = content;
+ tcuTestCase.runner.testName = testName;
+ tcuTestCase.runner.runCallback(glsShaderLibrary.processTestFile);
+ } else {
+ testFailed('Failed to load test file: ' + testName);
+ tcuTestCase.runner.terminate();
+ }
+ });
+};
+
+});
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 000000000..fa9666de5
--- /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
+ };
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderRenderCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderRenderCase.js
new file mode 100644
index 000000000..31f59de1f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderRenderCase.js
@@ -0,0 +1,1200 @@
+/*-------------------------------------------------------------------------
+ * 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.glsShaderRenderCase');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuMatrix');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluTexture');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.opengl.gluShaderProgram');
+
+goog.scope(function() {
+ var glsShaderRenderCase = modules.shared.glsShaderRenderCase;
+
+ var deMath = framework.delibs.debase.deMath;
+ var deString = framework.delibs.debase.deString;
+ var deRandom = framework.delibs.debase.deRandom;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var gluTexture = framework.opengl.gluTexture;
+ var gluDrawUtil = framework.opengl.gluDrawUtil;
+ var tcuImageCompare = framework.common.tcuImageCompare;
+ var tcuTexture = framework.common.tcuTexture;
+ var tcuMatrix = framework.common.tcuMatrix;
+ var tcuRGBA = framework.common.tcuRGBA;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuSurface = framework.common.tcuSurface;
+ var gluShaderProgram = framework.opengl.gluShaderProgram;
+
+ /** @typedef {function(glsShaderRenderCase.ShaderEvalContext)} */ glsShaderRenderCase.ShaderEvalFunc;
+
+ /** @const {number} */ glsShaderRenderCase.GRID_SIZE = 64;
+ /** @const {number} */ glsShaderRenderCase.MAX_RENDER_WIDTH = 128;
+ /** @const {number} */ glsShaderRenderCase.MAX_RENDER_HEIGHT = 112;
+ /** @const {Array<number>} */ glsShaderRenderCase.DEFAULT_CLEAR_COLOR = [0.125, 0.25, 0.5, 1.0];
+ /** @const {number} */ glsShaderRenderCase.MAX_USER_ATTRIBS = 4;
+ /** @const {number} */ glsShaderRenderCase.MAX_TEXTURES = 4;
+
+ /**
+ * @param {Array<number>} a
+ * @return {tcuRGBA.RGBA}
+ */
+ glsShaderRenderCase.toRGBA = function(a) {
+ return tcuRGBA.newRGBAComponents(
+ deMath.clamp(Math.round(a[0] * 255.0), 0, 255),
+ deMath.clamp(Math.round(a[1] * 255.0), 0, 255),
+ deMath.clamp(Math.round(a[2] * 255.0), 0, 255),
+ deMath.clamp(Math.round(a[3] * 255.0), 0, 255));
+ };
+
+ /**
+ * Helper function
+ * @param {?(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} tex
+ * @return {gluTexture.Type}
+ */
+ glsShaderRenderCase.getTextureType = function(tex) {
+ if (tex === null || tex.getType() <= 0)
+ return gluTexture.Type.TYPE_NONE;
+ else
+ return tex.getType();
+ };
+
+ /**
+ * @constructor
+ * @param {number=} indent
+ */
+ glsShaderRenderCase.LineStream = function(indent) {
+ indent = indent === undefined ? 0 : indent;
+ /** @type {number} */ this.m_indent = indent;
+ /** @type {string} */ this.m_stream;
+ /** @type {string} */ this.m_string;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsShaderRenderCase.LineStream.prototype.str = function() {
+ this.m_string = this.m_stream;
+ return this.m_string;
+ };
+
+ /**
+ * @constructor
+ * @param {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)=} tex
+ * @param {tcuTexture.Sampler=} sampler
+ */
+ glsShaderRenderCase.TextureBinding = function(tex, sampler) {
+ tex = tex === undefined ? null : tex;
+ sampler = sampler === undefined ? null : sampler;
+ /** @type {gluTexture.Type} */ this.m_type = glsShaderRenderCase.getTextureType(tex);
+ /** @type {tcuTexture.Sampler} */ this.m_sampler = sampler;
+ /** @type {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} */
+ this.m_binding = tex;
+ };
+
+ /**
+ * @param {tcuTexture.Sampler} sampler
+ */
+ glsShaderRenderCase.TextureBinding.prototype.setSampler = function(sampler) {
+ this.m_sampler = sampler;
+ };
+
+ /**
+ * @param {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} tex
+ */
+ glsShaderRenderCase.TextureBinding.prototype.setTexture = function(tex) {
+ this.m_type = glsShaderRenderCase.getTextureType(tex);
+ this.m_binding = tex;
+ };
+
+ /** @return {gluTexture.Type} */
+ glsShaderRenderCase.TextureBinding.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /** @return {tcuTexture.Sampler} */
+ glsShaderRenderCase.TextureBinding.prototype.getSampler = function() {
+ return this.m_sampler;
+ };
+
+ /** @return {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} */
+ glsShaderRenderCase.TextureBinding.prototype.getBinding = function() {
+ return this.m_binding;
+ };
+
+ /**
+ * @constructor
+ * @param {number} gridSize
+ * @param {number} width
+ * @param {number} height
+ * @param {Array<number>} constCoords
+ * @param {Array<tcuMatrix.Matrix>} userAttribTransforms
+ * @param {Array<glsShaderRenderCase.TextureBinding>} textures
+ */
+ glsShaderRenderCase.QuadGrid = function(gridSize, width, height, constCoords, userAttribTransforms, textures) {
+ /** @type {number} */ this.m_gridSize = gridSize;
+ /** @type {number} */ this.m_numVertices = (gridSize + 1) * (gridSize + 1);
+ /** @type {number} */ this.m_numTriangles = (gridSize * gridSize *2);
+ /** @type {Array<number>} */ this.m_constCoords = constCoords;
+ /** @type {Array<tcuMatrix.Matrix>} */ this.m_userAttribTransforms = userAttribTransforms;
+ /** @type {Array<glsShaderRenderCase.TextureBinding>} */ this.m_textures = textures;
+ /** @type {Array<Array<number>>} */ this.m_screenPos = [];
+ /** @type {Array<Array<number>>} */ this.m_positions = [];
+ /** @type {Array<Array<number>>} */ this.m_coords = []; //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
+ /** @type {Array<Array<number>>} */ this.m_unitCoords = []; //!< Positive-only coordinates [0.0 .. 1.5].
+ /** @type {Array<number>} */ this.m_attribOne = [];
+ /** @type {Array<Array<number>>} */ this.m_userAttribs = [];
+ for (var attribNdx = 0; attribNdx < this.getNumUserAttribs(); attribNdx++)
+ this.m_userAttribs[attribNdx] = [];
+ /** @type {Array<number>} */ this.m_indices = [];
+
+ /** @type Array<number>} */ var viewportScale = [width, height, 0, 0];
+ for (var y = 0; y < gridSize + 1; y++)
+ for (var x = 0; x < gridSize + 1; x++) {
+ /** @type {number} */ var sx = x / gridSize;
+ /** @type {number} */ var sy = y / gridSize;
+ /** @type {number} */ var fx = 2.0 * sx - 1.0;
+ /** @type {number} */ var fy = 2.0 * sy - 1.0;
+ /** @type {number} */ var vtxNdx = ((y * (gridSize + 1)) + x);
+
+ this.m_positions[vtxNdx] = [fx, fy, 0.0, 1.0];
+ this.m_attribOne[vtxNdx] = 1.0;
+ this.m_screenPos[vtxNdx] = deMath.multiply([sx, sy, 0.0, 1.0], viewportScale);
+ this.m_coords[vtxNdx] = this.getCoords(sx, sy);
+ this.m_unitCoords[vtxNdx] = this.getUnitCoords(sx, sy);
+
+ for (var attribNdx = 0; attribNdx < this.getNumUserAttribs(); attribNdx++)
+ this.m_userAttribs[attribNdx][vtxNdx] = this.getUserAttrib(attribNdx, sx, sy);
+ }
+
+ // Compute indices.
+ for (var y = 0; y < gridSize; y++)
+ for (var x = 0; x < gridSize; x++) {
+ /** @type {number} */ var stride = gridSize + 1;
+ /** @type {number} */ var v00 = (y * stride) + x;
+ /** @type {number} */ var v01 = (y * stride) + x + 1;
+ /** @type {number} */ var v10 = ((y + 1) * stride) + x;
+ /** @type {number} */ var v11 = ((y + 1) * stride) + x + 1;
+
+ /** @type {number} */ var baseNdx = ((y * gridSize) + x) * 6;
+ this.m_indices[baseNdx + 0] = v10;
+ this.m_indices[baseNdx + 1] = v00;
+ this.m_indices[baseNdx + 2] = v01;
+
+ this.m_indices[baseNdx + 3] = v10;
+ this.m_indices[baseNdx + 4] = v01;
+ this.m_indices[baseNdx + 5] = v11;
+ }
+ };
+
+ /** @return {number} */
+ glsShaderRenderCase.QuadGrid.prototype.getGridSize = function() {
+ return this.m_gridSize;
+ };
+
+ /** @return {number} */
+ glsShaderRenderCase.QuadGrid.prototype.getNumVertices = function() {
+ return this.m_numVertices;
+ };
+
+ /** @return {number} */
+ glsShaderRenderCase.QuadGrid.prototype.getNumTriangles = function() {
+ return this.m_numTriangles;
+ };
+
+ /** @return {Array<number>} */
+ glsShaderRenderCase.QuadGrid.prototype.getConstCoords = function() {
+ return this.m_constCoords;
+ };
+
+ /** @return {Array<tcuMatrix.Matrix>} */
+ glsShaderRenderCase.QuadGrid.prototype.getUserAttribTransforms = function() {
+ return this.m_userAttribTransforms;
+ };
+
+ /** @return {Array<glsShaderRenderCase.TextureBinding>} */
+ glsShaderRenderCase.QuadGrid.prototype.getTextures = function() {
+ return this.m_textures;
+ };
+
+ /** @return {Array<Array<number>>} */
+ glsShaderRenderCase.QuadGrid.prototype.getPositions = function() {
+ return this.m_positions;
+ };
+
+ /** @return {Array<number>} */
+ glsShaderRenderCase.QuadGrid.prototype.getAttribOne = function() {
+ return this.m_attribOne;
+ };
+
+ /** @return {Array<Array<number>>} */
+ glsShaderRenderCase.QuadGrid.prototype.getCoordsArray = function() {
+ return this.m_coords;
+ };
+
+ /** @return {Array<Array<number>>} */
+ glsShaderRenderCase.QuadGrid.prototype.getUnitCoordsArray = function() {
+ return this.m_unitCoords;
+ };
+
+ /**
+ * @param {number} attribNdx
+ * @return {Array<number>}
+ */
+ glsShaderRenderCase.QuadGrid.prototype.getUserAttribByIndex = function(attribNdx) {
+ return this.m_userAttribs[attribNdx];
+ };
+
+ /** @return {Array<number>} */
+ glsShaderRenderCase.QuadGrid.prototype.getIndices = function() {
+ return this.m_indices;
+ };
+
+ /**
+ * @param {number} sx
+ * @param {number} sy
+ * @return {Array<number>}
+ */
+ glsShaderRenderCase.QuadGrid.prototype.getCoords = function(sx, sy) {
+ /** @type {number} */ var fx = 2.0 * sx - 1.0;
+ /** @type {number} */ var fy = 2.0 * sy - 1.0;
+ return [fx, fy, -fx + 0.33 * fy, -0.275 * fx - fy];
+ };
+
+ /**
+ * @param {number} sx
+ * @param {number} sy
+ * @return {Array<number>}
+ */
+ glsShaderRenderCase.QuadGrid.prototype.getUnitCoords = function(sx, sy) {
+ return [sx, sy, 0.33 * sx + 0.5 * sy, 0.5 * sx + 0.25 * sy];
+ };
+
+ /**
+ * @return {number}
+ */
+ glsShaderRenderCase.QuadGrid.prototype.getNumUserAttribs = function() {
+ return this.m_userAttribTransforms.length;
+ };
+
+ /**
+ * @param {number} attribNdx
+ * @param {number} sx
+ * @param {number} sy
+ * @return {Array<number>}
+ */
+ glsShaderRenderCase.QuadGrid.prototype.getUserAttrib = function(attribNdx, sx, sy) {
+ // homogeneous normalized screen-space coordinates
+ return tcuMatrix.multiplyMatVec(this.m_userAttribTransforms[attribNdx], [sx, sy, 0.0, 1.0]);
+ };
+
+ /**
+ * @constructor
+ * @struct
+ */
+ glsShaderRenderCase.ShaderSampler = function() {
+ /** @type {tcuTexture.Sampler} */ this.sampler;
+ /** @type {tcuTexture.Texture2D} */ this.tex2D = null;
+ /** @type {tcuTexture.TextureCube} */ this.texCube = null;
+ /** @type {tcuTexture.Texture2DArray} */ this.tex2DArray = null;
+ /** @type {tcuTexture.Texture3D} */ this.tex3D = null;
+ };
+
+ /**
+ * @constructor
+ * @param {glsShaderRenderCase.QuadGrid} quadGrid_
+ */
+ glsShaderRenderCase.ShaderEvalContext = function(quadGrid_) {
+ /** @type {Array<number>} */ this.coords = [0, 0, 0, 0]
+ /** @type {Array<number>} */ this.unitCoords = [0, 0, 0, 0]
+ /** @type {Array<number>} */ this.constCoords = quadGrid_.getConstCoords();
+ /** @type {Array<Array<number>>} */ this.in_ = [];
+ /** @type {Array<glsShaderRenderCase.ShaderSampler>} */ this.textures = [];
+ /** @type {Array<number>} */ this.color = [0, 0, 0, 0.0];
+ /** @type {boolean} */ this.isDiscarded = false;
+ /** @type {glsShaderRenderCase.QuadGrid} */ this.quadGrid = quadGrid_;
+
+ /** @type {Array<glsShaderRenderCase.TextureBinding>} */ var bindings = this.quadGrid.getTextures();
+ assertMsgOptions(bindings.length <= glsShaderRenderCase.MAX_TEXTURES, 'Too many bindings.', false, true);
+
+ // Fill in texture array.
+ for (var ndx = 0; ndx < bindings.length; ndx++) {
+ /** @type {glsShaderRenderCase.TextureBinding} */ var binding = bindings[ndx];
+
+ this.textures[ndx] = new glsShaderRenderCase.ShaderSampler();
+
+ if (binding.getType() == gluTexture.Type.TYPE_NONE)
+ continue;
+
+ this.textures[ndx].sampler = binding.getSampler();
+
+ switch (binding.getType()) {
+ case gluTexture.Type.TYPE_2D:
+ this.textures[ndx].tex2D = binding.getBinding().getRefTexture();
+ break;
+ case gluTexture.Type.TYPE_CUBE_MAP:
+ this.textures[ndx].texCube = binding.getBinding().getRefTexture();
+ break;
+ case gluTexture.Type.TYPE_2D_ARRAY:
+ this.textures[ndx].tex2DArray = binding.getBinding().getRefTexture();
+ break;
+ case gluTexture.Type.TYPE_3D:
+ this.textures[ndx].tex3D = binding.getBinding().getRefTexture();
+ break;
+ default:
+ throw new Error("Binding type not supported");
+ }
+ }
+ };
+
+ /**
+ * @param {number} sx
+ * @param {number} sy
+ */
+ glsShaderRenderCase.ShaderEvalContext.prototype.reset = function(sx, sy) {
+ // Clear old values
+ this.color = [0.0, 0.0, 0.0, 1.0];
+ this.isDiscarded = false;
+
+ // Compute coords
+ this.coords = this.quadGrid.getCoords(sx, sy);
+ this.unitCoords = this.quadGrid.getUnitCoords(sx, sy);
+
+ // Compute user attributes.
+ /** @type {number} */ var numAttribs = this.quadGrid.getNumUserAttribs();
+ assertMsgOptions(numAttribs <= glsShaderRenderCase.MAX_USER_ATTRIBS, 'numAttribs out of range', false, true);
+ for (var attribNdx = 0; attribNdx < numAttribs; attribNdx++)
+ this.in_[attribNdx] = this.quadGrid.getUserAttrib(attribNdx, sx, sy);
+ };
+
+ glsShaderRenderCase.ShaderEvalContext.prototype.discard = function() {
+ this.isDiscarded = true;
+ };
+
+ /**
+ * @param {number} unitNdx
+ * @param {Array<number>} coords
+ */
+ glsShaderRenderCase.ShaderEvalContext.prototype.texture2D = function(unitNdx, coords) {
+ if (this.textures.length > 0 && this.textures[unitNdx].tex2D)
+ return this.textures[unitNdx].tex2D.getView().sample(this.textures[unitNdx].sampler, coords, 0.0);
+ else
+ return [0.0, 0.0, 0.0, 1.0];
+ };
+
+ /** @param {glsShaderRenderCase.ShaderEvalContext} c */
+ glsShaderRenderCase.evalCoordsPassthroughX = function(c) {
+ c.color[0] = c.coords[0];
+ };
+
+ /** @param {glsShaderRenderCase.ShaderEvalContext} c */
+ glsShaderRenderCase.evalCoordsPassthroughXY = function(c) {
+ var swizzle01 = deMath.swizzle(c.coords, [0, 1]);
+ c.color[0] = swizzle01[0];
+ c.color[1] = swizzle01[1];
+ };
+
+ /** @param {glsShaderRenderCase.ShaderEvalContext} c */
+ glsShaderRenderCase.evalCoordsPassthroughXYZ = function(c) {
+ var swizzle012 = deMath.swizzle(c.coords, [0, 1, 2]);
+ c.color[0] = swizzle012[0];
+ c.color[1] = swizzle012[1];
+ c.color[2] = swizzle012[2];
+ };
+
+ /** @param {glsShaderRenderCase.ShaderEvalContext} c */
+ glsShaderRenderCase.evalCoordsPassthrough = function(c) {
+ c.color = c.coords;
+ };
+
+ /** @param {glsShaderRenderCase.ShaderEvalContext} c */
+ glsShaderRenderCase.evalCoordsSwizzleWZYX = function(c) {
+ c.color = deMath.swizzle(c.coords, [3, 2, 1, 0]);
+ };
+
+ /**
+ * @constructor
+ * @param {?glsShaderRenderCase.ShaderEvalFunc=} evalFunc
+ */
+ glsShaderRenderCase.ShaderEvaluator = function(evalFunc) {
+ /** @type {?glsShaderRenderCase.ShaderEvalFunc} */ this.m_evalFunc = evalFunc || null;
+ };
+
+ /**
+ * @param {glsShaderRenderCase.ShaderEvalContext} ctx
+ */
+ glsShaderRenderCase.ShaderEvaluator.prototype.evaluate = function(ctx) {
+ assertMsgOptions(this.m_evalFunc !== null, 'No evaluation function specified.', false, true);
+ this.m_evalFunc(ctx);
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ * @param {boolean} isVertexCase
+ * @param {glsShaderRenderCase.ShaderEvalFunc=} evalFunc
+ */
+ glsShaderRenderCase.ShaderRenderCase = function(name, description, isVertexCase, evalFunc) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ // evalFunc = evalFunc || null;
+ /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
+ /** @type {?glsShaderRenderCase.ShaderEvalFunc} */ this.m_defaultEvaluator = evalFunc || null;
+ /** @type {glsShaderRenderCase.ShaderEvaluator} */ this.m_evaluator = new glsShaderRenderCase.ShaderEvaluator(this.m_defaultEvaluator);
+ /** @type {string} */ this.m_vertShaderSource = '';
+ /** @type {string} */ this.m_fragShaderSource = '';
+ /** @type {Array<number>} */ this.m_clearColor = glsShaderRenderCase.DEFAULT_CLEAR_COLOR;
+ /** @type {Array<tcuMatrix.Matrix>} */ this.m_userAttribTransforms = [];
+ /** @type {Array<glsShaderRenderCase.TextureBinding>} */ this.m_textures = [];
+ /** @type {?gluShaderProgram.ShaderProgram} */ this.m_program = null;
+ };
+
+ /**
+ * @param {string} name
+ * @param {string} description
+ * @param {boolean} isVertexCase
+ * @param {glsShaderRenderCase.ShaderEvaluator} evaluator
+ * @return {glsShaderRenderCase.ShaderRenderCase}
+ */
+ glsShaderRenderCase.ShaderRenderCase.newWithEvaluator = function(name, description, isVertexCase, evaluator) {
+ var renderCase = new glsShaderRenderCase.ShaderRenderCase(name, description, isVertexCase);
+ renderCase.m_evaluator = evaluator;
+ return renderCase;
+ };
+
+ glsShaderRenderCase.ShaderRenderCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsShaderRenderCase.ShaderRenderCase.prototype.constructor = glsShaderRenderCase.ShaderRenderCase;
+
+ glsShaderRenderCase.ShaderRenderCase.prototype.deinit = function() {
+ this.m_program = null;
+ };
+
+ glsShaderRenderCase.ShaderRenderCase.prototype.init = function() {
+ this.postinit();
+ };
+
+ glsShaderRenderCase.ShaderRenderCase.prototype.postinit = function() {
+ if (this.m_vertShaderSource.length === 0 || this.m_fragShaderSource.length === 0) {
+ assertMsgOptions(this.m_vertShaderSource.length === 0 && this.m_fragShaderSource.length === 0, 'No shader source.', false, true);
+ this.setupShaderData();
+ }
+
+ assertMsgOptions(!this.m_program, 'Program defined.', false, true);
+ this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(this.m_vertShaderSource, this.m_fragShaderSource));
+
+ try {
+ bufferedLogToConsole(this.m_program.program.info.infoLog); // Always log shader program.
+
+ if (!this.m_program.isOk())
+ throw new Error("Shader compile error.");
+ }
+ catch (exception) {
+ // Clean up.
+ this.deinit();
+ throw exception;
+ }
+ };
+
+ /**
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.postiterate = function() {
+ assertMsgOptions(this.m_program !== null, 'Program not specified.', false, true);
+ /** @type {?WebGLProgram} */ var programID = this.m_program.getProgram();
+ gl.useProgram(programID);
+
+ // Create quad grid.
+ /** @type {Array<number>} */ var viewportSize = this.getViewportSize();
+ /** @type {number} */ var width = viewportSize[0];
+ /** @type {number} */ var height = viewportSize[1];
+
+ // \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords).
+ /** @type {glsShaderRenderCase.QuadGrid} */
+ var quadGrid = new glsShaderRenderCase.QuadGrid(
+ this.m_isVertexCase ? glsShaderRenderCase.GRID_SIZE : 4, width, height,
+ [0.125, 0.25, 0.5, 1.0], this.m_userAttribTransforms, this.m_textures);
+
+ // Render result.
+ /** @type {tcuSurface.Surface} */ var resImage = new tcuSurface.Surface(width, height);
+ this.render(resImage, programID, quadGrid);
+
+ // Compute reference.
+ /** @type {tcuSurface.Surface} */ var refImage = new tcuSurface.Surface(width, height);
+ if (this.m_isVertexCase)
+ this.computeVertexReference(refImage, quadGrid);
+ else
+ this.computeFragmentReference(refImage, quadGrid);
+
+ // Compare.
+ /** @type {boolean} */ var testOk = this.compareImages(resImage, refImage, 0.05);
+
+ // De-initialize.
+ gl.useProgram(null);
+
+ if (!testOk)
+ testFailedOptions("Fail", false);
+ else
+ testPassedOptions("Pass", true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.iterate = function() {
+ return this.postiterate();
+ };
+
+ glsShaderRenderCase.ShaderRenderCase.prototype.setupShaderData = function() {};
+
+ /**
+ * @param {?WebGLProgram} programId
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.setup = function(programId) {};
+
+ /**
+ * @param {?WebGLProgram} programId
+ * @param {Array<number>} constCoords
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.setupUniforms = function(programId, constCoords) {};
+
+ /**
+ * @return {Array<number>}
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.getViewportSize = function() {
+ return [Math.min(gl.canvas.width, glsShaderRenderCase.MAX_RENDER_WIDTH),
+ Math.min(gl.canvas.height, glsShaderRenderCase.MAX_RENDER_HEIGHT)];
+ };
+
+ /**
+ * @param {?WebGLProgram} programId
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.setupDefaultInputs = function(programId) {
+ // SETUP UNIFORMS.
+ glsShaderRenderCase.setupDefaultUniforms(programId);
+
+ // SETUP TEXTURES.
+ for (var ndx = 0; ndx < this.m_textures.length; ndx++) {
+ /** @type {glsShaderRenderCase.TextureBinding} */ var tex = this.m_textures[ndx];
+ /** @type {tcuTexture.Sampler} */ var sampler = tex.getSampler();
+ /** @type {number} */ var texTarget = gl.NONE;
+ /** @type {number} */ var texObj = 0;
+
+ if (tex.getType() === gluTexture.Type.TYPE_NONE)
+ continue;
+
+ switch (tex.getType()) {
+ case gluTexture.Type.TYPE_2D:
+ texTarget = gl.TEXTURE_2D;
+ texObj = tex.getBinding().getGLTexture();
+ break;
+ case gluTexture.Type.TYPE_CUBE_MAP:
+ texTarget = gl.TEXTURE_CUBE_MAP;
+ texObj = tex.getBinding().getGLTexture();
+ break;
+ case gluTexture.Type.TYPE_2D_ARRAY:
+ texTarget = gl.TEXTURE_2D_ARRAY;
+ texObj = tex.getBinding().getGLTexture();
+ break;
+ case gluTexture.Type.TYPE_3D:
+ texTarget = gl.TEXTURE_3D;
+ texObj = tex.getBinding().getGLTexture();
+ break;
+ default:
+ throw new Error("Type not supported");
+ }
+
+ gl.activeTexture(gl.TEXTURE0+ ndx);
+ gl.bindTexture(texTarget, texObj);
+ gl.texParameteri(texTarget, gl.TEXTURE_WRAP_S, gluTextureUtil.getGLWrapMode(sampler.wrapS));
+ gl.texParameteri(texTarget, gl.TEXTURE_WRAP_T, gluTextureUtil.getGLWrapMode(sampler.wrapT));
+ gl.texParameteri(texTarget, gl.TEXTURE_MIN_FILTER, gluTextureUtil.getGLFilterMode(sampler.minFilter));
+ gl.texParameteri(texTarget, gl.TEXTURE_MAG_FILTER, gluTextureUtil.getGLFilterMode(sampler.magFilter));
+
+ if (texTarget === gl.TEXTURE_3D)
+ gl.texParameteri(texTarget, gl.TEXTURE_WRAP_R, gluTextureUtil.getGLWrapMode(sampler.wrapR));
+
+ if (sampler.compare != tcuTexture.CompareMode.COMPAREMODE_NONE)
+ {
+ gl.texParameteri(texTarget, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+ gl.texParameteri(texTarget, gl.TEXTURE_COMPARE_FUNC, gluTextureUtil.getGLCompareFunc(sampler.compare));
+ }
+ }
+ };
+
+ /**
+ * @param {tcuSurface.Surface} result
+ * @param {?WebGLProgram} programId
+ * @param {glsShaderRenderCase.QuadGrid} quadGrid
+ **/
+ glsShaderRenderCase.ShaderRenderCase.prototype.render = function(result, programId, quadGrid) {
+ // Buffer info.
+ /** @type {number} */ var width = result.getWidth();
+ /** @type {number} */ var height = result.getHeight();
+
+ /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
+ /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
+
+ /** @type {number} */ var hash = deString.deStringHash(this.m_vertShaderSource) + deString.deStringHash(this.m_fragShaderSource);
+ /** @type {deRandom.Random} */ var rnd = new deRandom.Random(hash);
+
+ /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
+ /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
+
+ gl.viewport(xOffset, yOffset, width, height);
+
+ // Setup program.
+ this.setupUniforms(programId, quadGrid.getConstCoords());
+ this.setupDefaultInputs(programId);
+
+ // Clear.
+ gl.clearColor(this.m_clearColor[0], this.m_clearColor[1], this.m_clearColor[2], this.m_clearColor[3]);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ // Draw.
+ /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
+ /** @type {number} */ var numElements = quadGrid.getNumTriangles()*3;
+
+ glsShaderRenderCase.getDefaultVertexArrays(quadGrid, programId, vertexArrays);
+
+ gluDrawUtil.draw(gl, programId, vertexArrays, gluDrawUtil.triangles(quadGrid.getIndices()));
+
+ // Read back results.
+ result.readViewport(gl, [xOffset, yOffset, width, height]);
+
+ };
+
+ /**
+ * @param {tcuSurface.Surface} result
+ * @param {glsShaderRenderCase.QuadGrid} quadGrid
+ **/
+ glsShaderRenderCase.ShaderRenderCase.prototype.computeVertexReference = function(result, quadGrid) {
+ // Buffer info.
+ /** @type {number} */ var width = result.getWidth();
+ /** @type {number} */ var height = result.getHeight();
+ /** @type {number} */ var gridSize = quadGrid.getGridSize();
+ /** @type {number} */ var stride = gridSize + 1;
+ /** @type {boolean} */ var hasAlpha = gl.getContextAttributes().alpha;
+ /** @type {glsShaderRenderCase.ShaderEvalContext} */
+ var evalCtx = new glsShaderRenderCase.ShaderEvalContext(quadGrid);
+ /** @type {Array<number>} */ var color = [];
+ // Evaluate color for each vertex.
+ /** @type {Array<Array<number>>} */ var colors = [];
+ for (var y = 0; y < gridSize + 1; y++)
+ for (var x = 0; x < gridSize + 1; x++) {
+ /** @type {number} */ var sx = x / gridSize;
+ /** @type {number} */ var sy = y / gridSize;
+ /** @type {number} */ var vtxNdx = ((y * (gridSize+ 1 )) + x);
+
+ evalCtx.reset(sx, sy);
+ this.m_evaluator.evaluate(evalCtx);
+ assertMsgOptions(!evalCtx.isDiscarded, 'Discard is not available in vertex shader.', false, true);
+ color = evalCtx.color;
+
+ if (!hasAlpha)
+ color[3] = 1.0;
+
+ colors[vtxNdx] = color;
+ }
+ // Render quads.
+ for (var y = 0; y < gridSize; y++)
+ for (var x = 0; x < gridSize; x++) {
+ /** @type {number} */ var x0 = x / gridSize;
+ /** @type {number} */ var x1 = (x + 1) / gridSize;
+ /** @type {number} */ var y0 = y / gridSize;
+ /** @type {number} */ var y1 = (y + 1) / gridSize;
+
+ /** @type {number} */ var sx0 = x0 * width;
+ /** @type {number} */ var sx1 = x1 * width;
+ /** @type {number} */ var sy0 = y0 * height;
+ /** @type {number} */ var sy1 = y1 * height;
+ /** @type {number} */ var oosx = 1.0 / (sx1 - sx0);
+ /** @type {number} */ var oosy = 1.0 / (sy1 - sy0);
+
+ /** @type {number} */ var ix0 = Math.ceil(sx0 - 0.5);
+ /** @type {number} */ var ix1 = Math.ceil(sx1 - 0.5);
+ /** @type {number} */ var iy0 = Math.ceil(sy0 - 0.5);
+ /** @type {number} */ var iy1 = Math.ceil(sy1 - 0.5);
+
+ /** @type {number} */ var v00 = (y * stride) + x;
+ /** @type {number} */ var v01 = (y * stride) + x + 1;
+ /** @type {number} */ var v10 = ((y + 1) * stride) + x;
+ /** @type {number} */ var v11 = ((y + 1) * stride) + x + 1;
+ /** @type {Array<number>} */ var c00 = colors[v00];
+ /** @type {Array<number>} */ var c01 = colors[v01];
+ /** @type {Array<number>} */ var c10 = colors[v10];
+ /** @type {Array<number>} */ var c11 = colors[v11];
+
+ for (var iy = iy0; iy < iy1; iy++)
+ for (var ix = ix0; ix < ix1; ix++) {
+ assertMsgOptions(deMath.deInBounds32(ix, 0, width), 'Out of bounds.', false, true);
+ assertMsgOptions(deMath.deInBounds32(iy, 0, height), 'Out of bounds.', false, true);
+
+ /** @type {number} */ var sfx = ix + 0.5;
+ /** @type {number} */ var sfy = iy + 0.5;
+ /** @type {number} */ var fx1 = deMath.clamp((sfx - sx0) * oosx, 0.0, 1.0);
+ /** @type {number} */ var fy1 = deMath.clamp((sfy - sy0) * oosy, 0.0, 1.0);
+
+ // Triangle quad interpolation.
+ /** @type {boolean} */ var tri = fx1 + fy1 <= 1.0;
+ /** @type {number} */ var tx = tri ? fx1 : (1.0 - fx1);
+ /** @type {number} */ var ty = tri ? fy1 : (1.0 - fy1);
+ /** @type {Array<number>} */ var t0 = tri ? c00 : c11;
+ /** @type {Array<number>} */ var t1 = tri ? c01 : c10;
+ /** @type {Array<number>} */ var t2 = tri ? c10 : c01;
+ color = deMath.add(t0, deMath.add(deMath.scale(deMath.subtract(t1, t0), tx), deMath.scale(deMath.subtract(t2, t0), ty)));
+
+ result.setPixel(ix, iy, glsShaderRenderCase.toRGBA(color).toIVec());
+ }
+ }
+ };
+
+ /**
+ * @param {tcuSurface.Surface} result
+ * @param {glsShaderRenderCase.QuadGrid} quadGrid
+ **/
+ glsShaderRenderCase.ShaderRenderCase.prototype.computeFragmentReference = function(result, quadGrid) {
+ // Buffer info.
+ /** @type {number} */ var width = result.getWidth();
+ /** @type {number} */ var height = result.getHeight();
+ /** @type {boolean} */ var hasAlpha = gl.getContextAttributes().alpha;
+ /** @type {glsShaderRenderCase.ShaderEvalContext} */ var evalCtx = new glsShaderRenderCase.ShaderEvalContext(quadGrid);
+
+ // Render.
+ for (var y = 0; y < height; y++)
+ for (var x = 0; x < width; x++) {
+ /** @type {number} */ var sx = (x + 0.5) / width;
+ /** @type {number} */ var sy = (y + 0.5) / height;
+
+ evalCtx.reset(sx, sy);
+ this.m_evaluator.evaluate(evalCtx);
+ // Select either clear color or computed color based on discarded bit.
+ /** @type {Array<number>} */ var color = evalCtx.isDiscarded ? this.m_clearColor : evalCtx.color;
+
+ if (!hasAlpha)
+ color[3] = 1.0;
+
+ result.setPixel(x, y, glsShaderRenderCase.toRGBA(color).toIVec());
+ }
+ };
+
+ /**
+ * @param {tcuSurface.Surface} resImage
+ * @param {tcuSurface.Surface} refImage
+ * @param {number} errorThreshold
+ * @return {boolean}
+ */
+ glsShaderRenderCase.ShaderRenderCase.prototype.compareImages = function(resImage, refImage, errorThreshold) {
+ return tcuImageCompare.fuzzyCompare("ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), errorThreshold);
+ };
+
+ /**
+ * @param {number} number
+ * @return {string} */
+ glsShaderRenderCase.getIntUniformName = function(number) {
+ switch (number) {
+ case 0: return "ui_zero";
+ case 1: return "ui_one";
+ case 2: return "ui_two";
+ case 3: return "ui_three";
+ case 4: return "ui_four";
+ case 5: return "ui_five";
+ case 6: return "ui_six";
+ case 7: return "ui_seven";
+ case 8: return "ui_eight";
+ case 101: return "ui_oneHundredOne";
+ default:
+ throw new Error("Uniform not supported.");
+ }
+ };
+
+ /**
+ * @param {number} number
+ * @return {string} */
+ glsShaderRenderCase.getFloatUniformName = function(number) {
+ switch (number) {
+ case 0: return "uf_zero";
+ case 1: return "uf_one";
+ case 2: return "uf_two";
+ case 3: return "uf_three";
+ case 4: return "uf_four";
+ case 5: return "uf_five";
+ case 6: return "uf_six";
+ case 7: return "uf_seven";
+ case 8: return "uf_eight";
+ default:
+ throw new Error("Uniform not supported.");
+ }
+ };
+
+ /**
+ * @param {number} number
+ * @return {string} */
+ glsShaderRenderCase.getFloatFractionUniformName = function(number) {
+ switch (number) {
+ case 1: return "uf_one";
+ case 2: return "uf_half";
+ case 3: return "uf_third";
+ case 4: return "uf_fourth";
+ case 5: return "uf_fifth";
+ case 6: return "uf_sixth";
+ case 7: return "uf_seventh";
+ case 8: return "uf_eighth";
+ default:
+ throw new Error("Uniform not supported.");
+ }
+ };
+
+ /**
+ * @param {?WebGLProgram} programID
+ */
+ glsShaderRenderCase.setupDefaultUniforms = function(programID) {
+ /** @type {?WebGLUniformLocation} */ var uniLoc;
+ // Bool.
+ /**
+ * @constructor
+ * @struct
+ */
+ var BoolUniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {boolean} */ this.value = value;
+ };
+
+ /** @type {Array<BoolUniform>} */ var s_boolUniforms = [
+ new BoolUniform("ub_true", true),
+ new BoolUniform("ub_false", false)
+ ];
+
+ for (var i = 0; i < s_boolUniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform1i(uniLoc, s_boolUniforms[i].value ? 1 : 0);
+ }
+
+ // BVec4.
+ /**
+ * @constructor
+ * @struct
+ */
+ var BVec4Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<boolean>} */ this.value = value;
+ };
+
+ /** @type {Array<BVec4Uniform>} */ var s_bvec4Uniforms = [
+ new BVec4Uniform("ub4_true", [true, true, true, true]),
+ new BVec4Uniform("ub4_false", [false, false, false, false])
+ ];
+
+ for (var i = 0; i < s_bvec4Uniforms.length; i++) {
+ /** @type {BVec4Uniform} */ var uni = s_bvec4Uniforms[i];
+ /** @type {Array<number>} */ var arr = [];
+ arr[0] = uni.value[0] ? 1 : 0;
+ arr[1] = uni.value[1] ? 1 : 0;
+ arr[2] = uni.value[2] ? 1 : 0;
+ arr[3] = uni.value[3] ? 1 : 0;
+ uniLoc = gl.getUniformLocation(programID, uni.name);
+ if (uniLoc != null)
+ gl.uniform4iv(uniLoc, new Int32Array(arr));
+ }
+
+ // Int.
+ /**
+ * @constructor
+ * @struct
+ */
+ var IntUniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {number} */ this.value = value;
+ };
+
+ /** @type {Array<IntUniform>} */ var s_intUniforms = [
+ new IntUniform("ui_minusOne", -1),
+ new IntUniform("ui_zero", 0),
+ new IntUniform("ui_one", 1),
+ new IntUniform("ui_two", 2),
+ new IntUniform("ui_three", 3),
+ new IntUniform("ui_four", 4),
+ new IntUniform("ui_five", 5),
+ new IntUniform("ui_six", 6),
+ new IntUniform("ui_seven", 7),
+ new IntUniform("ui_eight", 8),
+ new IntUniform("ui_oneHundredOne", 101)
+ ];
+
+ for (var i = 0; i < s_intUniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform1i(uniLoc, s_intUniforms[i].value);
+ }
+
+ // IVec2.
+ /**
+ * @constructor
+ * @struct
+ */
+ var IVec2Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+
+ /** @type {Array<IVec2Uniform>} */ var s_ivec2Uniforms = [
+ new IVec2Uniform("ui2_minusOne", [-1, -1]),
+ new IVec2Uniform("ui2_zero", [0, 0]),
+ new IVec2Uniform("ui2_one", [1, 1]),
+ new IVec2Uniform("ui2_two", [2, 2]),
+ new IVec2Uniform("ui2_four", [4, 4]),
+ new IVec2Uniform("ui2_five", [5, 5])
+ ];
+
+ for (var i = 0; i < s_ivec2Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform2iv(uniLoc, new Int32Array(s_ivec2Uniforms[i].value));
+ }
+
+ // IVec3.
+ /**
+ * @constructor
+ * @struct
+ */
+ var IVec3Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+
+ /** @type {Array<IVec3Uniform>} */ var s_ivec3Uniforms = [
+ new IVec3Uniform("ui3_minusOne", [-1, -1, -1]),
+ new IVec3Uniform("ui3_zero", [0, 0, 0]),
+ new IVec3Uniform("ui3_one", [1, 1, 1]),
+ new IVec3Uniform("ui3_two", [2, 2, 2]),
+ new IVec3Uniform("ui3_four", [4, 4, 4]),
+ new IVec3Uniform("ui3_five", [5, 5, 5])
+ ];
+
+ for (var i = 0; i < s_ivec3Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform3iv(uniLoc, new Int32Array(s_ivec3Uniforms[i].value));
+ }
+
+ // IVec4.
+ /**
+ * @constructor
+ * @struct
+ */
+ var IVec4Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+ /** @type {Array<IVec4Uniform>} */ var s_ivec4Uniforms = [
+ new IVec4Uniform("ui4_minusOne", [-1, -1, -1, -1]),
+ new IVec4Uniform("ui4_zero", [0, 0, 0, 0]),
+ new IVec4Uniform("ui4_one", [1, 1, 1, 1]),
+ new IVec4Uniform("ui4_two", [2, 2, 2, 2]),
+ new IVec4Uniform("ui4_four", [4, 4, 4, 4]),
+ new IVec4Uniform("ui4_five", [5, 5, 5, 5])
+ ];
+
+ for (var i = 0; i < s_ivec4Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform4iv(uniLoc, new Int32Array(s_ivec4Uniforms[i].value));
+ }
+
+ // Float.
+ /**
+ * @constructor
+ * @struct
+ */
+ var FloatUniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {number} */ this.value = value;
+ };
+ /** @type {Array<FloatUniform>} */ var s_floatUniforms = [
+ new FloatUniform("uf_zero", 0.0),
+ new FloatUniform("uf_one", 1.0),
+ new FloatUniform("uf_two", 2.0),
+ new FloatUniform("uf_three", 3.0),
+ new FloatUniform("uf_four", 4.0),
+ new FloatUniform("uf_five", 5.0),
+ new FloatUniform("uf_six", 6.0),
+ new FloatUniform("uf_seven", 7.0),
+ new FloatUniform("uf_eight", 8.0),
+ new FloatUniform("uf_half", 1.0 / 2.0),
+ new FloatUniform("uf_third", 1.0 / 3.0),
+ new FloatUniform("uf_fourth", 1.0 / 4.0),
+ new FloatUniform("uf_fifth", 1.0 / 5.0),
+ new FloatUniform("uf_sixth", 1.0 / 6.0),
+ new FloatUniform("uf_seventh", 1.0 / 7.0),
+ new FloatUniform("uf_eighth", 1.0 / 8.0)
+ ];
+
+ for (var i = 0; i < s_floatUniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform1f(uniLoc, s_floatUniforms[i].value);
+ }
+
+ // Vec2.
+ /**
+ * @constructor
+ * @struct
+ */
+ var Vec2Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+ /** @type {Array<Vec2Uniform>} */ var s_vec2Uniforms = [
+ new Vec2Uniform("uv2_minusOne", [-1.0, -1.0]),
+ new Vec2Uniform("uv2_zero", [0.0, 0.0]),
+ new Vec2Uniform("uv2_half", [0.5, 0.5]),
+ new Vec2Uniform("uv2_one", [1.0, 1.0]),
+ new Vec2Uniform("uv2_two", [2.0, 2.0])
+ ];
+
+ for (var i = 0; i < s_vec2Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform2fv(uniLoc, new Float32Array(s_vec2Uniforms[i].value));
+ }
+
+ // Vec3.
+ /**
+ * @constructor
+ * @struct
+ */
+ var Vec3Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+ /** @type {Array<Vec3Uniform>} */ var s_vec3Uniforms = [
+ new Vec3Uniform("uv3_minusOne", [-1.0, -1.0, -1.0]),
+ new Vec3Uniform("uv3_zero", [0.0, 0.0, 0.0]),
+ new Vec3Uniform("uv3_half", [0.5, 0.5, 0.5]),
+ new Vec3Uniform("uv3_one", [1.0, 1.0, 1.0]),
+ new Vec3Uniform("uv3_two", [2.0, 2.0, 2.0])
+ ];
+
+ for (var i = 0; i < s_vec3Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform3fv(uniLoc, new Float32Array(s_vec3Uniforms[i].value));
+ }
+
+ // Vec4.
+ /**
+ * @constructor
+ * @struct
+ */
+ var Vec4Uniform = function(name, value) {
+ /** @type {string} */ this.name = name;
+ /** @type {Array<number>} */ this.value = value;
+ };
+ /** @type {Array<Vec4Uniform>} */ var s_vec4Uniforms = [
+ new Vec4Uniform("uv4_minusOne", [-1.0, -1.0, -1.0, -1.0]),
+ new Vec4Uniform("uv4_zero", [0.0, 0.0, 0.0, 0.0]),
+ new Vec4Uniform("uv4_half", [0.5, 0.5, 0.5, 0.5]),
+ new Vec4Uniform("uv4_one", [1.0, 1.0, 1.0, 1.0]),
+ new Vec4Uniform("uv4_two", [2.0, 2.0, 2.0, 2.0]),
+ new Vec4Uniform("uv4_black", [0.0, 0.0, 0.0, 1.0]),
+ new Vec4Uniform("uv4_gray", [0.5, 0.5, 0.5, 1.0]),
+ new Vec4Uniform("uv4_white", [1.0, 1.0, 1.0, 1.0])
+ ];
+
+ for (var i = 0; i < s_vec4Uniforms.length; i++) {
+ uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name);
+ if (uniLoc != null)
+ gl.uniform4fv(uniLoc, new Float32Array(s_vec4Uniforms[i].value));
+ }
+ };
+
+ /**
+ * @param {glsShaderRenderCase.QuadGrid} quadGrid
+ * @param {?WebGLProgram} program
+ * @param {Array<gluDrawUtil.VertexArrayBinding>} vertexArrays
+ */
+ glsShaderRenderCase.getDefaultVertexArrays = function(quadGrid, program, vertexArrays) {
+ /** @type {number} */ var numElements = quadGrid.getNumVertices();
+ var posArray = [].concat.apply([], quadGrid.getPositions());
+ var coordsArray = [].concat.apply([], quadGrid.getCoordsArray());
+ var unitCoordsArray = [].concat.apply([], quadGrid.getUnitCoordsArray());
+
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numElements, 0, posArray));
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_coords", 4, numElements, 0, coordsArray));
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_unitCoords", 4, numElements, 0, unitCoordsArray));
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_one", 1, numElements, 0, quadGrid.getAttribOne()));
+
+ // a_inN.
+ for (var userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++) {
+ /** @type {string} */ var name = "a_in" + userNdx;
+ var userAttribArray = [].concat.apply([], quadGrid.getUserAttribByIndex(userNdx));
+ vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding(name, 4, numElements, 0, userAttribArray));
+ }
+
+ // Matrix attributes - these are set by location
+ /**
+ * @constructor
+ * @struct
+ */
+ var Matrix = function(name, cols, rows) {
+ this.name = name;
+ this.numCols = cols;
+ this.numRows = rows;
+ };
+
+ /** @type {Array<Matrix>} */ var matrices = [
+ new Matrix('a_mat2', 2, 2),
+ new Matrix('a_mat2x3', 2, 3),
+ new Matrix('a_mat2x4', 2, 4),
+ new Matrix('a_mat3x2', 3, 2),
+ new Matrix('a_mat3', 3, 3),
+ new Matrix('a_mat3x4', 3, 4),
+ new Matrix('a_mat4x2', 4, 2),
+ new Matrix('a_mat4x3', 4, 3),
+ new Matrix('a_mat4', 4, 4)
+ ];
+
+ for (var matNdx = 0; matNdx < matrices.length; matNdx++) {
+ /** @type {number} */ var loc = gl.getAttribLocation(program, matrices[matNdx].name);
+
+ if (loc < 0)
+ continue; // Not used in shader.
+
+ /** @type {number} */ var numRows = matrices[matNdx].numRows;
+ /** @type {number} */ var numCols = matrices[matNdx].numCols;
+
+ for (var colNdx = 0; colNdx < numCols; colNdx++) {
+ var data = [].concat.apply([], quadGrid.getUserAttribByIndex(colNdx));
+ vertexArrays.push(gluDrawUtil.newFloatColumnVertexArrayBinding(matrices[matNdx].name, colNdx, numRows, numElements, 4 * 4, data));
+ }
+ }
+ };
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsStateQuery.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsStateQuery.js
new file mode 100644
index 000000000..962d87fb4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsStateQuery.js
@@ -0,0 +1,367 @@
+/*-------------------------------------------------------------------------
+ * 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.glsStateQuery');
+
+goog.scope(function() {
+var glsStateQuery = modules.shared.glsStateQuery;
+
+/**
+ * Compare two objects. Objects must have the same type and contents.
+ * If comparing numbers, allow some epsilon differences
+ * @param {*} a
+ * @param {*} b
+ * return {boolean}
+ */
+glsStateQuery.compare = function(a, b) {
+ /** @const */ var eps = 0.01;
+ if (a === b)
+ return true;
+
+ if (typeof a === 'number' && typeof b === 'number')
+ return Math.abs(a - b) < eps;
+
+ //compare array-like parameters
+ if (typeof a == 'object' && typeof b == 'object') {
+ if (a.constructor !== b.constructor)
+ return false;
+
+ if ('length' in a && 'length' in b) {
+ if (a.length !== b.length)
+ return false;
+ for (var i = 0; i < a.length; i++) {
+ if (typeof a[i] === 'number' && typeof b[i] === 'number') {
+ if (Math.abs(a[i] - b[i]) >= eps)
+ return false;
+ } else if (a[i] !== b[i])
+ return false;
+ }
+ return true;
+ }
+
+ }
+ return false;
+};
+
+/**
+ * Verify that WebGL state 'param' has the expected value
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verify = function(param, reference) {
+ var value = gl.getParameter(param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL current vertex attrib has the expected value
+ * @param {number} index
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyCurrentVertexAttrib = function(index, reference) {
+ var value = gl.getVertexAttrib(index, gl.CURRENT_VERTEX_ATTRIB);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL vertex attrib attribute 'param' has the expected value
+ * @param {number} index
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyVertexAttrib = function(index, param, reference) {
+ var value = (param == gl.VERTEX_ATTRIB_ARRAY_POINTER) ?
+ gl.getVertexAttribOffset(index, param) :
+ gl.getVertexAttrib(index, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL uniform has the expected value
+ * @param {WebGLProgram} program
+ * @param {WebGLUniformLocation} location
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyUniform = function(program, location, reference) {
+ var value = gl.getUniform(program, location);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL shader state 'param' has the expected value
+ * @param {WebGLShader} shader
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyShader = function(shader, param, reference) {
+ var value = gl.getShaderParameter(shader, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL program state 'param' has the expected value
+ * @param {WebGLProgram} program
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyProgram = function(program, param, reference) {
+ var value = gl.getProgramParameter(program, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL sampler state 'param' has the expected value
+ * @param {WebGLSampler} sampler
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifySampler = function(sampler, param, reference) {
+ var value = gl.getSamplerParameter(sampler, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL texture state 'param' has the expected value
+ * @param {number} target
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyTexture = function(target, param, reference) {
+ var value = gl.getTexParameter(target, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL state 'param' has one of the expected values
+ * @param {number} param
+ * @param {Array<*>} reference
+ * return {boolean}
+ */
+glsStateQuery.verifyAnyOf = function(param, reference) {
+ var value = gl.getParameter(param);
+ for (var i = 0; i < reference.length; i++)
+ if (glsStateQuery.compare(value, reference[i]))
+ return true;
+ bufferedLogToConsole('Result: ' + value + ' Expected one of: ' + reference);
+ return false;
+};
+
+/**
+ * Verify that WebGL state 'param' has the expected value
+ * @param {number} param
+ * @param {number|Array<number>} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyGreaterOrEqual = function(param, reference) {
+ var value = gl.getParameter(param);
+ if (reference instanceof Array) {
+ var v = /** @type {Array<number>} */ (value);
+ if (v.length != reference.length) {
+ bufferedLogToConsole('Result: ' + value + ' Expected >= : ' + reference);
+ return false;
+ }
+ for (var i = 0; i < reference.length; i++)
+ if (v[i] < reference[i]) {
+ bufferedLogToConsole('Result: ' + value + ' Expected >= : ' + reference);
+ return false;
+ }
+ return true;
+ }
+ var n = /** @type {number} */ (value);
+ if (n < reference) {
+ bufferedLogToConsole('Result: ' + value + ' Expected >= : ' + reference);
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Verify that WebGL state 'param' has the expected value
+ * @param {number} param
+ * @param {number|Array<number>} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyLessOrEqual = function(param, reference) {
+ var value = gl.getParameter(param);
+ if (reference instanceof Array) {
+ var v = /** @type {Array<number>} */ (value);
+ if (v.length != reference.length) {
+ bufferedLogToConsole('Result: ' + value + ' Expected <= : ' + reference);
+ return false;
+ }
+ for (var i = 0; i > reference.length; i++)
+ if (v[i] < reference[i]) {
+ bufferedLogToConsole('Result: ' + value + ' Expected <= : ' + reference);
+ return false;
+ }
+ return true;
+ }
+ var n = /** @type {number} */ (value);
+ if (n > reference) {
+ bufferedLogToConsole('Result: ' + value + ' Expected <= : ' + reference);
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Verify that WebGL state 'param' has the expected value (value & mask == reference)
+ * @param {number} param
+ * @param {number} reference
+ * @param {number} mask
+ * @return {boolean}
+ */
+glsStateQuery.verifyMasked = function(param, reference, mask) {
+ var value = /** @type {number} */ (gl.getParameter(param));
+ if ((value & mask) !== reference) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference + 'Mask: 0x' + mask.toString(16));
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Verify that WebGL fbo attachment 'param' has the expected value
+ * @param {number} fbo
+ * @param {number} attachment
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyAttachment = function(fbo, attachment, param, reference) {
+ var value = gl.getFramebufferAttachmentParameter(fbo, attachment, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL fbo color attachment 'param' has the expected value
+ * @param {number} fbo
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyColorAttachment = function(fbo, param, reference) {
+ return glsStateQuery.verifyAttachment(fbo, gl.COLOR_ATTACHMENT0, param, reference);
+};
+
+/**
+ * Verify that WebGL rbo attribute 'param' has the expected value
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyRenderbuffer = function(param, reference) {
+ var value = gl.getRenderbufferParameter(gl.RENDERBUFFER, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * Verify that WebGL active uniform block's attribute 'param' has the expected value
+ * @param {WebGLProgram} program
+ * @param {number} index
+ * @param {number} param
+ * @param {*} reference
+ * @return {boolean}
+ */
+glsStateQuery.verifyActiveUniformBlock = function(program, index, param, reference) {
+ var value = gl.getActiveUniformBlockParameter(program, index, param);
+ var result = glsStateQuery.compare(value, reference);
+ if (!result) {
+ bufferedLogToConsole('Result: ' + value + ' Expected: ' + reference);
+ }
+ return result;
+};
+
+/**
+ * @param {number} param
+ * @param {Array<number>} reference
+ * @param {Array<boolean>} enableRef
+ * @return {boolean}
+ */
+
+glsStateQuery.verifyMask = function(param, reference, enableRef) {
+ var intVector4 = /** @type {Array<number>} */ (gl.getParameter(param));
+
+ if ((enableRef[0] && (intVector4[0] != reference[0])) ||
+ (enableRef[1] && (intVector4[1] != reference[1])) ||
+ (enableRef[2] && (intVector4[2] != reference[2])) ||
+ (enableRef[3] && (intVector4[3] != reference[3])))
+ {
+ bufferedLogToConsole("// ERROR: expected " +
+ (enableRef[0] ? "" : "(") + reference[0] + (enableRef[0] ? "" : ")") + ", " +
+ (enableRef[1] ? "" : "(") + reference[1] + (enableRef[1] ? "" : ")") + ", " +
+ (enableRef[2] ? "" : "(") + reference[2] + (enableRef[2] ? "" : ")") + ", " +
+ (enableRef[3] ? "" : "(") + reference[3] + (enableRef[3] ? "" : ")"));
+
+ return false;
+ }
+ return true;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js
new file mode 100644
index 000000000..f35d94226
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js
@@ -0,0 +1,2642 @@
+/*-------------------------------------------------------------------------
+ * 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.glsTextureTestUtil');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuStringTemplate');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTexLookupVerifier');
+goog.require('framework.common.tcuTexCompareVerifier');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.delibs.debase.deRandom');
+
+goog.scope(function() {
+var tcuTexLookupVerifier = framework.common.tcuTexLookupVerifier;
+var tcuTexCompareVerifier = framework.common.tcuTexCompareVerifier;
+var glsTextureTestUtil = modules.shared.glsTextureTestUtil;
+var gluDrawUtil = framework.opengl.gluDrawUtil;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+var tcuTexture = framework.common.tcuTexture;
+var tcuSurface = framework.common.tcuSurface;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+var tcuStringTemplate = framework.common.tcuStringTemplate;
+var deMath = framework.delibs.debase.deMath;
+var tcuImageCompare = framework.common.tcuImageCompare;
+var tcuPixelFormat = framework.common.tcuPixelFormat;
+var tcuRGBA = framework.common.tcuRGBA;
+var deRandom = framework.delibs.debase.deRandom;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+var MIN_SUBPIXEL_BITS = 4;
+
+/**
+ * @enum
+ */
+glsTextureTestUtil.textureType = {
+ TEXTURETYPE_2D: 0,
+ TEXTURETYPE_CUBE: 1,
+ TEXTURETYPE_2D_ARRAY: 2,
+ TEXTURETYPE_3D: 3,
+ TEXTURETYPE_CUBE_ARRAY: 4,
+ TEXTURETYPE_1D: 5,
+ TEXTURETYPE_1D_ARRAY: 6,
+ TEXTURETYPE_BUFFER: 7
+};
+
+/**
+ * @enum
+ */
+glsTextureTestUtil.samplerType = {
+ SAMPLERTYPE_FLOAT: 0,
+ SAMPLERTYPE_INT: 1,
+ SAMPLERTYPE_UINT: 2,
+ SAMPLERTYPE_SHADOW: 3,
+
+ SAMPLERTYPE_FETCH_FLOAT: 4,
+ SAMPLERTYPE_FETCH_INT: 5,
+ SAMPLERTYPE_FETCH_UINT: 6
+};
+
+/**
+ * @param {tcuTexture.TextureFormat} format
+ * @return {glsTextureTestUtil.samplerType}
+ */
+glsTextureTestUtil.getSamplerType = function(format) {
+ if (format == null)
+ throw new Error('Missing format information');
+
+ switch (format.type) {
+ case tcuTexture.ChannelType.SIGNED_INT8:
+ case tcuTexture.ChannelType.SIGNED_INT16:
+ case tcuTexture.ChannelType.SIGNED_INT32:
+ return glsTextureTestUtil.samplerType.SAMPLERTYPE_INT;
+
+ case tcuTexture.ChannelType.UNSIGNED_INT8:
+ case tcuTexture.ChannelType.UNSIGNED_INT32:
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV:
+ return glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT;
+
+ // Texture formats used in depth/stencil textures.
+ case tcuTexture.ChannelType.UNSIGNED_INT16:
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ return (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS) ? glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT : glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT;
+
+ default:
+ return glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT;
+ }
+};
+
+/**
+ * @constructor
+ * @param {HTMLElement} canvas
+ * @param {number} preferredWidth
+ * @param {number} preferredHeight
+ * @param {number=} seed
+ */
+glsTextureTestUtil.RandomViewport = function(canvas, preferredWidth, preferredHeight, seed) {
+ this.width = Math.min(canvas.width, preferredWidth);
+ this.height = Math.min(canvas.height, preferredHeight);
+
+ if (typeof seed === 'undefined')
+ seed = preferredWidth + preferredHeight;
+
+ var rnd = new deRandom.Random(seed);
+ this.x = rnd.getInt(0, canvas.width - this.width);
+ this.y = rnd.getInt(0, canvas.height - this.height);
+};
+
+/**
+ * @constructor
+ * @param {glsTextureTestUtil.textureType} texType
+ */
+glsTextureTestUtil.RenderParams = function(texType) {
+ this.flags = {
+ projected: false,
+ use_bias: false,
+ log_programs: false,
+ log_uniforms: false
+ };
+ this.texType = texType;
+ this.w = [1, 1, 1, 1];
+ this.bias = 0;
+ this.ref = 0;
+ this.colorScale = [1, 1, 1, 1];
+ this.colorBias = [0, 0, 0, 0];
+ this.samplerType = glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT;
+};
+
+/**
+ * @enum
+ */
+glsTextureTestUtil.lodMode = {
+ EXACT: 0, //!< Ideal lod computation.
+ MIN_BOUND: 1, //!< Use estimation range minimum bound.
+ MAX_BOUND: 2 //!< Use estimation range maximum bound.
+
+};
+
+/**
+ * @constructor
+ * @extends {glsTextureTestUtil.RenderParams}
+ * @param {glsTextureTestUtil.textureType} texType
+ * @param {tcuTexture.Sampler=} sampler
+ * @param {glsTextureTestUtil.lodMode=} lodMode_
+ */
+glsTextureTestUtil.ReferenceParams = function(texType, sampler, lodMode_) {
+ glsTextureTestUtil.RenderParams.call(this, texType);
+ if (sampler)
+ this.sampler = sampler;
+ if (lodMode_)
+ this.lodMode = lodMode_;
+ else
+ this.lodMode = glsTextureTestUtil.lodMode.EXACT;
+ this.minLod = -1000;
+ this.maxLod = 1000;
+ this.baseLevel = 0;
+ this.maxLevel = 1000;
+};
+
+glsTextureTestUtil.ReferenceParams.prototype = Object.create(glsTextureTestUtil.RenderParams.prototype);
+
+/** Copy constructor */
+glsTextureTestUtil.ReferenceParams.prototype.constructor = glsTextureTestUtil.ReferenceParams;
+
+/**
+ * @param {Array<number>} bottomLeft
+ * @param {Array<number>} topRight
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.computeQuadTexCoord2D = function(bottomLeft, topRight) {
+ var dst = [];
+ dst.length = 4 * 2;
+
+ dst[0] = bottomLeft[0]; dst[1] = bottomLeft[1];
+ dst[2] = bottomLeft[0]; dst[3] = topRight[1];
+ dst[4] = topRight[0]; dst[5] = bottomLeft[1];
+ dst[6] = topRight[0]; dst[7] = topRight[1];
+
+ return dst;
+};
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.computeQuadTexCoordCube = function(face) {
+ var texCoordNegX = [
+ -1, 1, -1,
+ -1, -1, -1,
+ -1, 1, 1,
+ -1, -1, 1
+ ];
+ var texCoordPosX = [
+ +1, 1, 1,
+ +1, -1, 1,
+ +1, 1, -1,
+ +1, -1, -1
+ ];
+ var texCoordNegY = [
+ -1, -1, 1,
+ -1, -1, -1,
+ 1, -1, 1,
+ 1, -1, -1
+ ];
+ var texCoordPosY = [
+ -1, +1, -1,
+ -1, +1, 1,
+ 1, +1, -1,
+ 1, +1, 1
+ ];
+ var texCoordNegZ = [
+ 1, 1, -1,
+ 1, -1, -1,
+ -1, 1, -1,
+ -1, -1, -1
+ ];
+ var texCoordPosZ = [
+ -1, 1, +1,
+ -1, -1, +1,
+ 1, 1, +1,
+ 1, -1, +1
+ ];
+
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: return texCoordNegX;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: return texCoordPosX;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: return texCoordNegY;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: return texCoordPosY;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: return texCoordNegZ;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: return texCoordPosZ;
+ }
+ throw new Error('Unrecognized face ' + face);
+};
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @param {Array<number>} bottomLeft
+ * @param {Array<number>} topRight
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.computeQuadTexCoordCubeFace = function(face, bottomLeft, topRight) {
+ var dst = [];
+ /** @type {number} */ var sRow = 0;
+ /** @type {number} */ var tRow = 0;
+ /** @type {number} */ var mRow = 0;
+ /** @type {number} */ var sSign = 1.0;
+ /** @type {number} */ var tSign = 1.0;
+ /** @type {number} */ var mSign = 1.0;
+
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0; tSign = -1.0; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0; tSign = -1.0; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0; tSign = -1.0; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0; sSign = -1.0; tSign = -1.0; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0; break;
+ default:
+ throw new Error('Invalid cube face specified.');
+ }
+
+ dst[0 + mRow] = mSign;
+ dst[3 + mRow] = mSign;
+ dst[6 + mRow] = mSign;
+ dst[9 + mRow] = mSign;
+
+ dst[0 + sRow] = sSign * bottomLeft[0];
+ dst[3 + sRow] = sSign * bottomLeft[0];
+ dst[6 + sRow] = sSign * topRight[0];
+ dst[9 + sRow] = sSign * topRight[0];
+
+ dst[0 + tRow] = tSign * bottomLeft[1];
+ dst[3 + tRow] = tSign * topRight[1];
+ dst[6 + tRow] = tSign * bottomLeft[1];
+ dst[9 + tRow] = tSign * topRight[1];
+
+ return dst;
+};
+
+/**
+ * @param {number} layerNdx
+ * @param {Array<number>} bottomLeft
+ * @param {Array<number>} topRight
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.computeQuadTexCoord2DArray = function(layerNdx, bottomLeft, topRight) {
+ var dst = [];
+ dst.length = 4 * 3;
+
+ dst[0] = bottomLeft[0]; dst[1] = bottomLeft[1]; dst[2] = layerNdx;
+ dst[3] = bottomLeft[0]; dst[4] = topRight[1]; dst[5] = layerNdx;
+ dst[6] = topRight[0]; dst[7] = bottomLeft[1]; dst[8] = layerNdx;
+ dst[9] = topRight[0]; dst[10] = topRight[1]; dst[11] = layerNdx;
+
+ return dst;
+};
+
+/**
+ * @param {Array<number>} a
+ * @param {Array<number>} b
+ * @param {Array<number>} c
+ * @return {Array<number>} a + (b - a) * c
+ */
+glsTextureTestUtil.selectCoords = function(a, b, c) {
+ var x1 = deMath.subtract(b, a);
+ var x2 = deMath.multiply(x1, c);
+ var x3 = deMath.add(a, x2);
+ return x3;
+};
+
+/**
+ * @param {Array<number>} p0
+ * @param {Array<number>} p1
+ * @param {Array<number>} dirSwz
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.computeQuadTexCoord3D = function(p0, p1, dirSwz) {
+ var dst = [];
+ dst.length = 4 * 3;
+
+ var f0 = deMath.swizzle(([0, 0, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]);
+ var f1 = deMath.swizzle(([0, 1, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]);
+ var f2 = deMath.swizzle(([1, 0, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]);
+ var f3 = deMath.swizzle(([1, 1, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]);
+
+ var v0 = glsTextureTestUtil.selectCoords(p0, p1, f0);
+ var v1 = glsTextureTestUtil.selectCoords(p0, p1, f1);
+ var v2 = glsTextureTestUtil.selectCoords(p0, p1, f2);
+ var v3 = glsTextureTestUtil.selectCoords(p0, p1, f3);
+
+ dst[0] = v0[0]; dst[1] = v0[1]; dst[2] = v0[2];
+ dst[3] = v1[0]; dst[4] = v1[1]; dst[5] = v1[2];
+ dst[6] = v2[0]; dst[7] = v2[1]; dst[8] = v2[2];
+ dst[9] = v3[0]; dst[10] = v3[1]; dst[11] = v3[2];
+
+ return dst;
+};
+
+/**
+ * @enum
+ */
+glsTextureTestUtil.programType = {
+ PROGRAM_2D_FLOAT: 0,
+ PROGRAM_2D_INT: 1,
+ PROGRAM_2D_UINT: 2,
+ PROGRAM_2D_SHADOW: 3,
+
+ PROGRAM_2D_FLOAT_BIAS: 4,
+ PROGRAM_2D_INT_BIAS: 5,
+ PROGRAM_2D_UINT_BIAS: 6,
+ PROGRAM_2D_SHADOW_BIAS: 7,
+
+ PROGRAM_1D_FLOAT: 8,
+ PROGRAM_1D_INT: 9,
+ PROGRAM_1D_UINT: 10,
+ PROGRAM_1D_SHADOW: 11,
+
+ PROGRAM_1D_FLOAT_BIAS: 12,
+ PROGRAM_1D_INT_BIAS: 13,
+ PROGRAM_1D_UINT_BIAS: 14,
+ PROGRAM_1D_SHADOW_BIAS: 15,
+
+ PROGRAM_CUBE_FLOAT: 16,
+ PROGRAM_CUBE_INT: 17,
+ PROGRAM_CUBE_UINT: 18,
+ PROGRAM_CUBE_SHADOW: 19,
+
+ PROGRAM_CUBE_FLOAT_BIAS: 20,
+ PROGRAM_CUBE_INT_BIAS: 21,
+ PROGRAM_CUBE_UINT_BIAS: 22,
+ PROGRAM_CUBE_SHADOW_BIAS: 23,
+
+ PROGRAM_1D_ARRAY_FLOAT: 24,
+ PROGRAM_1D_ARRAY_INT: 25,
+ PROGRAM_1D_ARRAY_UINT: 26,
+ PROGRAM_1D_ARRAY_SHADOW: 27,
+
+ PROGRAM_2D_ARRAY_FLOAT: 28,
+ PROGRAM_2D_ARRAY_INT: 29,
+ PROGRAM_2D_ARRAY_UINT: 30,
+ PROGRAM_2D_ARRAY_SHADOW: 31,
+
+ PROGRAM_3D_FLOAT: 32,
+ PROGRAM_3D_INT: 33,
+ PROGRAM_3D_UINT: 34,
+
+ PROGRAM_3D_FLOAT_BIAS: 35,
+ PROGRAM_3D_INT_BIAS: 36,
+ PROGRAM_3D_UINT_BIAS: 37,
+
+ PROGRAM_CUBE_ARRAY_FLOAT: 38,
+ PROGRAM_CUBE_ARRAY_INT: 39,
+ PROGRAM_CUBE_ARRAY_UINT: 40,
+ PROGRAM_CUBE_ARRAY_SHADOW: 41,
+
+ PROGRAM_BUFFER_FLOAT: 42,
+ PROGRAM_BUFFER_INT: 43,
+ PROGRAM_BUFFER_UINT: 44
+};
+
+/**
+ * @constructor
+ * @param {string} version GL version
+ * @param {gluShaderUtil.precision} precision
+ */
+glsTextureTestUtil.ProgramLibrary = function(version, precision) {
+ this.m_glslVersion = version;
+ this.m_texCoordPrecision = precision;
+};
+
+/**
+ * @param {glsTextureTestUtil.programType} program
+ * @return {gluShaderProgram.ShaderProgram}
+ */
+glsTextureTestUtil.ProgramLibrary.prototype.getProgram = function(program) {
+ /* TODO: Implement */
+ // if (m_programs.find(program) != m_programs.end())
+ // return m_programs[program]; // Return from cache.
+
+ var vertShaderTemplate =
+ '${VTX_HEADER}' +
+ '${VTX_IN} highp vec4 a_position;\n' +
+ '${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n' +
+ '${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n' +
+ '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' gl_Position = a_position;\n' +
+ ' v_texCoord = a_texCoord;\n' +
+ '}\n';
+ var fragShaderTemplate =
+ '${FRAG_HEADER}' +
+ '${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n' +
+ 'uniform ${PRECISION} float u_bias;\n' +
+ 'uniform ${PRECISION} float u_ref;\n' +
+ 'uniform ${PRECISION} vec4 u_colorScale;\n' +
+ 'uniform ${PRECISION} vec4 u_colorBias;\n' +
+ 'uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n' +
+ '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n' +
+ '}\n';
+
+ var params = [];
+
+ var isCube = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT, glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS);
+ var isArray = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW) ||
+ deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW);
+
+ var is1D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS) ||
+ deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW) ||
+ deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT, glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT);
+
+ var is2D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS) ||
+ deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW);
+
+ var is3D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_3D_FLOAT, glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS);
+ var isCubeArray = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW);
+ var isBuffer = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT, glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT);
+
+ if (this.m_glslVersion === '100 es') {
+ params['FRAG_HEADER'] = '';
+ params['VTX_HEADER'] = '';
+ params['VTX_IN'] = 'attribute';
+ params['VTX_OUT'] = 'varying';
+ params['FRAG_IN'] = 'varying';
+ params['FRAG_COLOR'] = 'gl_FragColor';
+ } else if (this.m_glslVersion === '300 es' || this.m_glslVersion === '310 es' || this.m_glslVersion === '330 es') {
+ var ext = null;
+
+ // if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
+ // ext = "gl.EXT_texture_cube_map_array";
+ // else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
+ // ext = "gl.EXT_texture_buffer";
+
+ var extension = '';
+ if (ext)
+ extension = '\n#extension ' + ext + ' : require';
+
+ params['FRAG_HEADER'] = '#version ' + this.m_glslVersion + extension + '\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+ params['VTX_HEADER'] = '#version ' + this.m_glslVersion + '\n';
+ params['VTX_IN'] = 'in';
+ params['VTX_OUT'] = 'out';
+ params['FRAG_IN'] = 'in';
+ params['FRAG_COLOR'] = 'dEQP_FragColor';
+ } else
+ throw new Error('Unsupported version: ' + this.m_glslVersion);
+
+ params['PRECISION'] = gluShaderUtil.getPrecisionName(this.m_texCoordPrecision);
+
+ if (isCubeArray)
+ params['TEXCOORD_TYPE'] = 'vec4';
+ else if (isCube || (is2D && isArray) || is3D)
+ params['TEXCOORD_TYPE'] = 'vec3';
+ else if ((is1D && isArray) || is2D)
+ params['TEXCOORD_TYPE'] = 'vec2';
+ else if (is1D)
+ params['TEXCOORD_TYPE'] = 'float';
+ else
+ DE_ASSERT(false);
+
+ var sampler = null;
+ var lookup = null;
+
+ if (this.m_glslVersion === '300 es' || this.m_glslVersion === '310 es' || this.m_glslVersion === '330 es') {
+ switch (program) {
+ case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT: sampler = 'sampler2D'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_INT: sampler = 'isampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_UINT: sampler = 'usampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_SHADOW: sampler = 'sampler2DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS: sampler = 'sampler2D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_INT_BIAS: sampler = 'isampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS: sampler = 'usampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_SHADOW_BIAS: sampler = 'sampler2DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_FLOAT: sampler = 'sampler1D'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_INT: sampler = 'isampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_UINT: sampler = 'usampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_SHADOW: sampler = 'sampler1DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_FLOAT_BIAS: sampler = 'sampler1D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_INT_BIAS: sampler = 'isampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS: sampler = 'usampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_SHADOW_BIAS: sampler = 'sampler1DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT: sampler = 'samplerCube'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_INT: sampler = 'isamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_UINT: sampler = 'usamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW: sampler = 'samplerCubeShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS: sampler = 'samplerCube'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_INT_BIAS: sampler = 'isamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_UINT_BIAS: sampler = 'usamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS: sampler = 'samplerCubeShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT: sampler = 'sampler2DArray'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_INT: sampler = 'isampler2DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_UINT: sampler = 'usampler2DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW: sampler = 'sampler2DArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_FLOAT: sampler = 'sampler3D'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_INT: sampler = 'isampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_UINT: sampler = ' usampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_FLOAT_BIAS: sampler = 'sampler3D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_INT_BIAS: sampler = 'isampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS: sampler = ' usampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT: sampler = 'samplerCubeArray'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_INT: sampler = 'isamplerCubeArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_UINT: sampler = 'usamplerCubeArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW: sampler = 'samplerCubeArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT: sampler = 'sampler1DArray'; lookup = 'texture(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_INT: sampler = 'isampler1DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_UINT: sampler = 'usampler1DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW: sampler = 'sampler1DArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT: sampler = 'samplerBuffer'; lookup = 'texelFetch(u_sampler, int(v_texCoord))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_BUFFER_INT: sampler = 'isamplerBuffer'; lookup = 'vec4(texelFetch(u_sampler, int(v_texCoord)))'; break;
+ case glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT: sampler = 'usamplerBuffer'; lookup = 'vec4(texelFetch(u_sampler, int(v_texCoord)))'; break;
+ default:
+ DE_ASSERT(false);
+ }
+ } else if (this.m_glslVersion === '100 es') {
+ sampler = isCube ? 'samplerCube' : 'sampler2D';
+
+ switch (program) {
+ case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT: lookup = 'texture2D(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS: lookup = 'texture2D(u_sampler, v_texCoord, u_bias)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT: lookup = 'textureCube(u_sampler, v_texCoord)'; break;
+ case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS: lookup = 'textureCube(u_sampler, v_texCoord, u_bias)'; break;
+ default:
+ DE_ASSERT(false);
+ }
+ } else
+ DE_ASSERT(!'Unsupported version');
+
+ params['SAMPLER_TYPE'] = sampler;
+ params['LOOKUP'] = lookup;
+
+ var vertSrc = tcuStringTemplate.specialize(vertShaderTemplate, params);
+ var fragSrc = tcuStringTemplate.specialize(fragShaderTemplate, params);
+ var progObj = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertSrc, fragSrc));
+ // if (!progObj.isOk()) {
+ // // log << *progObj;
+ // testFailedOptions("Failed to create shader", true);
+ // }
+
+ // try
+ // {
+ // m_programs[program] = progObj;
+ // }
+ // catch (...)
+ // {
+ // delete progObj;
+ // throw;
+ // }
+
+ return progObj;
+};
+
+// public:
+// glsTextureTestUtil.ProgramLibrary (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision);
+// ~glsTextureTestUtil.ProgramLibrary (void);
+
+// glu::ShaderProgram* getProgram (Program program);
+// void clear (void);
+
+// private:
+// glsTextureTestUtil.ProgramLibrary (const glsTextureTestUtil.ProgramLibrary& other);
+// glsTextureTestUtil.ProgramLibrary& operator= (const glsTextureTestUtil.ProgramLibrary& other);
+
+// const glu::RenderContext& m_context;
+// tcu::TestContext& m_testCtx;
+// glu::GLSLVersion m_glslVersion;
+// glu::Precision m_texCoordPrecision;
+// std::map<Program, glu::ShaderProgram*> m_programs;
+// };
+
+/**
+ * @constructor
+ * @param {string} version GL version
+ * @param {gluShaderUtil.precision} precision
+ */
+glsTextureTestUtil.TextureRenderer = function(version, precision) {
+ this.m_programLibrary = new glsTextureTestUtil.ProgramLibrary(version, precision);
+};
+
+/**
+ * @param {tcuPixelFormat.PixelFormat} format
+ * @return {Array<boolean>}
+ */
+glsTextureTestUtil.getCompareMask = function(format) {
+ return [
+ format.redBits > 0,
+ format.greenBits > 0,
+ format.blueBits > 0,
+ format.alphaBits > 0
+ ];
+};
+
+/**
+ * @param {tcuPixelFormat.PixelFormat} format
+ * @return {Array<number>}
+ */
+glsTextureTestUtil.getBitsVec = function(format) {
+ return [
+ format.redBits,
+ format.greenBits,
+ format.blueBits,
+ format.alphaBits
+ ];
+};
+
+/**
+ * @param {number} texUnit
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.RenderParams} params
+ */
+glsTextureTestUtil.TextureRenderer.prototype.renderQuad = function(texUnit, texCoord, params) {
+ var wCoord = params.flags.projected ? params.w : [1, 1, 1, 1];
+ var useBias = params.flags.use_bias;
+ var logUniforms = params.flags.log_uniforms;
+
+ // Render quad with texture.
+ var position = [
+ -1 * wCoord[0], -1 * wCoord[0], 0, wCoord[0],
+ -1 * wCoord[1], +1 * wCoord[1], 0, wCoord[1],
+ +1 * wCoord[2], -1 * wCoord[2], 0, wCoord[2],
+ +1 * wCoord[3], +1 * wCoord[3], 0, wCoord[3]
+ ];
+ /** @const */ var indices = [0, 1, 2, 2, 1, 3];
+
+ /** @type {?glsTextureTestUtil.programType} */ var progSpec = null;
+ var numComps = 0;
+ if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_2D) {
+ numComps = 2;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_1D) {
+ numComps = 1;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_CUBE) {
+ numComps = 3;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_3D) {
+ numComps = 3;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_UINT; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_2D_ARRAY) {
+ DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
+
+ numComps = 3;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_CUBE_ARRAY) {
+ DE_ASSERT(!useBias);
+
+ numComps = 4;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_1D_ARRAY) {
+ DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
+
+ numComps = 2;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_UINT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_BUFFER) {
+ numComps = 1;
+
+ switch (params.samplerType) {
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_INT; break;
+ case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT; break;
+ default: throw new Error('Unrecognized sampler type:' + params.samplerType);
+ }
+ } else
+ throw new Error('Unrecognized texture type:' + params.texType);
+
+ if (progSpec === null)
+ throw new Error('Could not find program specification');
+
+ var program = this.m_programLibrary.getProgram(progSpec);
+
+ // \todo [2012-09-26 pyry] Move to glsTextureTestUtil.ProgramLibrary and log unique programs only(?)
+ /* TODO: Port logging
+ if (params.flags.log_programs)
+ log << *program;
+ */
+
+ // Program and uniforms.
+ var prog = program.getProgram();
+ gl.useProgram(prog);
+
+ var loc = gl.getUniformLocation(prog, 'u_sampler');
+ gl.uniform1i(loc, texUnit);
+ // if (logUniforms)
+ // log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
+
+ if (useBias) {
+ gl.uniform1f(gl.getUniformLocation(prog, 'u_bias'), params.bias);
+ // if (logUniforms)
+ // log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
+ }
+
+ if (params.samplerType == glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW) {
+ gl.uniform1f(gl.getUniformLocation(prog, 'u_ref'), params.ref);
+ // if (logUniforms)
+ // log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
+ }
+
+ gl.uniform4fv(gl.getUniformLocation(prog, 'u_colorScale'), params.colorScale);
+ gl.uniform4fv(gl.getUniformLocation(prog, 'u_colorBias'), params.colorBias);
+
+ // if (logUniforms)
+ // {
+ // log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
+ // log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
+ // }
+ var vertexArrays = [];
+
+ var posLoc = gl.getAttribLocation(prog, 'a_position');
+ if (posLoc === -1) {
+ testFailedOptions("no location found for attribute 'a_position'", true);
+ }
+ var texLoc = gl.getAttribLocation(prog, 'a_texCoord');
+ if (texLoc === -1) {
+ testFailedOptions("no location found for attribute 'a_texCoord'", true);
+ }
+
+ vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, posLoc, 4, 4, position));
+ vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, texLoc, numComps, 4, texCoord));
+ gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
+};
+
+// public:
+// glsTextureTestUtil.TextureRenderer (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision);
+// ~glsTextureTestUtil.TextureRenderer (void);
+
+// void clear (void); //!< Frees allocated resources. Destructor will call clear() as well.
+
+// void renderQuad (int texUnit, const float* texCoord, TextureType texType);
+// void renderQuad (int texUnit, const float* texCoord, const glsTextureTestUtil.RenderParams& params);
+
+// private:
+// glsTextureTestUtil.TextureRenderer (const glsTextureTestUtil.TextureRenderer& other);
+// glsTextureTestUtil.TextureRenderer& operator= (const glsTextureTestUtil.TextureRenderer& other);
+
+// const glu::RenderContext& m_renderCtx;
+// tcu::TestContext& m_testCtx;
+// glsTextureTestUtil.ProgramLibrary m_programLibrary;
+// };
+
+/**
+ * @constructor
+ * @param {tcuSurface.Surface} surface
+ * @param {tcuPixelFormat.PixelFormat=} colorFmt
+ * @param {number=} x
+ * @param {number=} y
+ * @param {number=} width
+ * @param {number=} height
+ */
+glsTextureTestUtil.SurfaceAccess = function(surface, colorFmt, x, y, width, height) {
+ this.m_surface = surface;
+ this.colorMask = undefined; /*TODO*/
+ this.m_x = x || 0;
+ this.m_y = y || 0;
+ this.m_width = width || surface.getWidth();
+ this.m_height = height || surface.getHeight();
+};
+
+/** @return {number} */
+glsTextureTestUtil.SurfaceAccess.prototype.getWidth = function() { return this.m_width; };
+/** @return {number} */
+glsTextureTestUtil.SurfaceAccess.prototype.getHeight = function() { return this.m_height; };
+
+/**
+ * @param {Array<number>} color
+ * @param {number} x
+ * @param {number} y
+ */
+glsTextureTestUtil.SurfaceAccess.prototype.setPixel = function(color, x, y) {
+ /* TODO: Apply color mask */
+ var c = color;
+ for (var i = 0; i < c.length; i++)
+ c[i] = deMath.clamp(Math.round(color[i] * 255), 0, 255);
+ this.m_surface.setPixel(x, y, c);
+};
+
+/**
+ * @param {glsTextureTestUtil.lodMode} mode
+ * @param {number} dudx
+ * @param {number} dvdx
+ * @param {number} dwdx
+ * @param {number} dudy
+ * @param {number} dvdy
+ * @param {number} dwdy
+ * @return {number}
+ */
+glsTextureTestUtil.computeLodFromDerivates3D = function(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy) {
+ var p = 0;
+ switch (mode) {
+ case glsTextureTestUtil.lodMode.EXACT:
+ p = Math.max(Math.sqrt(dudx * dudx + dvdx * dvdx + dwdx * dwdx), Math.sqrt(dudy * dudy + dvdy * dvdy + dwdy * dwdy));
+ break;
+
+ case glsTextureTestUtil.lodMode.MIN_BOUND:
+ case glsTextureTestUtil.lodMode.MAX_BOUND: {
+ var mu = Math.max(Math.abs(dudx), Math.abs(dudy));
+ var mv = Math.max(Math.abs(dvdx), Math.abs(dvdy));
+ var mw = Math.max(Math.abs(dwdx), Math.abs(dwdy));
+
+ p = (mode == glsTextureTestUtil.lodMode.MIN_BOUND) ? Math.max(mu, mv, mw) : mu + mv + mw;
+ break;
+ }
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ // Native dEQP uses 32-bit numbers. So here 64-bit floating numbers should be transformed into 32-bit ones to ensure the correctness of the result.
+ return deMath.toFloat32(Math.log(p)) * deMath.INV_LOG_2_FLOAT32;
+};
+
+/**
+ * @param {glsTextureTestUtil.lodMode} mode
+ * @param {Array<number>} dstSize
+ * @param {Array<number>} srcSize
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {Array<number>=} rq
+ * @return {number}
+ */
+glsTextureTestUtil.computeNonProjectedTriLod = function(mode, dstSize, srcSize, sq, tq, rq) {
+ var dux = (sq[2] - sq[0]) * srcSize[0];
+ var duy = (sq[1] - sq[0]) * srcSize[0];
+ var dvx = (tq[2] - tq[0]) * srcSize[1];
+ var dvy = (tq[1] - tq[0]) * srcSize[1];
+ var dwx = 0;
+ var dwy = 0;
+ if (rq) {
+ dwx = (rq[2] - rq[0]) * srcSize[2];
+ dwy = (rq[1] - rq[0]) * srcSize[2];
+ }
+ var dx = dstSize[0];
+ var dy = dstSize[1];
+
+ return glsTextureTestUtil.computeLodFromDerivates3D(mode, dux / dx, dvx / dx, dwx / dx, duy / dy, dvy / dy, dwy / dy);
+};
+
+/**
+ * @param {Array<number>} v
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+glsTextureTestUtil.triangleInterpolate = function(v, x, y) {
+ return v[0] + (v[2] - v[0]) * x + (v[1] - v[0]) * y;
+};
+
+/**
+ * @param {Array<number>} s
+ * @param {Array<number>} w
+ * @param {number} wx
+ * @param {number} width
+ * @param {number} ny
+ * @return {number}
+ */
+glsTextureTestUtil.triDerivateX = function(s, w, wx, width, ny) {
+ var d = w[1] * w[2] * (width * (ny - 1) + wx) - w[0] * (w[2] * width * ny + w[1] * wx);
+ return (w[0] * w[1] * w[2] * width * (w[1] * (s[0] - s[2]) * (ny - 1) + ny * (w[2] * (s[1] - s[0]) + w[0] * (s[2] - s[1])))) / (d * d);
+};
+
+/**
+ * @param {Array<number>} s
+ * @param {Array<number>} w
+ * @param {number} wy
+ * @param {number} height
+ * @param {number} nx
+ * @return {number}
+ */
+glsTextureTestUtil.triDerivateY = function(s, w, wy, height, nx) {
+ var d = w[1] * w[2] * (height * (nx - 1) + wy) - w[0] * (w[1] * height * nx + w[2] * wy);
+ return (w[0] * w[1] * w[2] * height * (w[2] * (s[0] - s[1]) * (nx - 1) + nx * (w[0] * (s[1] - s[2]) + w[1] * (s[2] - s[0])))) / (d * d);
+};
+
+/**
+ * @param {(tcuTexture.Texture2DView|tcuTexture.Texture2DArrayView|tcuTexture.TextureCubeView)} src
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ * @param {Array<number>} texCoord Texture coordinates
+ * @param {number} lod
+ * @return {Array<number>} sample
+ */
+glsTextureTestUtil.execSample = function(src, params, texCoord, lod) {
+ if (params.samplerType == glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW)
+ return [src.sampleCompare(params.sampler, params.ref, texCoord, lod), 0, 0, 1];
+ else
+ return src.sample(params.sampler, texCoord, lod);
+};
+
+/**
+ * @param {Array<number>} pixel
+ * @param {Array<number>} scale
+ * @param {Array<number>} bias
+ */
+glsTextureTestUtil.applyScaleAndBias = function(pixel, scale, bias) {
+ pixel[0] = pixel[0] * scale[0] + bias[0];
+ pixel[1] = pixel[1] * scale[1] + bias[1];
+ pixel[2] = pixel[2] * scale[2] + bias[2];
+ pixel[3] = pixel[3] * scale[3] + bias[3];
+};
+
+/**
+ * @param {Array<number>} pixel
+ * @param {Array<number>} scale
+ * @param {Array<number>} bias
+ */
+glsTextureTestUtil.deapplyScaleAndBias = function(pixel, scale, bias) {
+ pixel[0] = (pixel[0] - bias[0]) / scale[0];
+ pixel[1] = (pixel[1] - bias[1]) / scale[1];
+ pixel[2] = (pixel[2] - bias[2]) / scale[2];
+ pixel[3] = (pixel[3] - bias[3]) / scale[3];
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture2DView} src
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureProjected2D = function(dst, src, sq, tq, params) {
+ /** @type {number} */ var lodBias = params.flags.use_bias ? params.bias : 0.0;
+ /** @type {number} */ var dstW = dst.getWidth();
+ /** @type {number} */ var dstH = dst.getHeight();
+
+ /** @type {Array<number>} */ var uq = deMath.scale(sq, src.getWidth());
+ /** @type {Array<number>} */ var vq = deMath.scale(tq, src.getHeight());
+
+ /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triU = [deMath.swizzle(uq, [0, 1, 2]), deMath.swizzle(uq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triV = [deMath.swizzle(vq, [0, 1, 2]), deMath.swizzle(vq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(params.w, [0, 1, 2]), deMath.swizzle(params.w, [3, 2, 1])];
+
+ for (var py = 0; py < dst.getHeight(); py++) {
+ for (var px = 0; px < dst.getWidth(); px++) {
+ /** @type {number} */ var wx = px + 0.5;
+ /** @type {number} */ var wy = py + 0.5;
+ /** @type {number} */ var nx = wx / dstW;
+ /** @type {number} */ var ny = wy / dstH;
+
+ /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ /** @type {number} */ var triWx = triNdx ? dstW - wx : wx;
+ /** @type {number} */ var triWy = triNdx ? dstH - wy : wy;
+ /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx;
+ /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny;
+
+ /** @type {number} */ var s = glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
+ /** @type {number} */ var t = glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
+ /** @type {number} */ var lod = glsTextureTestUtil.computeProjectedTriLod2D(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, dst.getWidth(), dst.getHeight()) + lodBias;
+
+ var pixel = glsTextureTestUtil.execSample(src, params, [s, t], lod);
+ glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias);
+ dst.setPixel(pixel, px, py);
+ }
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.lodMode} mode
+ * @param {Array<number>} u
+ * @param {Array<number>} v
+ * @param {Array<number>} projection
+ * @param {number} wx
+ * @param {number} wy
+ * @param {number} width
+ * @param {number} height
+ * @return {number}
+ */
+glsTextureTestUtil.computeProjectedTriLod2D = function(mode, u, v, projection, wx, wy, width, height) {
+ // Exact derivatives.
+ /** @type {number} */ var dudx = glsTextureTestUtil.triDerivateX(u, projection, wx, width, wy / height);
+ /** @type {number} */ var dvdx = glsTextureTestUtil.triDerivateX(v, projection, wx, width, wy / height);
+ /** @type {number} */ var dudy = glsTextureTestUtil.triDerivateY(u, projection, wy, height, wx / width);
+ /** @type {number} */ var dvdy = glsTextureTestUtil.triDerivateY(v, projection, wy, height, wx / width);
+
+ return glsTextureTestUtil.computeLodFromDerivates2D(mode, dudx, dvdx, dudy, dvdy);
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture2DView} src
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureNonProjected2D = function(dst, src, sq, tq, params) {
+ var lodBias = params.flags.use_bias ? params.bias : 0;
+
+ var dstSize = [dst.getWidth(), dst.getHeight()];
+ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triLod = [deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias), params.minLod, params.maxLod),
+ deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias), params.minLod, params.maxLod)];
+
+
+ for (var y = 0; y < dst.getHeight(); y++) {
+ for (var x = 0; x < dst.getWidth(); x++) {
+ var yf = (y + 0.5) / dst.getHeight();
+ var xf = (x + 0.5) / dst.getWidth();
+
+ var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule.
+ var triX = triNdx ? 1 - xf : xf;
+ var triY = triNdx ? 1 - yf : yf;
+
+ var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY);
+ var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY);
+ var lod = triLod[triNdx];
+
+ var pixel = glsTextureTestUtil.execSample(src, params, [s, t], lod);
+ glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias);
+ dst.setPixel(pixel, x, y);
+ }
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture2DArrayView} src
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {Array<number>} rq
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureNonProjected2DArray = function(dst, src, sq, tq, rq, params) {
+ var lodBias = (params.flags.use_bias) ? params.bias : 0;
+
+ var dstSize = [dst.getWidth(), dst.getHeight()];
+ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triLod = [glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
+ glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias];
+
+ for (var y = 0; y < dst.getHeight(); y++) {
+ for (var x = 0; x < dst.getWidth(); x++) {
+ var yf = (y + 0.5) / dst.getHeight();
+ var xf = (x + 0.5) / dst.getWidth();
+
+ var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule.
+ var triX = triNdx ? 1 - xf : xf;
+ var triY = triNdx ? 1 - yf : yf;
+
+ var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY);
+ var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY);
+ var r = glsTextureTestUtil.triangleInterpolate(triR[triNdx], triX, triY);
+ var lod = triLod[triNdx];
+
+ var pixel = glsTextureTestUtil.execSample(src, params, [s, t, r], lod);
+ glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias);
+ dst.setPixel(pixel, x, y);
+ }
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture2DView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTexture2D = function(dst, src, texCoord, params) {
+ var view = src.getSubView(params.baseLevel, params.maxLevel);
+ var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]];
+
+ if (params.flags.projected)
+ glsTextureTestUtil.sampleTextureProjected2D(dst, view, sq, tq, params);
+ else
+ glsTextureTestUtil.sampleTextureNonProjected2D(dst, view, sq, tq, params);
+};
+
+/**
+ * @param {glsTextureTestUtil.lodMode} mode
+ * @param {number} dudx
+ * @param {number} dvdx
+ * @param {number} dudy
+ * @param {number} dvdy
+ * @return {number}
+ */
+glsTextureTestUtil.computeLodFromDerivates2D = function(mode, dudx, dvdx, dudy, dvdy) {
+ var p = 0;
+ switch (mode) {
+ case glsTextureTestUtil.lodMode.EXACT:
+ p = Math.max(Math.sqrt(dudx * dudx + dvdx * dvdx), Math.sqrt(dudy * dudy + dvdy * dvdy));
+ break;
+
+ case glsTextureTestUtil.lodMode.MIN_BOUND:
+ case glsTextureTestUtil.lodMode.MAX_BOUND: {
+ var mu = Math.max(Math.abs(dudx), Math.abs(dudy));
+ var mv = Math.max(Math.abs(dvdx), Math.abs(dvdy));
+
+ p = (mode == glsTextureTestUtil.lodMode.MIN_BOUND) ? Math.max(mu, mv) : mu + mv;
+ break;
+ }
+
+ default:
+ throw new Error('Unrecognized mode:' + mode);
+ }
+
+ // Native dEQP uses 32-bit numbers. So here 64-bit floating numbers should be transformed into 32-bit ones to ensure the correctness of the result.
+ return deMath.toFloat32(Math.log(p)) * deMath.INV_LOG_2_FLOAT32;
+};
+
+/**
+ * @param {glsTextureTestUtil.lodMode} lodModeParm
+ * @param {Array<number>} coord
+ * @param {Array<number>} coordDx
+ * @param {Array<number>} coordDy
+ * @param {number} faceSize
+ * @return {number}
+ */
+glsTextureTestUtil.computeCubeLodFromDerivates = function(lodModeParm, coord, coordDx, coordDy, faceSize) {
+ var face = tcuTexture.selectCubeFace(coord);
+ var maNdx = 0;
+ var sNdx = 0;
+ var tNdx = 0;
+
+ // \note Derivate signs don't matter when computing lod
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
+ default:
+ throw new Error('Unrecognized face ' + face);
+ } {
+ var sc = coord[sNdx];
+ var tc = coord[tNdx];
+ var ma = Math.abs(coord[maNdx]);
+ var scdx = coordDx[sNdx];
+ var tcdx = coordDx[tNdx];
+ var madx = Math.abs(coordDx[maNdx]);
+ var scdy = coordDy[sNdx];
+ var tcdy = coordDy[tNdx];
+ var mady = Math.abs(coordDy[maNdx]);
+ var dudx = faceSize * 0.5 * (scdx * ma - sc * madx) / (ma * ma);
+ var dvdx = faceSize * 0.5 * (tcdx * ma - tc * madx) / (ma * ma);
+ var dudy = faceSize * 0.5 * (scdy * ma - sc * mady) / (ma * ma);
+ var dvdy = faceSize * 0.5 * (tcdy * ma - tc * mady) / (ma * ma);
+ return glsTextureTestUtil.computeLodFromDerivates2D(lodModeParm, dudx, dvdx, dudy, dvdy);
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.TextureCubeView} src
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {Array<number>} rq
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureCube_str = function(dst, src, sq, tq, rq, params) {
+ var dstSize = [dst.getWidth(), dst.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = src.getSize();
+
+ // Coordinates per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triW = [deMath.swizzle(params.w, [0, 1, 2]), deMath.swizzle(params.w, [3, 2, 1])];
+
+ var lodBias = (params.flags.use_bias ? params.bias : 0);
+
+ for (var py = 0; py < dst.getHeight(); py++) {
+ for (var px = 0; px < dst.getWidth(); px++) {
+ var wx = px + 0.5;
+ var wy = py + 0.5;
+ var nx = wx / dstW;
+ var ny = wy / dstH;
+ var triNdx = nx + ny >= 1 ? 1 : 0;
+ var triNx = triNdx ? 1 - nx : nx;
+ var triNy = triNdx ? 1 - ny : ny;
+
+ var coord = [glsTextureTestUtil.triangleInterpolate(triS[triNdx], triNx, triNy),
+ glsTextureTestUtil.triangleInterpolate(triT[triNdx], triNx, triNy),
+ glsTextureTestUtil.triangleInterpolate(triR[triNdx], triNx, triNy)];
+ var coordDx = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)];
+ var coordDy = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)];
+
+ var lod = deMath.clamp((glsTextureTestUtil.computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias), params.minLod, params.maxLod);
+
+ var pixel = glsTextureTestUtil.execSample(src, params, coord, lod);
+ glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias);
+ dst.setPixel(pixel, px, py);
+ }
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.TextureCubeView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureCube = function(dst, src, texCoord, params) {
+ /*const tcu::TextureCubeView*/ var view = src.getSubView(params.baseLevel, params.maxLevel);
+ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ glsTextureTestUtil.sampleTextureCube_str(dst, view, sq, tq, rq, params);
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture2DArrayView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTexture2DArray = function(dst, src, texCoord, params) {
+ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ DE_ASSERT(!(params.flags.projected)); // \todo [2012-02-17 pyry] Support projected lookups.
+ glsTextureTestUtil.sampleTextureNonProjected2DArray(dst, src, sq, tq, rq, params);
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture3DView} src
+ * @param {Array<number>} sq
+ * @param {Array<number>} tq
+ * @param {Array<number>} rq
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTextureNonProjected3D = function(dst, src, sq, tq, rq, params) {
+ var lodBias = params.flags.use_bias ? params.bias : 0;
+
+ var dstSize = [dst.getWidth(), dst.getHeight()];
+ var srcSize = [src.getWidth(), src.getHeight(), src.getDepth()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triLod = [deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias), params.minLod, params.maxLod),
+ deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias), params.minLod, params.maxLod)];
+
+ for (var y = 0; y < dst.getHeight(); y++) {
+ for (var x = 0; x < dst.getWidth(); x++) {
+ var yf = (y + 0.5) / dst.getHeight();
+ var xf = (x + 0.5) / dst.getWidth();
+
+ var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule.
+ var triX = triNdx ? 1 - xf : xf;
+ var triY = triNdx ? 1 - yf : yf;
+
+ var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY);
+ var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY);
+ var r = glsTextureTestUtil.triangleInterpolate(triR[triNdx], triX, triY);
+ var lod = triLod[triNdx];
+
+ var pixel = src.sample(params.sampler, [s, t, r], lod);
+ glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias);
+ dst.setPixel(pixel, x, y);
+ }
+ }
+};
+
+/**
+ * @param {glsTextureTestUtil.SurfaceAccess} dst
+ * @param {tcuTexture.Texture3DView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} params
+ */
+glsTextureTestUtil.sampleTexture3D = function(dst, src, texCoord, params) {
+ /*const tcu::TextureCubeView*/ var view = src.getSubView(params.baseLevel, params.maxLevel);
+ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ glsTextureTestUtil.sampleTextureNonProjected3D(dst, view, sq, tq, rq, params);
+};
+
+/**
+ * @param {tcuSurface.Surface} reference
+ * @param {tcuSurface.Surface} rendered
+ * @param {Array<number>} threshold
+ * @param {Array< Array<number> >} skipPixels
+ *
+ * @return {boolean}
+ */
+glsTextureTestUtil.compareImages = function(reference, rendered, threshold, skipPixels) {
+ return tcuImageCompare.pixelThresholdCompare('Result', 'Image comparison result', reference, rendered, threshold, undefined /*tcu::COMPARE_LOG_RESULT*/, skipPixels);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.Texture2DView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {tcuPixelFormat.PixelFormat} pixelFormat
+ * @return {boolean}
+ */
+glsTextureTestUtil.verifyTexture2DResult = function(result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat) {
+ DE_ASSERT(deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask));
+ /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ /** @type {number} */ var numFailedPixels;
+
+ /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat);
+
+ glsTextureTestUtil.sampleTexture2D(surface, src, texCoord, sampleParams);
+ numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff2D(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec/*, testCtx.getWatchDog()*/);
+
+ if (numFailedPixels > 0)
+ tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess());
+
+ return numFailedPixels == 0;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.Texture2DView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {Array<number>} nonShadowThreshold
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureCompareDiff2D = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) {
+ DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+ DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+ var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]];
+
+ var dstSize = [result.getWidth(), result.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])];
+
+ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0];
+ var numFailed = 0;
+
+ var lodOffsets = [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ];
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ errorMask.clear(green);
+
+ /** @type {Array<number>} */ var red = [];
+ for (var py = 0; py < result.getHeight(); py++) {
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+
+ if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(refPix, [1, 2, 3]), deMath.swizzle(resPix, [1, 2, 3])), nonShadowThreshold))) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ continue;
+ }
+
+ if (resPix[0] != refPix[0]) {
+ var wx = px + 0.5;
+ var wy = py + 0.5;
+ var nx = wx / dstW;
+ var ny = wy / dstH;
+
+ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ var triWx = triNdx ? dstW - wx : wx;
+ var triWy = triNdx ? dstH - wy : wy;
+ var triNx = triNdx ? 1.0 - nx : nx;
+ var triNy = triNdx ? 1.0 - ny : ny;
+
+ var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)];
+ var coordDx = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize);
+ var coordDy = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize);
+
+ var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec);
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) {
+ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ var nxo = wxo / dstW;
+ var nyo = wyo / dstH;
+
+ var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)];
+ var coordDxo = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize);
+ var coordDyo = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize);
+ var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec);
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec);
+ var isOk = tcuTexCompareVerifier.isTexCompareResultValid2D(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]);
+
+ if (!isOk) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.Texture3DView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {tcuPixelFormat.PixelFormat} pixelFormat
+ * @return {boolean}
+ */
+glsTextureTestUtil.verifyTexture3DResult = function(
+ result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat
+) {
+ /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ var numFailedPixels = 0;
+
+ assertMsgOptions(
+ deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask),
+ 'Compare color masks do not match', false, true
+ );
+
+ /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat);
+ glsTextureTestUtil.sampleTexture3D(surface, src, texCoord, sampleParams);
+ numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff3D(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec);
+
+ if (numFailedPixels > 0)
+ tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess());
+
+ return numFailedPixels == 0;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.Texture3DView} baseView
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureLookupDiff3D = function(
+ result, reference, errorMask, baseView, texCoord,
+ sampleParams, lookupPrec, lodPrec
+) {
+ assertMsgOptions(
+ result.getWidth() == reference.getWidth() &&
+ result.getHeight() == reference.getHeight(),
+ 'Result and reference images are not the same size', false, true
+ );
+ assertMsgOptions(
+ result.getWidth() == errorMask.getWidth() &&
+ result.getHeight() == errorMask.getHeight(),
+ 'Result and error mask images are not the same size', false, true
+ );
+
+ /** @type {tcuTexture.Texture3DView} */
+ var src = baseView.getSubView(
+ sampleParams.baseLevel, sampleParams.maxLevel
+ );
+
+ var sq =
+ [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq =
+ [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq =
+ [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ var dstSize = [result.getWidth(), result.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = [src.getWidth(), src.getHeight(), src.getDepth()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triW = [
+ deMath.swizzle(sampleParams.w, [0, 1, 2]),
+ deMath.swizzle(sampleParams.w, [3, 2, 1])
+ ];
+
+ var lodBias = sampleParams.flags.useBias ? sampleParams.bias : 0.0;
+
+ var posEps = 1.0 / ((1 << MIN_SUBPIXEL_BITS) + 1);
+
+ var numFailed = 0;
+
+ var lodOffsets = [
+ [-1, 0],
+ [+1, 0],
+ [0, -1],
+ [0, +1]
+ ];
+
+ var green = [0, 255, 0, 255];
+ errorMask.clear(new tcuRGBA.RGBA(green).toVec());
+
+ for (var py = 0; py < result.getHeight(); py++) {
+ // Ugly hack, validation can take way too long at the moment.
+ /*TODO: if (watchDog)
+ qpWatchDog_touch(watchDog);*/
+
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias);
+
+ // Try comparison to ideal reference first,
+ // and if that fails use slower verificator.
+ if (!deMath.boolAll(deMath.lessThanEqual(
+ deMath.absDiff(resPix, refPix),
+ lookupPrec.colorThreshold))
+ ) {
+ /** @type {number} */ var wx = px + 0.5;
+ /** @type {number} */ var wy = py + 0.5;
+ /** @type {number} */ var nx = wx / dstW;
+ /** @type {number} */ var ny = wy / dstH;
+
+ /** @type {boolean} */ var tri0 = nx + ny - posEps <= 1.0;
+ /** @type {boolean} */ var tri1 = nx + ny + posEps >= 1.0;
+
+ var isOk = false;
+
+ assertMsgOptions(
+ tri0 || tri1,
+ 'Pixel should belong at least to one triangle',
+ false, true
+ );
+
+ // Pixel can belong to either of the triangles
+ // if it lies close enough to the edge.
+ for (var triNdx = (tri0 ? 0 : 1);
+ triNdx <= (tri1 ? 1 : 0);
+ triNdx++) {
+ var triWx = triNdx ? dstW - wx : wx;
+ var triWy = triNdx ? dstH - wy : wy;
+ var triNx = triNdx ? 1.0 - nx : nx;
+ var triNy = triNdx ? 1.0 - ny : ny;
+
+ var coord = [
+ glsTextureTestUtil.projectedTriInterpolate(
+ triS[triNdx], triW[triNdx], triNx, triNy
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triT[triNdx], triW[triNdx], triNx, triNy
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triR[triNdx], triW[triNdx], triNx, triNy
+ )
+ ];
+ var coordDx = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(
+ triS[triNdx], triW[triNdx], wx, dstW, triNy
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triT[triNdx], triW[triNdx], wx, dstW, triNy
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triR[triNdx], triW[triNdx], wx, dstW, triNy
+ )
+ ], srcSize);
+ var coordDy = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(
+ triS[triNdx], triW[triNdx], wy, dstH, triNx
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triT[triNdx], triW[triNdx], wy, dstH, triNx
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triR[triNdx], triW[triNdx], wy, dstH, triNx
+ )
+ ], srcSize);
+
+ var lodBounds =
+ tcuTexLookupVerifier.computeLodBoundsFromDerivates(
+ coordDx[0], coordDx[1], coordDx[2],
+ coordDy[0], coordDy[1], coordDy[2], lodPrec
+ );
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0;
+ lodOffsNdx < lodOffsets.length;
+ lodOffsNdx++) {
+ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ var nxo = wxo / dstW;
+ var nyo = wyo / dstH;
+
+ var coordO = [
+ glsTextureTestUtil.projectedTriInterpolate(
+ triS[triNdx], triW[triNdx], nxo, nyo
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triT[triNdx], triW[triNdx], nxo, nyo
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triR[triNdx], triW[triNdx], nxo, nyo
+ )
+ ];
+ var coordDxo = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(
+ triS[triNdx], triW[triNdx], wxo, dstW, nyo
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triT[triNdx], triW[triNdx], wxo, dstW, nyo
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triR[triNdx], triW[triNdx], wxo, dstW, nyo
+ )
+ ], srcSize);
+ var coordDyo = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(
+ triS[triNdx], triW[triNdx], wyo, dstH, nxo
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triT[triNdx], triW[triNdx], wyo, dstH, nxo
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triR[triNdx], triW[triNdx], wyo, dstH, nxo
+ )
+ ], srcSize);
+ var lodO =
+ tcuTexLookupVerifier.computeLodBoundsFromDerivates(
+ coordDxo[0], coordDxo[1], coordDxo[2],
+ coordDyo[0], coordDyo[1], coordDyo[2], lodPrec
+ );
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ var clampedLod = tcuTexLookupVerifier.clampLodBounds(
+ deMath.addScalar(lodBounds, lodBias),
+ [sampleParams.minLod, sampleParams.maxLod],
+ lodPrec
+ );
+
+ if (
+ tcuTexLookupVerifier.isLookupResultValid(
+ src, sampleParams.sampler, lookupPrec,
+ coord, clampedLod, resPix
+ )
+ ) {
+ isOk = true;
+ break;
+ }
+ }
+
+ if (!isOk) {
+ var red = [255, 0, 0, 255];
+ errorMask.setPixel(new tcuRGBA.RGBA(red).toVec(), px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.TextureCubeView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {tcuPixelFormat.PixelFormat} pixelFormat
+ * @return {boolean}
+ */
+glsTextureTestUtil.verifyTextureCubeResult = function(
+ result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat
+) {
+ /** @type {tcuSurface.Surface} */
+ var reference = new tcuSurface.Surface(
+ result.getWidth(), result.getHeight()
+ );
+ /** @type {tcuSurface.Surface} */
+ var errorMask = new tcuSurface.Surface(
+ result.getWidth(), result.getHeight()
+ );
+ /** @type {number} */ var numFailedPixels = 0;
+
+ assertMsgOptions(
+ deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask),
+ 'Compare color masks do not match', false, true
+ );
+
+ /** @type {glsTextureTestUtil.SurfaceAccess} */
+ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat);
+
+ glsTextureTestUtil.sampleTextureCube(
+ surface, src, texCoord, sampleParams
+ );
+
+ numFailedPixels = glsTextureTestUtil.computeTextureLookupDiffCube(
+ result, reference.getAccess(), errorMask.getAccess(),
+ src, texCoord, sampleParams, lookupPrec, lodPrec
+ /*, testCtx.getWatchDog()*/
+ );
+
+ if (numFailedPixels > 0)
+ tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess());
+
+ return numFailedPixels == 0;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.TextureCubeView} baseView
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureLookupDiffCube = function(
+ result, reference, errorMask, baseView, texCoord,
+ sampleParams, lookupPrec, lodPrec
+) {
+ assertMsgOptions(
+ result.getWidth() == reference.getWidth() &&
+ result.getHeight() == reference.getHeight(),
+ 'Result and reference images are not the same size', false, true
+ );
+ assertMsgOptions(
+ result.getWidth() == errorMask.getWidth() &&
+ result.getHeight() == errorMask.getHeight(),
+ 'Result and error mask images are not the same size', false, true
+ );
+
+ /** @type {tcuTexture.TextureCubeView} */
+ var src = baseView.getSubView(
+ sampleParams.baseLevel, sampleParams.maxLevel
+ );
+
+ var sq =
+ [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq =
+ [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq =
+ [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ var dstSize = [result.getWidth(), result.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = [src.getSize(), src.getSize()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triW = [
+ deMath.swizzle(sampleParams.w, [0, 1, 2]),
+ deMath.swizzle(sampleParams.w, [3, 2, 1])
+ ];
+
+ var lodBias = sampleParams.flags.useBias ? sampleParams.bias : 0.0;
+
+ var posEps = 1.0 / ((1 << MIN_SUBPIXEL_BITS) + 1);
+
+ var numFailed = 0;
+
+ var lodOffsets = [
+ [-1, 0],
+ [+1, 0],
+ [0, -1],
+ [0, +1],
+
+ // \note Not strictly allowed by spec,
+ // but implementations do this in practice.
+ [-1, -1],
+ [-1, 1],
+ [1, -1],
+ [1, 1]
+ ];
+
+ var green = [0, 255, 0, 255];
+ errorMask.clear(new tcuRGBA.RGBA(green).toVec());
+
+ for (var py = 0; py < result.getHeight(); py++) {
+ // Ugly hack, validation can take way too long at the moment.
+ /*TODO: if (watchDog)
+ qpWatchDog_touch(watchDog);*/
+
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias);
+
+ // Try comparison to ideal reference first,
+ // and if that fails use slower verificator.
+ if (!deMath.boolAll(deMath.lessThanEqual(
+ deMath.absDiff(resPix, refPix),
+ lookupPrec.colorThreshold))
+ ) {
+ /** @type {number} */ var wx = px + 0.5;
+ /** @type {number} */ var wy = py + 0.5;
+ /** @type {number} */ var nx = wx / dstW;
+ /** @type {number} */ var ny = wy / dstH;
+
+ /** @type {boolean} */ var tri0 = nx + ny - posEps <= 1.0;
+ /** @type {boolean} */ var tri1 = nx + ny + posEps >= 1.0;
+
+ var isOk = false;
+
+ assertMsgOptions(
+ tri0 || tri1,
+ 'Pixel should belong at least to one triangle',
+ false, true
+ );
+
+ // Pixel can belong to either of the triangles
+ // if it lies close enough to the edge.
+ for (var triNdx = (tri0 ? 0 : 1);
+ triNdx <= (tri1 ? 1 : 0);
+ triNdx++) {
+ var triWx = triNdx ? dstW - wx : wx;
+ var triWy = triNdx ? dstH - wy : wy;
+ var triNx = triNdx ? 1.0 - nx : nx;
+ var triNy = triNdx ? 1.0 - ny : ny;
+
+ var coord = [
+ glsTextureTestUtil.projectedTriInterpolate(
+ triS[triNdx], triW[triNdx], triNx, triNy
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triT[triNdx], triW[triNdx], triNx, triNy
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triR[triNdx], triW[triNdx], triNx, triNy
+ )
+ ];
+ var coordDx = [
+ glsTextureTestUtil.triDerivateX(
+ triS[triNdx], triW[triNdx], wx, dstW, triNy
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triT[triNdx], triW[triNdx], wx, dstW, triNy
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triR[triNdx], triW[triNdx], wx, dstW, triNy
+ )
+ ];
+ var coordDy = [
+ glsTextureTestUtil.triDerivateY(
+ triS[triNdx], triW[triNdx], wy, dstH, triNx
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triT[triNdx], triW[triNdx], wy, dstH, triNx
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triR[triNdx], triW[triNdx], wy, dstH, triNx
+ )
+ ];
+
+ var lodBounds =
+ tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates(
+ coord, coordDx, coordDy, src.getSize(), lodPrec
+ );
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0;
+ lodOffsNdx < lodOffsets.length;
+ lodOffsNdx++) {
+ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ var nxo = wxo / dstW;
+ var nyo = wyo / dstH;
+
+ var coordO = [
+ glsTextureTestUtil.projectedTriInterpolate(
+ triS[triNdx], triW[triNdx], nxo, nyo
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triT[triNdx], triW[triNdx], nxo, nyo
+ ),
+ glsTextureTestUtil.projectedTriInterpolate(
+ triR[triNdx], triW[triNdx], nxo, nyo
+ )
+ ];
+ var coordDxo = [
+ glsTextureTestUtil.triDerivateX(
+ triS[triNdx], triW[triNdx], wxo, dstW, nyo
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triT[triNdx], triW[triNdx], wxo, dstW, nyo
+ ),
+ glsTextureTestUtil.triDerivateX(
+ triR[triNdx], triW[triNdx], wxo, dstW, nyo
+ )
+ ];
+ var coordDyo = [
+ glsTextureTestUtil.triDerivateY(
+ triS[triNdx], triW[triNdx], wyo, dstH, nxo
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triT[triNdx], triW[triNdx], wyo, dstH, nxo
+ ),
+ glsTextureTestUtil.triDerivateY(
+ triR[triNdx], triW[triNdx], wyo, dstH, nxo
+ )
+ ];
+ var lodO =
+ tcuTexLookupVerifier.
+ computeCubeLodBoundsFromDerivates(
+ coordO, coordDxo, coordDyo,
+ src.getSize(), lodPrec
+ );
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ var clampedLod = tcuTexLookupVerifier.clampLodBounds(
+ deMath.addScalar(lodBounds, lodBias),
+ [sampleParams.minLod, sampleParams.maxLod],
+ lodPrec
+ );
+
+ if (tcuTexLookupVerifier.
+ isLookupResultValid_TextureCubeView(
+ src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix
+ )
+ ) {
+ isOk = true;
+ break;
+ }
+ }
+
+ if (!isOk) {
+ var red = [255, 0, 0, 255];
+ errorMask.setPixel(new tcuRGBA.RGBA(red).toVec(), px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.Texture2DArrayView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {tcuPixelFormat.PixelFormat} pixelFormat
+ * @return {boolean}
+ */
+glsTextureTestUtil.verifyTexture2DArrayResult = function(result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat) {
+ DE_ASSERT(deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask));
+ /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight());
+ /** @type {number} */ var numFailedPixels;
+
+ /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat);
+
+ glsTextureTestUtil.sampleTexture2DArray(surface, src, texCoord, sampleParams);
+ numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff2DArray(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec/*, testCtx.getWatchDog()*/);
+
+ if (numFailedPixels > 0)
+ tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess());
+
+ return numFailedPixels == 0;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.Texture2DArrayView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {Array<number>} nonShadowThreshold
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureCompareDiff2DArray = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) {
+ DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+ DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ var dstSize = [result.getWidth(), result.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])];
+
+ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0];
+ var numFailed = 0;
+
+ var lodOffsets = [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ];
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ errorMask.clear(green);
+
+ /** @type {Array<number>} */ var red = [];
+ for (var py = 0; py < result.getHeight(); py++) {
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+
+ if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(refPix, [1, 2, 3]), deMath.swizzle(resPix, [1, 2, 3])), nonShadowThreshold))) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ continue;
+ }
+
+ if (resPix[0] != refPix[0]) {
+ var wx = px + 0.5;
+ var wy = py + 0.5;
+ var nx = wx / dstW;
+ var ny = wy / dstH;
+
+ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ var triWx = triNdx ? dstW - wx : wx;
+ var triWy = triNdx ? dstH - wy : wy;
+ var triNx = triNdx ? 1.0 - nx : nx;
+ var triNy = triNdx ? 1.0 - ny : ny;
+
+ var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)];
+ var coordDx = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize);
+ var coordDy = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize);
+
+ var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec);
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) {
+ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ var nxo = wxo / dstW;
+ var nyo = wyo / dstH;
+
+ var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)];
+ var coordDxo = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize);
+ var coordDyo = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize);
+ var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec);
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec);
+ var isOk = tcuTexCompareVerifier.isTexCompareResultValid2DArray(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]);
+
+ if (!isOk) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.TextureCubeView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {Array<number>} nonShadowThreshold
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureCompareDiffCube = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) {
+ DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+ DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ var dstSize = [result.getWidth(), result.getHeight()];
+ var dstW = dstSize[0];
+ var dstH = dstSize[1];
+ var srcSize = src.getSize();
+
+ // Coordinates per triangle.
+ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])];
+
+ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0];
+ var numFailed = 0;
+
+ var lodOffsets = [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ];
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ errorMask.clear(new tcuRGBA.RGBA(green).toVec());
+
+ /** @type {Array<number>} */ var red = [];
+ for (var py = 0; py < result.getHeight(); py++) {
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+
+ if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(resPix, [1, 2, 3]), deMath.swizzle(refPix, [1, 2, 3])), nonShadowThreshold))) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ continue;
+ }
+
+ if (resPix[0] != refPix[0]) {
+ var wx = px + 0.5;
+ var wy = py + 0.5;
+ var nx = wx / dstW;
+ var ny = wy / dstH;
+
+ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ var triWx = triNdx ? dstW - wx : wx;
+ var triWy = triNdx ? dstH - wy : wy;
+ var triNx = triNdx ? 1.0 - nx : nx;
+ var triNy = triNdx ? 1.0 - ny : ny;
+
+ var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)];
+ var coordDx = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)];
+ var coordDy = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)];
+
+ var lodBounds = tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) {
+ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ var nxo = wxo / dstW;
+ var nyo = wyo / dstH;
+
+ var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)];
+ var coordDxo = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)];
+ var coordDyo = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)];
+ var lodO = tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec);
+ var isOk = tcuTexCompareVerifier.isTexCompareResultValidCube(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]);
+
+ if (!isOk) {
+ red = [255, 0, 0, 255];
+ errorMask.setPixel(red, px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+/**
+ * @param {Array<number>} s
+ * @param {Array<number>} w
+ * @param {number} nx
+ * @param {number} ny
+ * @return {number}
+ */
+glsTextureTestUtil.projectedTriInterpolate = function(s, w, nx, ny) {
+ return (s[0] * (1.0 - nx - ny) / w[0] + s[1] * ny / w[1] + s[2] * nx / w[2]) / ((1.0 - nx - ny) / w[0] + ny / w[1] + nx / w[2]);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.Texture2DView} baseView
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {*=} watchDog - TODO: ??
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureLookupDiff2D = function(result, reference, errorMask, baseView, texCoord, sampleParams, lookupPrec, lodPrec, watchDog) {
+ DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+ DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+ /** @type {tcuTexture.Texture2DView} */ var src = baseView.getSubView(sampleParams.baseLevel, sampleParams.maxLevel);
+
+ /** @type {Array<number>} */ var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]];
+ /** @type {Array<number>} */ var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]];
+
+ /** @type {Array<number>} */ var dstSize = [result.getWidth(), result.getHeight()];
+ /** @type {number} */ var dstW = dstSize[0];
+ /** @type {number} */ var dstH = dstSize[1];
+ /** @type {Array<number>} */ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])];
+
+ /** @type {Array<number>} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0];
+
+ /** @type {number} */ var numFailed = 0;
+
+ /** @type {Array<Array<number>>} */ var lodOffsets = [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ];
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ errorMask.clear(new tcuRGBA.RGBA(green).toVec());
+
+ for (var py = 0; py < result.getHeight(); py++) {
+ // Ugly hack, validation can take way too long at the moment.
+
+ // TODO:are we implementing qpWatchDog? skipping in the meantime
+ // if (watchDog)
+ // qpWatchDog_touch(watchDog);
+
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias);
+
+ // Try comparison to ideal reference first, and if that fails use slower verificator.
+ if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(resPix, refPix), lookupPrec.colorThreshold))) {
+ /** @type {number} */ var wx = px + 0.5;
+ /** @type {number} */ var wy = py + 0.5;
+ /** @type {number} */ var nx = wx / dstW;
+ /** @type {number} */ var ny = wy / dstH;
+
+ /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ /** @type {number} */ var triWx = triNdx ? dstW - wx : wx;
+ /** @type {number} */ var triWy = triNdx ? dstH - wy : wy;
+ /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx;
+ /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny;
+
+ /** @type {Array<number>} */ var coord = [
+ glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)
+ ];
+ /** @type {Array<number>} */ var coordDx = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize);
+ /** @type {Array<number>} */ var coordDy = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize);
+
+ /** @type {Array<number>} */
+ var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec);
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) {
+ /** @type {number} */ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ /** @type {number} */ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ /** @type {number} */ var nxo = wxo / dstW;
+ /** @type {number} */ var nyo = wyo / dstH;
+
+ /** @type {Array<number>} */ var coordO = [
+ glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)];
+ /** @type {Array<number>} */ var coordDxo = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize);
+ /** @type {Array<number>} */ var coordDyo = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize);
+ /** @type {Array<number>} */
+ var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec);
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ /** @type {Array<number>} */ var clampedLod = tcuTexLookupVerifier.clampLodBounds(
+ deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec);
+ /** @type {boolean} */
+ var isOk = tcuTexLookupVerifier.isLookupResultValid_Texture2DView(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
+
+ if (!isOk) {
+ /** @type {tcuRGBA.RGBA} */ var red = tcuRGBA.newRGBAComponents(255, 0, 0, 255);
+ errorMask.setPixel(red.toVec(), px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+// Verifies texture lookup results and returns number of failed pixels.
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.Texture2DArrayView} src
+ * @param {Array<number>} texCoord
+ * @param {glsTextureTestUtil.ReferenceParams} sampleParams
+ * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec
+ * @param {tcuTexLookupVerifier.LodPrecision} lodPrec
+ * @param {*=} watchDog - TODO: ??
+ * @return {number}
+ */
+glsTextureTestUtil.computeTextureLookupDiff2DArray = function(result, reference, errorMask, src, texCoord, sampleParams, lookupPrec, lodPrec, watchDog) {
+ DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
+ DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
+
+ /** @type {Array<number>} */ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]];
+ /** @type {Array<number>} */ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]];
+ /** @type {Array<number>} */ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]];
+
+ /** @type {Array<number>} */ var dstSize = [result.getWidth(), result.getHeight()];
+ /** @type {number} */ var dstW = dstSize[0];
+ /** @type {number} */ var dstH = dstSize[1];
+ /** @type {Array<number>} */ var srcSize = [src.getWidth(), src.getHeight()];
+
+ // Coordinates and lod per triangle.
+ /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])];
+ /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])];
+
+ /** @type {Array<number>} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0];
+
+ /** @type {number} */ var numFailed = 0;
+
+ /** @type {Array<Array<number>>} */ var lodOffsets = [
+ [-1, 0],
+ [1, 0],
+ [0, -1],
+ [0, 1]
+ ];
+
+ /** @type {Array<number>} */ var green = [0, 255, 0, 255];
+ errorMask.clear(new tcuRGBA.RGBA(green).toVec());
+
+ for (var py = 0; py < result.getHeight(); py++) {
+ // Ugly hack, validation can take way too long at the moment.
+
+ // TODO:are we implementing qpWatchDog? skipping in the meantime
+ // if (watchDog)
+ // qpWatchDog_touch(watchDog);
+
+ for (var px = 0; px < result.getWidth(); px++) {
+ /** @type {Array<number>} */
+ var resPix = result.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias);
+ /** @type {Array<number>} */
+ var refPix = reference.getPixel(px, py);
+ glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias);
+
+
+ // Try comparison to ideal reference first, and if that fails use slower verificator.
+ if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(resPix, refPix), lookupPrec.colorThreshold))) {
+ /** @type {number} */ var wx = px + 0.5;
+ /** @type {number} */ var wy = py + 0.5;
+ /** @type {number} */ var nx = wx / dstW;
+ /** @type {number} */ var ny = wy / dstH;
+
+ /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0;
+ /** @type {number} */ var triWx = triNdx ? dstW - wx : wx;
+ /** @type {number} */ var triWy = triNdx ? dstH - wy : wy;
+ /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx;
+ /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny;
+
+ /** @type {Array<number>} */ var coord = [
+ glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
+ glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)
+ ];
+ /** @type {Array<number>} */ var coordDx = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize);
+ /** @type {Array<number>} */ var coordDy = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize);
+
+ /** @type {Array<number>} */
+ var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec);
+
+ // Compute lod bounds across lodOffsets range.
+ for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) {
+ /** @type {number} */ var wxo = triWx + lodOffsets[lodOffsNdx][0];
+ /** @type {number} */ var wyo = triWy + lodOffsets[lodOffsNdx][1];
+ /** @type {number} */ var nxo = wxo / dstW;
+ /** @type {number} */ var nyo = wyo / dstH;
+
+ /** @type {Array<number>} */ var coordO = [
+ glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
+ glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)
+ ];
+ /** @type {Array<number>} */ var coordDxo = deMath.multiply([
+ glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
+ glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize
+ );
+ /** @type {Array<number>} */ var coordDyo = deMath.multiply([
+ glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
+ glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize
+ );
+ /** @type {Array<number>} */
+ var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec);
+
+ lodBounds[0] = Math.min(lodBounds[0], lodO[0]);
+ lodBounds[1] = Math.max(lodBounds[1], lodO[1]);
+ }
+
+ /** @type {Array<number>} */ var clampedLod = tcuTexLookupVerifier.clampLodBounds(
+ deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec);
+ /** @type {boolean} */
+ var isOk = tcuTexLookupVerifier.isLookupResultValid_Texture2DArrayView(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
+
+ if (!isOk) {
+ /** @type {tcuRGBA.RGBA} */ var red = tcuRGBA.newRGBAComponents(255, 0, 0, 255);
+ errorMask.setPixel(red.toVec(), px, py);
+ numFailed += 1;
+ }
+ }
+ }
+ }
+
+ return numFailed;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js
new file mode 100644
index 000000000..e9c45366a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js
@@ -0,0 +1,2451 @@
+/*-------------------------------------------------------------------------
+ * 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.glsUniformBlockCase');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.delibs.debase.deUtil');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+var glsUniformBlockCase = modules.shared.glsUniformBlockCase;
+var tcuTestCase = framework.common.tcuTestCase;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+var gluDrawUtil = framework.opengl.gluDrawUtil;
+var deUtil = framework.delibs.debase.deUtil;
+var deMath = framework.delibs.debase.deMath;
+var deRandom = framework.delibs.debase.deRandom;
+var deString = framework.delibs.debase.deString;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+var littleEndian = (function() {
+ var buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
+ // Int16Array uses the platform's endianness.
+ return new Int16Array(buffer)[0] === 256;
+})();
+
+/**
+ * Class to implement some pointers functionality.
+ * @constructor
+ */
+glsUniformBlockCase.BlockPointers = function() {
+ /** @type {ArrayBuffer} */ this.data; //!< Data (vector<deUint8>).
+ /** @type {Array<number>} */ this.offsets = []; //!< Reference block pointers (map<int, void*>).
+ /** @type {Array<number>} */ this.sizes = [];
+};
+
+/**
+ * push - Adds an offset/size pair to the collection
+ * @param {number} offset Offset of the element to refer.
+ * @param {number} size Size of the referred element.
+ */
+glsUniformBlockCase.BlockPointers.prototype.push = function(offset, size) {
+ this.offsets.push(offset);
+ this.sizes.push(size);
+};
+
+/**
+ * find - Finds and maps the data at the given offset, and returns a Uint8Array
+ * @param {number} index of the element to find.
+ * @return {Uint8Array}
+ */
+glsUniformBlockCase.BlockPointers.prototype.find = function(index) {
+ return new Uint8Array(this.data, this.offsets[index], this.sizes[index]);
+};
+
+/**
+ * resize - Replaces resize of a vector in C++. Sets the size of the data buffer.
+ * NOTE: In this case however, if you resize, the data is lost.
+ * @param {number} newsize The new size of the data buffer.
+ */
+glsUniformBlockCase.BlockPointers.prototype.resize = function(newsize) {
+ this.data = new ArrayBuffer(newsize);
+};
+
+/**
+ * glsUniformBlockCase.isSupportedGLSLVersion
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {boolean}
+ */
+glsUniformBlockCase.isSupportedGLSLVersion = function(version) {
+ return version >= gluShaderUtil.GLSLVersion.V300_ES;
+};
+
+/**
+ * @enum {number}
+ */
+glsUniformBlockCase.UniformFlags = {
+ PRECISION_LOW: (1 << 0),
+ PRECISION_MEDIUM: (1 << 1),
+ PRECISION_HIGH: (1 << 2),
+
+ LAYOUT_SHARED: (1 << 3),
+ LAYOUT_PACKED: (1 << 4),
+ LAYOUT_STD140: (1 << 5),
+ LAYOUT_ROW_MAJOR: (1 << 6),
+ LAYOUT_COLUMN_MAJOR: (1 << 7), //!< \note Lack of both flags means column-major matrix.
+
+ DECLARE_VERTEX: (1 << 8),
+ DECLARE_FRAGMENT: (1 << 9),
+
+ UNUSED_VERTEX: (1 << 10), //!< glsUniformBlockCase.Uniform or struct member is not read in vertex shader.
+ UNUSED_FRAGMENT: (1 << 11) //!< glsUniformBlockCase.Uniform or struct member is not read in fragment shader.
+};
+
+/** @const */ glsUniformBlockCase.UniformFlags.PRECISION_MASK = glsUniformBlockCase.UniformFlags.PRECISION_LOW | glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM | glsUniformBlockCase.UniformFlags.PRECISION_HIGH;
+/** @const */ glsUniformBlockCase.UniformFlags.LAYOUT_MASK = glsUniformBlockCase.UniformFlags.LAYOUT_SHARED | glsUniformBlockCase.UniformFlags.LAYOUT_PACKED | glsUniformBlockCase.UniformFlags.LAYOUT_STD140 | glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR | glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR;
+/** @const */ glsUniformBlockCase.UniformFlags.DECLARE_BOTH = glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT;
+/** @const */ glsUniformBlockCase.UniformFlags.UNUSED_BOTH = glsUniformBlockCase.UniformFlags.UNUSED_VERTEX | glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT;
+
+/**
+* glsUniformBlockCase.VarType types enum
+* @enum {number}
+*/
+glsUniformBlockCase.Type = {
+ TYPE_BASIC: 0,
+ TYPE_ARRAY: 1,
+ TYPE_STRUCT: 2
+};
+
+glsUniformBlockCase.Type.TYPE_LAST = Object.keys(glsUniformBlockCase.Type).length;
+
+/**
+* glsUniformBlockCase.TypeArray struct (nothing to do with JS's TypedArrays)
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @constructor
+*/
+glsUniformBlockCase.TypeArray = function(elementType, arraySize) {
+ /** @type {glsUniformBlockCase.VarType} */ this.elementType = elementType;
+ /** @type {number} */ this.size = arraySize;
+};
+
+/**
+ * glsUniformBlockCase.VarType class
+ * @constructor
+ */
+glsUniformBlockCase.VarType = function() {
+ /** @type {glsUniformBlockCase.Type} */ this.m_type;
+ /** @type {number} */ this.m_flags = 0;
+
+ /*
+ * m_data used to be a 'Data' union in C++. Using a var is enough here.
+ * it will contain any necessary value.
+ */
+
+ /** @type {(gluShaderUtil.DataType|glsUniformBlockCase.TypeArray|glsUniformBlockCase.StructType)} */
+ this.m_data;
+};
+
+/**
+* Creates a basic type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {gluShaderUtil.DataType} basicType
+* @param {number} flags
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeBasic = function(basicType, flags) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_BASIC;
+ this.m_flags = flags;
+ this.m_data = basicType;
+
+ return this;
+};
+
+/**
+* Creates an array type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeArray = function(elementType, arraySize) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_ARRAY;
+ this.m_flags = 0;
+ this.m_data = new glsUniformBlockCase.TypeArray(elementType, arraySize);
+
+ return this;
+};
+
+/**
+* Creates a struct type glsUniformBlockCase.VarType. Use this after the constructor call.
+* @param {glsUniformBlockCase.StructType} structPtr
+* @return {glsUniformBlockCase.VarType} The currently modified object
+*/
+glsUniformBlockCase.VarType.prototype.VarTypeStruct = function(structPtr) {
+ this.m_type = glsUniformBlockCase.Type.TYPE_STRUCT;
+ this.m_flags = 0;
+ this.m_data = structPtr;
+
+ return this;
+};
+
+/** isBasicType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents a basic type.
+**/
+glsUniformBlockCase.VarType.prototype.isBasicType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_BASIC;
+};
+
+/** isArrayType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents an array.
+**/
+glsUniformBlockCase.VarType.prototype.isArrayType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_ARRAY;
+};
+
+/** isStructType
+* @return {boolean} true if the glsUniformBlockCase.VarType represents a struct.
+**/
+glsUniformBlockCase.VarType.prototype.isStructType = function() {
+ return this.m_type == glsUniformBlockCase.Type.TYPE_STRUCT;
+};
+
+/** getFlags
+* @return {number} returns the flags of the glsUniformBlockCase.VarType.
+**/
+glsUniformBlockCase.VarType.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** getBasicType
+* @return {gluShaderUtil.DataType} returns the basic data type of the glsUniformBlockCase.VarType.
+**/
+glsUniformBlockCase.VarType.prototype.getBasicType = function() {
+ return /** @type {gluShaderUtil.DataType} */ (this.m_data);
+};
+
+/** getElementType
+* @return {glsUniformBlockCase.VarType} returns the glsUniformBlockCase.VarType of the element in case of an Array.
+**/
+glsUniformBlockCase.VarType.prototype.getElementType = function() {
+ return this.m_data.elementType;
+};
+
+/** getArraySize
+* (not to be confused with a javascript array)
+* @return {number} returns the size of the array in case it is an array.
+**/
+glsUniformBlockCase.VarType.prototype.getArraySize = function() {
+ return this.m_data.size;
+};
+
+/** getStruct
+* @return {glsUniformBlockCase.StructType} returns the structure when it is a glsUniformBlockCase.StructType.
+**/
+glsUniformBlockCase.VarType.prototype.getStruct = function() {
+ return /** @type {glsUniformBlockCase.StructType} */ (this.m_data);
+};
+
+/**
+ * Creates a basic type glsUniformBlockCase.VarType.
+ * @param {gluShaderUtil.DataType} basicType
+ * @param {number} flags
+ * @return {glsUniformBlockCase.VarType}
+ */
+glsUniformBlockCase.newVarTypeBasic = function(basicType, flags) {
+ return new glsUniformBlockCase.VarType().VarTypeBasic(basicType, flags);
+};
+
+/**
+* Creates an array type glsUniformBlockCase.VarType.
+* @param {glsUniformBlockCase.VarType} elementType
+* @param {number} arraySize
+* @return {glsUniformBlockCase.VarType}
+*/
+glsUniformBlockCase.newVarTypeArray = function(elementType, arraySize) {
+ return new glsUniformBlockCase.VarType().VarTypeArray(elementType, arraySize);
+};
+
+/**
+* Creates a struct type glsUniformBlockCase.VarType.
+* @param {glsUniformBlockCase.StructType} structPtr
+* @return {glsUniformBlockCase.VarType}
+*/
+glsUniformBlockCase.newVarTypeStruct = function(structPtr) {
+ return new glsUniformBlockCase.VarType().VarTypeStruct(structPtr);
+};
+
+/** glsUniformBlockCase.StructMember
+ * in the JSDoc annotations or if a number would do.
+ * @constructor
+**/
+glsUniformBlockCase.StructMember = function() {
+ /** @type {string} */ this.m_name;
+ /** @type {glsUniformBlockCase.VarType} */ this.m_type;
+ /** @type {number} */ this.m_flags = 0;
+};
+
+/**
+ * Creates a glsUniformBlockCase.StructMember. Use this after the constructor call.
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number} flags
+ * @return {glsUniformBlockCase.StructMember} The currently modified object
+ */
+glsUniformBlockCase.StructMember.prototype.Constructor = function(name, type, flags) {
+ this.m_type = type;
+ this.m_name = name;
+ this.m_flags = flags;
+
+ return this;
+};
+
+/** getName
+* @return {string} the name of the member
+**/
+glsUniformBlockCase.StructMember.prototype.getName = function() { return this.m_name; };
+
+/** getType
+* @return {glsUniformBlockCase.VarType} the type of the member
+**/
+glsUniformBlockCase.StructMember.prototype.getType = function() { return this.m_type; };
+
+/** getFlags
+* @return {number} the flags in the member
+**/
+glsUniformBlockCase.StructMember.prototype.getFlags = function() { return this.m_flags; };
+
+/**
+ * Creates a glsUniformBlockCase.StructMember with name, type and flags.
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @return {glsUniformBlockCase.StructMember}
+ */
+ glsUniformBlockCase.newStructMember = function(name, type, flags) {
+ return new glsUniformBlockCase.StructMember().Constructor(name, type, flags);
+ };
+
+/**
+ * glsUniformBlockCase.StructType
+ * @constructor
+ */
+glsUniformBlockCase.StructType = function() {
+ /** @type {string}*/ this.m_typeName;
+ /** @type {Array<glsUniformBlockCase.StructMember>} */ this.m_members = [];
+};
+
+/**
+ * glsUniformBlockCase.StructType - Constructor with type name
+ * @param {string} typeName
+ * @return {glsUniformBlockCase.StructType} The currently modified object.
+ */
+glsUniformBlockCase.StructType.prototype.Constructor = function(typeName) {
+ /** @type {string}*/ this.m_typeName = typeName;
+ return this;
+};
+
+/** getTypeName
+* @return {string}
+**/
+glsUniformBlockCase.StructType.prototype.getTypeName = function() {
+ return this.m_typeName;
+};
+
+/*
+ * Instead of iterators, we'll add
+ * a getter for a specific element (getMember),
+ * and current members amount (getSize).
+ */
+
+/** getMember
+* @param {number} memberNdx The index of the member to retrieve.
+* @return {glsUniformBlockCase.StructMember}
+**/
+glsUniformBlockCase.StructType.prototype.getMember = function(memberNdx) {
+ if (memberNdx >= 0 && memberNdx < this.m_members.length)
+ return this.m_members[memberNdx];
+ else {
+ throw new Error("Invalid member index for glsUniformBlockCase.StructType's members");
+ }
+};
+
+/** getSize
+* @return {number} The size of the m_members array.
+**/
+glsUniformBlockCase.StructType.prototype.getSize = function() {
+ return this.m_members.length;
+};
+
+/** addMember
+* @param {string} member_name
+* @param {glsUniformBlockCase.VarType} member_type
+* @param {number=} member_flags
+**/
+glsUniformBlockCase.StructType.prototype.addMember = function(member_name, member_type, member_flags) {
+ var member = glsUniformBlockCase.newStructMember(member_name, member_type, member_flags);
+
+ this.m_members.push(member);
+};
+
+/**
+ * Creates a glsUniformBlockCase.StructType.
+ * @param {string} name
+ * @return {glsUniformBlockCase.StructType}
+ */
+glsUniformBlockCase.newStructType = function(name) {
+ return new glsUniformBlockCase.StructType().Constructor(name);
+};
+
+/** glsUniformBlockCase.Uniform
+ * @param {string} name
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number=} flags
+ * @constructor
+**/
+glsUniformBlockCase.Uniform = function(name, type, flags) {
+ /** @type {string} */ this.m_name = name;
+ /** @type {glsUniformBlockCase.VarType} */ this.m_type = type;
+ /** @type {number} */ this.m_flags = (typeof flags === 'undefined') ? 0 : flags;
+};
+
+/** getName
+ * @return {string}
+ */
+glsUniformBlockCase.Uniform.prototype.getName = function() {
+ return this.m_name;
+};
+
+/** getType
+ * @return {glsUniformBlockCase.VarType}
+ */
+glsUniformBlockCase.Uniform.prototype.getType = function() {
+ return this.m_type;
+};
+
+/** getFlags
+* @return {number}
+**/
+glsUniformBlockCase.Uniform.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** glsUniformBlockCase.UniformBlock
+ * @param {string} blockName
+ * @constructor
+**/
+glsUniformBlockCase.UniformBlock = function(blockName) {
+ /** @type {string} */ this.m_blockName = blockName;
+ /** @type {string} */ this.m_instanceName;
+ /** @type {Array<glsUniformBlockCase.Uniform>} */ this.m_uniforms = [];
+ /** @type {number} */ this.m_arraySize = 0; //!< Array size or 0 if not interface block array.
+ /** @type {number} */ this.m_flags = 0;
+};
+
+/** getBlockName
+* @return {string}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getBlockName = function() {
+ return this.m_blockName;
+};
+
+/** getInstanceName
+* @return {string}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getInstanceName = function() {
+ return this.m_instanceName;
+};
+
+/** isArray
+* @return {boolean}
+**/
+glsUniformBlockCase.UniformBlock.prototype.isArray = function() {
+ return this.m_arraySize > 0;
+};
+
+/** getArraySize
+* @return {number}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getArraySize = function() {
+ return this.m_arraySize;
+};
+
+/** getFlags
+* @return {number}
+**/
+glsUniformBlockCase.UniformBlock.prototype.getFlags = function() {
+ return this.m_flags;
+};
+
+/** setInstanceName
+* @param {string} name
+**/
+glsUniformBlockCase.UniformBlock.prototype.setInstanceName = function(name) {
+ this.m_instanceName = name;
+};
+
+/** setFlags
+* @param {number} flags
+**/
+glsUniformBlockCase.UniformBlock.prototype.setFlags = function(flags) {
+ this.m_flags = flags;
+};
+
+/** setArraySize
+* @param {number} arraySize
+**/
+glsUniformBlockCase.UniformBlock.prototype.setArraySize = function(arraySize) {
+ this.m_arraySize = arraySize;
+};
+
+/** addUniform
+* @param {glsUniformBlockCase.Uniform} uniform
+**/
+glsUniformBlockCase.UniformBlock.prototype.addUniform = function(uniform) {
+ this.m_uniforms.push(uniform);
+};
+
+/*
+ * Using uniform getter (getUniform),
+ * and uniform array size getter (countUniforms)
+ * instead of iterators.
+*/
+
+/**
+ * getUniform
+ * @param {number} index
+ * @return {glsUniformBlockCase.Uniform}
+ */
+glsUniformBlockCase.UniformBlock.prototype.getUniform = function(index) {
+ if (index >= 0 && index < this.m_uniforms.length)
+ return this.m_uniforms[index];
+ else {
+ throw new Error("Invalid uniform index for glsUniformBlockCase.UniformBlock's uniforms");
+ }
+};
+
+/**
+ * countUniforms
+ * @return {number}
+ */
+glsUniformBlockCase.UniformBlock.prototype.countUniforms = function() {
+ return this.m_uniforms.length;
+};
+
+/**
+ * glsUniformBlockCase.ShaderInterface
+ * @constructor
+ */
+glsUniformBlockCase.ShaderInterface = function() {
+ /** @type {Array<glsUniformBlockCase.StructType>} */ this.m_structs = [];
+ /** @type {Array<glsUniformBlockCase.UniformBlock>} */ this.m_uniformBlocks = [];
+};
+
+/** allocStruct
+* @param {string} name
+* @return {glsUniformBlockCase.StructType}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.allocStruct = function(name) {
+ //m_structs.reserve(m_structs.length + 1);
+ this.m_structs.push(glsUniformBlockCase.newStructType(name));
+ return this.m_structs[this.m_structs.length - 1];
+};
+
+/** findStruct
+* @param {string} name
+* @return {glsUniformBlockCase.StructType}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.findStruct = function(name) {
+ for (var pos = 0; pos < this.m_structs.length; pos++) {
+ if (this.m_structs[pos].getTypeName() == name)
+ return this.m_structs[pos];
+ }
+ return null;
+};
+
+/** getNamedStructs
+* @param {Array<glsUniformBlockCase.StructType>} structs
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getNamedStructs = function(structs) {
+ for (var pos = 0; pos < this.m_structs.length; pos++) {
+ if (this.m_structs[pos].getTypeName() != undefined)
+ structs.push(this.m_structs[pos]);
+ }
+};
+
+/** allocBlock
+* @param {string} name
+* @return {glsUniformBlockCase.UniformBlock}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.allocBlock = function(name) {
+ this.m_uniformBlocks.push(new glsUniformBlockCase.UniformBlock(name));
+ return this.m_uniformBlocks[this.m_uniformBlocks.length - 1];
+};
+
+/** getNumUniformBlocks
+* @return {number}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getNumUniformBlocks = function() {
+ return this.m_uniformBlocks.length;
+};
+
+/** getUniformBlock
+* @param {number} ndx
+* @return {glsUniformBlockCase.UniformBlock}
+**/
+glsUniformBlockCase.ShaderInterface.prototype.getUniformBlock = function(ndx) {
+ return this.m_uniformBlocks[ndx];
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.BlockLayoutEntry = function() {
+ return {
+ /** @type {number} */ size: 0,
+ /** @type {string} */ name: '',
+ /** @type {Array<number>} */ activeUniformIndices: []
+ };
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformLayoutEntry = function() {
+ return {
+ /** @type {string} */ name: '',
+ /** @type {gluShaderUtil.DataType} */ type: gluShaderUtil.DataType.INVALID,
+ /** @type {number} */ size: 0,
+ /** @type {number} */ blockNdx: -1,
+ /** @type {number} */ offset: -1,
+ /** @type {number} */ arrayStride: -1,
+ /** @type {number} */ matrixStride: -1,
+ /** @type {boolean} */ isRowMajor: false
+ };
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformLayout = function() {
+ /** @type {Array<glsUniformBlockCase.BlockLayoutEntry>}*/ this.blocks = [];
+ /** @type {Array<glsUniformBlockCase.UniformLayoutEntry>}*/ this.uniforms = [];
+};
+
+/** getUniformIndex, returns a uniform index number in the layout,
+ * given the uniform's name.
+ * @param {string} name
+ * @return {number} uniform's index
+ */
+glsUniformBlockCase.UniformLayout.prototype.getUniformIndex = function(name) {
+ for (var ndx = 0; ndx < this.uniforms.length; ndx++) {
+ if (this.uniforms[ndx].name == name)
+ return ndx;
+ }
+ return -1;
+};
+
+/** getBlockIndex, returns a block index number in the layout,
+ * given the block's name.
+ * @param {string} name the name of the block
+ * @return {number} block's index
+ */
+glsUniformBlockCase.UniformLayout.prototype.getBlockIndex = function(name) {
+ for (var ndx = 0; ndx < this.blocks.length; ndx++) {
+ if (this.blocks[ndx].name == name)
+ return ndx;
+ }
+ return -1;
+};
+
+/**
+ * @enum {number}
+ */
+glsUniformBlockCase.BufferMode = {
+ BUFFERMODE_SINGLE: 0, //!< Single buffer shared between uniform blocks.
+ BUFFERMODE_PER_BLOCK: 1 //!< Per-block buffers
+};
+
+glsUniformBlockCase.BufferMode.BUFFERMODE_LAST = Object.keys(glsUniformBlockCase.BufferMode).length;
+
+/**
+ * glsUniformBlockCase.PrecisionFlagsFmt
+ * @param {number} flags
+ * @return {string}
+ */
+glsUniformBlockCase.PrecisionFlagsFmt = function(flags) {
+ // Precision.
+ DE_ASSERT(deMath.dePop32(flags & (glsUniformBlockCase.UniformFlags.PRECISION_LOW | glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM | glsUniformBlockCase.UniformFlags.PRECISION_HIGH)) <= 1);
+ var str = '';
+ str += (flags & glsUniformBlockCase.UniformFlags.PRECISION_LOW ? 'lowp' :
+ flags & glsUniformBlockCase.UniformFlags.PRECISION_MEDIUM ? 'mediump' :
+ flags & glsUniformBlockCase.UniformFlags.PRECISION_HIGH ? 'highp' : '');
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.LayoutFlagsFmt
+ * @param {number} flags_
+ * @return {string}
+ */
+glsUniformBlockCase.LayoutFlagsFmt = function(flags_) {
+ var str = '';
+ var bitDesc =
+ [{ bit: glsUniformBlockCase.UniformFlags.LAYOUT_SHARED, token: 'shared' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_PACKED, token: 'packed' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_STD140, token: 'std140' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR, token: 'row_major' }, { bit: glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR, token: 'column_major' }
+ ];
+
+ /** @type {number} */ var remBits = flags_;
+ for (var descNdx = 0; descNdx < bitDesc.length; descNdx++) {
+ if (remBits & bitDesc[descNdx].bit) {
+ if (remBits != flags_)
+ str += ', ';
+ str += bitDesc[descNdx].token;
+ remBits &= (~bitDesc[descNdx].bit) & 0xFFFFFFFF; //0xFFFFFFFF truncate to 32 bit value
+ }
+ }
+ DE_ASSERT(remBits == 0);
+
+ return str;
+};
+
+/**
+ * @constructor
+ */
+glsUniformBlockCase.UniformBufferManager = function(renderCtx) {
+ this.m_renderCtx = renderCtx;
+ /** @type {Array<number>} */ this.m_buffers = [];
+};
+
+/**
+ * allocBuffer
+ * @return {WebGLBuffer}
+ */
+glsUniformBlockCase.UniformBufferManager.prototype.allocBuffer = function() {
+ /** @type {WebGLBuffer} */ var buf = this.m_renderCtx.createBuffer();
+
+ this.m_buffers.push(buf);
+
+ return buf;
+};
+
+/**
+ * @param {string} name
+ * @param {string} description
+ * @param {glsUniformBlockCase.BufferMode} bufferMode
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ */
+glsUniformBlockCase.UniformBlockCase = function(name, description, bufferMode) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ /** @type {string} */ this.m_name = name;
+ /** @type {string} */ this.m_description = description;
+ /** @type {glsUniformBlockCase.BufferMode} */ this.m_bufferMode = bufferMode;
+ /** @type {glsUniformBlockCase.ShaderInterface} */ this.m_interface = new glsUniformBlockCase.ShaderInterface();
+};
+
+glsUniformBlockCase.UniformBlockCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+glsUniformBlockCase.UniformBlockCase.prototype.constructor = glsUniformBlockCase.UniformBlockCase;
+
+/**
+ * glsUniformBlockCase.getDataTypeByteSize
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeByteSize = function(type) {
+ return gluShaderUtil.getDataTypeScalarSize(type) * deMath.INT32_SIZE;
+};
+
+/**
+ * glsUniformBlockCase.getDataTypeByteAlignment
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeByteAlignment = function(type) {
+ switch (type) {
+ case gluShaderUtil.DataType.FLOAT:
+ case gluShaderUtil.DataType.INT:
+ case gluShaderUtil.DataType.UINT:
+ case gluShaderUtil.DataType.BOOL: return 1 * deMath.INT32_SIZE;
+
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.INT_VEC2:
+ case gluShaderUtil.DataType.UINT_VEC2:
+ case gluShaderUtil.DataType.BOOL_VEC2: return 2 * deMath.INT32_SIZE;
+
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.INT_VEC3:
+ case gluShaderUtil.DataType.UINT_VEC3:
+ case gluShaderUtil.DataType.BOOL_VEC3: // Fall-through to vec4
+
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ case gluShaderUtil.DataType.INT_VEC4:
+ case gluShaderUtil.DataType.UINT_VEC4:
+ case gluShaderUtil.DataType.BOOL_VEC4: return 4 * deMath.INT32_SIZE;
+
+ default:
+ DE_ASSERT(false);
+ return 0;
+ }
+};
+
+/**
+ * glsUniformBlockCase.getDataTypeArrayStride
+ * @param {gluShaderUtil.DataType} type
+ * @return {number}
+ */
+glsUniformBlockCase.getDataTypeArrayStride = function(type) {
+ DE_ASSERT(!gluShaderUtil.isDataTypeMatrix(type));
+
+ /** @type {number} */ var baseStride = glsUniformBlockCase.getDataTypeByteSize(type);
+ /** @type {number} */ var vec4Alignment = deMath.INT32_SIZE * 4;
+
+ DE_ASSERT(baseStride <= vec4Alignment);
+ return Math.max(baseStride, vec4Alignment); // Really? See rule 4.
+};
+
+/**
+ * glsUniformBlockCase.deRoundUp32 Rounds up 'a' in case the
+ * relationship with 'b' has a decimal part.
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+glsUniformBlockCase.deRoundUp32 = function(a, b) {
+ var d = Math.trunc(a / b);
+ return d * b == a ? a : (d + 1) * b;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140BaseAlignment
+ * @param {glsUniformBlockCase.VarType} type
+ * @return {number}
+ */
+glsUniformBlockCase.computeStd140BaseAlignment = function(type) {
+ /** @type {number} */ var vec4Alignment = deMath.INT32_SIZE * 4;
+
+ if (type.isBasicType()) {
+ /** @type {gluShaderUtil.DataType} */ var basicType = type.getBasicType();
+
+ if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ /** @type {boolean} */ var isRowMajor = !!(type.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ /** @type {number} */ var vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+
+ return glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+ } else
+ return glsUniformBlockCase.getDataTypeByteAlignment(basicType);
+ } else if (type.isArrayType()) {
+ /** @type {number} */ var elemAlignment = glsUniformBlockCase.computeStd140BaseAlignment(type.getElementType());
+
+ // Round up to alignment of vec4
+ return glsUniformBlockCase.deRoundUp32(elemAlignment, vec4Alignment);
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ /** @type {number} */ var maxBaseAlignment = 0;
+
+ for (var memberNdx = 0; memberNdx < type.getStruct().getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = type.getStruct().getMember(memberNdx);
+ maxBaseAlignment = Math.max(maxBaseAlignment, glsUniformBlockCase.computeStd140BaseAlignment(memberIter.getType()));
+ }
+
+ return glsUniformBlockCase.deRoundUp32(maxBaseAlignment, vec4Alignment);
+ }
+};
+
+/**
+ * mergeLayoutflags
+ * @param {number} prevFlags
+ * @param {number} newFlags
+ * @return {number}
+ */
+glsUniformBlockCase.mergeLayoutFlags = function(prevFlags, newFlags) {
+ /** @type {number} */ var packingMask = glsUniformBlockCase.UniformFlags.LAYOUT_PACKED | glsUniformBlockCase.UniformFlags.LAYOUT_SHARED | glsUniformBlockCase.UniformFlags.LAYOUT_STD140;
+ /** @type {number} */ var matrixMask = glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR | glsUniformBlockCase.UniformFlags.LAYOUT_COLUMN_MAJOR;
+
+ /** @type {number} */ var mergedFlags = 0;
+
+ mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
+ mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
+
+ return mergedFlags;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140Layout_B
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {number} curOffset
+ * @param {number} curBlockNdx
+ * @param {string} curPrefix
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {number} layoutFlags
+ * @return {number} //This is what would return in the curOffset output parameter in the original C++ project.
+ */
+glsUniformBlockCase.computeStd140Layout_B = function(layout, curOffset, curBlockNdx, curPrefix, type, layoutFlags) {
+ /** @type {number} */ var baseAlignment = glsUniformBlockCase.computeStd140BaseAlignment(type);
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry;
+ /** @type {number} */ var stride;
+ /** @type {gluShaderUtil.DataType} */ var elemBasicType;
+ /** @type {boolean} */ var isRowMajor;
+ /** @type {number} */ var vecSize;
+ /** @type {number} */ var numVecs;
+
+ curOffset = deMath.deAlign32(curOffset, baseAlignment);
+
+ if (type.isBasicType()) {
+ /** @type {gluShaderUtil.DataType} */ var basicType = type.getBasicType();
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+
+ entry.name = curPrefix;
+ entry.type = basicType;
+ entry.size = 1;
+ entry.arrayStride = 0;
+ entry.matrixStride = 0;
+ entry.blockNdx = curBlockNdx;
+
+ if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ // Array of vectors as specified in rules 5 & 7.
+ isRowMajor = !!(layoutFlags & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(basicType);
+ numVecs = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(basicType) :
+ gluShaderUtil.getDataTypeMatrixNumColumns(basicType);
+ stride = glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+
+ entry.offset = curOffset;
+ entry.matrixStride = stride;
+ entry.isRowMajor = isRowMajor;
+
+ curOffset += numVecs * stride;
+ } else {
+ // Scalar or vector.
+ entry.offset = curOffset;
+
+ curOffset += glsUniformBlockCase.getDataTypeByteSize(basicType);
+ }
+
+ layout.uniforms.push(entry);
+ } else if (type.isArrayType()) {
+ /** @type {glsUniformBlockCase.VarType} */ var elemType = type.getElementType();
+
+ if (elemType.isBasicType() && !gluShaderUtil.isDataTypeMatrix(elemType.getBasicType())) {
+ // Array of scalars or vectors.
+ elemBasicType = elemType.getBasicType();
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+ stride = glsUniformBlockCase.getDataTypeArrayStride(elemBasicType);
+
+ entry.name = curPrefix + '[0]'; // Array uniforms are always postfixed with [0]
+ entry.type = elemBasicType;
+ entry.blockNdx = curBlockNdx;
+ entry.offset = curOffset;
+ entry.size = type.getArraySize();
+ entry.arrayStride = stride;
+ entry.matrixStride = 0;
+
+ curOffset += stride * type.getArraySize();
+
+ layout.uniforms.push(entry);
+ } else if (elemType.isBasicType() && gluShaderUtil.isDataTypeMatrix(elemType.getBasicType())) {
+ // Array of matrices.
+ elemBasicType = elemType.getBasicType();
+ isRowMajor = !!(layoutFlags & glsUniformBlockCase.UniformFlags.LAYOUT_ROW_MAJOR);
+ vecSize = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(elemBasicType) :
+ gluShaderUtil.getDataTypeMatrixNumRows(elemBasicType);
+ numVecs = isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(elemBasicType) :
+ gluShaderUtil.getDataTypeMatrixNumColumns(elemBasicType);
+ stride = glsUniformBlockCase.getDataTypeArrayStride(gluShaderUtil.getDataTypeFloatVec(vecSize));
+ entry = new glsUniformBlockCase.UniformLayoutEntry();
+
+ entry.name = curPrefix + '[0]'; // Array uniforms are always postfixed with [0]
+ entry.type = elemBasicType;
+ entry.blockNdx = curBlockNdx;
+ entry.offset = curOffset;
+ entry.size = type.getArraySize();
+ entry.arrayStride = stride * numVecs;
+ entry.matrixStride = stride;
+ entry.isRowMajor = isRowMajor;
+
+ curOffset += numVecs * type.getArraySize() * stride;
+
+ layout.uniforms.push(entry);
+ } else {
+ DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
+
+ for (var elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, curBlockNdx, curPrefix + '[' + elemNdx + ']', type.getElementType(), layoutFlags);
+ }
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ for (var memberNdx = 0; memberNdx < type.getStruct().getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = type.getStruct().getMember(memberNdx);
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, curBlockNdx, curPrefix + '.' + memberIter.getName(), memberIter.getType(), layoutFlags);
+ }
+
+ curOffset = deMath.deAlign32(curOffset, baseAlignment);
+ }
+
+ return curOffset;
+};
+
+/**
+ * glsUniformBlockCase.computeStd140Layout
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.computeStd140Layout = function(layout, sinterface) {
+ // \todo [2012-01-23 pyry] Uniforms in default block.
+
+ /** @type {number} */ var numUniformBlocks = sinterface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var hasInstanceName = block.getInstanceName() !== undefined;
+ /** @type {string} */ var blockPrefix = hasInstanceName ? (block.getBlockName() + '.') : '';
+ /** @type {number} */ var curOffset = 0;
+ /** @type {number} */ var activeBlockNdx = layout.blocks.length;
+ /** @type {number} */ var firstUniformNdx = layout.uniforms.length;
+
+ for (var ubNdx = 0; ubNdx < block.countUniforms(); ubNdx++) {
+ /** @type {glsUniformBlockCase.Uniform} */ var uniform = block.getUniform(ubNdx);
+ curOffset = glsUniformBlockCase.computeStd140Layout_B(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(), glsUniformBlockCase.mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
+ }
+
+ /** @type {number} */ var uniformIndicesEnd = layout.uniforms.length;
+ /** @type {number} */ var blockSize = curOffset;
+ /** @type {number} */ var numInstances = block.isArray() ? block.getArraySize() : 1;
+
+ // Create block layout entries for each instance.
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ // Allocate entry for instance.
+ layout.blocks.push(new glsUniformBlockCase.BlockLayoutEntry());
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var blockEntry = layout.blocks[layout.blocks.length - 1];
+
+ blockEntry.name = block.getBlockName();
+ blockEntry.size = blockSize;
+
+ // Compute active uniform set for block.
+ for (var uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
+ blockEntry.activeUniformIndices.push(uniformNdx);
+
+ if (block.isArray())
+ blockEntry.name += '[' + instanceNdx + ']';
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.generateValue - Value generator
+ * @param {glsUniformBlockCase.UniformLayoutEntry} entry
+ * @param {Uint8Array} basePtr
+ * @param {deRandom.Random} rnd
+ */
+glsUniformBlockCase.generateValue = function(entry, basePtr, rnd) {
+ /** @type {gluShaderUtil.DataType}*/ var scalarType = gluShaderUtil.getDataTypeScalarTypeAsDataType(entry.type); //Using a more appropriate function in this case.
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(entry.type);
+ /** @type {boolean} */ var isMatrix = gluShaderUtil.isDataTypeMatrix(entry.type);
+ /** @type {number} */ var numVecs = isMatrix ? (entry.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(entry.type) : gluShaderUtil.getDataTypeMatrixNumColumns(entry.type)) : 1;
+ /** @type {number} */ var vecSize = scalarSize / numVecs;
+ /** @type {boolean} */ var isArray = entry.size > 1;
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+
+ DE_ASSERT(scalarSize % numVecs == 0);
+
+ for (var elemNdx = 0; elemNdx < entry.size; elemNdx++) {
+ /** @type {Uint8Array} */ var elemPtr = basePtr.subarray(entry.offset + (isArray ? elemNdx * entry.arrayStride : 0));
+
+ for (var vecNdx = 0; vecNdx < numVecs; vecNdx++) {
+ /** @type {Uint8Array} */ var vecPtr = elemPtr.subarray(isMatrix ? vecNdx * entry.matrixStride : 0);
+
+ for (var compNdx = 0; compNdx < vecSize; compNdx++) {
+ /** @type {Uint8Array} */ var compPtr = vecPtr.subarray(compSize * compNdx);
+ /** @type {number} */ var _random;
+
+ //Copy the random data byte per byte
+ var _size = glsUniformBlockCase.getDataTypeByteSize(scalarType);
+
+ var nbuffer = new ArrayBuffer(_size);
+ var nview = new DataView(nbuffer);
+
+ switch (scalarType) {
+ case gluShaderUtil.DataType.FLOAT:
+ _random = rnd.getInt(-9, 9);
+ nview.setFloat32(0, _random, littleEndian);
+ break;
+ case gluShaderUtil.DataType.INT:
+ _random = rnd.getInt(-9, 9);
+ nview.setInt32(0, _random, littleEndian);
+ break;
+ case gluShaderUtil.DataType.UINT:
+ _random = rnd.getInt(0, 9);
+ nview.setUint32(0, _random, littleEndian);
+ break;
+ // \note Random bit pattern is used for true values. Spec states that all non-zero values are
+ // interpreted as true but some implementations fail this.
+ case gluShaderUtil.DataType.BOOL:
+ _random = rnd.getBool() ? 1 : 0;
+ nview.setUint32(0, _random, littleEndian);
+ break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ for (var i = 0; i < _size; i++) {
+ compPtr[i] = nview.getUint8(i);
+ }
+ }
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.generateValues
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ * @param {number} seed
+ */
+glsUniformBlockCase.generateValues = function(layout, blockPointers, seed) {
+ /** @type  {deRandom.Random} */ var rnd = new deRandom.Random(seed);
+ /** @type  {number} */ var numBlocks = layout.blocks.length;
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {Uint8Array} */ var basePtr = blockPointers.find(blockNdx);
+ /** @type  {number} */ var numEntries = layout.blocks[blockNdx].activeUniformIndices.length;
+
+ for (var entryNdx = 0; entryNdx < numEntries; entryNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
+ glsUniformBlockCase.generateValue(entry, basePtr, rnd);
+ }
+ }
+};
+
+// Shader generator.
+
+/**
+ * glsUniformBlockCase.getCompareFuncForType
+ * @param {gluShaderUtil.DataType} type
+ * @return {string}
+ */
+glsUniformBlockCase.getCompareFuncForType = function(type) {
+ switch (type) {
+ case gluShaderUtil.DataType.FLOAT: return 'mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 'mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 'mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n';
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 'mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 'mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 'mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 'mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n';
+ case gluShaderUtil.DataType.INT: return 'mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC2: return 'mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC3: return 'mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.INT_VEC4: return 'mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT: return 'mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC2: return 'mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC3: return 'mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.UINT_VEC4: return 'mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL: return 'mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC2: return 'mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC3: return 'mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n';
+ case gluShaderUtil.DataType.BOOL_VEC4: return 'mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n';
+ default:
+ throw new Error('Type "' + type + '" not supported.');
+
+ }
+};
+
+/**
+ * glsUniformBlockCase.getCompareDependencies
+ * @param {Array<gluShaderUtil.DataType>} compareFuncs Should contain unique elements
+ * @param {gluShaderUtil.DataType} basicType
+ */
+glsUniformBlockCase.getCompareDependencies = function(compareFuncs, basicType) {
+ switch (basicType) {
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.DataType.FLOAT);
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+
+ case gluShaderUtil.DataType.FLOAT_MAT2:
+ case gluShaderUtil.DataType.FLOAT_MAT2X3:
+ case gluShaderUtil.DataType.FLOAT_MAT2X4:
+ case gluShaderUtil.DataType.FLOAT_MAT3X2:
+ case gluShaderUtil.DataType.FLOAT_MAT3:
+ case gluShaderUtil.DataType.FLOAT_MAT3X4:
+ case gluShaderUtil.DataType.FLOAT_MAT4X2:
+ case gluShaderUtil.DataType.FLOAT_MAT4X3:
+ case gluShaderUtil.DataType.FLOAT_MAT4:
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.DataType.FLOAT);
+ deUtil.dePushUniqueToArray(compareFuncs, gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType)));
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+
+ default:
+ deUtil.dePushUniqueToArray(compareFuncs, basicType);
+ break;
+ }
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes_B
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.VarType} type
+ */
+glsUniformBlockCase.collectUniqueBasicTypes_B = function(basicTypes, type) {
+ if (type.isStructType()) {
+ /** @type {glsUniformBlockCase.StructType} */ var stype = type.getStruct();
+ for (var memberNdx = 0; memberNdx < stype.getSize(); memberNdx++)
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, stype.getMember(memberNdx).getType());
+ } else if (type.isArrayType())
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, type.getElementType());
+ else {
+ DE_ASSERT(type.isBasicType());
+ deUtil.dePushUniqueToArray(basicTypes, type.getBasicType());
+ }
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes_A
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.UniformBlock} uniformBlock
+ */
+glsUniformBlockCase.collectUniqueBasicTypes_A = function(basicTypes, uniformBlock) {
+ for (var uniformNdx = 0; uniformNdx < uniformBlock.countUniforms(); uniformNdx++)
+ glsUniformBlockCase.collectUniqueBasicTypes_B(basicTypes, uniformBlock.getUniform(uniformNdx).getType());
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes
+ * @param {Array<gluShaderUtil.DataType>} basicTypes Should contain unique elements
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.collectUniqueBasicTypes = function(basicTypes, sinterface) {
+ for (var ndx = 0; ndx < sinterface.getNumUniformBlocks(); ++ndx)
+ glsUniformBlockCase.collectUniqueBasicTypes_A(basicTypes, sinterface.getUniformBlock(ndx));
+};
+
+/**
+ * glsUniformBlockCase.collectUniqueBasicTypes
+ * @return {string} Was originally an output parameter. As it is a basic type, we have to return it instead.
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ */
+glsUniformBlockCase.generateCompareFuncs = function(sinterface) {
+ /** @type {string} */ var str = '';
+ /** @type {Array<gluShaderUtil.DataType>} */ var types = []; //Will contain unique elements.
+ /** @type {Array<gluShaderUtil.DataType>} */ var compareFuncs = []; //Will contain unique elements.
+
+ // Collect unique basic types
+ glsUniformBlockCase.collectUniqueBasicTypes(types, sinterface);
+
+ // Set of compare functions required
+ for (var typeNdx = 0; typeNdx < types.length; typeNdx++)
+ glsUniformBlockCase.getCompareDependencies(compareFuncs, types[typeNdx]);
+
+ for (var type in gluShaderUtil.DataType) {
+ if (compareFuncs.indexOf(gluShaderUtil.DataType[type]) > -1)
+ str += glsUniformBlockCase.getCompareFuncForType(gluShaderUtil.DataType[type]);
+ }
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.Indent - Prints level_ number of tab chars
+ * @param {number} level_
+ * @return {string}
+ */
+glsUniformBlockCase.Indent = function(level_) {
+ var str = '';
+ for (var i = 0; i < level_; i++)
+ str += '\t';
+
+ return str;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_C
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateDeclaration_C = function(structType, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ DE_ASSERT(structType.getTypeName() !== undefined);
+ src += glsUniformBlockCase.generateFullDeclaration(structType, indentLevel);
+ src += ';\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateFullDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateFullDeclaration = function(structType, indentLevel) {
+ var src = 'struct';
+ if (structType.getTypeName())
+ src += ' ' + structType.getTypeName();
+ src += '\n' + glsUniformBlockCase.Indent(indentLevel) + ' {\n';
+
+ for (var memberNdx = 0; memberNdx < structType.getSize(); memberNdx++) {
+ src += glsUniformBlockCase.Indent(indentLevel + 1);
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = structType.getMember(memberNdx);
+ src += glsUniformBlockCase.generateDeclaration_B(memberIter.getType(), memberIter.getName(), indentLevel + 1, memberIter.getFlags() & glsUniformBlockCase.UniformFlags.UNUSED_BOTH);
+ }
+
+ src += glsUniformBlockCase.Indent(indentLevel) + '}';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateLocalDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.StructType} structType
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateLocalDeclaration = function(structType, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ if (structType.getTypeName() === undefined)
+ src += glsUniformBlockCase.generateFullDeclaration(structType, indentLevel);
+ else
+ src += structType.getTypeName();
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_B
+ * @return {string} src
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {string} name
+ * @param {number} indentLevel
+ * @param {number} unusedHints
+ */
+glsUniformBlockCase.generateDeclaration_B = function(type, name, indentLevel, unusedHints) {
+ /** @type {string} */ var src = '';
+ /** @type {number} */ var flags = type.getFlags();
+
+ if ((flags & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(flags & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ if ((flags & glsUniformBlockCase.UniformFlags.PRECISION_MASK) != 0)
+ src += glsUniformBlockCase.PrecisionFlagsFmt(flags & glsUniformBlockCase.UniformFlags.PRECISION_MASK) + ' ';
+
+ if (type.isBasicType())
+ src += gluShaderUtil.getDataTypeName(type.getBasicType()) + ' ' + name;
+ else if (type.isArrayType()) {
+ /** @type {Array<number>} */ var arraySizes = [];
+ /** @type {glsUniformBlockCase.VarType} */ var curType = type;
+ while (curType.isArrayType()) {
+ arraySizes.push(curType.getArraySize());
+ curType = curType.getElementType();
+ }
+
+ if (curType.isBasicType()) {
+ if ((curType.getFlags() & glsUniformBlockCase.UniformFlags.PRECISION_MASK) != 0)
+ src += glsUniformBlockCase.PrecisionFlagsFmt(curType.getFlags() & glsUniformBlockCase.UniformFlags.PRECISION_MASK) + ' ';
+ src += gluShaderUtil.getDataTypeName(curType.getBasicType());
+ } else {
+ DE_ASSERT(curType.isStructType());
+ src += glsUniformBlockCase.generateLocalDeclaration(curType.getStruct(), indentLevel + 1);
+ }
+
+ src += ' ' + name;
+
+ for (var sizeNdx = 0; sizeNdx < arraySizes.length; sizeNdx++)
+ src += '[' + arraySizes[sizeNdx] + ']';
+ } else {
+ src += glsUniformBlockCase.generateLocalDeclaration(type.getStruct(), indentLevel + 1);
+ src += ' ' + name;
+ }
+
+ src += ';';
+
+ // Print out unused hints.
+ if (unusedHints != 0)
+ src += ' // unused in ' + (unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_BOTH ? 'both shaders' :
+ unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_VERTEX ? 'vertex shader' :
+ unusedHints == glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT ? 'fragment shader' : '???');
+
+ src += '\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration_A
+ * @return {string} src
+ * @param {glsUniformBlockCase.Uniform} uniform
+ * @param {number} indentLevel
+ */
+glsUniformBlockCase.generateDeclaration_A = function(uniform, indentLevel) {
+ /** @type {string} */ var src = '';
+
+ if ((uniform.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(uniform.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ src += glsUniformBlockCase.generateDeclaration_B(uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & glsUniformBlockCase.UniformFlags.UNUSED_BOTH);
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateDeclaration
+ * @return {string} src
+ * @param {glsUniformBlockCase.UniformBlock} block
+ */
+glsUniformBlockCase.generateDeclaration = function(block) {
+ /** @type {string} */ var src = '';
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) != 0)
+ src += 'layout(' + glsUniformBlockCase.LayoutFlagsFmt(block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_MASK) + ') ';
+
+ src += 'uniform ' + block.getBlockName();
+ src += '\n {\n';
+
+ for (var uniformNdx = 0; uniformNdx < block.countUniforms(); uniformNdx++) {
+ src += glsUniformBlockCase.Indent(1);
+ src += glsUniformBlockCase.generateDeclaration_A(block.getUniform(uniformNdx), 1 /* indent level */);
+ }
+
+ src += '}';
+
+ if (block.getInstanceName() !== undefined) {
+ src += ' ' + block.getInstanceName();
+ if (block.isArray())
+ src += '[' + block.getArraySize() + ']';
+ } else
+ DE_ASSERT(!block.isArray());
+
+ src += ';\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.newArrayBufferFromView - Creates a new buffer copying data from a given view
+ * @param {goog.NumberArray} view
+ * @return {ArrayBuffer} The newly created buffer
+ */
+glsUniformBlockCase.newArrayBufferFromView = function(view) {
+ var buffer = new ArrayBuffer(view.length * view.BYTES_PER_ELEMENT);
+ var copyview;
+ switch (view.BYTES_PER_ELEMENT) {
+ case 1:
+ copyview = new Uint8Array(buffer); break;
+ case 2:
+ copyview = new Uint16Array(buffer); break;
+ case 4:
+ copyview = new Uint32Array(buffer); break;
+ default:
+ assertMsgOptions(false, 'Unexpected value for BYTES_PER_ELEMENT in view', false, true);
+ }
+ for (var i = 0; i < view.length; i++)
+ copyview[i] = view[i];
+
+ return buffer;
+};
+
+/**
+ * glsUniformBlockCase.generateValueSrc
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {glsUniformBlockCase.UniformLayoutEntry} entry
+ * @param {Uint8Array} basePtr
+ * @param {number} elementNdx
+ */
+glsUniformBlockCase.generateValueSrc = function(entry, basePtr, elementNdx) {
+ /** @type {string} */ var src = '';
+ /** @type {gluShaderUtil.DataType} */ var scalarType = gluShaderUtil.getDataTypeScalarTypeAsDataType(entry.type);
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(entry.type);
+ /** @type {boolean} */ var isArray = entry.size > 1;
+ /** @type {Uint8Array} */ var elemPtr = basePtr.subarray(entry.offset + (isArray ? elementNdx * entry.arrayStride : 0));
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+ /** @type {Uint8Array} */ var compPtr;
+ if (scalarSize > 1)
+ src += gluShaderUtil.getDataTypeName(entry.type) + '(';
+
+ if (gluShaderUtil.isDataTypeMatrix(entry.type)) {
+ /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(entry.type);
+ /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(entry.type);
+
+ DE_ASSERT(scalarType == gluShaderUtil.DataType.FLOAT);
+
+ // Constructed in column-wise order.
+ for (var colNdx = 0; colNdx < numCols; colNdx++) {
+ for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
+ compPtr = elemPtr.subarray(entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
+ colNdx * entry.matrixStride + rowNdx * compSize);
+
+ if (colNdx > 0 || rowNdx > 0)
+ src += ', ';
+
+ var newbuffer = new Uint8Array(compPtr.subarray(0, 4)).buffer;
+ var newview = new DataView(newbuffer);
+ src += parseFloat(newview.getFloat32(0, littleEndian)).toFixed(1);
+ }
+ }
+ } else {
+ for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) {
+ compPtr = elemPtr.subarray(scalarNdx * compSize);
+
+ if (scalarNdx > 0)
+ src += ', ';
+
+ var newbuffer = glsUniformBlockCase.newArrayBufferFromView(compPtr.subarray(0, 4));
+ var newview = new DataView(newbuffer);
+
+ switch (scalarType) {
+ case gluShaderUtil.DataType.FLOAT: src += parseFloat(newview.getFloat32(0, littleEndian) * 100 / 100).toFixed(1); break;
+ case gluShaderUtil.DataType.INT: src += newview.getInt32(0, littleEndian); break;
+ case gluShaderUtil.DataType.UINT: src += newview.getUint32(0, littleEndian) + 'u'; break;
+ case gluShaderUtil.DataType.BOOL: src += (newview.getUint32(0, littleEndian) != 0 ? 'true' : 'false'); break;
+ default:
+ DE_ASSERT(false);
+ }
+ }
+ }
+
+ if (scalarSize > 1)
+ src += ')';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateCompareSrc_A
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {string} resultVar
+ * @param {glsUniformBlockCase.VarType} type
+ * @param {string} srcName
+ * @param {string} apiName
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {Uint8Array} basePtr
+ * @param {number} unusedMask
+ */
+glsUniformBlockCase.generateCompareSrc_A = function(resultVar, type, srcName, apiName, layout, basePtr, unusedMask) {
+ /** @type {string} */ var src = '';
+ /** @type {string} */ var op;
+ /** @type {glsUniformBlockCase.VarType|gluShaderUtil.DataType} */ var elementType;
+
+ if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType())) {
+ // Basic type or array of basic types.
+ /** @type {boolean} */ var isArray = type.isArrayType();
+ elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
+ /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(elementType);
+ /** @type {string} */ var fullApiName = apiName + (isArray ? '[0]' : ''); // Arrays are always postfixed with [0]
+ /** @type {number} */ var uniformNdx = layout.getUniformIndex(fullApiName);
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entry = layout.uniforms[uniformNdx];
+
+ if (isArray) {
+ for (var elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) {
+ src += '\tresult *= compare_' + typeName + '(' + srcName + '[' + elemNdx + '], ';
+ src += glsUniformBlockCase.generateValueSrc(entry, basePtr, elemNdx);
+ src += ');\n';
+ }
+ } else {
+ src += '\tresult *= compare_' + typeName + '(' + srcName + ', ';
+ src += glsUniformBlockCase.generateValueSrc(entry, basePtr, 0);
+ src += ');\n';
+ }
+ } else if (type.isArrayType()) {
+ elementType = type.getElementType();
+
+ for (var elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++) {
+ op = '[' + elementNdx + ']';
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, elementType, srcName + op, apiName + op, layout, basePtr, unusedMask);
+ }
+ } else {
+ DE_ASSERT(type.isStructType());
+
+ /** @type {glsUniformBlockCase.StructType} */ var stype = type.getStruct();
+ for (var memberNdx = 0; memberNdx < stype.getSize(); memberNdx++) {
+ /** @type {glsUniformBlockCase.StructMember} */ var memberIter = stype.getMember(memberNdx);
+ if (memberIter.getFlags() & unusedMask)
+ continue; // Skip member.
+
+ op = '.' + memberIter.getName();
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, memberIter.getType(), srcName + op, apiName + op, layout, basePtr, unusedMask);
+ }
+ }
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateCompareSrc
+ * @return {string} Used to be an output parameter in C++ project
+ * @param {string} resultVar
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ * @param {boolean} isVertex
+ */
+glsUniformBlockCase.generateCompareSrc = function(resultVar, sinterface, layout, blockPointers, isVertex) {
+ /** @type {string} */ var src = '';
+ /** @type {number} */ var unusedMask = isVertex ? glsUniformBlockCase.UniformFlags.UNUSED_VERTEX : glsUniformBlockCase.UniformFlags.UNUSED_FRAGMENT;
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+
+ if ((block.getFlags() & (isVertex ? glsUniformBlockCase.UniformFlags.DECLARE_VERTEX : glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) == 0)
+ continue; // Skip.
+
+ /** @type {boolean} */ var hasInstanceName = block.getInstanceName() !== undefined;
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {number} */ var numInstances = isArray ? block.getArraySize() : 1;
+ /** @type {string} */ var apiPrefix = hasInstanceName ? block.getBlockName() + '.' : '';
+
+ DE_ASSERT(!isArray || hasInstanceName);
+
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ /** @type {string} */ var instancePostfix = isArray ? '[' + instanceNdx + ']' : '';
+ /** @type {string} */ var blockInstanceName = block.getBlockName() + instancePostfix;
+ /** @type {string} */ var srcPrefix = hasInstanceName ? block.getInstanceName() + instancePostfix + '.' : '';
+ /** @type {number} */ var activeBlockNdx = layout.getBlockIndex(blockInstanceName);
+ /** @type {Uint8Array} */ var basePtr = blockPointers.find(activeBlockNdx);
+
+ for (var uniformNdx = 0; uniformNdx < block.countUniforms(); uniformNdx++) {
+ /** @type {glsUniformBlockCase.Uniform} */ var uniform = block.getUniform(uniformNdx);
+
+ if (uniform.getFlags() & unusedMask)
+ continue; // Don't read from that uniform.
+
+ src += glsUniformBlockCase.generateCompareSrc_A(resultVar, uniform.getType(), srcPrefix + uniform.getName(), apiPrefix + uniform.getName(), layout, basePtr, unusedMask);
+ }
+ }
+ }
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateVertexShader
+ * @return {string} src
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ */
+glsUniformBlockCase.generateVertexShader = function(sinterface, layout, blockPointers) {
+ /** @type {string} */ var src = '';
+
+ DE_ASSERT(glsUniformBlockCase.isSupportedGLSLVersion(gluShaderUtil.getGLSLVersion(gl)));
+
+ src += gluShaderUtil.getGLSLVersionDeclaration(gluShaderUtil.getGLSLVersion(gl)) + '\n';
+ src += 'in highp vec4 a_position;\n';
+ src += 'out mediump float v_vtxResult;\n';
+ src += '\n';
+
+ /** @type {Array<glsUniformBlockCase.StructType>} */ var namedStructs = [];
+ sinterface.getNamedStructs(namedStructs);
+ for (var structNdx = 0; structNdx < namedStructs.length; structNdx++)
+ src += glsUniformBlockCase.generateDeclaration_C(namedStructs[structNdx], 0);
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ if (block.getFlags() & glsUniformBlockCase.UniformFlags.DECLARE_VERTEX)
+ src += glsUniformBlockCase.generateDeclaration(block);
+ }
+
+ // Comparison utilities.
+ src += '\n';
+ src += glsUniformBlockCase.generateCompareFuncs(sinterface);
+
+ src += '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' gl_Position = a_position;\n' +
+ ' mediump float result = 1.0;\n';
+
+ // Value compare.
+ src += glsUniformBlockCase.generateCompareSrc('result', sinterface, layout, blockPointers, true);
+
+ src += ' v_vtxResult = result;\n' +
+ '}\n';
+
+ return src;
+};
+
+/**
+ * glsUniformBlockCase.generateFragmentShader
+ * @return {string} Used to be an output parameter
+ * @param {glsUniformBlockCase.ShaderInterface} sinterface
+ * @param {glsUniformBlockCase.UniformLayout} layout
+ * @param {glsUniformBlockCase.BlockPointers} blockPointers
+ */
+glsUniformBlockCase.generateFragmentShader = function(sinterface, layout, blockPointers) {
+ /** @type {string} */ var src = '';
+ DE_ASSERT(glsUniformBlockCase.isSupportedGLSLVersion(gluShaderUtil.getGLSLVersion(gl)));
+
+ src += gluShaderUtil.getGLSLVersionDeclaration(gluShaderUtil.getGLSLVersion(gl)) + '\n';
+ src += 'in mediump float v_vtxResult;\n';
+ src += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+ src += '\n';
+
+ /** @type {Array<glsUniformBlockCase.StructType>} */ var namedStructs = [];
+ sinterface.getNamedStructs(namedStructs);
+ for (var structNdx = 0; structNdx < namedStructs.length; structNdx++)
+ src += glsUniformBlockCase.generateDeclaration_C(namedStructs[structNdx], 0);
+
+ for (var blockNdx = 0; blockNdx < sinterface.getNumUniformBlocks(); blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = sinterface.getUniformBlock(blockNdx);
+ if (block.getFlags() & glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)
+ src += glsUniformBlockCase.generateDeclaration(block);
+ }
+
+ // Comparison utilities.
+ src += '\n';
+ src += glsUniformBlockCase.generateCompareFuncs(sinterface);
+
+ src += '\n' +
+ 'void main (void)\n' +
+ ' {\n' +
+ ' mediump float result = 1.0;\n';
+
+ // Value compare.
+ src += glsUniformBlockCase.generateCompareSrc('result', sinterface, layout, blockPointers, false);
+
+ src += ' dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n' +
+ '}\n';
+
+ return src;
+};
+
+/**
+ * TODO: test glsUniformBlockCase.getGLUniformLayout Gets the uniform blocks and uniforms in the program.
+ * @param {WebGL2RenderingContext} gl
+ * @param {glsUniformBlockCase.UniformLayout} layout To store the layout described in program.
+ * @param {WebGLProgram} program id
+ */
+glsUniformBlockCase.getGLUniformLayout = function(gl, layout, program) {
+ /** @type {number} */ var numActiveUniforms = 0;
+ /** @type {number} */ var numActiveBlocks = 0;
+
+ numActiveUniforms = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS)); // ACTIVE_UNIFORM* returns GLInt
+ numActiveBlocks = /** @type {number} */ (gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS));
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var entryBlock;
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var entryUniform;
+ /** @type {number} */ var size;
+ /** @type {number} */ var nameLen;
+ /** @type {string} */ var nameBuf;
+ /** @type {number} */ var numBlockUniforms;
+
+ // Block entries.
+ //No need to allocate these beforehand: layout.blocks.resize(numActiveBlocks);
+ for (var blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++) {
+ entryBlock = new glsUniformBlockCase.BlockLayoutEntry();
+
+ size = /** @type {number} */ (gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_DATA_SIZE));
+ // nameLen not used so this line is removed.
+ // nameLen = gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_NAME_LENGTH); // TODO: UNIFORM_BLOCK_NAME_LENGTH is removed in WebGL2
+ numBlockUniforms = /** @type {number} */ (gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS));
+
+ nameBuf = gl.getActiveUniformBlockName(program, blockNdx);
+
+ entryBlock.name = nameBuf;
+ entryBlock.size = size;
+ //entry.activeUniformIndices.resize(numBlockUniforms);
+
+ if (numBlockUniforms > 0)
+ entryBlock.activeUniformIndices = gl.getActiveUniformBlockParameter(program, blockNdx, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
+
+ layout.blocks.push(entryBlock); //Pushing the block into the array here.
+ }
+
+ if (numActiveUniforms > 0) {
+ // glsUniformBlockCase.Uniform entries.
+ /** @type {Array<number>} */ var uniformIndices = [];
+ for (var i = 0; i < numActiveUniforms; i++)
+ uniformIndices.push(i);
+
+ /** @type {Array<number>} */ var types = [];
+ /** @type {Array<number>} */ var sizes = [];
+ /** @type {Array<number>} */ var nameLengths = [];
+ /** @type {Array<number>} */ var blockIndices = [];
+ /** @type {Array<number>} */ var offsets = [];
+ /** @type {Array<number>} */ var arrayStrides = [];
+ /** @type {Array<number>} */ var matrixStrides = [];
+ /** @type {Array<number>} */ var rowMajorFlags = [];
+
+ // Execute queries.
+ types = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_TYPE);
+ sizes = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_SIZE);
+ // Remove this: nameLengths = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_NAME_LENGTH);
+ blockIndices = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_BLOCK_INDEX);
+ offsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ arrayStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_ARRAY_STRIDE);
+ matrixStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_MATRIX_STRIDE);
+ rowMajorFlags = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_IS_ROW_MAJOR);
+
+ // Translate to LayoutEntries
+ // No resize needed. Will push them: layout.uniforms.resize(numActiveUniforms);
+ for (var uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++) {
+ entryUniform = new glsUniformBlockCase.UniformLayoutEntry();
+
+ // Remove this: nameLen = 0;
+ size = 0;
+ /** @type {number} */ var type = gl.NONE;
+
+ var uniform = gl.getActiveUniform(program, uniformNdx);
+
+ nameBuf = uniform.name;
+ // Remove this: nameLen = nameBuf.length;
+ size = uniform.size;
+ type = uniform.type;
+
+ // Remove this: nameLen != nameLengths[uniformNdx] ||
+ if (size != sizes[uniformNdx] ||
+ type != types[uniformNdx])
+ testFailedOptions("Values returned by gl.getActiveUniform() don't match with values queried with gl.getActiveUniforms().", true);
+
+ entryUniform.name = nameBuf;
+ entryUniform.type = gluShaderUtil.getDataTypeFromGLType(types[uniformNdx]);
+ entryUniform.size = sizes[uniformNdx];
+ entryUniform.blockNdx = blockIndices[uniformNdx];
+ entryUniform.offset = offsets[uniformNdx];
+ entryUniform.arrayStride = arrayStrides[uniformNdx];
+ entryUniform.matrixStride = matrixStrides[uniformNdx];
+ entryUniform.isRowMajor = rowMajorFlags[uniformNdx] != false;
+
+ layout.uniforms.push(entryUniform); //Pushing this uniform in the end.
+ }
+ }
+};
+
+/**
+ * glsUniformBlockCase.copyUniformData_A - Copies a source uniform buffer segment to a destination uniform buffer segment.
+ * @param {glsUniformBlockCase.UniformLayoutEntry} dstEntry
+ * @param {Uint8Array} dstBlockPtr
+ * @param {glsUniformBlockCase.UniformLayoutEntry} srcEntry
+ * @param {Uint8Array} srcBlockPtr
+ */
+glsUniformBlockCase.copyUniformData_A = function(dstEntry, dstBlockPtr, srcEntry, srcBlockPtr) {
+ /** @type {Uint8Array} */ var dstBasePtr = dstBlockPtr.subarray(dstEntry.offset);
+ /** @type {Uint8Array} */ var srcBasePtr = srcBlockPtr.subarray(srcEntry.offset);
+
+ DE_ASSERT(dstEntry.size <= srcEntry.size);
+ DE_ASSERT(dstEntry.type == srcEntry.type);
+
+ /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(dstEntry.type);
+ /** @type {boolean} */ var isMatrix = gluShaderUtil.isDataTypeMatrix(dstEntry.type);
+ /** @type {number} */ var compSize = deMath.INT32_SIZE;
+
+ for (var elementNdx = 0; elementNdx < dstEntry.size; elementNdx++) {
+ /** @type {Uint8Array} */ var dstElemPtr = dstBasePtr.subarray(elementNdx * dstEntry.arrayStride);
+ /** @type {Uint8Array} */ var srcElemPtr = srcBasePtr.subarray(elementNdx * srcEntry.arrayStride);
+
+ if (isMatrix) {
+ /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(dstEntry.type);
+ /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(dstEntry.type);
+
+ for (var colNdx = 0; colNdx < numCols; colNdx++) {
+ for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
+ var srcoffset = dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
+ colNdx * dstEntry.matrixStride + rowNdx * compSize;
+ /** @type {Uint8Array} */ var dstCompPtr = dstElemPtr.subarray(srcoffset, srcoffset + compSize);
+ var dstoffset = srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
+ colNdx * srcEntry.matrixStride + rowNdx * compSize;
+ /** @type {Uint8Array} */ var srcCompPtr = srcElemPtr.subarray(dstoffset, dstoffset + compSize);
+
+ //Copy byte per byte
+ for (var i = 0; i < compSize; i++)
+ dstCompPtr[i] = srcCompPtr[i];
+ }
+ }
+ } else
+ //Copy byte per byte
+ for (var i = 0; i < scalarSize * compSize; i++)
+ dstElemPtr[i] = srcElemPtr[i];
+ }
+};
+
+/**
+ * glsUniformBlockCase.copyUniformData - Copies a source uniform buffer to a destination uniform buffer.
+ * @param {glsUniformBlockCase.UniformLayout} dstLayout
+ * @param {glsUniformBlockCase.BlockPointers} dstBlockPointers
+ * @param {glsUniformBlockCase.UniformLayout} srcLayout
+ * @param {glsUniformBlockCase.BlockPointers} srcBlockPointers
+ */
+glsUniformBlockCase.copyUniformData = function(dstLayout, dstBlockPointers, srcLayout, srcBlockPointers) {
+ // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
+ /** @type {number} */ var numBlocks = srcLayout.blocks.length;
+
+ for (var srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var srcBlock = srcLayout.blocks[srcBlockNdx];
+ /** @type {Uint8Array} */ var srcBlockPtr = srcBlockPointers.find(srcBlockNdx);
+ /** @type {number} */ var dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name);
+ /** @type {Uint8Array} */ var dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx) : null;
+
+ if (dstBlockNdx < 0)
+ continue;
+
+ for (var srcUniformNdx = 0; srcUniformNdx < srcBlock.activeUniformIndices.length; srcUniformNdx++) {
+ /** @type {number} */ var srcUniformNdxIter = srcBlock.activeUniformIndices[srcUniformNdx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var srcEntry = srcLayout.uniforms[srcUniformNdxIter];
+ /** @type {number} */ var dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name);
+
+ if (dstUniformNdx < 0)
+ continue;
+
+ glsUniformBlockCase.copyUniformData_A(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
+ }
+ }
+};
+
+ /**
+ * TODO: Test with an actual WebGL 2.0 context
+ * iterate - The actual execution of the test.
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsUniformBlockCase.UniformBlockCase.prototype.iterate = function() {
+ /** @type {glsUniformBlockCase.UniformLayout} */ var refLayout = new glsUniformBlockCase.UniformLayout(); //!< std140 layout.
+ /** @type {glsUniformBlockCase.BlockPointers} */ var blockPointers = new glsUniformBlockCase.BlockPointers();
+
+ // Compute reference layout.
+ glsUniformBlockCase.computeStd140Layout(refLayout, this.m_interface);
+
+ // Assign storage for reference values.
+ /** @type {number} */ var totalSize = 0;
+ for (var blockNdx = 0; blockNdx < refLayout.blocks.length; blockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var blockIter = refLayout.blocks[blockNdx];
+ totalSize += blockIter.size;
+ }
+ blockPointers.resize(totalSize);
+
+ // Pointers for each block.
+ var curOffset = 0;
+ for (var blockNdx = 0; blockNdx < refLayout.blocks.length; blockNdx++) {
+ var size = refLayout.blocks[blockNdx].size;
+ blockPointers.push(curOffset, size);
+ curOffset += size;
+ }
+
+ // Generate values.
+ glsUniformBlockCase.generateValues(refLayout, blockPointers, 1 /* seed */);
+
+ // Generate shaders and build program.
+ /** @type {string} */ var vtxSrc = glsUniformBlockCase.generateVertexShader(this.m_interface, refLayout, blockPointers);
+ /** @type {string} */ var fragSrc = glsUniformBlockCase.generateFragmentShader(this.m_interface, refLayout, blockPointers);
+
+ /** @type {gluShaderProgram.ShaderProgram}*/ var program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtxSrc, fragSrc));
+ bufferedLogToConsole(program.getProgramInfo().infoLog);
+
+ if (!program.isOk()) {
+ // Compile failed.
+ testFailedOptions('Compile failed', false);
+ return tcuTestCase.IterateResult.STOP;
+ }
+
+ // Query layout from GL.
+ /** @type {glsUniformBlockCase.UniformLayout} */ var glLayout = new glsUniformBlockCase.UniformLayout();
+ glsUniformBlockCase.getGLUniformLayout(gl, glLayout, program.getProgram());
+
+ // Print layout to log.
+ bufferedLogToConsole('Active glsUniformBlockCase.Uniform Blocks');
+ for (var blockNdx = 0; blockNdx < glLayout.blocks.length; blockNdx++)
+ bufferedLogToConsole(blockNdx + ': ' + glLayout.blocks[blockNdx]);
+
+ bufferedLogToConsole('Active Uniforms');
+ for (var uniformNdx = 0; uniformNdx < glLayout.uniforms.length; uniformNdx++)
+ bufferedLogToConsole(uniformNdx + ': ' + glLayout.uniforms[uniformNdx]);
+
+ // Check that we can even try rendering with given layout.
+ if (!this.checkLayoutIndices(glLayout) || !this.checkLayoutBounds(glLayout) || !this.compareTypes(refLayout, glLayout)) {
+ testFailedOptions('Invalid layout', false);
+ return tcuTestCase.IterateResult.STOP; // It is not safe to use the given layout.
+ }
+
+ // Verify all std140 blocks.
+ if (!this.compareStd140Blocks(refLayout, glLayout))
+ testFailedOptions('Invalid std140 layout', false);
+
+ // Verify all shared blocks - all uniforms should be active, and certain properties match.
+ if (!this.compareSharedBlocks(refLayout, glLayout))
+ testFailedOptions('Invalid shared layout', false);
+
+ // Check consistency with index queries
+ if (!this.checkIndexQueries(program.getProgram(), glLayout))
+ testFailedOptions('Inconsintent block index query results', false);
+
+ // Use program.
+ gl.useProgram(program.getProgram());
+
+ /** @type {number} */ var binding;
+ /** @type {WebGLBuffer} */ var buffer;
+
+ // Assign binding points to all active uniform blocks.
+ for (var blockNdx = 0; blockNdx < glLayout.blocks.length; blockNdx++) {
+ binding = blockNdx; // \todo [2012-01-25 pyry] Randomize order?
+ gl.uniformBlockBinding(program.getProgram(), blockNdx, binding);
+ }
+
+ /** @type {number} */ var numBlocks;
+ /** @type {glsUniformBlockCase.BlockPointers} */ var glBlockPointers;
+
+ // Allocate buffers, write data and bind to targets.
+ /** @type {glsUniformBlockCase.UniformBufferManager} */ var bufferManager = new glsUniformBlockCase.UniformBufferManager(gl);
+ if (this.m_bufferMode == glsUniformBlockCase.BufferMode.BUFFERMODE_PER_BLOCK) {
+ numBlocks = glLayout.blocks.length;
+ glBlockPointers = new glsUniformBlockCase.BlockPointers();
+
+ var totalsize = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++)
+ totalsize += glLayout.blocks[blockNdx].size;
+
+ glBlockPointers.resize(totalsize);
+
+ var offset = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ glBlockPointers.push(offset, glLayout.blocks[blockNdx].size);
+ offset += glLayout.blocks[blockNdx].size;
+ }
+
+ glsUniformBlockCase.copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ buffer = bufferManager.allocBuffer();
+ binding = blockNdx;
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+ gl.bufferData(gl.UNIFORM_BUFFER, glBlockPointers.find(blockNdx) /*(glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0]*/, gl.STATIC_DRAW);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, buffer);
+ }
+ } else {
+ DE_ASSERT(this.m_bufferMode == glsUniformBlockCase.BufferMode.BUFFERMODE_SINGLE);
+
+ totalSize = 0;
+ curOffset = 0;
+ numBlocks = glLayout.blocks.length;
+ /** @type {number} */ var bindingAlignment = 0;
+ glBlockPointers = new glsUniformBlockCase.BlockPointers();
+
+ bindingAlignment = /** @type {number} */ (gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT));
+
+ // Compute total size and offsets.
+ curOffset = 0;
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ if (bindingAlignment > 0)
+ curOffset = glsUniformBlockCase.deRoundUp32(curOffset, bindingAlignment);
+ glBlockPointers.push(curOffset, glLayout.blocks[blockNdx].size);
+ curOffset += glLayout.blocks[blockNdx].size;
+ }
+ totalSize = curOffset;
+ glBlockPointers.resize(totalSize);
+
+ // Copy to gl format.
+ glsUniformBlockCase.copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
+
+ // Allocate buffer and upload data.
+ buffer = bufferManager.allocBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer);
+ if (glBlockPointers.data.byteLength > 0 /*!glData.empty()*/)
+ gl.bufferData(gl.UNIFORM_BUFFER, glBlockPointers.find(blockNdx) /*(glw::GLsizeiptr)glData.size(), &glData[0]*/, gl.STATIC_DRAW);
+
+ // Bind ranges to binding points.
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ binding = blockNdx;
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, binding, buffer, glBlockPointers.offsets[blockNdx], glLayout.blocks[blockNdx].size);
+ }
+ }
+
+ /** @type {boolean} */ var renderOk = this.render(program);
+ if (!renderOk)
+ testFailedOptions('Image compare failed', false);
+ else
+ assertMsgOptions(renderOk, '', true, false);
+
+ return tcuTestCase.IterateResult.STOP;
+};
+
+/**
+* compareStd140Blocks
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareStd140Blocks = function(refLayout, cmpLayout) {
+ /**@type {boolean} */ var isOk = true;
+ /**@type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /**@type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /**@type {boolean} */ var isArray = block.isArray();
+ /**@type {string} */ var instanceName = block.getBlockName() + (isArray ? '[0]' : '');
+ /**@type {number} */ var refBlockNdx = refLayout.getBlockIndex(instanceName);
+ /**@type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+ /**@type {boolean} */ var isUsed = (block.getFlags() & (glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) != 0;
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_STD140) == 0)
+ continue; // Not std140 layout.
+
+ DE_ASSERT(refBlockNdx >= 0);
+
+ if (cmpBlockNdx < 0) {
+ // Not found, should it?
+ if (isUsed) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform block '" + instanceName + "' not found");
+ isOk = false;
+ }
+
+ continue; // Skip block.
+ }
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var refBlockLayout = refLayout.blocks[refBlockNdx];
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
+ // \todo [2012-01-24 pyry] Verify all instances.
+ if (refBlockLayout.activeUniformIndices.length != cmpBlockLayout.activeUniformIndices.length) {
+ bufferedLogToConsole("Error: Number of active uniforms differ in block '" + instanceName +
+ "' (expected " + refBlockLayout.activeUniformIndices.length +
+ ', got ' + cmpBlockLayout.activeUniformIndices.length +
+ ')');
+ isOk = false;
+ }
+
+ for (var ndx = 0; ndx < refBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = refBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[ndxIter];
+ /** @type {number} */ var cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name);
+
+ if (cmpEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + refEntry.name + "' not found");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
+
+ if (refEntry.type != cmpEntry.type ||
+ refEntry.size != cmpEntry.size ||
+ refEntry.offset != cmpEntry.offset ||
+ refEntry.arrayStride != cmpEntry.arrayStride ||
+ refEntry.matrixStride != cmpEntry.matrixStride ||
+ refEntry.isRowMajor != cmpEntry.isRowMajor) {
+ bufferedLogToConsole("Error: Layout mismatch in '" + refEntry.name + "':\n" +
+ ' expected: type = ' + gluShaderUtil.getDataTypeName(refEntry.type) + ', size = ' + refEntry.size + ', row major = ' + (refEntry.isRowMajor ? 'true' : 'false') + '\n' +
+ ' got: type = ' + gluShaderUtil.getDataTypeName(cmpEntry.type) + ', size = ' + cmpEntry.size + ', row major = ' + (cmpEntry.isRowMajor ? 'true' : 'false'));
+ isOk = false;
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/**
+* compareSharedBlocks
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareSharedBlocks = function(refLayout, cmpLayout) {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {string} */ var instanceName = block.getBlockName() + (isArray ? '[0]' : '');
+ /** @type {number} */ var refBlockNdx = refLayout.getBlockIndex(instanceName);
+ /** @type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+ /** @type {boolean} */ var isUsed = (block.getFlags() & (glsUniformBlockCase.UniformFlags.DECLARE_VERTEX | glsUniformBlockCase.UniformFlags.DECLARE_FRAGMENT)) != 0;
+
+ if ((block.getFlags() & glsUniformBlockCase.UniformFlags.LAYOUT_SHARED) == 0)
+ continue; // Not shared layout.
+
+ DE_ASSERT(refBlockNdx >= 0);
+
+ if (cmpBlockNdx < 0) {
+ // Not found, should it?
+ if (isUsed) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform block '" + instanceName + "' not found");
+ isOk = false;
+ }
+
+ continue; // Skip block.
+ }
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var refBlockLayout = refLayout.blocks[refBlockNdx];
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ if (refBlockLayout.activeUniformIndices.length != cmpBlockLayout.activeUniformIndices.length) {
+ bufferedLogToConsole("Error: Number of active uniforms differ in block '" + instanceName +
+ "' (expected " + refBlockLayout.activeUniformIndices.length +
+ ', got ' + cmpBlockLayout.activeUniformIndices.length +
+ ')');
+ isOk = false;
+ }
+
+ for (var ndx = 0; ndx < refBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = refBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[ndxIter];
+ /** @type {number} */ var cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name);
+
+ if (cmpEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + refEntry.name + "' not found");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
+
+ if (refEntry.type != cmpEntry.type ||
+ refEntry.size != cmpEntry.size ||
+ refEntry.isRowMajor != cmpEntry.isRowMajor) {
+ bufferedLogToConsole("Error: Layout mismatch in '" + refEntry.name + "':\n" +
+ ' expected: type = ' + gluShaderUtil.getDataTypeName(refEntry.type) + ', size = ' + refEntry.size + ', row major = ' + (refEntry.isRowMajor ? 'true' : 'false') + '\n' +
+ ' got: type = ' + gluShaderUtil.getDataTypeName(cmpEntry.type) + ', size = ' + cmpEntry.size + ', row major = ' + (cmpEntry.isRowMajor ? 'true' : 'false'));
+ isOk = false;
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/** compareTypes
+* @param {glsUniformBlockCase.UniformLayout} refLayout
+* @param {glsUniformBlockCase.UniformLayout} cmpLayout
+* @return {boolean} true if uniform types are the same
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.compareTypes = function(refLayout, cmpLayout) {
+ /** @type {boolean} */ var isOk = true;
+ /** @type {number} */ var numBlocks = this.m_interface.getNumUniformBlocks();
+
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.UniformBlock} */ var block = this.m_interface.getUniformBlock(blockNdx);
+ /** @type {boolean} */ var isArray = block.isArray();
+ /** @type {number} */ var numInstances = isArray ? block.getArraySize() : 1;
+
+ for (var instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) {
+ /** @type {string} */ var instanceName;
+
+ instanceName += block.getBlockName();
+ if (isArray)
+ instanceName = instanceName + '[' + instanceNdx + ']';
+
+ /** @type {number} */ var cmpBlockNdx = cmpLayout.getBlockIndex(instanceName);
+
+ if (cmpBlockNdx < 0)
+ continue;
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
+
+ for (var ndx = 0; ndx < cmpBlockLayout.activeUniformIndices.length; ndx++) {
+ /** @type {number} */ var ndxIter = cmpBlockLayout.activeUniformIndices[ndx];
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var cmpEntry = cmpLayout.uniforms[ndxIter];
+ /** @type {number} */ var refEntryNdx = refLayout.getUniformIndex(cmpEntry.name);
+
+ if (refEntryNdx < 0) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + cmpEntry.name + "' not found in reference layout");
+ isOk = false;
+ continue;
+ }
+
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var refEntry = refLayout.uniforms[refEntryNdx];
+
+ // \todo [2012-11-26 pyry] Should we check other properties as well?
+ if (refEntry.type != cmpEntry.type) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform type mismatch in '" + refEntry.name + "':</br>" +
+ "' expected: '" + gluShaderUtil.getDataTypeName(refEntry.type) + "'</br>" +
+ "' got: '" + gluShaderUtil.getDataTypeName(cmpEntry.type) + "'");
+ isOk = false;
+ }
+ }
+ }
+ }
+
+ return isOk;
+};
+
+/** checkLayoutIndices
+* @param {glsUniformBlockCase.UniformLayout} layout Layout whose indices are to be checked
+* @return {boolean} true if all is ok
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkLayoutIndices = function(layout) {
+ /** @type {number} */ var numUniforms = layout.uniforms.length;
+ /** @type {number} */ var numBlocks = layout.blocks.length;
+ /** @type {boolean} */ var isOk = true;
+
+ // Check uniform block indices.
+ for (var uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var uniform = layout.uniforms[uniformNdx];
+
+ if (uniform.blockNdx < 0 || !deMath.deInBounds32(uniform.blockNdx, 0, numBlocks)) {
+ bufferedLogToConsole("Error: Invalid block index in uniform '" + uniform.name + "'");
+ isOk = false;
+ }
+ }
+
+ // Check active uniforms.
+ for (var blockNdx = 0; blockNdx < numBlocks; blockNdx++) {
+ /** @type {glsUniformBlockCase.BlockLayoutEntry} */ var block = layout.blocks[blockNdx];
+
+ for (var uniformNdx = 0; uniformNdx < block.activeUniformIndices.length; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry} */ var activeUniformNdx = block.activeUniformIndices[uniformNdx];
+ if (!deMath.deInBounds32(activeUniformNdx, 0, numUniforms)) {
+ bufferedLogToConsole('Error: Invalid active uniform index ' + activeUniformNdx + " in block '" + block.name);
+ isOk = false;
+ }
+ }
+ }
+ return isOk;
+};
+
+/** checkLayoutBounds
+* @param {glsUniformBlockCase.UniformLayout} layout The uniform layout to check
+* @return {boolean} true if all is within bounds
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkLayoutBounds = function(layout) {
+ /** @type {number} */ var numUniforms = layout.uniforms.length;
+ /** @type {boolean}*/ var isOk = true;
+
+ for (var uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) {
+ /** @type {glsUniformBlockCase.UniformLayoutEntry}*/ var uniform = layout.uniforms[uniformNdx];
+
+ if (uniform.blockNdx < 0)
+ continue;
+
+ /** @type {glsUniformBlockCase.BlockLayoutEntry}*/ var block = layout.blocks[uniform.blockNdx];
+ /** @type {boolean}*/ var isMatrix = gluShaderUtil.isDataTypeMatrix(uniform.type);
+ /** @type {number}*/ var numVecs = isMatrix ? (uniform.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumRows(uniform.type) : gluShaderUtil.getDataTypeMatrixNumColumns(uniform.type)) : 1;
+ /** @type {number}*/ var numComps = isMatrix ? (uniform.isRowMajor ? gluShaderUtil.getDataTypeMatrixNumColumns(uniform.type) : gluShaderUtil.getDataTypeMatrixNumRows(uniform.type)) : gluShaderUtil.getDataTypeScalarSize(uniform.type);
+ /** @type {number}*/ var numElements = uniform.size;
+ /** @type {number}*/ var compSize = deMath.INT32_SIZE;
+ /** @type {number}*/ var vecSize = numComps * compSize;
+
+ /** @type {number}*/ var minOffset = 0;
+ /** @type {number}*/ var maxOffset = 0;
+
+ // For negative strides.
+ minOffset = Math.min(minOffset, (numVecs - 1) * uniform.matrixStride);
+ minOffset = Math.min(minOffset, (numElements - 1) * uniform.arrayStride);
+ minOffset = Math.min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
+
+ maxOffset = Math.max(maxOffset, vecSize);
+ maxOffset = Math.max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
+ maxOffset = Math.max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
+ maxOffset = Math.max(maxOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
+
+ if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size) {
+ bufferedLogToConsole("Error: glsUniformBlockCase.Uniform '" + uniform.name + "' out of block bounds");
+ isOk = false;
+ }
+ }
+
+ return isOk;
+};
+
+/** checkIndexQueries
+* @param {WebGLProgram} program The shader program to be checked against
+* @param {glsUniformBlockCase.UniformLayout} layout The layout to check
+* @return {boolean} true if everything matches.
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.checkIndexQueries = function(program, layout) {
+ /** @type {boolean}*/ var allOk = true;
+
+ // \note Spec mandates that uniform blocks are assigned consecutive locations from 0
+ // to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in glsUniformBlockCase.UniformLayout.
+ for (var blockNdx = 0; blockNdx < layout.blocks.length; blockNdx++) {
+ /** @const */ var block = layout.blocks[blockNdx];
+ /** @const */ var queriedNdx = gl.getUniformBlockIndex(program, block.name);
+
+ if (queriedNdx != blockNdx) {
+ bufferedLogToConsole('ERROR: glGetUniformBlockIndex(' + block.name + ') returned ' + queriedNdx + ', expected ' + blockNdx + '!');
+ allOk = false;
+ }
+ }
+
+ return allOk;
+};
+
+/** @const @type {number} */ glsUniformBlockCase.VIEWPORT_WIDTH = 128;
+/** @const @type {number} */ glsUniformBlockCase.VIEWPORT_HEIGHT = 128;
+
+/** Renders a white square, and then tests all pixels are
+* effectively white in the color buffer.
+* @param {gluShaderProgram.ShaderProgram} program The shader program to use.
+* @return {boolean} false if there was at least one incorrect pixel
+**/
+glsUniformBlockCase.UniformBlockCase.prototype.render = function(program) {
+ // Compute viewport.
+ /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
+ /** @const */ var viewportW = Math.min(gl.canvas.width, glsUniformBlockCase.VIEWPORT_WIDTH);
+ /** @const */ var viewportH = Math.min(gl.canvas.height, glsUniformBlockCase.VIEWPORT_HEIGHT);
+ /** @const */ var viewportX = rnd.getInt(0, gl.canvas.width);
+ /** @const */ var viewportY = rnd.getInt(0, gl.canvas.height);
+
+ gl.clearColor(0.125, 0.25, 0.5, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ //Draw
+ var position = [
+ -1.0, -1.0, 0.0, 1.0,
+ -1.0, 1.0, 0.0, 1.0,
+ 1.0, -1.0, 0.0, 1.0,
+ 1.0, 1.0, 0.0, 1.0
+ ];
+ var indices = [0, 1, 2, 2, 1, 3];
+
+ gl.viewport(viewportX, viewportY, viewportW, viewportH);
+
+ // Access
+ var posLoc = gl.getAttribLocation(program.getProgram(), 'a_position');
+ var posArray = [new gluDrawUtil.VertexArrayBinding(gl.FLOAT, posLoc, 4, 4, position)];
+ gluDrawUtil.draw(gl, program.getProgram(), posArray, gluDrawUtil.triangles(indices));
+
+ // Verify that all pixels are white.
+ var pixels = new gluDrawUtil.Surface();
+ var numFailedPixels = 0;
+
+ var readPixelsX = (viewportX + viewportW) > gl.canvas.width
+ ? (gl.canvas.width - viewportX) : viewportW;
+ var readPixelsY = (viewportY + viewportH) > gl.canvas.height
+ ? (gl.canvas.height - viewportY) : viewportH;
+
+ var buffer = pixels.readSurface(gl, viewportX, viewportY, readPixelsX, readPixelsY);
+
+ var whitePixel = new gluDrawUtil.Pixel([255.0, 255.0, 255.0, 255.0]);
+ for (var y = 0; y < readPixelsY; y++) {
+ for (var x = 0; x < readPixelsX; x++) {
+ if (!pixels.getPixel(x, y).equals(whitePixel))
+ numFailedPixels += 1;
+ }
+ }
+
+ if (numFailedPixels > 0) {
+ bufferedLogToConsole('Image comparison failed, got ' + numFailedPixels + ' non-white pixels.');
+ }
+
+ return numFailedPixels == 0;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsVertexArrayTests.js b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsVertexArrayTests.js
new file mode 100644
index 000000000..99dc79f35
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsVertexArrayTests.js
@@ -0,0 +1,2534 @@
+/*-------------------------------------------------------------------------
+ * 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.glsVertexArrayTests');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.common.tcuImageCompare');
+goog.require('framework.common.tcuLogImage');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.simplereference.sglrGLContext');
+goog.require('framework.opengl.simplereference.sglrReferenceContext');
+goog.require('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.referencerenderer.rrFragmentOperations');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrShadingContext');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+goog.require('framework.referencerenderer.rrVertexPacket');
+
+goog.scope(function() {
+
+ var glsVertexArrayTests = modules.shared.glsVertexArrayTests;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuRGBA = framework.common.tcuRGBA;
+ var tcuFloat = framework.common.tcuFloat;
+ var tcuPixelFormat = framework.common.tcuPixelFormat;
+ var tcuSurface = framework.common.tcuSurface;
+ var tcuImageCompare = framework.common.tcuImageCompare;
+ var tcuLogImage = framework.common.tcuLogImage;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var sglrGLContext = framework.opengl.simplereference.sglrGLContext;
+ var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext;
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var deMath = framework.delibs.debase.deMath;
+ var deRandom = framework.delibs.debase.deRandom;
+ var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var rrShadingContext = framework.referencerenderer.rrShadingContext;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrVertexPacket = framework.referencerenderer.rrVertexPacket;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * @interface
+ */
+ glsVertexArrayTests.deArray = function() {};
+
+ /**
+ * glsVertexArrayTests.deArray.Target enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.Target = {
+ ELEMENT_ARRAY: 0,
+ ARRAY: 1
+ };
+
+ /**
+ * glsVertexArrayTests.deArray.InputType enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.InputType = {
+ FLOAT: 0,
+ /*FIXED: 1,
+ DOUBLE: 2,*/
+
+ BYTE: 1,
+ SHORT: 2,
+
+ UNSIGNED_BYTE: 3,
+ UNSIGNED_SHORT: 4,
+
+ INT: 5,
+ UNSIGNED_INT: 6,
+ HALF: 7,
+ UNSIGNED_INT_2_10_10_10: 8,
+ INT_2_10_10_10: 9
+ };
+
+ /**
+ * glsVertexArrayTests.deArray.OutputType enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.OutputType = {
+ FLOAT: 0,
+ VEC2: 1,
+ VEC3: 2,
+ VEC4: 3,
+
+ INT: 4,
+ UINT: 5,
+
+ IVEC2: 6,
+ IVEC3: 7,
+ IVEC4: 8,
+
+ UVEC2: 9,
+ UVEC3: 10,
+ UVEC4: 11
+ };
+
+ /**
+ * glsVertexArrayTests.deArray.Usage enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.Usage = {
+ DYNAMIC_DRAW: 0,
+ STATIC_DRAW: 1,
+ STREAM_DRAW: 2,
+
+ STREAM_READ: 3,
+ STREAM_COPY: 4,
+
+ STATIC_READ: 5,
+ STATIC_COPY: 6,
+
+ DYNAMIC_READ: 7,
+ DYNAMIC_COPY: 8
+ };
+
+ /**
+ * glsVertexArrayTests.deArray.Storage enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.Storage = {
+ USER: 0,
+ BUFFER: 1
+ };
+
+ /**
+ * glsVertexArrayTests.deArray.Primitive enum
+ * @enum
+ */
+ glsVertexArrayTests.deArray.Primitive = {
+ POINTS: 0,
+ TRIANGLES: 1,
+ TRIANGLE_FAN: 2,
+ TRIANGLE_STRIP: 3
+ };
+
+ //glsVertexArrayTests.deArray static functions
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.targetToString = function(target) {
+ DE_ASSERT(target < Object.keys(glsVertexArrayTests.deArray.Target).length);
+
+ /** @type {Array<string>} */ var targets =
+ [
+ 'element_array', // glsVertexArrayTests.deArray.Target.ELEMENT_ARRAY
+ 'array' // glsVertexArrayTests.deArray.Target.ARRAY
+ ];
+ DE_ASSERT(targets.length == Object.keys(glsVertexArrayTests.deArray.Target).length);
+
+ return targets[target];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.inputTypeToString = function(type) {
+ DE_ASSERT(type < Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ /** @type {Array<string>} */ var types =
+ [
+ 'float', // glsVertexArrayTests.deArray.InputType.FLOAT
+
+ 'byte', // glsVertexArrayTests.deArray.InputType.BYTE
+ 'short', // glsVertexArrayTests.deArray.InputType.SHORT
+
+ 'unsigned_byte', // glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE
+ 'unsigned_short', // glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT
+
+ 'int', // glsVertexArrayTests.deArray.InputType.INT
+ 'unsigned_int', // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT
+ 'half', // glsVertexArrayTests.deArray.InputType.HALF
+ 'unsigned_int2_10_10_10', // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10
+ 'int2_10_10_10' // glsVertexArrayTests.deArray.InputType.INT_2_10_10_10
+ ];
+ DE_ASSERT(types.length == Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ return types[type];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.OutputType} type
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.outputTypeToString = function(type) {
+ DE_ASSERT(type < Object.keys(glsVertexArrayTests.deArray.OutputType).length);
+
+ /** @type {Array<string>} */ var types =
+ [
+ 'float', // glsVertexArrayTests.deArray.OutputType.FLOAT
+ 'vec2', // glsVertexArrayTests.deArray.OutputType.VEC2
+ 'vec3', // glsVertexArrayTests.deArray.OutputType.VEC3
+ 'vec4', // glsVertexArrayTests.deArray.OutputType.VEC4
+
+ 'int', // glsVertexArrayTests.deArray.OutputType.INT
+ 'uint', // glsVertexArrayTests.deArray.OutputType.UINT
+
+ 'ivec2', // glsVertexArrayTests.deArray.OutputType.IVEC2
+ 'ivec3', // glsVertexArrayTests.deArray.OutputType.IVEC3
+ 'ivec4', // glsVertexArrayTests.deArray.OutputType.IVEC4
+
+ 'uvec2', // glsVertexArrayTests.deArray.OutputType.UVEC2
+ 'uvec3', // glsVertexArrayTests.deArray.OutputType.UVEC3
+ 'uvec4' // glsVertexArrayTests.deArray.OutputType.UVEC4
+ ];
+ DE_ASSERT(types.length == Object.keys(glsVertexArrayTests.deArray.OutputType).length);
+
+ return types[type];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Usage} usage
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.usageTypeToString = function(usage) {
+ DE_ASSERT(usage < Object.keys(glsVertexArrayTests.deArray.Usage).length);
+
+ /** @type {Array<string>} */ var usages =
+ [
+ 'dynamic_draw', // glsVertexArrayTests.deArray.Usage.DYNAMIC_DRAW
+ 'static_draw', // glsVertexArrayTests.deArray.Usage.STATIC_DRAW
+ 'stream_draw', // glsVertexArrayTests.deArray.Usage.STREAM_DRAW
+
+ 'stream_read', // glsVertexArrayTests.deArray.Usage.STREAM_READ
+ 'stream_copy', // glsVertexArrayTests.deArray.Usage.STREAM_COPY
+
+ 'static_read', // glsVertexArrayTests.deArray.Usage.STATIC_READ
+ 'static_copy', // glsVertexArrayTests.deArray.Usage.STATIC_COPY
+
+ 'dynamic_read', // glsVertexArrayTests.deArray.Usage.DYNAMIC_READ
+ 'dynamic_copy' // glsVertexArrayTests.deArray.Usage.DYNAMIC_COPY
+ ];
+ DE_ASSERT(usages.length == Object.keys(glsVertexArrayTests.deArray.Usage).length);
+
+ return usages[usage];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Storage} storage
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.storageToString = function(storage) {
+ DE_ASSERT(storage < Object.keys(glsVertexArrayTests.deArray.Storage).length);
+
+ /** @type {Array<string>} */ var storages =
+ [
+ 'user_ptr', // glsVertexArrayTests.deArray.Storage.USER
+ 'buffer' // glsVertexArrayTests.deArray.Storage.BUFFER
+ ];
+ DE_ASSERT(storages.length == Object.keys(glsVertexArrayTests.deArray.Storage).length);
+
+ return storages[storage];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @return {string}
+ */
+ glsVertexArrayTests.deArray.primitiveToString = function(primitive) {
+ DE_ASSERT(primitive < Object.keys(glsVertexArrayTests.deArray.Primitive).length);
+
+ /** @type {Array<string>} */ var primitives =
+ [
+ 'points', // glsVertexArrayTests.deArray.Primitive.POINTS
+ 'triangles', // glsVertexArrayTests.deArray.Primitive.TRIANGLES
+ 'triangle_fan', // glsVertexArrayTests.deArray.Primitive.TRIANGLE_FAN
+ 'triangle_strip' // glsVertexArrayTests.deArray.Primitive.TRIANGLE_STRIP
+ ];
+ DE_ASSERT(primitives.length == Object.keys(glsVertexArrayTests.deArray.Primitive).length);
+
+ return primitives[primitive];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {number}
+ */
+ glsVertexArrayTests.deArray.inputTypeSize = function(type) {
+ DE_ASSERT(type < Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ /** @type {Array<number>} */ var size = [
+ 4, // glsVertexArrayTests.deArray.InputType.FLOAT
+
+ 1, // glsVertexArrayTests.deArray.InputType.BYTE
+ 2, // glsVertexArrayTests.deArray.InputType.SHORT
+
+ 1, // glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE
+ 2, // glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT
+
+ 4, // glsVertexArrayTests.deArray.InputType.INT
+ 4, // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT
+ 2, // glsVertexArrayTests.deArray.InputType.HALF
+ 4 / 4, // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10
+ 4 / 4 // glsVertexArrayTests.deArray.InputType.INT_2_10_10_10
+ ];
+ DE_ASSERT(size.length == Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ return size[type];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {boolean}
+ */
+ glsVertexArrayTests.inputTypeIsFloatType = function(type) {
+ if (type == glsVertexArrayTests.deArray.InputType.FLOAT)
+ return true;
+ /*if (type == glsVertexArrayTests.deArray.InputType.FIXED)
+ return true;
+ if (type == glsVertexArrayTests.deArray.InputType.DOUBLE)
+ return true;*/
+ if (type == glsVertexArrayTests.deArray.InputType.HALF)
+ return true;
+ return false;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.OutputType} type
+ * @return {boolean}
+ */
+ glsVertexArrayTests.outputTypeIsFloatType = function(type) {
+ if (type == glsVertexArrayTests.deArray.OutputType.FLOAT ||
+ type == glsVertexArrayTests.deArray.OutputType.VEC2 ||
+ type == glsVertexArrayTests.deArray.OutputType.VEC3 ||
+ type == glsVertexArrayTests.deArray.OutputType.VEC4)
+ return true;
+
+ return false;
+ };
+
+ //glsVertexArrayTests.deArray member functions (all virtual, since this is an interface)
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @param {number} size
+ * @param {Uint8Array} data
+ * @param {glsVertexArrayTests.deArray.Usage} usage
+ */
+ glsVertexArrayTests.deArray.prototype.data = function(target, size, data, usage) {};
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @param {number} offset
+ * @param {number} size
+ * @param {Uint8Array} data
+ */
+ glsVertexArrayTests.deArray.prototype.subdata = function(target, offset, size, data) {};
+
+ /**
+ * @param {number} attribNdx
+ * @param {number} offset
+ * @param {number} size
+ * @param {glsVertexArrayTests.deArray.InputType} inType
+ * @param {glsVertexArrayTests.deArray.OutputType} outType
+ * @param {boolean} normalized
+ * @param {number} stride
+ */
+ glsVertexArrayTests.deArray.prototype.bind = function(attribNdx, offset, size, inType, outType, normalized, stride) {};
+
+ /**
+ * unBind
+ */
+ glsVertexArrayTests.deArray.prototype.unBind = function() {};
+
+ /**
+ * @return {boolean}
+ */
+ glsVertexArrayTests.deArray.prototype.isBound = function() {};
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.deArray.prototype.getComponentCount = function() {};
+
+ /**
+ * @return {glsVertexArrayTests.deArray.Target}
+ */
+ glsVertexArrayTests.deArray.prototype.getTarget = function() {};
+
+ /**
+ * @return {glsVertexArrayTests.deArray.InputType}
+ */
+ glsVertexArrayTests.deArray.prototype.getInputType = function() {};
+
+ /**
+ * @return {glsVertexArrayTests.deArray.OutputType}
+ */
+ glsVertexArrayTests.deArray.prototype.getOutputType = function() {};
+
+ /**
+ * @return {glsVertexArrayTests.deArray.Storage}
+ */
+ glsVertexArrayTests.deArray.prototype.getStorageType = function() {};
+
+ /**
+ * @return {boolean}
+ */
+ glsVertexArrayTests.deArray.prototype.getNormalized = function() {};
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.deArray.prototype.getStride = function() {};
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.deArray.prototype.getAttribNdx = function() {};
+
+ /**
+ * @param {number} attribNdx
+ */
+ glsVertexArrayTests.deArray.prototype.setAttribNdx = function(attribNdx) {};
+
+ //glsVertexArrayTests.ContextArray class, implements glsVertexArrayTests.deArray interface
+
+ /**
+ * @constructor
+ * @implements {glsVertexArrayTests.deArray}
+ * @param {glsVertexArrayTests.deArray.Storage} storage
+ * @param {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} context
+ */
+ glsVertexArrayTests.ContextArray = function(storage, context) {
+ /** @type {glsVertexArrayTests.deArray.Storage} */ this.m_storage = storage;
+ /** @type {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} */ this.m_ctx = context;
+ /** @type {WebGLBuffer|sglrReferenceContext.DataBuffer|null} */ this.m_glBuffer = null;
+
+ /** @type {boolean} */ this.m_bound = false;
+ /** @type {number} */ this.m_attribNdx = 0;
+ /** @type {number} */ this.m_size = 0;
+ /** @type {Uint8Array} */ this.m_data = null;
+ /** @type {number} */ this.m_componentCount = 1;
+ /** @type {glsVertexArrayTests.deArray.Target} */ this.m_target = glsVertexArrayTests.deArray.Target.ARRAY;
+ /** @type {glsVertexArrayTests.deArray.InputType} */ this.m_inputType = glsVertexArrayTests.deArray.InputType.FLOAT;
+ /** @type {glsVertexArrayTests.deArray.OutputType} */ this.m_outputType = glsVertexArrayTests.deArray.OutputType.FLOAT;
+ /** @type {boolean} */ this.m_normalize = false;
+ /** @type {number} */ this.m_stride = 0;
+ /** @type {number} */ this.m_offset = 0;
+
+ if (this.m_storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ this.m_glBuffer = this.m_ctx.createBuffer();
+ }
+ };
+
+ // glsVertexArrayTests.ContextArray member functions
+
+ /**
+ * unBind
+ */
+ glsVertexArrayTests.ContextArray.prototype.unBind = function() { this.m_bound = false; };
+
+ /**
+ * @return {boolean}
+ */
+ glsVertexArrayTests.ContextArray.prototype.isBound = function() { return this.m_bound; };
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getComponentCount = function() { return this.m_componentCount; };
+
+ /**
+ * @return {glsVertexArrayTests.deArray.Target}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getTarget = function() { return this.m_target; };
+
+ /**
+ * @return {glsVertexArrayTests.deArray.InputType}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getInputType = function() { return this.m_inputType; };
+
+ /**
+ * @return {glsVertexArrayTests.deArray.OutputType}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getOutputType = function() { return this.m_outputType; };
+
+ /**
+ * @return {glsVertexArrayTests.deArray.Storage}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getStorageType = function() { return this.m_storage; };
+
+ /**
+ * @return {boolean}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getNormalized = function() { return this.m_normalize; };
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getStride = function() { return this.m_stride; };
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.prototype.getAttribNdx = function() { return this.m_attribNdx; };
+
+ /**
+ * @param {number} attribNdx
+ */
+ glsVertexArrayTests.ContextArray.prototype.setAttribNdx = function(attribNdx) { this.m_attribNdx = attribNdx; };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @param {number} size
+ * @param {Uint8Array} ptr
+ * @param {glsVertexArrayTests.deArray.Usage} usage
+ */
+ glsVertexArrayTests.ContextArray.prototype.data = function(target, size, ptr, usage) {
+ this.m_size = size;
+ this.m_target = target;
+
+ if (this.m_storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(target), this.m_glBuffer);
+
+ //No need for size param here, as opposed to GL ES.
+ this.m_ctx.bufferData(glsVertexArrayTests.ContextArray.targetToGL(target), ptr, glsVertexArrayTests.ContextArray.usageToGL(usage));
+ } else if (this.m_storage == glsVertexArrayTests.deArray.Storage.USER) {
+ this.m_data = new Uint8Array(size);
+ for (var i = 0; i < size; i++)
+ this.m_data[i] = ptr[i];
+ } else
+ throw new Error('glsVertexArrayTests.ContextArray.prototype.data - Invalid storage type specified');
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @param {number} offset
+ * @param {number} size
+ * @param {Uint8Array} ptr
+ */
+ glsVertexArrayTests.ContextArray.prototype.subdata = function(target, offset, size, ptr) {
+ this.m_target = target;
+
+ if (this.m_storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(target), this.m_glBuffer);
+
+ this.m_ctx.bufferSubData(glsVertexArrayTests.ContextArray.targetToGL(target), offset, ptr);
+ } else if (this.m_storage == glsVertexArrayTests.deArray.Storage.USER)
+ for (var i = offset; i < size; i++)
+ this.m_data[i] = ptr[i];
+ else
+ throw new Error('glsVertexArrayTests.ContextArray.prototype.subdata - Invalid storage type specified');
+ };
+
+ /**
+ * @param {number} attribNdx
+ * @param {number} offset
+ * @param {number} size
+ * @param {glsVertexArrayTests.deArray.InputType} inType
+ * @param {glsVertexArrayTests.deArray.OutputType} outType
+ * @param {boolean} normalized
+ * @param {number} stride
+ */
+ glsVertexArrayTests.ContextArray.prototype.bind = function(attribNdx, offset, size, inType, outType, normalized, stride) {
+ this.m_attribNdx = attribNdx;
+ this.m_bound = true;
+ this.m_componentCount = size;
+ this.m_inputType = inType;
+ this.m_outputType = outType;
+ this.m_normalize = normalized;
+ this.m_stride = stride;
+ this.m_offset = offset;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ */
+ glsVertexArrayTests.ContextArray.prototype.bindIndexArray = function(target) {
+ if (this.m_storage == glsVertexArrayTests.deArray.Storage.USER) {
+ } else if (this.m_storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(target), this.m_glBuffer);
+ }
+ };
+
+ /**
+ * @param {number} loc
+ */
+ glsVertexArrayTests.ContextArray.prototype.glBind = function(loc) {
+ if (this.m_storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(this.m_target), this.m_glBuffer);
+
+ if (!glsVertexArrayTests.inputTypeIsFloatType(this.m_inputType)) {
+ // Input is not float type
+
+ if (glsVertexArrayTests.outputTypeIsFloatType(this.m_outputType)) {
+ // Output type is float type
+ this.m_ctx.vertexAttribPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_normalize, this.m_stride, this.m_offset);
+ } else {
+ // Output type is int type
+ this.m_ctx.vertexAttribIPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_stride, this.m_offset);
+ }
+ } else {
+ // Input type is float type
+ // Output type must be float type
+ DE_ASSERT(this.m_outputType == glsVertexArrayTests.deArray.OutputType.FLOAT || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC2 || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC3 || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC4);
+
+ this.m_ctx.vertexAttribPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_normalize, this.m_stride, this.m_offset);
+ }
+
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(this.m_target), null);
+ } else if (this.m_storage == glsVertexArrayTests.deArray.Storage.USER) {
+ this.m_ctx.bindBuffer(glsVertexArrayTests.ContextArray.targetToGL(this.m_target), null);
+
+ if (!glsVertexArrayTests.inputTypeIsFloatType(this.m_inputType)) {
+ // Input is not float type
+
+ if (glsVertexArrayTests.outputTypeIsFloatType(this.m_outputType)) {
+ // Output type is float type
+ this.m_ctx.vertexAttribPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_normalize, this.m_stride, this.m_data.subarray(this.m_offset));
+ } else {
+ // Output type is int type
+ this.m_ctx.vertexAttribIPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_stride, this.m_data.subarray(this.m_offset));
+ }
+ } else {
+ // Input type is float type
+
+ // Output type must be float type
+ DE_ASSERT(this.m_outputType == glsVertexArrayTests.deArray.OutputType.FLOAT || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC2 || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC3 || this.m_outputType == glsVertexArrayTests.deArray.OutputType.VEC4);
+
+ this.m_ctx.vertexAttribPointer(loc, this.m_componentCount, glsVertexArrayTests.ContextArray.inputTypeToGL(this.m_inputType), this.m_normalize, this.m_stride, this.m_data.subarray(this.m_offset));
+ }
+ } else
+ throw new Error('glsVertexArrayTests.ContextArray.prototype.glBind - Invalid storage type specified');
+ };
+
+ //glsVertexArrayTests.ContextArray static functions
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Target} target
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.targetToGL = function(target) {
+ DE_ASSERT(target < Object.keys(glsVertexArrayTests.deArray.Target).length);
+
+ /** @type {Array<number>} */ var targets =
+ [
+ gl.ELEMENT_ARRAY_BUFFER, // glsVertexArrayTests.deArray.Target.ELEMENT_ARRAY
+ gl.ARRAY_BUFFER // glsVertexArrayTests.deArray.Target.ARRAY
+ ];
+
+ return targets[target];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Usage} usage
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.usageToGL = function(usage) {
+ DE_ASSERT(usage < Object.keys(glsVertexArrayTests.deArray.Usage).length);
+
+ /** @type {Array<number>} */ var usages =
+ [
+ gl.DYNAMIC_DRAW, // glsVertexArrayTests.deArray.Usage.DYNAMIC_DRAW
+ gl.STATIC_DRAW, // glsVertexArrayTests.deArray.Usage.STATIC_DRAW
+ gl.STREAM_DRAW, // glsVertexArrayTests.deArray.Usage.STREAM_DRAW
+
+ gl.STREAM_READ, // glsVertexArrayTests.deArray.Usage.STREAM_READ
+ gl.STREAM_COPY, // glsVertexArrayTests.deArray.Usage.STREAM_COPY
+
+ gl.STATIC_READ, // glsVertexArrayTests.deArray.Usage.STATIC_READ
+ gl.STATIC_COPY, // glsVertexArrayTests.deArray.Usage.STATIC_COPY
+
+ gl.DYNAMIC_READ, // glsVertexArrayTests.deArray.Usage.DYNAMIC_READ
+ gl.DYNAMIC_COPY // glsVertexArrayTests.deArray.Usage.DYNAMIC_COPY
+ ];
+ DE_ASSERT(usages.length == Object.keys(glsVertexArrayTests.deArray.Usage).length);
+
+ return usages[usage];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.inputTypeToGL = function(type) {
+ DE_ASSERT(type < Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ /** @type {Array<number>} */ var types =
+ [
+ gl.FLOAT, // glsVertexArrayTests.deArray.InputType.FLOAT
+
+ gl.BYTE, // glsVertexArrayTests.deArray.InputType.BYTE
+ gl.SHORT, // glsVertexArrayTests.deArray.InputType.SHORT
+ gl.UNSIGNED_BYTE, // glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE
+ gl.UNSIGNED_SHORT, // glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT
+
+ gl.INT, // glsVertexArrayTests.deArray.InputType.INT
+ gl.UNSIGNED_INT, // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT
+ gl.HALF_FLOAT, // glsVertexArrayTests.deArray.InputType.HALF
+ gl.UNSIGNED_INT_2_10_10_10_REV, // glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10
+ gl.INT_2_10_10_10_REV // glsVertexArrayTests.deArray.InputType.INT_2_10_10_10
+ ];
+ DE_ASSERT(types.length == Object.keys(glsVertexArrayTests.deArray.InputType).length);
+
+ return types[type];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.OutputType} type
+ * @return {string}
+ */
+ glsVertexArrayTests.ContextArray.outputTypeToGLType = function(type) {
+ DE_ASSERT(type < Object.keys(glsVertexArrayTests.deArray.OutputType).length);
+
+ /** @type {Array<string>} */ var types =
+ [
+ 'float', // glsVertexArrayTests.deArray.OutputType.FLOAT
+ 'vec2', // glsVertexArrayTests.deArray.OutputType.VEC2
+ 'vec3', // glsVertexArrayTests.deArray.OutputType.VEC3
+ 'vec4', // glsVertexArrayTests.deArray.OutputType.VEC4
+
+ 'int', // glsVertexArrayTests.deArray.OutputType.INT
+ 'uint', // glsVertexArrayTests.deArray.OutputType.UINT
+
+ 'ivec2', // glsVertexArrayTests.deArray.OutputType.IVEC2
+ 'ivec3', // glsVertexArrayTests.deArray.OutputType.IVEC3
+ 'ivec4', // glsVertexArrayTests.deArray.OutputType.IVEC4
+
+ 'uvec2', // glsVertexArrayTests.deArray.OutputType.UVEC2
+ 'uvec3', // glsVertexArrayTests.deArray.OutputType.UVEC3
+ 'uvec4' // glsVertexArrayTests.deArray.OutputType.UVEC4
+ ];
+ DE_ASSERT(types.length == Object.keys(glsVertexArrayTests.deArray.OutputType).length);
+
+ return types[type];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArray.primitiveToGL = function(primitive) {
+ /** @type {Array<number>} */ var primitives =
+ [
+ gl.POINTS, // glsVertexArrayTests.deArray.Primitive.POINTS
+ gl.TRIANGLES, // glsVertexArrayTests.deArray.Primitive.TRIANGLES
+ gl.TRIANGLE_FAN, // glsVertexArrayTests.deArray.Primitive.TRIANGLE_FAN
+ gl.TRIANGLE_STRIP // glsVertexArrayTests.deArray.Primitive.TRIANGLE_STRIP
+ ];
+ DE_ASSERT(primitives.length == Object.keys(glsVertexArrayTests.deArray.Primitive).length);
+
+ return primitives[primitive];
+ };
+
+ /**
+ * @constructor
+ * @param {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} drawContext
+ */
+ glsVertexArrayTests.ContextArrayPack = function(drawContext) {
+ /** @type {WebGLRenderingContextBase} */ this.m_renderCtx = gl;
+ //TODO: Reference rasterizer implementation.
+ /** @type {sglrGLContext.GLContext | sglrReferenceContext.ReferenceContext} */ this.m_ctx = drawContext;
+
+ /** @type {Array<glsVertexArrayTests.ContextArray>} */ this.m_arrays = [];
+ /** @type {sglrShaderProgram.ShaderProgram} */ this.m_program;
+ /** @type {tcuSurface.Surface} */ this.m_screen = new tcuSurface.Surface(
+ Math.min(512, canvas.width),
+ Math.min(512, canvas.height)
+ );
+ };
+
+ /**
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.getArrayCount = function() {
+ return this.m_arrays.length;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Storage} storage
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.newArray = function(storage) {
+ this.m_arrays.push(new glsVertexArrayTests.ContextArray(storage, this.m_ctx));
+ };
+
+ /**
+ * @param {number} i
+ * @return {glsVertexArrayTests.ContextArray}
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.getArray = function(i) {
+ return this.m_arrays[i];
+ };
+
+ /**
+ * updateProgram
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.updateProgram = function() {
+ this.m_program = new glsVertexArrayTests.ContextShaderProgram(this.m_renderCtx, this.m_arrays);
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @param {number} firstVertex
+ * @param {number} vertexCount
+ * @param {boolean} useVao
+ * @param {number} coordScale
+ * @param {number} colorScale
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.render = function(primitive, firstVertex, vertexCount, useVao, coordScale, colorScale) {
+ var program;
+ /** @type {(WebGLVertexArrayObject|sglrReferenceContext.VertexArray|null)} */ var vaoID = null;
+
+ this.updateProgram();
+
+ this.m_ctx.viewport(0, 0, this.m_screen.getWidth(), this.m_screen.getHeight());
+ this.m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
+ this.m_ctx.clear(gl.COLOR_BUFFER_BIT);
+
+ program = this.m_ctx.createProgram(this.m_program);
+
+ this.m_ctx.useProgram(program);
+
+ this.m_ctx.uniform1f(this.m_ctx.getUniformLocation(program, 'u_coordScale'), coordScale);
+ this.m_ctx.uniform1f(this.m_ctx.getUniformLocation(program, 'u_colorScale'), colorScale);
+
+ if (useVao) {
+ vaoID = this.m_ctx.createVertexArray();
+ this.m_ctx.bindVertexArray(vaoID);
+ }
+
+ /** @type {string} */ var attribName;
+ /** @type {number} */ var loc;
+ for (var arrayNdx = 0; arrayNdx < this.m_arrays.length; arrayNdx++) {
+ if (this.m_arrays[arrayNdx].isBound()) {
+ attribName = 'a_' + this.m_arrays[arrayNdx].getAttribNdx();
+ loc = this.m_ctx.getAttribLocation(program, attribName);
+ this.m_ctx.enableVertexAttribArray(loc);
+
+ this.m_arrays[arrayNdx].glBind(loc);
+ }
+ }
+
+ DE_ASSERT((firstVertex % 6) == 0);
+ //this.m_ctx.drawArrays(glsVertexArrayTests.ContextArray.primitiveToGL(primitive), firstVertex, vertexCount - firstVertex);
+ this.m_ctx.drawQuads(gl.TRIANGLES, firstVertex, vertexCount - firstVertex);
+
+ for (var arrayNdx = 0; arrayNdx < this.m_arrays.length; arrayNdx++) {
+ if (this.m_arrays[arrayNdx].isBound()) {
+ attribName = 'a_' + this.m_arrays[arrayNdx].getAttribNdx();
+ loc = this.m_ctx.getAttribLocation(program, attribName);
+
+ this.m_ctx.disableVertexAttribArray(loc);
+ }
+ }
+
+ if (useVao)
+ vaoID = this.m_ctx.deleteVertexArray(vaoID);
+
+ this.m_ctx.deleteProgram(program);
+ this.m_ctx.useProgram(null);
+ this.m_ctx.readPixels(0, 0, this.m_screen.getWidth(), this.m_screen.getHeight(), gl.RGBA, gl.UNSIGNED_BYTE, this.m_screen.getAccess().getDataPtr());
+ };
+
+ /**
+ * @return {tcuSurface.Surface}
+ */
+ glsVertexArrayTests.ContextArrayPack.prototype.getSurface = function() { return this.m_screen; };
+
+ /**
+ * glsVertexArrayTests.ContextShaderProgram class
+ * @constructor
+ * @extends {sglrShaderProgram.ShaderProgram}
+ * @param {WebGLRenderingContextBase | sglrReferenceContext.ReferenceContext} ctx
+ * @param {Array<glsVertexArrayTests.ContextArray>} arrays
+ */
+ glsVertexArrayTests.ContextShaderProgram = function(ctx, arrays) {
+ sglrShaderProgram.ShaderProgram.call(this, this.createProgramDeclaration(ctx, arrays));
+ this.m_componentCount = new Array(arrays.length);
+ /** @type {Array<rrGenericVector.GenericVecType>} */ this.m_attrType = new Array(arrays.length);
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ this.m_componentCount[arrayNdx] = this.getComponentCount(arrays[arrayNdx].getOutputType());
+ this.m_attrType[arrayNdx] = this.mapOutputType(arrays[arrayNdx].getOutputType());
+ }
+ };
+
+ glsVertexArrayTests.ContextShaderProgram.prototype = Object.create(sglrShaderProgram.ShaderProgram.prototype);
+ glsVertexArrayTests.ContextShaderProgram.prototype.constructor = glsVertexArrayTests.ContextShaderProgram;
+
+ /**
+ * glsVertexArrayTests.calcShaderColorCoord function
+ * @param {Array<number>} coord (2 elements)
+ * @param {Array<number>} color (3 elements)
+ * @param {goog.NumberArray} attribValue (4 elements)
+ * @param {boolean} isCoordinate
+ * @param {number} numComponents
+ */
+ glsVertexArrayTests.calcShaderColorCoord = function(coord, color, attribValue, isCoordinate, numComponents) {
+ if (isCoordinate)
+ switch (numComponents) {
+ case 1:
+ coord[0] = attribValue[0];
+ coord[1] = attribValue[0];
+ break;
+ case 2:
+ coord[0] = attribValue[0];
+ coord[1] = attribValue[1];
+ break;
+ case 3:
+ coord[0] = attribValue[0] + attribValue[2];
+ coord[1] = attribValue[1];
+ break;
+ case 4:
+ coord[0] = attribValue[0] + attribValue[2];
+ coord[1] = attribValue[1] + attribValue[3];
+ break;
+ default:
+ throw new Error('glsVertexArrayTests.calcShaderColorCoord - Invalid number of components');
+ } else {
+ switch (numComponents) {
+ case 1:
+ color[0] = color[0] * attribValue[0];
+ break;
+ case 2:
+ color[0] = color[0] * attribValue[0];
+ color[1] = color[1] * attribValue[1];
+ break;
+ case 3:
+ color[0] = color[0] * attribValue[0];
+ color[1] = color[1] * attribValue[1];
+ color[2] = color[2] * attribValue[2];
+ break;
+ case 4:
+ color[0] = color[0] * attribValue[0] * attribValue[3];
+ color[1] = color[1] * attribValue[1] * attribValue[3];
+ color[2] = color[2] * attribValue[2] * attribValue[3];
+ break;
+ default:
+ throw new Error('glsVertexArrayTests.calcShaderColorCoord - Invalid number of components');
+ }
+ }
+ };
+
+ /**
+ * glsVertexArrayTests.ContextShaderProgram.shadeVertices
+ * @param {Array<rrVertexAttrib.VertexAttrib>} inputs
+ * @param {Array<rrVertexPacket.VertexPacket>} packets
+ * @param {number} numPackets
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) {
+ /** @type {number} */ var u_coordScale = this.getUniformByName('u_coordScale').value[0];
+ /** @type {number} */ var u_colorScale = this.getUniformByName('u_colorScale').value[0];
+
+ for (var packetNdx = 0; packetNdx < numPackets; ++packetNdx) {
+ /** @type {number} */ var varyingLocColor = 0;
+
+ /** @type {rrVertexPacket.VertexPacket} */ var packet = packets[packetNdx];
+
+ // Calc output color
+ /** @type {Array<number>} */ var coord = [1.0, 1.0];
+ /** @type {Array<number>} */ var color = [1.0, 1.0, 1.0];
+
+ for (var attribNdx = 0; attribNdx < this.m_attrType.length; attribNdx++) {
+ /** @type {number} */ var numComponents = this.m_componentCount[attribNdx];
+
+ glsVertexArrayTests.calcShaderColorCoord(coord, color, rrVertexAttrib.readVertexAttrib(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx, this.m_attrType[attribNdx]), attribNdx == 0, numComponents);
+ }
+
+ // Transform position
+ packet.position = [u_coordScale * coord[0], u_coordScale * coord[1], 1.0, 1.0];
+
+ // Pass color to FS
+ packet.outputs[varyingLocColor] = [u_colorScale * color[0], u_colorScale * color[1], u_colorScale * color[2], 1.0];
+ }
+ };
+
+ /**
+ * @param {Array<rrFragmentOperations.Fragment>} packets
+ * @param {rrShadingContext.FragmentShadingContext} context
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.shadeFragments = function(packets, context) {
+ var varyingLocColor = 0;
+
+ // Normal shading
+ for (var packetNdx = 0; packetNdx < packets.length; ++packetNdx)
+ packets[packetNdx].value = rrShadingContext.readTriangleVarying(packets[packetNdx], context, varyingLocColor);
+ };
+
+ /**
+ * @param {Array<glsVertexArrayTests.ContextArray>} arrays
+ * @return string
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.genVertexSource = function(arrays) {
+ var vertexShaderSrc = '';
+ var params = [];
+
+ params['VTX_IN'] = 'in';
+ params['VTX_OUT'] = 'out';
+ params['FRAG_IN'] = 'in';
+ params['FRAG_COLOR'] = 'dEQP_FragColor';
+ params['VTX_HDR'] = '#version 300 es\n';
+ params['FRAG_HDR'] = '#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+
+ vertexShaderSrc += params['VTX_HDR'];
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ vertexShaderSrc += params['VTX_IN'] + ' highp ' + glsVertexArrayTests.ContextArray.outputTypeToGLType(arrays[arrayNdx].getOutputType()) + ' a_' + arrays[arrayNdx].getAttribNdx() + ';\n';
+ }
+
+ vertexShaderSrc +=
+ 'uniform highp float u_coordScale;\n' +
+ 'uniform highp float u_colorScale;\n' +
+ params['VTX_OUT'] + ' mediump vec4 v_color;\n' +
+ 'void main(void)\n' +
+ ' {\n' +
+ '\tgl_PointSize = 1.0;\n' +
+ '\thighp vec2 coord = vec2(1.0, 1.0);\n' +
+ '\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n';
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++) {
+ if (arrays[arrayNdx].getAttribNdx() == 0) {
+ switch (arrays[arrayNdx].getOutputType()) {
+ case (glsVertexArrayTests.deArray.OutputType.FLOAT):
+ vertexShaderSrc +=
+ '\tcoord = vec2(a_0);\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC2):
+ vertexShaderSrc +=
+ '\tcoord = a_0.xy;\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC3):
+ vertexShaderSrc +=
+ '\tcoord = a_0.xy;\n' +
+ '\tcoord.x = coord.x + a_0.z;\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC4):
+ vertexShaderSrc +=
+ '\tcoord = a_0.xy;\n' +
+ '\tcoord += a_0.zw;\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.IVEC2):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC2):
+ vertexShaderSrc +=
+ '\tcoord = vec2(a_0.xy);\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.IVEC3):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC3):
+ vertexShaderSrc +=
+ '\tcoord = vec2(a_0.xy);\n' +
+ '\tcoord.x = coord.x + float(a_0.z);\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.IVEC4):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC4):
+ vertexShaderSrc +=
+ '\tcoord = vec2(a_0.xy);\n' +
+ '\tcoord += vec2(a_0.zw);\n';
+ break;
+
+ default:
+ throw new Error('Invalid output type');
+ break;
+ }
+ continue;
+ }
+
+ switch (arrays[arrayNdx].getOutputType()) {
+ case (glsVertexArrayTests.deArray.OutputType.FLOAT):
+ vertexShaderSrc +=
+ '\tcolor = color * a_' + arrays[arrayNdx].getAttribNdx() + ';\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC2):
+ vertexShaderSrc +=
+ '\tcolor.rg = color.rg * a_' + arrays[arrayNdx].getAttribNdx() + '.xy;\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC3):
+ vertexShaderSrc +=
+ '\tcolor = color.rgb * a_' + arrays[arrayNdx].getAttribNdx() + '.xyz;\n';
+ break;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC4):
+ vertexShaderSrc +=
+ '\tcolor = color.rgb * a_' + arrays[arrayNdx].getAttribNdx() + '.xyz * a_' + arrays[arrayNdx].getAttribNdx() + '.w;\n';
+ break;
+
+ default:
+ throw new Error('Invalid output type');
+ break;
+ }
+ }
+
+ vertexShaderSrc +=
+ '\tv_color = vec4(u_colorScale * color, 1.0);\n' +
+ '\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n' +
+ '}\n';
+
+ return vertexShaderSrc;
+ };
+
+ /**
+ * @return {string}
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.genFragmentSource = function() {
+ var params = [];
+
+ params['VTX_IN'] = 'in';
+ params['VTX_OUT'] = 'out';
+ params['FRAG_IN'] = 'in';
+ params['FRAG_COLOR'] = 'dEQP_FragColor';
+ params['VTX_HDR'] = '#version 300 es\n';
+ params['FRAG_HDR'] = '#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n';
+
+ /* TODO: Check if glsl supported version check function is needed.*/
+
+ var fragmentShaderSrc = params['FRAG_HDR'] +
+ params['FRAG_IN'] + ' mediump vec4 v_color;\n' +
+ 'void main(void)\n' +
+ ' {\n' +
+ '\t' + params['FRAG_COLOR'] + ' = v_color;\n' +
+ '}\n';
+
+ return fragmentShaderSrc;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.OutputType} type
+ * @return {rrGenericVector.GenericVecType}
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.mapOutputType = function(type) {
+ switch (type) {
+ case (glsVertexArrayTests.deArray.OutputType.FLOAT):
+ case (glsVertexArrayTests.deArray.OutputType.VEC2):
+ case (glsVertexArrayTests.deArray.OutputType.VEC3):
+ case (glsVertexArrayTests.deArray.OutputType.VEC4):
+ return rrGenericVector.GenericVecType.FLOAT;
+
+ case (glsVertexArrayTests.deArray.OutputType.INT):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC2):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC3):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC4):
+ return rrGenericVector.GenericVecType.INT32;
+
+ case (glsVertexArrayTests.deArray.OutputType.UINT):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC2):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC3):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC4):
+ return rrGenericVector.GenericVecType.UINT32;
+
+ default:
+ throw new Error('Invalid output type');
+ }
+ };
+
+ /**
+ * @param {glsVertexArrayTests.deArray.OutputType} type
+ * @return {number}
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.getComponentCount = function(type) {
+ switch (type) {
+ case (glsVertexArrayTests.deArray.OutputType.FLOAT):
+ case (glsVertexArrayTests.deArray.OutputType.INT):
+ case (glsVertexArrayTests.deArray.OutputType.UINT):
+ return 1;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC2):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC2):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC2):
+ return 2;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC3):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC3):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC3):
+ return 3;
+
+ case (glsVertexArrayTests.deArray.OutputType.VEC4):
+ case (glsVertexArrayTests.deArray.OutputType.IVEC4):
+ case (glsVertexArrayTests.deArray.OutputType.UVEC4):
+ return 4;
+
+ default:
+ throw new Error('Invalid output type');
+ }
+ };
+
+ /**
+ * @param {WebGLRenderingContextBase | sglrReferenceContext.ReferenceContext} ctx
+ * @param {Array<glsVertexArrayTests.ContextArray>} arrays
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ glsVertexArrayTests.ContextShaderProgram.prototype.createProgramDeclaration = function(ctx, arrays) {
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var decl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ for (var arrayNdx = 0; arrayNdx < arrays.length; arrayNdx++)
+ decl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('a_' + arrayNdx, this.mapOutputType(arrays[arrayNdx].getOutputType())));
+
+ decl.pushVertexToFragmentVarying(new sglrShaderProgram.VertexToFragmentVarying(rrGenericVector.GenericVecType.FLOAT));
+ decl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ decl.pushVertexSource(new sglrShaderProgram.VertexSource(this.genVertexSource(/*ctx,*/ arrays))); //TODO: Check if we need to review the support of a given GLSL version (we'd need the ctx)
+ decl.pushFragmentSource(new sglrShaderProgram.FragmentSource(this.genFragmentSource(/*ctx*/)));
+
+ decl.pushUniform(new sglrShaderProgram.Uniform('u_coordScale', gluShaderUtil.DataType.FLOAT));
+ decl.pushUniform(new sglrShaderProgram.Uniform('u_colorScale', gluShaderUtil.DataType.FLOAT));
+
+ return decl;
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue class
+ * @constructor
+ */
+ glsVertexArrayTests.GLValue = function() {
+ /** @type {goog.NumberArray} */ this.m_value = [0];
+ /** @type {glsVertexArrayTests.deArray.InputType} */ this.m_type;
+ };
+
+ /**
+ * @param {Uint8Array} dst
+ * @param {glsVertexArrayTests.GLValue} val
+ */
+ glsVertexArrayTests.copyGLValueToArray = function(dst, val) {
+ /** @type {Uint8Array} */ var val8 = new Uint8Array(val.m_value.buffer); // TODO: Fix encapsulation issue
+ dst.set(val8);
+ };
+
+ /**
+ * @param {Uint8Array} dst
+ * @param {goog.NumberArray} src
+ */
+ glsVertexArrayTests.copyArray = function(dst, src) {
+ /** @type {Uint8Array} */ var src8 = new Uint8Array(src.buffer).subarray(src.byteOffset, src.byteOffset + src.byteLength); // TODO: Fix encapsulation issue
+ dst.set(src8);
+ };
+
+ /**
+ * typeToTypedArray function. Determines which type of array will store the value, and stores it.
+ * @param {number} value
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ */
+ glsVertexArrayTests.GLValue.typeToTypedArray = function(value, type) {
+ var array;
+
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ array = new Float32Array(1);
+ break;
+ /*case glsVertexArrayTests.deArray.InputType.FIXED:
+ array = new Int32Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ array = new Float32Array(1); // 64-bit?
+ break;*/
+
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ array = new Int8Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ array = new Int16Array(1);
+ break;
+
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ array = new Uint8Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ array = new Uint16Array(1);
+ break;
+
+ case glsVertexArrayTests.deArray.InputType.INT:
+ array = new Int32Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ array = new Uint32Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ array = new Uint16Array(1);
+ value = glsVertexArrayTests.GLValue.floatToHalf(value);
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10:
+ array = new Uint32Array(1);
+ break;
+ case glsVertexArrayTests.deArray.InputType.INT_2_10_10_10:
+ array = new Int32Array(1);
+ break;
+ default:
+ throw new Error('glsVertexArrayTests.GLValue.typeToTypedArray - Invalid InputType');
+ }
+
+ array[0] = value;
+ return array;
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.create
+ * @param {number} value
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ */
+ glsVertexArrayTests.GLValue.create = function(value, type) {
+ var v = new glsVertexArrayTests.GLValue();
+ v.m_value = glsVertexArrayTests.GLValue.typeToTypedArray(value, type);
+ v.m_type = type;
+ return v;
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.halfToFloat
+ * @param {number} value
+ * @return {number}
+ */
+ glsVertexArrayTests.GLValue.halfToFloat = function(value) {
+ return tcuFloat.halfFloatToNumberNoDenorm(value);
+ };
+
+ /**
+ * @param {number} f
+ * @return {number}
+ */
+ glsVertexArrayTests.GLValue.floatToHalf = function(f) {
+ // No denorm support.
+ return tcuFloat.numberToHalfFloatNoDenorm(f);
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.getMaxValue
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.getMaxValue = function(type) {
+ var value;
+
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ value = 127;
+ break;
+ /*case glsVertexArrayTests.deArray.InputType.FIXED:
+ value = 32760;
+ break;
+ case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ value = 127;
+ break;*/
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ value = 127;
+ break;
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ value = 32760;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ value = 255;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ value = 65530;
+ break;
+ case glsVertexArrayTests.deArray.InputType.INT:
+ value = 2147483647;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ value = 4294967295;
+ break;
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ value = 256;
+ break;
+ default: //Original code returns garbage-filled GLValues
+ return new glsVertexArrayTests.GLValue();
+ }
+
+ return glsVertexArrayTests.GLValue.create(value, type);
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.getMinValue
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.getMinValue = function(type) {
+ var value;
+
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ value = -127;
+ break;
+ /*case glsVertexArrayTests.deArray.InputType.FIXED:
+ value = -32760;
+ break;
+ case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ value = -127;
+ break;*/
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ value = -127;
+ break;
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ value = -32760;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ value = 0;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ value = 0;
+ break;
+ case glsVertexArrayTests.deArray.InputType.INT:
+ value = -2147483647;
+ break;
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ value = 0;
+ break;
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ value = -256;
+ break;
+
+ default: //Original code returns garbage-filled GLValues
+ return new glsVertexArrayTests.GLValue();
+ }
+
+ return glsVertexArrayTests.GLValue.create(value, type);
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.getRandom
+ * @param {deRandom.Random} rnd
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.getRandom = function(rnd, min, max) {
+ DE_ASSERT(min.getType() == max.getType());
+
+ var minv = min.interpret();
+ var maxv = max.interpret();
+ var type = min.getType();
+ var value;
+
+ if (maxv < minv)
+ return min;
+
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ //case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ case glsVertexArrayTests.deArray.InputType.HALF: {
+ return glsVertexArrayTests.GLValue.create(minv + rnd.getFloat() * (maxv - minv), type);
+ break;
+ }
+
+ /*case glsVertexArrayTests.deArray.InputType.FIXED: {
+ return minv == maxv ? min : glsVertexArrayTests.GLValue.create(minv + rnd.getInt() % (maxv - minv), type);
+ break;
+ }*/
+
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ case glsVertexArrayTests.deArray.InputType.INT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT: {
+ return glsVertexArrayTests.GLValue.create(minv + rnd.getInt() % (maxv - minv), type);
+ break;
+ }
+
+ default:
+ throw new Error('glsVertexArrayTests.GLValue.getRandom - Invalid input type');
+ break;
+ }
+ };
+
+ // Minimum difference required between coordinates
+
+ /**
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.minValue = function(type) {
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ //case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ return glsVertexArrayTests.GLValue.create(4, type);
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ return glsVertexArrayTests.GLValue.create(4 * 256, type);
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ return glsVertexArrayTests.GLValue.create(4 * 2, type);
+ /*case glsVertexArrayTests.deArray.InputType.FIXED:
+ return glsVertexArrayTests.GLValue.create(4 * 512, type);*/
+ case glsVertexArrayTests.deArray.InputType.INT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ return glsVertexArrayTests.GLValue.create(4 * 16777216, type);
+
+ default:
+ throw new Error('glsVertexArrayTests.GLValue.minValue - Invalid input type');
+ }
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} val
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.abs = function(val) {
+ var type = val.getType();
+ switch (type) {
+ //case glsVertexArrayTests.deArray.InputType.FIXED:
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ return glsVertexArrayTests.GLValue.create(0x7FFF & val.getValue(), type);
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ return glsVertexArrayTests.GLValue.create(0x7F & val.getValue(), type);
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ return val;
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ //case glsVertexArrayTests.deArray.InputType.DOUBLE:
+ return glsVertexArrayTests.GLValue.create(Math.abs(val.interpret()), type);
+ case glsVertexArrayTests.deArray.InputType.INT:
+ return glsVertexArrayTests.GLValue.create(0x7FFFFFFF & val.getValue(), type);
+ default:
+ throw new Error('glsVertexArrayTests.GLValue.abs - Invalid input type');
+ }
+ };
+
+ /**
+ * @return {glsVertexArrayTests.deArray.InputType}
+ */
+ glsVertexArrayTests.GLValue.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.toFloat
+ * @return {number}
+ */
+ glsVertexArrayTests.GLValue.prototype.toFloat = function() {
+ return this.interpret();
+ };
+
+ /**
+ * glsVertexArrayTests.GLValue.getValue
+ * @return {number}
+ */
+ glsVertexArrayTests.GLValue.prototype.getValue = function() {
+ return this.m_value[0];
+ };
+
+ /**
+ * interpret function. Returns the m_value as a quantity so arithmetic operations can be performed on it
+ * Only some types require this.
+ * @return {number}
+ */
+ glsVertexArrayTests.GLValue.prototype.interpret = function() {
+ if (this.m_type == glsVertexArrayTests.deArray.InputType.HALF)
+ return glsVertexArrayTests.GLValue.halfToFloat(this.m_value[0]);
+ /*else if (this.m_type == glsVertexArrayTests.deArray.InputType.FIXED) {
+ var maxValue = 65536;
+ return Math.floor((2 * this.m_value[0] + 1) / (maxValue - 1));
+ }*/
+
+ return this.m_value[0];
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.add = function(other) {
+ return glsVertexArrayTests.GLValue.create(this.interpret() + other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.mul = function(other) {
+ return glsVertexArrayTests.GLValue.create(this.interpret() * other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.div = function(other) {
+ return glsVertexArrayTests.GLValue.create(this.interpret() / other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.sub = function(other) {
+ return glsVertexArrayTests.GLValue.create(this.interpret() - other.interpret(), this.m_type);
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.addToSelf = function(other) {
+ this.m_value[0] = this.interpret() + other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.subToSelf = function(other) {
+ this.m_value[0] = this.interpret() - other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.mulToSelf = function(other) {
+ this.m_value[0] = this.interpret() * other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {glsVertexArrayTests.GLValue}
+ */
+ glsVertexArrayTests.GLValue.prototype.divToSelf = function(other) {
+ this.m_value[0] = this.interpret() / other.interpret();
+ return this;
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {boolean}
+ */
+ glsVertexArrayTests.GLValue.prototype.equals = function(other) {
+ return this.m_value[0] == other.getValue();
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {boolean}
+ */
+ glsVertexArrayTests.GLValue.prototype.lessThan = function(other) {
+ return this.interpret() < other.interpret();
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {boolean}
+ */
+ glsVertexArrayTests.GLValue.prototype.greaterThan = function(other) {
+ return this.interpret() > other.interpret();
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {boolean}
+ */
+ glsVertexArrayTests.GLValue.prototype.lessOrEqualThan = function(other) {
+ return this.interpret() <= other.interpret();
+ };
+
+ /**
+ * @param {glsVertexArrayTests.GLValue} other
+ * @return {boolean}
+ */
+ glsVertexArrayTests.GLValue.prototype.greaterOrEqualThan = function(other) {
+ return this.interpret() >= other.interpret();
+ };
+
+ /**
+ * glsVertexArrayTests.RandomArrayGenerator class. Contains static methods only
+ */
+ glsVertexArrayTests.RandomArrayGenerator = function() {};
+
+ /**
+ * glsVertexArrayTests.RandomArrayGenerator.setData
+ * @param {Uint8Array} data
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @param {deRandom.Random} rnd
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ */
+ glsVertexArrayTests.RandomArrayGenerator.setData = function(data, type, rnd, min, max) {
+ // Parameter type is not necessary, but we'll use it to assert the created glsVertexArrayTests.GLValue is of the correct type.
+ /** @type {glsVertexArrayTests.GLValue} */ var value = glsVertexArrayTests.GLValue.getRandom(rnd, min, max);
+ DE_ASSERT(value.getType() == type);
+
+ glsVertexArrayTests.copyGLValueToArray(data, value);
+ };
+
+ /**
+ * generateArray
+ * @param {number} seed
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @return {ArrayBuffer}
+ */
+ glsVertexArrayTests.RandomArrayGenerator.generateArray = function(seed, min, max, count, componentCount, stride, type) {
+ /** @type {ArrayBuffer} */ var data;
+ /** @type {Uint8Array} */ var data8;
+
+ var rnd = new deRandom.Random(seed);
+
+ if (stride == 0)
+ stride = componentCount * glsVertexArrayTests.deArray.inputTypeSize(type);
+
+ data = new ArrayBuffer(stride * count);
+ data8 = new Uint8Array(data);
+
+ for (var vertexNdx = 0; vertexNdx < count; vertexNdx++) {
+ for (var componentNdx = 0; componentNdx < componentCount; componentNdx++) {
+ glsVertexArrayTests.RandomArrayGenerator.setData(data8.subarray(vertexNdx * stride + glsVertexArrayTests.deArray.inputTypeSize(type) * componentNdx), type, rnd, min, max);
+ }
+ }
+
+ return data;
+ };
+
+ /* {
+ static char* generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, glsVertexArrayTests.GLValue min, glsVertexArrayTests.GLValue max);
+ static char* generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, glsVertexArrayTests.GLValue min, glsVertexArrayTests.GLValue max);
+
+ private:
+ template<typename T>
+ static char* createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max);
+ template<typename T>
+ static char* createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max);
+ static char* createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive);
+ };*/
+
+ /**
+ * @param {number} seed
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} offset
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ * @param {number} scale Coordinate scaling factor
+ * @return {ArrayBuffer}
+ */
+ glsVertexArrayTests.RandomArrayGenerator.generateQuads = function(seed, count, componentCount, offset, stride, primitive, type, min, max, scale) {
+ /** @type {ArrayBuffer} */ var data;
+
+ switch (type) {
+ case glsVertexArrayTests.deArray.InputType.FLOAT:
+ /*case glsVertexArrayTests.deArray.InputType.FIXED:
+ case glsVertexArrayTests.deArray.InputType.DOUBLE:*/
+ case glsVertexArrayTests.deArray.InputType.BYTE:
+ case glsVertexArrayTests.deArray.InputType.SHORT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_BYTE:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_SHORT:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT:
+ case glsVertexArrayTests.deArray.InputType.INT:
+ case glsVertexArrayTests.deArray.InputType.HALF:
+ data = glsVertexArrayTests.RandomArrayGenerator.createQuads(seed, count, componentCount, offset, stride, primitive, min, max, scale);
+ break;
+
+ case glsVertexArrayTests.deArray.InputType.INT_2_10_10_10:
+ case glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10:
+ data = glsVertexArrayTests.RandomArrayGenerator.createQuadsPacked(seed, count, componentCount, offset, stride, primitive);
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.generateQuads - Invalid input type');
+ break;
+ }
+
+ return data;
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} offset
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @return {ArrayBuffer}
+ */
+ glsVertexArrayTests.RandomArrayGenerator.createQuadsPacked = function(seed, count, componentCount, offset, stride, primitive) {
+ DE_ASSERT(componentCount == 4);
+
+ /** @type {number} */ var quadStride = 0;
+
+ if (stride == 0)
+ stride = deMath.INT32_SIZE;
+
+ switch (primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ quadStride = stride * 6;
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.createQuadsPacked - Invalid primitive');
+ break;
+ }
+
+ /** @type {ArrayBuffer} */ var _data = new ArrayBuffer(offset + quadStride * (count - 1) + stride * 5 + componentCount * glsVertexArrayTests.deArray.inputTypeSize(glsVertexArrayTests.deArray.InputType.INT_2_10_10_10)); // last element must be fully in the array
+ /** @type {Uint8Array} */ var resultData = new Uint8Array(_data).subarray(offset);
+
+ /** @type {number} */ var max = 1024;
+ /** @type {number} */ var min = 10;
+ /** @type {number} */ var max2 = 4;
+
+ var rnd = new deRandom.Random(seed);
+
+ switch (primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES: {
+ for (var quadNdx = 0; quadNdx < count; quadNdx++) {
+ /** @type {number} */ var x1 = min + rnd.getInt() % (max - min);
+ /** @type {number} */ var x2 = min + rnd.getInt() % (max - x1);
+
+ /** @type {number} */ var y1 = min + rnd.getInt() % (max - min);
+ /** @type {number} */ var y2 = min + rnd.getInt() % (max - y1);
+
+ /** @type {number} */ var z = min + rnd.getInt() % (max - min);
+ /** @type {number} */ var w = rnd.getInt() % max2;
+
+ /** @type {number} */ var val1 = (w << 30) | (z << 20) | (y1 << 10) | x1;
+ /** @type {number} */ var val2 = (w << 30) | (z << 20) | (y1 << 10) | x2;
+ /** @type {number} */ var val3 = (w << 30) | (z << 20) | (y2 << 10) | x1;
+
+ /** @type {number} */ var val4 = (w << 30) | (z << 20) | (y2 << 10) | x1;
+ /** @type {number} */ var val5 = (w << 30) | (z << 20) | (y1 << 10) | x2;
+ /** @type {number} */ var val6 = (w << 30) | (z << 20) | (y2 << 10) | x2;
+
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 0), new Uint32Array([val1]));
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 1), new Uint32Array([val2]));
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 2), new Uint32Array([val3]));
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 3), new Uint32Array([val4]));
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 4), new Uint32Array([val5]));
+ glsVertexArrayTests.copyArray(resultData.subarray(quadNdx * quadStride + stride * 5), new Uint32Array([val6]));
+ }
+
+ break;
+ }
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.createQuadsPacked - Invalid primitive');
+ break;
+ }
+
+ return _data;
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} offset
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ * @param {number} scale Coordinate scaling factor
+ * @return {ArrayBuffer}
+ */
+ glsVertexArrayTests.RandomArrayGenerator.createQuads = function(seed, count, componentCount, offset, stride, primitive, min, max, scale) {
+ var componentStride = min.m_value.byteLength; //TODO: Fix encapsulation issue
+ var quadStride = 0;
+ var type = min.getType(); //Instead of using the template parameter.
+
+ if (stride == 0)
+ stride = componentCount * componentStride;
+ DE_ASSERT(stride >= componentCount * componentStride);
+
+ switch (primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ quadStride = stride * 6;
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.createQuads - Invalid primitive');
+ break;
+ }
+
+ /** @type {ArrayBuffer} */ var _data = new ArrayBuffer(offset + quadStride * count);
+ /** @type {Uint8Array} */ var resultData = new Uint8Array(_data).subarray(offset);
+
+ var rnd = new deRandom.Random(seed);
+
+ switch (primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES: {
+ for (var quadNdx = 0; quadNdx < count; ++quadNdx) {
+ /** @type {glsVertexArrayTests.GLValue} */ var x1 = null;
+ /** @type {glsVertexArrayTests.GLValue} */ var x2 = null;
+ /** @type {glsVertexArrayTests.GLValue} */ var y1 = null;
+ /** @type {glsVertexArrayTests.GLValue} */ var y2 = null;
+ /** @type {glsVertexArrayTests.GLValue} */ var z = null;
+ /** @type {glsVertexArrayTests.GLValue} */ var w = null;
+
+ // attempt to find a good (i.e not extremely small) quad
+ for (var attemptNdx = 0; attemptNdx < 4; ++attemptNdx) {
+ x1 = glsVertexArrayTests.GLValue.getRandom(rnd, min, max);
+ x2 = glsVertexArrayTests.GLValue.getRandom(rnd, glsVertexArrayTests.GLValue.minValue(type), glsVertexArrayTests.GLValue.abs(max.sub(x1)));
+
+ y1 = glsVertexArrayTests.GLValue.getRandom(rnd, min, max);
+ y2 = glsVertexArrayTests.GLValue.getRandom(rnd, glsVertexArrayTests.GLValue.minValue(type), glsVertexArrayTests.GLValue.abs(max.sub(y1)));
+
+ z = (componentCount > 2) ? (glsVertexArrayTests.GLValue.getRandom(rnd, min, max)) : (glsVertexArrayTests.GLValue.create(0, type));
+ w = (componentCount > 3) ? (glsVertexArrayTests.GLValue.getRandom(rnd, min, max)) : (glsVertexArrayTests.GLValue.create(1, type));
+
+ // no additional components, all is good
+ if (componentCount <= 2)
+ break;
+
+ // The result quad is too thin?
+ if ((Math.abs(x2.interpret() + z.interpret()) < glsVertexArrayTests.GLValue.minValue(type).interpret()) ||
+ (Math.abs(y2.interpret() + w.interpret()) < glsVertexArrayTests.GLValue.minValue(type).interpret()))
+ continue;
+
+ // all ok
+ break;
+ }
+
+ x2 = x1.add(x2);
+ y2 = y1.add(y2);
+
+ /**
+ * Transform GL vertex coordinates so that after vertex shading the vertices will be rounded.
+ * We want to avoid quads that cover a pixel partially
+ */
+ var round = function(pos, scale, offset, range) {
+ // Perform the same transformation as the vertex shader
+ var val = (pos.interpret() + offset) * scale;
+ var half = range / 2;
+ val = val * half + half;
+ // Round it
+ val = Math.round(val);
+ // And reverse the vertex shading transformation
+ val = (val - half) / half;
+ val = val / scale - offset;
+ return glsVertexArrayTests.GLValue.create(val, pos.m_type);
+ };
+
+ var viewport = gl.getParameter(gl.VIEWPORT);
+ var voffset = 0;
+ if (componentCount > 2)
+ voffset = z.interpret();
+ x1 = round(x1, scale, voffset, viewport[2]);
+ x2 = round(x2, scale, voffset, viewport[2]);
+ voffset = 1;
+ if (componentCount > 3)
+ voffset = w.interpret();
+ y1 = round(y1, scale, voffset, viewport[3]);
+ y2 = round(y2, scale, voffset, viewport[3]);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride), x1);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + componentStride), y1);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride), x2);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride + componentStride), y1);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 2), x1);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 2 + componentStride), y2);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 3), x1);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 3 + componentStride), y2);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 4), x2);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 4 + componentStride), y1);
+
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 5), x2);
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * 5 + componentStride), y2);
+
+ if (componentCount > 2) {
+ for (var i = 0; i < 6; i++)
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * i + componentStride * 2), z);
+ }
+
+ if (componentCount > 3) {
+ for (var i = 0; i < 6; i++)
+ glsVertexArrayTests.copyGLValueToArray(resultData.subarray(quadNdx * quadStride + stride * i + componentStride * 3), w);
+ }
+ }
+
+ break;
+ }
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.createQuads - Invalid primitive');
+ break;
+ }
+
+ return _data;
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @param {glsVertexArrayTests.deArray.InputType} type
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ */
+ glsVertexArrayTests.RandomArrayGenerator.generatePerQuad = function(seed, count, componentCount, stride, primitive, type, min, max) {
+ /** @type {ArrayBuffer} */ var data = null;
+
+ data = glsVertexArrayTests.RandomArrayGenerator.createPerQuads(seed, count, componentCount, stride, primitive, min, max);
+ return data;
+ };
+
+ /**
+ * @param {number} seed
+ * @param {number} count
+ * @param {number} componentCount
+ * @param {number} stride
+ * @param {glsVertexArrayTests.deArray.Primitive} primitive
+ * @param {glsVertexArrayTests.GLValue} min
+ * @param {glsVertexArrayTests.GLValue} max
+ */
+ glsVertexArrayTests.RandomArrayGenerator.createPerQuads = function(seed, count, componentCount, stride, primitive, min, max) {
+ var rnd = new deRandom.Random(seed);
+
+ var componentStride = min.m_value.byteLength; //TODO: Fix encapsulation issue.
+
+ if (stride == 0)
+ stride = componentStride * componentCount;
+
+ var quadStride = 0;
+
+ switch (primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ quadStride = stride * 6;
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.RandomArrayGenerator.createPerQuads - Invalid primitive');
+ break;
+ }
+
+ /** @type {ArrayBuffer} */ var data = new ArrayBuffer(count * quadStride);
+
+ for (var quadNdx = 0; quadNdx < count; quadNdx++) {
+ for (var componentNdx = 0; componentNdx < componentCount; componentNdx++) {
+ /** @type {glsVertexArrayTests.GLValue} */ var val = glsVertexArrayTests.GLValue.getRandom(rnd, min, max);
+
+ var data8 = new Uint8Array(data);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 0 + componentStride * componentNdx), val);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 1 + componentStride * componentNdx), val);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 2 + componentStride * componentNdx), val);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 3 + componentStride * componentNdx), val);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 4 + componentStride * componentNdx), val);
+ glsVertexArrayTests.copyGLValueToArray(data8.subarray(quadNdx * quadStride + stride * 5 + componentStride * componentNdx), val);
+ }
+ }
+
+ return data;
+ };
+
+ /**
+ * class glsVertexArrayTests.VertexArrayTest
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ glsVertexArrayTests.VertexArrayTest = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+
+ var r = /** @type {number} */ (gl.getParameter(gl.RED_BITS));
+ var g = /** @type {number} */ (gl.getParameter(gl.GREEN_BITS));
+ var b = /** @type {number} */ (gl.getParameter(gl.BLUE_BITS));
+ var a = /** @type {number} */ (gl.getParameter(gl.ALPHA_BITS));
+ this.m_pixelformat = new tcuPixelFormat.PixelFormat(r, g, b, a);
+
+ /** @type {sglrReferenceContext.ReferenceContextBuffers} */ this.m_refBuffers = null;
+ /** @type {sglrReferenceContext.ReferenceContext} */ this.m_refContext = null;
+ /** @type {sglrGLContext.GLContext} */ this.m_glesContext = null;
+ /** @type {glsVertexArrayTests.ContextArrayPack} */ this.m_glArrayPack = null;
+ /** @type {glsVertexArrayTests.ContextArrayPack} */ this.m_rrArrayPack = null;
+ /** @type {boolean} */ this.m_isOk = false;
+ /** @type {number} */ this.m_maxDiffRed = Math.ceil(256.0 * (2.0 / (1 << this.m_pixelformat.redBits)));
+ /** @type {number} */ this.m_maxDiffGreen = Math.ceil(256.0 * (2.0 / (1 << this.m_pixelformat.greenBits)));
+ /** @type {number} */ this.m_maxDiffBlue = Math.ceil(256.0 * (2.0 / (1 << this.m_pixelformat.blueBits)));
+ };
+
+ glsVertexArrayTests.VertexArrayTest.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ glsVertexArrayTests.VertexArrayTest.prototype.constructor = glsVertexArrayTests.VertexArrayTest;
+
+ /**
+ * init
+ */
+ glsVertexArrayTests.VertexArrayTest.prototype.init = function() {
+ /** @type {number}*/ var renderTargetWidth = Math.min(512, canvas.width);
+ /** @type {number}*/ var renderTargetHeight = Math.min(512, canvas.height);
+ /** @type {sglrReferenceContext.ReferenceContextLimits} */ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+
+ this.m_glesContext = new sglrGLContext.GLContext(gl);
+ this.m_refBuffers = new sglrReferenceContext.ReferenceContextBuffers(this.m_pixelformat, 0, 0, renderTargetWidth, renderTargetHeight);
+ this.m_refContext = new sglrReferenceContext.ReferenceContext(limits, this.m_refBuffers.getColorbuffer(), this.m_refBuffers.getDepthbuffer(), this.m_refBuffers.getStencilbuffer());
+
+ this.m_glArrayPack = new glsVertexArrayTests.ContextArrayPack(this.m_glesContext);
+ this.m_rrArrayPack = new glsVertexArrayTests.ContextArrayPack(this.m_refContext);
+ };
+
+ /**
+ * compare
+ */
+ glsVertexArrayTests.VertexArrayTest.prototype.compare = function() {
+ /** @type {tcuSurface.Surface} */ var ref = this.m_rrArrayPack.getSurface();
+ /** @type {tcuSurface.Surface} */ var screen = this.m_glArrayPack.getSurface();
+
+ if (/** @type {number} */ (this.m_glesContext.getParameter(gl.SAMPLES)) > 1) {
+ // \todo [mika] Improve compare when using multisampling
+ bufferedLogToConsole('Warning: Comparison of result from multisample render targets are not as strict as without multisampling. Might produce false positives!');
+ this.m_isOk = tcuImageCompare.fuzzyCompare('Compare Results', 'Compare Results', ref.getAccess(), screen.getAccess(), 1.5);
+ } else {
+ /** @type {tcuRGBA.RGBA} */ var threshold = tcuRGBA.newRGBAComponents(this.m_maxDiffRed, this.m_maxDiffGreen, this.m_maxDiffBlue, 255);
+ /** @type {tcuSurface.Surface} */ var error = new tcuSurface.Surface(ref.getWidth(), ref.getHeight());
+
+ this.m_isOk = true;
+
+ for (var y = 1; y < ref.getHeight() - 1; y++) {
+ for (var x = 1; x < ref.getWidth() - 1; x++) {
+ /** @type {tcuRGBA.RGBA} */ var refPixel = tcuRGBA.newRGBAFromArray(ref.getPixel(x, y));
+ /** @type {tcuRGBA.RGBA} */ var screenPixel = tcuRGBA.newRGBAFromArray(screen.getPixel(x, y));
+ /** @type {boolean} */ var isOkPixel = false;
+
+ // Don't do comparisons for this pixel if it belongs to a one-pixel-thin part (i.e. it doesn't have similar-color neighbors in both x and y directions) in both result and reference.
+ // This fixes some false negatives.
+ /** @type {boolean} */ var refThin = (
+ !tcuRGBA.compareThreshold(refPixel, tcuRGBA.newRGBAFromArray(ref.getPixel(x - 1, y)), threshold) &&
+ !tcuRGBA.compareThreshold(refPixel, tcuRGBA.newRGBAFromArray(ref.getPixel(x + 1, y)), threshold)
+ ) || (
+ !tcuRGBA.compareThreshold(refPixel, tcuRGBA.newRGBAFromArray(ref.getPixel(x, y - 1)), threshold) &&
+ !tcuRGBA.compareThreshold(refPixel, tcuRGBA.newRGBAFromArray(ref.getPixel(x, y + 1)), threshold)
+ );
+
+ /** @type {boolean} */ var screenThin = (
+ !tcuRGBA.compareThreshold(screenPixel, tcuRGBA.newRGBAFromArray(screen.getPixel(x - 1, y)), threshold) &&
+ !tcuRGBA.compareThreshold(screenPixel, tcuRGBA.newRGBAFromArray(screen.getPixel(x + 1, y)), threshold)
+ ) || (
+ !tcuRGBA.compareThreshold(screenPixel, tcuRGBA.newRGBAFromArray(screen.getPixel(x, y - 1)), threshold) &&
+ !tcuRGBA.compareThreshold(screenPixel, tcuRGBA.newRGBAFromArray(screen.getPixel(x, y + 1)), threshold)
+ );
+
+ if (refThin && screenThin)
+ isOkPixel = true;
+ else {
+ //NOTE: This will ignore lines less than three pixels wide, so
+ //even if there's a difference, the test will pass.
+ for (var dy = -1; dy < 2 && !isOkPixel; dy++) {
+ for (var dx = -1; dx < 2 && !isOkPixel; dx++) {
+ // Check reference pixel against screen pixel
+ /** @type {tcuRGBA.RGBA} */ var screenCmpPixel = tcuRGBA.newRGBAFromArray(screen.getPixel(x + dx, y + dy));
+ /** @type {number} (8-bit) */ var r = Math.abs(refPixel.getRed() - screenCmpPixel.getRed());
+ /** @type {number} (8-bit) */ var g = Math.abs(refPixel.getGreen() - screenCmpPixel.getGreen());
+ /** @type {number} (8-bit) */ var b = Math.abs(refPixel.getBlue() - screenCmpPixel.getBlue());
+
+ if (r <= this.m_maxDiffRed && g <= this.m_maxDiffGreen && b <= this.m_maxDiffBlue)
+ isOkPixel = true;
+
+ // Check screen pixels against reference pixel
+ /** @type {tcuRGBA.RGBA} */ var refCmpPixel = tcuRGBA.newRGBAFromArray(ref.getPixel(x + dx, y + dy));
+ r = Math.abs(refCmpPixel.getRed() - screenPixel.getRed());
+ g = Math.abs(refCmpPixel.getGreen() - screenPixel.getGreen());
+ b = Math.abs(refCmpPixel.getBlue() - screenPixel.getBlue());
+
+ if (r <= this.m_maxDiffRed && g <= this.m_maxDiffGreen && b <= this.m_maxDiffBlue)
+ isOkPixel = true;
+ }
+ }
+ }
+
+ if (isOkPixel)
+ error.setPixel(x, y,
+ [tcuRGBA.newRGBAFromArray(screen.getPixel(x, y)).getRed(),
+ (tcuRGBA.newRGBAFromArray(screen.getPixel(x, y)).getGreen() + 255) / 2,
+ tcuRGBA.newRGBAFromArray(screen.getPixel(x, y)).getBlue(), 255]
+ );
+ else {
+ error.setPixel(x, y, [255, 0, 0, 255]);
+ this.m_isOk = false;
+ }
+ }
+ }
+
+ if (!this.m_isOk) {
+ debug('Image comparison failed, threshold = (' + this.m_maxDiffRed + ', ' + this.m_maxDiffGreen + ', ' + this.m_maxDiffBlue + ')');
+ //log << TestLog::ImageSet("Compare result", "Result of rendering");
+ tcuImageCompare.displayImages(screen.getAccess(), ref.getAccess(), error.getAccess());
+ } else {
+ //log << TestLog::ImageSet("Compare result", "Result of rendering")
+ tcuLogImage.logImage('Result', '', screen.getAccess());
+ }
+ }
+ };
+
+ //TODO: Is this actually used? -> glsVertexArrayTests.VertexArrayTest& operator= (const glsVertexArrayTests.VertexArrayTest& other);
+
+ /**
+ * glsVertexArrayTests.MultiVertexArrayTest class
+ * @constructor
+ * @extends {glsVertexArrayTests.VertexArrayTest}
+ * @param {glsVertexArrayTests.MultiVertexArrayTest.Spec} spec
+ * @param {string} name
+ * @param {string} desc
+ */
+ glsVertexArrayTests.MultiVertexArrayTest = function(spec, name, desc) {
+ glsVertexArrayTests.VertexArrayTest.call(this, name, desc);
+
+ /** @type {glsVertexArrayTests.MultiVertexArrayTest.Spec} */ this.m_spec = spec;
+ /** @type {number} */ this.m_iteration = 0;
+ };
+
+ glsVertexArrayTests.MultiVertexArrayTest.prototype = Object.create(glsVertexArrayTests.VertexArrayTest.prototype);
+ glsVertexArrayTests.MultiVertexArrayTest.prototype.constructor = glsVertexArrayTests.MultiVertexArrayTest;
+
+ /**
+ * glsVertexArrayTests.MultiVertexArrayTest.Spec class
+ * @constructor
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.Spec = function() {
+ /** @type {glsVertexArrayTests.deArray.Primitive} */ this.primitive;
+ /** @type {number} */ this.drawCount = 0;
+ /** @type {number} */ this.first = 0;
+ /** @type {Array<glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec>} */ this.arrays = [];
+ };
+
+ /**
+ * glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec class
+ * @constructor
+ * @param {glsVertexArrayTests.deArray.InputType} inputType_
+ * @param {glsVertexArrayTests.deArray.OutputType} outputType_
+ * @param {glsVertexArrayTests.deArray.Storage} storage_
+ * @param {glsVertexArrayTests.deArray.Usage} usage_
+ * @param {number} componentCount_
+ * @param {number} offset_
+ * @param {number} stride_
+ * @param {boolean} normalize_
+ * @param {glsVertexArrayTests.GLValue} min_
+ * @param {glsVertexArrayTests.GLValue} max_
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec = function(inputType_, outputType_, storage_, usage_, componentCount_, offset_, stride_, normalize_, min_, max_) {
+ this.inputType = inputType_;
+ this.outputType = outputType_;
+ this.storage = storage_;
+ this.usage = usage_;
+ this.componentCount = componentCount_;
+ this.offset = offset_;
+ /** @type {number} */ this.stride = stride_;
+ this.normalize = normalize_;
+ this.min = min_;
+ this.max = max_;
+ };
+
+ /**
+ * getName
+ * @return {string}
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.Spec.prototype.getName = function() {
+ var name = '';
+
+ for (var ndx = 0; ndx < this.arrays.length; ++ndx) {
+ /** @type {glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec} */ var array = this.arrays[ndx];
+
+ if (this.arrays.length > 1)
+ name += 'array' + ndx + '_';
+
+ name += glsVertexArrayTests.deArray.storageToString(array.storage) + '_' +
+ array.offset + '_' +
+ array.stride + '_' +
+ glsVertexArrayTests.deArray.inputTypeToString(array.inputType);
+
+ if (array.inputType != glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10 && array.inputType != glsVertexArrayTests.deArray.InputType.INT_2_10_10_10)
+ name += array.componentCount;
+ name += '_' +
+ (array.normalize ? 'normalized_' : '') +
+ glsVertexArrayTests.deArray.outputTypeToString(array.outputType) + '_' +
+ glsVertexArrayTests.deArray.usageTypeToString(array.usage) + '_';
+ }
+
+ if (this.first)
+ name += 'first' + this.first + '_';
+
+ switch (this.primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ name += 'quads_';
+ break;
+ case glsVertexArrayTests.deArray.Primitive.POINTS:
+ name += 'points_';
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.MultiVertexArrayTest.Spec.getName - Invalid primitive type');
+ break;
+ }
+
+ name += this.drawCount;
+
+ return name;
+ };
+
+ /**
+ * getName
+ * @return {string}
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.Spec.prototype.getDesc = function() {
+ var desc = '';
+
+ for (var ndx = 0; ndx < this.arrays.length; ++ndx) {
+ /** @type {glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec} */ var array = this.arrays[ndx];
+
+ desc += 'Array ' + ndx + ': ' +
+ 'Storage in ' + glsVertexArrayTests.deArray.storageToString(array.storage) + ', ' +
+ 'stride ' + array.stride + ', ' +
+ 'input datatype ' + glsVertexArrayTests.deArray.inputTypeToString(array.inputType) + ', ' +
+ 'input component count ' + array.componentCount + ', ' +
+ (array.normalize ? 'normalized, ' : '') +
+ 'used as ' + glsVertexArrayTests.deArray.outputTypeToString(array.outputType) + ', ';
+ }
+
+ desc += 'drawArrays(), ' +
+ 'first ' + this.first + ', ' +
+ this.drawCount;
+
+ switch (this.primitive) {
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ desc += 'quads ';
+ break;
+ case glsVertexArrayTests.deArray.Primitive.POINTS:
+ desc += 'points';
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.MultiVertexArrayTest.Spec.getDesc - Invalid primitive type');
+ break;
+ }
+
+ return desc;
+ };
+
+ /**
+ * iterate
+ * @return {tcuTestCase.IterateResult}
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.prototype.iterate = function() {
+ if (this.m_iteration == 0) {
+ var primitiveSize = (this.m_spec.primitive == glsVertexArrayTests.deArray.Primitive.TRIANGLES) ? (6) : (1); // in non-indexed draw Triangles means rectangles
+ var coordScale = 1.0;
+ var colorScale = 1.0;
+ var useVao = true; // WebGL, WebGL 2.0 - gl.getType().getProfile() == glu::PROFILE_CORE;
+
+ // Log info
+ bufferedLogToConsole(this.m_spec.getDesc());
+
+ // Color and Coord scale
+
+ // First array is always position
+ /** @type {glsVertexArrayTests.MultiVertexArrayTest.Spec.ArraySpec} */ var arraySpec = this.m_spec.arrays[0];
+ if (arraySpec.inputType == glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10) {
+ if (arraySpec.normalize)
+ coordScale = 1;
+ else
+ coordScale = 1 / 1024;
+ } else if (arraySpec.inputType == glsVertexArrayTests.deArray.InputType.INT_2_10_10_10) {
+ if (arraySpec.normalize)
+ coordScale = 1.0;
+ else
+ coordScale = 1.0 / 512.0;
+ } else
+ coordScale = arraySpec.normalize && !glsVertexArrayTests.inputTypeIsFloatType(arraySpec.inputType) ? 1.0 : 0.9 / arraySpec.max.toFloat();
+
+ if (arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.VEC3 || arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.VEC4 ||
+ arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.IVEC3 || arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.IVEC4 ||
+ arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.UVEC3 || arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.UVEC4)
+ coordScale = coordScale * 0.5;
+
+ // And other arrays are color-like
+ for (var arrayNdx = 1; arrayNdx < this.m_spec.arrays.length; arrayNdx++) {
+ arraySpec = this.m_spec.arrays[arrayNdx];
+
+ colorScale *= (arraySpec.normalize && !glsVertexArrayTests.inputTypeIsFloatType(arraySpec.inputType) ? 1.0 : 1.0 / arraySpec.max.toFloat());
+ if (arraySpec.outputType == glsVertexArrayTests.deArray.OutputType.VEC4)
+ colorScale *= (arraySpec.normalize && !glsVertexArrayTests.inputTypeIsFloatType(arraySpec.inputType) ? 1.0 : 1.0 / arraySpec.max.toFloat());
+ }
+
+ // Data
+
+ for (var arrayNdx = 0; arrayNdx < this.m_spec.arrays.length; arrayNdx++) {
+ arraySpec = this.m_spec.arrays[arrayNdx];
+ /** @type {number} */ var seed = arraySpec.inputType + 10 * arraySpec.outputType + 100 * arraySpec.storage + 1000 * this.m_spec.primitive + 10000 * arraySpec.usage + this.m_spec.drawCount + 12 * arraySpec.componentCount + arraySpec.stride + arraySpec.normalize;
+ /** @type {ArrayBuffer} */ var data = null;
+ /** @type {number} */ var stride = arraySpec.stride == 0 ? arraySpec.componentCount * glsVertexArrayTests.deArray.inputTypeSize(arraySpec.inputType) : arraySpec.stride;
+ /** @type {number} */ var bufferSize = arraySpec.offset + stride * (this.m_spec.drawCount * primitiveSize - 1) + arraySpec.componentCount * glsVertexArrayTests.deArray.inputTypeSize(arraySpec.inputType);
+
+ switch (this.m_spec.primitive) {
+ // case glsVertexArrayTests.deArray.Primitive.POINTS:
+ // data = glsVertexArrayTests.RandomArrayGenerator.generateArray(seed, arraySpec.min, arraySpec.max, arraySpec.count, arraySpec.componentCount, arraySpec.stride, arraySpec.inputType);
+ // break;
+ case glsVertexArrayTests.deArray.Primitive.TRIANGLES:
+ if (arrayNdx == 0) {
+ data = glsVertexArrayTests.RandomArrayGenerator.generateQuads(seed, this.m_spec.drawCount, arraySpec.componentCount, arraySpec.offset, arraySpec.stride, this.m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max, coordScale);
+ } else {
+ DE_ASSERT(arraySpec.offset == 0); // \note [jarkko] it just hasn't been implemented
+ data = glsVertexArrayTests.RandomArrayGenerator.generatePerQuad(seed, this.m_spec.drawCount, arraySpec.componentCount, arraySpec.stride, this.m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
+ }
+ break;
+
+ default:
+ throw new Error('glsVertexArrayTests.MultiVertexArrayTest.prototype.iterate - Invalid primitive type');
+ break;
+ }
+
+ this.m_glArrayPack.newArray(arraySpec.storage);
+ this.m_rrArrayPack.newArray(arraySpec.storage);
+
+ this.m_glArrayPack.getArray(arrayNdx).data(glsVertexArrayTests.deArray.Target.ARRAY, bufferSize, new Uint8Array(data), arraySpec.usage);
+ this.m_rrArrayPack.getArray(arrayNdx).data(glsVertexArrayTests.deArray.Target.ARRAY, bufferSize, new Uint8Array(data), arraySpec.usage);
+
+ this.m_glArrayPack.getArray(arrayNdx).bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
+ this.m_rrArrayPack.getArray(arrayNdx).bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
+ }
+
+ try {
+ this.m_glArrayPack.render(this.m_spec.primitive, this.m_spec.first, this.m_spec.drawCount * primitiveSize, useVao, coordScale, colorScale);
+ this.m_rrArrayPack.render(this.m_spec.primitive, this.m_spec.first, this.m_spec.drawCount * primitiveSize, useVao, coordScale, colorScale);
+ }
+ catch (err) {
+ // GL Errors are ok if the mode is not properly aligned
+
+ bufferedLogToConsole('Got error: ' + err.message);
+
+ if (this.isUnalignedBufferOffsetTest())
+ testFailedOptions('Failed to draw with unaligned buffers', false); // TODO: QP_TEST_RESULT_COMPATIBILITY_WARNING
+ else if (this.isUnalignedBufferStrideTest())
+ testFailedOptions('Failed to draw with unaligned stride', false); // QP_TEST_RESULT_COMPATIBILITY_WARNING
+ else
+ throw new Error(err.message);
+
+ return tcuTestCase.IterateResult.STOP;
+ }
+
+ this.m_iteration++;
+ return tcuTestCase.IterateResult.CONTINUE;
+ } else if (this.m_iteration == 1) {
+ this.compare();
+
+ if (this.m_isOk) {
+ testPassedOptions('', true);
+ } else {
+ if (this.isUnalignedBufferOffsetTest())
+ testFailedOptions('Failed to draw with unaligned buffers', false); // QP_TEST_RESULT_COMPATIBILITY_WARNING
+ else if (this.isUnalignedBufferStrideTest())
+ testFailedOptions('Failed to draw with unaligned stride', false); // QP_TEST_RESULT_COMPATIBILITY_WARNING
+ else
+ testFailedOptions('Image comparison failed', false);
+ }
+
+ this.m_iteration++;
+ return tcuTestCase.IterateResult.STOP;
+ } else {
+ testFailedOptions('glsVertexArrayTests.MultiVertexArrayTest.iterate - Invalid iteration stage', false);
+ return tcuTestCase.IterateResult.STOP;
+ }
+ };
+
+ /**
+ * isUnalignedBufferOffsetTest
+ * @return {boolean}
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.prototype.isUnalignedBufferOffsetTest = function() {
+ // Buffer offsets should be data type size aligned
+ for (var i = 0; i < this.m_spec.arrays.length; ++i) {
+ if (this.m_spec.arrays[i].storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ /** @type {boolean} */ var inputTypePacked = this.m_spec.arrays[i].inputType == glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10 || this.m_spec.arrays[i].inputType == glsVertexArrayTests.deArray.InputType.INT_2_10_10_10;
+
+ /** @type {number} */ var dataTypeSize = glsVertexArrayTests.deArray.inputTypeSize(this.m_spec.arrays[i].inputType);
+ if (inputTypePacked)
+ dataTypeSize = 4;
+
+ if (this.m_spec.arrays[i].offset % dataTypeSize != 0)
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * isUnalignedBufferStrideTest
+ * @return {boolean}
+ */
+ glsVertexArrayTests.MultiVertexArrayTest.prototype.isUnalignedBufferStrideTest = function() {
+ // Buffer strides should be data type size aligned
+ for (var i = 0; i < this.m_spec.arrays.length; ++i) {
+ if (this.m_spec.arrays[i].storage == glsVertexArrayTests.deArray.Storage.BUFFER) {
+ /** @type {boolean} */ var inputTypePacked = this.m_spec.arrays[i].inputType == glsVertexArrayTests.deArray.InputType.UNSIGNED_INT_2_10_10_10 || this.m_spec.arrays[i].inputType == glsVertexArrayTests.deArray.InputType.INT_2_10_10_10;
+
+ /** @type {number} */ var dataTypeSize = glsVertexArrayTests.deArray.inputTypeSize(this.m_spec.arrays[i].inputType);
+ if (inputTypePacked)
+ dataTypeSize = 4;
+
+ if (this.m_spec.arrays[i].stride % dataTypeSize != 0)
+ return true;
+ }
+ }
+ return false;
+ };
+
+});