tor-browser

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

es3fPrimitiveRestartTests.js (34632B)


      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.es3fPrimitiveRestartTests');
     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.gluTextureUtil');
     31 
     32 goog.scope(function() {
     33 
     34 var es3fPrimitiveRestartTests = functional.gles3.es3fPrimitiveRestartTests;
     35 var tcuTestCase = framework.common.tcuTestCase;
     36 var gluShaderProgram = framework.opengl.gluShaderProgram;
     37 var tcuSurface = framework.common.tcuSurface;
     38 var deMath = framework.delibs.debase.deMath;
     39 var deRandom = framework.delibs.debase.deRandom;
     40 var deString = framework.delibs.debase.deString;
     41 var tcuImageCompare = framework.common.tcuImageCompare;
     42 var gluTextureUtil = framework.opengl.gluTextureUtil;
     43 
     44    /** @type {WebGL2RenderingContext} */ var gl;
     45    /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_RENDER_WIDTH = 256;
     46    /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_RENDER_HEIGHT = 256;
     47 
     48    /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE = 255;
     49    /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT = 65535;
     50    /** @const @type {number} */ es3fPrimitiveRestartTests.MAX_UNSIGNED_INT = 4294967295;
     51 
     52    /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE = es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE;
     53    /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT = es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT;
     54    /** @const @type {number} */ es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT = es3fPrimitiveRestartTests.MAX_UNSIGNED_INT;
     55 
     56    var DE_ASSERT = function(expression) {
     57        if (!expression) throw new Error('Assert failed');
     58    };
     59 
     60    /**
     61     * @enum
     62     */
     63    es3fPrimitiveRestartTests.PrimitiveType = {
     64        PRIMITIVE_POINTS: 0,
     65        PRIMITIVE_LINE_STRIP: 1,
     66        PRIMITIVE_LINE_LOOP: 2,
     67        PRIMITIVE_LINES: 3,
     68        PRIMITIVE_TRIANGLE_STRIP: 4,
     69        PRIMITIVE_TRIANGLE_FAN: 5,
     70        PRIMITIVE_TRIANGLES: 6
     71    };
     72 
     73    /**
     74     * @enum
     75     */
     76    es3fPrimitiveRestartTests.IndexType = {
     77        INDEX_UNSIGNED_BYTE: 0,
     78        INDEX_UNSIGNED_SHORT: 1,
     79        INDEX_UNSIGNED_INT: 2
     80    };
     81 
     82    /**
     83     * @enum
     84     */
     85    es3fPrimitiveRestartTests.DrawFunction = {
     86        FUNCTION_DRAW_ELEMENTS: 0,
     87        FUNCTION_DRAW_ELEMENTS_INSTANCED: 1,
     88        FUNCTION_DRAW_RANGE_ELEMENTS: 2
     89    };
     90 
     91    /**
     92    * es3fPrimitiveRestartTests.PrimitiveRestartCase class, inherits from TestCase class
     93    * @constructor
     94    * @extends {tcuTestCase.DeqpTest}
     95    * @param {?string} name
     96    * @param {string} description
     97    * @param {es3fPrimitiveRestartTests.PrimitiveType} primType
     98    * @param {es3fPrimitiveRestartTests.IndexType} indexType
     99    * @param {es3fPrimitiveRestartTests.DrawFunction} _function
    100    * @param {boolean} beginWithRestart
    101    * @param {boolean} endWithRestart
    102    * @param {boolean} duplicateRestarts
    103    */
    104    es3fPrimitiveRestartTests.PrimitiveRestartCase = function(name, description, primType, indexType, _function, beginWithRestart, endWithRestart, duplicateRestarts) {
    105        tcuTestCase.DeqpTest.call(this, name, description);
    106        /** @type {es3fPrimitiveRestartTests.PrimitiveType} */ this.m_primType = primType;
    107        /** @type {es3fPrimitiveRestartTests.IndexType} */ this.m_indexType = indexType;
    108        /** @type {es3fPrimitiveRestartTests.DrawFunction} */ this.m_function = _function;
    109        /** @type {boolean} */ this.m_beginWithRestart = beginWithRestart; // Whether there will be restart indices at the beginning of the index array.
    110        /** @type {boolean} */ this.m_endWithRestart = endWithRestart; // Whether there will be restart indices at the end of the index array.
    111        /** @type {boolean} */ this.m_duplicateRestarts = duplicateRestarts; // Whether two consecutive restarts are used instead of one.
    112        /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
    113 
    114        // \note Only one of the following index vectors is used (according to m_indexType).
    115        /** @type {Array<number>} */ this.m_indicesUB = []; //deUint8
    116        /** @type {Array<number>} */ this.m_indicesUS = []; //deUint16
    117        /** @type {Array<number>} */ this.m_indicesUI = []; //deUint32
    118 
    119        /** @type {Array<number>} */ this.m_positions = [];
    120    };
    121 
    122    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    123    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.constructor = es3fPrimitiveRestartTests.PrimitiveRestartCase;
    124 
    125    /**
    126    * Draw with the appropriate GLES3 draw function.
    127    * @param {number} startNdx
    128    * @param {number} count
    129    */
    130    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.draw = function(startNdx, count) {
    131        /** @type {number} */ var primTypeGL;
    132 
    133        switch (this.m_primType) {
    134            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS:
    135                primTypeGL = gl.POINTS;
    136                break;
    137            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP:
    138                primTypeGL = gl.LINE_STRIP;
    139                break;
    140            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP:
    141                primTypeGL = gl.LINE_LOOP;
    142                break;
    143            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES:
    144                primTypeGL = gl.LINES;
    145                break;
    146            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP:
    147                primTypeGL = gl.TRIANGLE_STRIP;
    148                break;
    149            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN:
    150                primTypeGL = gl.TRIANGLE_FAN;
    151                break;
    152            case es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES:
    153                primTypeGL = gl.TRIANGLES;
    154                break;
    155            default:
    156                DE_ASSERT(false);
    157                primTypeGL = 0;
    158        }
    159 
    160        /** @type {number} */ var indexTypeGL;
    161 
    162        switch (this.m_indexType) {
    163            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
    164                indexTypeGL = gl.UNSIGNED_BYTE;
    165                break;
    166            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
    167                indexTypeGL = gl.UNSIGNED_SHORT;
    168                break;
    169            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
    170                indexTypeGL = gl.UNSIGNED_INT;
    171                break;
    172            default:
    173                DE_ASSERT(false);
    174                indexTypeGL = 0;
    175        }
    176 
    177        /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
    178                                                   this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
    179                                                   this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
    180                                                   0;
    181 
    182        DE_ASSERT(restartIndex != 0);
    183 
    184        var indexGLBuffer = gl.createBuffer();
    185        var bufferIndex = this.getIndexPtr(startNdx);
    186        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexGLBuffer);
    187        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferIndex, gl.STATIC_DRAW);
    188 
    189        if (this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS) {
    190            gl.drawElements(primTypeGL, count, indexTypeGL, 0);
    191        } else if (this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED) {
    192            gl.drawElementsInstanced(primTypeGL, count, indexTypeGL, 0, 1);
    193        } else {
    194            DE_ASSERT(this.m_function == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_RANGE_ELEMENTS);
    195 
    196            // Find the largest non-restart index in the index array (for glDrawRangeElements() end parameter).
    197 
    198            /** @type {number} */ var max = 0;
    199 
    200            /** @type {number} */ var numIndices = this.getNumIndices();
    201            for (var i = 0; i < numIndices; i++) {
    202                /** @type {number} */ var index = this.getIndex(i);
    203                if (index != restartIndex && index > max)
    204                    max = index;
    205            }
    206            //TODO: drawRangeElements -> check getIndexPtr usage
    207            gl.drawRangeElements(primTypeGL, 0, max, count, indexTypeGL, 0);
    208        }
    209    };
    210 
    211    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.renderWithRestart = function() {
    212        // Primitive Restart is always on in WebGL2
    213        //gl.enable(gl.PRIMITIVE_RESTART_FIXED_INDEX);
    214 
    215        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
    216 
    217        this.draw(0, this.getNumIndices());
    218    };
    219 
    220    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.renderWithoutRestart = function() {
    221        /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
    222                                                 this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
    223                                                 this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
    224                                                 0;
    225 
    226        DE_ASSERT(restartIndex != 0);
    227        // Primitive Restart is always on in WebGL2
    228        //gl.disable(gl.PRIMITIVE_RESTART_FIXED_INDEX);
    229 
    230        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
    231 
    232        // Draw, emulating primitive restart.
    233 
    234        /** @type {number} */ var numIndices = this.getNumIndices();
    235 
    236        DE_ASSERT(numIndices >= 0);
    237 
    238        /** @type {number} */ var indexArrayStartNdx = 0; // Keep track of the draw start index - first index after a primitive restart, or initially the first index altogether.
    239 
    240        for (var indexArrayNdx = 0; indexArrayNdx <= numIndices; indexArrayNdx++) { // \note Goes one "too far" in order to detect end of array as well.
    241            if (indexArrayNdx >= numIndices || this.getIndex(indexArrayNdx) == restartIndex) {// \note Handle end of array the same way as a restart index encounter.
    242                if (indexArrayStartNdx < numIndices) {
    243                    // Draw from index indexArrayStartNdx to index indexArrayNdx-1 .
    244 
    245                    this.draw(indexArrayStartNdx, indexArrayNdx - indexArrayStartNdx);
    246                }
    247 
    248                indexArrayStartNdx = indexArrayNdx + 1; // Next draw starts just after this restart index.
    249            }
    250        }
    251    };
    252 
    253    /**
    254    * @param {number} index
    255    */
    256    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.addIndex = function(index) {
    257        if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE) {
    258            DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_BYTE));
    259            this.m_indicesUB.push(index); // deUint8
    260        } else if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT) {
    261            DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_SHORT));
    262            this.m_indicesUS.push(index); // deUint16
    263        } else if (this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT) {
    264            DE_ASSERT(deMath.deInRange32(index, 0, es3fPrimitiveRestartTests.MAX_UNSIGNED_INT));
    265            this.m_indicesUI.push(index); // // deUint32
    266        } else
    267            DE_ASSERT(false);
    268    };
    269 
    270    /**
    271    * @param {number} indexNdx
    272    * @return {number}
    273    */
    274    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getIndex = function(indexNdx) {
    275        switch (this.m_indexType) {
    276            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
    277                return this.m_indicesUB[indexNdx]; //deUint32
    278            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
    279                return this.m_indicesUS[indexNdx]; //deUint32
    280            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
    281                return this.m_indicesUI[indexNdx];
    282            default:
    283                DE_ASSERT(false);
    284                return 0;
    285        }
    286    };
    287 
    288    /**
    289    * @return {number}
    290    */
    291    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getNumIndices = function() {
    292        switch (this.m_indexType) {
    293            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
    294                return this.m_indicesUB.length;
    295            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
    296                return this.m_indicesUS.length;
    297            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
    298                return this.m_indicesUI.length;
    299            default:
    300                DE_ASSERT(false);
    301                return 0;
    302        }
    303    };
    304 
    305    /**
    306    * Pointer to the index value at index indexNdx.
    307    * @param {number} indexNdx
    308    * @return {Uint8Array|Uint16Array|Uint32Array}
    309    */
    310    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.getIndexPtr = function(indexNdx) {
    311        //TODO: implement
    312        switch (this.m_indexType) {
    313            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE:
    314                return new Uint8Array(this.m_indicesUB).subarray(indexNdx);
    315            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT:
    316                return new Uint16Array(this.m_indicesUS).subarray(indexNdx);
    317            case es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT:
    318                return new Uint32Array(this.m_indicesUI).subarray(indexNdx);
    319            default:
    320                DE_ASSERT(false);
    321                return null;
    322        }
    323    };
    324 
    325    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.init = function() {
    326        // Clear errors from previous tests
    327        gl.getError();
    328 
    329        // Create shader program.
    330 
    331        /** @type {string} */ var vertShaderSource =
    332            '#version 300 es\n' +
    333            'in highp vec4 a_position;\n' +
    334            '\n' +
    335            'void main()\n' +
    336            ' {\n' +
    337            ' gl_Position = a_position;\n';
    338 
    339        if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS) {
    340            vertShaderSource += ' gl_PointSize = 1.0;\n';
    341        }
    342 
    343        vertShaderSource += '}\n';
    344 
    345        /** @type {string} */ var fragShaderSource =
    346            '#version 300 es\n' +
    347            'layout(location = 0) out mediump vec4 o_color;\n' +
    348            '\n' +
    349            'void main()\n' +
    350            ' {\n' +
    351            ' o_color = vec4(1.0f);\n' +
    352            '}\n';
    353 
    354        DE_ASSERT(!this.m_program);
    355 
    356        this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vertShaderSource, fragShaderSource));
    357 
    358        if (!this.m_program.isOk()) {
    359            //m_testCtx.getLog() << *this.m_program;
    360            testFailedOptions('Failed to compile shader', true);
    361        }
    362 
    363        /** @type {number} */ var restartIndex = this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_BYTE :
    364                                                 this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_SHORT :
    365                                                 this.m_indexType == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? es3fPrimitiveRestartTests.RESTART_INDEX_UNSIGNED_INT :
    366                                                 0;
    367 
    368        DE_ASSERT(restartIndex != 0);
    369 
    370        DE_ASSERT(this.getNumIndices() == 0);
    371 
    372        // If testing a case with restart at beginning, add it there.
    373        if (this.m_beginWithRestart) {
    374            this.addIndex(restartIndex);
    375            if (this.m_duplicateRestarts)
    376                this.addIndex(restartIndex);
    377        }
    378 
    379        // Generate vertex positions and indices depending on primitive type.
    380        // \note At this point, restarts shall not be added to the start or the end of the index vector. Those are special cases, and are done above and after the following if-else chain, respectively.
    381        /** @type {number} */ var curIndex;
    382        /** @type {number} */ var numRows;
    383        /** @type {number} */ var numCols;
    384        /** @type {number} */ var fx;
    385        /** @type {number} */ var fy;
    386        /** @type {number} */ var centerY;
    387        /** @type {number} */ var centerX;
    388        /** @type {number} */ var numVertices;
    389        /** @type {number} */ var numArcVertices;
    390        /** @type {number} */ var numStrips;
    391 
    392        if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS) {
    393            // Generate rows with different numbers of points.
    394 
    395            curIndex = 0;
    396            numRows = 20;
    397 
    398            for (var row = 0; row < numRows; row++) {
    399                for (var col = 0; col < row + 1; col++) {
    400                    fx = -1.0 + 2.0 * (col + 0.5) / numRows;
    401                    fy = -1.0 + 2.0 * (row + 0.5) / numRows;
    402 
    403                    this.m_positions.push(fx);
    404                    this.m_positions.push(fy);
    405 
    406                    this.addIndex(curIndex++);
    407                }
    408 
    409                if (row < numRows - 1) { // Add a restart after all but last row.
    410                    this.addIndex(restartIndex);
    411                    if (this.m_duplicateRestarts)
    412                        this.addIndex(restartIndex);
    413                }
    414            }
    415        } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP || this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP || this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES) {
    416            // Generate a numRows x numCols arrangement of line polygons of different vertex counts.
    417 
    418            curIndex = 0;
    419            numRows = 4;
    420            numCols = 4;
    421 
    422            for (var row = 0; row < numRows; row++) {
    423                centerY = -1.0 + 2.0 * (row + 0.5) / numRows;
    424 
    425                for (var col = 0; col < numCols; col++) {
    426                    centerX = -1.0 + 2.0 * (col + 0.5) / numCols;
    427                    numVertices = row * numCols + col + 1;
    428 
    429                    for (var i = 0; i < numVertices; i++) {
    430                        fx = centerX + 0.9 * Math.cos(i * 2.0 * Math.PI / numVertices) / numCols;
    431                        fy = centerY + 0.9 * Math.sin(i * 2.0 * Math.PI / numVertices) / numRows;
    432 
    433                        this.m_positions.push(fx);
    434                        this.m_positions.push(fy);
    435 
    436                        this.addIndex(curIndex++);
    437                    }
    438 
    439                    if (col < numCols - 1 || row < numRows - 1) {// Add a restart after all but last polygon.
    440                        this.addIndex(restartIndex);
    441                        if (this.m_duplicateRestarts)
    442                            this.addIndex(restartIndex);
    443                    }
    444                }
    445            }
    446        } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP) {
    447            // Generate a number of horizontal triangle strips of different lengths.
    448 
    449            curIndex = 0;
    450            numStrips = 20;
    451 
    452            for (var stripNdx = 0; stripNdx < numStrips; stripNdx++) {
    453                numVertices = stripNdx + 1;
    454 
    455                for (var i = 0; i < numVertices; i++) {
    456                    fx = -0.9 + 1.8 * (i / 2 * 2) / numStrips;
    457                    fy = -0.9 + 1.8 * (stripNdx + (i % 2 == 0 ? 0.0 : 0.8)) / numStrips;
    458 
    459                    this.m_positions.push(fx);
    460                    this.m_positions.push(fy);
    461 
    462                    this.addIndex(curIndex++);
    463                }
    464 
    465                if (stripNdx < numStrips - 1) { // Add a restart after all but last strip.
    466                    this.addIndex(restartIndex);
    467                    if (this.m_duplicateRestarts)
    468                        this.addIndex(restartIndex);
    469                }
    470            }
    471        } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN) {
    472            // Generate a numRows x numCols arrangement of triangle fan polygons of different vertex counts.
    473 
    474            curIndex = 0;
    475            numRows = 4;
    476            numCols = 4;
    477 
    478            for (var row = 0; row < numRows; row++) {
    479                centerY = -1.0 + 2.0 * (row + 0.5) / numRows;
    480 
    481                for (var col = 0; col < numCols; col++) {
    482                    centerX = -1.0 + 2.0 * (col + 0.5) / numCols;
    483                    numArcVertices = row * numCols + col;
    484 
    485                    this.m_positions.push(centerX);
    486                    this.m_positions.push(centerY);
    487 
    488                    this.addIndex(curIndex++);
    489 
    490                    for (var i = 0; i < numArcVertices; i++) {
    491                        fx = centerX + 0.9 * Math.cos(i * 2.0 * Math.PI / numArcVertices) / numCols;
    492                        fy = centerY + 0.9 * Math.sin(i * 2.0 * Math.PI / numArcVertices) / numRows;
    493 
    494                        this.m_positions.push(fx);
    495                        this.m_positions.push(fy);
    496 
    497                        this.addIndex(curIndex++);
    498                    }
    499 
    500                    if (col < numCols - 1 || row < numRows - 1) { // Add a restart after all but last polygon.
    501                        this.addIndex(restartIndex);
    502                        if (this.m_duplicateRestarts)
    503                            this.addIndex(restartIndex);
    504                    }
    505                }
    506            }
    507        } else if (this.m_primType == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES) {
    508            // Generate a number of rows with (potentially incomplete) triangles.
    509 
    510            curIndex = 0;
    511            numRows = 3 * 7;
    512 
    513            for (var rowNdx = 0; rowNdx < numRows; rowNdx++) {
    514                numVertices = rowNdx + 1;
    515 
    516                for (var i = 0; i < numVertices; i++) {
    517                    fx = -0.9 + 1.8 * ((i / 3) + (i % 3 == 2 ? 0.8 : 0.0)) * 3 / numRows;
    518                    fy = -0.9 + 1.8 * (rowNdx + (i % 3 == 0 ? 0.0 : 0.8)) / numRows;
    519 
    520                    this.m_positions.push(fx);
    521                    this.m_positions.push(fy);
    522 
    523                    this.addIndex(curIndex++);
    524                }
    525 
    526                if (rowNdx < numRows - 1) { // Add a restart after all but last row.
    527                    this.addIndex(restartIndex);
    528                    if (this.m_duplicateRestarts)
    529                        this.addIndex(restartIndex);
    530                }
    531            }
    532        } else
    533            DE_ASSERT(false);
    534 
    535        // If testing a case with restart at end, add it there.
    536        if (this.m_endWithRestart) {
    537            this.addIndex(restartIndex);
    538            if (this.m_duplicateRestarts)
    539                this.addIndex(restartIndex);
    540        }
    541 
    542        // Special case assertions.
    543 
    544        /** @type {number} */ var numIndices = this.getNumIndices();
    545 
    546        DE_ASSERT(numIndices > 0);
    547        DE_ASSERT(this.m_beginWithRestart || this.getIndex(0) != restartIndex); // We don't want restarts at beginning unless the case is a special case.
    548        DE_ASSERT(this.m_endWithRestart || this.getIndex(numIndices - 1) != restartIndex); // We don't want restarts at end unless the case is a special case.
    549 
    550        if (!this.m_duplicateRestarts)
    551            for (var i = 1; i < numIndices; i++)
    552                DE_ASSERT(this.getIndex(i) != restartIndex || this.getIndex(i - 1) != restartIndex); // We don't want duplicate restarts unless the case is a special case.
    553 
    554    };
    555 
    556    es3fPrimitiveRestartTests.PrimitiveRestartCase.prototype.iterate = function() {
    557        /** @type {number} */ var width = Math.min(gl.drawingBufferWidth, es3fPrimitiveRestartTests.MAX_RENDER_WIDTH);
    558        /** @type {number} */ var height = Math.min(gl.drawingBufferHeight, es3fPrimitiveRestartTests.MAX_RENDER_HEIGHT);
    559 
    560        /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
    561        /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
    562 
    563        /** @type {deRandom.Random} */ var rnd = new deRandom.Random(deString.deStringHash(this.name));
    564 
    565        /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
    566        /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
    567        /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(width, height);
    568        /** @type {tcuSurface.Surface} */ var resultImg = new tcuSurface.Surface(width, height);
    569 
    570        gl.viewport(xOffset, yOffset, width, height);
    571        gl.clearColor(0.0, 0.0, 0.0, 1.0);
    572 
    573        var program = this.m_program.getProgram();
    574        gl.useProgram(program);
    575 
    576        // Setup position attribute.
    577 
    578        /** @type {number} */ var loc = gl.getAttribLocation(program, 'a_position');
    579        gl.enableVertexAttribArray(loc);
    580 
    581        var locGlBuffer = gl.createBuffer();
    582        var bufferLoc = new Float32Array(this.m_positions);
    583        gl.bindBuffer(gl.ARRAY_BUFFER, locGlBuffer);
    584        gl.bufferData(gl.ARRAY_BUFFER, bufferLoc, gl.STATIC_DRAW);
    585        gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
    586 
    587        // Render result.
    588        this.renderWithRestart();
    589        var resImg = resultImg.getAccess();
    590        var resImgTransferFormat = gluTextureUtil.getTransferFormat(resImg.getFormat());
    591        gl.readPixels(xOffset, yOffset, resImg.m_width, resImg.m_height, resImgTransferFormat.format, resImgTransferFormat.dataType, resultImg.m_pixels);
    592 
    593        // Render reference (same scene as the real deal, but emulate primitive restart without actually using it).
    594        this.renderWithoutRestart();
    595 
    596        var refImg = referenceImg.getAccess();
    597        var refImgTransferFormat = gluTextureUtil.getTransferFormat(refImg.getFormat());
    598 
    599        gl.readPixels(xOffset, yOffset, refImg.m_width, refImg.m_height, refImgTransferFormat.format, refImgTransferFormat.dataType, referenceImg.m_pixels);
    600 
    601        // Compare.
    602        /** @type {boolean} */ var testOk = tcuImageCompare.pixelThresholdCompare('ComparisonResult', 'Image comparison result', referenceImg, resultImg, [0, 0, 0, 0]);
    603 
    604        assertMsgOptions(testOk, '', true, false);
    605        gl.useProgram(null);
    606 
    607        return tcuTestCase.IterateResult.STOP;
    608    };
    609 
    610    es3fPrimitiveRestartTests.init = function() {
    611        var testGroup = tcuTestCase.runner.testCases;
    612        for (var isRestartBeginCaseI = 0; isRestartBeginCaseI <= 1; isRestartBeginCaseI++) {
    613            for (var isRestartEndCaseI = 0; isRestartEndCaseI <= 1; isRestartEndCaseI++) {
    614                for (var isDuplicateRestartCaseI = 0; isDuplicateRestartCaseI <= 1; isDuplicateRestartCaseI++) {
    615                    /** @type {boolean} */ var isRestartBeginCase = isRestartBeginCaseI != 0;
    616                    /** @type {boolean} */ var isRestartEndCase = isRestartEndCaseI != 0;
    617                    /** @type {boolean} */ var isDuplicateRestartCase = isDuplicateRestartCaseI != 0;
    618 
    619                    /** @type {string} */ var specialCaseGroupName = '';
    620 
    621                    if (isRestartBeginCase) specialCaseGroupName = 'begin_restart';
    622                    if (isRestartEndCase) specialCaseGroupName += (deString.deIsStringEmpty(specialCaseGroupName) ? '' : '_') + 'end_restart';
    623                    if (isDuplicateRestartCase) specialCaseGroupName += (deString.deIsStringEmpty(specialCaseGroupName) ? '' : '_') + 'duplicate_restarts';
    624 
    625                    if (deString.deIsStringEmpty(specialCaseGroupName))
    626                        specialCaseGroupName = 'basic';
    627 
    628                    /** @type {tcuTestCase.DeqpTest} */ var specialCaseGroup = tcuTestCase.newTest(specialCaseGroupName, '');
    629                    testGroup.addChild(specialCaseGroup);
    630 
    631                    for (var primType in es3fPrimitiveRestartTests.PrimitiveType) {
    632                        /** @type {string} */ var primTypeName = es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_POINTS ? 'points' :
    633                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_STRIP ? 'line_strip' :
    634                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINE_LOOP ? 'line_loop' :
    635                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_LINES ? 'lines' :
    636                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_STRIP ? 'triangle_strip' :
    637                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLE_FAN ? 'triangle_fan' :
    638                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType] == es3fPrimitiveRestartTests.PrimitiveType.PRIMITIVE_TRIANGLES ? 'triangles' :
    639                                                                 '';
    640 
    641                        DE_ASSERT(primTypeName != null);
    642 
    643                        /** @type {tcuTestCase.DeqpTest} */ var primTypeGroup = tcuTestCase.newTest(primTypeName, '');
    644                        specialCaseGroup.addChild(primTypeGroup);
    645 
    646                        for (var indexType in es3fPrimitiveRestartTests.IndexType) {
    647                            /** @type {string} */ var indexTypeName = es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_BYTE ? 'unsigned_byte' :
    648                                                                      es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_SHORT ? 'unsigned_short' :
    649                                                                      es3fPrimitiveRestartTests.IndexType[indexType] == es3fPrimitiveRestartTests.IndexType.INDEX_UNSIGNED_INT ? 'unsigned_int' :
    650                                                                      '';
    651 
    652                            DE_ASSERT(indexTypeName != null);
    653 
    654                            /** @type {tcuTestCase.DeqpTest} */ var indexTypeGroup = tcuTestCase.newTest(indexTypeName, '');
    655                            primTypeGroup.addChild(indexTypeGroup);
    656 
    657                            for (var _function in es3fPrimitiveRestartTests.DrawFunction) {
    658                                /** @type {?string} */ var functionName = es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS ? 'draw_elements' :
    659                                                                         es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_ELEMENTS_INSTANCED ? 'draw_elements_instanced' :
    660                                                                         es3fPrimitiveRestartTests.DrawFunction[_function] == es3fPrimitiveRestartTests.DrawFunction.FUNCTION_DRAW_RANGE_ELEMENTS ? 'draw_range_elements' :
    661                                                                         null;
    662 
    663                                DE_ASSERT(functionName != null);
    664 
    665                                indexTypeGroup.addChild(new es3fPrimitiveRestartTests.PrimitiveRestartCase(functionName,
    666                                                                                 '',
    667                                                                                 es3fPrimitiveRestartTests.PrimitiveType[primType],
    668                                                                                 es3fPrimitiveRestartTests.IndexType[indexType],
    669                                                                                 es3fPrimitiveRestartTests.DrawFunction[_function],
    670                                                                                 isRestartBeginCase,
    671                                                                                 isRestartEndCase,
    672                                                                                 isDuplicateRestartCase));
    673                            }
    674                        }
    675                    }
    676                }
    677            }
    678        }
    679    };
    680 
    681    es3fPrimitiveRestartTests.run = function(context, range) {
    682        gl = context;
    683        //Set up Test Root parameters
    684        var testName = 'primitive_restart';
    685        var testDescription = 'Primitive Restart Tests';
    686        var state = tcuTestCase.runner;
    687 
    688        state.testName = testName;
    689        state.setRoot(tcuTestCase.newTest(testName, testDescription, null));
    690 
    691        //Set up name and description of this test series.
    692        setCurrentTestName(testName);
    693        description(testDescription);
    694 
    695        try {
    696            //Create test cases
    697            es3fPrimitiveRestartTests.init();
    698            if (range)
    699                state.setRange(range);
    700            //Run test cases
    701            tcuTestCase.runTestCases();
    702        }
    703        catch (err) {
    704            testFailedOptions('Failed to es3fPrimitiveRestartTests.run tests', false);
    705            tcuTestCase.runner.terminate();
    706        }
    707    };
    708 
    709 });