summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/modules/shared/glsTextureTestUtil.js2642
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;
+};
+
+});