diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js | 2642 |
1 files changed, 2642 insertions, 0 deletions
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<number>} bottomLeft + * @param {Array<number>} topRight + * @return {Array<number>} + */ +glsTextureTestUtil.computeQuadTexCoord2D = function(bottomLeft, topRight) { + var dst = []; + dst.length = 4 * 2; + + dst[0] = bottomLeft[0]; dst[1] = bottomLeft[1]; + dst[2] = bottomLeft[0]; dst[3] = topRight[1]; + dst[4] = topRight[0]; dst[5] = bottomLeft[1]; + dst[6] = topRight[0]; dst[7] = topRight[1]; + + return dst; +}; + +/** + * @param {tcuTexture.CubeFace} face + * @return {Array<number>} + */ +glsTextureTestUtil.computeQuadTexCoordCube = function(face) { + var texCoordNegX = [ + -1, 1, -1, + -1, -1, -1, + -1, 1, 1, + -1, -1, 1 + ]; + var texCoordPosX = [ + +1, 1, 1, + +1, -1, 1, + +1, 1, -1, + +1, -1, -1 + ]; + var texCoordNegY = [ + -1, -1, 1, + -1, -1, -1, + 1, -1, 1, + 1, -1, -1 + ]; + var texCoordPosY = [ + -1, +1, -1, + -1, +1, 1, + 1, +1, -1, + 1, +1, 1 + ]; + var texCoordNegZ = [ + 1, 1, -1, + 1, -1, -1, + -1, 1, -1, + -1, -1, -1 + ]; + var texCoordPosZ = [ + -1, 1, +1, + -1, -1, +1, + 1, 1, +1, + 1, -1, +1 + ]; + + switch (face) { + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: return texCoordNegX; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: return texCoordPosX; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: return texCoordNegY; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: return texCoordPosY; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: return texCoordNegZ; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: return texCoordPosZ; + } + throw new Error('Unrecognized face ' + face); +}; + +/** + * @param {tcuTexture.CubeFace} face + * @param {Array<number>} bottomLeft + * @param {Array<number>} topRight + * @return {Array<number>} + */ +glsTextureTestUtil.computeQuadTexCoordCubeFace = function(face, bottomLeft, topRight) { + var dst = []; + /** @type {number} */ var sRow = 0; + /** @type {number} */ var tRow = 0; + /** @type {number} */ var mRow = 0; + /** @type {number} */ var sSign = 1.0; + /** @type {number} */ var tSign = 1.0; + /** @type {number} */ var mSign = 1.0; + + switch (face) { + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0; tSign = -1.0; break; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0; tSign = -1.0; break; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0; tSign = -1.0; break; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0; sSign = -1.0; tSign = -1.0; break; + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0; break; + default: + throw new Error('Invalid cube face specified.'); + } + + dst[0 + mRow] = mSign; + dst[3 + mRow] = mSign; + dst[6 + mRow] = mSign; + dst[9 + mRow] = mSign; + + dst[0 + sRow] = sSign * bottomLeft[0]; + dst[3 + sRow] = sSign * bottomLeft[0]; + dst[6 + sRow] = sSign * topRight[0]; + dst[9 + sRow] = sSign * topRight[0]; + + dst[0 + tRow] = tSign * bottomLeft[1]; + dst[3 + tRow] = tSign * topRight[1]; + dst[6 + tRow] = tSign * bottomLeft[1]; + dst[9 + tRow] = tSign * topRight[1]; + + return dst; +}; + +/** + * @param {number} layerNdx + * @param {Array<number>} bottomLeft + * @param {Array<number>} topRight + * @return {Array<number>} + */ +glsTextureTestUtil.computeQuadTexCoord2DArray = function(layerNdx, bottomLeft, topRight) { + var dst = []; + dst.length = 4 * 3; + + dst[0] = bottomLeft[0]; dst[1] = bottomLeft[1]; dst[2] = layerNdx; + dst[3] = bottomLeft[0]; dst[4] = topRight[1]; dst[5] = layerNdx; + dst[6] = topRight[0]; dst[7] = bottomLeft[1]; dst[8] = layerNdx; + dst[9] = topRight[0]; dst[10] = topRight[1]; dst[11] = layerNdx; + + return dst; +}; + +/** + * @param {Array<number>} a + * @param {Array<number>} b + * @param {Array<number>} c + * @return {Array<number>} a + (b - a) * c + */ +glsTextureTestUtil.selectCoords = function(a, b, c) { + var x1 = deMath.subtract(b, a); + var x2 = deMath.multiply(x1, c); + var x3 = deMath.add(a, x2); + return x3; +}; + +/** + * @param {Array<number>} p0 + * @param {Array<number>} p1 + * @param {Array<number>} dirSwz + * @return {Array<number>} + */ +glsTextureTestUtil.computeQuadTexCoord3D = function(p0, p1, dirSwz) { + var dst = []; + dst.length = 4 * 3; + + var f0 = deMath.swizzle(([0, 0, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]); + var f1 = deMath.swizzle(([0, 1, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]); + var f2 = deMath.swizzle(([1, 0, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]); + var f3 = deMath.swizzle(([1, 1, 0]), [dirSwz[0], dirSwz[1], dirSwz[2]]); + + var v0 = glsTextureTestUtil.selectCoords(p0, p1, f0); + var v1 = glsTextureTestUtil.selectCoords(p0, p1, f1); + var v2 = glsTextureTestUtil.selectCoords(p0, p1, f2); + var v3 = glsTextureTestUtil.selectCoords(p0, p1, f3); + + dst[0] = v0[0]; dst[1] = v0[1]; dst[2] = v0[2]; + dst[3] = v1[0]; dst[4] = v1[1]; dst[5] = v1[2]; + dst[6] = v2[0]; dst[7] = v2[1]; dst[8] = v2[2]; + dst[9] = v3[0]; dst[10] = v3[1]; dst[11] = v3[2]; + + return dst; +}; + +/** + * @enum + */ +glsTextureTestUtil.programType = { + PROGRAM_2D_FLOAT: 0, + PROGRAM_2D_INT: 1, + PROGRAM_2D_UINT: 2, + PROGRAM_2D_SHADOW: 3, + + PROGRAM_2D_FLOAT_BIAS: 4, + PROGRAM_2D_INT_BIAS: 5, + PROGRAM_2D_UINT_BIAS: 6, + PROGRAM_2D_SHADOW_BIAS: 7, + + PROGRAM_1D_FLOAT: 8, + PROGRAM_1D_INT: 9, + PROGRAM_1D_UINT: 10, + PROGRAM_1D_SHADOW: 11, + + PROGRAM_1D_FLOAT_BIAS: 12, + PROGRAM_1D_INT_BIAS: 13, + PROGRAM_1D_UINT_BIAS: 14, + PROGRAM_1D_SHADOW_BIAS: 15, + + PROGRAM_CUBE_FLOAT: 16, + PROGRAM_CUBE_INT: 17, + PROGRAM_CUBE_UINT: 18, + PROGRAM_CUBE_SHADOW: 19, + + PROGRAM_CUBE_FLOAT_BIAS: 20, + PROGRAM_CUBE_INT_BIAS: 21, + PROGRAM_CUBE_UINT_BIAS: 22, + PROGRAM_CUBE_SHADOW_BIAS: 23, + + PROGRAM_1D_ARRAY_FLOAT: 24, + PROGRAM_1D_ARRAY_INT: 25, + PROGRAM_1D_ARRAY_UINT: 26, + PROGRAM_1D_ARRAY_SHADOW: 27, + + PROGRAM_2D_ARRAY_FLOAT: 28, + PROGRAM_2D_ARRAY_INT: 29, + PROGRAM_2D_ARRAY_UINT: 30, + PROGRAM_2D_ARRAY_SHADOW: 31, + + PROGRAM_3D_FLOAT: 32, + PROGRAM_3D_INT: 33, + PROGRAM_3D_UINT: 34, + + PROGRAM_3D_FLOAT_BIAS: 35, + PROGRAM_3D_INT_BIAS: 36, + PROGRAM_3D_UINT_BIAS: 37, + + PROGRAM_CUBE_ARRAY_FLOAT: 38, + PROGRAM_CUBE_ARRAY_INT: 39, + PROGRAM_CUBE_ARRAY_UINT: 40, + PROGRAM_CUBE_ARRAY_SHADOW: 41, + + PROGRAM_BUFFER_FLOAT: 42, + PROGRAM_BUFFER_INT: 43, + PROGRAM_BUFFER_UINT: 44 +}; + +/** + * @constructor + * @param {string} version GL version + * @param {gluShaderUtil.precision} precision + */ +glsTextureTestUtil.ProgramLibrary = function(version, precision) { + this.m_glslVersion = version; + this.m_texCoordPrecision = precision; +}; + +/** + * @param {glsTextureTestUtil.programType} program + * @return {gluShaderProgram.ShaderProgram} + */ +glsTextureTestUtil.ProgramLibrary.prototype.getProgram = function(program) { + /* TODO: Implement */ + // if (m_programs.find(program) != m_programs.end()) + // return m_programs[program]; // Return from cache. + + var vertShaderTemplate = + '${VTX_HEADER}' + + '${VTX_IN} highp vec4 a_position;\n' + + '${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n' + + '${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n' + + '\n' + + 'void main (void)\n' + + ' {\n' + + ' gl_Position = a_position;\n' + + ' v_texCoord = a_texCoord;\n' + + '}\n'; + var fragShaderTemplate = + '${FRAG_HEADER}' + + '${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n' + + 'uniform ${PRECISION} float u_bias;\n' + + 'uniform ${PRECISION} float u_ref;\n' + + 'uniform ${PRECISION} vec4 u_colorScale;\n' + + 'uniform ${PRECISION} vec4 u_colorBias;\n' + + 'uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n' + + '\n' + + 'void main (void)\n' + + ' {\n' + + ' ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n' + + '}\n'; + + var params = []; + + var isCube = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT, glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS); + var isArray = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW) || + deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW); + + var is1D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS) || + deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW) || + deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT, glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT); + + var is2D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS) || + deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW); + + var is3D = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_3D_FLOAT, glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS); + var isCubeArray = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT, glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW); + var isBuffer = deMath.deInRange32(program, glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT, glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT); + + if (this.m_glslVersion === '100 es') { + params['FRAG_HEADER'] = ''; + params['VTX_HEADER'] = ''; + params['VTX_IN'] = 'attribute'; + params['VTX_OUT'] = 'varying'; + params['FRAG_IN'] = 'varying'; + params['FRAG_COLOR'] = 'gl_FragColor'; + } else if (this.m_glslVersion === '300 es' || this.m_glslVersion === '310 es' || this.m_glslVersion === '330 es') { + var ext = null; + + // if (isCubeArray && glu::glslVersionIsES(m_glslVersion)) + // ext = "gl.EXT_texture_cube_map_array"; + // else if (isBuffer && glu::glslVersionIsES(m_glslVersion)) + // ext = "gl.EXT_texture_buffer"; + + var extension = ''; + if (ext) + extension = '\n#extension ' + ext + ' : require'; + + params['FRAG_HEADER'] = '#version ' + this.m_glslVersion + extension + '\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n'; + params['VTX_HEADER'] = '#version ' + this.m_glslVersion + '\n'; + params['VTX_IN'] = 'in'; + params['VTX_OUT'] = 'out'; + params['FRAG_IN'] = 'in'; + params['FRAG_COLOR'] = 'dEQP_FragColor'; + } else + throw new Error('Unsupported version: ' + this.m_glslVersion); + + params['PRECISION'] = gluShaderUtil.getPrecisionName(this.m_texCoordPrecision); + + if (isCubeArray) + params['TEXCOORD_TYPE'] = 'vec4'; + else if (isCube || (is2D && isArray) || is3D) + params['TEXCOORD_TYPE'] = 'vec3'; + else if ((is1D && isArray) || is2D) + params['TEXCOORD_TYPE'] = 'vec2'; + else if (is1D) + params['TEXCOORD_TYPE'] = 'float'; + else + DE_ASSERT(false); + + var sampler = null; + var lookup = null; + + if (this.m_glslVersion === '300 es' || this.m_glslVersion === '310 es' || this.m_glslVersion === '330 es') { + switch (program) { + case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT: sampler = 'sampler2D'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_INT: sampler = 'isampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_UINT: sampler = 'usampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_SHADOW: sampler = 'sampler2DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS: sampler = 'sampler2D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_INT_BIAS: sampler = 'isampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS: sampler = 'usampler2D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_SHADOW_BIAS: sampler = 'sampler2DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_FLOAT: sampler = 'sampler1D'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_INT: sampler = 'isampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_UINT: sampler = 'usampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_SHADOW: sampler = 'sampler1DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_FLOAT_BIAS: sampler = 'sampler1D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_INT_BIAS: sampler = 'isampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS: sampler = 'usampler1D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_SHADOW_BIAS: sampler = 'sampler1DShadow'; lookup = 'vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT: sampler = 'samplerCube'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_INT: sampler = 'isamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_UINT: sampler = 'usamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW: sampler = 'samplerCubeShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS: sampler = 'samplerCube'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_INT_BIAS: sampler = 'isamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_UINT_BIAS: sampler = 'usamplerCube'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS: sampler = 'samplerCubeShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT: sampler = 'sampler2DArray'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_INT: sampler = 'isampler2DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_UINT: sampler = 'usampler2DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW: sampler = 'sampler2DArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_FLOAT: sampler = 'sampler3D'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_INT: sampler = 'isampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_UINT: sampler = ' usampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_FLOAT_BIAS: sampler = 'sampler3D'; lookup = 'texture(u_sampler, v_texCoord, u_bias)'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_INT_BIAS: sampler = 'isampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS: sampler = ' usampler3D'; lookup = 'vec4(texture(u_sampler, v_texCoord, u_bias))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT: sampler = 'samplerCubeArray'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_INT: sampler = 'isamplerCubeArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_UINT: sampler = 'usamplerCubeArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW: sampler = 'samplerCubeArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT: sampler = 'sampler1DArray'; lookup = 'texture(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_INT: sampler = 'isampler1DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_UINT: sampler = 'usampler1DArray'; lookup = 'vec4(texture(u_sampler, v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW: sampler = 'sampler1DArrayShadow'; lookup = 'vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)'; break; + case glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT: sampler = 'samplerBuffer'; lookup = 'texelFetch(u_sampler, int(v_texCoord))'; break; + case glsTextureTestUtil.programType.PROGRAM_BUFFER_INT: sampler = 'isamplerBuffer'; lookup = 'vec4(texelFetch(u_sampler, int(v_texCoord)))'; break; + case glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT: sampler = 'usamplerBuffer'; lookup = 'vec4(texelFetch(u_sampler, int(v_texCoord)))'; break; + default: + DE_ASSERT(false); + } + } else if (this.m_glslVersion === '100 es') { + sampler = isCube ? 'samplerCube' : 'sampler2D'; + + switch (program) { + case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT: lookup = 'texture2D(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS: lookup = 'texture2D(u_sampler, v_texCoord, u_bias)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT: lookup = 'textureCube(u_sampler, v_texCoord)'; break; + case glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS: lookup = 'textureCube(u_sampler, v_texCoord, u_bias)'; break; + default: + DE_ASSERT(false); + } + } else + DE_ASSERT(!'Unsupported version'); + + params['SAMPLER_TYPE'] = sampler; + params['LOOKUP'] = lookup; + + var vertSrc = tcuStringTemplate.specialize(vertShaderTemplate, params); + var fragSrc = tcuStringTemplate.specialize(fragShaderTemplate, params); + var progObj = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertSrc, fragSrc)); + // if (!progObj.isOk()) { + // // log << *progObj; + // testFailedOptions("Failed to create shader", true); + // } + + // try + // { + // m_programs[program] = progObj; + // } + // catch (...) + // { + // delete progObj; + // throw; + // } + + return progObj; +}; + +// public: +// glsTextureTestUtil.ProgramLibrary (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision); +// ~glsTextureTestUtil.ProgramLibrary (void); + +// glu::ShaderProgram* getProgram (Program program); +// void clear (void); + +// private: +// glsTextureTestUtil.ProgramLibrary (const glsTextureTestUtil.ProgramLibrary& other); +// glsTextureTestUtil.ProgramLibrary& operator= (const glsTextureTestUtil.ProgramLibrary& other); + +// const glu::RenderContext& m_context; +// tcu::TestContext& m_testCtx; +// glu::GLSLVersion m_glslVersion; +// glu::Precision m_texCoordPrecision; +// std::map<Program, glu::ShaderProgram*> m_programs; +// }; + +/** + * @constructor + * @param {string} version GL version + * @param {gluShaderUtil.precision} precision + */ +glsTextureTestUtil.TextureRenderer = function(version, precision) { + this.m_programLibrary = new glsTextureTestUtil.ProgramLibrary(version, precision); +}; + +/** + * @param {tcuPixelFormat.PixelFormat} format + * @return {Array<boolean>} + */ +glsTextureTestUtil.getCompareMask = function(format) { + return [ + format.redBits > 0, + format.greenBits > 0, + format.blueBits > 0, + format.alphaBits > 0 + ]; +}; + +/** + * @param {tcuPixelFormat.PixelFormat} format + * @return {Array<number>} + */ +glsTextureTestUtil.getBitsVec = function(format) { + return [ + format.redBits, + format.greenBits, + format.blueBits, + format.alphaBits + ]; +}; + +/** + * @param {number} texUnit + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.RenderParams} params + */ +glsTextureTestUtil.TextureRenderer.prototype.renderQuad = function(texUnit, texCoord, params) { + var wCoord = params.flags.projected ? params.w : [1, 1, 1, 1]; + var useBias = params.flags.use_bias; + var logUniforms = params.flags.log_uniforms; + + // Render quad with texture. + var position = [ + -1 * wCoord[0], -1 * wCoord[0], 0, wCoord[0], + -1 * wCoord[1], +1 * wCoord[1], 0, wCoord[1], + +1 * wCoord[2], -1 * wCoord[2], 0, wCoord[2], + +1 * wCoord[3], +1 * wCoord[3], 0, wCoord[3] + ]; + /** @const */ var indices = [0, 1, 2, 2, 1, 3]; + + /** @type {?glsTextureTestUtil.programType} */ var progSpec = null; + var numComps = 0; + if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_2D) { + numComps = 2; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_2D_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_2D_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_1D) { + numComps = 1; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_1D_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_1D_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_CUBE) { + numComps = 3; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW_BIAS : glsTextureTestUtil.programType.PROGRAM_CUBE_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_3D) { + numComps = 3; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_FLOAT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_INT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = useBias ? glsTextureTestUtil.programType.PROGRAM_3D_UINT_BIAS : glsTextureTestUtil.programType.PROGRAM_3D_UINT; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_2D_ARRAY) { + DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias. + + numComps = 3; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_2D_ARRAY_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_CUBE_ARRAY) { + DE_ASSERT(!useBias); + + numComps = 4; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_CUBE_ARRAY_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_1D_ARRAY) { + DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias. + + numComps = 2; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_UINT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW: progSpec = glsTextureTestUtil.programType.PROGRAM_1D_ARRAY_SHADOW; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else if (params.texType == glsTextureTestUtil.textureType.TEXTURETYPE_BUFFER) { + numComps = 1; + + switch (params.samplerType) { + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_FLOAT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_FLOAT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_INT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_INT; break; + case glsTextureTestUtil.samplerType.SAMPLERTYPE_FETCH_UINT: progSpec = glsTextureTestUtil.programType.PROGRAM_BUFFER_UINT; break; + default: throw new Error('Unrecognized sampler type:' + params.samplerType); + } + } else + throw new Error('Unrecognized texture type:' + params.texType); + + if (progSpec === null) + throw new Error('Could not find program specification'); + + var program = this.m_programLibrary.getProgram(progSpec); + + // \todo [2012-09-26 pyry] Move to glsTextureTestUtil.ProgramLibrary and log unique programs only(?) + /* TODO: Port logging + if (params.flags.log_programs) + log << *program; + */ + + // Program and uniforms. + var prog = program.getProgram(); + gl.useProgram(prog); + + var loc = gl.getUniformLocation(prog, 'u_sampler'); + gl.uniform1i(loc, texUnit); + // if (logUniforms) + // log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage; + + if (useBias) { + gl.uniform1f(gl.getUniformLocation(prog, 'u_bias'), params.bias); + // if (logUniforms) + // log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage; + } + + if (params.samplerType == glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW) { + gl.uniform1f(gl.getUniformLocation(prog, 'u_ref'), params.ref); + // if (logUniforms) + // log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage; + } + + gl.uniform4fv(gl.getUniformLocation(prog, 'u_colorScale'), params.colorScale); + gl.uniform4fv(gl.getUniformLocation(prog, 'u_colorBias'), params.colorBias); + + // if (logUniforms) + // { + // log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage; + // log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage; + // } + var vertexArrays = []; + + var posLoc = gl.getAttribLocation(prog, 'a_position'); + if (posLoc === -1) { + testFailedOptions("no location found for attribute 'a_position'", true); + } + var texLoc = gl.getAttribLocation(prog, 'a_texCoord'); + if (texLoc === -1) { + testFailedOptions("no location found for attribute 'a_texCoord'", true); + } + + vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, posLoc, 4, 4, position)); + vertexArrays.push(new gluDrawUtil.VertexArrayBinding(gl.FLOAT, texLoc, numComps, 4, texCoord)); + gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices)); +}; + +// public: +// glsTextureTestUtil.TextureRenderer (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision); +// ~glsTextureTestUtil.TextureRenderer (void); + +// void clear (void); //!< Frees allocated resources. Destructor will call clear() as well. + +// void renderQuad (int texUnit, const float* texCoord, TextureType texType); +// void renderQuad (int texUnit, const float* texCoord, const glsTextureTestUtil.RenderParams& params); + +// private: +// glsTextureTestUtil.TextureRenderer (const glsTextureTestUtil.TextureRenderer& other); +// glsTextureTestUtil.TextureRenderer& operator= (const glsTextureTestUtil.TextureRenderer& other); + +// const glu::RenderContext& m_renderCtx; +// tcu::TestContext& m_testCtx; +// glsTextureTestUtil.ProgramLibrary m_programLibrary; +// }; + +/** + * @constructor + * @param {tcuSurface.Surface} surface + * @param {tcuPixelFormat.PixelFormat=} colorFmt + * @param {number=} x + * @param {number=} y + * @param {number=} width + * @param {number=} height + */ +glsTextureTestUtil.SurfaceAccess = function(surface, colorFmt, x, y, width, height) { + this.m_surface = surface; + this.colorMask = undefined; /*TODO*/ + this.m_x = x || 0; + this.m_y = y || 0; + this.m_width = width || surface.getWidth(); + this.m_height = height || surface.getHeight(); +}; + +/** @return {number} */ +glsTextureTestUtil.SurfaceAccess.prototype.getWidth = function() { return this.m_width; }; +/** @return {number} */ +glsTextureTestUtil.SurfaceAccess.prototype.getHeight = function() { return this.m_height; }; + +/** + * @param {Array<number>} color + * @param {number} x + * @param {number} y + */ +glsTextureTestUtil.SurfaceAccess.prototype.setPixel = function(color, x, y) { + /* TODO: Apply color mask */ + var c = color; + for (var i = 0; i < c.length; i++) + c[i] = deMath.clamp(Math.round(color[i] * 255), 0, 255); + this.m_surface.setPixel(x, y, c); +}; + +/** + * @param {glsTextureTestUtil.lodMode} mode + * @param {number} dudx + * @param {number} dvdx + * @param {number} dwdx + * @param {number} dudy + * @param {number} dvdy + * @param {number} dwdy + * @return {number} + */ +glsTextureTestUtil.computeLodFromDerivates3D = function(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy) { + var p = 0; + switch (mode) { + case glsTextureTestUtil.lodMode.EXACT: + p = Math.max(Math.sqrt(dudx * dudx + dvdx * dvdx + dwdx * dwdx), Math.sqrt(dudy * dudy + dvdy * dvdy + dwdy * dwdy)); + break; + + case glsTextureTestUtil.lodMode.MIN_BOUND: + case glsTextureTestUtil.lodMode.MAX_BOUND: { + var mu = Math.max(Math.abs(dudx), Math.abs(dudy)); + var mv = Math.max(Math.abs(dvdx), Math.abs(dvdy)); + var mw = Math.max(Math.abs(dwdx), Math.abs(dwdy)); + + p = (mode == glsTextureTestUtil.lodMode.MIN_BOUND) ? Math.max(mu, mv, mw) : mu + mv + mw; + break; + } + + default: + DE_ASSERT(false); + } + + // Native dEQP uses 32-bit numbers. So here 64-bit floating numbers should be transformed into 32-bit ones to ensure the correctness of the result. + return deMath.toFloat32(Math.log(p)) * deMath.INV_LOG_2_FLOAT32; +}; + +/** + * @param {glsTextureTestUtil.lodMode} mode + * @param {Array<number>} dstSize + * @param {Array<number>} srcSize + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {Array<number>=} rq + * @return {number} + */ +glsTextureTestUtil.computeNonProjectedTriLod = function(mode, dstSize, srcSize, sq, tq, rq) { + var dux = (sq[2] - sq[0]) * srcSize[0]; + var duy = (sq[1] - sq[0]) * srcSize[0]; + var dvx = (tq[2] - tq[0]) * srcSize[1]; + var dvy = (tq[1] - tq[0]) * srcSize[1]; + var dwx = 0; + var dwy = 0; + if (rq) { + dwx = (rq[2] - rq[0]) * srcSize[2]; + dwy = (rq[1] - rq[0]) * srcSize[2]; + } + var dx = dstSize[0]; + var dy = dstSize[1]; + + return glsTextureTestUtil.computeLodFromDerivates3D(mode, dux / dx, dvx / dx, dwx / dx, duy / dy, dvy / dy, dwy / dy); +}; + +/** + * @param {Array<number>} v + * @param {number} x + * @param {number} y + * @return {number} + */ +glsTextureTestUtil.triangleInterpolate = function(v, x, y) { + return v[0] + (v[2] - v[0]) * x + (v[1] - v[0]) * y; +}; + +/** + * @param {Array<number>} s + * @param {Array<number>} w + * @param {number} wx + * @param {number} width + * @param {number} ny + * @return {number} + */ +glsTextureTestUtil.triDerivateX = function(s, w, wx, width, ny) { + var d = w[1] * w[2] * (width * (ny - 1) + wx) - w[0] * (w[2] * width * ny + w[1] * wx); + return (w[0] * w[1] * w[2] * width * (w[1] * (s[0] - s[2]) * (ny - 1) + ny * (w[2] * (s[1] - s[0]) + w[0] * (s[2] - s[1])))) / (d * d); +}; + +/** + * @param {Array<number>} s + * @param {Array<number>} w + * @param {number} wy + * @param {number} height + * @param {number} nx + * @return {number} + */ +glsTextureTestUtil.triDerivateY = function(s, w, wy, height, nx) { + var d = w[1] * w[2] * (height * (nx - 1) + wy) - w[0] * (w[1] * height * nx + w[2] * wy); + return (w[0] * w[1] * w[2] * height * (w[2] * (s[0] - s[1]) * (nx - 1) + nx * (w[0] * (s[1] - s[2]) + w[1] * (s[2] - s[0])))) / (d * d); +}; + +/** + * @param {(tcuTexture.Texture2DView|tcuTexture.Texture2DArrayView|tcuTexture.TextureCubeView)} src + * @param {glsTextureTestUtil.ReferenceParams} params + * @param {Array<number>} texCoord Texture coordinates + * @param {number} lod + * @return {Array<number>} sample + */ +glsTextureTestUtil.execSample = function(src, params, texCoord, lod) { + if (params.samplerType == glsTextureTestUtil.samplerType.SAMPLERTYPE_SHADOW) + return [src.sampleCompare(params.sampler, params.ref, texCoord, lod), 0, 0, 1]; + else + return src.sample(params.sampler, texCoord, lod); +}; + +/** + * @param {Array<number>} pixel + * @param {Array<number>} scale + * @param {Array<number>} bias + */ +glsTextureTestUtil.applyScaleAndBias = function(pixel, scale, bias) { + pixel[0] = pixel[0] * scale[0] + bias[0]; + pixel[1] = pixel[1] * scale[1] + bias[1]; + pixel[2] = pixel[2] * scale[2] + bias[2]; + pixel[3] = pixel[3] * scale[3] + bias[3]; +}; + +/** + * @param {Array<number>} pixel + * @param {Array<number>} scale + * @param {Array<number>} bias + */ +glsTextureTestUtil.deapplyScaleAndBias = function(pixel, scale, bias) { + pixel[0] = (pixel[0] - bias[0]) / scale[0]; + pixel[1] = (pixel[1] - bias[1]) / scale[1]; + pixel[2] = (pixel[2] - bias[2]) / scale[2]; + pixel[3] = (pixel[3] - bias[3]) / scale[3]; +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture2DView} src + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureProjected2D = function(dst, src, sq, tq, params) { + /** @type {number} */ var lodBias = params.flags.use_bias ? params.bias : 0.0; + /** @type {number} */ var dstW = dst.getWidth(); + /** @type {number} */ var dstH = dst.getHeight(); + + /** @type {Array<number>} */ var uq = deMath.scale(sq, src.getWidth()); + /** @type {Array<number>} */ var vq = deMath.scale(tq, src.getHeight()); + + /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triU = [deMath.swizzle(uq, [0, 1, 2]), deMath.swizzle(uq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triV = [deMath.swizzle(vq, [0, 1, 2]), deMath.swizzle(vq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(params.w, [0, 1, 2]), deMath.swizzle(params.w, [3, 2, 1])]; + + for (var py = 0; py < dst.getHeight(); py++) { + for (var px = 0; px < dst.getWidth(); px++) { + /** @type {number} */ var wx = px + 0.5; + /** @type {number} */ var wy = py + 0.5; + /** @type {number} */ var nx = wx / dstW; + /** @type {number} */ var ny = wy / dstH; + + /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0; + /** @type {number} */ var triWx = triNdx ? dstW - wx : wx; + /** @type {number} */ var triWy = triNdx ? dstH - wy : wy; + /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx; + /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny; + + /** @type {number} */ var s = glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy); + /** @type {number} */ var t = glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy); + /** @type {number} */ var lod = glsTextureTestUtil.computeProjectedTriLod2D(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, dst.getWidth(), dst.getHeight()) + lodBias; + + var pixel = glsTextureTestUtil.execSample(src, params, [s, t], lod); + glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias); + dst.setPixel(pixel, px, py); + } + } +}; + +/** + * @param {glsTextureTestUtil.lodMode} mode + * @param {Array<number>} u + * @param {Array<number>} v + * @param {Array<number>} projection + * @param {number} wx + * @param {number} wy + * @param {number} width + * @param {number} height + * @return {number} + */ +glsTextureTestUtil.computeProjectedTriLod2D = function(mode, u, v, projection, wx, wy, width, height) { + // Exact derivatives. + /** @type {number} */ var dudx = glsTextureTestUtil.triDerivateX(u, projection, wx, width, wy / height); + /** @type {number} */ var dvdx = glsTextureTestUtil.triDerivateX(v, projection, wx, width, wy / height); + /** @type {number} */ var dudy = glsTextureTestUtil.triDerivateY(u, projection, wy, height, wx / width); + /** @type {number} */ var dvdy = glsTextureTestUtil.triDerivateY(v, projection, wy, height, wx / width); + + return glsTextureTestUtil.computeLodFromDerivates2D(mode, dudx, dvdx, dudy, dvdy); +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture2DView} src + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureNonProjected2D = function(dst, src, sq, tq, params) { + var lodBias = params.flags.use_bias ? params.bias : 0; + + var dstSize = [dst.getWidth(), dst.getHeight()]; + var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triLod = [deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias), params.minLod, params.maxLod), + deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias), params.minLod, params.maxLod)]; + + + for (var y = 0; y < dst.getHeight(); y++) { + for (var x = 0; x < dst.getWidth(); x++) { + var yf = (y + 0.5) / dst.getHeight(); + var xf = (x + 0.5) / dst.getWidth(); + + var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule. + var triX = triNdx ? 1 - xf : xf; + var triY = triNdx ? 1 - yf : yf; + + var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY); + var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY); + var lod = triLod[triNdx]; + + var pixel = glsTextureTestUtil.execSample(src, params, [s, t], lod); + glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias); + dst.setPixel(pixel, x, y); + } + } +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture2DArrayView} src + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {Array<number>} rq + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureNonProjected2DArray = function(dst, src, sq, tq, rq, params) { + var lodBias = (params.flags.use_bias) ? params.bias : 0; + + var dstSize = [dst.getWidth(), dst.getHeight()]; + var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triLod = [glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, + glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias]; + + for (var y = 0; y < dst.getHeight(); y++) { + for (var x = 0; x < dst.getWidth(); x++) { + var yf = (y + 0.5) / dst.getHeight(); + var xf = (x + 0.5) / dst.getWidth(); + + var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule. + var triX = triNdx ? 1 - xf : xf; + var triY = triNdx ? 1 - yf : yf; + + var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY); + var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY); + var r = glsTextureTestUtil.triangleInterpolate(triR[triNdx], triX, triY); + var lod = triLod[triNdx]; + + var pixel = glsTextureTestUtil.execSample(src, params, [s, t, r], lod); + glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias); + dst.setPixel(pixel, x, y); + } + } +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture2DView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTexture2D = function(dst, src, texCoord, params) { + var view = src.getSubView(params.baseLevel, params.maxLevel); + var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]]; + var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]]; + + if (params.flags.projected) + glsTextureTestUtil.sampleTextureProjected2D(dst, view, sq, tq, params); + else + glsTextureTestUtil.sampleTextureNonProjected2D(dst, view, sq, tq, params); +}; + +/** + * @param {glsTextureTestUtil.lodMode} mode + * @param {number} dudx + * @param {number} dvdx + * @param {number} dudy + * @param {number} dvdy + * @return {number} + */ +glsTextureTestUtil.computeLodFromDerivates2D = function(mode, dudx, dvdx, dudy, dvdy) { + var p = 0; + switch (mode) { + case glsTextureTestUtil.lodMode.EXACT: + p = Math.max(Math.sqrt(dudx * dudx + dvdx * dvdx), Math.sqrt(dudy * dudy + dvdy * dvdy)); + break; + + case glsTextureTestUtil.lodMode.MIN_BOUND: + case glsTextureTestUtil.lodMode.MAX_BOUND: { + var mu = Math.max(Math.abs(dudx), Math.abs(dudy)); + var mv = Math.max(Math.abs(dvdx), Math.abs(dvdy)); + + p = (mode == glsTextureTestUtil.lodMode.MIN_BOUND) ? Math.max(mu, mv) : mu + mv; + break; + } + + default: + throw new Error('Unrecognized mode:' + mode); + } + + // Native dEQP uses 32-bit numbers. So here 64-bit floating numbers should be transformed into 32-bit ones to ensure the correctness of the result. + return deMath.toFloat32(Math.log(p)) * deMath.INV_LOG_2_FLOAT32; +}; + +/** + * @param {glsTextureTestUtil.lodMode} lodModeParm + * @param {Array<number>} coord + * @param {Array<number>} coordDx + * @param {Array<number>} coordDy + * @param {number} faceSize + * @return {number} + */ +glsTextureTestUtil.computeCubeLodFromDerivates = function(lodModeParm, coord, coordDx, coordDy, faceSize) { + var face = tcuTexture.selectCubeFace(coord); + var maNdx = 0; + var sNdx = 0; + var tNdx = 0; + + // \note Derivate signs don't matter when computing lod + switch (face) { + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break; + case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: + case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break; + default: + throw new Error('Unrecognized face ' + face); + } { + var sc = coord[sNdx]; + var tc = coord[tNdx]; + var ma = Math.abs(coord[maNdx]); + var scdx = coordDx[sNdx]; + var tcdx = coordDx[tNdx]; + var madx = Math.abs(coordDx[maNdx]); + var scdy = coordDy[sNdx]; + var tcdy = coordDy[tNdx]; + var mady = Math.abs(coordDy[maNdx]); + var dudx = faceSize * 0.5 * (scdx * ma - sc * madx) / (ma * ma); + var dvdx = faceSize * 0.5 * (tcdx * ma - tc * madx) / (ma * ma); + var dudy = faceSize * 0.5 * (scdy * ma - sc * mady) / (ma * ma); + var dvdy = faceSize * 0.5 * (tcdy * ma - tc * mady) / (ma * ma); + return glsTextureTestUtil.computeLodFromDerivates2D(lodModeParm, dudx, dvdx, dudy, dvdy); + } +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.TextureCubeView} src + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {Array<number>} rq + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureCube_str = function(dst, src, sq, tq, rq, params) { + var dstSize = [dst.getWidth(), dst.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = src.getSize(); + + // Coordinates per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triW = [deMath.swizzle(params.w, [0, 1, 2]), deMath.swizzle(params.w, [3, 2, 1])]; + + var lodBias = (params.flags.use_bias ? params.bias : 0); + + for (var py = 0; py < dst.getHeight(); py++) { + for (var px = 0; px < dst.getWidth(); px++) { + var wx = px + 0.5; + var wy = py + 0.5; + var nx = wx / dstW; + var ny = wy / dstH; + var triNdx = nx + ny >= 1 ? 1 : 0; + var triNx = triNdx ? 1 - nx : nx; + var triNy = triNdx ? 1 - ny : ny; + + var coord = [glsTextureTestUtil.triangleInterpolate(triS[triNdx], triNx, triNy), + glsTextureTestUtil.triangleInterpolate(triT[triNdx], triNx, triNy), + glsTextureTestUtil.triangleInterpolate(triR[triNdx], triNx, triNy)]; + var coordDx = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)]; + var coordDy = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)]; + + var lod = deMath.clamp((glsTextureTestUtil.computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias), params.minLod, params.maxLod); + + var pixel = glsTextureTestUtil.execSample(src, params, coord, lod); + glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias); + dst.setPixel(pixel, px, py); + } + } +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.TextureCubeView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureCube = function(dst, src, texCoord, params) { + /*const tcu::TextureCubeView*/ var view = src.getSubView(params.baseLevel, params.maxLevel); + var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + glsTextureTestUtil.sampleTextureCube_str(dst, view, sq, tq, rq, params); +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture2DArrayView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTexture2DArray = function(dst, src, texCoord, params) { + var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + DE_ASSERT(!(params.flags.projected)); // \todo [2012-02-17 pyry] Support projected lookups. + glsTextureTestUtil.sampleTextureNonProjected2DArray(dst, src, sq, tq, rq, params); +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture3DView} src + * @param {Array<number>} sq + * @param {Array<number>} tq + * @param {Array<number>} rq + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTextureNonProjected3D = function(dst, src, sq, tq, rq, params) { + var lodBias = params.flags.use_bias ? params.bias : 0; + + var dstSize = [dst.getWidth(), dst.getHeight()]; + var srcSize = [src.getWidth(), src.getHeight(), src.getDepth()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triLod = [deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias), params.minLod, params.maxLod), + deMath.clamp((glsTextureTestUtil.computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias), params.minLod, params.maxLod)]; + + for (var y = 0; y < dst.getHeight(); y++) { + for (var x = 0; x < dst.getWidth(); x++) { + var yf = (y + 0.5) / dst.getHeight(); + var xf = (x + 0.5) / dst.getWidth(); + + var triNdx = xf + yf >= 1 ? 1 : 0; // Top left fill rule. + var triX = triNdx ? 1 - xf : xf; + var triY = triNdx ? 1 - yf : yf; + + var s = glsTextureTestUtil.triangleInterpolate(triS[triNdx], triX, triY); + var t = glsTextureTestUtil.triangleInterpolate(triT[triNdx], triX, triY); + var r = glsTextureTestUtil.triangleInterpolate(triR[triNdx], triX, triY); + var lod = triLod[triNdx]; + + var pixel = src.sample(params.sampler, [s, t, r], lod); + glsTextureTestUtil.applyScaleAndBias(pixel, params.colorScale, params.colorBias); + dst.setPixel(pixel, x, y); + } + } +}; + +/** + * @param {glsTextureTestUtil.SurfaceAccess} dst + * @param {tcuTexture.Texture3DView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} params + */ +glsTextureTestUtil.sampleTexture3D = function(dst, src, texCoord, params) { + /*const tcu::TextureCubeView*/ var view = src.getSubView(params.baseLevel, params.maxLevel); + var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + glsTextureTestUtil.sampleTextureNonProjected3D(dst, view, sq, tq, rq, params); +}; + +/** + * @param {tcuSurface.Surface} reference + * @param {tcuSurface.Surface} rendered + * @param {Array<number>} threshold + * @param {Array< Array<number> >} skipPixels + * + * @return {boolean} + */ +glsTextureTestUtil.compareImages = function(reference, rendered, threshold, skipPixels) { + return tcuImageCompare.pixelThresholdCompare('Result', 'Image comparison result', reference, rendered, threshold, undefined /*tcu::COMPARE_LOG_RESULT*/, skipPixels); +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.Texture2DView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {tcuPixelFormat.PixelFormat} pixelFormat + * @return {boolean} + */ +glsTextureTestUtil.verifyTexture2DResult = function(result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat) { + DE_ASSERT(deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask)); + /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + /** @type {number} */ var numFailedPixels; + + /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat); + + glsTextureTestUtil.sampleTexture2D(surface, src, texCoord, sampleParams); + numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff2D(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec/*, testCtx.getWatchDog()*/); + + if (numFailedPixels > 0) + tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess()); + + return numFailedPixels == 0; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.Texture2DView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array<number>} nonShadowThreshold + * @return {number} + */ +glsTextureTestUtil.computeTextureCompareDiff2D = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) { + DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); + DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); + + var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]]; + var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]]; + + var dstSize = [result.getWidth(), result.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0]; + var numFailed = 0; + + var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array<number>} */ var green = [0, 255, 0, 255]; + errorMask.clear(green); + + /** @type {Array<number>} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + + if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(refPix, [1, 2, 3]), deMath.swizzle(resPix, [1, 2, 3])), nonShadowThreshold))) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + continue; + } + + if (resPix[0] != refPix[0]) { + var wx = px + 0.5; + var wy = py + 0.5; + var nx = wx / dstW; + var ny = wy / dstH; + + var triNdx = nx + ny >= 1.0 ? 1 : 0; + var triWx = triNdx ? dstW - wx : wx; + var triWy = triNdx ? dstH - wy : wy; + var triNx = triNdx ? 1.0 - nx : nx; + var triNy = triNdx ? 1.0 - ny : ny; + + var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)]; + var coordDx = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize); + var coordDy = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize); + + var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) { + var wxo = triWx + lodOffsets[lodOffsNdx][0]; + var wyo = triWy + lodOffsets[lodOffsNdx][1]; + var nxo = wxo / dstW; + var nyo = wyo / dstH; + + var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)]; + var coordDxo = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize); + var coordDyo = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize); + var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec); + var isOk = tcuTexCompareVerifier.isTexCompareResultValid2D(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]); + + if (!isOk) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.Texture3DView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {tcuPixelFormat.PixelFormat} pixelFormat + * @return {boolean} + */ +glsTextureTestUtil.verifyTexture3DResult = function( + result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat +) { + /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + var numFailedPixels = 0; + + assertMsgOptions( + deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask), + 'Compare color masks do not match', false, true + ); + + /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat); + glsTextureTestUtil.sampleTexture3D(surface, src, texCoord, sampleParams); + numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff3D(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec); + + if (numFailedPixels > 0) + tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess()); + + return numFailedPixels == 0; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.Texture3DView} baseView + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @return {number} + */ +glsTextureTestUtil.computeTextureLookupDiff3D = function( + result, reference, errorMask, baseView, texCoord, + sampleParams, lookupPrec, lodPrec +) { + assertMsgOptions( + result.getWidth() == reference.getWidth() && + result.getHeight() == reference.getHeight(), + 'Result and reference images are not the same size', false, true + ); + assertMsgOptions( + result.getWidth() == errorMask.getWidth() && + result.getHeight() == errorMask.getHeight(), + 'Result and error mask images are not the same size', false, true + ); + + /** @type {tcuTexture.Texture3DView} */ + var src = baseView.getSubView( + sampleParams.baseLevel, sampleParams.maxLevel + ); + + var sq = + [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = + [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = + [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + var dstSize = [result.getWidth(), result.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = [src.getWidth(), src.getHeight(), src.getDepth()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triW = [ + deMath.swizzle(sampleParams.w, [0, 1, 2]), + deMath.swizzle(sampleParams.w, [3, 2, 1]) + ]; + + var lodBias = sampleParams.flags.useBias ? sampleParams.bias : 0.0; + + var posEps = 1.0 / ((1 << MIN_SUBPIXEL_BITS) + 1); + + var numFailed = 0; + + var lodOffsets = [ + [-1, 0], + [+1, 0], + [0, -1], + [0, +1] + ]; + + var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + for (var py = 0; py < result.getHeight(); py++) { + // Ugly hack, validation can take way too long at the moment. + /*TODO: if (watchDog) + qpWatchDog_touch(watchDog);*/ + + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias); + + // Try comparison to ideal reference first, + // and if that fails use slower verificator. + if (!deMath.boolAll(deMath.lessThanEqual( + deMath.absDiff(resPix, refPix), + lookupPrec.colorThreshold)) + ) { + /** @type {number} */ var wx = px + 0.5; + /** @type {number} */ var wy = py + 0.5; + /** @type {number} */ var nx = wx / dstW; + /** @type {number} */ var ny = wy / dstH; + + /** @type {boolean} */ var tri0 = nx + ny - posEps <= 1.0; + /** @type {boolean} */ var tri1 = nx + ny + posEps >= 1.0; + + var isOk = false; + + assertMsgOptions( + tri0 || tri1, + 'Pixel should belong at least to one triangle', + false, true + ); + + // Pixel can belong to either of the triangles + // if it lies close enough to the edge. + for (var triNdx = (tri0 ? 0 : 1); + triNdx <= (tri1 ? 1 : 0); + triNdx++) { + var triWx = triNdx ? dstW - wx : wx; + var triWy = triNdx ? dstH - wy : wy; + var triNx = triNdx ? 1.0 - nx : nx; + var triNy = triNdx ? 1.0 - ny : ny; + + var coord = [ + glsTextureTestUtil.projectedTriInterpolate( + triS[triNdx], triW[triNdx], triNx, triNy + ), + glsTextureTestUtil.projectedTriInterpolate( + triT[triNdx], triW[triNdx], triNx, triNy + ), + glsTextureTestUtil.projectedTriInterpolate( + triR[triNdx], triW[triNdx], triNx, triNy + ) + ]; + var coordDx = deMath.multiply([ + glsTextureTestUtil.triDerivateX( + triS[triNdx], triW[triNdx], wx, dstW, triNy + ), + glsTextureTestUtil.triDerivateX( + triT[triNdx], triW[triNdx], wx, dstW, triNy + ), + glsTextureTestUtil.triDerivateX( + triR[triNdx], triW[triNdx], wx, dstW, triNy + ) + ], srcSize); + var coordDy = deMath.multiply([ + glsTextureTestUtil.triDerivateY( + triS[triNdx], triW[triNdx], wy, dstH, triNx + ), + glsTextureTestUtil.triDerivateY( + triT[triNdx], triW[triNdx], wy, dstH, triNx + ), + glsTextureTestUtil.triDerivateY( + triR[triNdx], triW[triNdx], wy, dstH, triNx + ) + ], srcSize); + + var lodBounds = + tcuTexLookupVerifier.computeLodBoundsFromDerivates( + coordDx[0], coordDx[1], coordDx[2], + coordDy[0], coordDy[1], coordDy[2], lodPrec + ); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; + lodOffsNdx < lodOffsets.length; + lodOffsNdx++) { + var wxo = triWx + lodOffsets[lodOffsNdx][0]; + var wyo = triWy + lodOffsets[lodOffsNdx][1]; + var nxo = wxo / dstW; + var nyo = wyo / dstH; + + var coordO = [ + glsTextureTestUtil.projectedTriInterpolate( + triS[triNdx], triW[triNdx], nxo, nyo + ), + glsTextureTestUtil.projectedTriInterpolate( + triT[triNdx], triW[triNdx], nxo, nyo + ), + glsTextureTestUtil.projectedTriInterpolate( + triR[triNdx], triW[triNdx], nxo, nyo + ) + ]; + var coordDxo = deMath.multiply([ + glsTextureTestUtil.triDerivateX( + triS[triNdx], triW[triNdx], wxo, dstW, nyo + ), + glsTextureTestUtil.triDerivateX( + triT[triNdx], triW[triNdx], wxo, dstW, nyo + ), + glsTextureTestUtil.triDerivateX( + triR[triNdx], triW[triNdx], wxo, dstW, nyo + ) + ], srcSize); + var coordDyo = deMath.multiply([ + glsTextureTestUtil.triDerivateY( + triS[triNdx], triW[triNdx], wyo, dstH, nxo + ), + glsTextureTestUtil.triDerivateY( + triT[triNdx], triW[triNdx], wyo, dstH, nxo + ), + glsTextureTestUtil.triDerivateY( + triR[triNdx], triW[triNdx], wyo, dstH, nxo + ) + ], srcSize); + var lodO = + tcuTexLookupVerifier.computeLodBoundsFromDerivates( + coordDxo[0], coordDxo[1], coordDxo[2], + coordDyo[0], coordDyo[1], coordDyo[2], lodPrec + ); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + var clampedLod = tcuTexLookupVerifier.clampLodBounds( + deMath.addScalar(lodBounds, lodBias), + [sampleParams.minLod, sampleParams.maxLod], + lodPrec + ); + + if ( + tcuTexLookupVerifier.isLookupResultValid( + src, sampleParams.sampler, lookupPrec, + coord, clampedLod, resPix + ) + ) { + isOk = true; + break; + } + } + + if (!isOk) { + var red = [255, 0, 0, 255]; + errorMask.setPixel(new tcuRGBA.RGBA(red).toVec(), px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.TextureCubeView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {tcuPixelFormat.PixelFormat} pixelFormat + * @return {boolean} + */ +glsTextureTestUtil.verifyTextureCubeResult = function( + result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat +) { + /** @type {tcuSurface.Surface} */ + var reference = new tcuSurface.Surface( + result.getWidth(), result.getHeight() + ); + /** @type {tcuSurface.Surface} */ + var errorMask = new tcuSurface.Surface( + result.getWidth(), result.getHeight() + ); + /** @type {number} */ var numFailedPixels = 0; + + assertMsgOptions( + deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask), + 'Compare color masks do not match', false, true + ); + + /** @type {glsTextureTestUtil.SurfaceAccess} */ + var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat); + + glsTextureTestUtil.sampleTextureCube( + surface, src, texCoord, sampleParams + ); + + numFailedPixels = glsTextureTestUtil.computeTextureLookupDiffCube( + result, reference.getAccess(), errorMask.getAccess(), + src, texCoord, sampleParams, lookupPrec, lodPrec + /*, testCtx.getWatchDog()*/ + ); + + if (numFailedPixels > 0) + tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess()); + + return numFailedPixels == 0; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.TextureCubeView} baseView + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @return {number} + */ +glsTextureTestUtil.computeTextureLookupDiffCube = function( + result, reference, errorMask, baseView, texCoord, + sampleParams, lookupPrec, lodPrec +) { + assertMsgOptions( + result.getWidth() == reference.getWidth() && + result.getHeight() == reference.getHeight(), + 'Result and reference images are not the same size', false, true + ); + assertMsgOptions( + result.getWidth() == errorMask.getWidth() && + result.getHeight() == errorMask.getHeight(), + 'Result and error mask images are not the same size', false, true + ); + + /** @type {tcuTexture.TextureCubeView} */ + var src = baseView.getSubView( + sampleParams.baseLevel, sampleParams.maxLevel + ); + + var sq = + [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = + [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = + [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + var dstSize = [result.getWidth(), result.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = [src.getSize(), src.getSize()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triW = [ + deMath.swizzle(sampleParams.w, [0, 1, 2]), + deMath.swizzle(sampleParams.w, [3, 2, 1]) + ]; + + var lodBias = sampleParams.flags.useBias ? sampleParams.bias : 0.0; + + var posEps = 1.0 / ((1 << MIN_SUBPIXEL_BITS) + 1); + + var numFailed = 0; + + var lodOffsets = [ + [-1, 0], + [+1, 0], + [0, -1], + [0, +1], + + // \note Not strictly allowed by spec, + // but implementations do this in practice. + [-1, -1], + [-1, 1], + [1, -1], + [1, 1] + ]; + + var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + for (var py = 0; py < result.getHeight(); py++) { + // Ugly hack, validation can take way too long at the moment. + /*TODO: if (watchDog) + qpWatchDog_touch(watchDog);*/ + + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias); + + // Try comparison to ideal reference first, + // and if that fails use slower verificator. + if (!deMath.boolAll(deMath.lessThanEqual( + deMath.absDiff(resPix, refPix), + lookupPrec.colorThreshold)) + ) { + /** @type {number} */ var wx = px + 0.5; + /** @type {number} */ var wy = py + 0.5; + /** @type {number} */ var nx = wx / dstW; + /** @type {number} */ var ny = wy / dstH; + + /** @type {boolean} */ var tri0 = nx + ny - posEps <= 1.0; + /** @type {boolean} */ var tri1 = nx + ny + posEps >= 1.0; + + var isOk = false; + + assertMsgOptions( + tri0 || tri1, + 'Pixel should belong at least to one triangle', + false, true + ); + + // Pixel can belong to either of the triangles + // if it lies close enough to the edge. + for (var triNdx = (tri0 ? 0 : 1); + triNdx <= (tri1 ? 1 : 0); + triNdx++) { + var triWx = triNdx ? dstW - wx : wx; + var triWy = triNdx ? dstH - wy : wy; + var triNx = triNdx ? 1.0 - nx : nx; + var triNy = triNdx ? 1.0 - ny : ny; + + var coord = [ + glsTextureTestUtil.projectedTriInterpolate( + triS[triNdx], triW[triNdx], triNx, triNy + ), + glsTextureTestUtil.projectedTriInterpolate( + triT[triNdx], triW[triNdx], triNx, triNy + ), + glsTextureTestUtil.projectedTriInterpolate( + triR[triNdx], triW[triNdx], triNx, triNy + ) + ]; + var coordDx = [ + glsTextureTestUtil.triDerivateX( + triS[triNdx], triW[triNdx], wx, dstW, triNy + ), + glsTextureTestUtil.triDerivateX( + triT[triNdx], triW[triNdx], wx, dstW, triNy + ), + glsTextureTestUtil.triDerivateX( + triR[triNdx], triW[triNdx], wx, dstW, triNy + ) + ]; + var coordDy = [ + glsTextureTestUtil.triDerivateY( + triS[triNdx], triW[triNdx], wy, dstH, triNx + ), + glsTextureTestUtil.triDerivateY( + triT[triNdx], triW[triNdx], wy, dstH, triNx + ), + glsTextureTestUtil.triDerivateY( + triR[triNdx], triW[triNdx], wy, dstH, triNx + ) + ]; + + var lodBounds = + tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates( + coord, coordDx, coordDy, src.getSize(), lodPrec + ); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; + lodOffsNdx < lodOffsets.length; + lodOffsNdx++) { + var wxo = triWx + lodOffsets[lodOffsNdx][0]; + var wyo = triWy + lodOffsets[lodOffsNdx][1]; + var nxo = wxo / dstW; + var nyo = wyo / dstH; + + var coordO = [ + glsTextureTestUtil.projectedTriInterpolate( + triS[triNdx], triW[triNdx], nxo, nyo + ), + glsTextureTestUtil.projectedTriInterpolate( + triT[triNdx], triW[triNdx], nxo, nyo + ), + glsTextureTestUtil.projectedTriInterpolate( + triR[triNdx], triW[triNdx], nxo, nyo + ) + ]; + var coordDxo = [ + glsTextureTestUtil.triDerivateX( + triS[triNdx], triW[triNdx], wxo, dstW, nyo + ), + glsTextureTestUtil.triDerivateX( + triT[triNdx], triW[triNdx], wxo, dstW, nyo + ), + glsTextureTestUtil.triDerivateX( + triR[triNdx], triW[triNdx], wxo, dstW, nyo + ) + ]; + var coordDyo = [ + glsTextureTestUtil.triDerivateY( + triS[triNdx], triW[triNdx], wyo, dstH, nxo + ), + glsTextureTestUtil.triDerivateY( + triT[triNdx], triW[triNdx], wyo, dstH, nxo + ), + glsTextureTestUtil.triDerivateY( + triR[triNdx], triW[triNdx], wyo, dstH, nxo + ) + ]; + var lodO = + tcuTexLookupVerifier. + computeCubeLodBoundsFromDerivates( + coordO, coordDxo, coordDyo, + src.getSize(), lodPrec + ); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + var clampedLod = tcuTexLookupVerifier.clampLodBounds( + deMath.addScalar(lodBounds, lodBias), + [sampleParams.minLod, sampleParams.maxLod], + lodPrec + ); + + if (tcuTexLookupVerifier. + isLookupResultValid_TextureCubeView( + src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix + ) + ) { + isOk = true; + break; + } + } + + if (!isOk) { + var red = [255, 0, 0, 255]; + errorMask.setPixel(new tcuRGBA.RGBA(red).toVec(), px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.Texture2DArrayView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {tcuPixelFormat.PixelFormat} pixelFormat + * @return {boolean} + */ +glsTextureTestUtil.verifyTexture2DArrayResult = function(result, src, texCoord, sampleParams, lookupPrec, lodPrec, pixelFormat) { + DE_ASSERT(deMath.equal(glsTextureTestUtil.getCompareMask(pixelFormat), lookupPrec.colorMask)); + /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(result.getWidth(), result.getHeight()); + /** @type {number} */ var numFailedPixels; + + /** @type {glsTextureTestUtil.SurfaceAccess} */ var surface = new glsTextureTestUtil.SurfaceAccess(reference, pixelFormat); + + glsTextureTestUtil.sampleTexture2DArray(surface, src, texCoord, sampleParams); + numFailedPixels = glsTextureTestUtil.computeTextureLookupDiff2DArray(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec/*, testCtx.getWatchDog()*/); + + if (numFailedPixels > 0) + tcuImageCompare.displayImages(result, reference.getAccess(), errorMask.getAccess()); + + return numFailedPixels == 0; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.Texture2DArrayView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array<number>} nonShadowThreshold + * @return {number} + */ +glsTextureTestUtil.computeTextureCompareDiff2DArray = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) { + DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); + DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); + + var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + var dstSize = [result.getWidth(), result.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0]; + var numFailed = 0; + + var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array<number>} */ var green = [0, 255, 0, 255]; + errorMask.clear(green); + + /** @type {Array<number>} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + + if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(refPix, [1, 2, 3]), deMath.swizzle(resPix, [1, 2, 3])), nonShadowThreshold))) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + continue; + } + + if (resPix[0] != refPix[0]) { + var wx = px + 0.5; + var wy = py + 0.5; + var nx = wx / dstW; + var ny = wy / dstH; + + var triNdx = nx + ny >= 1.0 ? 1 : 0; + var triWx = triNdx ? dstW - wx : wx; + var triWy = triNdx ? dstH - wy : wy; + var triNx = triNdx ? 1.0 - nx : nx; + var triNy = triNdx ? 1.0 - ny : ny; + + var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)]; + var coordDx = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize); + var coordDy = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize); + + var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) { + var wxo = triWx + lodOffsets[lodOffsNdx][0]; + var wyo = triWy + lodOffsets[lodOffsNdx][1]; + var nxo = wxo / dstW; + var nyo = wyo / dstH; + + var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)]; + var coordDxo = deMath.multiply([glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize); + var coordDyo = deMath.multiply([glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize); + var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec); + var isOk = tcuTexCompareVerifier.isTexCompareResultValid2DArray(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]); + + if (!isOk) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.TextureCubeView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexCompareVerifier.TexComparePrecision} comparePrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {Array<number>} nonShadowThreshold + * @return {number} + */ +glsTextureTestUtil.computeTextureCompareDiffCube = function(result, reference, errorMask, src, texCoord, sampleParams, comparePrec, lodPrec, nonShadowThreshold) { + DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); + DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); + + var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + var dstSize = [result.getWidth(), result.getHeight()]; + var dstW = dstSize[0]; + var dstH = dstSize[1]; + var srcSize = src.getSize(); + + // Coordinates per triangle. + var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0, 0]; + var numFailed = 0; + + var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array<number>} */ var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + /** @type {Array<number>} */ var red = []; + for (var py = 0; py < result.getHeight(); py++) { + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + + if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(deMath.swizzle(resPix, [1, 2, 3]), deMath.swizzle(refPix, [1, 2, 3])), nonShadowThreshold))) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + continue; + } + + if (resPix[0] != refPix[0]) { + var wx = px + 0.5; + var wy = py + 0.5; + var nx = wx / dstW; + var ny = wy / dstH; + + var triNdx = nx + ny >= 1.0 ? 1 : 0; + var triWx = triNdx ? dstW - wx : wx; + var triWy = triNdx ? dstH - wy : wy; + var triNx = triNdx ? 1.0 - nx : nx; + var triNy = triNdx ? 1.0 - ny : ny; + + var coord = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)]; + var coordDx = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)]; + var coordDy = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)]; + + var lodBounds = tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) { + var wxo = triWx + lodOffsets[lodOffsNdx][0]; + var wyo = triWy + lodOffsets[lodOffsNdx][1]; + var nxo = wxo / dstW; + var nyo = wyo / dstH; + + var coordO = [glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)]; + var coordDxo = [glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)]; + var coordDyo = [glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)]; + var lodO = tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + var clampedLod = tcuTexLookupVerifier.clampLodBounds(deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec); + var isOk = tcuTexCompareVerifier.isTexCompareResultValidCube(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix[0]); + + if (!isOk) { + red = [255, 0, 0, 255]; + errorMask.setPixel(red, px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +/** + * @param {Array<number>} s + * @param {Array<number>} w + * @param {number} nx + * @param {number} ny + * @return {number} + */ +glsTextureTestUtil.projectedTriInterpolate = function(s, w, nx, ny) { + return (s[0] * (1.0 - nx - ny) / w[0] + s[1] * ny / w[1] + s[2] * nx / w[2]) / ((1.0 - nx - ny) / w[0] + ny / w[1] + nx / w[2]); +}; + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.Texture2DView} baseView + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {*=} watchDog - TODO: ?? + * @return {number} + */ +glsTextureTestUtil.computeTextureLookupDiff2D = function(result, reference, errorMask, baseView, texCoord, sampleParams, lookupPrec, lodPrec, watchDog) { + DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); + DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); + + /** @type {tcuTexture.Texture2DView} */ var src = baseView.getSubView(sampleParams.baseLevel, sampleParams.maxLevel); + + /** @type {Array<number>} */ var sq = [texCoord[0 + 0], texCoord[2 + 0], texCoord[4 + 0], texCoord[6 + 0]]; + /** @type {Array<number>} */ var tq = [texCoord[0 + 1], texCoord[2 + 1], texCoord[4 + 1], texCoord[6 + 1]]; + + /** @type {Array<number>} */ var dstSize = [result.getWidth(), result.getHeight()]; + /** @type {number} */ var dstW = dstSize[0]; + /** @type {number} */ var dstH = dstSize[1]; + /** @type {Array<number>} */ var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + /** @type {Array<number>} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0]; + + /** @type {number} */ var numFailed = 0; + + /** @type {Array<Array<number>>} */ var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array<number>} */ var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + for (var py = 0; py < result.getHeight(); py++) { + // Ugly hack, validation can take way too long at the moment. + + // TODO:are we implementing qpWatchDog? skipping in the meantime + // if (watchDog) + // qpWatchDog_touch(watchDog); + + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias); + + // Try comparison to ideal reference first, and if that fails use slower verificator. + if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(resPix, refPix), lookupPrec.colorThreshold))) { + /** @type {number} */ var wx = px + 0.5; + /** @type {number} */ var wy = py + 0.5; + /** @type {number} */ var nx = wx / dstW; + /** @type {number} */ var ny = wy / dstH; + + /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0; + /** @type {number} */ var triWx = triNdx ? dstW - wx : wx; + /** @type {number} */ var triWy = triNdx ? dstH - wy : wy; + /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx; + /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny; + + /** @type {Array<number>} */ var coord = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy) + ]; + /** @type {Array<number>} */ var coordDx = deMath.multiply([ + glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize); + /** @type {Array<number>} */ var coordDy = deMath.multiply([ + glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize); + + /** @type {Array<number>} */ + var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) { + /** @type {number} */ var wxo = triWx + lodOffsets[lodOffsNdx][0]; + /** @type {number} */ var wyo = triWy + lodOffsets[lodOffsNdx][1]; + /** @type {number} */ var nxo = wxo / dstW; + /** @type {number} */ var nyo = wyo / dstH; + + /** @type {Array<number>} */ var coordO = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo)]; + /** @type {Array<number>} */ var coordDxo = deMath.multiply([ + glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize); + /** @type {Array<number>} */ var coordDyo = deMath.multiply([ + glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize); + /** @type {Array<number>} */ + var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + /** @type {Array<number>} */ var clampedLod = tcuTexLookupVerifier.clampLodBounds( + deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec); + /** @type {boolean} */ + var isOk = tcuTexLookupVerifier.isLookupResultValid_Texture2DView(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); + + if (!isOk) { + /** @type {tcuRGBA.RGBA} */ var red = tcuRGBA.newRGBAComponents(255, 0, 0, 255); + errorMask.setPixel(red.toVec(), px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +// Verifies texture lookup results and returns number of failed pixels. + +/** + * @param {tcuTexture.ConstPixelBufferAccess} result + * @param {tcuTexture.ConstPixelBufferAccess} reference + * @param {tcuTexture.PixelBufferAccess} errorMask + * @param {tcuTexture.Texture2DArrayView} src + * @param {Array<number>} texCoord + * @param {glsTextureTestUtil.ReferenceParams} sampleParams + * @param {tcuTexLookupVerifier.LookupPrecision} lookupPrec + * @param {tcuTexLookupVerifier.LodPrecision} lodPrec + * @param {*=} watchDog - TODO: ?? + * @return {number} + */ +glsTextureTestUtil.computeTextureLookupDiff2DArray = function(result, reference, errorMask, src, texCoord, sampleParams, lookupPrec, lodPrec, watchDog) { + DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); + DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); + + /** @type {Array<number>} */ var sq = [texCoord[0 + 0], texCoord[3 + 0], texCoord[6 + 0], texCoord[9 + 0]]; + /** @type {Array<number>} */ var tq = [texCoord[0 + 1], texCoord[3 + 1], texCoord[6 + 1], texCoord[9 + 1]]; + /** @type {Array<number>} */ var rq = [texCoord[0 + 2], texCoord[3 + 2], texCoord[6 + 2], texCoord[9 + 2]]; + + /** @type {Array<number>} */ var dstSize = [result.getWidth(), result.getHeight()]; + /** @type {number} */ var dstW = dstSize[0]; + /** @type {number} */ var dstH = dstSize[1]; + /** @type {Array<number>} */ var srcSize = [src.getWidth(), src.getHeight()]; + + // Coordinates and lod per triangle. + /** @type {Array<Array<number>>} */ var triS = [deMath.swizzle(sq, [0, 1, 2]), deMath.swizzle(sq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triT = [deMath.swizzle(tq, [0, 1, 2]), deMath.swizzle(tq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triR = [deMath.swizzle(rq, [0, 1, 2]), deMath.swizzle(rq, [3, 2, 1])]; + /** @type {Array<Array<number>>} */ var triW = [deMath.swizzle(sampleParams.w, [0, 1, 2]), deMath.swizzle(sampleParams.w, [3, 2, 1])]; + + /** @type {Array<number>} */ var lodBias = sampleParams.flags.use_bias ? [sampleParams.bias, sampleParams.bias] : [0.0, 0.0]; + + /** @type {number} */ var numFailed = 0; + + /** @type {Array<Array<number>>} */ var lodOffsets = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1] + ]; + + /** @type {Array<number>} */ var green = [0, 255, 0, 255]; + errorMask.clear(new tcuRGBA.RGBA(green).toVec()); + + for (var py = 0; py < result.getHeight(); py++) { + // Ugly hack, validation can take way too long at the moment. + + // TODO:are we implementing qpWatchDog? skipping in the meantime + // if (watchDog) + // qpWatchDog_touch(watchDog); + + for (var px = 0; px < result.getWidth(); px++) { + /** @type {Array<number>} */ + var resPix = result.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(resPix, sampleParams.colorScale, sampleParams.colorBias); + /** @type {Array<number>} */ + var refPix = reference.getPixel(px, py); + glsTextureTestUtil.deapplyScaleAndBias(refPix, sampleParams.colorScale, sampleParams.colorBias); + + + // Try comparison to ideal reference first, and if that fails use slower verificator. + if (!deMath.boolAll(deMath.lessThanEqual(deMath.absDiff(resPix, refPix), lookupPrec.colorThreshold))) { + /** @type {number} */ var wx = px + 0.5; + /** @type {number} */ var wy = py + 0.5; + /** @type {number} */ var nx = wx / dstW; + /** @type {number} */ var ny = wy / dstH; + + /** @type {number} */ var triNdx = nx + ny >= 1.0 ? 1 : 0; + /** @type {number} */ var triWx = triNdx ? dstW - wx : wx; + /** @type {number} */ var triWy = triNdx ? dstH - wy : wy; + /** @type {number} */ var triNx = triNdx ? 1.0 - nx : nx; + /** @type {number} */ var triNy = triNdx ? 1.0 - ny : ny; + + /** @type {Array<number>} */ var coord = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), + glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy) + ]; + /** @type {Array<number>} */ var coordDx = deMath.multiply([ + glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)], srcSize); + /** @type {Array<number>} */ var coordDy = deMath.multiply([ + glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)], srcSize); + + /** @type {Array<number>} */ + var lodBounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDx[0], coordDx[1], coordDy[0], coordDy[1], lodPrec); + + // Compute lod bounds across lodOffsets range. + for (var lodOffsNdx = 0; lodOffsNdx < lodOffsets.length; lodOffsNdx++) { + /** @type {number} */ var wxo = triWx + lodOffsets[lodOffsNdx][0]; + /** @type {number} */ var wyo = triWy + lodOffsets[lodOffsNdx][1]; + /** @type {number} */ var nxo = wxo / dstW; + /** @type {number} */ var nyo = wyo / dstH; + + /** @type {Array<number>} */ var coordO = [ + glsTextureTestUtil.projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo), + glsTextureTestUtil.projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo) + ]; + /** @type {Array<number>} */ var coordDxo = deMath.multiply([ + glsTextureTestUtil.triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), + glsTextureTestUtil.triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)], srcSize + ); + /** @type {Array<number>} */ var coordDyo = deMath.multiply([ + glsTextureTestUtil.triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), + glsTextureTestUtil.triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)], srcSize + ); + /** @type {Array<number>} */ + var lodO = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(coordDxo[0], coordDxo[1], coordDyo[0], coordDyo[1], lodPrec); + + lodBounds[0] = Math.min(lodBounds[0], lodO[0]); + lodBounds[1] = Math.max(lodBounds[1], lodO[1]); + } + + /** @type {Array<number>} */ var clampedLod = tcuTexLookupVerifier.clampLodBounds( + deMath.add(lodBounds, lodBias), [sampleParams.minLod, sampleParams.maxLod], lodPrec); + /** @type {boolean} */ + var isOk = tcuTexLookupVerifier.isLookupResultValid_Texture2DArrayView(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); + + if (!isOk) { + /** @type {tcuRGBA.RGBA} */ var red = tcuRGBA.newRGBAComponents(255, 0, 0, 255); + errorMask.setPixel(red.toVec(), px, py); + numFailed += 1; + } + } + } + } + + return numFailed; +}; + +}); |