tor-browser

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

es3fTransformFeedbackTests.js (86411B)


      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.es3fTransformFeedbackTests');
     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.gluDrawUtil');
     30 goog.require('framework.opengl.gluShaderProgram');
     31 goog.require('framework.opengl.gluShaderUtil');
     32 goog.require('framework.opengl.gluVarType');
     33 goog.require('framework.opengl.gluVarTypeUtil');
     34 
     35 goog.scope(function() {
     36 
     37    var es3fTransformFeedbackTests = functional.gles3.es3fTransformFeedbackTests;
     38    var gluShaderUtil = framework.opengl.gluShaderUtil;
     39    var gluDrawUtil = framework.opengl.gluDrawUtil;
     40    var gluVarType = framework.opengl.gluVarType;
     41    var gluVarTypeUtil = framework.opengl.gluVarTypeUtil;
     42    var gluShaderProgram = framework.opengl.gluShaderProgram;
     43    var deRandom = framework.delibs.debase.deRandom;
     44    var deMath = framework.delibs.debase.deMath;
     45    var deString = framework.delibs.debase.deString;
     46    var tcuTestCase = framework.common.tcuTestCase;
     47    var tcuSurface = framework.common.tcuSurface;
     48    var tcuImageCompare = framework.common.tcuImageCompare;
     49 
     50    /** @type {WebGL2RenderingContext} */ var gl;
     51 
     52    var setParentClass = function(child, parent) {
     53        child.prototype = Object.create(parent.prototype);
     54        child.prototype.constructor = child;
     55    };
     56 
     57    /**
     58     * @enum
     59     */
     60    es3fTransformFeedbackTests.State = {
     61        DRAW: 0,
     62        VERIFY: 1,
     63        FINISH: 2
     64    };
     65 
     66    /* Maximum time to wait for query result (in seconds) */
     67    /** @const */ es3fTransformFeedbackTests.MAX_VERIFY_WAIT = 5;
     68 
     69    /** @const @type {number} */ es3fTransformFeedbackTests.VIEWPORT_WIDTH = 128;
     70    /** @const @type {number} */ es3fTransformFeedbackTests.VIEWPORT_HEIGHT = 128;
     71    /** @const @type {number} */ es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER = 2;
     72 
     73    /**
     74     * Enums for es3fTransformFeedbackTests.interpolation
     75     * @enum {number}
     76     */
     77    es3fTransformFeedbackTests.interpolation = {
     78        SMOOTH: 0,
     79        FLAT: 1,
     80        CENTROID: 2
     81 
     82    };
     83 
     84    /**
     85     * Returns es3fTransformFeedbackTests.interpolation name: smooth, flat or centroid
     86     * @param {number} interpol es3fTransformFeedbackTests.interpolation enum value
     87     * @return {string}
     88     */
     89    es3fTransformFeedbackTests.getInterpolationName = function(interpol) {
     90 
     91        switch (interpol) {
     92        case es3fTransformFeedbackTests.interpolation.SMOOTH: return 'smooth';
     93        case es3fTransformFeedbackTests.interpolation.FLAT: return 'flat';
     94        case es3fTransformFeedbackTests.interpolation.CENTROID: return 'centroid';
     95        default:
     96            throw new Error('Unrecognized es3fTransformFeedbackTests.interpolation name ' + interpol);
     97       }
     98 
     99    };
    100 
    101    /**
    102     * @struct
    103     * @param {string} name
    104     * @param {gluVarType.VarType} type
    105     * @param {number} interpolation
    106     * @constructor
    107     */
    108    es3fTransformFeedbackTests.Varying = function(name, type, interpolation) {
    109        this.name = name;
    110        this.type = type;
    111        this.interpolation = interpolation;
    112    };
    113 
    114    /** es3fTransformFeedbackTests.findAttributeNameEquals
    115     * Replaces original implementation of "VaryingNameEquals" and "AttributeNameEquals" in the C++ version
    116     * Returns an es3fTransformFeedbackTests.Attribute or es3fTransformFeedbackTests.Varying object which matches its name with the passed string value in the function
    117     * @param {(Array<es3fTransformFeedbackTests.Attribute> | Array<es3fTransformFeedbackTests.Varying>)} array
    118     * @param {string} name
    119     * @return { (es3fTransformFeedbackTests.Attribute | es3fTransformFeedbackTests.Varying | null)}
    120     */
    121    es3fTransformFeedbackTests.findAttributeNameEquals = function(array, name) {
    122        for (var pos = 0; pos < array.length; pos++) {
    123            if (array[pos].name === name) {
    124                return array[pos];
    125            }
    126        }
    127        return null;
    128    };
    129 
    130    /**
    131     * @struct
    132     * @param {string} name
    133     * @param {gluVarType.VarType} type
    134     * @param {number} offset
    135     * @constructor
    136     */
    137    es3fTransformFeedbackTests.Attribute = function(name, type, offset) {
    138        this.name = name;
    139        this.type = type;
    140        this.offset = offset;
    141    };
    142 
    143    /**
    144     * Constructs an es3fTransformFeedbackTests.Output object
    145     * @constructor
    146     */
    147    es3fTransformFeedbackTests.Output = function() {
    148        /** @type {number} */ this.bufferNdx = 0;
    149        /** @type {number} */ this.offset = 0;
    150        /** @type {string} */ this.name;
    151        /** @type {gluVarType.VarType} */ this.type = null;
    152        /** @type {Array<es3fTransformFeedbackTests.Attribute>} */ this.inputs = [];
    153    };
    154 
    155    /**
    156     * Constructs an object type es3fTransformFeedbackTests.DrawCall.
    157     * Contains the number of elements as well as whether the Transform Feedback is enabled or not.
    158     * @struct
    159     * @param {number} numElements
    160     * @param {boolean} tfEnabled is Transform Feedback enabled or not
    161     * @constructor
    162     */
    163    es3fTransformFeedbackTests.DrawCall = function(numElements, tfEnabled) {
    164        this.numElements = numElements;
    165        this.transformFeedbackEnabled = tfEnabled;
    166    };
    167 
    168    /**
    169     * @constructor
    170     */
    171    es3fTransformFeedbackTests.ProgramSpec = function() {
    172 
    173    /** @type {Array<gluVarType.StructType>} */ var m_structs = [];
    174    /** @type {Array<es3fTransformFeedbackTests.Varying>} */ var m_varyings = [];
    175    /** @type {Array<string>} */ var m_transformFeedbackVaryings = [];
    176 
    177        this.createStruct = function(name) {
    178            var struct = gluVarType.newStructType(name);
    179            m_structs.push(struct);
    180            return struct;
    181        };
    182 
    183        this.addVarying = function(name, type, interp) {
    184            m_varyings.push(new es3fTransformFeedbackTests.Varying(name, type, interp));
    185        };
    186 
    187        this.addTransformFeedbackVarying = function(name) {
    188            m_transformFeedbackVaryings.push(name);
    189        };
    190 
    191        this.getStructs = function() {
    192            return m_structs;
    193        };
    194        this.getVaryings = function() {
    195            return m_varyings;
    196        };
    197        this.getTransformFeedbackVaryings = function() {
    198            return m_transformFeedbackVaryings;
    199        };
    200 
    201        this.isPointSizeUsed = function() {
    202            for (var i = 0; i < m_transformFeedbackVaryings.length; ++i) {
    203                if (m_transformFeedbackVaryings[i] == 'gl_PointSize') return true;
    204            }
    205            return false;
    206        };
    207 
    208    };
    209 
    210    /** Returns if the program is supported or not
    211     * @param {es3fTransformFeedbackTests.ProgramSpec} spec
    212     * @param {number} tfMode
    213     * @return {boolean}
    214     */
    215    es3fTransformFeedbackTests.isProgramSupported = function(spec, tfMode) {
    216        var maxVertexAttribs = Number(gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
    217        var maxTfInterleavedComponents = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS));
    218        var maxTfSeparateAttribs = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS));
    219        var maxTfSeparateComponents = Number(gl.getParameter(gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS));
    220 
    221        // Check vertex attribs.
    222        /** @type {number} */ var totalVertexAttribs = (
    223            1 /* a_position */ + (spec.isPointSizeUsed() ? 1 : 0)
    224        );
    225 
    226        for (var i = 0; i < spec.getVaryings().length; ++i) {
    227            for (var v_iter = new gluVarTypeUtil.VectorTypeIterator(spec.getVaryings()[i].type); !v_iter.end(); v_iter.next()) {
    228                totalVertexAttribs += 1;
    229            }
    230        }
    231 
    232        if (totalVertexAttribs > maxVertexAttribs)
    233            return false; // Vertex attribute es3fTransformFeedbackTests.count exceeded.
    234 
    235        // check varyings
    236        /** @type {number} */ var totalTfComponents = 0;
    237        /** @type {number} */ var totalTfAttribs = 0;
    238        /** @type {Object.<number, number>} */ var presetNumComponents = {
    239            gl_Position: 4,
    240            gl_PointSize: 1
    241        };
    242        for (var i = 0; i < spec.getTransformFeedbackVaryings().length; ++i) {
    243            var name = spec.getTransformFeedbackVaryings()[i];
    244            var numComponents = 0;
    245 
    246            if (typeof(presetNumComponents[name]) != 'undefined') {
    247                numComponents = presetNumComponents[name];
    248            } else {
    249                var varName = gluVarTypeUtil.parseVariableName(name);
    250                // find the varying called varName
    251                /** @type {es3fTransformFeedbackTests.Varying} */ var varying = (function(varyings) {
    252                    for (var i = 0; i < varyings.length; ++i) {
    253                        if (varyings[i].name == varName) {
    254                            return varyings[i];
    255                        }
    256                    }
    257                    return null;
    258                }(spec.getVaryings()));
    259 
    260                // glu::TypeComponentVector
    261                var varPath = gluVarTypeUtil.parseTypePath(name, varying.type);
    262                numComponents = gluVarTypeUtil.getVarType(varying.type, varPath).getScalarSize();
    263            }
    264 
    265            if (tfMode == gl.SEPARATE_ATTRIBS && numComponents > maxTfSeparateComponents)
    266                return false; // Per-attribute component es3fTransformFeedbackTests.count exceeded.
    267 
    268            totalTfComponents += numComponents;
    269            totalTfAttribs += 1;
    270        }
    271 
    272        if (tfMode == gl.SEPARATE_ATTRIBS && totalTfAttribs > maxTfSeparateAttribs)
    273            return false;
    274 
    275        if (tfMode == gl.INTERLEAVED_ATTRIBS && totalTfComponents > maxTfInterleavedComponents)
    276            return false;
    277 
    278        return true;
    279 
    280    };
    281 
    282    /**
    283     * @param {string} varyingName
    284     * @param {Array<gluVarTypeUtil.VarTypeComponent>} path
    285     * @return {string}
    286     */
    287    es3fTransformFeedbackTests.getAttributeName = function(varyingName, path) {
    288    /** @type {string} */ var str = 'a_' + varyingName.substr(/^v_/.test(varyingName) ? 2 : 0);
    289 
    290        for (var i = 0; i < path.length; ++i) {
    291        /** @type {string} */ var prefix;
    292 
    293            switch (path[i].type) {
    294                case gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER: prefix = '_m'; break;
    295                case gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT: prefix = '_e'; break;
    296                case gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN: prefix = '_c'; break;
    297                case gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT: prefix = '_s'; break;
    298                default:
    299                    throw new Error('invalid type in the component path.');
    300            }
    301            str += prefix + path[i].index;
    302        }
    303        return str;
    304    };
    305 
    306    /**
    307     * original definition:
    308     * static void es3fTransformFeedbackTests.genShaderSources (const es3fTransformFeedbackTests.ProgramSpec& spec, std::string& vertSource, std::string& fragSource, bool pointSizeRequired)
    309     * in place of the std::string references, this function returns those params in an object
    310     *
    311     * @param {es3fTransformFeedbackTests.ProgramSpec} spec
    312     * @param {boolean} pointSizeRequired
    313     * @return {Object.<string, string>}
    314     */
    315    es3fTransformFeedbackTests.genShaderSources = function(spec, pointSizeRequired) {
    316 
    317        var vtx = { str: null };
    318        var frag = { str: null };
    319        var addPointSize = spec.isPointSizeUsed();
    320 
    321        vtx.str = '#version 300 es\n' +
    322                 'in highp vec4 a_position;\n';
    323        frag.str = '#version 300 es\n' +
    324                 'layout(location = 0) out mediump vec4 o_color;\n' +
    325                 'uniform highp vec4 u_scale;\n' +
    326                 'uniform highp vec4 u_bias;\n';
    327        //vtx.str = 'attribute highp vec4 a_position;\n';
    328        //frag.str = 'uniform highp vec4 u_scale;\n' +
    329        //         'uniform highp vec4 u_bias;\n';
    330 
    331        if (addPointSize) {
    332            vtx.str += 'in highp float a_pointSize;\n';
    333            //vtx.str += 'attribute highp float a_pointSize;\n';
    334        }
    335 
    336        // Declare attributes.
    337        for (var i = 0; i < spec.getVaryings().length; ++i) {
    338 
    339        /** @type {string} */ var name = spec.getVaryings()[i].name;
    340        /** @type {gluVarType.VarType} */ var type = spec.getVaryings()[i].type;
    341 
    342            for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(type); !vecIter.end(); vecIter.next()) {
    343 
    344                /** @type {gluVarType.VarType} */
    345                var attribType = gluVarTypeUtil.getVarType(type, vecIter.getPath());
    346 
    347                /** @type {string} */
    348                var attribName = es3fTransformFeedbackTests.getAttributeName(name, vecIter.getPath());
    349                vtx.str += 'in ' + gluVarType.declareVariable(attribType, attribName) + ';\n';
    350 
    351            }
    352        }
    353 
    354        // Declare varyings.
    355        for (var ndx = 0; ndx < 2; ++ndx) {
    356            var inout = ndx ? 'in' : 'out';
    357            var shader = ndx ? frag : vtx;
    358 
    359            for (var i = 0; i < spec.getStructs().length; ++i) {
    360                var struct = spec.getStructs()[i];
    361                if (struct.hasTypeName()) {
    362                    shader.str += gluVarType.declareStructType(struct) + ';\n';
    363                }
    364            }
    365 
    366            /** @type {Array<es3fTransformFeedbackTests.Varying>} */ var varyings = spec.getVaryings();
    367            for (var i = 0; i < varyings.length; ++i) {
    368                var varying = varyings[i];
    369                shader.str += es3fTransformFeedbackTests.getInterpolationName(varying.interpolation) +
    370                           ' ' + inout + ' ' +
    371                           gluVarType.declareVariable(varying.type, varying.name) +
    372                           ';\n';
    373            }
    374        }
    375 
    376        vtx.str += '\nvoid main (void)\n {\n' +
    377                 '\tgl_Position = a_position;\n';
    378        frag.str += '\nvoid main (void)\n {\n' +
    379                 '\thighp vec4 res = vec4(0.0);\n';
    380 
    381        if (addPointSize) {
    382            vtx.str += '\tgl_PointSize = a_pointSize;\n';
    383        } else if (pointSizeRequired) {
    384            vtx.str += '\tgl_PointSize = 1.0;\n';
    385        }
    386 
    387        for (var i = 0; i < spec.getVaryings().length; ++i) {
    388            var name = spec.getVaryings()[i].name;
    389            var type = spec.getVaryings()[i].type;
    390 
    391            for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(type); !vecIter.end(); vecIter.next()) {
    392                /** @type {gluVarType.VarType} */var subType = gluVarTypeUtil.getVarType(type, vecIter.getPath());
    393                var attribName = es3fTransformFeedbackTests.getAttributeName(name, vecIter.getPath());
    394 
    395                if (!(
    396                    subType.isBasicType() &&
    397                    gluShaderUtil.isDataTypeScalarOrVector(subType.getBasicType())
    398                )) throw new Error('Not a scalar or vector.');
    399 
    400                // Vertex: assign from attribute.
    401                vtx.str += '\t' + name + vecIter.toString() + ' = ' + attribName + ';\n';
    402 
    403                // Fragment: add to res variable.
    404                var scalarSize = gluShaderUtil.getDataTypeScalarSize(subType.getBasicType());
    405 
    406                frag.str += '\tres += ';
    407                if (scalarSize == 1) frag.str += 'vec4(' + name + vecIter.toString() + ')';
    408                else if (scalarSize == 2) frag.str += 'vec2(' + name + vecIter.toString() + ').xxyy';
    409                else if (scalarSize == 3) frag.str += 'vec3(' + name + vecIter.toString() + ').xyzx';
    410                else if (scalarSize == 4) frag.str += 'vec4(' + name + vecIter.toString() + ')';
    411 
    412                frag.str += ';\n';
    413            }
    414        }
    415 
    416        frag.str += '\to_color = res * u_scale + u_bias;\n}\n';
    417        //frag.str += '\tgl_FragColor = res * u_scale + u_bias;\n}\n';
    418        vtx.str += '}\n';
    419 
    420        return {
    421            vertSource: vtx.str,
    422            fragSource: frag.str
    423        };
    424    };
    425 
    426    /**
    427     * Returns a Shader program
    428     * @param {es3fTransformFeedbackTests.ProgramSpec} spec
    429     * @param {number} bufferMode
    430     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    431     * @return {gluShaderProgram.ShaderProgram}
    432     */
    433    es3fTransformFeedbackTests.createVertexCaptureProgram = function(spec, bufferMode, primitiveType) {
    434 
    435    /** @type {Object.<string, string>} */ var source = es3fTransformFeedbackTests.genShaderSources(spec, primitiveType === gluDrawUtil.primitiveType.POINTS /* Is point size required? */);
    436 
    437        var programSources = new gluShaderProgram.ProgramSources();
    438        programSources.add(new gluShaderProgram.VertexSource(source.vertSource))
    439                      .add(new gluShaderProgram.FragmentSource(source.fragSource))
    440                      .add(new gluShaderProgram.TransformFeedbackVaryings(spec.getTransformFeedbackVaryings()))
    441                      .add(new gluShaderProgram.TransformFeedbackMode(bufferMode));
    442 
    443        return new gluShaderProgram.ShaderProgram(gl, programSources);
    444 
    445    };
    446 
    447    /**
    448     * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
    449     * @param {Array<es3fTransformFeedbackTests.Varying>} varyings
    450     * @param {boolean} usePointSize
    451     * @return {number} input stride
    452     */
    453    es3fTransformFeedbackTests.computeInputLayout = function(attributes, varyings, usePointSize) {
    454 
    455        var inputStride = 0;
    456 
    457        // Add position
    458        var dataTypeVec4 = gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, gluShaderUtil.precision.PRECISION_HIGHP);
    459        attributes.push(new es3fTransformFeedbackTests.Attribute('a_position', dataTypeVec4, inputStride));
    460        inputStride += 4 * 4; /*sizeof(deUint32)*/
    461 
    462        if (usePointSize) {
    463            var dataTypeFloat = gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT, gluShaderUtil.precision.PRECISION_HIGHP);
    464            attributes.push(new es3fTransformFeedbackTests.Attribute('a_pointSize', dataTypeFloat, inputStride));
    465            inputStride += 1 * 4; /*sizeof(deUint32)*/
    466        }
    467 
    468        for (var i = 0; i < varyings.length; i++) {
    469            for (var vecIter = new gluVarTypeUtil.VectorTypeIterator(varyings[i].type); !vecIter.end(); vecIter.next()) {
    470                var type = vecIter.getType(); // originally getType() in getVarType() within gluVARTypeUtil.hpp.
    471                var name = es3fTransformFeedbackTests.getAttributeName(varyings[i].name, vecIter.getPath());
    472 
    473                attributes.push(new es3fTransformFeedbackTests.Attribute(name, type, inputStride));
    474                inputStride += gluShaderUtil.getDataTypeScalarSize(type.getBasicType()) * 4; /*sizeof(deUint32)*/
    475            }
    476        }
    477 
    478        return inputStride;
    479    };
    480 
    481    /**
    482     * @param {Array<es3fTransformFeedbackTests.Output>} transformFeedbackOutputs
    483     * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
    484     * @param {Array<es3fTransformFeedbackTests.Varying>} varyings
    485     * @param {Array<string>} transformFeedbackVaryings
    486     * @param {number} bufferMode
    487     */
    488    es3fTransformFeedbackTests.computeTransformFeedbackOutputs = function(transformFeedbackOutputs, attributes, varyings, transformFeedbackVaryings, bufferMode) {
    489 
    490        /** @type {number} */ var accumulatedSize = 0;
    491 
    492        // transformFeedbackOutputs.resize(transformFeedbackVaryings.size());
    493        for (var varNdx = 0; varNdx < transformFeedbackVaryings.length; varNdx++) {
    494            /** @type {string} */ var name = transformFeedbackVaryings[varNdx];
    495            /** @type {number} */ var bufNdx = (bufferMode === gl.SEPARATE_ATTRIBS ? varNdx : 0);
    496            /** @type {number} */ var offset = (bufferMode === gl.SEPARATE_ATTRIBS ? 0 : accumulatedSize);
    497            /** @type {es3fTransformFeedbackTests.Output} */ var output = new es3fTransformFeedbackTests.Output();
    498 
    499            output.name = name;
    500            output.bufferNdx = bufNdx;
    501            output.offset = offset;
    502 
    503            if (name === 'gl_Position') {
    504                var posIn = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_position');
    505                output.type = posIn.type;
    506                output.inputs.push(posIn);
    507            } else if (name === 'gl_PointSize') {
    508                var sizeIn = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_pointSize');
    509                output.type = sizeIn.type;
    510                output.inputs.push(sizeIn);
    511            } else {
    512                var varName = gluVarTypeUtil.parseVariableName(name);
    513                var varying = es3fTransformFeedbackTests.findAttributeNameEquals(varyings, varName);
    514 
    515                var varPath = gluVarTypeUtil.parseTypePath(name, varying.type);
    516                output.type = gluVarTypeUtil.getVarType(varying.type, varPath);
    517 
    518                // Add all vectorized attributes as inputs.
    519                for (var iter = new gluVarTypeUtil.VectorTypeIterator(output.type); !iter.end(); iter.next()) {
    520                    var fullpath = varPath.concat(iter.getPath());
    521                    var attribName = es3fTransformFeedbackTests.getAttributeName(varName, fullpath);
    522                    var attrib = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, attribName);
    523                    output.inputs.push(attrib);
    524                }
    525            }
    526            transformFeedbackOutputs.push(output);
    527            accumulatedSize += output.type.getScalarSize() * 4; /*sizeof(deUint32)*/
    528        }
    529    };
    530 
    531    /**
    532     * @param {es3fTransformFeedbackTests.Attribute} attrib
    533     * @param {ArrayBuffer} buffer
    534     * @param {number} stride
    535     * @param {number} numElements
    536     * @param {deRandom.Random} rnd
    537     */
    538    es3fTransformFeedbackTests.genAttributeData = function(attrib, buffer, stride, numElements, rnd) {
    539 
    540        /** @type {number} */ var elementSize = 4; /*sizeof(deUint32)*/
    541        /** @type {boolean} */ var isFloat = gluShaderUtil.isDataTypeFloatOrVec(attrib.type.getBasicType());
    542        /** @type {boolean} */ var isInt = gluShaderUtil.isDataTypeIntOrIVec(attrib.type.getBasicType());
    543        /** @type {boolean} */ var isUint = gluShaderUtil.isDataTypeUintOrUVec(attrib.type.getBasicType());
    544 
    545        /** @type {gluShaderUtil.precision} */ var precision = attrib.type.getPrecision();
    546 
    547        /** @type {number} */ var numComps = gluShaderUtil.getDataTypeScalarSize(attrib.type.getBasicType());
    548 
    549        for (var elemNdx = 0; elemNdx < numElements; elemNdx++) {
    550            for (var compNdx = 0; compNdx < numComps; compNdx++) {
    551                /** @type {number} */ var offset = attrib.offset + elemNdx * stride + compNdx * elementSize;
    552                if (isFloat) {
    553                    var pos = new Float32Array(buffer, offset, 1);
    554                    switch (precision) {
    555                        case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = 0.25 * rnd.getInt(0, 4); break;
    556                        case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getFloat(-1e3, 1e3); break;
    557                        case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = rnd.getFloat(-1e5, 1e5); break;
    558                        default: throw new Error('Unknown precision: ' + precision);
    559                    }
    560                } else if (isInt) {
    561                    var pos = new Int32Array(buffer, offset, 1);
    562                    switch (precision) {
    563                        case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = rnd.getInt(-128, 127); break;
    564                        case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getInt(-32768, 32767); break;
    565                        case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = rnd.getInt(); break;
    566                        default: throw new Error('Unknown precision: ' + precision);
    567                    }
    568                } else if (isUint) {
    569                    var pos = new Uint32Array(buffer, offset, 1);
    570                    switch (precision) {
    571                        case gluShaderUtil.precision.PRECISION_LOWP: pos[0] = rnd.getInt(0, 255); break;
    572                        case gluShaderUtil.precision.PRECISION_MEDIUMP: pos[0] = rnd.getInt(0, 65535); break;
    573                        case gluShaderUtil.precision.PRECISION_HIGHP: pos[0] = Math.abs(rnd.getInt()); break;
    574                        default: throw new Error('Unknown precision: ' + precision);
    575                    }
    576                }
    577            }
    578        }
    579    };
    580 
    581    /**
    582     * @param {Array<es3fTransformFeedbackTests.Attribute>} attributes
    583     * @param {number} numInputs
    584     * @param {number} inputStride
    585     * @param {deRandom.Random} rnd
    586     * @return {ArrayBuffer}
    587     */
    588    es3fTransformFeedbackTests.genInputData = function(attributes, numInputs, inputStride, rnd) {
    589        var buffer = new ArrayBuffer(numInputs * inputStride);
    590 
    591        var position = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_position');
    592        if (!position)
    593            throw new Error('Position attribute not found.');
    594 
    595        for (var ndx = 0; ndx < numInputs; ndx++) {
    596            var pos = new Float32Array(buffer, position.offset + inputStride * ndx, 4);
    597            pos[0] = rnd.getFloat(-1.2, 1.2);
    598            pos[1] = rnd.getFloat(-1.2, 1.2);
    599            pos[2] = rnd.getFloat(-1.2, 1.2);
    600            pos[3] = rnd.getFloat(0.1, 2.0);
    601        }
    602 
    603        var pointSizePos = es3fTransformFeedbackTests.findAttributeNameEquals(attributes, 'a_pointSize');
    604        if (pointSizePos) {
    605            for (var ndx = 0; ndx < numInputs; ndx++) {
    606                var pos = new Float32Array(buffer, pointSizePos.offset + inputStride * ndx, 1);
    607                pos[0] = rnd.getFloat(1, 8);
    608            }
    609        }
    610 
    611        // Random data for rest of components.
    612        for (var i = 0; i < attributes.length; i++) {
    613            if (attributes[i].name != 'a_position' && attributes[i].name != 'a_pointSize')
    614                es3fTransformFeedbackTests.genAttributeData(attributes[i], buffer, inputStride, numInputs, rnd);
    615        }
    616 
    617        return buffer;
    618    };
    619 
    620    /**
    621     * Returns the number of outputs with the es3fTransformFeedbackTests.count for the Primitives in the Transform Feedback.
    622     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    623     * @param {number} numElements
    624     * @return {number}
    625     */
    626    es3fTransformFeedbackTests.getTransformFeedbackOutputCount = function(primitiveType, numElements) {
    627 
    628    switch (primitiveType) {
    629        case gluDrawUtil.primitiveType.TRIANGLES: return numElements - numElements % 3;
    630        case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return Math.max(0, numElements - 2) * 3;
    631        case gluDrawUtil.primitiveType.TRIANGLE_FAN: return Math.max(0, numElements - 2) * 3;
    632        case gluDrawUtil.primitiveType.LINES: return numElements - numElements % 2;
    633        case gluDrawUtil.primitiveType.LINE_STRIP: return Math.max(0, numElements - 1) * 2;
    634        case gluDrawUtil.primitiveType.LINE_LOOP: return numElements > 1 ? numElements * 2 : 0;
    635        case gluDrawUtil.primitiveType.POINTS: return numElements;
    636        default:
    637            throw new Error('Unrecognized primitiveType ' + primitiveType);
    638       }
    639 
    640    };
    641 
    642    /**
    643     * Returns a number with the es3fTransformFeedbackTests.count for the Primitives in the Transform Feedback.
    644     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    645     * @param {number} numElements
    646     * @return {number}
    647     */
    648    es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount = function(primitiveType, numElements) {
    649 
    650    switch (primitiveType) {
    651        case gluDrawUtil.primitiveType.TRIANGLES: return Math.floor(numElements / 3);
    652        case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return Math.max(0, numElements - 2);
    653        case gluDrawUtil.primitiveType.TRIANGLE_FAN: return Math.max(0, numElements - 2);
    654        case gluDrawUtil.primitiveType.LINES: return Math.floor(numElements / 2);
    655        case gluDrawUtil.primitiveType.LINE_STRIP: return Math.max(0, numElements - 1);
    656        case gluDrawUtil.primitiveType.LINE_LOOP: return numElements > 1 ? numElements : 0;
    657        case gluDrawUtil.primitiveType.POINTS: return numElements;
    658        default:
    659            throw new Error('Unrecognized primitiveType ' + primitiveType);
    660       }
    661 
    662    };
    663 
    664    /**
    665     * Returns the type of Primitive Mode: Triangles for all Triangle Primitive's type and same for Line and Points.
    666     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    667     * @return {number} primitiveType
    668     */
    669    es3fTransformFeedbackTests.getTransformFeedbackPrimitiveMode = function(primitiveType) {
    670 
    671    switch (primitiveType) {
    672        case gluDrawUtil.primitiveType.TRIANGLES:
    673        case gluDrawUtil.primitiveType.TRIANGLE_STRIP:
    674        case gluDrawUtil.primitiveType.TRIANGLE_FAN:
    675            return gl.TRIANGLES;
    676 
    677        case gluDrawUtil.primitiveType.LINES:
    678        case gluDrawUtil.primitiveType.LINE_STRIP:
    679        case gluDrawUtil.primitiveType.LINE_LOOP:
    680            return gl.LINES;
    681 
    682        case gluDrawUtil.primitiveType.POINTS:
    683            return gl.POINTS;
    684 
    685        default:
    686            throw new Error('Unrecognized primitiveType ' + primitiveType);
    687       }
    688 
    689    };
    690 
    691    /**
    692     * Returns the attribute index for a certain primitive type.
    693     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    694     * @param {number} numInputs
    695     * @param {number} outNdx
    696     * @return {number}
    697     */
    698    es3fTransformFeedbackTests.getAttributeIndex = function(primitiveType, numInputs, outNdx) {
    699 
    700    switch (primitiveType) {
    701 
    702        case gluDrawUtil.primitiveType.TRIANGLES: return outNdx;
    703        case gluDrawUtil.primitiveType.LINES: return outNdx;
    704        case gluDrawUtil.primitiveType.POINTS: return outNdx;
    705 
    706        case gluDrawUtil.primitiveType.TRIANGLE_STRIP: {
    707            /** @type {number} */ var triNdx = outNdx / 3;
    708            /** @type {number} */ var vtxNdx = outNdx % 3;
    709            return (triNdx % 2 != 0 && vtxNdx < 2) ? (triNdx + 1 - vtxNdx) : (triNdx + vtxNdx);
    710        }
    711 
    712        case gluDrawUtil.primitiveType.TRIANGLE_FAN:
    713            return (outNdx % 3 != 0) ? (outNdx / 3 + outNdx % 3) : 0;
    714 
    715        case gluDrawUtil.primitiveType.LINE_STRIP:
    716            return outNdx / 2 + outNdx % 2;
    717 
    718        case gluDrawUtil.primitiveType.LINE_LOOP: {
    719            var inNdx = outNdx / 2 + outNdx % 2;
    720            return inNdx < numInputs ? inNdx : 0;
    721        }
    722 
    723        default:
    724            throw new Error('Unrecognized primitiveType ' + primitiveType);
    725       }
    726 
    727    };
    728 
    729    /**
    730     * @param {gluDrawUtil.primitiveType} primitiveType type number in gluDrawUtil.primitiveType
    731     * @param {es3fTransformFeedbackTests.Output} output
    732     * @param {number} numInputs
    733     * @param {Object} buffers
    734     * @return {boolean} isOk
    735     */
    736    es3fTransformFeedbackTests.compareTransformFeedbackOutput = function(primitiveType, output, numInputs, buffers) {
    737        /** @type {boolean} */ var isOk = true;
    738        /** @type {number} */ var outOffset = output.offset;
    739 
    740        for (var attrNdx = 0; attrNdx < output.inputs.length; attrNdx++) {
    741        /** @type {es3fTransformFeedbackTests.Attribute} */ var attribute = output.inputs[attrNdx];
    742        /** @type {gluShaderUtil.DataType} */ var type = attribute.type.getBasicType();
    743        /** @type {number} */ var numComponents = gluShaderUtil.getDataTypeScalarSize(type);
    744 
    745        /** @type {gluShaderUtil.precision} */ var precision = attribute.type.getPrecision();
    746 
    747        /** @type {string} */ var scalarType = gluShaderUtil.getDataTypeScalarType(type);
    748        /** @type {number} */ var numOutputs = es3fTransformFeedbackTests.getTransformFeedbackOutputCount(primitiveType, numInputs);
    749 
    750            for (var outNdx = 0; outNdx < numOutputs; outNdx++) {
    751            /** @type {number} */ var inNdx = es3fTransformFeedbackTests.getAttributeIndex(primitiveType, numInputs, outNdx);
    752 
    753                for (var compNdx = 0; compNdx < numComponents; compNdx++) {
    754                /** @type {boolean} */ var isEqual = false;
    755 
    756                    if (scalarType === 'float') {
    757                        var outBuffer = new Float32Array(buffers.output.buffer, buffers.output.offset + buffers.output.stride * outNdx + outOffset + compNdx * 4, 1);
    758                        var inBuffer = new Float32Array(buffers.input.buffer, buffers.input.offset + buffers.input.stride * inNdx + attribute.offset + compNdx * 4, 1);
    759                        var difInOut = inBuffer[0] - outBuffer[0];
    760                        /* TODO: Original code used ULP comparison for highp and mediump precision. This could cause failures. */
    761                        switch (precision) {
    762                            case gluShaderUtil.precision.PRECISION_HIGHP: {
    763                                isEqual = Math.abs(difInOut) < 0.1;
    764                                break;
    765                            }
    766 
    767                            case gluShaderUtil.precision.PRECISION_MEDIUMP: {
    768                                isEqual = Math.abs(difInOut) < 0.1;
    769                                break;
    770                            }
    771 
    772                            case gluShaderUtil.precision.PRECISION_LOWP: {
    773                                isEqual = Math.abs(difInOut) < 0.1;
    774                                break;
    775                            }
    776                            default:
    777                                throw new Error('Unknown precision: ' + precision);
    778                        }
    779                    } else {
    780                        var outBuffer = new Uint32Array(buffers.output.buffer, buffers.output.offset + buffers.output.stride * outNdx + outOffset + compNdx * 4, 1);
    781                        var inBuffer = new Uint32Array(buffers.input.buffer, buffers.input.offset + buffers.input.stride * inNdx + attribute.offset + compNdx * 4, 1);
    782                        isEqual = (inBuffer[0] == outBuffer[0]); // Bit-exact match required for integer types.
    783                    }
    784 
    785                    if (!isEqual) {
    786                        bufferedLogToConsole('Mismatch in ' + output.name + ' (' + attribute.name + '), output = ' + outNdx + ', input = ' + inNdx + ', component = ' + compNdx);
    787                        isOk = false;
    788                        break;
    789                    }
    790                }
    791 
    792                if (!isOk)
    793                    break;
    794            }
    795 
    796            if (!isOk)
    797                break;
    798 
    799            outOffset += numComponents * 4; /*sizeof(deUint32)*/
    800        }
    801 
    802        return isOk;
    803    };
    804 
    805    /**
    806     * Returns (for all the draw calls) the type of Primitive Mode, as it calls "es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount".
    807     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    808     * @param {Array<es3fTransformFeedbackTests.DrawCall>} array Object.<number, boolean>
    809     * @return {number} primCount
    810     */
    811    es3fTransformFeedbackTests.computeTransformFeedbackPrimitiveCount = function(primitiveType, array) {
    812 
    813    /** @type {number} */ var primCount = 0;
    814 
    815        for (var i = 0; i < array.length; ++ i) {
    816 
    817            if (array[i].transformFeedbackEnabled)
    818                primCount += es3fTransformFeedbackTests.getTransformFeedbackPrimitiveCount(primitiveType, array[i].numElements);
    819        }
    820 
    821        return primCount;
    822    };
    823 
    824    /**
    825     * @param {number} target
    826     * @param {number} bufferSize
    827     * @param {number} guardSize
    828     */
    829    es3fTransformFeedbackTests.writeBufferGuard = function(target, bufferSize, guardSize) {
    830        var buffer = new ArrayBuffer(guardSize);
    831        var view = new Uint8Array(buffer);
    832        for (var i = 0; i < guardSize; ++i) view[i] = 0xcd;
    833        gl.bufferSubData(target, bufferSize, buffer);
    834    };
    835 
    836    /**
    837     * Verifies guard
    838     * @param {ArrayBuffer} buffer
    839     * @param {number} start
    840     * @return {boolean}
    841     */
    842    es3fTransformFeedbackTests.verifyGuard = function(buffer, start) {
    843        start = start || 0;
    844        var view = new Uint8Array(buffer, start);
    845        for (var i = 0; i < view.length; i++) {
    846            if (view[i] != 0xcd)
    847                return false;
    848        }
    849        return true;
    850    };
    851 
    852    /**
    853     * @extends {tcuTestCase.DeqpTest}
    854     * @param {string} name
    855     * @param {string} desc
    856     * @param {number} bufferMode
    857     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
    858     * @constructor
    859     */
    860    es3fTransformFeedbackTests.TransformFeedbackCase = function(name, desc, bufferMode, primitiveType) {
    861        tcuTestCase.DeqpTest.call(this, name, desc);
    862        this.m_bufferMode = bufferMode;
    863        this.m_primitiveType = primitiveType;
    864        this.m_progSpec = new es3fTransformFeedbackTests.ProgramSpec();
    865 
    866        // Derived from es3fTransformFeedbackTests.ProgramSpec in es3fTransformFeedbackTests.init()
    867        this.m_inputStride = 0;
    868        this.m_attributes = []; // vector<es3fTransformFeedbackTests.Attribute>
    869        this.m_transformFeedbackOutputs = []; // vector<es3fTransformFeedbackTests.Output>
    870        this.m_bufferStrides = []; // vector<int>
    871 
    872        // GL state.
    873        this.m_program = null; // glu::ShaderProgram
    874        this.m_transformFeedback = null; // glu::TransformFeedback
    875        this.m_outputBuffers = []; // vector<deUint32>
    876 
    877        this.m_iterNdx = 0; // int
    878        this.m_testPassed = true;
    879        // State machine
    880        this.m_state = es3fTransformFeedbackTests.State.DRAW;
    881        this.m_verifyStart = null;
    882 
    883        this.m_frameWithTf = null;
    884        this.m_frameWithoutTf = null;
    885 
    886        this.m_viewportW = 0;
    887        this.m_viewportH = 0;
    888        this.m_viewportX = 0;
    889        this.m_viewportY = 0;
    890 
    891        this.m_primitiveQuery = null;
    892        this.m_outputsOk = true;
    893 
    894    };
    895 
    896    setParentClass(es3fTransformFeedbackTests.TransformFeedbackCase, tcuTestCase.DeqpTest);
    897 
    898    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.createVerificationResult = function(retry, result) {
    899        return { retry: retry, result: result };
    900    }
    901 
    902    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.dumpShaderText = function() {
    903        var dbgext = gl.getExtension('WEBGL_debug_shaders');
    904        for (var ii = 0; ii < this.m_program.shaders.length; ++ii) {
    905            debug('Shader source ' + ii + ' before translation:')
    906            debug(this.m_program.shaders[ii].info.source);
    907            debug('');
    908            debug('Shader source ' + ii + ' after translation:');
    909            debug(dbgext.getTranslatedShaderSource(this.m_program.shaders[ii].shader));
    910        }
    911    };
    912 
    913    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.init = function() {
    914        this.m_program = es3fTransformFeedbackTests.createVertexCaptureProgram(
    915            this.m_progSpec,
    916            this.m_bufferMode,
    917            this.m_primitiveType
    918        );
    919 
    920        if (!this.m_program.isOk()) {
    921            // this.dumpShaderText();
    922 
    923            var linkFail = this.m_program.shadersOK &&
    924                           !this.m_program.getProgramInfo().linkOk;
    925 
    926            if (linkFail) {
    927                if (!es3fTransformFeedbackTests.isProgramSupported(this.m_progSpec, this.m_bufferMode)) {
    928                    var msg = 'Not Supported. Implementation limits exceeded.';
    929                    checkMessage(false, msg);
    930                    throw new TestFailedException(msg);
    931                } else if (es3fTransformFeedbackTests.hasArraysInTFVaryings(this.m_progSpec)) {
    932                    msg = 'Capturing arrays is not supported (undefined in specification)';
    933                    checkMessage(false, msg);
    934                    throw new TestFailedException(msg);
    935                } else {
    936                    throw new Error('Link failed: ' + this.m_program.getProgramInfo().infoLog);
    937                }
    938            } else {
    939                throw new Error('Compile failed');
    940            }
    941        } else {
    942            // debug('Program is ' +
    943            //       (gl.getProgramParameter(this.m_program.getProgram(), gl.LINK_STATUS) ? 'linked' : 'not linked'));
    944            // this.dumpShaderText();
    945        }
    946 
    947 //          bufferedLogToConsole('Transform feedback varyings: ' + tcu.formatArray(this.m_progSpec.getTransformFeedbackVaryings()));
    948        bufferedLogToConsole('Transform feedback varyings: ' + this.m_progSpec.getTransformFeedbackVaryings());
    949 
    950        // Print out transform feedback points reported by GL.
    951        // bufferedLogToConsole('Transform feedback varyings reported by compiler:');
    952        //logTransformFeedbackVaryings(log, gl, this.m_program.getProgram());
    953 
    954        // Compute input specification.
    955        this.m_inputStride = es3fTransformFeedbackTests.computeInputLayout(this.m_attributes, this.m_progSpec.getVaryings(), this.m_progSpec.isPointSizeUsed());
    956 
    957        // Build list of varyings used in transform feedback.
    958        es3fTransformFeedbackTests.computeTransformFeedbackOutputs(
    959            this.m_transformFeedbackOutputs,
    960            this.m_attributes,
    961            this.m_progSpec.getVaryings(),
    962            this.m_progSpec.getTransformFeedbackVaryings(),
    963            this.m_bufferMode
    964        );
    965        if (!this.m_transformFeedbackOutputs.length) {
    966            throw new Error('transformFeedbackOutputs cannot be empty.');
    967        }
    968 
    969        if (this.m_bufferMode == gl.SEPARATE_ATTRIBS) {
    970            for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
    971                this.m_bufferStrides.push(this.m_transformFeedbackOutputs[i].type.getScalarSize() * 4 /*sizeof(deUint32)*/);
    972            }
    973        } else {
    974            var totalSize = 0;
    975            for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
    976                totalSize += this.m_transformFeedbackOutputs[i].type.getScalarSize() * 4 /*sizeof(deUint32)*/;
    977            }
    978            this.m_bufferStrides.push(totalSize);
    979        }
    980 
    981        this.m_outputBuffers.length = this.m_bufferStrides.length;
    982        for (var i = 0; i < this.m_outputBuffers.length; i++)
    983            this.m_outputBuffers[i] = gl.createBuffer();
    984 
    985        this.m_transformFeedback = gl.createTransformFeedback();
    986 
    987        this.m_iterNdx = 0;
    988 //          this.m_testCtx.setTestResult(QP_TEST_RESULT_PASS, 'Pass');
    989 
    990    };
    991 
    992    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.deinit = function() {
    993        for (var i = 0; i < this.m_outputBuffers.length; i++)
    994            gl.deleteBuffer(this.m_outputBuffers[i]);
    995 
    996    //    delete this.m_transformFeedback;
    997        this.m_transformFeedback = null;
    998 
    999    //    delete this.m_program;
   1000        this.m_program = null;
   1001 
   1002        // Clean up state.
   1003        this.m_attributes = [];
   1004        this.m_transformFeedbackOutputs = [];
   1005        this.m_bufferStrides = [];
   1006        this.m_inputStride = 0;
   1007 
   1008    };
   1009 
   1010    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.iterate = function() {
   1011        var s = es3fTransformFeedbackTests.TransformFeedbackCase.s_iterate;
   1012        var numIterations = s.iterations.length;
   1013        var seed = deMath.deMathHash(this.m_iterNdx);
   1014        switch(this.m_state) {
   1015            case es3fTransformFeedbackTests.State.DRAW:
   1016                bufferedLogToConsole('Testing ' +
   1017                    s.testCases[s.iterations[this.m_iterNdx]].length +
   1018                    ' draw calls, (element es3fTransformFeedbackTests.count, TF state): ' +
   1019                    s.testCases[s.iterations[this.m_iterNdx]]
   1020                );
   1021                this.draw(s.testCases[s.iterations[this.m_iterNdx]], seed);
   1022                this.m_state = es3fTransformFeedbackTests.State.VERIFY;
   1023                break;
   1024            case es3fTransformFeedbackTests.State.VERIFY:
   1025                var verifyResult = this.verify(s.testCases[s.iterations[this.m_iterNdx]]);
   1026                if (verifyResult.retry) {
   1027                    break;
   1028                }
   1029                this.m_testPassed = verifyResult.result;
   1030                this.m_iterNdx += 1;
   1031                if (this.m_testPassed && this.m_iterNdx < numIterations) {
   1032                    this.m_state = es3fTransformFeedbackTests.State.DRAW;
   1033                    break;
   1034                }
   1035                // Fall through
   1036            case es3fTransformFeedbackTests.State.FINISH:
   1037                if (!this.m_testPassed) testFailedOptions('Result comparison failed for iteration ' + s.iterations[this.m_iterNdx - 1], false);
   1038                else testPassedOptions('Result comparison succeeded', true);
   1039                return tcuTestCase.IterateResult.STOP;
   1040        }
   1041 
   1042        return tcuTestCase.IterateResult.CONTINUE;
   1043 
   1044    };
   1045 
   1046    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.draw = function(calls, seed) {
   1047        var _min = function(x, y) { return x < y ? x : y; };
   1048 
   1049        var rnd = new deRandom.Random(seed);
   1050        var numInputs = 0;
   1051        var numOutputs = 0;
   1052        var width = gl.drawingBufferWidth;
   1053        var height = gl.drawingBufferHeight;
   1054        this.m_viewportW = _min(es3fTransformFeedbackTests.VIEWPORT_WIDTH, width);
   1055        this.m_viewportH = _min(es3fTransformFeedbackTests.VIEWPORT_HEIGHT, height);
   1056        this.m_viewportX = rnd.getInt(0, width - this.m_viewportW);
   1057        this.m_viewportY = rnd.getInt(0, height - this.m_viewportH);
   1058        this.m_frameWithTf = new tcuSurface.Surface(this.m_viewportW, this.m_viewportH); // tcu::Surface
   1059        this.m_frameWithoutTf = new tcuSurface.Surface(this.m_viewportW, this.m_viewportH); // tcu::Surface
   1060        this.m_primitiveQuery = gl.createQuery();
   1061        this.m_outputsOk = true;
   1062 
   1063        // Compute totals.
   1064        for (var i = 0; i < calls.length; ++i) {
   1065            var call = calls[i];
   1066            numInputs += call.numElements;
   1067            numOutputs += call.transformFeedbackEnabled ? es3fTransformFeedbackTests.getTransformFeedbackOutputCount(this.m_primitiveType, call.numElements) : 0;
   1068        }
   1069 
   1070        // Input data.
   1071        var inputData = es3fTransformFeedbackTests.genInputData(this.m_attributes, numInputs, this.m_inputStride, rnd);
   1072 
   1073        gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, this.m_transformFeedback);
   1074 
   1075        // Allocate storage for transform feedback output buffers and bind to targets.
   1076        for (var bufNdx = 0; bufNdx < this.m_outputBuffers.length; ++bufNdx) {
   1077            var buffer = this.m_outputBuffers[bufNdx]; // deUint32
   1078            var stride = this.m_bufferStrides[bufNdx]; // int
   1079            var target = bufNdx; // int
   1080            var size = stride * numOutputs; // int
   1081            var guardSize = stride * es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER; // int
   1082            var usage = gl.DYNAMIC_READ; // const deUint32
   1083 
   1084            gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
   1085            gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, size + guardSize, usage);
   1086            es3fTransformFeedbackTests.writeBufferGuard(gl.TRANSFORM_FEEDBACK_BUFFER, size, guardSize);
   1087 
   1088            // \todo [2012-07-30 pyry] glBindBufferRange()?
   1089            gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, target, buffer);
   1090        }
   1091 
   1092        var attribBuffer = gl.createBuffer();
   1093        gl.bindBuffer(gl.ARRAY_BUFFER, attribBuffer);
   1094        gl.bufferData(gl.ARRAY_BUFFER, inputData, gl.STATIC_DRAW);
   1095 
   1096        // Setup attributes.
   1097        for (var i = 0; i < this.m_attributes.length; ++i) {
   1098            var attrib = this.m_attributes[i];
   1099            var loc = gl.getAttribLocation(this.m_program.getProgram(), attrib.name);
   1100            /** @type {string} */
   1101            var scalarType = gluShaderUtil.getDataTypeScalarType(attrib.type.getBasicType());
   1102            /** @type {number} */
   1103            var numComponents = gluShaderUtil.getDataTypeScalarSize(attrib.type.getBasicType());
   1104 
   1105            if (loc >= 0) {
   1106                gl.enableVertexAttribArray(loc);
   1107                switch (scalarType) {
   1108                    case 'float':
   1109                        gl.vertexAttribPointer(loc, numComponents, gl.FLOAT, false, this.m_inputStride, attrib.offset); break;
   1110                    case 'int':
   1111                        gl.vertexAttribIPointer(loc, numComponents, gl.INT, this.m_inputStride, attrib.offset); break;
   1112                    case 'uint':
   1113                        gl.vertexAttribIPointer(loc, numComponents, gl.UNSIGNED_INT, this.m_inputStride, attrib.offset); break;
   1114                }
   1115            }
   1116        }
   1117 
   1118        // Setup viewport.
   1119        gl.viewport(this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH);
   1120 
   1121        // Setup program.
   1122        gl.useProgram(this.m_program.getProgram());
   1123 
   1124        gl.uniform4fv(
   1125            gl.getUniformLocation(this.m_program.getProgram(), 'u_scale'),
   1126            [0.01, 0.01, 0.01, 0.01]
   1127        );
   1128        gl.uniform4fv(
   1129            gl.getUniformLocation(this.m_program.getProgram(), 'u_bias'),
   1130            [0.5, 0.5, 0.5, 0.5]
   1131        );
   1132 
   1133        // Enable query.
   1134        gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, this.m_primitiveQuery);
   1135 
   1136        // Draw
   1137        var offset = 0;
   1138        var tfEnabled = true;
   1139 
   1140        gl.clear(gl.COLOR_BUFFER_BIT);
   1141 
   1142        var tfPrimitiveMode = es3fTransformFeedbackTests.getTransformFeedbackPrimitiveMode(this.m_primitiveType);
   1143        gl.beginTransformFeedback(tfPrimitiveMode);
   1144 
   1145        for (var i = 0; i < calls.length; ++i) {
   1146            var call = calls[i];
   1147 
   1148            // Pause or resume transform feedback if necessary.
   1149            if (call.transformFeedbackEnabled != tfEnabled) {
   1150                if (call.transformFeedbackEnabled)
   1151                    gl.resumeTransformFeedback();
   1152                else
   1153                    gl.pauseTransformFeedback();
   1154                tfEnabled = call.transformFeedbackEnabled;
   1155            }
   1156 
   1157            gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, this.m_primitiveType), offset, call.numElements);
   1158            offset += call.numElements;
   1159        }
   1160 
   1161        // Resume feedback before finishing it.
   1162        if (!tfEnabled)
   1163            gl.resumeTransformFeedback();
   1164 
   1165        gl.endTransformFeedback();
   1166 
   1167        gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
   1168 
   1169        // Check and log query status right after submit
   1170        var query = this.m_primitiveQuery;
   1171 
   1172        var available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
   1173 
   1174        if (available) {
   1175            this.m_testPassed = false;
   1176            this.m_state = es3fTransformFeedbackTests.State.FINISH;
   1177            testFailedOptions('Transform feedback query result must not be available the same frame as they are issued.', true);
   1178        }
   1179 
   1180        // Compare result buffers.
   1181        for (var bufferNdx = 0; bufferNdx < this.m_outputBuffers.length; ++bufferNdx) {
   1182            var stride = this.m_bufferStrides[bufferNdx]; // int
   1183            var size = stride * numOutputs; // int
   1184            var guardSize = stride * es3fTransformFeedbackTests.BUFFER_GUARD_MULTIPLIER; // int
   1185            var buffer = new ArrayBuffer(size + guardSize); // const void*
   1186 
   1187            // Bind buffer for reading.
   1188            gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, this.m_outputBuffers[bufferNdx]);
   1189 
   1190            gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, new Uint8Array(buffer));
   1191 
   1192            // Verify all output variables that are written to this buffer.
   1193            for (var i = 0; i < this.m_transformFeedbackOutputs.length; ++i) {
   1194                var out = this.m_transformFeedbackOutputs[i];
   1195 
   1196                if (out.bufferNdx != bufferNdx)
   1197                    continue;
   1198 
   1199                var inputOffset = 0;
   1200                var outputOffset = 0;
   1201 
   1202                // Process all draw calls and check ones with transform feedback enabled
   1203                for (var callNdx = 0; callNdx < calls.length; ++callNdx) {
   1204                    var call = calls[callNdx];
   1205 
   1206                    if (call.transformFeedbackEnabled) {
   1207                        var inputPtr = inputData[0] + inputOffset * this.m_inputStride; // const deUint8*
   1208                        var outputPtr = outputOffset * stride; // const deUint8*
   1209 
   1210                        if (!es3fTransformFeedbackTests.compareTransformFeedbackOutput(this.m_primitiveType, out, call.numElements, {
   1211                                 input: {
   1212                                    buffer: inputData,
   1213                                    offset: inputOffset * this.m_inputStride,
   1214                                    stride: this.m_inputStride
   1215                                },
   1216                                output: {
   1217                                    buffer: buffer,
   1218                                    offset: outputOffset * stride,
   1219                                    stride: stride
   1220                                }
   1221                            })) {
   1222                            this.m_outputsOk = false;
   1223                            break;
   1224                        }
   1225                    }
   1226 
   1227                    inputOffset += call.numElements;
   1228                    outputOffset += call.transformFeedbackEnabled ? es3fTransformFeedbackTests.getTransformFeedbackOutputCount(this.m_primitiveType, call.numElements) : 0;
   1229                }
   1230            }
   1231 
   1232            // Verify guardband.
   1233            if (!es3fTransformFeedbackTests.verifyGuard(buffer, size)) {
   1234                bufferedLogToConsole('Error: Transform feedback buffer overrun detected');
   1235                this.m_outputsOk = false;
   1236            }
   1237        }
   1238    };
   1239 
   1240    es3fTransformFeedbackTests.TransformFeedbackCase.prototype.verify = function(calls) {
   1241        // Check status after mapping buffers.
   1242        var mustBeReady = this.m_outputBuffers.length > 0; // Mapping buffer forces synchronization. // const bool
   1243        var expectedCount = es3fTransformFeedbackTests.computeTransformFeedbackPrimitiveCount(this.m_primitiveType, calls); // const int
   1244        var available = /** @type {boolean} */ (gl.getQueryParameter(this.m_primitiveQuery, gl.QUERY_RESULT_AVAILABLE));
   1245        var verify_offset = 0;
   1246        var queryOk = true;
   1247        if (!available) {
   1248            if (!this.m_verifyStart)
   1249                this.m_verifyStart = new Date();
   1250            else {
   1251                var current = new Date();
   1252                var elapsedTime = 0.001 * (current.getTime() - this.m_verifyStart.getTime());
   1253                if (elapsedTime > es3fTransformFeedbackTests.MAX_VERIFY_WAIT) {
   1254                    testFailed('Query result not available after ' + elapsedTime + ' seconds.');
   1255                    this.m_state = es3fTransformFeedbackTests.State.FINISH;
   1256                    return this.createVerificationResult(false, false);
   1257                }
   1258            }
   1259            return this.createVerificationResult(true, false);
   1260        }
   1261 
   1262        var numPrimitives = /** @type {number} */ (gl.getQueryParameter(this.m_primitiveQuery, gl.QUERY_RESULT));
   1263 
   1264        if (!mustBeReady && available == false)
   1265            bufferedLogToConsole('ERROR: gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN result not available after mapping buffers!');
   1266 
   1267        bufferedLogToConsole('gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = ' + numPrimitives);
   1268 
   1269        if (numPrimitives != expectedCount) {
   1270            queryOk = false;
   1271            bufferedLogToConsole('ERROR: Expected ' + expectedCount + ' primitives!');
   1272        }
   1273 
   1274        // Clear transform feedback state.
   1275        gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
   1276        for (var bufNdx = 0; bufNdx < this.m_outputBuffers.length; ++bufNdx) {
   1277            gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
   1278            gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, bufNdx, null);
   1279        }
   1280 
   1281        gl.bindBuffer(gl.ARRAY_BUFFER, null);
   1282 
   1283        // Read back rendered image.
   1284        this.m_frameWithTf.readViewport(gl, [this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH]);
   1285 
   1286        // Render without transform feedback.
   1287 
   1288        gl.clear(gl.COLOR_BUFFER_BIT);
   1289 
   1290        for (var i = 0; i < calls.length; ++i) {
   1291            var call = calls[i];
   1292            gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, this.m_primitiveType), verify_offset, call.numElements);
   1293            verify_offset += call.numElements;
   1294        }
   1295        this.m_frameWithoutTf.readViewport(gl, [this.m_viewportX, this.m_viewportY, this.m_viewportW, this.m_viewportH]);
   1296 
   1297        // Compare images with and without transform feedback.
   1298        var imagesOk = tcuImageCompare.pixelThresholdCompare('Result', 'Image comparison result', this.m_frameWithoutTf, this.m_frameWithTf, [1, 1, 1, 1], tcuImageCompare.CompareLogMode.ON_ERROR);
   1299 
   1300        if (imagesOk)
   1301            bufferedLogToConsole('Rendering result comparison between TF enabled and TF disabled passed.');
   1302        else
   1303            bufferedLogToConsole('ERROR: Rendering result comparison between TF enabled and TF disabled failed!');
   1304 
   1305        return this.createVerificationResult(false, this.m_outputsOk && imagesOk && queryOk);
   1306 
   1307    };
   1308 
   1309    es3fTransformFeedbackTests.dc = function(numElements, tfEnabled) {
   1310        return new es3fTransformFeedbackTests.DrawCall(numElements, tfEnabled);
   1311    };
   1312 
   1313    // static data
   1314    es3fTransformFeedbackTests.TransformFeedbackCase.s_iterate = {
   1315 
   1316        testCases: {
   1317            elemCount1: [es3fTransformFeedbackTests.dc(1, true)],
   1318            elemCount2: [es3fTransformFeedbackTests.dc(2, true)],
   1319            elemCount3: [es3fTransformFeedbackTests.dc(3, true)],
   1320            elemCount4: [es3fTransformFeedbackTests.dc(4, true)],
   1321            elemCount123: [es3fTransformFeedbackTests.dc(123, true)],
   1322            basicPause1: [es3fTransformFeedbackTests.dc(64, true), es3fTransformFeedbackTests.dc(64, false), es3fTransformFeedbackTests.dc(64, true)],
   1323            basicPause2: [es3fTransformFeedbackTests.dc(13, true), es3fTransformFeedbackTests.dc(5, true), es3fTransformFeedbackTests.dc(17, false),
   1324                           es3fTransformFeedbackTests.dc(3, true), es3fTransformFeedbackTests.dc(7, false)],
   1325            startPaused: [es3fTransformFeedbackTests.dc(123, false), es3fTransformFeedbackTests.dc(123, true)],
   1326            random1: [es3fTransformFeedbackTests.dc(65, true), es3fTransformFeedbackTests.dc(135, false), es3fTransformFeedbackTests.dc(74, true),
   1327                           es3fTransformFeedbackTests.dc(16, false), es3fTransformFeedbackTests.dc(226, false), es3fTransformFeedbackTests.dc(9, true),
   1328                           es3fTransformFeedbackTests.dc(174, false)],
   1329            random2: [es3fTransformFeedbackTests.dc(217, true), es3fTransformFeedbackTests.dc(171, true), es3fTransformFeedbackTests.dc(147, true),
   1330                           es3fTransformFeedbackTests.dc(152, false), es3fTransformFeedbackTests.dc(55, true)]
   1331        },
   1332        iterations: [
   1333            'elemCount1', 'elemCount2', 'elemCount3', 'elemCount4', 'elemCount123',
   1334            'basicPause1', 'basicPause2', 'startPaused',
   1335            'random1', 'random2'
   1336        ]
   1337    };
   1338 
   1339    es3fTransformFeedbackTests.hasArraysInTFVaryings = function(spec) {
   1340 
   1341        for (var i = 0; i < spec.getTransformFeedbackVaryings().length; ++i) {
   1342            var tfVar = spec.getTransformFeedbackVaryings()[i];
   1343            var varName = gluVarTypeUtil.parseVariableName(tfVar);
   1344 
   1345        var attr = es3fTransformFeedbackTests.findAttributeNameEquals(spec.getVaryings(), varName);
   1346        if (attr && attr.type.isArrayType())
   1347                return true;
   1348        }
   1349        return false;
   1350 
   1351    };
   1352 
   1353    /** es3fTransformFeedbackTests.PositionCase
   1354     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1355     * @param {string} name
   1356     * @param {string} desc
   1357     * @param {number} bufferMode
   1358     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1359     * @constructor
   1360     */
   1361    es3fTransformFeedbackTests.PositionCase = function(name, desc, bufferMode, primitiveType) {
   1362        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1363        this.m_progSpec.addTransformFeedbackVarying('gl_Position');
   1364    };
   1365 
   1366    setParentClass(es3fTransformFeedbackTests.PositionCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1367 
   1368    /** es3fTransformFeedbackTests.PointSizeCase
   1369     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1370     * @param {string} name
   1371     * @param {string} desc
   1372     * @param {number} bufferMode
   1373     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1374     * @constructor
   1375     */
   1376    es3fTransformFeedbackTests.PointSizeCase = function(name, desc, bufferMode, primitiveType) {
   1377        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1378        this.m_progSpec.addTransformFeedbackVarying('gl_PointSize');
   1379 
   1380    };
   1381 
   1382    setParentClass(es3fTransformFeedbackTests.PointSizeCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1383 
   1384    /** es3fTransformFeedbackTests.BasicTypeCase
   1385     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1386     * @param {string} name
   1387     * @param {string} desc
   1388     * @param {number} bufferMode
   1389     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1390     * @param {gluShaderUtil.DataType} type
   1391     * @param {gluShaderUtil.precision} precision
   1392     * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
   1393     * @constructor
   1394     */
   1395    es3fTransformFeedbackTests.BasicTypeCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
   1396        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1397 
   1398        this.m_progSpec.addVarying('v_varA', gluVarType.newTypeBasic(type, precision), interpolation);
   1399        this.m_progSpec.addVarying('v_varB', gluVarType.newTypeBasic(type, precision), interpolation);
   1400 
   1401        this.m_progSpec.addTransformFeedbackVarying('v_varA');
   1402        this.m_progSpec.addTransformFeedbackVarying('v_varB');
   1403 
   1404    };
   1405 
   1406    setParentClass(es3fTransformFeedbackTests.BasicTypeCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1407 
   1408    /** es3fTransformFeedbackTests.BasicArrayCase
   1409     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1410     * @param {string} name
   1411     * @param {string} desc
   1412     * @param {number} bufferMode
   1413     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1414     * @param {gluShaderUtil.DataType} type
   1415     * @param {gluShaderUtil.precision} precision
   1416     * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
   1417     * @constructor
   1418     */
   1419    es3fTransformFeedbackTests.BasicArrayCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
   1420        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1421 
   1422        if (gluShaderUtil.isDataTypeMatrix(type) || this.m_bufferMode === gl.SEPARATE_ATTRIBS) {
   1423            // note For matrix types we need to use reduced array sizes or otherwise we will exceed maximum attribute (16)
   1424            // or transform feedback component es3fTransformFeedbackTests.count (64).
   1425            // On separate attribs mode maximum component es3fTransformFeedbackTests.count per varying is 4.
   1426            this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 1), interpolation);
   1427            this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 2), interpolation);
   1428        } else {
   1429            this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 3), interpolation);
   1430            this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 4), interpolation);
   1431        }
   1432 
   1433        this.m_progSpec.addTransformFeedbackVarying('v_varA');
   1434        this.m_progSpec.addTransformFeedbackVarying('v_varB');
   1435 
   1436    };
   1437 
   1438    setParentClass(es3fTransformFeedbackTests.BasicArrayCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1439 
   1440    /** es3fTransformFeedbackTests.ArrayElementCase
   1441     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1442     * @param {string} name
   1443     * @param {string} desc
   1444     * @param {number} bufferMode
   1445     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1446     * @param {gluShaderUtil.DataType} type
   1447     * @param {gluShaderUtil.precision} precision
   1448     * @param {es3fTransformFeedbackTests.interpolation} interpolation enum number in this javascript
   1449     * @constructor
   1450     */
   1451    es3fTransformFeedbackTests.ArrayElementCase = function(name, desc, bufferMode, primitiveType, type, precision, interpolation) {
   1452 
   1453        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1454 
   1455        this.m_progSpec.addVarying('v_varA', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 3), interpolation);
   1456        this.m_progSpec.addVarying('v_varB', gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), 4), interpolation);
   1457 
   1458        this.m_progSpec.addTransformFeedbackVarying('v_varA[1]');
   1459        this.m_progSpec.addTransformFeedbackVarying('v_varB[0]');
   1460        this.m_progSpec.addTransformFeedbackVarying('v_varB[3]');
   1461 
   1462    };
   1463 
   1464    setParentClass(es3fTransformFeedbackTests.ArrayElementCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1465 
   1466    /** es3fTransformFeedbackTests.RandomCase
   1467     * @extends {es3fTransformFeedbackTests.TransformFeedbackCase}
   1468     * @param {string} name
   1469     * @param {string} desc
   1470     * @param {number} bufferMode
   1471     * @param {gluDrawUtil.primitiveType} primitiveType GLenum that specifies what kind of primitive is
   1472     * @param {number} seed
   1473     * @constructor
   1474     */
   1475    es3fTransformFeedbackTests.RandomCase = function(name, desc, bufferMode, primitiveType, seed) {
   1476        es3fTransformFeedbackTests.TransformFeedbackCase.call(this, name, desc, bufferMode, primitiveType);
   1477 
   1478    };
   1479 
   1480    setParentClass(es3fTransformFeedbackTests.RandomCase, es3fTransformFeedbackTests.TransformFeedbackCase);
   1481 
   1482    es3fTransformFeedbackTests.RandomCase.prototype.init = function() {
   1483 
   1484        /** @type {number} */
   1485        var seed = /*deString.deStringHash(getName()) ^ */ deMath.deMathHash(this.m_iterNdx);
   1486 
   1487        /** @type {Array<gluShaderUtil.DataType>} */
   1488        var typeCandidates = [
   1489            gluShaderUtil.DataType.FLOAT,
   1490            gluShaderUtil.DataType.FLOAT_VEC2,
   1491            gluShaderUtil.DataType.FLOAT_VEC3,
   1492            gluShaderUtil.DataType.FLOAT_VEC4,
   1493            gluShaderUtil.DataType.INT,
   1494            gluShaderUtil.DataType.INT_VEC2,
   1495            gluShaderUtil.DataType.INT_VEC3,
   1496            gluShaderUtil.DataType.INT_VEC4,
   1497            gluShaderUtil.DataType.UINT,
   1498            gluShaderUtil.DataType.UINT_VEC2,
   1499            gluShaderUtil.DataType.UINT_VEC3,
   1500            gluShaderUtil.DataType.UINT_VEC4,
   1501 
   1502            gluShaderUtil.DataType.FLOAT_MAT2,
   1503            gluShaderUtil.DataType.FLOAT_MAT2X3,
   1504            gluShaderUtil.DataType.FLOAT_MAT2X4,
   1505 
   1506            gluShaderUtil.DataType.FLOAT_MAT3X2,
   1507            gluShaderUtil.DataType.FLOAT_MAT3,
   1508            gluShaderUtil.DataType.FLOAT_MAT3X4,
   1509 
   1510            gluShaderUtil.DataType.FLOAT_MAT4X2,
   1511            gluShaderUtil.DataType.FLOAT_MAT4X3,
   1512            gluShaderUtil.DataType.FLOAT_MAT4
   1513        ];
   1514 
   1515        /** @type {Array<gluShaderUtil.precision>} */
   1516        var precisions = [
   1517            gluShaderUtil.precision.PRECISION_LOWP,
   1518            gluShaderUtil.precision.PRECISION_MEDIUMP,
   1519            gluShaderUtil.precision.PRECISION_HIGHP
   1520        ];
   1521 
   1522        var interpModes = [{name: 'smooth', interp: es3fTransformFeedbackTests.interpolation.SMOOTH}, {name: 'flat', interp: es3fTransformFeedbackTests.interpolation.FLAT}, {name: 'centroid', interp: es3fTransformFeedbackTests.interpolation.CENTROID}
   1523        ];
   1524 
   1525        /** @type {number} */ var maxAttributeVectors = 16;
   1526       //** @type {number} */  var maxTransformFeedbackComponents = 64; // note It is enough to limit attribute set size.
   1527        /** @type {boolean} */ var isSeparateMode = (this.m_bufferMode === gl.SEPARATE_ATTRIBS);
   1528        /** @type {number} */ var maxTransformFeedbackVars = isSeparateMode ? 4 : maxAttributeVectors;
   1529        /** @type {number} */ var arrayWeight = 0.3;
   1530        /** @type {number} */ var positionWeight = 0.7;
   1531        /** @type {number} */ var pointSizeWeight = 0.1;
   1532        /** @type {number} */ var captureFullArrayWeight = 0.5;
   1533 
   1534        /** @type {deRandom.Random} */
   1535                               var rnd = new deRandom.Random(seed);
   1536        /** @type {boolean} */ var usePosition = rnd.getFloat() < positionWeight;
   1537        /** @type {boolean} */ var usePointSize = rnd.getFloat() < pointSizeWeight;
   1538        /** @type {number} */ var numAttribVectorsToUse = rnd.getInt(
   1539            1, maxAttributeVectors - 1/*position*/ - (usePointSize ? 1 : 0)
   1540        );
   1541 
   1542        /** @type {number} */ var numAttributeVectors = 0;
   1543        /** @type {number} */ var varNdx = 0;
   1544 
   1545        // Generate varyings.
   1546        while (numAttributeVectors < numAttribVectorsToUse) {
   1547            /** @type {number} */
   1548            var maxVecs = isSeparateMode ? Math.min(2 /*at most 2*mat2*/, numAttribVectorsToUse - numAttributeVectors) : numAttribVectorsToUse - numAttributeVectors;
   1549            /** @type {gluShaderUtil.DataType} */
   1550            var begin = typeCandidates[0];
   1551            /** @type {number} */
   1552            var endCandidates = begin + (
   1553                maxVecs >= 4 ? 21 : (
   1554                    maxVecs >= 3 ? 18 : (
   1555                        maxVecs >= 2 ? (isSeparateMode ? 13 : 15) : 12
   1556                    )
   1557                )
   1558            );
   1559            /** @type {gluShaderUtil.DataType} */
   1560            var end = typeCandidates[endCandidates];
   1561 
   1562            /** @type {gluShaderUtil.DataType} */
   1563            var type = rnd.choose(typeCandidates)[0];
   1564 
   1565            /** @type {gluShaderUtil.precision} */
   1566            var precision = rnd.choose(precisions)[0];
   1567 
   1568            /** @type {es3fTransformFeedbackTests.interpolation} */
   1569            var interp = (type === gluShaderUtil.DataType.FLOAT) ?
   1570                       rnd.choose(interpModes)[0].interp :
   1571                       es3fTransformFeedbackTests.interpolation.FLAT;
   1572 
   1573            /** @type {number} */
   1574            var numVecs = gluShaderUtil.isDataTypeMatrix(type) ? gluShaderUtil.getDataTypeMatrixNumColumns(type) : 1;
   1575            /** @type {number} */
   1576            var numComps = gluShaderUtil.getDataTypeScalarSize(type);
   1577            /** @type {number} */
   1578            var maxArrayLen = Math.max(1, isSeparateMode ? (4 / numComps) : (maxVecs / numVecs));
   1579            /** @type {boolean} */
   1580            var useArray = rnd.getFloat() < arrayWeight;
   1581            /** @type {number} */
   1582            var arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 1;
   1583            /** @type {string} */
   1584            var name = 'v_var' + varNdx;
   1585 
   1586            if (useArray)
   1587                this.m_progSpec.addVarying(name, gluVarType.newTypeArray(gluVarType.newTypeBasic(type, precision), arrayLen), interp);
   1588            else
   1589                this.m_progSpec.addVarying(name, gluVarType.newTypeBasic(type, precision), interp);
   1590 
   1591            numAttributeVectors += arrayLen * numVecs;
   1592            varNdx += 1;
   1593        }
   1594 
   1595        // Generate transform feedback candidate set.
   1596        /** @type {Array<string>} */ var tfCandidates = [];
   1597 
   1598        if (usePosition) tfCandidates.push('gl_Position');
   1599        if (usePointSize) tfCandidates.push('gl_PointSize');
   1600 
   1601        for (var ndx = 0; ndx < varNdx; ndx++) {
   1602            /** @type {es3fTransformFeedbackTests.Varying} */
   1603            var varying = this.m_progSpec.getVaryings()[ndx];
   1604 
   1605            if (varying.type.isArrayType()) {
   1606                /** @type {boolean} */
   1607                var captureFull = rnd.getFloat() < captureFullArrayWeight;
   1608 
   1609                if (captureFull) {
   1610                    tfCandidates.push(varying.name);
   1611                } else {
   1612                    /** @type {number} */
   1613                    var numElem = varying.type.getArraySize();
   1614                    for (var elemNdx = 0; elemNdx < numElem; elemNdx++)
   1615                        tfCandidates.push(varying.name + '[' + elemNdx + ']');
   1616                }
   1617            } else
   1618                tfCandidates.push(varying.name);
   1619        }
   1620 
   1621        // Pick random selection.
   1622        var tfVaryings = [];
   1623        rnd.choose(tfCandidates, tfVaryings, Math.min(tfCandidates.length, maxTransformFeedbackVars));
   1624        rnd.shuffle(tfVaryings);
   1625        for (var i = 0; i < tfVaryings.length; i++)
   1626            this.m_progSpec.addTransformFeedbackVarying(tfVaryings[i]);
   1627 
   1628        es3fTransformFeedbackTests.TransformFeedbackCase.prototype.init.call(this);
   1629 
   1630    };
   1631 
   1632    /**
   1633     * Creates the test in order to be executed
   1634    **/
   1635    es3fTransformFeedbackTests.init = function() {
   1636 
   1637        /** @const @type {tcuTestCase.DeqpTest} */
   1638        var testGroup = tcuTestCase.runner.testCases;
   1639 
   1640        var bufferModes = [{name: 'separate', mode: gl.SEPARATE_ATTRIBS}, {name: 'interleaved', mode: gl.INTERLEAVED_ATTRIBS}
   1641        ];
   1642 
   1643        var primitiveTypes = [{name: 'points', type: gluDrawUtil.primitiveType.POINTS}, {name: 'lines', type: gluDrawUtil.primitiveType.LINES}, {name: 'triangles', type: gluDrawUtil.primitiveType.TRIANGLES}
   1644        ];
   1645 
   1646        /** @type {Array<gluShaderUtil.DataType>} */
   1647        var basicTypes = [
   1648            gluShaderUtil.DataType.FLOAT,
   1649            gluShaderUtil.DataType.FLOAT_VEC2,
   1650            gluShaderUtil.DataType.FLOAT_VEC3,
   1651            gluShaderUtil.DataType.FLOAT_VEC4,
   1652            gluShaderUtil.DataType.FLOAT_MAT2,
   1653            gluShaderUtil.DataType.FLOAT_MAT2X3,
   1654            gluShaderUtil.DataType.FLOAT_MAT2X4,
   1655            gluShaderUtil.DataType.FLOAT_MAT3X2,
   1656            gluShaderUtil.DataType.FLOAT_MAT3,
   1657            gluShaderUtil.DataType.FLOAT_MAT3X4,
   1658            gluShaderUtil.DataType.FLOAT_MAT4X2,
   1659            gluShaderUtil.DataType.FLOAT_MAT4X3,
   1660            gluShaderUtil.DataType.FLOAT_MAT4,
   1661            gluShaderUtil.DataType.INT,
   1662            gluShaderUtil.DataType.INT_VEC2,
   1663            gluShaderUtil.DataType.INT_VEC3,
   1664            gluShaderUtil.DataType.INT_VEC4,
   1665            gluShaderUtil.DataType.UINT,
   1666            gluShaderUtil.DataType.UINT_VEC2,
   1667            gluShaderUtil.DataType.UINT_VEC3,
   1668            gluShaderUtil.DataType.UINT_VEC4
   1669        ];
   1670 
   1671        /** @type {Array<gluShaderUtil.precision>} */
   1672        var precisions = [
   1673 
   1674            gluShaderUtil.precision.PRECISION_LOWP,
   1675            gluShaderUtil.precision.PRECISION_MEDIUMP,
   1676            gluShaderUtil.precision.PRECISION_HIGHP
   1677 
   1678            // glsUBC.UniformFlags.PRECISION_LOW,
   1679            // glsUBC.UniformFlags.PRECISION_MEDIUM,
   1680            // glsUBC.UniformFlags.PRECISION_HIGH
   1681        ];
   1682 
   1683        var interpModes = [{name: 'smooth', interp: es3fTransformFeedbackTests.interpolation.SMOOTH}, {name: 'flat', interp: es3fTransformFeedbackTests.interpolation.FLAT}, {name: 'centroid', interp: es3fTransformFeedbackTests.interpolation.CENTROID}
   1684        ];
   1685 
   1686        // .position
   1687        /** @type {tcuTestCase.DeqpTest} */
   1688        var positionGroup = tcuTestCase.newTest('position', 'gl_Position capture using transform feedback');
   1689        testGroup.addChild(positionGroup);
   1690 
   1691        for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
   1692            for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
   1693                /** @type {string} */
   1694                var name = primitiveTypes[primitiveType].name + '_' + bufferModes[bufferMode].name;
   1695 
   1696                positionGroup.addChild(new es3fTransformFeedbackTests.PositionCase(
   1697                    name,
   1698                    '',
   1699                    bufferModes[bufferMode].mode,
   1700                    primitiveTypes[primitiveType].type
   1701                ));
   1702            }
   1703        }
   1704 
   1705        // .point_size
   1706        /** @type {tcuTestCase.DeqpTest} */ var pointSizeGroup = tcuTestCase.newTest('point_size', 'gl_PointSize capture using transform feedback');
   1707        testGroup.addChild(pointSizeGroup);
   1708 
   1709        for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
   1710            for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
   1711                var name = primitiveTypes[primitiveType].name + '_' + bufferModes[bufferMode].name;
   1712 
   1713                pointSizeGroup.addChild(new es3fTransformFeedbackTests.PointSizeCase(
   1714                    name,
   1715                    '',
   1716                    bufferModes[bufferMode].mode,
   1717                    primitiveTypes[primitiveType].type
   1718                ));
   1719            }
   1720        }
   1721 
   1722        // .basic_type
   1723        for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
   1724            /** @type {number} */
   1725            var bufferMode = bufferModes[bufferModeNdx].mode;
   1726            for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
   1727                /** @type {tcuTestCase.DeqpTest} */
   1728                var primitiveGroup = tcuTestCase.newTest(
   1729                    'basic_types.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
   1730                    'Basic types in transform feedback');
   1731                /** @type {number} */
   1732                var primitiveType = primitiveTypes[primitiveTypeNdx].type;
   1733                testGroup.addChild(primitiveGroup);
   1734 
   1735                for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
   1736                    /** @type {gluShaderUtil.DataType} */
   1737                    var type = basicTypes[typeNdx];
   1738                    /** @type {boolean} */
   1739                    var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
   1740 
   1741                    for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
   1742                        /** @type {gluShaderUtil.precision} */
   1743                        var precision = precisions[precNdx];
   1744                        var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
   1745 
   1746                        primitiveGroup.addChild(new es3fTransformFeedbackTests.BasicTypeCase(
   1747                            name,
   1748                            '',
   1749                            bufferMode,
   1750                            primitiveType,
   1751                            type,
   1752                            precision,
   1753                            isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
   1754                        ));
   1755                    }
   1756                }
   1757            }
   1758        }
   1759 
   1760        // .array
   1761        for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
   1762            var bufferMode = bufferModes[bufferModeNdx].mode;
   1763            for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
   1764                var primitiveGroup = tcuTestCase.newTest(
   1765                    'array.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
   1766                    'Capturing whole array in TF');
   1767                /** @type {number} */
   1768                var primitiveType = primitiveTypes[primitiveTypeNdx].type;
   1769                testGroup.addChild(primitiveGroup);
   1770 
   1771                for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
   1772                    var type = basicTypes[typeNdx];
   1773                    var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
   1774 
   1775                    for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
   1776                        var precision = precisions[precNdx];
   1777                        var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
   1778 
   1779                        primitiveGroup.addChild(new es3fTransformFeedbackTests.BasicArrayCase(
   1780                            name,
   1781                            '',
   1782                            bufferMode,
   1783                            primitiveType,
   1784                            type,
   1785                            precision,
   1786                            isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
   1787                        ));
   1788                    }
   1789                }
   1790            }
   1791        }
   1792 
   1793        // .array_element
   1794        for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
   1795            var bufferMode = bufferModes[bufferModeNdx].mode;
   1796            for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
   1797                var primitiveGroup = tcuTestCase.newTest(
   1798                    'array_element.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
   1799                    'Capturing single array element in TF');
   1800                var primitiveType = primitiveTypes[primitiveTypeNdx].type;
   1801                testGroup.addChild(primitiveGroup);
   1802 
   1803                for (var typeNdx = 0; typeNdx < basicTypes.length; typeNdx++) {
   1804                    var type = basicTypes[typeNdx];
   1805                    var isFloat = gluShaderUtil.getDataTypeScalarType(type) == gluShaderUtil.DataType.FLOAT;
   1806 
   1807                    for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
   1808                        var precision = precisions[precNdx];
   1809                        var name = gluShaderUtil.getPrecisionName(precision) + '_' + gluShaderUtil.getDataTypeName(type);
   1810 
   1811                        primitiveGroup.addChild(new es3fTransformFeedbackTests.ArrayElementCase(
   1812                            name,
   1813                            '',
   1814                            bufferMode,
   1815                            primitiveType,
   1816                            type,
   1817                            precision,
   1818                            isFloat ? es3fTransformFeedbackTests.interpolation.SMOOTH : es3fTransformFeedbackTests.interpolation.FLAT
   1819                        ));
   1820                    }
   1821                }
   1822            }
   1823        }
   1824 
   1825        // .interpolation
   1826        for (var modeNdx = 0; modeNdx < interpModes.length; modeNdx++) {
   1827            var interp = interpModes[modeNdx].interp;
   1828            var modeGroup = tcuTestCase.newTest(
   1829                'interpolation.' + interpModes[modeNdx].name,
   1830                'Different interpolation modes in transform feedback varyings');
   1831            testGroup.addChild(modeGroup);
   1832 
   1833            for (var precNdx = 0; precNdx < precisions.length; precNdx++) {
   1834                var precision = precisions[precNdx];
   1835 
   1836                for (var primitiveType = 0; primitiveType < primitiveTypes.length; primitiveType++) {
   1837                    for (var bufferMode = 0; bufferMode < bufferModes.length; bufferMode++) {
   1838                        var name = (
   1839                            gluShaderUtil.getPrecisionName(precision) +
   1840                            '_vec4_' + primitiveTypes[primitiveType].name +
   1841                            '_' + bufferModes[bufferMode].name
   1842                        );
   1843 
   1844                        modeGroup.addChild(new es3fTransformFeedbackTests.BasicTypeCase(
   1845                            name,
   1846                            '',
   1847                            bufferModes[bufferMode].mode,
   1848                            primitiveTypes[primitiveType].type,
   1849                            gluShaderUtil.DataType.FLOAT_VEC4,
   1850                            precision,
   1851                            interp
   1852                        ));
   1853                    }
   1854                }
   1855            }
   1856        }
   1857 
   1858        // .random
   1859        for (var bufferModeNdx = 0; bufferModeNdx < bufferModes.length; bufferModeNdx++) {
   1860            /** @type {number} */
   1861            var bufferMode = bufferModes[bufferModeNdx].mode;
   1862            for (var primitiveTypeNdx = 0; primitiveTypeNdx < primitiveTypes.length; primitiveTypeNdx++) {
   1863                var primitiveGroup = tcuTestCase.newTest(
   1864                    'random.' + bufferModes[bufferModeNdx].name + '.' + primitiveTypes[primitiveTypeNdx].name,
   1865                    'Randomized transform feedback cases');
   1866                /** @type {number} */
   1867                var primitiveType = primitiveTypes[primitiveTypeNdx].type;
   1868                testGroup.addChild(primitiveGroup);
   1869 
   1870                for (var ndx = 0; ndx < 10; ndx++) {
   1871                    /** @type {number} */
   1872                    var seed = deMath.deMathHash(bufferMode) ^ deMath.deMathHash(primitiveType) ^ deMath.deMathHash(ndx);
   1873 
   1874                    primitiveGroup.addChild(new es3fTransformFeedbackTests.RandomCase(
   1875                        (ndx + 1).toString(),
   1876                        '',
   1877                        bufferMode,
   1878                        primitiveType,
   1879                        seed
   1880                    ));
   1881                }
   1882            }
   1883        }
   1884 
   1885    };
   1886 
   1887    /**
   1888     * Create and execute the test cases
   1889     */
   1890    es3fTransformFeedbackTests.run = function(context, range) {
   1891        gl = context;
   1892        var testName = 'transform_feedback';
   1893        var testDescription = 'Transform Feedback Tests';
   1894        var state = tcuTestCase.runner;
   1895 
   1896        state.testName = testName;
   1897        state.testCases = tcuTestCase.newTest(testName, testDescription, null);
   1898 
   1899        //Set up name and description of this test series.
   1900        setCurrentTestName(testName);
   1901        description(testDescription);
   1902        try {
   1903            es3fTransformFeedbackTests.init();
   1904            if (range)
   1905                state.setRange(range);
   1906            tcuTestCase.runTestCases();
   1907        } catch (err) {
   1908            bufferedLogToConsole(err);
   1909            tcuTestCase.runner.terminate();
   1910        }
   1911 
   1912    };
   1913 
   1914 });