tor-browser

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

glsShaderRenderCase.js (48630B)


      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('modules.shared.glsShaderRenderCase');
     23 goog.require('framework.common.tcuImageCompare');
     24 goog.require('framework.common.tcuMatrix');
     25 goog.require('framework.common.tcuRGBA');
     26 goog.require('framework.common.tcuSurface');
     27 goog.require('framework.common.tcuTestCase');
     28 goog.require('framework.common.tcuTexture');
     29 goog.require('framework.delibs.debase.deMath');
     30 goog.require('framework.delibs.debase.deString');
     31 goog.require('framework.delibs.debase.deRandom');
     32 goog.require('framework.opengl.gluDrawUtil');
     33 goog.require('framework.opengl.gluTexture');
     34 goog.require('framework.opengl.gluTextureUtil');
     35 goog.require('framework.opengl.gluShaderProgram');
     36 
     37 goog.scope(function() {
     38    var glsShaderRenderCase = modules.shared.glsShaderRenderCase;
     39 
     40    var deMath = framework.delibs.debase.deMath;
     41    var deString = framework.delibs.debase.deString;
     42    var deRandom = framework.delibs.debase.deRandom;
     43    var gluTextureUtil = framework.opengl.gluTextureUtil;
     44    var gluTexture = framework.opengl.gluTexture;
     45    var gluDrawUtil = framework.opengl.gluDrawUtil;
     46    var tcuImageCompare = framework.common.tcuImageCompare;
     47    var tcuTexture = framework.common.tcuTexture;
     48    var tcuMatrix = framework.common.tcuMatrix;
     49    var tcuRGBA = framework.common.tcuRGBA;
     50    var tcuTestCase = framework.common.tcuTestCase;
     51    var tcuSurface = framework.common.tcuSurface;
     52    var gluShaderProgram = framework.opengl.gluShaderProgram;
     53 
     54    /** @typedef {function(glsShaderRenderCase.ShaderEvalContext)} */ glsShaderRenderCase.ShaderEvalFunc;
     55 
     56    /** @const {number} */ glsShaderRenderCase.GRID_SIZE = 64;
     57    /** @const {number} */ glsShaderRenderCase.MAX_RENDER_WIDTH = 128;
     58    /** @const {number} */ glsShaderRenderCase.MAX_RENDER_HEIGHT = 112;
     59    /** @const {Array<number>} */ glsShaderRenderCase.DEFAULT_CLEAR_COLOR = [0.125, 0.25, 0.5, 1.0];
     60    /** @const {number} */ glsShaderRenderCase.MAX_USER_ATTRIBS = 4;
     61    /** @const {number} */ glsShaderRenderCase.MAX_TEXTURES = 4;
     62 
     63    /**
     64     * @param  {Array<number>} a
     65     * @return {tcuRGBA.RGBA}
     66     */
     67    glsShaderRenderCase.toRGBA = function(a) {
     68        return tcuRGBA.newRGBAComponents(
     69            deMath.clamp(Math.round(a[0] * 255.0), 0, 255),
     70            deMath.clamp(Math.round(a[1] * 255.0), 0, 255),
     71            deMath.clamp(Math.round(a[2] * 255.0), 0, 255),
     72            deMath.clamp(Math.round(a[3] * 255.0), 0, 255));
     73    };
     74 
     75    /**
     76     * Helper function
     77     * @param  {?(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} tex
     78     * @return {gluTexture.Type}
     79     */
     80    glsShaderRenderCase.getTextureType = function(tex) {
     81        if (tex === null || tex.getType() <= 0)
     82            return gluTexture.Type.TYPE_NONE;
     83        else
     84            return tex.getType();
     85    };
     86 
     87    /**
     88     * @constructor
     89     * @param {number=} indent
     90     */
     91    glsShaderRenderCase.LineStream = function(indent) {
     92        indent = indent === undefined ? 0 : indent;
     93        /** @type {number} */ this.m_indent = indent;
     94        /** @type {string} */ this.m_stream;
     95        /** @type {string} */ this.m_string;
     96    };
     97 
     98    /**
     99     * @return {string}
    100     */
    101    glsShaderRenderCase.LineStream.prototype.str = function() {
    102         this.m_string = this.m_stream;
    103         return this.m_string;
    104    };
    105 
    106    /**
    107     * @constructor
    108     * @param  {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)=} tex
    109     * @param  {tcuTexture.Sampler=} sampler
    110     */
    111    glsShaderRenderCase.TextureBinding = function(tex, sampler) {
    112        tex = tex === undefined ? null : tex;
    113        sampler = sampler === undefined ? null : sampler;
    114        /** @type {gluTexture.Type} */ this.m_type = glsShaderRenderCase.getTextureType(tex);
    115        /** @type {tcuTexture.Sampler} */ this.m_sampler = sampler;
    116        /** @type {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} */
    117        this.m_binding = tex;
    118    };
    119 
    120    /**
    121     * @param {tcuTexture.Sampler} sampler
    122     */
    123    glsShaderRenderCase.TextureBinding.prototype.setSampler = function(sampler) {
    124        this.m_sampler = sampler;
    125    };
    126 
    127    /**
    128     * @param {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} tex
    129     */
    130    glsShaderRenderCase.TextureBinding.prototype.setTexture = function(tex) {
    131        this.m_type = glsShaderRenderCase.getTextureType(tex);
    132        this.m_binding = tex;
    133    };
    134 
    135    /** @return {gluTexture.Type} */
    136    glsShaderRenderCase.TextureBinding.prototype.getType = function() {
    137        return this.m_type;
    138    };
    139 
    140    /** @return {tcuTexture.Sampler} */
    141    glsShaderRenderCase.TextureBinding.prototype.getSampler = function() {
    142        return this.m_sampler;
    143    };
    144 
    145    /** @return {(gluTexture.Texture2D|gluTexture.TextureCube|gluTexture.Texture2DArray|gluTexture.Texture3D)} */
    146    glsShaderRenderCase.TextureBinding.prototype.getBinding = function() {
    147        return this.m_binding;
    148    };
    149 
    150    /**
    151     * @constructor
    152     * @param  {number} gridSize
    153     * @param  {number} width
    154     * @param  {number} height
    155     * @param  {Array<number>} constCoords
    156     * @param  {Array<tcuMatrix.Matrix>} userAttribTransforms
    157     * @param  {Array<glsShaderRenderCase.TextureBinding>} textures
    158     */
    159    glsShaderRenderCase.QuadGrid = function(gridSize, width, height, constCoords, userAttribTransforms, textures) {
    160        /** @type {number} */ this.m_gridSize = gridSize;
    161        /** @type {number} */ this.m_numVertices = (gridSize + 1) * (gridSize + 1);
    162        /** @type {number} */ this.m_numTriangles = (gridSize * gridSize *2);
    163        /** @type {Array<number>} */ this.m_constCoords = constCoords;
    164        /** @type {Array<tcuMatrix.Matrix>} */ this.m_userAttribTransforms = userAttribTransforms;
    165        /** @type {Array<glsShaderRenderCase.TextureBinding>} */ this.m_textures = textures;
    166        /** @type {Array<Array<number>>} */ this.m_screenPos = [];
    167        /** @type {Array<Array<number>>} */ this.m_positions = [];
    168        /** @type {Array<Array<number>>} */ this.m_coords = [];            //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
    169        /** @type {Array<Array<number>>} */ this.m_unitCoords = [];        //!< Positive-only coordinates [0.0 .. 1.5].
    170        /** @type {Array<number>} */ this.m_attribOne = [];
    171        /** @type {Array<Array<number>>} */ this.m_userAttribs = [];
    172        for (var attribNdx = 0; attribNdx < this.getNumUserAttribs(); attribNdx++)
    173            this.m_userAttribs[attribNdx] = [];
    174        /** @type {Array<number>} */ this.m_indices = [];
    175 
    176        /** @type Array<number>} */ var viewportScale = [width, height, 0, 0];
    177        for (var y = 0; y < gridSize + 1; y++)
    178        for (var x = 0; x < gridSize + 1; x++) {
    179            /** @type {number} */ var sx = x / gridSize;
    180            /** @type {number} */ var sy = y / gridSize;
    181            /** @type {number} */ var fx = 2.0 * sx - 1.0;
    182            /** @type {number} */ var fy = 2.0 * sy - 1.0;
    183            /** @type {number} */ var vtxNdx = ((y * (gridSize + 1)) + x);
    184 
    185            this.m_positions[vtxNdx] = [fx, fy, 0.0, 1.0];
    186            this.m_attribOne[vtxNdx] = 1.0;
    187            this.m_screenPos[vtxNdx] = deMath.multiply([sx, sy, 0.0, 1.0], viewportScale);
    188            this.m_coords[vtxNdx] = this.getCoords(sx, sy);
    189            this.m_unitCoords[vtxNdx] = this.getUnitCoords(sx, sy);
    190 
    191            for (var attribNdx = 0; attribNdx < this.getNumUserAttribs(); attribNdx++)
    192                this.m_userAttribs[attribNdx][vtxNdx] = this.getUserAttrib(attribNdx, sx, sy);
    193        }
    194 
    195        // Compute indices.
    196        for (var y = 0; y < gridSize; y++)
    197        for (var x = 0; x < gridSize; x++) {
    198            /** @type {number} */ var stride = gridSize + 1;
    199            /** @type {number} */ var v00 = (y * stride) + x;
    200            /** @type {number} */ var v01 = (y * stride) + x + 1;
    201            /** @type {number} */ var v10 = ((y + 1) * stride) + x;
    202            /** @type {number} */ var v11 = ((y + 1) * stride) + x + 1;
    203 
    204            /** @type {number} */ var baseNdx = ((y * gridSize) + x) * 6;
    205            this.m_indices[baseNdx + 0] = v10;
    206            this.m_indices[baseNdx + 1] = v00;
    207            this.m_indices[baseNdx + 2] = v01;
    208 
    209            this.m_indices[baseNdx + 3] = v10;
    210            this.m_indices[baseNdx + 4] = v01;
    211            this.m_indices[baseNdx + 5] = v11;
    212        }
    213    };
    214 
    215    /** @return {number} */
    216    glsShaderRenderCase.QuadGrid.prototype.getGridSize = function() {
    217        return this.m_gridSize;
    218    };
    219 
    220    /** @return {number} */
    221    glsShaderRenderCase.QuadGrid.prototype.getNumVertices = function() {
    222        return this.m_numVertices;
    223    };
    224 
    225    /** @return {number} */
    226    glsShaderRenderCase.QuadGrid.prototype.getNumTriangles = function() {
    227        return this.m_numTriangles;
    228    };
    229 
    230    /** @return {Array<number>} */
    231    glsShaderRenderCase.QuadGrid.prototype.getConstCoords = function() {
    232        return this.m_constCoords;
    233    };
    234 
    235    /** @return {Array<tcuMatrix.Matrix>} */
    236    glsShaderRenderCase.QuadGrid.prototype.getUserAttribTransforms = function() {
    237        return this.m_userAttribTransforms;
    238    };
    239 
    240    /** @return {Array<glsShaderRenderCase.TextureBinding>} */
    241    glsShaderRenderCase.QuadGrid.prototype.getTextures = function() {
    242        return this.m_textures;
    243    };
    244 
    245    /** @return {Array<Array<number>>} */
    246    glsShaderRenderCase.QuadGrid.prototype.getPositions = function() {
    247        return this.m_positions;
    248    };
    249 
    250    /** @return {Array<number>} */
    251    glsShaderRenderCase.QuadGrid.prototype.getAttribOne = function() {
    252        return this.m_attribOne;
    253    };
    254 
    255    /** @return {Array<Array<number>>} */
    256    glsShaderRenderCase.QuadGrid.prototype.getCoordsArray = function() {
    257        return this.m_coords;
    258    };
    259 
    260    /** @return {Array<Array<number>>} */
    261    glsShaderRenderCase.QuadGrid.prototype.getUnitCoordsArray = function() {
    262        return this.m_unitCoords;
    263    };
    264 
    265    /**
    266     * @param {number} attribNdx
    267     * @return {Array<number>}
    268     */
    269    glsShaderRenderCase.QuadGrid.prototype.getUserAttribByIndex = function(attribNdx) {
    270        return this.m_userAttribs[attribNdx];
    271    };
    272 
    273    /** @return {Array<number>} */
    274    glsShaderRenderCase.QuadGrid.prototype.getIndices = function() {
    275        return this.m_indices;
    276    };
    277 
    278    /**
    279     * @param {number} sx
    280     * @param {number} sy
    281     * @return {Array<number>}
    282     */
    283    glsShaderRenderCase.QuadGrid.prototype.getCoords = function(sx, sy) {
    284        /** @type {number} */ var fx = 2.0 * sx - 1.0;
    285        /** @type {number} */ var fy = 2.0 * sy - 1.0;
    286        return [fx, fy, -fx + 0.33 * fy, -0.275 * fx - fy];
    287    };
    288 
    289    /**
    290     * @param {number} sx
    291     * @param {number} sy
    292     * @return {Array<number>}
    293     */
    294    glsShaderRenderCase.QuadGrid.prototype.getUnitCoords = function(sx, sy) {
    295        return [sx, sy, 0.33 * sx + 0.5 * sy, 0.5 * sx + 0.25 * sy];
    296    };
    297 
    298    /**
    299     * @return {number}
    300     */
    301    glsShaderRenderCase.QuadGrid.prototype.getNumUserAttribs = function() {
    302        return this.m_userAttribTransforms.length;
    303    };
    304 
    305    /**
    306     * @param {number} attribNdx
    307     * @param {number} sx
    308     * @param {number} sy
    309     * @return {Array<number>}
    310     */
    311    glsShaderRenderCase.QuadGrid.prototype.getUserAttrib = function(attribNdx, sx, sy) {
    312        // homogeneous normalized screen-space coordinates
    313        return tcuMatrix.multiplyMatVec(this.m_userAttribTransforms[attribNdx], [sx, sy, 0.0, 1.0]);
    314    };
    315 
    316    /**
    317     * @constructor
    318     * @struct
    319     */
    320    glsShaderRenderCase.ShaderSampler = function() {
    321        /** @type {tcuTexture.Sampler} */ this.sampler;
    322        /** @type {tcuTexture.Texture2D} */ this.tex2D = null;
    323        /** @type {tcuTexture.TextureCube} */ this.texCube = null;
    324        /** @type {tcuTexture.Texture2DArray} */ this.tex2DArray = null;
    325        /** @type {tcuTexture.Texture3D} */ this.tex3D = null;
    326    };
    327 
    328    /**
    329     * @constructor
    330     * @param  {glsShaderRenderCase.QuadGrid} quadGrid_
    331     */
    332    glsShaderRenderCase.ShaderEvalContext = function(quadGrid_) {
    333        /** @type {Array<number>} */ this.coords = [0, 0, 0, 0]
    334        /** @type {Array<number>} */ this.unitCoords = [0, 0, 0, 0]
    335        /** @type {Array<number>} */ this.constCoords = quadGrid_.getConstCoords();
    336        /** @type {Array<Array<number>>} */ this.in_ = [];
    337        /** @type {Array<glsShaderRenderCase.ShaderSampler>} */ this.textures = [];
    338        /** @type {Array<number>} */ this.color = [0, 0, 0, 0.0];
    339        /** @type {boolean} */ this.isDiscarded = false;
    340        /** @type {glsShaderRenderCase.QuadGrid} */ this.quadGrid = quadGrid_;
    341 
    342        /** @type {Array<glsShaderRenderCase.TextureBinding>} */ var bindings = this.quadGrid.getTextures();
    343        assertMsgOptions(bindings.length <= glsShaderRenderCase.MAX_TEXTURES, 'Too many bindings.', false, true);
    344 
    345        // Fill in texture array.
    346        for (var ndx = 0; ndx < bindings.length; ndx++) {
    347            /** @type {glsShaderRenderCase.TextureBinding} */ var binding = bindings[ndx];
    348 
    349            this.textures[ndx] = new glsShaderRenderCase.ShaderSampler();
    350 
    351            if (binding.getType() == gluTexture.Type.TYPE_NONE)
    352                continue;
    353 
    354            this.textures[ndx].sampler = binding.getSampler();
    355 
    356            switch (binding.getType()) {
    357                case gluTexture.Type.TYPE_2D:
    358                    this.textures[ndx].tex2D = binding.getBinding().getRefTexture();
    359                    break;
    360                case gluTexture.Type.TYPE_CUBE_MAP:
    361                    this.textures[ndx].texCube = binding.getBinding().getRefTexture();
    362                    break;
    363                case gluTexture.Type.TYPE_2D_ARRAY:
    364                    this.textures[ndx].tex2DArray = binding.getBinding().getRefTexture();
    365                    break;
    366                case gluTexture.Type.TYPE_3D:
    367                    this.textures[ndx].tex3D = binding.getBinding().getRefTexture();
    368                    break;
    369                default:
    370                    throw new Error("Binding type not supported");
    371            }
    372        }
    373    };
    374 
    375    /**
    376     * @param {number} sx
    377     * @param {number} sy
    378     */
    379    glsShaderRenderCase.ShaderEvalContext.prototype.reset = function(sx, sy) {
    380        // Clear old values
    381        this.color = [0.0, 0.0, 0.0, 1.0];
    382        this.isDiscarded = false;
    383 
    384        // Compute coords
    385        this.coords = this.quadGrid.getCoords(sx, sy);
    386        this.unitCoords = this.quadGrid.getUnitCoords(sx, sy);
    387 
    388        // Compute user attributes.
    389        /** @type {number} */ var numAttribs = this.quadGrid.getNumUserAttribs();
    390        assertMsgOptions(numAttribs <= glsShaderRenderCase.MAX_USER_ATTRIBS, 'numAttribs out of range', false, true);
    391        for (var attribNdx = 0; attribNdx < numAttribs; attribNdx++)
    392            this.in_[attribNdx] = this.quadGrid.getUserAttrib(attribNdx, sx, sy);
    393    };
    394 
    395    glsShaderRenderCase.ShaderEvalContext.prototype.discard = function() {
    396        this.isDiscarded = true;
    397    };
    398 
    399    /**
    400     * @param {number} unitNdx
    401     * @param {Array<number>} coords
    402     */
    403    glsShaderRenderCase.ShaderEvalContext.prototype.texture2D = function(unitNdx, coords) {
    404        if (this.textures.length > 0 && this.textures[unitNdx].tex2D)
    405            return this.textures[unitNdx].tex2D.getView().sample(this.textures[unitNdx].sampler, coords, 0.0);
    406        else
    407            return [0.0, 0.0, 0.0, 1.0];
    408    };
    409 
    410    /** @param {glsShaderRenderCase.ShaderEvalContext} c */
    411    glsShaderRenderCase.evalCoordsPassthroughX = function(c) {
    412        c.color[0] = c.coords[0];
    413    };
    414 
    415    /** @param {glsShaderRenderCase.ShaderEvalContext} c */
    416    glsShaderRenderCase.evalCoordsPassthroughXY = function(c) {
    417        var swizzle01 = deMath.swizzle(c.coords, [0, 1]);
    418        c.color[0] = swizzle01[0];
    419        c.color[1] = swizzle01[1];
    420    };
    421 
    422    /** @param {glsShaderRenderCase.ShaderEvalContext} c */
    423    glsShaderRenderCase.evalCoordsPassthroughXYZ = function(c) {
    424        var swizzle012 = deMath.swizzle(c.coords, [0, 1, 2]);
    425        c.color[0] = swizzle012[0];
    426        c.color[1] = swizzle012[1];
    427        c.color[2] = swizzle012[2];
    428    };
    429 
    430    /** @param {glsShaderRenderCase.ShaderEvalContext} c */
    431    glsShaderRenderCase.evalCoordsPassthrough = function(c) {
    432        c.color = c.coords;
    433    };
    434 
    435    /** @param {glsShaderRenderCase.ShaderEvalContext} c */
    436    glsShaderRenderCase.evalCoordsSwizzleWZYX = function(c) {
    437        c.color = deMath.swizzle(c.coords, [3, 2, 1, 0]);
    438    };
    439 
    440    /**
    441     * @constructor
    442     * @param  {?glsShaderRenderCase.ShaderEvalFunc=} evalFunc
    443     */
    444    glsShaderRenderCase.ShaderEvaluator = function(evalFunc) {
    445        /** @type {?glsShaderRenderCase.ShaderEvalFunc} */ this.m_evalFunc = evalFunc || null;
    446    };
    447 
    448    /**
    449     * @param {glsShaderRenderCase.ShaderEvalContext} ctx
    450     */
    451    glsShaderRenderCase.ShaderEvaluator.prototype.evaluate = function(ctx) {
    452        assertMsgOptions(this.m_evalFunc !== null, 'No evaluation function specified.', false, true);
    453        this.m_evalFunc(ctx);
    454    };
    455 
    456    /**
    457     * @constructor
    458     * @extends {tcuTestCase.DeqpTest}
    459     * @param  {string} name
    460     * @param  {string} description
    461     * @param  {boolean} isVertexCase
    462     * @param  {glsShaderRenderCase.ShaderEvalFunc=} evalFunc
    463     */
    464    glsShaderRenderCase.ShaderRenderCase = function(name, description, isVertexCase, evalFunc) {
    465        tcuTestCase.DeqpTest.call(this, name, description);
    466        // evalFunc = evalFunc || null;
    467        /** @type {boolean} */ this.m_isVertexCase = isVertexCase;
    468        /** @type {?glsShaderRenderCase.ShaderEvalFunc} */ this.m_defaultEvaluator = evalFunc || null;
    469        /** @type {glsShaderRenderCase.ShaderEvaluator} */ this.m_evaluator = new glsShaderRenderCase.ShaderEvaluator(this.m_defaultEvaluator);
    470        /** @type {string} */ this.m_vertShaderSource = '';
    471        /** @type {string} */ this.m_fragShaderSource = '';
    472        /** @type {Array<number>} */ this.m_clearColor = glsShaderRenderCase.DEFAULT_CLEAR_COLOR;
    473        /** @type {Array<tcuMatrix.Matrix>} */ this.m_userAttribTransforms = [];
    474        /** @type {Array<glsShaderRenderCase.TextureBinding>} */ this.m_textures = [];
    475        /** @type {?gluShaderProgram.ShaderProgram} */ this.m_program = null;
    476    };
    477 
    478    /**
    479     * @param  {string} name
    480     * @param  {string} description
    481     * @param  {boolean} isVertexCase
    482     * @param  {glsShaderRenderCase.ShaderEvaluator} evaluator
    483     * @return {glsShaderRenderCase.ShaderRenderCase}
    484     */
    485    glsShaderRenderCase.ShaderRenderCase.newWithEvaluator = function(name, description, isVertexCase, evaluator) {
    486        var renderCase = new glsShaderRenderCase.ShaderRenderCase(name, description, isVertexCase);
    487        renderCase.m_evaluator = evaluator;
    488        return renderCase;
    489    };
    490 
    491    glsShaderRenderCase.ShaderRenderCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    492    glsShaderRenderCase.ShaderRenderCase.prototype.constructor = glsShaderRenderCase.ShaderRenderCase;
    493 
    494    glsShaderRenderCase.ShaderRenderCase.prototype.deinit = function() {
    495        this.m_program = null;
    496    };
    497 
    498    glsShaderRenderCase.ShaderRenderCase.prototype.init = function() {
    499        this.postinit();
    500    };
    501 
    502    glsShaderRenderCase.ShaderRenderCase.prototype.postinit = function() {
    503        if (this.m_vertShaderSource.length === 0 || this.m_fragShaderSource.length === 0) {
    504            assertMsgOptions(this.m_vertShaderSource.length === 0 && this.m_fragShaderSource.length === 0, 'No shader source.', false, true);
    505            this.setupShaderData();
    506        }
    507 
    508        assertMsgOptions(!this.m_program, 'Program defined.', false, true);
    509        this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(this.m_vertShaderSource, this.m_fragShaderSource));
    510 
    511        try {
    512            bufferedLogToConsole(this.m_program.program.info.infoLog); // Always log shader program.
    513 
    514            if (!this.m_program.isOk())
    515                throw new Error("Shader compile error.");
    516        }
    517        catch (exception) {
    518            // Clean up.
    519            this.deinit();
    520            throw exception;
    521        }
    522    };
    523 
    524    /**
    525     * @return {tcuTestCase.IterateResult}
    526     */
    527    glsShaderRenderCase.ShaderRenderCase.prototype.postiterate = function() {
    528        assertMsgOptions(this.m_program !== null, 'Program not specified.', false, true);
    529        /** @type {?WebGLProgram} */ var programID = this.m_program.getProgram();
    530        gl.useProgram(programID);
    531 
    532        // Create quad grid.
    533        /** @type {Array<number>} */ var viewportSize = this.getViewportSize();
    534        /** @type {number} */ var width = viewportSize[0];
    535        /** @type {number} */ var height = viewportSize[1];
    536 
    537        // \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords).
    538        /** @type {glsShaderRenderCase.QuadGrid} */
    539        var quadGrid = new glsShaderRenderCase.QuadGrid(
    540            this.m_isVertexCase ? glsShaderRenderCase.GRID_SIZE : 4, width, height,
    541            [0.125, 0.25, 0.5, 1.0], this.m_userAttribTransforms, this.m_textures);
    542 
    543        // Render result.
    544        /** @type {tcuSurface.Surface} */ var resImage = new tcuSurface.Surface(width, height);
    545        this.render(resImage, programID, quadGrid);
    546 
    547        // Compute reference.
    548        /** @type {tcuSurface.Surface} */ var refImage = new tcuSurface.Surface(width, height);
    549        if (this.m_isVertexCase)
    550            this.computeVertexReference(refImage, quadGrid);
    551        else
    552            this.computeFragmentReference(refImage, quadGrid);
    553 
    554        // Compare.
    555        /** @type {boolean} */ var testOk = this.compareImages(resImage, refImage, 0.05);
    556 
    557        // De-initialize.
    558        gl.useProgram(null);
    559 
    560        if (!testOk)
    561            testFailedOptions("Fail", false);
    562        else
    563            testPassedOptions("Pass", true);
    564 
    565        return tcuTestCase.IterateResult.STOP;
    566    };
    567 
    568    /**
    569     * @return {tcuTestCase.IterateResult}
    570     */
    571    glsShaderRenderCase.ShaderRenderCase.prototype.iterate = function() {
    572        return this.postiterate();
    573    };
    574 
    575    glsShaderRenderCase.ShaderRenderCase.prototype.setupShaderData = function() {};
    576 
    577    /**
    578     * @param {?WebGLProgram} programId
    579     */
    580    glsShaderRenderCase.ShaderRenderCase.prototype.setup = function(programId) {};
    581 
    582    /**
    583     * @param {?WebGLProgram} programId
    584     * @param {Array<number>} constCoords
    585     */
    586    glsShaderRenderCase.ShaderRenderCase.prototype.setupUniforms = function(programId, constCoords) {};
    587 
    588    /**
    589    * @return  {Array<number>}
    590    */
    591    glsShaderRenderCase.ShaderRenderCase.prototype.getViewportSize = function() {
    592        return [Math.min(gl.canvas.width, glsShaderRenderCase.MAX_RENDER_WIDTH),
    593                Math.min(gl.canvas.height, glsShaderRenderCase.MAX_RENDER_HEIGHT)];
    594    };
    595 
    596    /**
    597     * @param {?WebGLProgram} programId
    598     */
    599    glsShaderRenderCase.ShaderRenderCase.prototype.setupDefaultInputs = function(programId) {
    600        // SETUP UNIFORMS.
    601        glsShaderRenderCase.setupDefaultUniforms(programId);
    602 
    603        // SETUP TEXTURES.
    604        for (var ndx = 0; ndx < this.m_textures.length; ndx++) {
    605            /** @type {glsShaderRenderCase.TextureBinding} */ var tex = this.m_textures[ndx];
    606            /** @type {tcuTexture.Sampler} */ var sampler = tex.getSampler();
    607            /** @type {number} */ var texTarget = gl.NONE;
    608            /** @type {number} */ var texObj = 0;
    609 
    610            if (tex.getType() === gluTexture.Type.TYPE_NONE)
    611                continue;
    612 
    613            switch (tex.getType()) {
    614                case gluTexture.Type.TYPE_2D:
    615                    texTarget = gl.TEXTURE_2D;
    616                    texObj = tex.getBinding().getGLTexture();
    617                    break;
    618                case gluTexture.Type.TYPE_CUBE_MAP:
    619                    texTarget = gl.TEXTURE_CUBE_MAP;
    620                    texObj = tex.getBinding().getGLTexture();
    621                    break;
    622                case gluTexture.Type.TYPE_2D_ARRAY:
    623                    texTarget = gl.TEXTURE_2D_ARRAY;
    624                    texObj = tex.getBinding().getGLTexture();
    625                    break;
    626                case gluTexture.Type.TYPE_3D:
    627                    texTarget = gl.TEXTURE_3D;
    628                    texObj = tex.getBinding().getGLTexture();
    629                    break;
    630                default:
    631                    throw new Error("Type not supported");
    632            }
    633 
    634            gl.activeTexture(gl.TEXTURE0+ ndx);
    635            gl.bindTexture(texTarget, texObj);
    636            gl.texParameteri(texTarget, gl.TEXTURE_WRAP_S, gluTextureUtil.getGLWrapMode(sampler.wrapS));
    637            gl.texParameteri(texTarget, gl.TEXTURE_WRAP_T, gluTextureUtil.getGLWrapMode(sampler.wrapT));
    638            gl.texParameteri(texTarget, gl.TEXTURE_MIN_FILTER, gluTextureUtil.getGLFilterMode(sampler.minFilter));
    639            gl.texParameteri(texTarget, gl.TEXTURE_MAG_FILTER, gluTextureUtil.getGLFilterMode(sampler.magFilter));
    640 
    641            if (texTarget === gl.TEXTURE_3D)
    642                gl.texParameteri(texTarget, gl.TEXTURE_WRAP_R, gluTextureUtil.getGLWrapMode(sampler.wrapR));
    643 
    644            if (sampler.compare != tcuTexture.CompareMode.COMPAREMODE_NONE)
    645            {
    646                gl.texParameteri(texTarget, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
    647                gl.texParameteri(texTarget, gl.TEXTURE_COMPARE_FUNC, gluTextureUtil.getGLCompareFunc(sampler.compare));
    648            }
    649        }
    650    };
    651 
    652    /**
    653     * @param {tcuSurface.Surface} result
    654     * @param {?WebGLProgram} programId
    655     * @param {glsShaderRenderCase.QuadGrid} quadGrid
    656     **/
    657    glsShaderRenderCase.ShaderRenderCase.prototype.render = function(result, programId, quadGrid) {
    658        // Buffer info.
    659        /** @type {number} */ var width = result.getWidth();
    660        /** @type {number} */ var height = result.getHeight();
    661 
    662        /** @type {number} */ var xOffsetMax = gl.drawingBufferWidth - width;
    663        /** @type {number} */ var yOffsetMax = gl.drawingBufferHeight - height;
    664 
    665        /** @type {number} */ var hash = deString.deStringHash(this.m_vertShaderSource) + deString.deStringHash(this.m_fragShaderSource);
    666        /** @type {deRandom.Random} */ var rnd = new deRandom.Random(hash);
    667 
    668        /** @type {number} */ var xOffset = rnd.getInt(0, xOffsetMax);
    669        /** @type {number} */ var yOffset = rnd.getInt(0, yOffsetMax);
    670 
    671        gl.viewport(xOffset, yOffset, width, height);
    672 
    673        // Setup program.
    674        this.setupUniforms(programId, quadGrid.getConstCoords());
    675        this.setupDefaultInputs(programId);
    676 
    677        // Clear.
    678        gl.clearColor(this.m_clearColor[0], this.m_clearColor[1], this.m_clearColor[2], this.m_clearColor[3]);
    679        gl.clear(gl.COLOR_BUFFER_BIT);
    680 
    681        // Draw.
    682        /** @type {Array<gluDrawUtil.VertexArrayBinding>} */ var vertexArrays = [];
    683        /** @type {number} */ var numElements = quadGrid.getNumTriangles()*3;
    684 
    685        glsShaderRenderCase.getDefaultVertexArrays(quadGrid, programId, vertexArrays);
    686 
    687        gluDrawUtil.draw(gl, programId, vertexArrays, gluDrawUtil.triangles(quadGrid.getIndices()));
    688 
    689        // Read back results.
    690        result.readViewport(gl, [xOffset, yOffset, width, height]);
    691 
    692    };
    693 
    694    /**
    695     * @param {tcuSurface.Surface} result
    696     * @param {glsShaderRenderCase.QuadGrid} quadGrid
    697     **/
    698    glsShaderRenderCase.ShaderRenderCase.prototype.computeVertexReference = function(result, quadGrid) {
    699        // Buffer info.
    700        /** @type {number} */ var width = result.getWidth();
    701        /** @type {number} */ var height = result.getHeight();
    702        /** @type {number} */ var gridSize = quadGrid.getGridSize();
    703        /** @type {number} */ var stride = gridSize + 1;
    704        /** @type {boolean} */ var hasAlpha = gl.getContextAttributes().alpha;
    705        /** @type {glsShaderRenderCase.ShaderEvalContext} */
    706        var evalCtx = new glsShaderRenderCase.ShaderEvalContext(quadGrid);
    707        /** @type {Array<number>} */ var color = [];
    708        // Evaluate color for each vertex.
    709        /** @type {Array<Array<number>>} */ var colors = [];
    710        for (var y = 0; y < gridSize + 1; y++)
    711        for (var x = 0; x < gridSize + 1; x++) {
    712            /** @type {number} */ var sx = x / gridSize;
    713            /** @type {number} */ var sy = y / gridSize;
    714            /** @type {number} */ var vtxNdx = ((y * (gridSize+ 1 )) + x);
    715 
    716            evalCtx.reset(sx, sy);
    717            this.m_evaluator.evaluate(evalCtx);
    718            assertMsgOptions(!evalCtx.isDiscarded, 'Discard is not available in vertex shader.', false, true);
    719            color = evalCtx.color;
    720 
    721            if (!hasAlpha)
    722                color[3] = 1.0;
    723 
    724            colors[vtxNdx] = color;
    725        }
    726        // Render quads.
    727        for (var y = 0; y < gridSize; y++)
    728        for (var x = 0; x < gridSize; x++) {
    729            /** @type {number} */ var x0 = x / gridSize;
    730            /** @type {number} */ var x1 = (x + 1) / gridSize;
    731            /** @type {number} */ var y0 = y / gridSize;
    732            /** @type {number} */ var y1 = (y + 1) / gridSize;
    733 
    734            /** @type {number} */ var sx0 = x0 * width;
    735            /** @type {number} */ var sx1 = x1 * width;
    736            /** @type {number} */ var sy0 = y0 * height;
    737            /** @type {number} */ var sy1 = y1 * height;
    738            /** @type {number} */ var oosx = 1.0 / (sx1 - sx0);
    739            /** @type {number} */ var oosy = 1.0 / (sy1 - sy0);
    740 
    741            /** @type {number} */ var ix0 = Math.ceil(sx0 - 0.5);
    742            /** @type {number} */ var ix1 = Math.ceil(sx1 - 0.5);
    743            /** @type {number} */ var iy0 = Math.ceil(sy0 - 0.5);
    744            /** @type {number} */ var iy1 = Math.ceil(sy1 - 0.5);
    745 
    746            /** @type {number} */ var v00 = (y * stride) + x;
    747            /** @type {number} */ var v01 = (y * stride) + x + 1;
    748            /** @type {number} */ var v10 = ((y + 1) * stride) + x;
    749            /** @type {number} */ var v11 = ((y + 1) * stride) + x + 1;
    750            /** @type {Array<number>} */ var c00 = colors[v00];
    751            /** @type {Array<number>} */ var c01 = colors[v01];
    752            /** @type {Array<number>} */ var c10 = colors[v10];
    753            /** @type {Array<number>} */ var c11 = colors[v11];
    754 
    755            for (var iy = iy0; iy < iy1; iy++)
    756            for (var ix = ix0; ix < ix1; ix++) {
    757                assertMsgOptions(deMath.deInBounds32(ix, 0, width), 'Out of bounds.', false, true);
    758                assertMsgOptions(deMath.deInBounds32(iy, 0, height), 'Out of bounds.', false, true);
    759 
    760                /** @type {number} */ var sfx = ix + 0.5;
    761                /** @type {number} */ var sfy = iy + 0.5;
    762                /** @type {number} */ var fx1 = deMath.clamp((sfx - sx0) * oosx, 0.0, 1.0);
    763                /** @type {number} */ var fy1 = deMath.clamp((sfy - sy0) * oosy, 0.0, 1.0);
    764 
    765                // Triangle quad interpolation.
    766                /** @type {boolean} */ var tri = fx1 + fy1 <= 1.0;
    767                /** @type {number} */ var tx = tri ? fx1 : (1.0 - fx1);
    768                /** @type {number} */ var ty = tri ? fy1 : (1.0 - fy1);
    769                /** @type {Array<number>} */ var t0 = tri ? c00 : c11;
    770                /** @type {Array<number>} */ var t1 = tri ? c01 : c10;
    771                /** @type {Array<number>} */ var t2 = tri ? c10 : c01;
    772                color = deMath.add(t0, deMath.add(deMath.scale(deMath.subtract(t1, t0), tx), deMath.scale(deMath.subtract(t2, t0), ty)));
    773 
    774                result.setPixel(ix, iy, glsShaderRenderCase.toRGBA(color).toIVec());
    775            }
    776        }
    777    };
    778 
    779    /**
    780     * @param {tcuSurface.Surface} result
    781     * @param {glsShaderRenderCase.QuadGrid} quadGrid
    782     **/
    783    glsShaderRenderCase.ShaderRenderCase.prototype.computeFragmentReference = function(result, quadGrid) {
    784        // Buffer info.
    785        /** @type {number} */ var width = result.getWidth();
    786        /** @type {number} */ var height = result.getHeight();
    787        /** @type {boolean} */ var hasAlpha    = gl.getContextAttributes().alpha;
    788        /** @type {glsShaderRenderCase.ShaderEvalContext} */ var evalCtx = new glsShaderRenderCase.ShaderEvalContext(quadGrid);
    789 
    790        // Render.
    791        for (var y = 0; y < height; y++)
    792        for (var x = 0; x < width; x++) {
    793            /** @type {number} */ var sx = (x + 0.5) / width;
    794            /** @type {number} */ var sy = (y + 0.5) / height;
    795 
    796            evalCtx.reset(sx, sy);
    797            this.m_evaluator.evaluate(evalCtx);
    798            // Select either clear color or computed color based on discarded bit.
    799            /** @type {Array<number>} */ var color = evalCtx.isDiscarded ? this.m_clearColor : evalCtx.color;
    800 
    801            if (!hasAlpha)
    802                color[3] = 1.0;
    803 
    804            result.setPixel(x, y, glsShaderRenderCase.toRGBA(color).toIVec());
    805        }
    806    };
    807 
    808    /**
    809     * @param {tcuSurface.Surface} resImage
    810     * @param {tcuSurface.Surface} refImage
    811     * @param {number} errorThreshold
    812     * @return {boolean}
    813     */
    814    glsShaderRenderCase.ShaderRenderCase.prototype.compareImages = function(resImage, refImage, errorThreshold) {
    815        return tcuImageCompare.fuzzyCompare("ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), errorThreshold);
    816    };
    817 
    818    /**
    819     * @param {number} number
    820     * @return {string} */
    821    glsShaderRenderCase.getIntUniformName = function(number) {
    822        switch (number) {
    823            case 0: return "ui_zero";
    824            case 1: return "ui_one";
    825            case 2: return "ui_two";
    826            case 3: return "ui_three";
    827            case 4: return "ui_four";
    828            case 5: return "ui_five";
    829            case 6: return "ui_six";
    830            case 7: return "ui_seven";
    831            case 8: return "ui_eight";
    832            case 101: return "ui_oneHundredOne";
    833            default:
    834                throw new Error("Uniform not supported.");
    835        }
    836    };
    837 
    838    /**
    839     * @param {number} number
    840     * @return {string} */
    841    glsShaderRenderCase.getFloatUniformName = function(number) {
    842        switch (number) {
    843            case 0: return "uf_zero";
    844            case 1: return "uf_one";
    845            case 2: return "uf_two";
    846            case 3: return "uf_three";
    847            case 4: return "uf_four";
    848            case 5: return "uf_five";
    849            case 6: return "uf_six";
    850            case 7: return "uf_seven";
    851            case 8: return "uf_eight";
    852            default:
    853                throw new Error("Uniform not supported.");
    854        }
    855    };
    856 
    857    /**
    858     * @param {number} number
    859     * @return {string} */
    860    glsShaderRenderCase.getFloatFractionUniformName = function(number) {
    861        switch (number) {
    862            case 1: return "uf_one";
    863            case 2: return "uf_half";
    864            case 3: return "uf_third";
    865            case 4: return "uf_fourth";
    866            case 5: return "uf_fifth";
    867            case 6: return "uf_sixth";
    868            case 7: return "uf_seventh";
    869            case 8: return "uf_eighth";
    870            default:
    871                throw new Error("Uniform not supported.");
    872        }
    873    };
    874 
    875    /**
    876     * @param {?WebGLProgram} programID
    877     */
    878    glsShaderRenderCase.setupDefaultUniforms = function(programID) {
    879        /** @type {?WebGLUniformLocation} */ var uniLoc;
    880        // Bool.
    881        /**
    882         * @constructor
    883         * @struct
    884         */
    885        var BoolUniform = function(name, value) {
    886            /** @type {string} */ this.name = name;
    887            /** @type {boolean} */ this.value = value;
    888        };
    889 
    890        /** @type {Array<BoolUniform>} */ var s_boolUniforms = [
    891            new BoolUniform("ub_true", true),
    892            new BoolUniform("ub_false", false)
    893        ];
    894 
    895        for (var i = 0; i < s_boolUniforms.length; i++) {
    896            uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name);
    897            if (uniLoc != null)
    898                gl.uniform1i(uniLoc, s_boolUniforms[i].value ? 1 : 0);
    899        }
    900 
    901        // BVec4.
    902        /**
    903         * @constructor
    904         * @struct
    905         */
    906        var BVec4Uniform = function(name, value) {
    907            /** @type {string} */ this.name = name;
    908            /** @type {Array<boolean>} */ this.value = value;
    909        };
    910 
    911        /** @type {Array<BVec4Uniform>} */ var s_bvec4Uniforms = [
    912            new BVec4Uniform("ub4_true", [true, true, true, true]),
    913            new BVec4Uniform("ub4_false", [false, false, false, false])
    914        ];
    915 
    916        for (var i = 0; i < s_bvec4Uniforms.length; i++) {
    917            /** @type {BVec4Uniform} */ var uni = s_bvec4Uniforms[i];
    918            /** @type {Array<number>} */ var arr = [];
    919            arr[0] = uni.value[0] ? 1 : 0;
    920            arr[1] = uni.value[1] ? 1 : 0;
    921            arr[2] = uni.value[2] ? 1 : 0;
    922            arr[3] = uni.value[3] ? 1 : 0;
    923            uniLoc = gl.getUniformLocation(programID, uni.name);
    924            if (uniLoc != null)
    925                gl.uniform4iv(uniLoc, new Int32Array(arr));
    926        }
    927 
    928        // Int.
    929        /**
    930         * @constructor
    931         * @struct
    932         */
    933        var IntUniform = function(name, value) {
    934            /** @type {string} */ this.name = name;
    935            /** @type {number} */ this.value = value;
    936        };
    937 
    938        /** @type {Array<IntUniform>} */ var s_intUniforms = [
    939            new IntUniform("ui_minusOne", -1),
    940            new IntUniform("ui_zero", 0),
    941            new IntUniform("ui_one", 1),
    942            new IntUniform("ui_two", 2),
    943            new IntUniform("ui_three", 3),
    944            new IntUniform("ui_four", 4),
    945            new IntUniform("ui_five", 5),
    946            new IntUniform("ui_six", 6),
    947            new IntUniform("ui_seven", 7),
    948            new IntUniform("ui_eight", 8),
    949            new IntUniform("ui_oneHundredOne", 101)
    950        ];
    951 
    952        for (var i = 0; i < s_intUniforms.length; i++) {
    953            uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name);
    954            if (uniLoc != null)
    955                gl.uniform1i(uniLoc, s_intUniforms[i].value);
    956        }
    957 
    958        // IVec2.
    959        /**
    960         * @constructor
    961         * @struct
    962         */
    963        var IVec2Uniform = function(name, value) {
    964            /** @type {string} */ this.name = name;
    965            /** @type {Array<number>} */ this.value = value;
    966        };
    967 
    968        /** @type {Array<IVec2Uniform>} */ var s_ivec2Uniforms = [
    969            new IVec2Uniform("ui2_minusOne", [-1, -1]),
    970            new IVec2Uniform("ui2_zero", [0, 0]),
    971            new IVec2Uniform("ui2_one", [1, 1]),
    972            new IVec2Uniform("ui2_two", [2, 2]),
    973            new IVec2Uniform("ui2_four", [4, 4]),
    974            new IVec2Uniform("ui2_five", [5, 5])
    975        ];
    976 
    977        for (var i = 0; i < s_ivec2Uniforms.length; i++) {
    978            uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name);
    979            if (uniLoc != null)
    980                gl.uniform2iv(uniLoc, new Int32Array(s_ivec2Uniforms[i].value));
    981        }
    982 
    983        // IVec3.
    984        /**
    985         * @constructor
    986         * @struct
    987         */
    988        var IVec3Uniform = function(name, value) {
    989            /** @type {string} */ this.name = name;
    990            /** @type {Array<number>} */ this.value = value;
    991        };
    992 
    993        /** @type {Array<IVec3Uniform>} */ var s_ivec3Uniforms = [
    994            new IVec3Uniform("ui3_minusOne", [-1, -1, -1]),
    995            new IVec3Uniform("ui3_zero", [0, 0, 0]),
    996            new IVec3Uniform("ui3_one", [1, 1, 1]),
    997            new IVec3Uniform("ui3_two", [2, 2, 2]),
    998            new IVec3Uniform("ui3_four", [4, 4, 4]),
    999            new IVec3Uniform("ui3_five", [5, 5, 5])
   1000        ];
   1001 
   1002        for (var i = 0; i < s_ivec3Uniforms.length; i++) {
   1003            uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name);
   1004            if (uniLoc != null)
   1005                gl.uniform3iv(uniLoc, new Int32Array(s_ivec3Uniforms[i].value));
   1006        }
   1007 
   1008        // IVec4.
   1009        /**
   1010         * @constructor
   1011         * @struct
   1012         */
   1013        var IVec4Uniform = function(name, value) {
   1014            /** @type {string} */ this.name = name;
   1015            /** @type {Array<number>} */ this.value = value;
   1016        };
   1017        /** @type {Array<IVec4Uniform>} */ var s_ivec4Uniforms = [
   1018            new IVec4Uniform("ui4_minusOne", [-1, -1, -1, -1]),
   1019            new IVec4Uniform("ui4_zero", [0, 0, 0, 0]),
   1020            new IVec4Uniform("ui4_one", [1, 1, 1, 1]),
   1021            new IVec4Uniform("ui4_two", [2, 2, 2, 2]),
   1022            new IVec4Uniform("ui4_four", [4, 4, 4, 4]),
   1023            new IVec4Uniform("ui4_five", [5, 5, 5, 5])
   1024        ];
   1025 
   1026        for (var i = 0; i < s_ivec4Uniforms.length; i++) {
   1027            uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name);
   1028            if (uniLoc != null)
   1029                gl.uniform4iv(uniLoc, new Int32Array(s_ivec4Uniforms[i].value));
   1030        }
   1031 
   1032        // Float.
   1033        /**
   1034         * @constructor
   1035         * @struct
   1036         */
   1037        var FloatUniform = function(name, value) {
   1038            /** @type {string} */ this.name = name;
   1039            /** @type {number} */ this.value = value;
   1040        };
   1041        /** @type {Array<FloatUniform>} */ var s_floatUniforms = [
   1042            new FloatUniform("uf_zero", 0.0),
   1043            new FloatUniform("uf_one", 1.0),
   1044            new FloatUniform("uf_two", 2.0),
   1045            new FloatUniform("uf_three", 3.0),
   1046            new FloatUniform("uf_four", 4.0),
   1047            new FloatUniform("uf_five", 5.0),
   1048            new FloatUniform("uf_six", 6.0),
   1049            new FloatUniform("uf_seven", 7.0),
   1050            new FloatUniform("uf_eight", 8.0),
   1051            new FloatUniform("uf_half", 1.0 / 2.0),
   1052            new FloatUniform("uf_third", 1.0 / 3.0),
   1053            new FloatUniform("uf_fourth", 1.0 / 4.0),
   1054            new FloatUniform("uf_fifth", 1.0 / 5.0),
   1055            new FloatUniform("uf_sixth", 1.0 / 6.0),
   1056            new FloatUniform("uf_seventh", 1.0 / 7.0),
   1057            new FloatUniform("uf_eighth", 1.0 / 8.0)
   1058        ];
   1059 
   1060        for (var i = 0; i < s_floatUniforms.length; i++) {
   1061            uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name);
   1062            if (uniLoc != null)
   1063                gl.uniform1f(uniLoc, s_floatUniforms[i].value);
   1064        }
   1065 
   1066        // Vec2.
   1067        /**
   1068         * @constructor
   1069         * @struct
   1070         */
   1071        var Vec2Uniform = function(name, value) {
   1072            /** @type {string} */ this.name = name;
   1073            /** @type {Array<number>} */ this.value = value;
   1074        };
   1075        /** @type {Array<Vec2Uniform>} */ var s_vec2Uniforms = [
   1076            new Vec2Uniform("uv2_minusOne", [-1.0, -1.0]),
   1077            new Vec2Uniform("uv2_zero", [0.0, 0.0]),
   1078            new Vec2Uniform("uv2_half", [0.5, 0.5]),
   1079            new Vec2Uniform("uv2_one", [1.0, 1.0]),
   1080            new Vec2Uniform("uv2_two", [2.0, 2.0])
   1081        ];
   1082 
   1083        for (var i = 0; i < s_vec2Uniforms.length; i++) {
   1084            uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name);
   1085            if (uniLoc != null)
   1086                gl.uniform2fv(uniLoc, new Float32Array(s_vec2Uniforms[i].value));
   1087        }
   1088 
   1089        // Vec3.
   1090        /**
   1091         * @constructor
   1092         * @struct
   1093         */
   1094        var Vec3Uniform = function(name, value) {
   1095            /** @type {string} */ this.name = name;
   1096            /** @type {Array<number>} */ this.value = value;
   1097        };
   1098        /** @type {Array<Vec3Uniform>} */ var s_vec3Uniforms = [
   1099            new Vec3Uniform("uv3_minusOne", [-1.0, -1.0, -1.0]),
   1100            new Vec3Uniform("uv3_zero", [0.0, 0.0, 0.0]),
   1101            new Vec3Uniform("uv3_half", [0.5, 0.5, 0.5]),
   1102            new Vec3Uniform("uv3_one", [1.0, 1.0, 1.0]),
   1103            new Vec3Uniform("uv3_two", [2.0, 2.0, 2.0])
   1104        ];
   1105 
   1106        for (var i = 0; i < s_vec3Uniforms.length; i++) {
   1107            uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name);
   1108            if (uniLoc != null)
   1109                gl.uniform3fv(uniLoc, new Float32Array(s_vec3Uniforms[i].value));
   1110        }
   1111 
   1112        // Vec4.
   1113        /**
   1114         * @constructor
   1115         * @struct
   1116         */
   1117        var Vec4Uniform = function(name, value) {
   1118            /** @type {string} */ this.name = name;
   1119            /** @type {Array<number>} */ this.value = value;
   1120        };
   1121        /** @type {Array<Vec4Uniform>} */ var s_vec4Uniforms = [
   1122            new Vec4Uniform("uv4_minusOne", [-1.0, -1.0, -1.0, -1.0]),
   1123            new Vec4Uniform("uv4_zero", [0.0, 0.0, 0.0, 0.0]),
   1124            new Vec4Uniform("uv4_half", [0.5, 0.5, 0.5, 0.5]),
   1125            new Vec4Uniform("uv4_one", [1.0, 1.0, 1.0, 1.0]),
   1126            new Vec4Uniform("uv4_two", [2.0, 2.0, 2.0, 2.0]),
   1127            new Vec4Uniform("uv4_black", [0.0, 0.0, 0.0, 1.0]),
   1128            new Vec4Uniform("uv4_gray", [0.5, 0.5, 0.5, 1.0]),
   1129            new Vec4Uniform("uv4_white", [1.0, 1.0, 1.0, 1.0])
   1130        ];
   1131 
   1132        for (var i = 0; i < s_vec4Uniforms.length; i++) {
   1133            uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name);
   1134            if (uniLoc != null)
   1135                gl.uniform4fv(uniLoc, new Float32Array(s_vec4Uniforms[i].value));
   1136        }
   1137    };
   1138 
   1139    /**
   1140     * @param {glsShaderRenderCase.QuadGrid} quadGrid
   1141     * @param {?WebGLProgram} program
   1142     * @param {Array<gluDrawUtil.VertexArrayBinding>} vertexArrays
   1143     */
   1144    glsShaderRenderCase.getDefaultVertexArrays = function(quadGrid, program, vertexArrays) {
   1145        /** @type {number} */ var numElements = quadGrid.getNumVertices();
   1146        var posArray = [].concat.apply([], quadGrid.getPositions());
   1147        var coordsArray = [].concat.apply([], quadGrid.getCoordsArray());
   1148        var unitCoordsArray = [].concat.apply([], quadGrid.getUnitCoordsArray());
   1149 
   1150        vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_position", 4, numElements, 0, posArray));
   1151        vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_coords", 4, numElements, 0, coordsArray));
   1152        vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_unitCoords", 4, numElements, 0, unitCoordsArray));
   1153        vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding("a_one", 1, numElements, 0, quadGrid.getAttribOne()));
   1154 
   1155        // a_inN.
   1156        for (var userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++) {
   1157            /** @type {string} */ var name = "a_in" + userNdx;
   1158            var userAttribArray = [].concat.apply([], quadGrid.getUserAttribByIndex(userNdx));
   1159            vertexArrays.push(gluDrawUtil.newFloatVertexArrayBinding(name, 4, numElements, 0, userAttribArray));
   1160        }
   1161 
   1162        // Matrix attributes - these are set by location
   1163        /**
   1164         * @constructor
   1165         * @struct
   1166         */
   1167        var Matrix = function(name, cols, rows) {
   1168            this.name = name;
   1169            this.numCols = cols;
   1170            this.numRows = rows;
   1171        };
   1172 
   1173        /** @type {Array<Matrix>} */ var matrices = [
   1174             new Matrix('a_mat2', 2, 2),
   1175             new Matrix('a_mat2x3', 2, 3),
   1176             new Matrix('a_mat2x4', 2, 4),
   1177             new Matrix('a_mat3x2', 3, 2),
   1178             new Matrix('a_mat3', 3, 3),
   1179             new Matrix('a_mat3x4', 3, 4),
   1180             new Matrix('a_mat4x2', 4, 2),
   1181             new Matrix('a_mat4x3', 4, 3),
   1182             new Matrix('a_mat4', 4, 4)
   1183        ];
   1184 
   1185        for (var matNdx = 0; matNdx < matrices.length; matNdx++) {
   1186            /** @type {number} */ var loc = gl.getAttribLocation(program, matrices[matNdx].name);
   1187 
   1188            if (loc < 0)
   1189                continue; // Not used in shader.
   1190 
   1191            /** @type {number} */ var numRows = matrices[matNdx].numRows;
   1192            /** @type {number} */ var numCols = matrices[matNdx].numCols;
   1193 
   1194            for (var colNdx = 0; colNdx < numCols; colNdx++) {
   1195                var data = [].concat.apply([], quadGrid.getUserAttribByIndex(colNdx));
   1196                vertexArrays.push(gluDrawUtil.newFloatColumnVertexArrayBinding(matrices[matNdx].name, colNdx, numRows, numElements, 4 * 4, data));
   1197            }
   1198        }
   1199    };
   1200 });