tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

es3fInstancedRenderingTests.js (40461B)


      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 */
     20 
     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');
     32 
     33 goog.scope(function() {
     34 
     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;
     45 
     46    /** @type {?WebGL2RenderingContext} */ var gl;
     47 
     48    /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_WIDTH = 128;
     49    /** @const @type {number} */ es3fInstancedRenderingTests.MAX_RENDER_HEIGHT = 128;
     50 
     51    /** @const @type {number} */ es3fInstancedRenderingTests.QUAD_GRID_SIZE = 127;
     52 
     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;
     57 
     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.
     59 
     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;
     65 
     66    var DE_ASSERT = function(expression) {
     67        if (!expression) throw new Error('Assert failed');
     68    };
     69 
     70    es3fInstancedRenderingTests.TCU_FAIL = function(message) {
     71        throw new Error(message);
     72    };
     73 
     74    // es3fInstancedRenderingTests.InstancedRenderingCase
     75 
     76    /**
     77     * es3fInstancedRenderingTests.DrawFunction
     78     * @enum {number}
     79     */
     80    es3fInstancedRenderingTests.DrawFunction = {
     81            FUNCTION_DRAW_ARRAYS_INSTANCED: 0,
     82            FUNCTION_DRAW_ELEMENTS_INSTANCED: 1
     83    };
     84 
     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    };
     94 
     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    };
    120 
    121    es3fInstancedRenderingTests.InstancedRenderingCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    122    es3fInstancedRenderingTests.InstancedRenderingCase.prototype.constructor = es3fInstancedRenderingTests.InstancedRenderingCase;
    123 
    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    };
    143 
    144    es3fInstancedRenderingTests.InstancedRenderingCase.prototype.init = function() {
    145        // Clear errors from previous tests
    146        gl.getError();
    147 
    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);
    156 
    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) + ')';
    161 
    162        DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase);
    163 
    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.
    166 
    167        /** @type {string} */ var numInstancesStr = this.m_numInstances.toString() + '.0';
    168 
    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 = '';
    174 
    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;
    178 
    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        }
    184 
    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';
    188 
    189                DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4);
    190 
    191                for (var i = 0; i < 4 - es3fInstancedRenderingTests.OFFSET_COMPONENTS; i++)
    192                    posExpression += ', 0.0';
    193                posExpression += ')';
    194 
    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);
    205 
    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            }
    209 
    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);
    224 
    225            instanceAttribs += 'in mediump ' + typeName + ' a_instanceG;\n';
    226            instanceAttribs += 'in mediump ' + typeName + ' a_instanceB;\n';
    227        }
    228 
    229        DE_ASSERT(!(posExpression.length == 0));
    230        DE_ASSERT(!(colorRExpression.length == 0));
    231        DE_ASSERT(!(colorGExpression.length == 0));
    232        DE_ASSERT(!(colorBExpression.length == 0));
    233 
    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';
    248 
    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';
    258 
    259        // Create shader program and log it.
    260 
    261        DE_ASSERT(!this.m_program);
    262        this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertShaderSourceStr, fragShaderSource));
    263 
    264        //tcu::TestLog& log = this.m_testCtx.getLog();
    265        //log << *m_program;
    266        // TODO: bufferedLogToConsole?
    267        //bufferedLogToConsole(this.m_program);
    268 
    269        assertMsgOptions(this.m_program.isOk(), 'Failed to compile shader', false, true);
    270 
    271        // Vertex shader attributes.
    272 
    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>.
    275 
    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;
    280 
    281                    this.m_gridVertexPositions.push(fx);
    282                    this.m_gridVertexPositions.push(fy);
    283                }
    284 
    285            // Indices.
    286 
    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;
    293 
    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);
    298 
    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);
    306 
    307            // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
    308 
    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;
    315 
    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);
    323 
    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        }
    333 
    334        // Instanced attributes: position offset and color RGB components.
    335 
    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);
    341 
    342                    DE_ASSERT(es3fInstancedRenderingTests.OFFSET_COMPONENTS >= 1 && es3fInstancedRenderingTests.OFFSET_COMPONENTS <= 4);
    343 
    344                    for (var j = 0; j < es3fInstancedRenderingTests.OFFSET_COMPONENTS - 1; j++)
    345                        this.m_instanceOffsets.push(0.0);
    346                }
    347 
    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);
    351 
    352                    for (var j = 0; j < typeSize - 1; j++)
    353                        this.pushVarCompAttrib(this.m_instanceColorR, 0.0);
    354                }
    355            }
    356 
    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);
    360 
    361                for (var j = 0; j < typeSize - 1; j++)
    362                    this.pushVarCompAttrib(this.m_instanceColorG, 0.0);
    363            }
    364 
    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);
    368 
    369                for (var j = 0; j < typeSize - 1; j++)
    370                    this.pushVarCompAttrib(this.m_instanceColorB, 0.0);
    371            }
    372        }
    373    };
    374 
    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    };
    382 
    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);
    386 
    387        /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
    388        /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
    389 
    390        /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
    391 
    392        /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
    393        /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
    394 
    395        /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(width, height);
    396        /** @type {tcuSurface.Surface} */ var resultImg = new tcuSurface.Surface(width, height);
    397 
    398        // Draw result.
    399 
    400        gl.viewport(xOffset, yOffset, width, height);
    401        gl.clear(gl.COLOR_BUFFER_BIT);
    402 
    403        this.setupAndRender();
    404 
    405        var resImg = resultImg.getAccess();
    406        var resImgTransferFormat = gluTextureUtil.getTransferFormat(resImg.getFormat());
    407 
    408        gl.readPixels(xOffset, yOffset, resImg.m_width, resImg.m_height, resImgTransferFormat.format, resImgTransferFormat.dataType, resultImg.m_pixels);
    409 
    410        // Compute reference.
    411        this.computeReference(referenceImg);
    412 
    413        // Compare.
    414 
    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*/);
    417 
    418        assertMsgOptions(testOk, '', true, false);
    419 
    420        return tcuTestCase.IterateResult.STOP;
    421    };
    422 
    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.
    435 
    436        for (var slotNdx = 0; slotNdx < numSlots; slotNdx++) {
    437            /** @type {number} */ var curLoc = location + slotNdx;
    438 
    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);
    446 
    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);
    452 
    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);
    458 
    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);
    463 
    464                var bufferCurLoc = new Float32Array(attrPtr);
    465                gl.bindBuffer(gl.ARRAY_BUFFER, curLocGlBuffer);
    466                gl.bufferData(gl.ARRAY_BUFFER, bufferCurLoc, gl.STATIC_DRAW);
    467 
    468                gl.vertexAttribPointer(curLoc, numRows, gl.FLOAT, false, numCols * numRows * 4, 0);
    469            } else
    470                DE_ASSERT(false);
    471        }
    472    };
    473 
    474    es3fInstancedRenderingTests.InstancedRenderingCase.prototype.setupAndRender = function() {
    475        /** @type {WebGLProgram} */ var program = this.m_program.getProgram();
    476 
    477        gl.useProgram(program);
    478        // Setup attributes.
    479 
    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);
    488 
    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);
    495 
    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);
    500 
    501                gl.vertexAttribPointer(offsetLoc, es3fInstancedRenderingTests.OFFSET_COMPONENTS, gl.FLOAT, false, 0, 0);
    502 
    503                /** @type {number} */ var rLoc = gl.getAttribLocation(program, 'a_instanceR');
    504                this.setupVarAttribPointer(this.m_instanceColorR, rLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_R);
    505            }
    506 
    507            /** @type {number} */ var gLoc = gl.getAttribLocation(program, 'a_instanceG');
    508            this.setupVarAttribPointer(this.m_instanceColorG, gLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_G);
    509 
    510            /** @type {number} */ var bLoc = gl.getAttribLocation(program, 'a_instanceB');
    511            this.setupVarAttribPointer(this.m_instanceColorB, bLoc, es3fInstancedRenderingTests.ATTRIB_DIVISOR_B);
    512        }
    513 
    514        // Draw using appropriate function.
    515 
    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);
    524 
    525            gl.drawElementsInstanced(gl.TRIANGLES, this.m_gridIndices.length, gl.UNSIGNED_SHORT, 0, this.m_numInstances);
    526        }
    527        gl.useProgram(null);
    528    };
    529 
    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();
    536 
    537        // Draw a rectangle (vertical bar) for each instance.
    538 
    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);
    542 
    543            // Emulate attribute divisors if that is the case.
    544 
    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;
    548 
    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;
    552 
    553            // Calculate colors.
    554 
    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;
    558 
    559            // Convert to integer and back if shader inputs are integers.
    560 
    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            }
    576 
    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);
    580 
    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    };
    587 
    588    es3fInstancedRenderingTests.init = function() {
    589        var testGroup = tcuTestCase.runner.testCases;
    590    /** @type {Array<number>} */ var instanceCounts = [1, 2, 4, 20];
    591 
    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;
    597 
    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;
    602 
    603            DE_ASSERT(functionName != null);
    604            DE_ASSERT(functionDesc != null);
    605 
    606            /** @type {tcuTestCase.DeqpTest} */ var functionGroup = tcuTestCase.newTest(functionName, functionDesc);
    607            testGroup.addChild(functionGroup);
    608 
    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;
    615 
    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;
    621 
    622                DE_ASSERT(instancingTypeName != null);
    623                DE_ASSERT(instancingTypeDesc != null);
    624 
    625                /** @type {tcuTestCase.DeqpTest} */
    626                var instancingTypeGroup = tcuTestCase.newTest(instancingTypeName, instancingTypeDesc);
    627 
    628                functionGroup.addChild(instancingTypeGroup);
    629 
    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        }
    641 
    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,
    657 
    658            gluShaderUtil.DataType.INT,
    659            gluShaderUtil.DataType.INT_VEC2,
    660            gluShaderUtil.DataType.INT_VEC3,
    661            gluShaderUtil.DataType.INT_VEC4,
    662 
    663            gluShaderUtil.DataType.UINT,
    664            gluShaderUtil.DataType.UINT_VEC2,
    665            gluShaderUtil.DataType.UINT_VEC3,
    666            gluShaderUtil.DataType.UINT_VEC4
    667        ];
    668 
    669        /** @type {number} */ var typeTestNumInstances = 4;
    670 
    671        /** @type {tcuTestCase.DeqpTest} */ var typesGroup = tcuTestCase.newTest('types', 'Tests for instanced attributes of particular data types');
    672 
    673        testGroup.addChild(typesGroup);
    674 
    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    };
    684 
    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;
    691 
    692        state.testName = testName;
    693        state.setRoot(tcuTestCase.newTest(testName, testDescription, null));
    694 
    695        //Set up name and description of this test series.
    696        setCurrentTestName(testName);
    697        description(testDescription);
    698 
    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    };
    710 
    711 });