From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../modules/shared/glsAttributeLocationTests.js | 1477 ++++++ .../deqp/modules/shared/glsBufferTestUtil.js | 1068 ++++ .../modules/shared/glsBuiltinPrecisionTests.js | 5415 ++++++++++++++++++++ .../shared/glsBuiltinPrecisionTestsUnitTests.js | 2819 ++++++++++ .../checkout/deqp/modules/shared/glsDrawTests.js | 3452 +++++++++++++ .../deqp/modules/shared/glsFboCompletenessTests.js | 961 ++++ .../checkout/deqp/modules/shared/glsFboUtil.js | 1413 +++++ .../deqp/modules/shared/glsLifetimeTests.js | 1118 ++++ .../modules/shared/glsRandomUniformBlockCase.js | 282 + .../deqp/modules/shared/glsSamplerObjectTest.js | 1148 +++++ .../deqp/modules/shared/glsShaderExecUtil.js | 731 +++ .../deqp/modules/shared/glsShaderLibrary.js | 1114 ++++ .../deqp/modules/shared/glsShaderLibraryCase.js | 1132 ++++ .../deqp/modules/shared/glsShaderRenderCase.js | 1200 +++++ .../checkout/deqp/modules/shared/glsStateQuery.js | 367 ++ .../deqp/modules/shared/glsTextureTestUtil.js | 2642 ++++++++++ .../deqp/modules/shared/glsUniformBlockCase.js | 2451 +++++++++ .../deqp/modules/shared/glsVertexArrayTests.js | 2534 +++++++++ 18 files changed, 31324 insertions(+) create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsAttributeLocationTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBufferTestUtil.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsBuiltinPrecisionTestsUnitTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsDrawTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboCompletenessTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsFboUtil.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsLifetimeTests.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsRandomUniformBlockCase.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsSamplerObjectTest.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibrary.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderRenderCase.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsStateQuery.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsUniformBlockCase.js create mode 100644 dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsVertexArrayTests.js (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/modules') 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 0000000000..5ba033ffc0 --- /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} bindings + * @param {string} attrib + * @return {number} + */ + glsAttributeLocationTests.getBoundLocation = function(bindings, attrib) { + return (bindings[attrib] === undefined ? glsAttributeLocationTests.LocationEnum.UNDEF : bindings[attrib]); + }; + + /** + * @param {Array} attributes + * @param {Array} bindings + * @return {boolean} + */ + glsAttributeLocationTests.hasAttributeAliasing = function(attributes, bindings) { + /** @type {Array} */ 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} 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} attributes + * @return {string} + */ + glsAttributeLocationTests.generateConditionUniformDefinitions = function(attributes) { + /** @type {string} */ var src = ''; + /** @type {Array} */ 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} 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} 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} 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} */ 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} */ 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} attributes + * @return {boolean} + */ + glsAttributeLocationTests.checkActiveAttribQuery = function(program, attributes) { + /** @type {number} */ var activeAttribCount = 0; + /** @type {Array} */ 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} attributes + * @param {Array} 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} attributes + * @param {Array} 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} 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} 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} attributes + * @param {Array} preAttachBind + * @param {Array} preLinkBind + * @param {Array} postLinkBind + * @param {boolean} relink + * @param {boolean=} reattach + * @param {Array=} 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} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations(); + /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1); + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ 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} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations(); + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ 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} */ var bindings = []; + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations(); + /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1); + + /** @type {Array} */ 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} */ 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} */ 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} */ var noBindings = []; + + /** @type {Array} */ var bindings = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {number} */ var maxAttributes = glsAttributeLocationTests.getMaxAttributeLocations(); + /** @type {number} */ var arrayElementCount = (this.m_arraySize != glsAttributeLocationTests.ArrayEnum.NOT ? this.m_arraySize : 1); + + /** @type {Array} */ var bindings = []; + /** @type {Array} */ 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} */ 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} */ var bindings = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4); + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ var preLinkBindings = []; + /** @type {Array} */ 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} */ 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} */ var attributes = []; + /** @type {Array} */ var preLinkBindings = []; + /** @type {Array} */ 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} */ 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} */ var preLinkBindings = []; + /** @type {Array} */ var postLinkBindings = []; + /** @type {Array} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ 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} */ var bindings = []; + /** @type {Array} */ var attributes = []; + /** @type {Array} */ 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} */ var noBindings = []; + /** @type {glsAttributeLocationTests.AttribType} */ var vec4 = new glsAttributeLocationTests.AttribType('vec4', 1, gl.FLOAT_VEC4); + + /** @type {Array} */ var attributes = []; + /** @type {Array} */ var preLinkBindings = []; + /** @type {Array} */ 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 0000000000..446782b4b6 --- /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} */ 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} */ 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} */ 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} + */ + 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} + */ + 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} */ var v00 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 0); + /** @type {Array} */ var v10 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 1); + /** @type {Array} */ var v01 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 2); + /** @type {Array} */ 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} */ var t0 = tri ? v00 : v11; + /** @type {Array} */ var t1 = tri ? v01 : v10; + /** @type {Array} */ var t2 = tri ? v10 : v01; + /** @type {Array} */ 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} */ 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} + */ + 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} + */ + 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} dst + * @param {Array} 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 0000000000..4dc3be70f3 --- /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|tcuMatrix.Matrix)} */ + glsBuiltinPrecisionTests.Intervals; + + /** @typedef {(number|Array|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.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} + */ + 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 || ''; + }; + + 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} 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 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 + */ + 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} 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} 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 + * + */ + 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 > + * @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} 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 + * @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} 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} 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 in0; + // vector in1; + // vector in2; + // vector 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} 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} 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::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} */ 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 + * @param {glsBuiltinPrecisionTests.Inputs} inputs Inputs + * @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 + * @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 + * @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*/ var ret = new glsBuiltinPrecisionTests.Inputs(In); + /*Inputs*/ var fixedInputs = new glsBuiltinPrecisionTests.Inputs(In); + // set, InputLess > > seenInputs; + /** @type {Array} */ + 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 + * @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 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 + * @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 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.CaseFactories.prototype.getFactories = function() {}; + + /** + * @constructor + * @extends {glsBuiltinPrecisionTests.CaseFactories} + */ + glsBuiltinPrecisionTests.BuiltinFuncs = function() { + /** @type {Array} */ this.m_factories = []; + }; + + glsBuiltinPrecisionTests.BuiltinFuncs.prototype = Object.create(glsBuiltinPrecisionTests.CaseFactories.prototype); + glsBuiltinPrecisionTests.BuiltinFuncs.prototype.constructor = glsBuiltinPrecisionTests.BuiltinFuncs; + + /** + * @return {Array} + */ + 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} 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} shaderTypes_ + * @param {number} numRandoms_ + */ + glsBuiltinPrecisionTests.PrecisionTestContext = function(highp_, mediump_, lowp_, shaderTypes_, numRandoms_) { + /** @type {Array} */ this.shaderTypes = shaderTypes_; + /** @type {Array} */ 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 + */ + 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 + */ + 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(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(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} 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 0000000000..e8df9d28e3 --- /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 0000000000..eb7a4b2935 --- /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} */ 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} + */ + glsDrawTests.generateRandomVec4 = function(random) { + /** @type {Array} */ var retVal = []; + + for (var i = 0; i < 4; ++i) + retVal[i] = random.getFloat(); + + return retVal; + }; + + /** + * @param {deRandom.Random} random + * @return {Array} + */ + glsDrawTests.generateRandomIVec4 = function(random) { + /** @type {Array} */ var retVal = []; + + for (var i = 0; i < 4; ++i) + retVal[i] = random.getInt(); + + return retVal; + }; + + /** + * @param {deRandom.Random} random + * @return {Array} + */ + glsDrawTests.generateRandomUVec4 = function(random) { + /** @type {Array} */ 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} */ 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} 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} */ 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} 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} color + * @param {goog.NumberArray} attribValue + * @param {number} numComponents + * @return {Array} + */ + 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} coord + * @param {goog.NumberArray} attribValue + * @param {number} numComponents + * @return {Array} + */ + 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} inputs + * @param {Array} 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} */ var coord = [0.0, 0.0]; + /** @type {Array} */ 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} 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} arrays + * @return {string} + */ + glsDrawTests.DrawTestShaderProgram.prototype.genVertexSource = function(arrays) { + /** @type {Array}*/ 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} */ 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} + */ + glsDrawTests.DrawTestShaderProgram.prototype.generateShaderParams = function() { + /** @type {Array} */ 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} 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} */ (components)[3], 30), deMath.binaryOp( + deMath.shiftLeft(/** @type {Array} */ (components)[2], 20), deMath.binaryOp( + deMath.shiftLeft(/** @type {Array} */ (components)[1], 10), /** @type {Array} */ (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::max() || + max < 0 || max > std::numeric_limits::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} + */ + 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} 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} */ 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} */ 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} */ this.m_specs = []; + /** @type {Array} */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} */ 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} */ 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} 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} 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} 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} 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} compareThreshold + * @param {Array} 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} */ var green = [0, 255, 0, 255]; + /** @type {Array} */ 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:
' + + ' allowed deviation in pixel positions = 1
' + + ' number of allowed invalid pixels = ' + maxAllowedInvalidPixels + '
' + + ' 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} 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} */ var green = [0, 255, 0, 255]; + /** @type {Array} */ 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:
' + + ' allowed deviation in pixel positions = 1
' + + ' number of allowed invalid pixels = ' + maxAllowedInvalidPixels + '
' + + ' 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} */ 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 0000000000..c0f59c2092 --- /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} + */ + 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} + */ + glsFboCompletenessTests.s_oesPackedDepthStencilSizedFormats = [ + gl.DEPTH24_STENCIL8 + ]; + + /** + * s_oesPackedDepthStencilTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_oesPackedDepthStencilTexFormats = [ + glsFboUtil.formatkey(gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8) + ]; + + /** + * OES_required_internalformat + * @type {Array} + */ + 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} + */ + glsFboCompletenessTests.s_oesRequiredInternalFormatDepthFormats = [ + gl.DEPTH_COMPONENT16 + ]; + + /** + * EXT_color_buffer_half_float + * @type {Array} + */ + glsFboCompletenessTests.s_extColorBufferHalfFloatFormats = [ + gl.RGBA16F, gl.RGB16F, gl.RG16F, gl.R16F + ]; + + /** + * s_oesDepth24SizedFormats + * @type {Array} + */ + glsFboCompletenessTests.s_oesDepth24SizedFormats = [ + gl.DEPTH_COMPONENT24 + ]; + + /** + * s_oesDepth32SizedFormats + * @type {Array} + */ + glsFboCompletenessTests.s_oesDepth32SizedFormats = [ + gl['DEPTH_COMPONENT32'] + ]; + + /** + * s_oesRgb8Rgba8RboFormats + * @type {Array} + */ + glsFboCompletenessTests.s_oesRgb8Rgba8RboFormats = [ + gl.RGB8, gl.RGBA8 + ]; + + /** + * s_oesRequiredInternalFormatRgb8ColorFormat + * @type {Array} + */ + glsFboCompletenessTests.s_oesRequiredInternalFormatRgb8ColorFormat = [ + gl.RGB8 + ]; + + /** + * s_extTextureType2101010RevFormats + * @type {Array} + */ + 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} + */ + glsFboCompletenessTests.s_oesRequiredInternalFormat10bitColorFormats = [ + gl.RGB10_A2, gl['RGB10'] + ]; + + /** + * s_extTextureRgRboFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extTextureRgRboFormats = [ + gl.R8, gl.RG8 + ]; + + /** + * s_extTextureRgTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extTextureRgTexFormats = [ + glsFboUtil.formatkey(gl.RED, gl.UNSIGNED_BYTE), + glsFboUtil.formatkey(gl.RG, gl.UNSIGNED_BYTE) + ]; + + /** + * s_extTextureRgFloatTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extTextureRgFloatTexFormats = [ + glsFboUtil.formatkey(gl.RED, gl.FLOAT), + glsFboUtil.formatkey(gl.RG, gl.FLOAT) + ]; + + /** + * s_extTextureRgHalfFloatTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extTextureRgHalfFloatTexFormats = [ + glsFboUtil.formatkey(gl.RED, gl['HALF_FLOAT_OES']), + glsFboUtil.formatkey(gl.RG, gl['HALF_FLOAT_OES']) + ]; + + /** + * s_nvPackedFloatRboFormats + * @type {Array} + */ + glsFboCompletenessTests.s_nvPackedFloatRboFormats = [ + gl.R11F_G11F_B10F + ]; + + /** + * s_nvPackedFloatTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_nvPackedFloatTexFormats = [ + glsFboUtil.formatkey(gl.RGB, gl.UNSIGNED_INT_10F_11F_11F_REV) + ]; + + /** + * s_extSrgbRboFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extSrgbRboFormats = [ + gl.SRGB8_ALPHA8 + ]; + + /** + * s_extSrgbRenderableTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extSrgbRenderableTexFormats = [ + glsFboUtil.formatkey(gl['SRGB_ALPHA'], gl.UNSIGNED_BYTE) + ]; + + /** + * s_extSrgbNonRenderableTexFormats + * @type {Array} + */ + glsFboCompletenessTests.s_extSrgbNonRenderableTexFormats = [ + glsFboUtil.formatkey(gl.SRGB, gl.UNSIGNED_BYTE), + gl.SRGB8 + ]; + + /** + * s_nvSrgbFormatsRboFormats + * @type {Array} + */ + 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} + */ + glsFboCompletenessTests.s_nvSrgbFormatsTextureFormats = [ + gl.SRGB8, + glsFboUtil.formatkey(gl.SRGB, gl.UNSIGNED_BYTE) + ]; + + /** + * s_oesRgb8Rgba8TexFormats + * @type {Array} + */ + 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} + */ + 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 0000000000..86d05891f2 --- /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} */( + 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.FormatDB.prototype.getFormats = function(requirements) { + /** @type {Array} */ 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} 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)>} + */ + glsFboUtil.formatT; + + /** + * @param {glsFboUtil.FormatDB} db + * @param {glsFboUtil.Range} 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} 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} + */ + this.m_array = array; + // @private + this.m_index = this.m_begin; + }; + + /** + * @return {Array} + */ + 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} array + * @return {glsFboUtil.Range} + */ + 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} */( + new glsFboUtil.Map(glsFboUtil.Map.compareNumber) + ); + this.textures = /** @type {glsFboUtil.Map} */( + new glsFboUtil.Map(fbidCompare) + ); + this.rbos = /** @type {glsFboUtil.Map} */( + 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} + */ + 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 0000000000..427a3a4fce --- /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} */ this.m_types = []; + /** @type {Array} */ this.m_attachers = []; + /** @type {Array} */ this.m_inAttachers = []; + /** @type {Array} */ 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 0000000000..20b8dcd472 --- /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} */ 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} */ 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} */ 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} */ 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}*/ 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 0000000000..0d4030bd91 --- /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} */ 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} */ 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} */ 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} */ 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} */ 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 0000000000..9ea29e7e4c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderExecUtil.js @@ -0,0 +1,731 @@ +/*------------------------------------------------------------------------- + * 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 ? '' : 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} */ this.inputs = []; + /** @type {Array} */ 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} */ this.m_inputs = shaderSpec.inputs; + /** @type {Array} */ 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>} inputs + * @return {Array} 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 {string} */ var src; + + src = '#version 300 es\n'; + src += 'out lowp vec4 color;\n'; + src += 'void main (void)\n{\n'; + src += ' color = 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} 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} ptr + * @param {number} colNdx + * @param {number} size Column size + * @return {Array} + */ + 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} */ 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} */ 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 0000000000..27f86e055c --- /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} arr + * @return {Array} output + */ + glsShaderLibrary.removeExtraIndentationArray = function(arr) { + /** @type {Array} */ 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} */ 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 = ''; + + } 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.} + */ + 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 ''; + case Token.TOKEN_EOF: return ''; + case Token.TOKEN_STRING: return ''; + case Token.TOKEN_SHADER_SOURCE: return 'source'; + + case Token.TOKEN_INT_LITERAL: return ''; + case Token.TOKEN_FLOAT_LITERAL: return ''; + + // identifiers + case Token.TOKEN_IDENTIFIER: return ''; + 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 ''; + } + }; + + /** + * @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} */ 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.} 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.} 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} 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} + * 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.} */ 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} */ 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} 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} */ 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 0000000000..fa9666de56 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsShaderLibraryCase.js @@ -0,0 +1,1132 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES Utilities + * ------------------------------------------------ + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; +goog.provide('modules.shared.glsShaderLibraryCase'); +goog.require('framework.common.tcuTestCase'); +goog.require('framework.opengl.gluDrawUtil'); +goog.require('framework.opengl.gluShaderProgram'); +goog.require('framework.opengl.gluShaderUtil'); + +goog.scope(function() { + +var glsShaderLibraryCase = modules.shared.glsShaderLibraryCase; +var tcuTestCase = framework.common.tcuTestCase; +var gluShaderProgram = framework.opengl.gluShaderProgram; +var gluShaderUtil = framework.opengl.gluShaderUtil; +var gluDrawUtil = framework.opengl.gluDrawUtil; + + /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_WIDTH = 128; + /** @const @type {number} */ glsShaderLibraryCase.VIEWPORT_HEIGHT = 128; + +/** + * Shader compilation expected result enum + * @enum {number} + */ +glsShaderLibraryCase.expectResult = { + EXPECT_PASS: 0, + EXPECT_COMPILE_FAIL: 1, + EXPECT_LINK_FAIL: 2, + EXPECT_COMPILE_LINK_FAIL: 3, + EXPECT_VALIDATION_FAIL: 4, + EXPECT_BUILD_SUCCESSFUL: 5 +}; + +/** + * Test case type + * @enum {number} + */ +glsShaderLibraryCase.caseType = { + CASETYPE_COMPLETE: 0, //!< Has all shaders specified separately. + CASETYPE_VERTEX_ONLY: 1, //!< "Both" case, vertex shader sub case. + CASETYPE_FRAGMENT_ONLY: 2 //!< "Both" case, fragment shader sub case. +}; + +/** + * glsShaderLibraryCase.BeforeDrawValidator target type enum + * @enum {number} + */ +glsShaderLibraryCase.targetType = { + PROGRAM: 0, + PIPELINE: 1 +}; + +/** + * Shader case type enum + * @enum {number} + */ +glsShaderLibraryCase.shaderCase = { + STORAGE_INPUT: 0, + STORAGE_OUTPUT: 1, + STORAGE_UNIFORM: 2 +}; + +/** + * Checks if shader uses in/out qualifiers depending on the version + * @param {string} version + * @return {boolean} version + */ +glsShaderLibraryCase.usesShaderInoutQualifiers = function(version) { + switch (version) { + case '100': + case '130': + case '140': + case '150': + return false; + + default: + return true; + } +}; + +/** + * Checks if version supports fragment highp precision + * @param {string} version + * @return {boolean} version ,True when is different from version 100 + */ +glsShaderLibraryCase.supportsFragmentHighp = function(version) { + return version !== '100'; +}; + +/** + * This functions builds a matching vertex shader for a 'both' case, when + * the fragment shader is being tested. + * We need to build attributes and varyings for each 'input'. + * @param { {values:Array}} valueBlock + * @return {string} res + */ +glsShaderLibraryCase.genVertexShader = function(valueBlock) { + /** @type {string} */ var res = ''; + /** @type {Object} */ var state = tcuTestCase.runner; + /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); + /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; + /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying'; + + res += '#version ' + state.currentTest.spec.targetVersion + '\n'; + res += 'precision highp float;\n'; + res += 'precision highp int;\n'; + res += '\n'; + res += vtxIn + ' highp vec4 dEQP_Position;\n'; + + for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { + var val = valueBlock.values[ndx]; + if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { + /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); + res += vtxIn + ' ' + floatType + ' a_' + val.valueName + ';\n'; + + if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') + res += vtxOut + ' ' + floatType + ' ' + val.valueName + ';\n'; + else + res += vtxOut + ' ' + floatType + ' v_' + val.valueName + ';\n'; + } + } + res += '\n'; + + // Main function. + // - gl_Position = dEQP_Position; + // - for each input: write attribute directly to varying + res += 'void main()\n'; + res += ' {\n'; + res += '\tgl_Position = dEQP_Position;\n'; + for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { + var val = valueBlock.values[ndx]; + if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_INPUT) { + /** @type {string} */ var name = val.valueName; + if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') + res += '\t' + name + ' = a_' + name + ';\n'; + else + res += '\tv_' + name + ' = a_' + name + ';\n'; + } + } + + res += '}\n'; + return res; +}; + +/** + * @param { {values:Array}} valueBlock + * @param {boolean} useFloatTypes + * @return {string} stream + */ +glsShaderLibraryCase.genCompareFunctions = function(valueBlock, useFloatTypes) { + var cmpTypeFound = {}; + /** @type {string} */ var stream = ''; + + for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { + /** @type {Array} */ var val = valueBlock.values[ndx]; + if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) + cmpTypeFound[gluShaderUtil.getDataTypeName(val.dataType)] = true; + + } + if (useFloatTypes) { + if (cmpTypeFound['bool']) stream += 'bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n'; + if (cmpTypeFound['bvec2']) stream += 'bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n'; + if (cmpTypeFound['bvec3']) stream += 'bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n'; + if (cmpTypeFound['bvec4']) stream += 'bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n'; + if (cmpTypeFound['int']) stream += 'bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n'; + if (cmpTypeFound['ivec2']) stream += 'bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n'; + if (cmpTypeFound['ivec3']) stream += 'bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n'; + if (cmpTypeFound['ivec4']) stream += 'bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n'; + if (cmpTypeFound['uint']) stream += 'bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n'; + if (cmpTypeFound['uvec2']) stream += 'bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n'; + if (cmpTypeFound['uvec3']) stream += 'bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n'; + if (cmpTypeFound['uvec4']) stream += 'bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n'; + } else { + if (cmpTypeFound['bool']) stream += 'bool isOk (bool a, bool b) { return (a == b); }\n'; + if (cmpTypeFound['bvec2']) stream += 'bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n'; + if (cmpTypeFound['bvec3']) stream += 'bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n'; + if (cmpTypeFound['bvec4']) stream += 'bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n'; + if (cmpTypeFound['int']) stream += 'bool isOk (int a, int b) { return (a == b); }\n'; + if (cmpTypeFound['ivec2']) stream += 'bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n'; + if (cmpTypeFound['ivec3']) stream += 'bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n'; + if (cmpTypeFound['ivec4']) stream += 'bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n'; + if (cmpTypeFound['uint']) stream += 'bool isOk (uint a, uint b) { return (a == b); }\n'; + if (cmpTypeFound['uvec2']) stream += 'bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n'; + if (cmpTypeFound['uvec3']) stream += 'bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n'; + if (cmpTypeFound['uvec4']) stream += 'bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n'; + } + + if (cmpTypeFound['float']) + stream += 'bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n'; + if (cmpTypeFound['vec2']) + stream += 'bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; + if (cmpTypeFound['vec3']) + stream += 'bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; + if (cmpTypeFound['vec4']) + stream += 'bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n'; + + if (cmpTypeFound['mat2']) + stream += 'bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n'; + if (cmpTypeFound['mat2x3']) + stream += 'bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n'; + if (cmpTypeFound['mat2x4']) + stream += 'bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n'; + if (cmpTypeFound['mat3x2']) + stream += 'bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n'; + if (cmpTypeFound['mat3']) + stream += 'bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n'; + if (cmpTypeFound['mat3x4']) + stream += 'bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n'; + if (cmpTypeFound['mat4x2']) + stream += 'bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n'; + if (cmpTypeFound['mat4x3']) + stream += 'bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n'; + if (cmpTypeFound['mat4']) + stream += 'bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n'; + + return stream; +}; + +/** + * @param {string} dstVec4Var + * @param { {values:Array}} valueBlock + * @param {string} nonFloatNamePrefix + * @param {?string=} checkVarName + * @return {string} output + */ +glsShaderLibraryCase.genCompareOp = function(dstVec4Var, valueBlock, nonFloatNamePrefix, checkVarName) { + + /** @type {boolean} */ var isFirstOutput = true; + /** @type {string} */ var output = ''; + + for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { + /** @type {Array} */ var val = valueBlock.values[ndx]; + /** @type {string} */ var valueName = val.valueName; + + if (val.storageType === glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { + // Check if we're only interested in one variable (then skip if not the right one). + if (checkVarName && (valueName !== checkVarName)) + continue; + + // Prefix. + if (isFirstOutput) { + output += 'bool RES = '; + isFirstOutput = false; + } else + output += 'RES = RES && '; + + // Generate actual comparison. + if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') + output += 'isOk(' + valueName + ', ref_' + valueName + ', 0.05);\n'; + else + output += 'isOk(' + nonFloatNamePrefix + valueName + ', ref_' + valueName + ');\n'; + } + // \note Uniforms are already declared in shader. + } + + if (isFirstOutput) + output += dstVec4Var + ' = vec4(1.0);\n'; // \todo [petri] Should we give warning if not expect-failure case? + else + output += dstVec4Var + ' = vec4(RES, RES, RES, 1.0);\n'; + + return output; +}; + +/** + * @param { {values:Array}} valueBlock + * @return {string} shader + */ +glsShaderLibraryCase.genFragmentShader = function(valueBlock) { + /** @type {string} */ var shader = ''; + /** @type {Object} */ var state = tcuTestCase.runner; + /** @type {boolean} */ var usesInout = glsShaderLibraryCase.usesShaderInoutQualifiers(state.currentTest.spec.targetVersion); + /** @type {string} */ var vtxIn = usesInout ? 'in' : 'attribute'; + /** @type {string} */ var vtxOut = usesInout ? 'out' : 'varying'; + /** @type {boolean} */ var customColorOut = usesInout; + /** @type {string} */ var fragIn = usesInout ? 'in' : 'varying'; + /** @type {string} */ var prec = glsShaderLibraryCase.supportsFragmentHighp(state.currentTest.spec.targetVersion) ? 'highp' : 'mediump'; + + shader += '#version ' + state.currentTest.spec.targetVersion + '\n'; + + shader += 'precision ' + prec + ' float;\n'; + shader += 'precision ' + prec + ' int;\n'; + shader += '\n'; + + if (customColorOut) { + shader += 'layout(location = 0) out mediump vec4 dEQP_FragColor;\n'; + shader += '\n'; + } + + shader += glsShaderLibraryCase.genCompareFunctions(valueBlock, true); + shader += '\n'; + + // Declarations (varying, reference for each output). + for (var ndx = 0; ndx < valueBlock.values.length; ndx++) { + /** @type {Array} */ var val = valueBlock.values[ndx]; + /** @type {string} */ var floatType = gluShaderUtil.getDataTypeFloatScalars(val.dataType); + /** @type {string} */ var refType = gluShaderUtil.getDataTypeName(val.dataType); + + if (val.storageType == glsShaderLibraryCase.shaderCase.STORAGE_OUTPUT) { + if (gluShaderUtil.getDataTypeScalarType(val.dataType) === 'float') + shader += fragIn + ' ' + floatType + ' ' + val.valueName + ';\n'; + else + shader += fragIn + ' ' + floatType + ' v_' + val.valueName + ';\n'; + + shader += 'uniform ' + refType + ' ref_' + val.valueName + ';\n'; + } + } + + shader += '\n'; + shader += 'void main()\n'; + shader += ' {\n'; + + shader += '\t'; + shader += glsShaderLibraryCase.genCompareOp(customColorOut ? 'dEQP_FragColor' : 'gl_FragColor', valueBlock, 'v_', null); + + shader += '}\n'; + return shader; +}; + +glsShaderLibraryCase.caseRequirement = (function() { + +/** + * @constructor + */ +var CaseRequirement = function() { + +/** + * @param {number} shaderType + * @return {boolean} + */ + this.isAffected = function(shaderType) { + for (var i = 0; i < this.shaderTypes.length; i++) + if (this.shaderTypes[i] === shaderType) + return true; + return false; + }; + + this.checkRequirements = function(gl) { + if (this.type === requirementType.EXTENSION) { + var extns = gl.getSupportedExtensions(); + for (var i = 0; i < extns.length; i++) + for (var j = 0; j < this.requirements.length; j++) + if (extns[i] === this.requirements[j]) { + this.supportedExtension = this.requirements[j]; + return true; + } + if (this.requirements.length === 1) + throw Error('Test requires extension of ' + this.requirements[0]); + else + throw Error('Test requires any extension of ' + this.requirements); + } else if (this.type === requirementType.IMPLEMENTATION_LIMIT) { + var value = gl.getParameter(this.enumName); + assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Failed to read parameter ' + this.enumName, false, true); + + if (!(value > this.referenceValue)) + throw Error('Test requires ' + this.enumName + ' (' + value + ') > ' + this.referenceValue); + } + }; + + this.getSupportedExtension = function() { + return this.supportedExtension; + }; + +}; + +var createAnyExtensionRequirement = function(requirements, shaderTypes) { + var cr = new CaseRequirement(); + cr.type = requirementType.EXTENSION; + cr.requirements = requirements; + cr.shaderTypes = shaderTypes; + return cr; +}; + +var createLimitRequirement = function(enumName, ref) { + var cr = new CaseRequirement(); + cr.type = requirementType.IMPLEMENTATION_LIMIT; + cr.enumName = enumName; + cr.referenceValue = ref; +}; + +/** + * @enum {number} + */ +var requirementType = { + EXTENSION: 0, + IMPLEMENTATION_LIMIT: 1 +}; + +return { + createAnyExtensionRequirement: createAnyExtensionRequirement, + createLimitRequirement: createLimitRequirement, + requirementType: requirementType +}; + +}()); + +/** Specialize a shader only for the vertex test case. + * @param {string} baseCode + * @param {number} shaderType + * @param {Array} requirements + * @return {string} resultBuf + */ +glsShaderLibraryCase.injectExtensionRequirements = function(baseCode, shaderType, requirements) { +/** + * @param {Array} 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} */ 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} */ 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} */ + 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} */ + 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} */ var pipelineProgramIDs = []; + /** @type {Array} */ 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} */ 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 0000000000..31f59de1f6 --- /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} */ 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} 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} constCoords + * @param {Array} userAttribTransforms + * @param {Array} 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} */ this.m_constCoords = constCoords; + /** @type {Array} */ this.m_userAttribTransforms = userAttribTransforms; + /** @type {Array} */ this.m_textures = textures; + /** @type {Array>} */ this.m_screenPos = []; + /** @type {Array>} */ this.m_positions = []; + /** @type {Array>} */ this.m_coords = []; //!< Near-unit coordinates, roughly [-2.0 .. 2.0]. + /** @type {Array>} */ this.m_unitCoords = []; //!< Positive-only coordinates [0.0 .. 1.5]. + /** @type {Array} */ this.m_attribOne = []; + /** @type {Array>} */ this.m_userAttribs = []; + for (var attribNdx = 0; attribNdx < this.getNumUserAttribs(); attribNdx++) + this.m_userAttribs[attribNdx] = []; + /** @type {Array} */ this.m_indices = []; + + /** @type Array} */ 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} */ + glsShaderRenderCase.QuadGrid.prototype.getConstCoords = function() { + return this.m_constCoords; + }; + + /** @return {Array} */ + glsShaderRenderCase.QuadGrid.prototype.getUserAttribTransforms = function() { + return this.m_userAttribTransforms; + }; + + /** @return {Array} */ + glsShaderRenderCase.QuadGrid.prototype.getTextures = function() { + return this.m_textures; + }; + + /** @return {Array>} */ + glsShaderRenderCase.QuadGrid.prototype.getPositions = function() { + return this.m_positions; + }; + + /** @return {Array} */ + glsShaderRenderCase.QuadGrid.prototype.getAttribOne = function() { + return this.m_attribOne; + }; + + /** @return {Array>} */ + glsShaderRenderCase.QuadGrid.prototype.getCoordsArray = function() { + return this.m_coords; + }; + + /** @return {Array>} */ + glsShaderRenderCase.QuadGrid.prototype.getUnitCoordsArray = function() { + return this.m_unitCoords; + }; + + /** + * @param {number} attribNdx + * @return {Array} + */ + glsShaderRenderCase.QuadGrid.prototype.getUserAttribByIndex = function(attribNdx) { + return this.m_userAttribs[attribNdx]; + }; + + /** @return {Array} */ + glsShaderRenderCase.QuadGrid.prototype.getIndices = function() { + return this.m_indices; + }; + + /** + * @param {number} sx + * @param {number} sy + * @return {Array} + */ + 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} + */ + 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} + */ + 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} */ this.coords = [0, 0, 0, 0] + /** @type {Array} */ this.unitCoords = [0, 0, 0, 0] + /** @type {Array} */ this.constCoords = quadGrid_.getConstCoords(); + /** @type {Array>} */ this.in_ = []; + /** @type {Array} */ this.textures = []; + /** @type {Array} */ this.color = [0, 0, 0, 0.0]; + /** @type {boolean} */ this.isDiscarded = false; + /** @type {glsShaderRenderCase.QuadGrid} */ this.quadGrid = quadGrid_; + + /** @type {Array} */ 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} 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} */ this.m_clearColor = glsShaderRenderCase.DEFAULT_CLEAR_COLOR; + /** @type {Array} */ this.m_userAttribTransforms = []; + /** @type {Array} */ 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} */ 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} constCoords + */ + glsShaderRenderCase.ShaderRenderCase.prototype.setupUniforms = function(programId, constCoords) {}; + + /** + * @return {Array} + */ + 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} */ 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} */ var color = []; + // Evaluate color for each vertex. + /** @type {Array>} */ 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} */ var c00 = colors[v00]; + /** @type {Array} */ var c01 = colors[v01]; + /** @type {Array} */ var c10 = colors[v10]; + /** @type {Array} */ 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} */ var t0 = tri ? c00 : c11; + /** @type {Array} */ var t1 = tri ? c01 : c10; + /** @type {Array} */ 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} */ 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} */ 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} */ this.value = value; + }; + + /** @type {Array} */ 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} */ 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} */ 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} */ this.value = value; + }; + + /** @type {Array} */ 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} */ this.value = value; + }; + + /** @type {Array} */ 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} */ this.value = value; + }; + /** @type {Array} */ 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} */ 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} */ this.value = value; + }; + /** @type {Array} */ 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} */ this.value = value; + }; + /** @type {Array} */ 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} */ this.value = value; + }; + /** @type {Array} */ 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} 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} */ 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 0000000000..962d87fb47 --- /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} reference + * @return {boolean} + */ +glsStateQuery.verifyGreaterOrEqual = function(param, reference) { + var value = gl.getParameter(param); + if (reference instanceof Array) { + var v = /** @type {Array} */ (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} reference + * @return {boolean} + */ +glsStateQuery.verifyLessOrEqual = function(param, reference) { + var value = gl.getParameter(param); + if (reference instanceof Array) { + var v = /** @type {Array} */ (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} reference + * @param {Array} enableRef + * @return {boolean} + */ + +glsStateQuery.verifyMask = function(param, reference, enableRef) { + var intVector4 = /** @type {Array} */ (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 0000000000..f35d942261 --- /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} bottomLeft + * @param {Array} topRight + * @return {Array} + */ +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} + */ +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} bottomLeft + * @param {Array} topRight + * @return {Array} + */ +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} bottomLeft + * @param {Array} topRight + * @return {Array} + */ +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} a + * @param {Array} b + * @param {Array} c + * @return {Array} 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} p0 + * @param {Array} p1 + * @param {Array} dirSwz + * @return {Array} + */ +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 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} + */ +glsTextureTestUtil.getCompareMask = function(format) { + return [ + format.redBits > 0, + format.greenBits > 0, + format.blueBits > 0, + format.alphaBits > 0 + ]; +}; + +/** + * @param {tcuPixelFormat.PixelFormat} format + * @return {Array} + */ +glsTextureTestUtil.getBitsVec = function(format) { + return [ + format.redBits, + format.greenBits, + format.blueBits, + format.alphaBits + ]; +}; + +/** + * @param {number} texUnit + * @param {Array} 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} 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} dstSize + * @param {Array} srcSize + * @param {Array} sq + * @param {Array} tq + * @param {Array=} 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} 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} s + * @param {Array} 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} s + * @param {Array} 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} texCoord Texture coordinates + * @param {number} lod + * @return {Array} 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} pixel + * @param {Array} scale + * @param {Array} 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} pixel + * @param {Array} scale + * @param {Array} 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} sq + * @param {Array} 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} */ var uq = deMath.scale(sq, src.getWidth()); + /** @type {Array} */ var vq = deMath.scale(tq, src.getHeight()); + + /** @type {Array>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array>} */ var triU = [deMath.swizzle(uq, [0, 1, 2]), deMath.swizzle(uq, [3, 2, 1])]; + /** @type {Array>} */ var triV = [deMath.swizzle(vq, [0, 1, 2]), deMath.swizzle(vq, [3, 2, 1])]; + /** @type {Array>} */ 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} u + * @param {Array} v + * @param {Array} 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} sq + * @param {Array} 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} sq + * @param {Array} tq + * @param {Array} 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} 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} coord + * @param {Array} coordDx + * @param {Array} 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} sq + * @param {Array} tq + * @param {Array} 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} 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} 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} sq + * @param {Array} tq + * @param {Array} 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} 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} threshold + * @param {Array< Array >} 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} 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} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array} 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} */ var green = [0, 255, 0, 255]; + errorMask.clear(green); + + /** @type {Array} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array} */ + var resPix = result.getPixel(px, py); + /** @type {Array} */ + 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} 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} 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} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array} */ + 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} 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} 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} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array} */ + 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} 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} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array} 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} */ var green = [0, 255, 0, 255]; + errorMask.clear(green); + + /** @type {Array} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array} */ + var resPix = result.getPixel(px, py); + /** @type {Array} */ + 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} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array} 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} */ var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + /** @type {Array} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array} */ + var resPix = result.getPixel(px, py); + /** @type {Array} */ + 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} s + * @param {Array} 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} 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} */ var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]]; + /** @type {Array} */ var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]]; + + /** @type {Array} */ var dstSize = [result.getWidth(), result.getHeight()]; + /** @type {number} */ var dstW = dstSize[0]; + /** @type {number} */ var dstH = dstSize[1]; + /** @type {Array} */ var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + /** @type {Array>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + /** @type {Array} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0]; + + /** @type {number} */ var numFailed = 0; + + /** @type {Array>} */ var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array} */ 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} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array} */ + 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} */ var coord = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy) + ]; + /** @type {Array} */ 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} */ 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} */ + 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} */ var coordO = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)]; + /** @type {Array} */ 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} */ 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} */ + 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} */ 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} 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} */ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + /** @type {Array} */ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + /** @type {Array} */ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + /** @type {Array} */ var dstSize = [result.getWidth(), result.getHeight()]; + /** @type {number} */ var dstW = dstSize[0]; + /** @type {number} */ var dstH = dstSize[1]; + /** @type {Array} */ var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + /** @type {Array>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array>} */ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + /** @type {Array>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + /** @type {Array} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0]; + + /** @type {number} */ var numFailed = 0; + + /** @type {Array>} */ var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array} */ 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} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array} */ + 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} */ 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} */ 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} */ 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} */ + 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} */ 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} */ 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} */ 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} */ + 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} */ 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 0000000000..e9c45366ac --- /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). + /** @type {Array} */ this.offsets = []; //!< Reference block pointers (map). + /** @type {Array} */ 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} */ 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} */ 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} */ this.m_structs = []; + /** @type {Array} */ 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} 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} */ 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}*/ this.blocks = []; + /** @type {Array}*/ 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} */ 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} 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} 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} 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} 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} */ var types = []; //Will contain unique elements. + /** @type {Array} */ 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} */ 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} */ 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} */ 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} */ var uniformIndices = []; + for (var i = 0; i < numActiveUniforms; i++) + uniformIndices.push(i); + + /** @type {Array} */ var types = []; + /** @type {Array} */ var sizes = []; + /** @type {Array} */ var nameLengths = []; + /** @type {Array} */ var blockIndices = []; + /** @type {Array} */ var offsets = []; + /** @type {Array} */ var arrayStrides = []; + /** @type {Array} */ var matrixStrides = []; + /** @type {Array} */ 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 + "':
" + + "' expected: '" + gluShaderUtil.getDataTypeName(refEntry.type) + "'
" + + "' 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 0000000000..99dc79f35e --- /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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} */ 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} arrays + */ + glsVertexArrayTests.ContextShaderProgram = function(ctx, arrays) { + sglrShaderProgram.ShaderProgram.call(this, this.createProgramDeclaration(ctx, arrays)); + this.m_componentCount = new Array(arrays.length); + /** @type {Array} */ 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} coord (2 elements) + * @param {Array} 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} inputs + * @param {Array} 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} */ var coord = [1.0, 1.0]; + /** @type {Array} */ 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} 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} 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} 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 + static char* createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max); + template + 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} */ 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; + }; + +}); -- cgit v1.2.3