/*------------------------------------------------------------------------- * 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('functional.gles3.es3fShaderCommonFunctionTests'); goog.require('framework.common.tcuFloat'); 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.opengl.gluShaderProgram'); goog.require('framework.opengl.gluShaderUtil'); goog.require('framework.opengl.gluVarType'); goog.require('modules.shared.glsShaderExecUtil'); goog.scope(function() { var es3fShaderCommonFunctionTests = functional.gles3.es3fShaderCommonFunctionTests; var tcuFloat = framework.common.tcuFloat; var tcuTestCase = framework.common.tcuTestCase; var gluShaderProgram = framework.opengl.gluShaderProgram; var gluShaderUtil = framework.opengl.gluShaderUtil; var gluVarType = framework.opengl.gluVarType; var deRandom = framework.delibs.debase.deRandom; var deMath = framework.delibs.debase.deMath; var deString = framework.delibs.debase.deString; var glsShaderExecUtil = modules.shared.glsShaderExecUtil; /** @typedef {function(new: es3fShaderCommonFunctionTests.CommonFunctionCase, gluShaderUtil.DataType, gluShaderUtil.precision, gluShaderProgram.shaderType)} */ es3fShaderCommonFunctionTests.TestClass; /** * @enum */ es3fShaderCommonFunctionTests.Types = { FLOAT: 0, INT: 1, UINT: 2 }; /** * @param {Array} values */ es3fShaderCommonFunctionTests.vecToFloat16 = function(values) { for (var ndx = 0; ndx < values.length; ndx++) values[ndx] = tcuFloat.newFloat16(values[ndx]).getValue(); }; /** * @param {es3fShaderCommonFunctionTests.Types} type * @param {deRandom.Random} rnd * @param {number} minValue * @param {number} maxValue * @return {number} */ es3fShaderCommonFunctionTests.randomScalar = function(type, rnd, minValue, maxValue) { switch (type) { case es3fShaderCommonFunctionTests.Types.FLOAT: return rnd.getFloat(minValue, maxValue); case es3fShaderCommonFunctionTests.Types.INT: return rnd.getInt(minValue, maxValue); case es3fShaderCommonFunctionTests.Types.UINT: return Math.abs(rnd.getInt(minValue, maxValue)); default: throw new Error('Only FLOAT, INT, and UINT are supported.'); } }; /** * @param {es3fShaderCommonFunctionTests.Types} type * @param {Array} size * @param {deRandom.Random} rnd * @param {Array} minValue * @param {Array} maxValue * @return {Array} */ es3fShaderCommonFunctionTests.randomVector = function(type, size, rnd, minValue, maxValue) { /** @type {Array} */ var res = []; for (var ndx = 0; ndx < size; ndx++) res.push(es3fShaderCommonFunctionTests.randomScalar(type, rnd, minValue[ndx], maxValue[ndx])); return res; }; /** * @param {es3fShaderCommonFunctionTests.Types} type * @param {Array} size * @param {deRandom.Random} rnd * @param {Array} minValue * @param {Array} maxValue * @param {number} numValues * @param {number=} offset * @return {Array>} */ es3fShaderCommonFunctionTests.fillRandomVectors = function(type, size, rnd, minValue, maxValue, numValues, offset) { offset = offset === undefined ? 0 : offset; /** @type {Array>} */ var access; for (var ndx = 0; ndx < numValues; ndx++) access[offset + ndx] = es3fShaderCommonFunctionTests.randomVector(type, size, rnd, minValue, maxValue); return access; }; /** * @param {es3fShaderCommonFunctionTests.Types} type * @param {deRandom.Random} rnd * @param {number} minValue * @param {number} maxValue * @param {number} numValues * @param {number=} offset * @return {Array} */ es3fShaderCommonFunctionTests.fillRandomScalars = function(type, rnd, minValue, maxValue, numValues, offset) { offset = offset === undefined ? 0 : offset; /** @type {Array} */ var access = []; for (var ndx = 0; ndx < numValues; ndx++) access[offset + ndx] = es3fShaderCommonFunctionTests.randomScalar(type, rnd, minValue, maxValue); return access; }; /** * @param {number} input * @param {number} output * @return {number} */ es3fShaderCommonFunctionTests.numBitsLostInOp = function(input, output) { /** @type {number} */ var inExp = tcuFloat.newFloat32(input).exponent(); /** @type {number} */ var outExp = tcuFloat.newFloat32(output).exponent(); return Math.max(0, inExp - outExp); // Lost due to mantissa shift. }; /** * @param {number} a * @param {number} b * @return {number} */ es3fShaderCommonFunctionTests.getUlpDiff = function(a, b) { /** @type {number} */ var aBits = tcuFloat.newFloat32(a).bits(); /** @type {number} */ var bBits = tcuFloat.newFloat32(b).bits(); return aBits > bBits ? aBits - bBits : bBits - aBits; }; /** * @param {number} a * @param {number} b * @return {number} */ es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign = function(a, b) { if (tcuFloat.newFloat32(a).isZero()) return es3fShaderCommonFunctionTests.getUlpDiff(new tcuFloat.deFloat().construct(tcuFloat.newFloat32(b).sign(), 0, 0).getValue(), b); else if (tcuFloat.newFloat32(b).isZero()) return es3fShaderCommonFunctionTests.getUlpDiff(a, new tcuFloat.deFloat().construct(tcuFloat.newFloat32(a).sign(), 0, 0).getValue()); else return es3fShaderCommonFunctionTests.getUlpDiff(a, b); }; /** * @param {gluShaderUtil.precision} precision * @return {boolean} */ es3fShaderCommonFunctionTests.supportsSignedZero = function(precision) { // \note GLSL ES 3.0 doesn't really require support for -0, but we require it for highp // as it is very widely supported. return precision == gluShaderUtil.precision.PRECISION_HIGHP; }; /** * @param {number} value * @param {number} ulpDiff * @return {number} */ es3fShaderCommonFunctionTests.getEpsFromMaxUlpDiff = function(value, ulpDiff) { /** @type {number} */ var exp = tcuFloat.newFloat32(value).exponent(); return new tcuFloat.deFloat().construct(+1, exp, (1 << 23) | ulpDiff).getValue() - new tcuFloat.deFloat().construct(+1, exp, 1 << 23).getValue(); }; /** * @param {number} numAccurateBits * @return {number} */ es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits = function(numAccurateBits) { /** @type {number} */ var numGarbageBits = 23 - numAccurateBits; /** @type {number} */ var mask = (1 << numGarbageBits) - 1; return mask; }; /** * @param {number} value * @param {number} numAccurateBits * @return {number} */ es3fShaderCommonFunctionTests.getEpsFromBits = function(value, numAccurateBits) { return es3fShaderCommonFunctionTests.getEpsFromMaxUlpDiff(value, es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(numAccurateBits)); }; /** * @param {gluShaderUtil.precision} precision * @return {number} */ es3fShaderCommonFunctionTests.getMinMantissaBits = function(precision) { /** @type {Array} */ var bits = [ 7, // lowp 10, // mediump 23 // highp ]; assertMsgOptions(deMath.deInBounds32(precision, 0, bits.length), 'Unexpected precision option.', false, true); return bits[precision]; }; /** * @constructor * @extends {tcuTestCase.DeqpTest} * @param {string} name * @param {string} description * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.CommonFunctionCase = function(name, description, shaderType) { tcuTestCase.DeqpTest.call(this, name, description); /** @type {gluShaderProgram.shaderType} */ this.m_shaderType = shaderType; /** @type {number} */ this.m_numValues = 100; /** @type {glsShaderExecUtil.ShaderExecutor} */ this.m_executor = null; /** @type {glsShaderExecUtil.ShaderSpec} */ this.m_spec = new glsShaderExecUtil.ShaderSpec(); this.m_spec.version = gluShaderUtil.GLSLVersion.V300_ES; /** @type {string} */ this.m_failMsg; //!< Comparison failure help message. }; es3fShaderCommonFunctionTests.CommonFunctionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype); es3fShaderCommonFunctionTests.CommonFunctionCase.prototype.constructor = es3fShaderCommonFunctionTests.CommonFunctionCase; es3fShaderCommonFunctionTests.CommonFunctionCase.prototype.init = function() { assertMsgOptions(!this.m_executor, 'Shader executor should be null at this point', false, true); this.m_executor = glsShaderExecUtil.createExecutor(this.m_shaderType, this.m_spec); if (!this.m_executor.isOk()) throw new Error('Compile failed'); }; es3fShaderCommonFunctionTests.CommonFunctionCase.prototype.deinit = function() { this.m_executor = null; }; /** * @param {Array} symbols * @return {Array} */ es3fShaderCommonFunctionTests.getScalarSizes = function(symbols) { /** @type {Array} */ var sizes = []; for (var ndx = 0; ndx < symbols.length; ++ndx) sizes.push(symbols[ndx].varType.getScalarSize()); return sizes; }; /** * @param {Array} symbols * @return {number} */ es3fShaderCommonFunctionTests.computeTotalScalarSize = function(symbols) { /** @type {number} */ var totalSize = 0; for (var sym in symbols) totalSize += symbols[sym].varType.getScalarSize(); return totalSize; }; /** * @param {boolean} value * @return {string} */ es3fShaderCommonFunctionTests.ToBoolString = function(value) { return value ? "true" : "false"; }; /** * @param {gluVarType.VarType} varType * @param {Array<*>} values * @return {string} */ es3fShaderCommonFunctionTests.VarValue = function(varType, values) { /** @type {gluShaderUtil.DataType} */ var basicType = varType.getBasicType(); /** @type {gluShaderUtil.DataType} */ var scalarType = gluShaderUtil.getDataTypeScalarTypeAsDataType(basicType); /** @type {number} */ var numComponents = gluShaderUtil.getDataTypeScalarSize(basicType); /** @type {string} */ var outputStr = ""; if (numComponents > 1) { outputStr += gluShaderUtil.getDataTypeName(basicType) + "("; } for (var compNdx = 0; compNdx < numComponents; ++compNdx) { if (compNdx != 0) { outputStr += ", "; } // tcu::toHex() is all commented out in this project. // e.g. Line 199 of es3fShaderPackingFunctionTests.js switch (scalarType) { case gluShaderUtil.DataType.FLOAT: case gluShaderUtil.DataType.INT: case gluShaderUtil.DataType.UINT: outputStr += values[compNdx]; break; case gluShaderUtil.DataType.BOOL: outputStr += es3fShaderCommonFunctionTests.ToBoolString(values[compNdx]); break; default: throw Error('Unrecognized dataType ' + scalarType); } } if (numComponents > 1) { outputStr += ")"; } return outputStr; } /** * @return {tcuTestCase.IterateResult} */ es3fShaderCommonFunctionTests.CommonFunctionCase.prototype.iterate = function() { /** @type {number} */ var numInputScalars = es3fShaderCommonFunctionTests.computeTotalScalarSize(this.m_spec.inputs); /** @type {number} */ var numOutputScalars = es3fShaderCommonFunctionTests.computeTotalScalarSize(this.m_spec.outputs); /** @type {Array} */ var inputData = []; /** @type {Array} */ var outputData = []; /** @type {gluShaderUtil.DataType} */ var inputType = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.DataType} */ var outputType = this.m_spec.outputs[0].varType.getBasicType(); /** @type {Array>} */ var inputValues; /** @type {ArrayBuffer} */ var outputValues; inputValues = this.getInputValues(this.m_numValues); for (var inNdx = 0; inNdx < inputValues.length; inNdx++) { var data = inputType >= gluShaderUtil.DataType.FLOAT && inputType <= gluShaderUtil.DataType.FLOAT_VEC4 ? new Float32Array(inputValues[inNdx]) : inputType >= gluShaderUtil.DataType.INT && inputType <= gluShaderUtil.DataType.INT_VEC4 ? new Int32Array(inputValues[inNdx]) : inputType >= gluShaderUtil.DataType.UINT && inputType <= gluShaderUtil.DataType.UINT_VEC4 ? new Uint32Array(inputValues[inNdx]) : null; inputData.push(data); } // Execute shader. this.m_executor.useProgram(); outputValues = this.m_executor.execute(this.m_numValues, inputData); for (var outNdx = 0; outNdx < outputValues.length; outNdx++) { var data = outputType >= gluShaderUtil.DataType.FLOAT && outputType <= gluShaderUtil.DataType.FLOAT_VEC4 ? new Float32Array(outputValues[outNdx].buffer) : outputType >= gluShaderUtil.DataType.INT && outputType <= gluShaderUtil.DataType.INT_VEC4 ? new Int32Array(outputValues[outNdx].buffer) : outputType >= gluShaderUtil.DataType.UINT && outputType <= gluShaderUtil.DataType.UINT_VEC4 ? new Uint32Array(outputValues[outNdx].buffer) : outputType >= gluShaderUtil.DataType.BOOL && outputType <= gluShaderUtil.DataType.BOOL_VEC4 ? new Int32Array(outputValues[outNdx].buffer) : null; outputData.push(data); } // TODO: verify proper TypedArray for BOOL types; defaulting to Int32Array in the mean time (outputValues returns 400 bytes, we need 100 elements) // Compare results. /** @type {Array} */ var inScalarSizes = es3fShaderCommonFunctionTests.getScalarSizes(this.m_spec.inputs); /** @type {Array} */ var outScalarSizes = es3fShaderCommonFunctionTests.getScalarSizes(this.m_spec.outputs); /** @type {Array<*>} */ var curInputPtr = []; /** @type {Array<*>} */ var curOutputPtr = []; /** @type {number} */ var numFailed = 0; for (var inNdx = 0; inNdx < inputData.length; inNdx++) { curInputPtr[inNdx] = []; for (var valNdx = 0; valNdx < inputData[inNdx].length; valNdx += inScalarSizes[inNdx]) curInputPtr[inNdx].push(inputData[inNdx].slice(valNdx, valNdx + inScalarSizes[inNdx])); } for (var outNdx = 0; outNdx < outputData.length; outNdx++) { curOutputPtr[outNdx] = []; for (var valNdx = 0; valNdx < outputData[outNdx].length; valNdx += outScalarSizes[outNdx]) curOutputPtr[outNdx].push(outputData[outNdx].slice(valNdx, valNdx + outScalarSizes[outNdx])); } this.m_failMsg = ''; for (var valNdx = 0; valNdx < this.m_numValues; valNdx++) { var curInputValues = []; var curOutputValues = []; for (var inNdx = 0; inNdx < inputData.length; inNdx++) { curInputValues.push(curInputPtr[inNdx][valNdx]); } for (var outNdx = 0; outNdx < outputData.length; outNdx++) { curOutputValues.push(curOutputPtr[outNdx][valNdx]); } if (!this.compare(curInputValues, curOutputValues)) { // \todo [2013-08-08 pyry] We probably want to log reference value as well? bufferedLogToConsole('ERROR: comparison failed for value ' + valNdx + ':\n ' + this.m_failMsg); bufferedLogToConsole(' inputs:'); for (var inNdx = 0; inNdx < inputData.length; ++inNdx) { var varValue = es3fShaderCommonFunctionTests.VarValue(this.m_spec.inputs[0].varType, curInputValues[inNdx]); bufferedLogToConsole(' ' + this.m_spec.inputs[inNdx].name + ' = ' + varValue); } bufferedLogToConsole(' outputs:'); for (var outNdx = 0; outNdx < outputData.length; ++outNdx) { var varValue = es3fShaderCommonFunctionTests.VarValue(this.m_spec.inputs[0].varType, curOutputValues[outNdx]); bufferedLogToConsole(' ' + this.m_spec.outputs[outNdx].name + ' = ' + varValue); } this.m_failMsg = ''; numFailed += 1; } } bufferedLogToConsole((this.m_numValues - numFailed) + ' / ' + this.m_numValues + ' values passed'); /** @type {boolean} */ var isOk = numFailed === 0; if (!isOk) testFailedOptions('Result comparison failed', false); else testPassedOptions('Pass', true); return tcuTestCase.IterateResult.STOP; }; /** * @param {gluShaderUtil.precision} precision * @return {string} */ es3fShaderCommonFunctionTests.getPrecisionPostfix = function(precision) { /** @type {Array} */ var s_postfix = [ '_lowp', '_mediump', '_highp' ]; assertMsgOptions(0 <= precision && precision < s_postfix.length, 'Error: Out of range', false, true); return s_postfix[precision]; }; /** * @param {gluShaderProgram.shaderType} shaderType * @return {string} */ es3fShaderCommonFunctionTests.getShaderTypePostfix = function(shaderType) { /** @type {Array} */ var s_postfix = [ '_vertex', '_fragment' ]; assertMsgOptions(0 <= shaderType && shaderType < s_postfix.length, 'Error Out of range', false, true); return s_postfix[shaderType]; }; /** * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType * @return {string} */ es3fShaderCommonFunctionTests.getCommonFuncCaseName = function(baseType, precision, shaderType) { return gluShaderUtil.getDataTypeName(baseType) + es3fShaderCommonFunctionTests.getPrecisionPostfix(precision) + es3fShaderCommonFunctionTests.getShaderTypePostfix(shaderType); }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.AbsCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'abs', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = abs(in0);'; }; es3fShaderCommonFunctionTests.AbsCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.AbsCase.prototype.constructor = es3fShaderCommonFunctionTests.AbsCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.AbsCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var floatRanges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {Array>} */ var intRanges = [ [-(1 << 7) + 1, (1 << 7) - 1], [-(1 << 15) + 1, (1 << 15) - 1], [-0x80000000 + 1, 0x7fffffff] ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0x235fac); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; values[0] = []; if (gluShaderUtil.isDataTypeFloatOrVec(type)) values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, floatRanges[precision][0], floatRanges[precision][1], numValues * scalarSize); else values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.INT, rnd, intRanges[precision][0], intRanges[precision][1], numValues * scalarSize); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.AbsCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref0; if (gluShaderUtil.isDataTypeFloatOrVec(type)) { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = (1 << (23 - mantissaBits)) - 1; for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref0 = Math.abs(in0); /** @type {number} */ var ulpDiff0 = es3fShaderCommonFunctionTests.getUlpDiff(out0, ref0); if (ulpDiff0 > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref0 /*HexFloat(ref0)*/ + ' with ULP threshold ' + maxUlpDiff + ', got ULP diff ' + ulpDiff0; return false; } } } else for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref0 = Math.abs(in0); if (out0 != ref0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref0; return false; } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.SignCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'sign', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = sign(in0);'; }; es3fShaderCommonFunctionTests.SignCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.SignCase.prototype.constructor = es3fShaderCommonFunctionTests.SignCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.SignCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var floatRanges = [ [-2.0, 2.0], // lowp [-1e4, 1e4], // mediump [-1e8, 1e8] // highp ]; /** @type {Array>} */ var intRanges = [ [-(1 << 7), (1 << 7) - 1], [-(1 << 15), (1 << 15) - 1], [0x80000000, 0x7fffffff] ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0x324); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; values[0] = []; if (gluShaderUtil.isDataTypeFloatOrVec(type)) { // Special cases. // [dag] The special cases are 1, -1, and 0 var specialCases = [1.0, -1.0, 0.0]; for (var caseNdx = 0; caseNdx < specialCases.length; caseNdx++) for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) { values[0].push(specialCases[caseNdx]); } values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, floatRanges[precision][0], floatRanges[precision][1], (numValues - 3) * scalarSize)); } else { var specialCases = [1, -1, 0]; for (var caseNdx = 0; caseNdx < specialCases.length; caseNdx++) for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) { values[0].push(specialCases[caseNdx]); } values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.INT, rnd, intRanges[precision][0], intRanges[precision][1], (numValues - 3) * scalarSize)); } return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.SignCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref0; if (gluShaderUtil.isDataTypeFloatOrVec(type)) { // Both highp and mediump should be able to represent -1, 0, and +1 exactly /** @type {number} */ var maxUlpDiff = precision === gluShaderUtil.precision.PRECISION_LOWP ? es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(es3fShaderCommonFunctionTests.getMinMantissaBits(precision)) : 0; for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref0 = in0 < 0.0 ? -1.0 : in0 > 0.0 ? 1.0 : 0.0; /** @type {number} */ var ulpDiff0 = es3fShaderCommonFunctionTests.getUlpDiff(out0, ref0); if (ulpDiff0 > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref0 /*HexFloat(ref0)*/ + ' with ULP threshold ' + maxUlpDiff + ', got ULP diff ' + ulpDiff0; return false; } } } else { for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref0 = in0 < 0 ? -1 : in0 > 0 ? 1 : 0; if (out0 != ref0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref0; return false; } } } return true; }; /** * @param {number} v * @return {number} */ es3fShaderCommonFunctionTests.roundEven = function(v) { /** @type {number} */ var q = deMath.deFloatFrac(v); /** @type {number} */ var truncated = Math.trunc(v - q); /** @type {number} */ var rounded = (q > 0.5) ? (truncated + 1) : // Rounded up (q == 0.5 && (truncated % 2 != 0)) ? (truncated + 1) : // Round to nearest even at 0.5 truncated; // Rounded down return rounded; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.RoundEvenCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'roundEven', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = roundEven(in0);'; }; es3fShaderCommonFunctionTests.RoundEvenCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.RoundEvenCase.prototype.constructor = es3fShaderCommonFunctionTests.RoundEvenCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.RoundEvenCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var numSpecialCases = 0; /** @type {Array>} */ var values = []; values[0] = []; // Special cases. if (precision !== gluShaderUtil.precision.PRECISION_LOWP) { assertMsgOptions(numValues >= 20, 'numValues should be greater or equal than 20', false, true); for (var ndx = 0; ndx < 20; ndx++) { /** @type {number} */ var v = deMath.clamp(ndx - 10.5, ranges[precision][0], ranges[precision][1]); for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) { values[0].push(v); } numSpecialCases += 1; } } // Random cases. values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], (numValues - numSpecialCases) * scalarSize)); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.RoundEvenCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; if (precision == gluShaderUtil.precision.PRECISION_HIGHP || precision == gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact rounding result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var ref = es3fShaderCommonFunctionTests.roundEven(in0); /** @type {number} */ var ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var minRes = Math.floor(es3fShaderCommonFunctionTests.roundEven(in0 - eps)); /** @type {number} */ var maxRes = Math.floor(es3fShaderCommonFunctionTests.roundEven(in0 + eps)); /** @type {boolean} */ var anyOk = false; for (var roundedVal = minRes; roundedVal <= maxRes; roundedVal++) { ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, roundedVal); if (ulpDiff <= maxUlpDiff) { anyOk = true; break; } } if (!anyOk) { this.m_failMsg += 'Expected [' + compNdx + '] = [' + minRes + ', ' + maxRes + '] with ULP threshold ' + maxUlpDiff; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.ModfCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'modf', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out1', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = modf(in0, out1);'; }; es3fShaderCommonFunctionTests.ModfCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.ModfCase.prototype.constructor = es3fShaderCommonFunctionTests.ModfCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.ModfCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], numValues * scalarSize); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.ModfCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {boolean} */ var hasZeroSign = es3fShaderCommonFunctionTests.supportsSignedZero(precision); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var out1; for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; out1 = outputs[1][compNdx]; /** @type {number} */ var refOut1 = Math.floor(in0); /** @type {number} */ var refOut0 = in0 - refOut1; /** @type {number} */ var bitsLost = precision != gluShaderUtil.precision.PRECISION_HIGHP ? es3fShaderCommonFunctionTests.numBitsLostInOp(in0, refOut0) : 0; /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(Math.max(mantissaBits - bitsLost, 0)); /** @type {number} */ var resSum = out0 + out1; /** @type {number} */ var ulpDiff = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(resSum, in0) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(resSum, in0); if (ulpDiff > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = (' + refOut0 + ') + (' + refOut1 + ') = ' + in0 + ' with ULP threshold ' + maxUlpDiff + ', got ULP diff ' + ulpDiff; return false; } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.IsnanCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'isnan', shaderType); assertMsgOptions(gluShaderUtil.isDataTypeFloatOrVec(baseType), 'Assert error.', false, true); /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(baseType); /** @type {gluShaderUtil.DataType} */ var boolType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.BOOL, vecSize) : gluShaderUtil.DataType.BOOL; this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(boolType))); this.m_spec.source = 'out0 = isnan(in0);'; }; es3fShaderCommonFunctionTests.IsnanCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.IsnanCase.prototype.constructor = es3fShaderCommonFunctionTests.IsnanCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.IsnanCase.prototype.getInputValues = function(numValues) { /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xc2a39f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var mantissaMask = (~es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits)) & ((1 << 23) - 1); /** @type {Array>} */ var values = []; values[0] = []; for (var valNdx = 0; valNdx < numValues * scalarSize; valNdx++) { /** @type {boolean} */ var isNan = rnd.getFloat() > 0.3; /** @type {boolean} */ var isInf = !isNan && rnd.getFloat() > 0.4; /** @type {number} */ var mantissa = !isInf ? ((1 << 22) | (Math.abs(rnd.getInt()) & mantissaMask)) : 0; /** @type {number} */ var exp = !isNan && !isInf ? (Math.abs(rnd.getInt()) & 0x7f) : 0xff; /** @type {number} */ var sign = Math.abs(rnd.getInt()) & 0x1; /** @type {number} */ var value = (sign << 31) | (exp << 23) | mantissa; // Convert int to float. var view = new DataView(new ArrayBuffer(4)); view.setInt32(0, value, true); value = view.getFloat32(0, true); assertMsgOptions(tcuFloat.newFloat32(value).isInf() === isInf && tcuFloat.newFloat32(value).isNaN() === isNan, 'Assert error.', false, true); values[0].push(value); } return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.IsnanCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; if (precision === gluShaderUtil.precision.PRECISION_HIGHP) { for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref = tcuFloat.newFloat32(in0).isNaN() ? 1 : 0; if (out0 !== ref) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref; return false; } } } else { for (var compNdx = 0; compNdx < scalarSize; compNdx++) { out0 = outputs[0][compNdx]; if (out0 !== 0 && out0 !== 1) { this.m_failMsg += 'Expected [' + compNdx + '] = 0 / 1'; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.IsinfCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'isinf', shaderType); assertMsgOptions(gluShaderUtil.isDataTypeFloatOrVec(baseType), 'Assert error.', false, true); /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(baseType); /** @type {gluShaderUtil.DataType} */ var boolType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.BOOL, vecSize) : gluShaderUtil.DataType.BOOL; this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(boolType))); this.m_spec.source = 'out0 = isinf(in0);'; }; es3fShaderCommonFunctionTests.IsinfCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.IsinfCase.prototype.constructor = es3fShaderCommonFunctionTests.IsinfCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.IsinfCase.prototype.getInputValues = function(numValues) { /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xc2a39f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var mantissaMask = (~es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits)) & ((1 << 23) - 1); /** @type {Array>} */ var values = []; values[0] = []; for (var valNdx = 0; valNdx < numValues * scalarSize; valNdx++) { /** @type {boolean} */ var isInf = rnd.getFloat() > 0.3; /** @type {boolean} */ var isNan = !isInf && rnd.getFloat() > 0.4; /** @type {number} */ var mantissa = !isInf ? ((1 << 22) | (Math.abs(rnd.getInt()) & mantissaMask)) : 0; /** @type {number} */ var exp = !isNan && !isInf ? (Math.abs(rnd.getInt()) & 0x7f) : 0xff; /** @type {number} */ var sign = Math.abs(rnd.getInt()) & 0x1; /** @type {number} */ var value = (sign << 31) | (exp << 23) | mantissa; // Convert int to float. var view = new DataView(new ArrayBuffer(4)); view.setInt32(0, value, true); value = view.getFloat32(0, true); assertMsgOptions(tcuFloat.newFloat32(value).isInf() === isInf && tcuFloat.newFloat32(value).isNaN() === isNan, 'Assert error.', false, true); values[0].push(value); } return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.IsinfCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; if (precision === gluShaderUtil.precision.PRECISION_HIGHP) { for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref = tcuFloat.newFloat32(in0).isInf() ? 1 : 0; if (out0 !== ref) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref; return false; } } } else { for (var compNdx = 0; compNdx < scalarSize; compNdx++) { out0 = outputs[0][compNdx]; if (out0 !== 0 && out0 !== 1) { this.m_failMsg += 'Expected [' + compNdx + '] = 0 / 1'; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType * @param {boolean} outIsSigned */ es3fShaderCommonFunctionTests.FloatBitsToUintIntCase = function(baseType, precision, shaderType, outIsSigned) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), outIsSigned ? 'floatBitsToInt' : 'floatBitsToUint', shaderType); /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(baseType); /** @type {gluShaderUtil.DataType} */ var intType = outIsSigned ? (vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT) : (vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.UINT, vecSize) : gluShaderUtil.DataType.UINT); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(intType, gluShaderUtil.precision.PRECISION_HIGHP))); this.m_spec.source = outIsSigned ? 'out0 = floatBitsToInt(in0);' : 'out0 = floatBitsToUint(in0);'; }; es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype.constructor = es3fShaderCommonFunctionTests.FloatBitsToUintIntCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype.getInputValues = function(numValues) { /** @type {Array} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0x2790a); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], numValues * scalarSize); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var refOut0; /** @type {number} */ var ulpDiff; for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; // Convert int to uint because ref out is in uint format. var view = new DataView(new ArrayBuffer(4)); view.setInt32(0, out0, true); out0 = view.getUint32(0, true); refOut0 = tcuFloat.newFloat32(in0).bits(); ulpDiff = Math.abs(out0 - refOut0); if (ulpDiff > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + refOut0 + ' with threshold ' + maxUlpDiff + ', got diff ' + ulpDiff; return false; } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.FloatBitsToUintIntCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.FloatBitsToIntCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.call(this, baseType, precision, shaderType, true); }; es3fShaderCommonFunctionTests.FloatBitsToIntCase.prototype = Object.create(es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype); es3fShaderCommonFunctionTests.FloatBitsToIntCase.prototype.constructor = es3fShaderCommonFunctionTests.FloatBitsToIntCase; /** * @constructor * @extends {es3fShaderCommonFunctionTests.FloatBitsToUintIntCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.FloatBitsToUintCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.call(this, baseType, precision, shaderType, false); }; es3fShaderCommonFunctionTests.FloatBitsToUintCase.prototype = Object.create(es3fShaderCommonFunctionTests.FloatBitsToUintIntCase.prototype); es3fShaderCommonFunctionTests.FloatBitsToUintCase.prototype.constructor = es3fShaderCommonFunctionTests.FloatBitsToUintCase; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.BitsToFloatCase = function(baseType, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, gluShaderUtil.precision.PRECISION_HIGHP, shaderType), gluShaderUtil.isDataTypeIntOrIVec(baseType) ? 'intBitsToFloat' : 'uintBitsToFloat', shaderType); /** @type {boolean} */ var inIsSigned = gluShaderUtil.isDataTypeIntOrIVec(baseType); /** @type {number} */ var vecSize = gluShaderUtil.getDataTypeScalarSize(baseType); /** @type {gluShaderUtil.DataType} */ var floatType = vecSize > 1 ? gluShaderUtil.getDataTypeFloatVec(vecSize) : gluShaderUtil.DataType.FLOAT; this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, gluShaderUtil.precision.PRECISION_HIGHP))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(floatType, gluShaderUtil.precision.PRECISION_HIGHP))); this.m_spec.source = inIsSigned ? 'out0 = intBitsToFloat(in0);' : 'out0 = uintBitsToFloat(in0);'; }; es3fShaderCommonFunctionTests.BitsToFloatCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.BitsToFloatCase.prototype.constructor = es3fShaderCommonFunctionTests.BitsToFloatCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.BitsToFloatCase.prototype.getInputValues = function(numValues) { /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xbbb225); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array} */ var range = [-1e8, 1e8]; /** @type {Array>} */ var values = []; values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, range[0], range[1], numValues * scalarSize); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.BitsToFloatCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var maxUlpDiff = 0; /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ulpDiff; /** @type {number} */ var refOut0; for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; // Convert int to float var view = new DataView(new ArrayBuffer(4)); view.setInt32(0, in0, true); in0 = view.getFloat32(0, true); ulpDiff = es3fShaderCommonFunctionTests.getUlpDiff(in0, out0); if (ulpDiff > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + in0 + ' with ULP threshold ' + maxUlpDiff + ', got ULP diff ' + ulpDiff; return false; } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.FloorCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'floor', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = floor(in0);'; }; es3fShaderCommonFunctionTests.FloorCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.FloorCase.prototype.constructor = es3fShaderCommonFunctionTests.FloorCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.FloorCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; // Random cases. values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], numValues * scalarSize); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.FloorCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; /** @type {number} */ var ulpDiff; if (precision === gluShaderUtil.precision.PRECISION_HIGHP || precision === gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref = Math.floor(in0); ulpDiff = es3fShaderCommonFunctionTests.getUlpDiff(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var minRes = Math.floor(in0 - eps); /** @type {number} */ var maxRes = Math.floor(in0 + eps); /** @type {boolean} */ var anyOk = false; for (var roundedVal = minRes; roundedVal <= maxRes; roundedVal++) { ulpDiff = es3fShaderCommonFunctionTests.getUlpDiff(out0, roundedVal); if (ulpDiff <= maxUlpDiff) { anyOk = true; break; } } if (!anyOk) { this.m_failMsg += 'Expected [' + compNdx + '] = [' + minRes + ', ' + maxRes + '] with ULP threshold ' + maxUlpDiff; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.TruncCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'trunc', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = trunc(in0);'; }; es3fShaderCommonFunctionTests.TruncCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.TruncCase.prototype.constructor = es3fShaderCommonFunctionTests.TruncCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.TruncCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array} */ var specialCases = [0.0, -0.0, -0.9, 0.9, 1.0, -1.0]; /** @type {Array>} */ var values = []; values[0] = []; // Special cases for (var caseNdx = 0; caseNdx < specialCases.length; caseNdx++) for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) values[0].push(specialCases[caseNdx]); // Random cases. values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], (numValues - specialCases.length) * scalarSize)); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.TruncCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; /** @type {number} */ var ulpDiff; if (precision === gluShaderUtil.precision.PRECISION_HIGHP || precision === gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {boolean} */ var isNeg = tcuFloat.newFloat32(in0).sign() < 0; ref = isNeg ? (-Math.floor(-in0)) : Math.floor(in0); // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero. ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var minRes = Math.trunc(in0 - eps); /** @type {number} */ var maxRes = Math.trunc(in0 + eps); /** @type {boolean} */ var anyOk = false; for (var roundedVal = minRes; roundedVal <= maxRes; roundedVal++) { ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, roundedVal); if (ulpDiff <= maxUlpDiff) { anyOk = true; break; } } if (!anyOk) { this.m_failMsg += 'Expected [' + compNdx + '] = [' + minRes + ', ' + maxRes + '] with ULP threshold ' + maxUlpDiff; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.RoundCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'round', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = round(in0);'; }; es3fShaderCommonFunctionTests.RoundCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.RoundCase.prototype.constructor = es3fShaderCommonFunctionTests.RoundCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.RoundCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var numSpecialCases = 0; /** @type {Array>} */ var values = []; values[0] = [] // Special cases. if (precision === gluShaderUtil.precision.PRECISION_LOWP) { assertMsgOptions(numValues >= 10, 'Sample too small.', false, true); for (var ndx = 0; ndx < 10; ndx++) { /** @type {number} */ var v = deMath.clamp(ndx - 5.5, ranges[precision][0], ranges[precision][1]); for (var iter = 1; iter <= scalarSize; iter++) values[0].push(v); numSpecialCases += 1; } } // Random cases. values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], (numValues - numSpecialCases) * scalarSize)); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.RoundCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {boolean} */ var hasZeroSign = es3fShaderCommonFunctionTests.supportsSignedZero(precision); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ulpDiff; if (precision === gluShaderUtil.precision.PRECISION_HIGHP || precision === gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; if ((in0 - Math.floor(in0)) === 0.5) { /** @type {number} */ var ref0 = Math.floor(in0); /** @type {number} */ var ref1 = Math.ceil(in0); /** @type {number} */ var ulpDiff0 = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(out0, ref0) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref0); /** @type {number} */ var ulpDiff1 = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(out0, ref1) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref1); if (ulpDiff0 > 0 && ulpDiff1 > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref0 + ' or ' + ref1 + ', got ULP diff ' + Math.min(ulpDiff0, ulpDiff1); return false; } } else { // Require exact result /** @type {number} */ var ref = es3fShaderCommonFunctionTests.roundEven(in0); ulpDiff = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(out0, ref) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var minRes = Math.floor(es3fShaderCommonFunctionTests.roundEven(in0 - eps)); /** @type {number} */ var maxRes = Math.floor(es3fShaderCommonFunctionTests.roundEven(in0 + eps)); /** @type {boolean} */ var anyOk = false; for (var roundedVal = minRes; roundedVal <= maxRes; roundedVal++) { ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, roundedVal); if (ulpDiff <= maxUlpDiff) { anyOk = true; break; } } if (!anyOk) { this.m_failMsg += 'Expected [' + compNdx + '] = [' + minRes + ', ' + maxRes + '] with ULP threshold ' + maxUlpDiff; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.CeilCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'ceil', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = ceil(in0);'; }; es3fShaderCommonFunctionTests.CeilCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.CeilCase.prototype.constructor = es3fShaderCommonFunctionTests.CeilCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.CeilCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {Array>} */ var values = []; // Random cases. values[0] = es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], numValues * scalarSize); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]); return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.CeilCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {boolean} */ var hasZeroSign = es3fShaderCommonFunctionTests.supportsSignedZero(precision); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; /** @type {number} */ var ulpDiff; if (precision === gluShaderUtil.precision.PRECISION_HIGHP || precision === gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref = Math.ceil(in0); ulpDiff = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(out0, ref) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; /** @type {number} */ var minRes = Math.ceil(in0 - eps); /** @type {number} */ var maxRes = Math.ceil(in0 + eps); /** @type {boolean} */ var anyOk = false; for (var roundedVal = minRes; roundedVal <= maxRes; roundedVal++) { ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, roundedVal); if (ulpDiff <= maxUlpDiff) { anyOk = true; break; } } if (!anyOk & deMath.deInRange32(0, minRes, maxRes)) { ulpDiff = Math.abs(Math.floor(tcuFloat.newFloat32(out0).bits()) - 0x80000000); anyOk = ulpDiff <= maxUlpDiff; } if (!anyOk) { this.m_failMsg += 'Expected [' + compNdx + '] = [' + minRes + ', ' + maxRes + '] with ULP threshold ' + maxUlpDiff; return false; } } } return true; }; /** * @constructor * @extends {es3fShaderCommonFunctionTests.CommonFunctionCase} * @param {gluShaderUtil.DataType} baseType * @param {gluShaderUtil.precision} precision * @param {gluShaderProgram.shaderType} shaderType */ es3fShaderCommonFunctionTests.FractCase = function(baseType, precision, shaderType) { es3fShaderCommonFunctionTests.CommonFunctionCase.call(this, es3fShaderCommonFunctionTests.getCommonFuncCaseName(baseType, precision, shaderType), 'fract', shaderType); this.m_spec.inputs.push(new glsShaderExecUtil.Symbol('in0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.outputs.push(new glsShaderExecUtil.Symbol('out0', gluVarType.newTypeBasic(baseType, precision))); this.m_spec.source = 'out0 = fract(in0);'; }; es3fShaderCommonFunctionTests.FractCase.prototype = Object.create(es3fShaderCommonFunctionTests.CommonFunctionCase.prototype); es3fShaderCommonFunctionTests.FractCase.prototype.constructor = es3fShaderCommonFunctionTests.FractCase; /** * @param {number} numValues * @return {*} */ es3fShaderCommonFunctionTests.FractCase.prototype.getInputValues = function(numValues) { /** @type {Array>} */ var ranges = [ [-2.0, 2.0], // lowp [-1e3, 1e3], // mediump [-1e7, 1e7] // highp ]; /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name) ^ 0xac23f); /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var numSpecialCases = 0; /** @type {Array>} */ var values = []; values[0] = []; // Special cases. if (precision !== gluShaderUtil.precision.PRECISION_LOWP) { assertMsgOptions(numValues >= 10, 'Sample too small.', false, true); for (var ndx = 0; ndx < 10; ndx++) { /** @type {number} */ var v = deMath.clamp(ndx - 5.5, ranges[precision][0], ranges[precision][1]); for (var scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) { values[0].push(v); } numSpecialCases += 1; } } // Random cases. values[0] = values[0].concat(es3fShaderCommonFunctionTests.fillRandomScalars(es3fShaderCommonFunctionTests.Types.FLOAT, rnd, ranges[precision][0], ranges[precision][1], (numValues - numSpecialCases) * scalarSize)); // If precision is mediump, make sure values can be represented in fp16 exactly if (precision === gluShaderUtil.precision.PRECISION_MEDIUMP) es3fShaderCommonFunctionTests.vecToFloat16(values[0]) return values; }; /** * @param {*} inputs * @param {*} outputs * @return {boolean} */ es3fShaderCommonFunctionTests.FractCase.prototype.compare = function(inputs, outputs) { /** @type {gluShaderUtil.DataType} */ var type = this.m_spec.inputs[0].varType.getBasicType(); /** @type {gluShaderUtil.precision} */ var precision = this.m_spec.inputs[0].varType.getPrecision(); /** @type {boolean} */ var hasZeroSign = es3fShaderCommonFunctionTests.supportsSignedZero(precision); /** @type {number} */ var scalarSize = gluShaderUtil.getDataTypeScalarSize(type); /** @type {number} */ var in0; /** @type {number} */ var out0; /** @type {number} */ var ref; /** @type {number} */ var ulpDiff; if (precision === gluShaderUtil.precision.PRECISION_HIGHP || precision === gluShaderUtil.precision.PRECISION_MEDIUMP) { // Require exact result. for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; ref = in0 - Math.floor(in0); ulpDiff = hasZeroSign ? es3fShaderCommonFunctionTests.getUlpDiff(out0, ref) : es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > 0) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ', got ULP diff ' + ulpDiff; return false; } } } else { /** @type {number} */ var mantissaBits = es3fShaderCommonFunctionTests.getMinMantissaBits(precision); /** @type {number} */ var eps = es3fShaderCommonFunctionTests.getEpsFromBits(1.0, mantissaBits); // epsilon for rounding bounds for (var compNdx = 0; compNdx < scalarSize; compNdx++) { in0 = inputs[0][compNdx]; out0 = outputs[0][compNdx]; if (Math.floor(in0 - eps) == Math.floor(in0 + eps)) { ref = in0 - Math.floor(in0); /** @type {number} */ var bitsLost = es3fShaderCommonFunctionTests.numBitsLostInOp(in0, ref); /** @type {number} */ var maxUlpDiff = es3fShaderCommonFunctionTests.getMaxUlpDiffFromBits(Math.max(0, mantissaBits - bitsLost)); // ULP diff for rounded integer value. ulpDiff = es3fShaderCommonFunctionTests.getUlpDiffIgnoreZeroSign(out0, ref); if (ulpDiff > maxUlpDiff) { this.m_failMsg += 'Expected [' + compNdx + '] = ' + ref + ' with ULP threshold ' + maxUlpDiff + ', got diff ' + ulpDiff; return false; } } else { if (out0 >= 1.0) { this.m_failMsg += 'Expected [' + compNdx + '] < 1.0'; return false; } } } } return true; }; /** * @constructor * @extends {tcuTestCase.DeqpTest} */ es3fShaderCommonFunctionTests.ShaderCommonFunctionTests = function() { tcuTestCase.DeqpTest.call(this, 'common', 'Common function tests'); }; es3fShaderCommonFunctionTests.ShaderCommonFunctionTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype); es3fShaderCommonFunctionTests.ShaderCommonFunctionTests.prototype.constructor = es3fShaderCommonFunctionTests.ShaderCommonFunctionTests; /** * @param {tcuTestCase.DeqpTest} parent * @param {es3fShaderCommonFunctionTests.TestClass} testClass * @param {string} functionName * @param {boolean} floatTypes * @param {boolean} intTypes * @param {boolean} uintTypes */ es3fShaderCommonFunctionTests.addFunctionCases = function(parent, testClass, functionName, floatTypes, intTypes, uintTypes) { /** @type {tcuTestCase.DeqpTest} */ var group = tcuTestCase.newTest(functionName, functionName); parent.addChild(group); /** @type {Array} */ var scalarTypes = [ gluShaderUtil.DataType.FLOAT, gluShaderUtil.DataType.INT, gluShaderUtil.DataType.UINT ]; for (var scalarTypeNdx = 0; scalarTypeNdx < scalarTypes.length; scalarTypeNdx++) { /** @type {gluShaderUtil.DataType} */ var scalarType = scalarTypes[scalarTypeNdx]; if ((!floatTypes && scalarType == gluShaderUtil.DataType.FLOAT) || (!intTypes && scalarType == gluShaderUtil.DataType.INT) || (!uintTypes && scalarType == gluShaderUtil.DataType.UINT)) continue; for (var vecSize = 1; vecSize <= 4; vecSize++) for (var prec = gluShaderUtil.precision.PRECISION_LOWP; prec <= gluShaderUtil.precision.PRECISION_HIGHP; prec++) for (var shaderType = gluShaderProgram.shaderType.VERTEX; shaderType <= gluShaderProgram.shaderType.FRAGMENT; shaderType++) group.addChild(new testClass(/** @type {gluShaderUtil.DataType} */ (scalarType + vecSize - 1), prec, shaderType)); } }; es3fShaderCommonFunctionTests.ShaderCommonFunctionTests.prototype.init = function() { var testGroup = tcuTestCase.runner.testCases; es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.AbsCase, 'abs', true, true, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.SignCase, 'sign', true, true, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.FloorCase, 'floor', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.TruncCase, 'trunc', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.RoundCase, 'round', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.RoundEvenCase, 'roundeven', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.CeilCase, 'ceil', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.FractCase, 'fract', true, false, false); // mod es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.ModfCase, 'modf', true, false, false); // min, max, clamp, mix, step, smoothstep es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.IsnanCase, 'isnan', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.IsinfCase, 'isinf', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.FloatBitsToIntCase, 'floatbitstoint', true, false, false); es3fShaderCommonFunctionTests.addFunctionCases(testGroup, es3fShaderCommonFunctionTests.FloatBitsToUintCase, 'floatbitstouint', true, false, false); // (u)intBitsToFloat() /** @type {tcuTestCase.DeqpTest} */ var intGroup = tcuTestCase.newTest('intbitstofloat', 'intBitsToFloat() Tests'); /** @type {tcuTestCase.DeqpTest} */ var uintGroup = tcuTestCase.newTest('uintbitstofloat', 'uintBitsToFloat() Tests'); testGroup.addChild(intGroup); testGroup.addChild(uintGroup); /** @type {Array} */ var shaderTypes = [ gluShaderProgram.shaderType.VERTEX, gluShaderProgram.shaderType.FRAGMENT ]; for (var vecSize = 1; vecSize < 4; vecSize++) { /** @type {gluShaderUtil.DataType} */ var intType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.INT, vecSize) : gluShaderUtil.DataType.INT; /** @type {gluShaderUtil.DataType} */ var uintType = vecSize > 1 ? gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.UINT, vecSize) : gluShaderUtil.DataType.UINT; for (var shaderType in shaderTypes) { intGroup.addChild(new es3fShaderCommonFunctionTests.BitsToFloatCase(intType, shaderTypes[shaderType])); uintGroup.addChild(new es3fShaderCommonFunctionTests.BitsToFloatCase(uintType, shaderTypes[shaderType])); } } }; /** * Run test * @param {WebGL2RenderingContext} context */ es3fShaderCommonFunctionTests.run = function(context) { gl = context; //Set up Test Root parameters var state = tcuTestCase.runner; state.setRoot(new es3fShaderCommonFunctionTests.ShaderCommonFunctionTests()); //Set up name and description of this test series. setCurrentTestName(state.testCases.fullName()); description(state.testCases.getDescription()); try { //Run test cases tcuTestCase.runTestCases(); } catch (err) { testFailedOptions('Failed to es3fShaderCommonFunctionTests.run tests', false); tcuTestCase.runner.terminate(); } }; });