Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / functional / gles3 / es3fInstancedRenderingTests.js
blobadc7e857ca9f275ba429ce5490f800353c11e425
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
21 'use strict';
22 goog.provide('functional.gles3.es3fInstancedRenderingTests');
23 goog.require('framework.common.tcuImageCompare');
24 goog.require('framework.common.tcuSurface');
25 goog.require('framework.common.tcuTestCase');
26 goog.require('framework.delibs.debase.deMath');
27 goog.require('framework.delibs.debase.deRandom');
28 goog.require('framework.delibs.debase.deString');
29 goog.require('framework.opengl.gluShaderProgram');
30 goog.require('framework.opengl.gluShaderUtil');
31 goog.require('framework.opengl.gluTextureUtil');
33 goog.scope(function() {
35 var es3fInstancedRenderingTests = functional.gles3.es3fInstancedRenderingTests;
36 var gluShaderUtil = framework.opengl.gluShaderUtil;
37 var gluShaderProgram = framework.opengl.gluShaderProgram;
38 var tcuTestCase = framework.common.tcuTestCase;
39 var tcuSurface = framework.common.tcuSurface;
40 var deString = framework.delibs.debase.deString;
41 var deRandom = framework.delibs.debase.deRandom;
42 var tcuImageCompare = framework.common.tcuImageCompare;
43 var gluTextureUtil = framework.opengl.gluTextureUtil;
44 var deMath = framework.delibs.debase.deMath;
46     /** @type {?WebGL2RenderingContext} */ var gl;
48     /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_WIDTH = 128;
49     /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_HEIGHT = 128;
51     /** @const @type {number} */ es3fInstancedRenderingTests.QUAD_GRID_SIZE = 127;
53     // Attribute divisors for the attributes defining the color's RGB components.
54     /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_R = 3;
55     /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_G = 2;
56     /** @const @type {number} */es3fInstancedRenderingTests.ATTRIB_DIVISOR_B = 1;
58     /** @const @type {number} */es3fInstancedRenderingTests.OFFSET_COMPONENTS = 3; // \note Affects whether a float or a vecN is used in shader, but only first component is non-zero.
60     // Scale and bias values when converting float to integer, when attribute is of integer type.
61     /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_INT_SCALE = 100.0;
62     /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_INT_BIAS = -50.0;
63     /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_UINT_SCALE = 100.0;
64     /** @const @type {number} */es3fInstancedRenderingTests.FLOAT_UINT_BIAS = 0.0;
66     var DE_ASSERT = function(expression) {
67         if (!expression) throw new Error('Assert failed');
68     };
70     es3fInstancedRenderingTests.TCU_FAIL = function(message) {
71         throw new Error(message);
72     };
74     // es3fInstancedRenderingTests.InstancedRenderingCase
76     /**
77      * es3fInstancedRenderingTests.DrawFunction
78      * @enum {number}
79      */
80     es3fInstancedRenderingTests.DrawFunction = {
81             FUNCTION_DRAW_ARRAYS_INSTANCED: 0,
82             FUNCTION_DRAW_ELEMENTS_INSTANCED: 1
83     };
85     /**
86      * es3fInstancedRenderingTests.InstancingType
87      * @enum {number}
88      */
89     es3fInstancedRenderingTests.InstancingType = {
90             TYPE_INSTANCE_ID: 0,
91             TYPE_ATTRIB_DIVISOR: 1,
92             TYPE_MIXED: 2
93     };
95     /**
96     * es3fInstancedRenderingTests.InstancedRenderingCase class, inherits from TestCase class
97     * @constructor
98     * @extends {tcuTestCase.DeqpTest}
99     * @param {string} name
100     * @param {string} description
101     * @param {es3fInstancedRenderingTests.DrawFunction} drawFunction
102     * @param {es3fInstancedRenderingTests.InstancingType} instancingType
103     * @param {gluShaderUtil.DataType} rgbAttrType
104     * @param {number} numInstances
105     */
106     es3fInstancedRenderingTests.InstancedRenderingCase = function(name, description, drawFunction, instancingType, rgbAttrType, numInstances) {
107         tcuTestCase.DeqpTest.call(this, name, description);
108         /** @type {es3fInstancedRenderingTests.DrawFunction} */ this.m_function = drawFunction;
109         /** @type {es3fInstancedRenderingTests.InstancingType} */ this.m_instancingType = instancingType;
110         /** @type {gluShaderUtil.DataType} */ this.m_rgbAttrType = rgbAttrType;
111         /** @type {number} */ this.m_numInstances = numInstances;
112         /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
113         /** @type {Array<number>} */ this.m_gridVertexPositions = [];
114         /** @type {Array<number>} */ this.m_gridIndices = [];
115         /** @type {Array<number>} */ this.m_instanceOffsets = [];
116         /** @type {Array<number>} */ this.m_instanceColorR = [];
117         /** @type {Array<number>} */ this.m_instanceColorG = [];
118         /** @type {Array<number>} */ this.m_instanceColorB = [];
119     };
121     es3fInstancedRenderingTests.InstancedRenderingCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
122     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.constructor = es3fInstancedRenderingTests.InstancedRenderingCase;
124     /**
125     * Helper function that does biasing and scaling when converting float to integer.
126     * @param {Array<number>} vec
127     * @param {number} val
128     */
129     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.pushVarCompAttrib = function(vec, val) {
130         var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType);
131         var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType);
132         var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType);
133         var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType);
134         if (isFloatCase || isMatCase)
135             vec.push(val);
136         else if (isIntCase)
137             vec.push(val * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS);
138         else if (isUintCase)
139             vec.push(val * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS);
140         else
141             throw new Error('Invalid attribute type.');
142     };
144     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.init = function() {
145         // Clear errors from previous tests
146         gl.getError();
148         /** @type {boolean} */ var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType);
149         /** @type {boolean} */ var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType);
150         /** @type {boolean} */ var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType);
151         /** @type {boolean} */ var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType);
152         /** @type {number} */ var typeSize = gluShaderUtil.getDataTypeScalarSize(this.m_rgbAttrType);
153         /** @type {boolean} */ var isScalarCase = typeSize == 1;
154         /** @type {string} */ var swizzleFirst = isScalarCase ? '' : '.x';
155         /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(this.m_rgbAttrType);
157         /** @type {string} */ var floatIntScaleStr = '(' + es3fInstancedRenderingTests.FLOAT_INT_SCALE.toFixed(3) + ')';
158         /** @type {string} */ var floatIntBiasStr = '(' + es3fInstancedRenderingTests.FLOAT_INT_BIAS.toFixed(3) + ')';
159         /** @type {string} */ var floatUintScaleStr = '(' + es3fInstancedRenderingTests.FLOAT_UINT_SCALE.toFixed(3) + ')';
160         /** @type {string} */ var floatUintBiasStr = '(' + es3fInstancedRenderingTests.FLOAT_UINT_BIAS.toFixed(3) + ')';
162         DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase);
164         // Generate shader.
165         // \note For case TYPE_MIXED, vertex position offset and color red component get their values from instance id, while green and blue get their values from instanced attributes.
167         /** @type {string} */ var numInstancesStr = this.m_numInstances.toString() + '.0';
169         /** @type {string} */ var instanceAttribs = '';
170         /** @type {string} */ var posExpression = '';
171         /** @type {string} */ var colorRExpression = '';
172         /** @type {string} */ var colorGExpression = '';
173         /** @type {string} */ var colorBExpression = '';
175         if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) {
176             posExpression = 'a_position + vec4(float(gl_InstanceID) * 2.0 / ' + numInstancesStr + ', 0.0, 0.0, 0.0)';
177             colorRExpression = 'float(gl_InstanceID)/' + numInstancesStr;
179             if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID) {
180                 colorGExpression = 'float(gl_InstanceID)*2.0/' + numInstancesStr;
181                 colorBExpression = '1.0 - float(gl_InstanceID)/' + numInstancesStr;
182             }
183         }
185         if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) {
186             if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) {
187                 posExpression = 'a_position + vec4(a_instanceOffset';
189                 DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4);
191                 for (var i = 0; i < 4 - es3fInstancedRenderingTests.OFFSET_COMPONENTS; i++)
192                     posExpression += ', 0.0';
193                 posExpression += ')';
195                 if (isFloatCase)
196                     colorRExpression = 'a_instanceR' + swizzleFirst;
197                 else if (isIntCase)
198                     colorRExpression = '(float(a_instanceR' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr;
199                 else if (isUintCase)
200                     colorRExpression = '(float(a_instanceR' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr;
201                 else if (isMatCase)
202                     colorRExpression = 'a_instanceR[0][0]';
203                 else
204                     DE_ASSERT(false);
206                 instanceAttribs += 'in highp ' + (es3fInstancedRenderingTests.OFFSET_COMPONENTS == 1 ? 'float' : 'vec' + es3fInstancedRenderingTests.OFFSET_COMPONENTS.toString()) + ' a_instanceOffset;\n';
207                 instanceAttribs += 'in mediump ' + typeName + ' a_instanceR;\n';
208             }
210             if (isFloatCase) {
211                 colorGExpression = 'a_instanceG' + swizzleFirst;
212                 colorBExpression = 'a_instanceB' + swizzleFirst;
213             } else if (isIntCase) {
214                 colorGExpression = '(float(a_instanceG' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr;
215                 colorBExpression = '(float(a_instanceB' + swizzleFirst + ') - ' + floatIntBiasStr + ') / ' + floatIntScaleStr;
216             } else if (isUintCase) {
217                 colorGExpression = '(float(a_instanceG' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr;
218                 colorBExpression = '(float(a_instanceB' + swizzleFirst + ') - ' + floatUintBiasStr + ') / ' + floatUintScaleStr;
219             } else if (isMatCase) {
220                 colorGExpression = 'a_instanceG[0][0]';
221                 colorBExpression = 'a_instanceB[0][0]';
222             } else
223                 DE_ASSERT(false);
225             instanceAttribs += 'in mediump ' + typeName + ' a_instanceG;\n';
226             instanceAttribs += 'in mediump ' + typeName + ' a_instanceB;\n';
227         }
229         DE_ASSERT(!(posExpression.length == 0));
230         DE_ASSERT(!(colorRExpression.length == 0));
231         DE_ASSERT(!(colorGExpression.length == 0));
232         DE_ASSERT(!(colorBExpression.length == 0));
234         /** @type {string} */ var vertShaderSourceStr =
235             '#version 300 es\n' +
236             'in highp vec4 a_position;\n' +
237             instanceAttribs +
238             'out mediump vec4 v_color;\n' +
239             '\n' +
240             'void main()\n' +
241             ' {\n' +
242             ' gl_Position = ' + posExpression + ';\n' +
243             ' v_color.r = ' + colorRExpression + ';\n' +
244             ' v_color.g = ' + colorGExpression + ';\n' +
245             ' v_color.b = ' + colorBExpression + ';\n' +
246             ' v_color.a = 1.0;\n' +
247             '}\n';
249         /** @type {string} */ var fragShaderSource =
250             '#version 300 es\n' +
251             'layout(location = 0) out mediump vec4 o_color;\n' +
252             'in mediump vec4 v_color;\n' +
253             '\n' +
254             'void main()\n' +
255             ' {\n' +
256             ' o_color = v_color;\n' +
257             '}\n';
259         // Create shader program and log it.
261         DE_ASSERT(!this.m_program);
262         this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertShaderSourceStr, fragShaderSource));
264         //tcu::TestLog& log = this.m_testCtx.getLog();
265         //log << *m_program;
266         // TODO: bufferedLogToConsole?
267         //bufferedLogToConsole(this.m_program);
269         assertMsgOptions(this.m_program.isOk(), 'Failed to compile shader', false, true);
271         // Vertex shader attributes.
273         if (this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED) {
274             // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
276             for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1; y++)
277                 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1; x++) {
278                     /** @type {number} */ var fx = -1.0 + x / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances;
279                     /** @type {number} */ var fy = -1.0 + y / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0;
281                     this.m_gridVertexPositions.push(fx);
282                     this.m_gridVertexPositions.push(fy);
283                 }
285             // Indices.
287             for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE; y++)
288                 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE; x++) {
289                     /** @type {number} */ var ndx00 = y * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x;
290                     /** @type {number} */ var ndx10 = y * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x + 1;
291                     /** @type {number} */ var ndx01 = (y + 1) * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x;
292                     /** @type {number} */ var ndx11 = (y + 1) * (es3fInstancedRenderingTests.QUAD_GRID_SIZE + 1) + x + 1;
294                     // Lower-left triangle of a quad.
295                     this.m_gridIndices.push(ndx00);
296                     this.m_gridIndices.push(ndx10);
297                     this.m_gridIndices.push(ndx01);
299                     // Upper-right triangle of a quad.
300                     this.m_gridIndices.push(ndx11);
301                     this.m_gridIndices.push(ndx01);
302                     this.m_gridIndices.push(ndx10);
303                 }
304         } else {
305             DE_ASSERT(this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED);
307             // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
309             for (var y = 0; y < es3fInstancedRenderingTests.QUAD_GRID_SIZE; y++)
310                 for (var x = 0; x < es3fInstancedRenderingTests.QUAD_GRID_SIZE; x++) {
311                     /** @type {number} */ var fx0 = -1.0 + (x + 0) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances;
312                     /** @type {number} */ var fx1 = -1.0 + (x + 1) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0 / this.m_numInstances;
313                     /** @type {number} */ var fy0 = -1.0 + (y + 0) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0;
314                     /** @type {number} */ var fy1 = -1.0 + (y + 1) / es3fInstancedRenderingTests.QUAD_GRID_SIZE * 2.0;
316                     // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
317                     this.m_gridVertexPositions.push(fx0);
318                     this.m_gridVertexPositions.push(fy0);
319                     this.m_gridVertexPositions.push(fx1);
320                     this.m_gridVertexPositions.push(fy0);
321                     this.m_gridVertexPositions.push(fx0);
322                     this.m_gridVertexPositions.push(fy1);
324                     // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
325                     this.m_gridVertexPositions.push(fx1);
326                     this.m_gridVertexPositions.push(fy1);
327                     this.m_gridVertexPositions.push(fx0);
328                     this.m_gridVertexPositions.push(fy1);
329                     this.m_gridVertexPositions.push(fx1);
330                     this.m_gridVertexPositions.push(fy0);
331                 }
332         }
334         // Instanced attributes: position offset and color RGB components.
336         if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) {
337             if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) {
338                 // Offsets are such that the vertical bars are drawn next to each other.
339                 for (var i = 0; i < this.m_numInstances; i++) {
340                     this.m_instanceOffsets.push(i * 2.0 / this.m_numInstances);
342                     DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4);
344                     for (var j = 0; j < es3fInstancedRenderingTests.OFFSET_COMPONENTS - 1; j++)
345                         this.m_instanceOffsets.push(0.0);
346                 }
348                 /** @type {number} */ var rInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_R == 0 ? 0 : 1);
349                 for (var i = 0; i < rInstances; i++) {
350                     this.pushVarCompAttrib(this.m_instanceColorR, i / rInstances);
352                     for (var j = 0; j < typeSize - 1; j++)
353                         this.pushVarCompAttrib(this.m_instanceColorR, 0.0);
354                 }
355             }
357             /** @type {number} */ var gInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_G == 0 ? 0 : 1);
358             for (var i = 0; i < gInstances; i++) {
359                 this.pushVarCompAttrib(this.m_instanceColorG, i * 2.0 / gInstances);
361                 for (var j = 0; j < typeSize - 1; j++)
362                     this.pushVarCompAttrib(this.m_instanceColorG, 0.0);
363             }
365             /** @type {number} */ var bInstances = Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_B == 0 ? 0 : 1);
366             for (var i = 0; i < bInstances; i++) {
367                 this.pushVarCompAttrib(this.m_instanceColorB, 1.0 - i / bInstances);
369                 for (var j = 0; j < typeSize - 1; j++)
370                     this.pushVarCompAttrib(this.m_instanceColorB, 0.0);
371             }
372         }
373     };
375     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.deinit = function() {
376         var numVertexAttribArrays = /** @type{number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
377         for (var idx = 0; idx < numVertexAttribArrays; idx++) {
378             gl.disableVertexAttribArray(idx);
379             gl.vertexAttribDivisor(idx, 0);
380         }
381     };
383     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.iterate = function() {
384         /** @type {number} */ var width = Math.min(gl.drawingBufferWidth, es3fInstancedRenderingTests.MAX_RENDER_WIDTH);
385         /** @type {number} */ var height = Math.min(gl.drawingBufferHeight, es3fInstancedRenderingTests.MAX_RENDER_HEIGHT);
387         /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
388         /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
390         /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
392         /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
393         /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
395         /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(width, height);
396         /** @type {tcuSurface.Surface} */ var resultImg = new tcuSurface.Surface(width, height);
398         // Draw result.
400         gl.viewport(xOffset, yOffset, width, height);
401         gl.clear(gl.COLOR_BUFFER_BIT);
403         this.setupAndRender();
405         var resImg = resultImg.getAccess();
406         var resImgTransferFormat = gluTextureUtil.getTransferFormat(resImg.getFormat());
408         gl.readPixels(xOffset, yOffset, resImg.m_width, resImg.m_height, resImgTransferFormat.format, resImgTransferFormat.dataType, resultImg.m_pixels);
410         // Compute reference.
411         this.computeReference(referenceImg);
413         // Compare.
415         // Passing referenceImg.getAccess() and resultImg.getAccess() instead of referenceImg and resultImg
416     /** @type {boolean} */ var testOk = tcuImageCompare.fuzzyCompare('ComparisonResult', 'Image comparison result', referenceImg.getAccess(), resultImg.getAccess(), 0.05 /*, gluShaderUtil.COMPARE_LOG_RESULT*/);
418         assertMsgOptions(testOk, '', true, false);
420         return tcuTestCase.IterateResult.STOP;
421     };
423     /**
424     * @param {Array<number>} attrPtr
425     * @param {number} location
426     * @param {number} divisor
427     */
428     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.setupVarAttribPointer = function(attrPtr, location, divisor) {
429         /** @type {boolean} */ var isFloatCase = gluShaderUtil.isDataTypeFloatOrVec(this.m_rgbAttrType);
430         /** @type {boolean} */ var isIntCase = gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType);
431         /** @type {boolean} */ var isUintCase = gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType);
432         /** @type {boolean} */ var isMatCase = gluShaderUtil.isDataTypeMatrix(this.m_rgbAttrType);
433         /** @type {number} */ var typeSize = gluShaderUtil.getDataTypeScalarSize(this.m_rgbAttrType);
434         /** @type {number} */ var numSlots = isMatCase ? gluShaderUtil.getDataTypeMatrixNumColumns(this.m_rgbAttrType) : 1; // Matrix uses as many attribute slots as it has columns.
436         for (var slotNdx = 0; slotNdx < numSlots; slotNdx++) {
437             /** @type {number} */ var curLoc = location + slotNdx;
439             gl.enableVertexAttribArray(curLoc);
440             gl.vertexAttribDivisor(curLoc, divisor);
441             var curLocGlBuffer = gl.createBuffer();
442             if (isFloatCase) {
443                 var bufferCurLoc = new Float32Array(attrPtr);
444                 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer);
445                 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW);
447                 gl.vertexAttribPointer(curLoc, typeSize, gl.FLOAT, false, 0, 0);
448             } else if (isIntCase) {
449                 var bufferCurLoc = new Int32Array(attrPtr);
450                 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer);
451                 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW);
453                 gl.vertexAttribIPointer(curLoc, typeSize, gl.INT, 0, 0);
454             } else if (isUintCase) {
455                 var bufferCurLoc = new Uint32Array(attrPtr);
456                 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer);
457                 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW);
459                 gl.vertexAttribIPointer(curLoc, typeSize, gl.UNSIGNED_INT, 0, 0);
460             } else if (isMatCase) {
461                 /** @type {number} */ var numRows = gluShaderUtil.getDataTypeMatrixNumRows(this.m_rgbAttrType);
462                 /** @type {number} */ var numCols = gluShaderUtil.getDataTypeMatrixNumColumns(this.m_rgbAttrType);
464                 var bufferCurLoc = new Float32Array(attrPtr);
465                 gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer);
466                 gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW);
468                 gl.vertexAttribPointer(curLoc, numRows, gl.FLOAT, false, numCols * numRows * 4, 0);
469             } else
470                 DE_ASSERT(false);
471         }
472     };
474     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.setupAndRender = function() {
475         /** @type {WebGLProgram} */ var program = this.m_program.getProgram();
477         gl.useProgram(program);
478         // Setup attributes.
480         // Position attribute is non-instanced.
481         /** @type {number} */ var positionLoc = gl.getAttribLocation(program, 'a_position');
482         gl.enableVertexAttribArray(positionLoc);
483         var positionBuffer = gl.createBuffer();
484         var bufferGridVertexPosition = new Float32Array(this.m_gridVertexPositions);
485         gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
486         gl.bufferData(gl.ARRAY_BUFFER, bufferGridVertexPosition, gl.STATIC_DRAW);
487         gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
489         if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED) {
490             if (this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR) {
491                 // Position offset attribute is instanced with separate offset for every instance.
492                 /** @type {number} */ var offsetLoc = gl.getAttribLocation(program, 'a_instanceOffset');
493                 gl.enableVertexAttribArray(offsetLoc);
494                 gl.vertexAttribDivisor(offsetLoc, 1);
496                 var offsetLocGlBuffer = gl.createBuffer();
497                 var bufferOffsetLoc = new Float32Array(this.m_instanceOffsets);
498                 gl.bindBuffer(gl.ARRAY_BUFFER, offsetLocGlBuffer);
499                 gl.bufferData(gl.ARRAY_BUFFER, bufferOffsetLoc, gl.STATIC_DRAW);
501                 gl.vertexAttribPointer(offsetLoc, es3fInstancedRenderingTests.OFFSET_COMPONENTS, gl.FLOAT, false, 0, 0);
503                 /** @type {number} */ var rLoc = gl.getAttribLocation(program, 'a_instanceR');
504                 this.setupVarAttribPointer(this.m_instanceColorR, rLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_R);
505             }
507             /** @type {number} */ var gLoc = gl.getAttribLocation(program, 'a_instanceG');
508             this.setupVarAttribPointer(this.m_instanceColorG, gLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_G);
510             /** @type {number} */ var bLoc = gl.getAttribLocation(program, 'a_instanceB');
511             this.setupVarAttribPointer(this.m_instanceColorB, bLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_B);
512         }
514         // Draw using appropriate function.
516         if (this.m_function == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED) {
517             /** @type {number} */ var numPositionComponents = 2;
518             gl.drawArraysInstanced(gl.TRIANGLES, 0, Math.floor(this.m_gridVertexPositions.length / numPositionComponents), this.m_numInstances);
519         } else {
520             var gridIndicesGLBuffer = gl.createBuffer();
521             var bufferGridIndices = new Uint16Array(this.m_gridIndices);
522             gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gridIndicesGLBuffer);
523             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferGridIndices, gl.STATIC_DRAW);
525             gl.drawElementsInstanced(gl.TRIANGLES, this.m_gridIndices.length, gl.UNSIGNED_SHORT, 0, this.m_numInstances);
526         }
527         gl.useProgram(null);
528     };
530     /**
531     * @param {tcuSurface.Surface} dst
532     */
533     es3fInstancedRenderingTests.InstancedRenderingCase.prototype.computeReference = function(dst) {
534         /** @type {number} */ var wid = dst.getWidth();
535         /** @type {number} */ var hei = dst.getHeight();
537         // Draw a rectangle (vertical bar) for each instance.
539         for (var instanceNdx = 0; instanceNdx < this.m_numInstances; instanceNdx++) {
540             /** @type {number} */ var xStart = Math.floor(instanceNdx * wid / this.m_numInstances);
541             /** @type {number} */ var xEnd = Math.floor((instanceNdx + 1) * wid / this.m_numInstances);
543             // Emulate attribute divisors if that is the case.
545             /** @type {number} */ var clrNdxR = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) : instanceNdx;
546             /** @type {number} */ var clrNdxG = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) : instanceNdx;
547             /** @type {number} */ var clrNdxB = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(instanceNdx / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) : instanceNdx;
549             /** @type {number} */ var rInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_R) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_R == 0 ? 0 : 1) : this.m_numInstances;
550             /** @type {number} */ var gInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_G) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_G == 0 ? 0 : 1) : this.m_numInstances;
551             /** @type {number} */ var bInstances = this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR || this.m_instancingType == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? Math.floor(this.m_numInstances / es3fInstancedRenderingTests.ATTRIB_DIVISOR_B) + (this.m_numInstances % es3fInstancedRenderingTests.ATTRIB_DIVISOR_B == 0 ? 0 : 1) : this.m_numInstances;
553             // Calculate colors.
555             /** @type {number} */ var r = clrNdxR / rInstances;
556             /** @type {number} */ var g = clrNdxG * 2.0 / gInstances;
557             /** @type {number} */ var b = 1.0 - clrNdxB / bInstances;
559             // Convert to integer and back if shader inputs are integers.
561             if (gluShaderUtil.isDataTypeIntOrIVec(this.m_rgbAttrType)) {
562                 /** @type {number} */var intR = (r * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS);
563                 /** @type {number} */var intG = (g * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS);
564                 /** @type {number} */var intB = (b * es3fInstancedRenderingTests.FLOAT_INT_SCALE + es3fInstancedRenderingTests.FLOAT_INT_BIAS);
565                 r = (intR - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE;
566                 g = (intG - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE;
567                 b = (intB - es3fInstancedRenderingTests.FLOAT_INT_BIAS) / es3fInstancedRenderingTests.FLOAT_INT_SCALE;
568             } else if (gluShaderUtil.isDataTypeUintOrUVec(this.m_rgbAttrType)) {
569                 /** @type {number} */var uintR = (r * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS);
570                 /** @type {number} */var uintG = (g * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS);
571                 /** @type {number} */var uintB = (b * es3fInstancedRenderingTests.FLOAT_UINT_SCALE + es3fInstancedRenderingTests.FLOAT_UINT_BIAS);
572                 r = (uintR - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE;
573                 g = (uintG - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE;
574                 b = (uintB - es3fInstancedRenderingTests.FLOAT_UINT_BIAS) / es3fInstancedRenderingTests.FLOAT_UINT_SCALE;
575             }
577             // Convert from float to unorm8.
578             var color = deMath.add(deMath.scale([r, g, b, 1.0], 255), [0.5, 0.5, 0.5, 0.5]);
579             color = deMath.clampVector(color, 0, 255);
581             // Draw rectangle.
582             for (var y = 0; y < hei; y++)
583                 for (var x = xStart; x < xEnd; x++)
584                     dst.setPixel(x, y, color);
585         }
586     };
588     es3fInstancedRenderingTests.init = function() {
589         var testGroup = tcuTestCase.runner.testCases;
590     /** @type {Array<number>} */ var instanceCounts = [1, 2, 4, 20];
592         for (var _function in es3fInstancedRenderingTests.DrawFunction) {
593             /** @type {?string} */ var functionName =
594                                        es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED ? 'draw_arrays_instanced' :
595                                        es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'draw_elements_instanced' :
596                                        null;
598             /** @type {?string} */ var functionDesc =
599                                        es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED ? 'Use glDrawArraysInstanced()' :
600                                        es3fInstancedRenderingTests.DrawFunction[_function] == es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'Use glDrawElementsInstanced()' :
601                                        null;
603             DE_ASSERT(functionName != null);
604             DE_ASSERT(functionDesc != null);
606             /** @type {tcuTestCase.DeqpTest} */ var functionGroup = tcuTestCase.newTest(functionName, functionDesc);
607             testGroup.addChild(functionGroup);
609             for (var instancingType in es3fInstancedRenderingTests.InstancingType) {
610                 /** @type {?string} */ var instancingTypeName =
611                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID ? 'instance_id' :
612                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? 'attribute_divisor' :
613                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? 'mixed' :
614                                                  null;
616                 /** @type {?string} */ var instancingTypeDesc =
617                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_INSTANCE_ID ? 'Use gl_InstanceID for instancing' :
618                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR ? 'Use vertex attribute divisors for instancing' :
619                                                  es3fInstancedRenderingTests.InstancingType[instancingType] == es3fInstancedRenderingTests.InstancingType.TYPE_MIXED ? 'Use both gl_InstanceID and vertex attribute divisors for instancing' :
620                                                  null;
622                 DE_ASSERT(instancingTypeName != null);
623                 DE_ASSERT(instancingTypeDesc != null);
625                 /** @type {tcuTestCase.DeqpTest} */
626                 var instancingTypeGroup = tcuTestCase.newTest(instancingTypeName, instancingTypeDesc);
628                 functionGroup.addChild(instancingTypeGroup);
630                 for (var countNdx in instanceCounts) {
631                     /** @type {string} */ var countName = instanceCounts[countNdx].toString() + '_instances';
632                     instancingTypeGroup.addChild(new es3fInstancedRenderingTests.InstancedRenderingCase(countName,
633                                                                              '',
634                                                                              es3fInstancedRenderingTests.DrawFunction[_function],
635                                                                              es3fInstancedRenderingTests.InstancingType[instancingType],
636                                                                              gluShaderUtil.DataType.FLOAT,
637                                                                              instanceCounts[countNdx]));
638                 }
639             }
640         }
642         /** @type {Array<gluShaderUtil.DataType>} */ var s_testTypes =
643         [
644             gluShaderUtil.DataType.FLOAT,
645             gluShaderUtil.DataType.FLOAT_VEC2,
646             gluShaderUtil.DataType.FLOAT_VEC3,
647             gluShaderUtil.DataType.FLOAT_VEC4,
648             gluShaderUtil.DataType.FLOAT_MAT2,
649             gluShaderUtil.DataType.FLOAT_MAT2X3,
650             gluShaderUtil.DataType.FLOAT_MAT2X4,
651             gluShaderUtil.DataType.FLOAT_MAT3X2,
652             gluShaderUtil.DataType.FLOAT_MAT3,
653             gluShaderUtil.DataType.FLOAT_MAT3X4,
654             gluShaderUtil.DataType.FLOAT_MAT4X2,
655             gluShaderUtil.DataType.FLOAT_MAT4X3,
656             gluShaderUtil.DataType.FLOAT_MAT4,
658             gluShaderUtil.DataType.INT,
659             gluShaderUtil.DataType.INT_VEC2,
660             gluShaderUtil.DataType.INT_VEC3,
661             gluShaderUtil.DataType.INT_VEC4,
663             gluShaderUtil.DataType.UINT,
664             gluShaderUtil.DataType.UINT_VEC2,
665             gluShaderUtil.DataType.UINT_VEC3,
666             gluShaderUtil.DataType.UINT_VEC4
667         ];
669         /** @type {number} */ var typeTestNumInstances = 4;
671         /** @type {tcuTestCase.DeqpTest} */ var typesGroup = tcuTestCase.newTest('types', 'Tests for instanced attributes of particular data types');
673         testGroup.addChild(typesGroup);
675         for (var typeNdx in s_testTypes) {
676             /** @type {gluShaderUtil.DataType} */ var type = s_testTypes[typeNdx];
677             typesGroup.addChild(new es3fInstancedRenderingTests.InstancedRenderingCase(gluShaderUtil.getDataTypeName(type), '',
678                                                             es3fInstancedRenderingTests.DrawFunction.FUNCTION_DRAW_ARRAYS_INSTANCED,
679                                                             es3fInstancedRenderingTests.InstancingType.TYPE_ATTRIB_DIVISOR,
680                                                             type,
681                                                             typeTestNumInstances));
682         }
683     };
685     es3fInstancedRenderingTests.run = function(context) {
686         gl = context;
687         //Set up Test Root parameters
688         var testName = 'instanced_rendering';
689         var testDescription = 'Instanced Rendering Tests';
690         var state = tcuTestCase.runner;
692         state.testName = testName;
693         state.setRoot(tcuTestCase.newTest(testName, testDescription, null));
695         //Set up name and description of this test series.
696         setCurrentTestName(testName);
697         description(testDescription);
699         try {
700             //Create test cases
701             es3fInstancedRenderingTests.init();
702             //Run test cases
703             tcuTestCase.runTestCases();
704         }
705         catch (err) {
706             testFailedOptions('Failed to es3fInstancedRenderingTests.run tests', false);
707             tcuTestCase.runner.terminate();
708         }
709     };