tor-browser

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

es3fShaderPrecisionTests.js (48813B)


      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.es3fShaderPrecisionTests');
     23 goog.require('framework.common.tcuTestCase');
     24 goog.require('framework.common.tcuFloat');
     25 goog.require('framework.delibs.debase.deMath');
     26 goog.require('framework.delibs.debase.deRandom');
     27 goog.require('framework.delibs.debase.deString');
     28 goog.require('framework.opengl.gluDrawUtil');
     29 goog.require('framework.opengl.gluShaderProgram');
     30 goog.require('framework.opengl.gluShaderUtil');
     31 
     32 goog.scope(function() {
     33    var es3fShaderPrecisionTests = functional.gles3.es3fShaderPrecisionTests;
     34    var deMath = framework.delibs.debase.deMath;
     35    var deRandom = framework.delibs.debase.deRandom;
     36    var deString = framework.delibs.debase.deString;
     37    var tcuFloat = framework.common.tcuFloat;
     38    var tcuTestCase = framework.common.tcuTestCase;
     39    var gluDrawUtil = framework.opengl.gluDrawUtil;
     40    var gluShaderUtil = framework.opengl.gluShaderUtil;
     41    var gluShaderProgram = framework.opengl.gluShaderProgram;
     42 
     43    /** @const {number} */ es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH = 32;
     44    /** @const {number} */ es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT = 32;
     45 
     46    es3fShaderPrecisionTests.add = function(a, b) { return a + b; };
     47    es3fShaderPrecisionTests.sub = function(a, b) { return a - b; };
     48    es3fShaderPrecisionTests.mul = function(a, b) { return a * b; };
     49    // a * b = (a1 * 2^16 + a0) * (b1 * 2^16 + b0) = a1 * b1 * 2^32 + (a0 * b1 + a1 * b0) * 2^16 + a0 * b0
     50    // 32bit integer multiplication may overflow in JavaScript. Only return low 32bit of the result.
     51    es3fShaderPrecisionTests.mul32 = function(a, b) {
     52        var sign = Math.sign(a) * Math.sign(b);
     53        a = Math.abs(a);
     54        b = Math.abs(b);
     55        var a1 = deMath.split16(a)[1];
     56        var a0 = deMath.split16(a)[0];
     57        var b1 = deMath.split16(b)[1];
     58        var b0 = deMath.split16(b)[0];
     59        return sign * ((a0 * b1 + a1 * b0) * 0x10000 + a0 * b0);
     60    }
     61    es3fShaderPrecisionTests.div = function(a, b) { if (b !== 0) return a / b; else throw new Error('division by zero.')};
     62 
     63    /**
     64     * @param {gluShaderUtil.precision} precision
     65     * @param {string} evalOp
     66     * @param {boolean} isVertexCase
     67     * @return {gluShaderProgram.ShaderProgram}
     68     */
     69    es3fShaderPrecisionTests.createFloatPrecisionEvalProgram = function(precision, evalOp, isVertexCase) {
     70        /** @type {gluShaderUtil.DataType} */ var type = gluShaderUtil.DataType.FLOAT;
     71        /** @type {gluShaderUtil.DataType} */ var outType = gluShaderUtil.DataType.UINT;
     72        /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(type);
     73        /** @type {string} */ var outTypeName = gluShaderUtil.getDataTypeName(outType);
     74        /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(precision);
     75        /** @type {string} */ var vtx = '';
     76        /** @type {string} */ var frag = '';
     77        /** @type {string} */ var op = '';
     78 
     79        vtx += '#version 300 es\n' +
     80            'in highp vec4 a_position;\n' +
     81            'in ' + precName + ' ' + typeName + ' a_in0;\n' +
     82            'in ' + precName + ' ' + typeName + ' a_in1;\n';
     83        frag += '#version 300 es\n' +
     84            'layout(location = 0) out highp ' + outTypeName + ' o_out;\n';
     85 
     86        if (isVertexCase) {
     87            vtx += 'flat out ' + precName + ' ' + typeName + ' v_out;\n';
     88            frag += 'flat in ' + precName + ' ' + typeName + ' v_out;\n';
     89        } else {
     90            vtx += 'flat out ' + precName + ' ' + typeName + ' v_in0;\n' +
     91                'flat out ' + precName + ' ' + typeName + ' v_in1;\n';
     92            frag += 'flat in ' + precName + ' ' + typeName + ' v_in0;\n' +
     93                'flat in ' + precName + ' ' + typeName + ' v_in1;\n';
     94        }
     95 
     96        vtx += '\nvoid main (void)\n{\n' +
     97            '    gl_Position = a_position;\n';
     98        frag += '\nvoid main (void)\n{\n';
     99 
    100        op += '\t' + precName + ' ' + typeName + ' in0 = ' + (isVertexCase ? 'a_' : 'v_') + 'in0;\n' +
    101            '\t' + precName + ' ' + typeName + ' in1 = ' + (isVertexCase ? 'a_' : 'v_') + 'in1;\n';
    102 
    103        if (!isVertexCase)
    104            op += '\t' + precName + ' ' + typeName + ' res;\n';
    105 
    106        op += '\t' + (isVertexCase ? 'v_out' : 'res') + ' = ' + evalOp + ';\n';
    107 
    108        vtx += isVertexCase ? op : '';
    109        frag += isVertexCase ? '' : op;
    110        op = '';
    111 
    112        if (isVertexCase) {
    113            frag += '    o_out = floatBitsToUint(v_out);\n';
    114        } else {
    115            vtx += '    v_in0 = a_in0;\n' +
    116                '    v_in1 = a_in1;\n';
    117            frag += '    o_out = floatBitsToUint(res);\n';
    118        }
    119 
    120        vtx += '}\n';
    121        frag += '}\n';
    122 
    123        return new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
    124    };
    125 
    126    /**
    127     * @param {gluShaderUtil.DataType} type
    128     * @param {gluShaderUtil.precision} precision
    129     * @param {string} evalOp
    130     * @param {boolean} isVertexCase
    131     * @return {gluShaderProgram.ShaderProgram}
    132     */
    133    es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram = function(type, precision, evalOp, isVertexCase) {
    134        /** @type {string} */ var typeName = gluShaderUtil.getDataTypeName(type);
    135        /** @type {string} */ var precName = gluShaderUtil.getPrecisionName(precision);
    136        /** @type {string} */ var vtx = '';
    137        /** @type {string} */ var frag = '';
    138        /** @type {string} */ var op = '';
    139 
    140        vtx += '#version 300 es\n' +
    141            'in highp vec4 a_position;\n' +
    142            'in ' + precName + ' ' + typeName + ' a_in0;\n' +
    143            'in ' + precName + ' ' + typeName + ' a_in1;\n';
    144        frag += '#version 300 es\n' +
    145            'layout(location = 0) out ' + precName + ' ' + typeName + ' o_out;\n';
    146 
    147        if (isVertexCase) {
    148            vtx += 'flat out ' + precName + ' ' + typeName + ' v_out;\n';
    149            frag += 'flat in ' + precName + ' ' + typeName + ' v_out;\n';
    150        } else {
    151            vtx += 'flat out ' + precName + ' ' + typeName + ' v_in0;\n' +
    152                'flat out ' + precName + ' ' + typeName + ' v_in1;\n';
    153            frag += 'flat in ' + precName + ' ' + typeName + ' v_in0;\n' +
    154                'flat in ' + precName + ' ' + typeName + ' v_in1;\n';
    155        }
    156 
    157        vtx += '\nvoid main (void)\n{\n'+
    158            '    gl_Position = a_position;\n';
    159        frag += '\nvoid main (void)\n{\n';
    160 
    161        op += '\t' + precName + ' ' + typeName + ' in0 = ' + (isVertexCase ? 'a_' : 'v_') + 'in0;\n' +
    162            '\t' + precName + ' ' + typeName + ' in1 = ' + (isVertexCase ? 'a_' : 'v_') + 'in1;\n';
    163 
    164        op += '\t' + (isVertexCase ? 'v_' : 'o_') + 'out = ' + evalOp + ';\n';
    165 
    166        vtx += isVertexCase ? op : '';
    167        frag += isVertexCase ? '' : op;
    168        op = '';
    169 
    170        if (isVertexCase) {
    171            frag += '    o_out = v_out;\n';
    172        } else {
    173            vtx += '    v_in0 = a_in0;\n' +
    174                '    v_in1 = a_in1;\n';
    175        }
    176 
    177        vtx += '}\n';
    178        frag += '}\n';
    179 
    180        return new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(vtx, frag));
    181    };
    182 
    183    /** @typedef {function(number, number)} */ es3fShaderPrecisionTests.EvalFunc;
    184 
    185 
    186    /**
    187     * @constructor
    188     * @extends {tcuTestCase.DeqpTest}
    189     * @param {string} name
    190     * @param {string} desc
    191     * @param {string} op
    192     * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    193     * @param {gluShaderUtil.precision} precision
    194     * @param {Array<number>} rangeA
    195     * @param {Array<number>} rangeB
    196     * @param {boolean} isVertexCase
    197     */
    198    es3fShaderPrecisionTests.ShaderFloatPrecisionCase = function(name, desc, op, evalFunc, precision, rangeA, rangeB, isVertexCase) {
    199        tcuTestCase.DeqpTest.call(this, name, desc);
    200        // Case parameters.
    201        /** @type {string} */ this.m_op = op;
    202        /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
    203        /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
    204        /** @type {Array<number>} */ this.m_rangeA = rangeA;
    205        /** @type {Array<number>} */ this.m_rangeB = rangeB;
    206        /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
    207 
    208        /** @type {number} */ this.m_numTestsPerIter = 32;
    209        /** @type {number} */ this.m_numIters = 4;
    210        /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
    211 
    212        // Iteration state.
    213        /** @type {?gluShaderProgram.ShaderProgram} */ this.m_program = null;
    214        /** @type {?WebGLFramebuffer} */ this.m_framebuffer = null;
    215        /** @type {?WebGLRenderbuffer} */ this.m_renderbuffer = null;
    216        /** @type {number} */ this.m_iterNdx = 0;
    217        /** @type {Array<boolean>} */ this.m_iterPass = [];
    218    };
    219 
    220    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    221    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderFloatPrecisionCase;
    222 
    223    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.init = function() {
    224        assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
    225 
    226        // Create program.
    227        this.m_program = es3fShaderPrecisionTests.createFloatPrecisionEvalProgram(this.m_precision, this.m_op, this.m_isVertexCase);
    228 
    229        if (!this.m_program.isOk())
    230            assertMsgOptions(false, 'Compile failed', false, true);
    231 
    232        // Create framebuffer.
    233        this.m_framebuffer = gl.createFramebuffer();
    234        this.m_renderbuffer = gl.createRenderbuffer();
    235 
    236        gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
    237        gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32UI, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
    238 
    239        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    240        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
    241 
    242        assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
    243 
    244        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    245 
    246        this.m_iterNdx = 0;
    247    };
    248 
    249    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.deinit = function() {
    250        if(this.m_framebuffer)
    251            gl.deleteFramebuffer(this.m_framebuffer);
    252        if(this.m_renderbuffer)
    253            gl.deleteRenderbuffer(this.m_renderbuffer);
    254        this.m_program = null;
    255        this.m_framebuffer = null;
    256        this.m_renderbuffer = null;
    257    };
    258 
    259    /**
    260     * @param {number} in0
    261     * @param {number} in1
    262     * @param {number} reference
    263     * @param {number} result
    264     */
    265 
    266    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.compare = function(in0, in1, reference, result) {
    267        // Comparison is done using 64-bit reference value to accurately evaluate rounding mode error.
    268        // If 32-bit reference value is used, 2 bits of rounding error must be allowed.
    269 
    270        // For mediump and lowp types the comparison currently allows 3 bits of rounding error:
    271        // two bits from conversions and one from actual operation.
    272 
    273        // \todo [2013-09-30 pyry] Make this more strict: determine if rounding can actually happen.
    274 
    275        /** @type {number} */ var  mantissaBits = this.m_precision == gluShaderUtil.precision.PRECISION_HIGHP ? 23 : 10;
    276        /** @type {number} */ var  numPrecBits = 52 - mantissaBits;
    277 
    278        /** @type {number} */ var  in0Exp = tcuFloat.newFloat32(in0).exponent();
    279        /** @type {number} */ var  in1Exp = tcuFloat.newFloat32(in1).exponent();
    280        /** @type {number} */ var  resExp = tcuFloat.newFloat32(result).exponent();
    281        /** @type {number} */ var  numLostBits = Math.max(in0Exp - resExp, in1Exp - resExp, 0); // Lost due to mantissa shift.
    282 
    283        /** @type {number} */ var  roundingUlpError = this.m_precision == gluShaderUtil.precision.PRECISION_HIGHP ? 1 : 3;
    284        /** @type {number} */ var  maskBits = numLostBits + numPrecBits;
    285 
    286        bufferedLogToConsole("Assuming " + mantissaBits + " mantissa bits, " + numLostBits + " bits lost in operation, and " + roundingUlpError + " ULP rounding error.")
    287 
    288        // These numbers should never be larger than 52 bits. An assertion in getBitRange verifies this.
    289        /** @type {number} */ var accurateRefBits = tcuFloat.newFloat64(reference).getBitRange(maskBits, 64);
    290        /** @type {number} */ var accurateResBits = tcuFloat.newFloat64(result).getBitRange(maskBits, 64);
    291        /** @type {number} */ var ulpDiff = Math.abs(accurateRefBits - accurateResBits);
    292 
    293        if (ulpDiff > roundingUlpError) {
    294            bufferedLogToConsole("ERROR: comparison failed! ULP diff (ignoring lost/undefined bits) = " + ulpDiff );
    295            return false;
    296        }
    297        else
    298            return true;
    299    };
    300 
    301    /**
    302     * @return {tcuTestCase.IterateResult}
    303     */
    304    es3fShaderPrecisionTests.ShaderFloatPrecisionCase.prototype.iterate = function() {
    305        var testPassed = true;
    306        var testPassedMsg = 'Pass';
    307 
    308        // Constant data.
    309        /** @type {Array<number>} */ var position =[
    310        -1.0, -1.0, 0.0, 1.0,
    311            -1.0, 1.0, 0.0, 1.0,
    312            1.0, -1.0, 0.0, 1.0,
    313            1.0, 1.0, 0.0, 1.0
    314    ];
    315 
    316        /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
    317        /** @type {number} */ var numVertices = 4;
    318        /** @type {Array<number>} */ var in0Arr = [0.0, 0.0, 0.0, 0.0];
    319        /** @type {Array<number>} */ var in1Arr = [0.0, 0.0, 0.0, 0.0];
    320 
    321        /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
    322 
    323        // Image read from GL.
    324        /** @type {goog.TypedArray} */ var pixels_uint = new Uint32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
    325 
    326        // \todo [2012-05-03 pyry] Could be cached.
    327        /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
    328 
    329        gl.useProgram(prog);
    330        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    331 
    332        vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
    333 
    334 
    335        // Compute values and reference.
    336        for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
    337            /** @type {number} */ var in0 = this.m_rnd.getFloat(this.m_rangeA[0], this.m_rangeA[1]);
    338            /** @type {number} */ var in1 = this.m_rnd.getFloat(this.m_rangeB[0], this.m_rangeB[1]);
    339 
    340            // These random numbers are used in the reference computation. But
    341            // highp is only 32 bits, so these float64s must be rounded to
    342            // float32 first for correctness. This is needed for highp_mul_* on
    343            // one Linux/NVIDIA machine.
    344            in0 = tcuFloat.newFloat32(in0).getValue();
    345            in1 = tcuFloat.newFloat32(in1).getValue();
    346 
    347            /** @type {number} */ var refD = this.m_evalFunc(in0, in1);
    348 
    349            bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": "+
    350                "in0 = " + in0 + " / " + tcuFloat.newFloat32(in0).bits() +
    351                ", in1 = " + in1 + " / " + tcuFloat.newFloat32(in1).bits() +
    352                "  reference = " + refD + " / " + tcuFloat.newFloat32(refD).bits());
    353 
    354            in0Arr = [in0, in0, in0, in0];
    355            in1Arr = [in1, in1, in1, in1];
    356            vertexArrays[1] = gluDrawUtil.newFloatVertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
    357            vertexArrays[2] = gluDrawUtil.newFloatVertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
    358 
    359            gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
    360 
    361            gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
    362                es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT, gl.RGBA_INTEGER, gl.UNSIGNED_INT, pixels_uint);
    363 
    364            var pixels = new Float32Array(pixels_uint.buffer);
    365            bufferedLogToConsole("  result = " + pixels[0] + " / " + tcuFloat.newFloat32(pixels[0]).bits());
    366 
    367            // Verify results
    368            /** @type {boolean} */ var firstPixelOk = this.compare(in0, in1, refD, pixels[0]);
    369 
    370            if (firstPixelOk) {
    371                // Check that rest of pixels match to first one.
    372                /** @type {number} */ var firstPixelBits = tcuFloat.newFloat32(pixels[0]).bits();
    373                /** @type {boolean} */ var allPixelsOk = true;
    374 
    375                for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
    376                    for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
    377                        /** @type {number} */ var pixelBits = tcuFloat.newFloat32(pixels[(y * es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4]).bits();
    378 
    379                        if (pixelBits != firstPixelBits) {
    380                            bufferedLogToConsole("ERROR: Inconsistent results, got " + pixelBits + " at (" + x + ", " + y + ")")
    381                            allPixelsOk = false;
    382                        }
    383                    }
    384 
    385                    if (!allPixelsOk)
    386                        break;
    387                }
    388 
    389                if (!allPixelsOk){
    390                    bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + "Inconsistent values in framebuffer");
    391                    testPassed = false;
    392                    testPassedMsg = 'Inconsistent values in framebuffer';
    393                }
    394            }
    395            else{
    396                bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + "Result comparison failed");
    397                testPassed = false;
    398                testPassedMsg = 'Result comparison failed'
    399            }
    400        }
    401 
    402        // [dag] Aggregating test results to make the test less verbose.
    403        this.m_iterPass[this.m_iterNdx] = testPassed;
    404 
    405        // [dag] Show test results after the last iteration is done.
    406        if (this.m_iterPass.length === this.m_numIters) {
    407            if (!deMath.boolAll(this.m_iterPass))
    408                testFailedOptions(testPassedMsg, false);
    409            else
    410                testPassedOptions(testPassedMsg, true);
    411        }
    412        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    413 
    414        this.m_iterNdx += 1;
    415        return (this.m_iterNdx < this.m_numIters) ? tcuTestCase.IterateResult.CONTINUE : tcuTestCase.IterateResult.STOP;
    416    };
    417 
    418    /**
    419     * @constructor
    420     * @extends {tcuTestCase.DeqpTest}
    421     * @param {string} name
    422     * @param {string} desc
    423     * @param {string} op
    424     * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    425     * @param {gluShaderUtil.precision} precision
    426     * @param {number} bits
    427     * @param {Array<number>} rangeA
    428     * @param {Array<number>} rangeB
    429     * @param {boolean} isVertexCase
    430     */
    431    es3fShaderPrecisionTests.ShaderIntPrecisionCase = function(name, desc, op, evalFunc, precision, bits, rangeA, rangeB, isVertexCase) {
    432        tcuTestCase.DeqpTest.call(this, name, desc);
    433        // Case parameters.
    434        /** @type {string} */ this.m_op = op;
    435        /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
    436        /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
    437        /** @type {number} */ this.m_bits = bits;
    438        /** @type {Array<number>} */ this.m_rangeA = rangeA;
    439        /** @type {Array<number>} */ this.m_rangeB = rangeB;
    440        /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
    441 
    442        /** @type {number} */ this.m_numTestsPerIter = 32;
    443        /** @type {number} */ this.m_numIters = 4;
    444        /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
    445 
    446        // Iteration state.
    447        /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
    448        /** @type {WebGLFramebuffer} */ this.m_framebuffer = null;
    449        /** @type {WebGLRenderbuffer} */ this.m_renderbuffer = null;
    450        /** @type {number} */ this.m_iterNdx = 0;
    451    };
    452 
    453    es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    454    es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderIntPrecisionCase;
    455 
    456    es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.init = function() {
    457        assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
    458        // Create program.
    459        this.m_program = es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram(gluShaderUtil.DataType.INT, this.m_precision, this.m_op, this.m_isVertexCase);
    460 
    461        if (!this.m_program.isOk())
    462            assertMsgOptions(false, 'Compile failed', false, true);
    463 
    464        // Create framebuffer.
    465        this.m_framebuffer = gl.createFramebuffer();
    466        this.m_renderbuffer = gl.createRenderbuffer();
    467 
    468        gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
    469        gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32I, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
    470 
    471        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    472        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
    473 
    474        assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
    475 
    476        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    477 
    478        this.m_iterNdx = 0;
    479 
    480        bufferedLogToConsole("Number of accurate bits assumed = " + this.m_bits);
    481    };
    482 
    483    es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.deinit = function() {
    484        if(this.m_framebuffer)
    485            gl.deleteFramebuffer(this.m_framebuffer);
    486        if(this.m_renderbuffer)
    487            gl.deleteRenderbuffer(this.m_renderbuffer);
    488        this.m_program = null;
    489        this.m_framebuffer = null;
    490        this.m_renderbuffer = null;
    491    };
    492 
    493    /**
    494     * @param {number} value
    495     * @param {number} bits
    496     * @return {number}
    497     */
    498 
    499    es3fShaderPrecisionTests.extendTo32Bit = function(value, bits) {
    500        return (value & ((1 << (bits - 1)) - 1)) | ((value & (1 << (bits - 1))) << (32 - bits)) >> (32 - bits);
    501    };
    502 
    503    /**
    504     * @return {tcuTestCase.IterateResult}
    505     */
    506    es3fShaderPrecisionTests.ShaderIntPrecisionCase.prototype.iterate = function() {
    507        var testPassed = true;
    508        var testPassedMsg = 'Pass';
    509        // Constant data.
    510        /** @type {Array<number>} */ var position = [
    511        -1.0, -1.0, 0.0, 1.0,
    512            -1.0, 1.0, 0.0, 1.0,
    513            1.0, -1.0, 0.0, 1.0,
    514            1.0, 1.0, 0.0, 1.0
    515    ]
    516        /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
    517 
    518        /** @type {number} */ var numVertices    = 4;
    519        /** @type {Array<number>} */ var in0Arr = [0, 0, 0, 0];
    520        /** @type {Array<number>} */ var in1Arr = [0, 0, 0, 0];
    521 
    522        /** @type {number} */ var mask = this.m_bits === 32 ? 0xffffffff : ((1 << this.m_bits) - 1);
    523        /** @type {goog.TypedArray} */ var pixels = new Int32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
    524        /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
    525 
    526        /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
    527 
    528        // \todo [2012-05-03 pyry] A bit hacky. getInt() should work fine with ranges like this.
    529        /** @type {boolean} */ var isMaxRangeA = this.m_rangeA[0] === 0x80000000 && this.m_rangeA[1] === 0x7fffffff;
    530        /** @type {boolean} */ var isMaxRangeB = this.m_rangeB[0] === 0x80000000 && this.m_rangeB[1] === 0x7fffffff;
    531 
    532        gl.useProgram(prog);
    533        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    534 
    535        vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
    536 
    537        // Compute values and reference.
    538        for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
    539            /** @type {number} */ var in0 = this.m_rnd.getInt(this.m_rangeA[0], this.m_rangeA[1]); //es3fShaderPrecisionTests.extendTo32Bit(((isMaxRangeA ? Math.abs(this.m_rnd.getInt()) : this.m_rnd.getInt(this.m_rangeA[0], this.m_rangeA[1])) & mask), this.m_bits);
    540            /** @type {number} */ var in1 = this.m_rnd.getInt(this.m_rangeB[0], this.m_rangeB[1]); //es3fShaderPrecisionTests.extendTo32Bit(((isMaxRangeB ? Math.abs(this.m_rnd.getInt()) : this.m_rnd.getInt(this.m_rangeB[0], this.m_rangeB[1])) & mask), this.m_bits);
    541            /** @type {number} */ var refMasked = this.m_evalFunc(in0, in1) & mask;
    542            /** @type {number} */ var refOut = es3fShaderPrecisionTests.extendTo32Bit(refMasked, this.m_bits);
    543 
    544            bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": " +
    545                "in0 = " + in0 + ", in1 = " + in1 + ", ref out = " + refOut + " / " + refMasked);
    546 
    547            in0Arr = [in0, in0, in0, in0];
    548            in1Arr = [in1, in1, in1, in1];
    549 
    550            vertexArrays[1] = gluDrawUtil.newInt32VertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
    551            vertexArrays[2] = gluDrawUtil.newInt32VertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
    552 
    553            gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
    554 
    555            gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
    556                es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT,
    557                gl.RGBA_INTEGER, gl.INT, pixels);
    558 
    559            // Compare pixels.
    560            for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
    561                for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
    562                    /** @type {number} */ var cmpOut = pixels[(y * es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4];
    563                    /** @type {number} */ var cmpMasked = cmpOut & mask;
    564 
    565                    if (cmpMasked != refMasked) {
    566                        bufferedLogToConsole("Comparison failed (at " + x + ", " + y + "): " +
    567                            + "got " + cmpOut + " / " + cmpOut);
    568                        testPassed = false;
    569                        testPassedMsg = 'Comparison failed';
    570                    }
    571                }
    572            }
    573        }
    574 
    575        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    576 
    577        this.m_iterNdx += 1;
    578        if (!testPassed) {
    579            testFailedOptions(testPassedMsg, false);
    580            return tcuTestCase.IterateResult.STOP;
    581        } else if (testPassed && this.m_iterNdx < this.m_numIters) {
    582            return tcuTestCase.IterateResult.CONTINUE;
    583        } else {
    584            testPassedOptions(testPassedMsg, true);
    585            return tcuTestCase.IterateResult.STOP;
    586        }
    587    };
    588 
    589    /**
    590     * @constructor
    591     * @extends {tcuTestCase.DeqpTest}
    592     * @param {string} name
    593     * @param {string} desc
    594     * @param {string} op
    595     * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    596     * @param {gluShaderUtil.precision} precision
    597     * @param {number} bits
    598     * @param {Array<number>} rangeA
    599     * @param {Array<number>} rangeB
    600     * @param {boolean} isVertexCase
    601     */
    602    es3fShaderPrecisionTests.ShaderUintPrecisionCase = function(name, desc, op, evalFunc, precision, bits, rangeA, rangeB, isVertexCase) {
    603        tcuTestCase.DeqpTest.call(this, name, desc);
    604        // Case parameters.
    605        /** @type {string} */ this.m_op = op;
    606        /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.m_evalFunc = evalFunc;
    607        /** @type {gluShaderUtil.precision} */ this.m_precision = precision;
    608        /** @type {number} */ this.m_bits = bits;
    609        /** @type {Array<number>} */ this.m_rangeA = rangeA;
    610        /** @type {Array<number>} */ this.m_rangeB = rangeB;
    611        /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
    612 
    613        /** @type {number} */ this.m_numTestsPerIter = 32;
    614        /** @type {number} */ this.m_numIters = 4;
    615        /** @type {deRandom.Random} */ this.m_rnd = new deRandom.Random(deString.deStringHash(this.name));
    616 
    617        // Iteration state.
    618        /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
    619        /** @type {WebGLFramebuffer} */ this.m_framebuffer = null;
    620        /** @type {WebGLRenderbuffer} */ this.m_renderbuffer = null;
    621        /** @type {number} */ this.m_iterNdx = 0;
    622    };
    623 
    624    es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    625    es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.constructor = es3fShaderPrecisionTests.ShaderUintPrecisionCase;
    626 
    627    es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.init = function() {
    628        assertMsgOptions(!this.m_program && !this.m_framebuffer && !this.m_renderbuffer, 'Program/Framebuffer/Renderbuffer should be null at this point.', false, true);
    629        // Create program.
    630        this.m_program = es3fShaderPrecisionTests.createIntUintPrecisionEvalProgram(gluShaderUtil.DataType.UINT, this.m_precision, this.m_op, this.m_isVertexCase);
    631 
    632        if (!this.m_program.isOk())
    633            assertMsgOptions(false, 'Compile failed', false, true);
    634 
    635        // Create framebuffer.
    636        this.m_framebuffer = gl.createFramebuffer();
    637        this.m_renderbuffer = gl.createRenderbuffer();
    638 
    639        gl.bindRenderbuffer(gl.RENDERBUFFER, this.m_renderbuffer);
    640        gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32UI, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH, es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT);
    641 
    642        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    643        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, this.m_renderbuffer);
    644 
    645        assertMsgOptions(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is incomplete', false, true);
    646 
    647        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    648 
    649        this.m_iterNdx = 0;
    650 
    651        bufferedLogToConsole("Number of accurate bits assumed = " + this.m_bits);
    652    };
    653 
    654    es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.deinit = function() {
    655        if(this.m_framebuffer)
    656            gl.deleteFramebuffer(this.m_framebuffer);
    657        if(this.m_renderbuffer)
    658            gl.deleteRenderbuffer(this.m_renderbuffer);
    659        this.m_program = null;
    660        this.m_framebuffer = null;
    661        this.m_renderbuffer = null;
    662    };
    663 
    664    /**
    665     * @return {tcuTestCase.IterateResult}
    666     */
    667    es3fShaderPrecisionTests.ShaderUintPrecisionCase.prototype.iterate = function() {
    668        var testPassed = true;
    669        var testPassedMsg = 'Pass';
    670 
    671        // Constant data.
    672        /** @type {Array<number>} */ var position = [
    673        -1.0, -1.0, 0.0, 1.0,
    674            -1.0, 1.0, 0.0, 1.0,
    675            1.0, -1.0, 0.0, 1.0,
    676            1.0, 1.0, 0.0, 1.0
    677    ];
    678        /** @type {Array<number>} */ var indices = [0, 1, 2, 2, 1, 3];
    679 
    680        /** @type {number} */ var numVertices = 4;
    681        /** @type {Array<number>} */ var in0Arr = [0, 0, 0, 0];
    682        /** @type {Array<number>} */ var in1Arr = [0, 0, 0, 0];
    683 
    684        /** @type {number} */ var mask = this.m_bits === 32 ? 0xffffffff : ((1 << this.m_bits) - 1);
    685        /** @type {goog.TypedArray} */ var pixels = new Uint32Array(es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH * es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT * 4);
    686        /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
    687 
    688        /** @type {WebGLProgram} */ var prog = this.m_program.getProgram();
    689 
    690        // \todo [2012-05-03 pyry] A bit hacky.
    691        /** @type {boolean} */ var isMaxRangeA = this.m_rangeA[0] === 0 && this.m_rangeA[1] === 0xffffffff;
    692        /** @type {boolean} */ var isMaxRangeB = this.m_rangeB[0] === 0 && this.m_rangeB[1] === 0xffffffff;
    693 
    694        gl.useProgram(prog);
    695        gl.bindFramebuffer(gl.FRAMEBUFFER, this.m_framebuffer);
    696 
    697        vertexArrays[0] = gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numVertices, 0, position);
    698 
    699        // Compute values and reference.
    700        for (var testNdx = 0; testNdx < this.m_numTestsPerIter; testNdx++) {
    701            /** @type {number} */ var in0 = (isMaxRangeA ? Math.abs(this.m_rnd.getInt()) : (this.m_rangeA[0] + Math.abs(this.m_rnd.getInt()) % (this.m_rangeA[1] - this.m_rangeA[0] + 1))) & mask;
    702            /** @type {number} */ var in1 = (isMaxRangeB ? Math.abs(this.m_rnd.getInt()) : (this.m_rangeB[0] + Math.abs(this.m_rnd.getInt()) % (this.m_rangeB[1] - this.m_rangeB[0] + 1))) & mask;
    703            /** @type {number} */ var refOut = this.m_evalFunc(in0, in1) & mask;
    704 
    705            bufferedLogToConsole("iter " + this.m_iterNdx + ", test " + testNdx + ": " +
    706                + "in0 = " + in0 + ", in1 = " + in1 + ", ref out = " + refOut)
    707 
    708            in0Arr = [in0, in0, in0, in0];
    709            in1Arr = [in1, in1, in1, in1];
    710            vertexArrays[1] = gluDrawUtil.newUint32VertexArrayBinding("a_in0", 1, numVertices, 0, in0Arr);
    711            vertexArrays[2] = gluDrawUtil.newUint32VertexArrayBinding("a_in1", 1, numVertices, 0, in1Arr);
    712 
    713            gluDrawUtil.draw(gl, prog, vertexArrays, gluDrawUtil.triangles(indices));
    714 
    715            gl.readPixels(0, 0, es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH,
    716                es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT, gl.RGBA_INTEGER, gl.UNSIGNED_INT, pixels);
    717 
    718            // Compare pixels.
    719            for (var y = 0; y < es3fShaderPrecisionTests.FRAMEBUFFER_HEIGHT; y++) {
    720                for (var x = 0; x < es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH; x++) {
    721                    /** @type {number} */ var cmpOut = pixels[(y*es3fShaderPrecisionTests.FRAMEBUFFER_WIDTH + x) * 4];
    722                    /** @type {number} */ var cmpMasked = cmpOut & mask;
    723 
    724                    if (cmpMasked != refOut) {
    725                        bufferedLogToConsole("Comparison failed (at " + x + ", " + y + "): " + "got " + cmpOut)
    726                        testPassed = false;
    727                        testPassedMsg = 'Comparison failed';
    728                    }
    729                }
    730            }
    731        }
    732 
    733 
    734        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    735 
    736        this.m_iterNdx += 1;
    737        if (!testPassed) {
    738            testFailedOptions(testPassedMsg, false);
    739            return tcuTestCase.IterateResult.STOP;
    740        } else if (testPassed && this.m_iterNdx < this.m_numIters) {
    741            return tcuTestCase.IterateResult.CONTINUE;
    742        } else {
    743            testPassedOptions(testPassedMsg, true);
    744            return tcuTestCase.IterateResult.STOP;
    745        }
    746    };
    747 
    748    /**
    749     * @constructor
    750     * @extends {tcuTestCase.DeqpTest}
    751     */
    752    es3fShaderPrecisionTests.ShaderPrecisionTests = function() {
    753        tcuTestCase.DeqpTest.call(this, 'precision', 'Shader precision requirements validation tests');
    754    };
    755 
    756    es3fShaderPrecisionTests.ShaderPrecisionTests.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    757    es3fShaderPrecisionTests.ShaderPrecisionTests.prototype.constructor = es3fShaderPrecisionTests.ShaderPrecisionTests;
    758 
    759    es3fShaderPrecisionTests.ShaderPrecisionTests.prototype.init = function() {
    760        var testGroup = tcuTestCase.runner.testCases;
    761        // Exp = Emax-2, Mantissa = 0
    762        // /** @type {number} */ var minF32 = tcuFloat.newFloat32((1 << 31) | (0xfd << 23) | 0x0).getValue();
    763        // /** @type {number} */ var maxF32 = tcuFloat.newFloat32((0 << 31) | (0xfd << 23) | 0x0).getValue();
    764        // [dag] Workaround for float32 numbers
    765        /** @type {number} */ var minF32 = new Float32Array(new Uint32Array([1<<31|0xfd<<23|0x0]).buffer)[0];
    766        /** @type {number} */ var maxF32 = new Float32Array(new Uint32Array([0<<31|0xfd<<23|0x0]).buffer)[0];
    767 
    768        // /** @type {number} */ var minF16 = tcuFloat.newFloat16(((1 << 15) | (0x1d << 10) | 0x0)).getValue();
    769        // /** @type {number} */ var maxF16 = tcuFloat.newFloat16(((0 << 15) | (0x1d << 10) | 0x0)).getValue();
    770        /** @type {number} */ var minF16 = -16384; //-1 << 14; // 1 << 15 | 0x1d | 0x0 == 0b1111010000000000; -1 * (2**(29-15)) * 1
    771        /** @type {number} */ var maxF16 = 16384; //1 << 14; // 0 << 15 | 0x1d | 0x0 == 0b0111010000000000; +1 * (2**(29-15)) * 1
    772 
    773        /** @type {Array<number>} */ var fullRange32F = [minF32, maxF32];
    774        /** @type {Array<number>} */ var fullRange16F = [minF16, maxF16];
    775        /** @type {Array<number>} */ var fullRange32I = [-2147483648, 2147483647]; // [0x80000000|0, 0x7fffffff|0]; // |0 to force the number as a 32-bit integer
    776        /** @type {Array<number>} */ var fullRange16I = [minF16, maxF16 - 1]; //[-(1 << 15), (1 << 15) - 1]; // Added the negative sign to index 0
    777        /** @type {Array<number>} */ var fullRange8I = [-128, 127]; //[-(1 << 7), (1 << 7) - 1]; // Added the negative sign to index 0
    778        /** @type {Array<number>} */ var fullRange32U = [0, 0xffffffff];
    779        /** @type {Array<number>} */ var fullRange16U = [0, 0xffff];
    780        /** @type {Array<number>} */ var fullRange8U = [0, 0xff];
    781 
    782        // \note Right now it is not programmatically verified that the results shouldn't end up being inf/nan but
    783        // actual values used are ok.
    784 
    785        /**
    786         * @constructor
    787         * @struct
    788         * @param {string} name
    789         * @param {string} op
    790         * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    791         * @param {gluShaderUtil.precision} precision
    792         * @param {Array<number>} rangeA
    793         * @param {Array<number>} rangeB
    794         */
    795        var FloatCase = function(name, op, evalFunc, precision, rangeA, rangeB) {
    796            /** @type {string} */ this.name = name;
    797            /** @type {string} */ this.op = op;
    798            /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
    799            /** @type {gluShaderUtil.precision} */ this.precision = precision;
    800            /** @type {Array<number>} */ this.rangeA = rangeA;
    801            /** @type {Array<number>} */ this.rangeB = rangeB;
    802        };
    803 
    804        /** @type {Array<FloatCase>} */ var floatCases = [
    805        new FloatCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, fullRange32F, fullRange32F),
    806            new FloatCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, fullRange32F, fullRange32F),
    807            new FloatCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_HIGHP, [-1e5, 1e5], [-1e5, 1e5]),
    808            new FloatCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, [-1e5, 1e5], [-1e5, 1e5]),
    809            new FloatCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, fullRange16F, fullRange16F),
    810            new FloatCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, fullRange16F, fullRange16F),
    811            new FloatCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, [-1e2, 1e2], [-1e2, 1e2]),
    812            new FloatCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, [-1e2, 1e2], [-1e2, 1e2])
    813    ];
    814 
    815        /**
    816         * @constructor
    817         * @struct
    818         * @param {string} name
    819         * @param {string} op
    820         * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    821         * @param {gluShaderUtil.precision} precision
    822         * @param {number} bits
    823         * @param {Array<number>} rangeA
    824         * @param {Array<number>} rangeB
    825         */
    826        var IntCase = function(name, op, evalFunc, precision, bits, rangeA, rangeB) {
    827            /** @type {string} */ this.name = name;
    828            /** @type {string} */ this.op = op;
    829            /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
    830            /** @type {gluShaderUtil.precision} */ this.precision = precision;
    831            /** @type {number} */ this.bits = bits;
    832            /** @type {Array<number>} */ this.rangeA = rangeA;
    833            /** @type {Array<number>} */ this.rangeB = rangeB;
    834        };
    835 
    836        /** @type {Array<IntCase>} */ var intCases = [
    837        new IntCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
    838            new IntCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
    839            new IntCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul32, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, fullRange32I),
    840            new IntCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32I, [-10000, -1]),
    841            new IntCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
    842            new IntCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
    843            new IntCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, fullRange16I),
    844            new IntCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16I, [1, 1000]),
    845            new IntCase('lowp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
    846            new IntCase('lowp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
    847            new IntCase('lowp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, fullRange8I),
    848            new IntCase('lowp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8I, [-50, -1])
    849    ];
    850 
    851        /**
    852         * @constructor
    853         * @struct
    854         * @param {string} name
    855         * @param {string} op
    856         * @param {es3fShaderPrecisionTests.EvalFunc} evalFunc
    857         * @param {gluShaderUtil.precision} precision
    858         * @param {number} bits
    859         * @param {Array<number>} rangeA
    860         * @param {Array<number>} rangeB
    861         */
    862        var UintCase = function(name, op, evalFunc, precision, bits, rangeA, rangeB) {
    863            /** @type {string} */ this.name = name;
    864            /** @type {string} */ this.op = op;
    865            /** @type {es3fShaderPrecisionTests.EvalFunc} */ this.evalFunc = evalFunc;
    866            /** @type {gluShaderUtil.precision} */ this.precision = precision;
    867            /** @type {number} */ this.bits = bits;
    868            /** @type {Array<number>} */ this.rangeA = rangeA;
    869            /** @type {Array<number>} */ this.rangeB = rangeB;
    870        };
    871 
    872        /** @type {Array<UintCase>} */ var uintCases = [
    873        new UintCase('highp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
    874            new UintCase('highp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
    875            new UintCase('highp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul32, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, fullRange32U),
    876            new UintCase('highp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_HIGHP, 32, fullRange32U, [1, 10000]),
    877            new UintCase('mediump_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
    878            new UintCase('mediump_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
    879            new UintCase('mediump_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, fullRange16U),
    880            new UintCase('mediump_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_MEDIUMP, 16, fullRange16U, [1, 1000]),
    881            new UintCase('lowp_add', 'in0 + in1', es3fShaderPrecisionTests.add, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
    882            new UintCase('lowp_sub', 'in0 - in1', es3fShaderPrecisionTests.sub, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
    883            new UintCase('lowp_mul', 'in0 * in1', es3fShaderPrecisionTests.mul, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, fullRange8U),
    884            new UintCase('lowp_div', 'in0 / in1', es3fShaderPrecisionTests.div, gluShaderUtil.precision.PRECISION_LOWP, 8, fullRange8U, [1, 50])
    885    ];
    886 
    887        /** @type {tcuTestCase.DeqpTest} */ var floatGroup = tcuTestCase.newTest('float', 'Floating-point precision tests');
    888        testGroup.addChild(floatGroup);
    889        for (var ndx = 0; ndx < floatCases.length; ndx++) {
    890            floatGroup.addChild(new es3fShaderPrecisionTests.ShaderFloatPrecisionCase(
    891                floatCases[ndx].name + '_vertex', '', floatCases[ndx].op, floatCases[ndx].evalFunc,
    892                floatCases[ndx].precision, floatCases[ndx].rangeA, floatCases[ndx].rangeB, true));
    893            floatGroup.addChild(new es3fShaderPrecisionTests.ShaderFloatPrecisionCase(
    894                floatCases[ndx].name + '_fragment', '', floatCases[ndx].op, floatCases[ndx].evalFunc,
    895                floatCases[ndx].precision, floatCases[ndx].rangeA, floatCases[ndx].rangeB, false));
    896        }
    897 
    898        /** @type {tcuTestCase.DeqpTest} */ var intGroup = tcuTestCase.newTest('int', 'Integer precision tests');
    899        testGroup.addChild(intGroup);
    900        for (var ndx = 0; ndx < intCases.length; ndx++) {
    901            intGroup.addChild(new es3fShaderPrecisionTests.ShaderIntPrecisionCase(
    902                intCases[ndx].name + '_vertex', '', intCases[ndx].op, intCases[ndx].evalFunc,
    903                intCases[ndx].precision, intCases[ndx].bits, intCases[ndx].rangeA, intCases[ndx].rangeB, true));
    904            intGroup.addChild(new es3fShaderPrecisionTests.ShaderIntPrecisionCase(
    905                intCases[ndx].name + '_fragment', '', intCases[ndx].op, intCases[ndx].evalFunc,
    906                intCases[ndx].precision, intCases[ndx].bits, intCases[ndx].rangeA, intCases[ndx].rangeB, false));
    907        }
    908 
    909        /** @type {tcuTestCase.DeqpTest} */ var uintGroup = tcuTestCase.newTest('uint', 'Unsigned integer precision tests');
    910        testGroup.addChild(uintGroup);
    911        for (var ndx = 0; ndx < uintCases.length; ndx++) {
    912            uintGroup.addChild(new es3fShaderPrecisionTests.ShaderUintPrecisionCase(
    913                uintCases[ndx].name + '_vertex', '', uintCases[ndx].op, uintCases[ndx].evalFunc,
    914                uintCases[ndx].precision, uintCases[ndx].bits, uintCases[ndx].rangeA, uintCases[ndx].rangeB, true));
    915            uintGroup.addChild(new es3fShaderPrecisionTests.ShaderUintPrecisionCase(
    916                uintCases[ndx].name + '_fragment', '', uintCases[ndx].op, uintCases[ndx].evalFunc,
    917                uintCases[ndx].precision, uintCases[ndx].bits, uintCases[ndx].rangeA, uintCases[ndx].rangeB, false));
    918        }
    919    };
    920 
    921    /**
    922     * Run test
    923     * @param {WebGL2RenderingContext} context
    924     */
    925    es3fShaderPrecisionTests.run = function(context, range) {
    926        gl = context;
    927        //Set up Test Root parameters
    928        var state = tcuTestCase.runner;
    929        state.setRoot(new es3fShaderPrecisionTests.ShaderPrecisionTests());
    930 
    931        //Set up name and description of this test series.
    932        setCurrentTestName(state.testCases.fullName());
    933        description(state.testCases.getDescription());
    934 
    935        try {
    936            if (range)
    937                state.setRange(range);
    938            //Run test cases
    939            tcuTestCase.runTestCases();
    940        }
    941        catch (err) {
    942            testFailedOptions('Failed to es3fShaderPrecisionTests.run tests', false);
    943            tcuTestCase.runner.terminate();
    944        }
    945    };
    946 
    947 });