tor-browser

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

sglrReferenceContext.js (223251B)


      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('framework.opengl.simplereference.sglrReferenceContext');
     23 goog.require('framework.common.tcuMatrix');
     24 goog.require('framework.common.tcuMatrixUtil');
     25 goog.require('framework.common.tcuPixelFormat');
     26 goog.require('framework.common.tcuTexture');
     27 goog.require('framework.common.tcuTextureUtil');
     28 goog.require('framework.delibs.debase.deMath');
     29 goog.require('framework.opengl.gluShaderUtil');
     30 goog.require('framework.opengl.gluTextureUtil');
     31 goog.require('framework.opengl.simplereference.sglrReferenceUtils');
     32 goog.require('framework.opengl.simplereference.sglrShaderProgram');
     33 goog.require('framework.referencerenderer.rrDefs');
     34 goog.require('framework.referencerenderer.rrGenericVector');
     35 goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess');
     36 goog.require('framework.referencerenderer.rrRenderState');
     37 goog.require('framework.referencerenderer.rrRenderer');
     38 goog.require('framework.referencerenderer.rrVertexAttrib');
     39 
     40 goog.scope(function() {
     41 
     42    var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext;
     43    var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess;
     44    var tcuTexture = framework.common.tcuTexture;
     45    var deMath = framework.delibs.debase.deMath;
     46    var gluTextureUtil = framework.opengl.gluTextureUtil;
     47    var tcuTextureUtil = framework.common.tcuTextureUtil;
     48    var tcuPixelFormat = framework.common.tcuPixelFormat;
     49    var gluShaderUtil = framework.opengl.gluShaderUtil;
     50    var rrRenderer = framework.referencerenderer.rrRenderer;
     51    var rrDefs = framework.referencerenderer.rrDefs;
     52    var rrGenericVector = framework.referencerenderer.rrGenericVector;
     53    var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
     54    var rrRenderState = framework.referencerenderer.rrRenderState;
     55    var sglrReferenceUtils = framework.opengl.simplereference.sglrReferenceUtils;
     56    var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
     57    var tcuMatrix = framework.common.tcuMatrix;
     58    var tcuMatrixUtil = framework.common.tcuMatrixUtil;
     59 
     60    sglrReferenceContext.rrMPBA = rrMultisamplePixelBufferAccess;
     61 
     62    //TODO: Implement automatic error checking in sglrReferenceContext, optional on creation.
     63 
     64    /** @typedef {WebGLRenderbuffer|WebGLTexture|sglrReferenceContext.Renderbuffer|sglrReferenceContext.TextureContainer} */ sglrReferenceContext.AnyRenderbuffer;
     65 
     66    /** @typedef {WebGLFramebuffer|sglrReferenceContext.Framebuffer} */ sglrReferenceContext.AnyFramebuffer;
     67 
     68    /**
     69     * @param {number} error
     70     * @param {number} message
     71     * @throws {Error}
     72     */
     73    sglrReferenceContext.GLU_EXPECT_NO_ERROR = function(error, message) {
     74        if (error !== gl.NONE) {
     75            bufferedLogToConsole('Assertion failed message:' + message);
     76        }
     77    };
     78 
     79    var DE_ASSERT = function(x) {
     80        if (!x)
     81            throw new Error('Assert failed');
     82    };
     83 
     84    // /* TODO: remove */
     85    // /** @type {WebGL2RenderingContext} */ var gl;
     86 
     87    sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2 = 14;
     88    sglrReferenceContext.MAX_TEXTURE_SIZE = 1 << sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2;
     89 
     90    /**
     91     * @param {number} width
     92     * @param {number} height
     93     * @return {number}
     94     */
     95    sglrReferenceContext.getNumMipLevels2D = function(width, height) {
     96        return Math.floor(Math.log2(Math.max(width, height)) + 1);
     97    };
     98 
     99    /**
    100     * @param {number} width
    101     * @param {number} height
    102     * @param {number} depth
    103     * @return {number}
    104     */
    105    sglrReferenceContext.getNumMipLevels3D = function(width, height, depth) {
    106        return Math.floor(Math.log2(Math.max(width, height, depth)) + 1);
    107    };
    108 
    109    /**
    110     * @param {number} baseLevelSize
    111     * @param {number} levelNdx
    112     * @return {number}
    113     */
    114    sglrReferenceContext.getMipLevelSize = function(baseLevelSize, levelNdx) {
    115        return Math.max(baseLevelSize >> levelNdx, 1);
    116    };
    117 
    118    sglrReferenceContext.mapGLCubeFace = function(face) {
    119        switch (face) {
    120            case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
    121            case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X;
    122            case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
    123            case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y;
    124            case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
    125            case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z;
    126            default: throw new Error('Invalid cube face: ' + face);
    127        }
    128    };
    129 
    130    /**
    131     * @param {tcuTexture.FilterMode} mode
    132     * @return {boolean}
    133     */
    134    sglrReferenceContext.isMipmapFilter = function(/*const tcu::Sampler::FilterMode*/ mode) {
    135        return mode != tcuTexture.FilterMode.NEAREST && mode != tcuTexture.FilterMode.LINEAR;
    136    };
    137 
    138    sglrReferenceContext.getNumMipLevels1D = function(size) {
    139        return Math.floor(Math.log2(size)) + 1;
    140    };
    141 
    142    /**
    143     * @param {?sglrReferenceContext.TextureType} type
    144     * @return {sglrReferenceContext.TexTarget}
    145     */
    146    sglrReferenceContext.texLayeredTypeToTarget = function(type) {
    147        switch (type) {
    148            case sglrReferenceContext.TextureType.TYPE_2D_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY;
    149            case sglrReferenceContext.TextureType.TYPE_3D: return sglrReferenceContext.TexTarget.TEXTARGET_3D;
    150            case sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY;
    151            default: throw new Error('Invalid texture type: ' + type);
    152        }
    153    };
    154 
    155    /**
    156     * @param {rrDefs.IndexType} indexType
    157     * @return {number}
    158     * @throws {Error}
    159     */
    160    sglrReferenceContext.getFixedRestartIndex = function(indexType) {
    161        switch (indexType) {
    162            case rrDefs.IndexType.INDEXTYPE_UINT8: return 0xFF;
    163            case rrDefs.IndexType.INDEXTYPE_UINT16: return 0xFFFF;
    164            case rrDefs.IndexType.INDEXTYPE_UINT32: return 0xFFFFFFFF;
    165            default:
    166                throw new Error('Unrecognized index type: ' + indexType);
    167            }
    168    };
    169 
    170    /**
    171    * @constructor
    172    * @param {sglrShaderProgram.ShaderProgram} program
    173    */
    174    sglrReferenceContext.ShaderProgramObjectContainer = function(program) {
    175        this.m_program = program;
    176        /** @type {boolean} */ this.m_deleteFlag = false;
    177    };
    178 
    179    /**
    180    * @param {WebGL2RenderingContext} gl
    181    * @constructor
    182    */
    183    sglrReferenceContext.ReferenceContextLimits = function(gl) {
    184        /** @type {number} */ this.maxTextureImageUnits = 16;
    185        /** @type {number} */ this.maxTexture2DSize = 2048;
    186        /** @type {number} */ this.maxTextureCubeSize = 2048;
    187        /** @type {number} */ this.maxTexture2DArrayLayers = 256;
    188        /** @type {number} */ this.maxTexture3DSize = 256;
    189        /** @type {number} */ this.maxRenderbufferSize = 2048;
    190        /** @type {number} */ this.maxVertexAttribs = 16;
    191 
    192        if (gl) {
    193            this.maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
    194            this.maxTexture2DSize = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_SIZE));
    195            this.maxTextureCubeSize = /** @type {number} */ (gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE));
    196            this.maxRenderbufferSize = /** @type {number} */ (gl.getParameter(gl.MAX_RENDERBUFFER_SIZE));
    197            this.maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
    198            this.maxTexture2DArrayLayers = /** @type {number} */ (gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS));
    199            this.maxTexture3DSize = /** @type {number} */ (gl.getParameter(gl.MAX_3D_TEXTURE_SIZE));
    200 
    201            // Limit texture sizes to supported values
    202            this.maxTexture2DSize = Math.min(this.maxTexture2DSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
    203            this.maxTextureCubeSize = Math.min(this.maxTextureCubeSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
    204            this.maxTexture3DSize = Math.min(this.maxTexture3DSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
    205 
    206            sglrReferenceContext.GLU_EXPECT_NO_ERROR(gl.getError(), gl.NO_ERROR);
    207        }
    208 
    209        /* TODO: Port
    210        // \todo [pyry] Figure out following things:
    211        // + supported fbo configurations
    212        // ...
    213 
    214        // \todo [2013-08-01 pyry] Do we want to make these conditional based on renderCtx?
    215        addExtension("gl.EXT_color_buffer_half_float");
    216        addExtension("gl.WEBGL_color_buffer_float");
    217        */
    218    };
    219 
    220    /**
    221    * @enum
    222    */
    223    sglrReferenceContext.TextureType = {
    224        TYPE_2D: 0,
    225        TYPE_CUBE_MAP: 1,
    226        TYPE_2D_ARRAY: 2,
    227        TYPE_3D: 3,
    228        TYPE_CUBE_MAP_ARRAY: 4
    229    };
    230 
    231    /**
    232    * @constructor
    233    * @implements {rrDefs.Sampler}
    234    * @param {sglrReferenceContext.TextureType} type
    235    */
    236    sglrReferenceContext.Texture = function(type) {
    237        // NamedObject.call(this, name);
    238        /** @type {sglrReferenceContext.TextureType} */ this.m_type = type;
    239        /** @type {boolean} */ this.m_immutable = false;
    240        /** @type {number} */ this.m_baseLevel = 0;
    241        /** @type {number} */ this.m_maxLevel = 1000;
    242        /** @type {tcuTexture.Sampler} */ this.m_sampler = new tcuTexture.Sampler(
    243            tcuTexture.WrapMode.REPEAT_GL,
    244            tcuTexture.WrapMode.REPEAT_GL,
    245            tcuTexture.WrapMode.REPEAT_GL,
    246            tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR,
    247            tcuTexture.FilterMode.LINEAR,
    248            0,
    249            true,
    250            tcuTexture.CompareMode.COMPAREMODE_NONE,
    251            0,
    252            [0, 0, 0, 0],
    253            true);
    254    };
    255 
    256    /**
    257    * @param {Array<number>} pos
    258    * @param {number=} lod
    259    * @throws {Error}
    260    */
    261    sglrReferenceContext.Texture.prototype.sample = function(pos, lod) {throw new Error('Intentionally empty. Call method from child class instead'); };
    262 
    263    /**
    264    * @param {Array<Array<number>>} packetTexcoords
    265    * @param {number} lodBias
    266    * @throws {Error}
    267    */
    268    sglrReferenceContext.Texture.prototype.sample4 = function(packetTexcoords, lodBias) {throw new Error('Intentionally empty. Call method from child class instead'); };
    269 
    270    // sglrReferenceContext.Texture.prototype = Object.create(NamedObject.prototype);
    271    // sglrReferenceContext.Texture.prototype.constructor = sglrReferenceContext.Texture;
    272 
    273    /**
    274    * @return {number}
    275    */
    276    sglrReferenceContext.Texture.prototype.getType = function() { return this.m_type; };
    277 
    278    /**
    279    * @return {number}
    280    */
    281    sglrReferenceContext.Texture.prototype.getBaseLevel = function() { return this.m_baseLevel; };
    282 
    283    /**
    284    * @return {number}
    285    */
    286    sglrReferenceContext.Texture.prototype.getMaxLevel = function() { return this.m_maxLevel; };
    287 
    288    /**
    289    * @return {boolean}
    290    */
    291    sglrReferenceContext.Texture.prototype.isImmutable = function() { return this.m_immutable; };
    292 
    293    /**
    294    * @param {number} baseLevel
    295    */
    296    sglrReferenceContext.Texture.prototype.setBaseLevel = function(baseLevel) { this.m_baseLevel = baseLevel; };
    297 
    298    /**
    299    * @param {number} maxLevel
    300    */
    301    sglrReferenceContext.Texture.prototype.setMaxLevel = function(maxLevel) { this.m_maxLevel = maxLevel; };
    302 
    303    /**
    304    */
    305    sglrReferenceContext.Texture.prototype.setImmutable = function() { this.m_immutable = true; };
    306 
    307    /**
    308    * @return {tcuTexture.Sampler}
    309    */
    310    sglrReferenceContext.Texture.prototype.getSampler = function() { return this.m_sampler; };
    311 
    312    /**
    313    * @constructor
    314    */
    315    sglrReferenceContext.TextureLevelArray = function() {
    316        /** @type {Array<ArrayBuffer>} */ this.m_data = [];
    317        /** @type {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = [];
    318    };
    319 
    320    /**
    321     * @param {number} level
    322     * @return {boolean}
    323     */
    324    sglrReferenceContext.TextureLevelArray.prototype.hasLevel = function(level) { return this.m_data[level] != null; };
    325 
    326    /**
    327     * @param {number} level
    328     * @return {tcuTexture.PixelBufferAccess}
    329     * @throws {Error}
    330     */
    331    sglrReferenceContext.TextureLevelArray.prototype.getLevel = function(level) {
    332        if (!this.hasLevel(level))
    333            throw new Error('Level: ' + level + ' is not defined.');
    334 
    335        return this.m_access[level];
    336    };
    337 
    338    /**
    339     * @return {Array<tcuTexture.PixelBufferAccess>}
    340     */
    341    sglrReferenceContext.TextureLevelArray.prototype.getLevels = function() { return this.m_access; };
    342 
    343    /**
    344     * @param {number} level
    345     * @param {tcuTexture.TextureFormat} format
    346     * @param {number} width
    347     * @param {number} height
    348     * @param {number} depth
    349     */
    350    sglrReferenceContext.TextureLevelArray.prototype.allocLevel = function(level, format, width, height, depth) {
    351        /** @type {number} */ var dataSize = format.getPixelSize() * width * height * depth;
    352        if (this.hasLevel(level))
    353            this.clearLevel(level);
    354 
    355        this.m_data[level] = new ArrayBuffer(dataSize);
    356        this.m_access[level] = new tcuTexture.PixelBufferAccess({
    357            format: format,
    358            width: width,
    359            height: height,
    360            depth: depth,
    361            data: this.m_data[level]});
    362    };
    363 
    364    /**
    365     * @param {number} level
    366     */
    367    sglrReferenceContext.TextureLevelArray.prototype.clearLevel = function(level) {
    368        delete this.m_data[level];
    369        delete this.m_access[level];
    370    };
    371 
    372    /**
    373    */
    374    sglrReferenceContext.TextureLevelArray.prototype.clear = function() {
    375        for (var key in this.m_data)
    376            delete this.m_data[key];
    377 
    378        for (var key in this.m_access)
    379            delete this.m_access[key];
    380    };
    381 
    382    /**
    383    * @constructor
    384    * @extends {sglrReferenceContext.Texture}
    385    */
    386    sglrReferenceContext.Texture2D = function() {
    387        sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D);
    388        /** @type {tcuTexture.Texture2DView} */ this.m_view = new tcuTexture.Texture2DView(0, null);
    389        /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
    390    };
    391 
    392    /**
    393    */
    394    sglrReferenceContext.Texture2D.prototype = Object.create(sglrReferenceContext.Texture.prototype);
    395    sglrReferenceContext.Texture2D.prototype.constructor = sglrReferenceContext.Texture2D;
    396 
    397    sglrReferenceContext.Texture2D.prototype.clearLevels = function() { this.m_levels.clear(); };
    398 
    399    /**
    400    * @param {number} level
    401    * @return {boolean}
    402    */
    403    sglrReferenceContext.Texture2D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
    404 
    405    /**
    406    * @param {number} level
    407    * @return {tcuTexture.PixelBufferAccess}
    408    */
    409    sglrReferenceContext.Texture2D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
    410 
    411    /**
    412    * @param {number} level
    413    * @param {?tcuTexture.TextureFormat} format
    414    * @param {number} width
    415    * @param {number} height
    416    */
    417    sglrReferenceContext.Texture2D.prototype.allocLevel = function(level, format, width, height) { this.m_levels.allocLevel(level, format, width, height, 1); };
    418 
    419    /**
    420     * @return {boolean}
    421     */
    422    sglrReferenceContext.Texture2D.prototype.isComplete = function() {
    423        /** @type {number} */ var baseLevel = this.getBaseLevel();
    424 
    425        if (this.hasLevel(baseLevel)) {
    426            /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
    427            /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    428 
    429            if (mipmap) {
    430                /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
    431                /** @type {number} */ var w = level0.getWidth();
    432                /** @type {number} */ var h = level0.getHeight();
    433                /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h));
    434 
    435                for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
    436                    if (this.hasLevel(baseLevel + levelNdx)) {
    437                        /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
    438                        /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
    439                        /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
    440 
    441                        if (level.getWidth() != expectedW ||
    442                            level.getHeight() != expectedH ||
    443                            !level.getFormat().isEqual(format))
    444                            return false;
    445                    } else
    446                        return false;
    447                }
    448            }
    449 
    450            return true;
    451        } else
    452            return false;
    453    };
    454 
    455    /**
    456     */
    457    sglrReferenceContext.Texture2D.prototype.updateView = function() {
    458        /** @type {number} */ var baseLevel = this.getBaseLevel();
    459 
    460        if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
    461            // Update number of levels in mipmap pyramid.
    462            /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
    463            /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
    464            /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    465            /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
    466 
    467            this.m_view = new tcuTexture.Texture2DView(numLevels, this.m_levels.getLevels().slice(baseLevel));
    468        } else
    469            this.m_view = new tcuTexture.Texture2DView(0, null);
    470    };
    471 
    472    /**
    473     * @param {Array<number>} pos
    474     * @param {number=} lod
    475     * @return {Array<number>}
    476     */
    477    sglrReferenceContext.Texture2D.prototype.sample = function(pos, lod) {
    478        return this.m_view.sample(this.getSampler(), pos, lod);
    479    };
    480 
    481    /**
    482    * @param {Array<Array<number>>} packetTexcoords 4 vec2 coordinates
    483    * @param {number} lodBias_
    484    * @return {Array<Array<number>>} 4 vec4 samples
    485    */
    486    sglrReferenceContext.Texture2D.prototype.sample4 = function(packetTexcoords, lodBias_) {
    487        /** @type {number} */ var lodBias = lodBias_ || 0;
    488        /** @type {number} */ var texWidth = this.m_view.getWidth();
    489        /** @type {number} */ var texHeight = this.m_view.getHeight();
    490        /** @type {Array<Array<number>>}*/ var output = [];
    491 
    492        /** @type {Array<number>}*/ var dFdx0 = deMath.subtract(packetTexcoords[1], packetTexcoords[0]);
    493        /** @type {Array<number>}*/ var dFdx1 = deMath.subtract(packetTexcoords[3], packetTexcoords[2]);
    494        /** @type {Array<number>}*/ var dFdy0 = deMath.subtract(packetTexcoords[2], packetTexcoords[0]);
    495        /** @type {Array<number>}*/ var dFdy1 = deMath.subtract(packetTexcoords[3], packetTexcoords[1]);
    496 
    497        for (var fragNdx = 0; fragNdx < 4; ++fragNdx) {
    498            /** @type {Array<number>}*/var dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
    499            /** @type {Array<number>}*/var dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
    500 
    501            /** @type {number} */ var mu = Math.max(Math.abs(dFdx[0]), Math.abs(dFdy[0]));
    502            /** @type {number} */ var mv = Math.max(Math.abs(dFdx[1]), Math.abs(dFdy[1]));
    503            /** @type {number} */ var p = Math.max(mu * texWidth, mv * texHeight);
    504 
    505            /** @type {number} */ var lod = Math.log2(p) + lodBias;
    506 
    507            output.push(this.sample([packetTexcoords[fragNdx][0], packetTexcoords[fragNdx][1]], lod));
    508        }
    509 
    510        return output;
    511    };
    512 
    513    /**
    514    * @constructor
    515    * @extends {sglrReferenceContext.Texture}
    516    */
    517    sglrReferenceContext.TextureCube = function() {
    518        sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_CUBE_MAP);
    519        /** @type {tcuTexture.TextureCubeView} */ this.m_view = new tcuTexture.TextureCubeView(0, null);
    520        /** @type {Array<sglrReferenceContext.TextureLevelArray>} */ this.m_levels = [];
    521        for (var face in tcuTexture.CubeFace)
    522            this.m_levels[tcuTexture.CubeFace[face]] = new sglrReferenceContext.TextureLevelArray();
    523    };
    524 
    525    /**
    526    */
    527    sglrReferenceContext.TextureCube.prototype = Object.create(sglrReferenceContext.Texture.prototype);
    528    sglrReferenceContext.TextureCube.prototype.constructor = sglrReferenceContext.Texture2D;
    529 
    530    sglrReferenceContext.TextureCube.prototype.clearLevels = function() {
    531        for (var face in tcuTexture.CubeFace)
    532            this.m_levels[tcuTexture.CubeFace[face]].clear();
    533    };
    534 
    535    /**
    536    * @param {number} level
    537    * @param {tcuTexture.CubeFace} face
    538    * @return {boolean}
    539    */
    540    sglrReferenceContext.TextureCube.prototype.hasFace = function(level, face) { return this.m_levels[face].hasLevel(level); };
    541 
    542    /**
    543    * @param {number} level
    544    * @param {tcuTexture.CubeFace} face
    545    * @return {tcuTexture.PixelBufferAccess}
    546    */
    547    sglrReferenceContext.TextureCube.prototype.getFace = function(level, face) { return this.m_levels[face].getLevel(level); };
    548 
    549    /**
    550    * @param {number} level
    551    * @param {tcuTexture.CubeFace} face
    552    * @param {?tcuTexture.TextureFormat} format
    553    * @param {number} width
    554    * @param {number} height
    555    */
    556    sglrReferenceContext.TextureCube.prototype.allocLevel = function(level, face, format, width, height) {
    557        this.m_levels[face].allocLevel(level, format, width, height, 1);
    558    };
    559 
    560    sglrReferenceContext.TextureCube.prototype.isComplete = function() {
    561        var baseLevel = this.getBaseLevel();
    562 
    563        if (this.hasFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X)) {
    564            var level = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X);
    565            var width = level.getWidth();
    566            var height = level.getHeight();
    567            var format = level.getFormat();
    568            var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    569            var numLevels = mipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
    570 
    571            if (width != height)
    572                return false; // Non-square is not supported.
    573 
    574            // \note Level 0 is always checked for consistency
    575            for (var levelNdx = 0; levelNdx < numLevels; levelNdx++) {
    576                var levelW = sglrReferenceContext.getMipLevelSize(width, levelNdx);
    577                var levelH = sglrReferenceContext.getMipLevelSize(height, levelNdx);
    578 
    579                for (var face in tcuTexture.CubeFace) {
    580                    if (this.hasFace(baseLevel + levelNdx, tcuTexture.CubeFace[face])) {
    581                        level = this.getFace(baseLevel + levelNdx, tcuTexture.CubeFace[face]);
    582 
    583                        if (level.getWidth() != levelW ||
    584                            level.getHeight() != levelH ||
    585                            !level.getFormat().isEqual(format))
    586                            return false;
    587                    } else
    588                        return false;
    589                }
    590            }
    591 
    592            return true;
    593        } else
    594            return false;
    595    };
    596 
    597    sglrReferenceContext.TextureCube.prototype.updateView = function() {
    598 
    599        var baseLevel = this.getBaseLevel();
    600        var faces = [];
    601 
    602        if (this.isComplete()) {
    603            var size = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X).getWidth();
    604            var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    605            var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels1D(size)) : 1;
    606 
    607            for (var face in tcuTexture.CubeFace)
    608                faces[tcuTexture.CubeFace[face]] = this.m_levels[tcuTexture.CubeFace[face]].getLevels().slice(baseLevel);
    609 
    610            this.m_view = new tcuTexture.TextureCubeView(numLevels, faces);
    611        } else
    612            this.m_view = new tcuTexture.TextureCubeView(0, null);
    613    };
    614 
    615    /**
    616     * @param {Array<number>} pos
    617     * @param {number=} lod
    618     * @return {Array<number>}
    619     */
    620    sglrReferenceContext.TextureCube.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) };
    621 
    622    /**
    623    * @constructor
    624    * @extends {sglrReferenceContext.Texture}
    625    */
    626    sglrReferenceContext.Texture2DArray = function() {
    627        sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
    628        /** @type {tcuTexture.Texture2DArrayView} */ this.m_view = new tcuTexture.Texture2DArrayView(0, null);
    629        /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
    630    };
    631 
    632    /**
    633    */
    634    sglrReferenceContext.Texture2DArray.prototype = Object.create(sglrReferenceContext.Texture.prototype);
    635    sglrReferenceContext.Texture2DArray.prototype.constructor = sglrReferenceContext.Texture2DArray;
    636 
    637    sglrReferenceContext.Texture2DArray.prototype.clearLevels = function() { this.m_levels.clear(); };
    638 
    639    /**
    640    * @param {number} level
    641    * @return {boolean}
    642    */
    643    sglrReferenceContext.Texture2DArray.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
    644 
    645    /**
    646    * @param {number} level
    647    * @return {tcuTexture.PixelBufferAccess}
    648    */
    649    sglrReferenceContext.Texture2DArray.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
    650 
    651    /**
    652    * @param {number} level
    653    * @param {?tcuTexture.TextureFormat} format
    654    * @param {number} width
    655    * @param {number} height
    656    * @param {number} numLayers
    657    */
    658    sglrReferenceContext.Texture2DArray.prototype.allocLevel = function(level, format, width, height, numLayers) {
    659        this.m_levels.allocLevel(level, format, width, height, numLayers);
    660    };
    661 
    662    /**
    663     * @return {boolean}
    664     */
    665    sglrReferenceContext.Texture2DArray.prototype.isComplete = function() {
    666        /** @type {number} */ var baseLevel = this.getBaseLevel();
    667 
    668        if (this.hasLevel(baseLevel)) {
    669            /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
    670            /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    671 
    672            if (mipmap) {
    673                /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
    674                /** @type {number} */ var w = level0.getWidth();
    675                /** @type {number} */ var h = level0.getHeight();
    676                /** @type {number} */ var numLayers = level0.getDepth();
    677                /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h));
    678 
    679                for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
    680                    if (this.hasLevel(baseLevel + levelNdx)) {
    681                        /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
    682                        /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
    683                        /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
    684 
    685                        if (level.getWidth() != expectedW ||
    686                            level.getHeight() != expectedH ||
    687                            level.getDepth() != numLayers ||
    688                            !level.getFormat().isEqual(format))
    689                            return false;
    690                    } else
    691                        return false;
    692                }
    693            }
    694 
    695            return true;
    696        } else
    697            return false;
    698    };
    699 
    700    /**
    701     */
    702    sglrReferenceContext.Texture2DArray.prototype.updateView = function() {
    703        /** @type {number} */ var baseLevel = this.getBaseLevel();
    704 
    705        if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
    706            // Update number of levels in mipmap pyramid.
    707            /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
    708            /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
    709            /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    710            /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
    711 
    712            this.m_view = new tcuTexture.Texture2DArrayView(numLevels, this.m_levels.getLevels().slice(baseLevel));
    713        } else
    714            this.m_view = new tcuTexture.Texture2DArrayView(0, null);
    715    };
    716 
    717    /**
    718     * @param {Array<number>} pos
    719     * @param {number=} lod
    720     * @return {Array<number>}
    721     */
    722    sglrReferenceContext.Texture2DArray.prototype.sample = function(pos, lod) {
    723        return this.m_view.sample(this.getSampler(), pos, lod);
    724    };
    725 
    726    /**
    727    * @constructor
    728    * @extends {sglrReferenceContext.Texture}
    729    */
    730    sglrReferenceContext.Texture3D = function() {
    731        sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
    732        /** @type {tcuTexture.Texture3DView} */ this.m_view = new tcuTexture.Texture3DView(0, null);
    733        /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
    734    };
    735 
    736    /**
    737    */
    738    sglrReferenceContext.Texture3D.prototype = Object.create(sglrReferenceContext.Texture.prototype);
    739    sglrReferenceContext.Texture3D.prototype.constructor = sglrReferenceContext.Texture3D;
    740 
    741    sglrReferenceContext.Texture3D.prototype.clearLevels = function() { this.m_levels.clear(); };
    742 
    743    /**
    744    * @param {number} level
    745    * @return {boolean}
    746    */
    747    sglrReferenceContext.Texture3D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
    748 
    749    /**
    750    * @param {number} level
    751    * @return {tcuTexture.PixelBufferAccess}
    752    */
    753    sglrReferenceContext.Texture3D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
    754 
    755    /**
    756    * @param {number} level
    757    * @param {?tcuTexture.TextureFormat} format
    758    * @param {number} width
    759    * @param {number} height
    760    * @param {number} depth
    761    */
    762    sglrReferenceContext.Texture3D.prototype.allocLevel = function(level, format, width, height, depth) {
    763        this.m_levels.allocLevel(level, format, width, height, depth);
    764    };
    765 
    766    /**
    767     * @return {boolean}
    768     */
    769    sglrReferenceContext.Texture3D.prototype.isComplete = function() {
    770        /** @type {number} */ var baseLevel = this.getBaseLevel();
    771 
    772        if (this.hasLevel(baseLevel)) {
    773            /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
    774            /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    775 
    776            if (mipmap) {
    777                /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
    778                /** @type {number} */ var w = level0.getWidth();
    779                /** @type {number} */ var h = level0.getHeight();
    780                /** @type {number} */ var d = level0.getDepth();
    781                /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels3D(w, h, d));
    782 
    783                for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
    784                    if (this.hasLevel(baseLevel + levelNdx)) {
    785                        /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
    786                        /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
    787                        /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
    788                        /** @type {number} */ var expectedD = sglrReferenceContext.getMipLevelSize(d, levelNdx);
    789 
    790                        if (level.getWidth() != expectedW ||
    791                            level.getHeight() != expectedH ||
    792                            level.getDepth() != expectedD ||
    793                            !level.getFormat().isEqual(format))
    794                            return false;
    795                    } else
    796                        return false;
    797                }
    798            }
    799 
    800            return true;
    801        } else
    802            return false;
    803    };
    804 
    805    /**
    806     */
    807    sglrReferenceContext.Texture3D.prototype.updateView = function() {
    808        /** @type {number} */ var baseLevel = this.getBaseLevel();
    809 
    810        if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
    811            // Update number of levels in mipmap pyramid.
    812            /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
    813            /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
    814            /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
    815            /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
    816 
    817            this.m_view = new tcuTexture.Texture3DView(numLevels, this.m_levels.getLevels().slice(baseLevel));
    818        } else
    819            this.m_view = new tcuTexture.Texture3DView(0, null);
    820    };
    821 
    822    /**
    823     * @param {Array<number>} pos
    824     * @param {number=} lod
    825     * @return {Array<number>}
    826     */
    827    sglrReferenceContext.Texture3D.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) };
    828 
    829    /**
    830    * A container object for storing one of texture types;
    831    * @constructor
    832    */
    833    sglrReferenceContext.TextureContainer = function() {
    834        /** @type {sglrReferenceContext.Texture2D | sglrReferenceContext.TextureCube|sglrReferenceContext.Texture2DArray|sglrReferenceContext.Texture3D} */
    835         this.texture = null;
    836        /** @type {?sglrReferenceContext.TextureType} */ this.textureType = null;
    837    };
    838 
    839    /**
    840     * @return {?sglrReferenceContext.TextureType}
    841     */
    842    sglrReferenceContext.TextureContainer.prototype.getType = function() { return this.textureType; };
    843 
    844    /**
    845     * @param {number} target
    846     * @throws {Error}
    847     */
    848    sglrReferenceContext.TextureContainer.prototype.init = function(target) {
    849        switch (target) {
    850            case gl.TEXTURE_2D:
    851                this.texture = new sglrReferenceContext.Texture2D();
    852                this.textureType = sglrReferenceContext.TextureType.TYPE_2D;
    853                break;
    854            case gl.TEXTURE_CUBE_MAP:
    855                this.texture = new sglrReferenceContext.TextureCube();
    856                this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP;
    857                break;
    858            case gl.TEXTURE_2D_ARRAY:
    859                this.texture = new sglrReferenceContext.Texture2DArray();
    860                this.textureType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY;
    861                break;
    862            case gl.TEXTURE_3D:
    863                this.texture = new sglrReferenceContext.Texture3D();
    864                this.textureType = sglrReferenceContext.TextureType.TYPE_3D;
    865                break;
    866            /* TODO: Implement other types */
    867            // case gl.TEXTURE_CUBE_MAP_ARRAY:
    868            //     this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY;
    869            //     break;
    870            default: throw new Error('Unrecognized target: ' + target);
    871        }
    872    };
    873 
    874    /**
    875    * @enum
    876    */
    877    sglrReferenceContext.AttachmentPoint = {
    878        ATTACHMENTPOINT_COLOR0: 0,
    879        ATTACHMENTPOINT_DEPTH: 1,
    880        ATTACHMENTPOINT_STENCIL: 2
    881    };
    882 
    883    /**
    884     * @param {number} attachment
    885     * @return {sglrReferenceContext.AttachmentPoint}
    886     * @throws {Error}
    887     */
    888    sglrReferenceContext.mapGLAttachmentPoint = function(attachment) {
    889        switch (attachment) {
    890            case gl.COLOR_ATTACHMENT0: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0;
    891            case gl.DEPTH_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH;
    892            case gl.STENCIL_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL;
    893            default: throw new Error('Wrong attachment point:' + attachment);
    894        }
    895    };
    896 
    897    /**
    898    * @enum
    899    */
    900    sglrReferenceContext.AttachmentType = {
    901        ATTACHMENTTYPE_RENDERBUFFER: 0,
    902        ATTACHMENTTYPE_TEXTURE: 1
    903    };
    904 
    905    /**
    906    * @enum
    907    */
    908    sglrReferenceContext.TexTarget = {
    909        TEXTARGET_2D: 0,
    910        TEXTARGET_CUBE_MAP_POSITIVE_X: 1,
    911        TEXTARGET_CUBE_MAP_POSITIVE_Y: 2,
    912        TEXTARGET_CUBE_MAP_POSITIVE_Z: 3,
    913        TEXTARGET_CUBE_MAP_NEGATIVE_X: 4,
    914        TEXTARGET_CUBE_MAP_NEGATIVE_Y: 5,
    915        TEXTARGET_CUBE_MAP_NEGATIVE_Z: 6,
    916        TEXTARGET_2D_ARRAY: 7,
    917        TEXTARGET_3D: 8,
    918        TEXTARGET_CUBE_MAP_ARRAY: 9
    919    };
    920 
    921    /**
    922     * @param {?sglrReferenceContext.TexTarget} target
    923     * @return {tcuTexture.CubeFace}
    924     */
    925    sglrReferenceContext.texTargetToFace = function(target) {
    926        switch (target) {
    927            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
    928            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X;
    929            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
    930            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y;
    931            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
    932            case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z;
    933            default: throw new Error('Invalid target ' + target);
    934        }
    935    };
    936 
    937    /**
    938     * @param {sglrReferenceContext.TexTarget} target
    939     * @return {sglrReferenceContext.TexTarget}
    940     * @throws {Error}
    941     */
    942    sglrReferenceContext.mapGLFboTexTarget = function(target) {
    943        switch (target) {
    944            case gl.TEXTURE_2D: return sglrReferenceContext.TexTarget.TEXTARGET_2D;
    945            case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X;
    946            case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y;
    947            case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z;
    948            case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X;
    949            case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y;
    950            case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z;
    951            default: throw new Error('Wrong texture target:' + target);
    952        }
    953    };
    954 
    955    /**
    956    * @constructor
    957    */
    958    sglrReferenceContext.Attachment = function() {
    959        /** @type {?sglrReferenceContext.AttachmentType} */ this.type = null;
    960        /** @type {sglrReferenceContext.TextureContainer|sglrReferenceContext.Renderbuffer} */ this.object = null; // TODO: fix reserved word
    961        /** @type {?sglrReferenceContext.TexTarget} */ this.texTarget = null;
    962        /** @type {number} */ this.level = 0;
    963        /** @type {number} */ this.layer = 0;
    964    };
    965 
    966    /**
    967    * @constructor
    968    */
    969    sglrReferenceContext.Framebuffer = function() {
    970        /** @type {Array<sglrReferenceContext.Attachment>} */ this.m_attachments = [];
    971        for (var key in sglrReferenceContext.AttachmentPoint)
    972            this.m_attachments[sglrReferenceContext.AttachmentPoint[key]] = new sglrReferenceContext.Attachment();
    973    };
    974 
    975    /**
    976    * @param {sglrReferenceContext.AttachmentPoint} point
    977    * @return {sglrReferenceContext.Attachment}
    978    */
    979    sglrReferenceContext.Framebuffer.prototype.getAttachment = function(point) { return this.m_attachments[point]; };
    980 
    981    /**
    982    * @param {sglrReferenceContext.AttachmentPoint} point
    983    * @param {sglrReferenceContext.Attachment} attachment
    984    */
    985    sglrReferenceContext.Framebuffer.prototype.setAttachment = function(point, attachment) { this.m_attachments[point] = attachment; };
    986 
    987    // /**
    988    //  * @enum
    989    //  */
    990    // var Format = {
    991    //     FORMAT_DEPTH_COMPONENT16: 0,
    992    //     FORMAT_RGBA4: 1,
    993    //     FORMAT_RGB5_A1: 2,
    994    //     FORMAT_RGB565: 3,
    995    //     FORMAT_STENCIL_INDEX8: 4
    996    // };
    997 
    998    /**
    999    * @constructor
   1000    */
   1001    sglrReferenceContext.Renderbuffer = function() {
   1002        /** @type {tcuTexture.TextureLevel} */ this.m_data;
   1003    };
   1004 
   1005    /**
   1006    * @param {tcuTexture.TextureFormat} format
   1007    * @param {number} width
   1008    * @param {number} height
   1009    */
   1010    sglrReferenceContext.Renderbuffer.prototype.setStorage = function(format, width, height) {
   1011        this.m_data = new tcuTexture.TextureLevel(format, width, height);
   1012    };
   1013 
   1014    /**
   1015     * @return {number}
   1016     */
   1017    sglrReferenceContext.Renderbuffer.prototype.getWidth = function() { return this.m_data.getWidth(); };
   1018 
   1019    /**
   1020     * @return {number}
   1021     */
   1022    sglrReferenceContext.Renderbuffer.prototype.getHeight = function() { return this.m_data.getHeight(); };
   1023 
   1024    /**
   1025     * @return {?tcuTexture.TextureFormat}
   1026     */
   1027    sglrReferenceContext.Renderbuffer.prototype.getFormat = function() { return this.m_data.getFormat(); };
   1028 
   1029    /**
   1030     * @return {tcuTexture.PixelBufferAccess}
   1031     */
   1032    sglrReferenceContext.Renderbuffer.prototype.getAccess = function() { return this.m_data.getAccess(); };
   1033 
   1034    /**
   1035     * @constructor
   1036     * @param {number} maxVertexAttribs
   1037     */
   1038    sglrReferenceContext.VertexArray = function(maxVertexAttribs) {
   1039        /** @type {sglrReferenceContext.DataBuffer} */ this.m_elementArrayBufferBinding = null;
   1040 
   1041        /** @type {Array<sglrReferenceContext.VertexArray.VertexAttribArray>} */this.m_arrays = [];
   1042        for (var i = 0; i < maxVertexAttribs; i++)
   1043            this.m_arrays.push(new sglrReferenceContext.VertexArray.VertexAttribArray());
   1044    };
   1045 
   1046    /** @constructor */
   1047    sglrReferenceContext.VertexArray.VertexAttribArray = function() {
   1048        this.enabled = false;
   1049        this.size = 4;
   1050        this.stride = 0;
   1051        this.type = gl.FLOAT;
   1052 
   1053        this.normalized = false;
   1054        this.integer = false;
   1055        this.divisor = 0;
   1056        this.offset = 0;
   1057        this.bufferBinding = null;
   1058    };
   1059 
   1060    /**
   1061    * @constructor
   1062    */
   1063    sglrReferenceContext.DataBuffer = function() {
   1064        /** @type {?ArrayBuffer} */ this.m_data = null;
   1065    };
   1066 
   1067    /**
   1068     * @param {number} size
   1069     */
   1070    sglrReferenceContext.DataBuffer.prototype.setStorage = function(size) {this.m_data = new ArrayBuffer(size); };
   1071 
   1072    /**
   1073     * @return {number}
   1074     */
   1075    sglrReferenceContext.DataBuffer.prototype.getSize = function() {
   1076        /** @type {number} */ var size = 0;
   1077        if (this.m_data)
   1078            size = this.m_data.byteLength;
   1079        return size;
   1080    };
   1081 
   1082    /**
   1083     * @return {?ArrayBuffer}
   1084     */
   1085    sglrReferenceContext.DataBuffer.prototype.getData = function() { return this.m_data; };
   1086 
   1087    /**
   1088     * @param {ArrayBuffer|goog.NumberArray} data
   1089     */
   1090    sglrReferenceContext.DataBuffer.prototype.setData = function(data) {
   1091        /** @type {ArrayBuffer} */ var buffer;
   1092        /** @type {number} */ var offset = 0;
   1093        /** @type {number} */ var byteLength = data.byteLength;
   1094        if (data instanceof ArrayBuffer)
   1095            buffer = data;
   1096        else {
   1097            buffer = data.buffer;
   1098            offset = data.byteOffset;
   1099        }
   1100 
   1101        if (!buffer)
   1102            throw new Error('Invalid buffer');
   1103 
   1104        this.m_data = buffer.slice(offset, offset + byteLength);
   1105    };
   1106 
   1107    /**
   1108     * @param {number} offset
   1109     * @param {goog.NumberArray} data
   1110     */
   1111    sglrReferenceContext.DataBuffer.prototype.setSubData = function(offset, data) {
   1112        /** @type {ArrayBuffer} */ var buffer;
   1113        /** @type {number} */ var srcOffset = 0;
   1114        /** @type {number} */ var byteLength = data.byteLength;
   1115        if (data instanceof ArrayBuffer)
   1116            buffer = data;
   1117        else {
   1118            buffer = data.buffer;
   1119            srcOffset = data.byteOffset;
   1120        }
   1121 
   1122        if (!buffer)
   1123            throw new Error('Invalid buffer');
   1124 
   1125        /** @type {goog.NumberArray} */ var src = new Uint8Array(buffer, srcOffset, byteLength);
   1126        /** @type {goog.NumberArray} */ var dst = new Uint8Array(this.m_data, offset, byteLength);
   1127        dst.set(src);
   1128    };
   1129 
   1130    // /**
   1131    //  * @constructor
   1132    //  */
   1133    // var ObjectManager = function() {
   1134    //     this.m_objects = {};
   1135    // };
   1136 
   1137    // ObjectManager.prototype.insert = function(obj) {
   1138    //     var name = obj.getName();
   1139    //     if (!name)
   1140    //         throw new Error("Cannot insert unnamed object");
   1141    //     this.m_objects[name] = obj;
   1142    // };
   1143 
   1144    // ObjectManager.prototype.find = function(name) { return this.m_objects[name]; };
   1145 
   1146    // ObjectManager.prototype.acquireReference = function(obj) {
   1147    //     if (this.find(obj.getName()) !== obj)
   1148    //         throw new Error("Object is not in the object manager");
   1149    //     obj.incRefCount();
   1150    // };
   1151 
   1152    // ObjectManager.prototype.releaseReference = function(obj) {
   1153    //     if (this.find(obj.getName()) !== obj)
   1154    //         throw new Error("Object is not in the object manager");
   1155 
   1156    //     obj.decRefCount();
   1157 
   1158    //     if (obj.getRefCount() == 0)
   1159    //         delete this.m_objects[obj.getName()];
   1160    // };
   1161 
   1162    // ObjectManager.prototype.getAll = function() { return this.m_objects; };
   1163 
   1164    /**
   1165    * @constructor
   1166    */
   1167    sglrReferenceContext.TextureUnit = function() {
   1168        /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DBinding = null;
   1169        /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeBinding = null;
   1170        /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DArrayBinding = null;
   1171        /** @type {?sglrReferenceContext.TextureContainer} */ this.tex3DBinding = null;
   1172        /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeArrayBinding = null;
   1173    };
   1174 
   1175    /**
   1176    * @constructor
   1177    */
   1178    sglrReferenceContext.StencilState = function() {
   1179        /** @type {number} */ this.func = gl.ALWAYS;
   1180        /** @type {number} */ this.ref = 0;
   1181        /** @type {number} */ this.opMask = ~0;
   1182        /** @type {number} */ this.opStencilFail = gl.KEEP;
   1183        /** @type {number} */ this.opDepthFail = gl.KEEP;
   1184        /** @type {number} */ this.opDepthPass = gl.KEEP;
   1185        /** @type {number} */ this.writeMask = ~0;
   1186    };
   1187 
   1188    /**
   1189     * @param {tcuPixelFormat.PixelFormat} pixelFmt
   1190     * @return {tcuTexture.TextureFormat}
   1191     * @throws {Error}
   1192     */
   1193    sglrReferenceContext.toTextureFormat = function(pixelFmt) {
   1194        if (pixelFmt.equals(8, 8, 8, 8))
   1195            return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
   1196        else if (pixelFmt.equals(8, 8, 8, 0))
   1197            return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
   1198        else if (pixelFmt.equals(4, 4, 4, 4))
   1199            return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444);
   1200        else if (pixelFmt.equals(5, 5, 5, 1))
   1201            return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551);
   1202        else if (pixelFmt.equals(5, 6, 5, 0))
   1203            return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565);
   1204 
   1205        throw new Error('Could not map pixel format:' + pixelFmt);
   1206    };
   1207 
   1208    /**
   1209     * @param {number} depthBits
   1210     * @return {tcuTexture.TextureFormat}
   1211     * @throws {Error}
   1212     */
   1213    sglrReferenceContext.getDepthFormat = function(depthBits) {
   1214        switch (depthBits) {
   1215            case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT8);
   1216            case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16);
   1217            case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
   1218            case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT);
   1219            default:
   1220                throw new Error("Can't map depth buffer format, bits: " + depthBits);
   1221        }
   1222    };
   1223 
   1224    /**
   1225     * @param {number} stencilBits
   1226     * @return {tcuTexture.TextureFormat}
   1227     * @throws {Error}
   1228     */
   1229    sglrReferenceContext.getStencilFormat = function(stencilBits) {
   1230        switch (stencilBits) {
   1231            case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8);
   1232            case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT16);
   1233            case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
   1234            case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT32);
   1235            default:
   1236                throw new Error("Can't map stencil buffer format, bits: " + stencilBits);
   1237        }
   1238    };
   1239 
   1240    /**
   1241    * @constructor
   1242    * @param {tcuPixelFormat.PixelFormat} colorBits
   1243    * @param {number} depthBits
   1244    * @param {number} stencilBits
   1245    * @param {number} width
   1246    * @param {number} height
   1247    * @param {number=} samples_
   1248    */
   1249    sglrReferenceContext.ReferenceContextBuffers = function(colorBits, depthBits, stencilBits, width, height, samples_) {
   1250        if (samples_ === undefined)
   1251            samples_ = 1;
   1252 
   1253        /** @type {number} */ var samples = samples_;
   1254        /** @type {tcuTexture.TextureLevel} */ this.m_colorbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.toTextureFormat(colorBits), samples, width, height);
   1255 
   1256        if (depthBits > 0)
   1257            /** @type {tcuTexture.TextureLevel} */ this.m_depthbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getDepthFormat(depthBits), samples, width, height);
   1258 
   1259        if (stencilBits > 0)
   1260            /** @type {tcuTexture.TextureLevel} */ this.m_stencilbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getStencilFormat(stencilBits), samples, width, height);
   1261    };
   1262 
   1263    /**
   1264     * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   1265     */
   1266    sglrReferenceContext.ReferenceContextBuffers.prototype.getColorbuffer = function() { return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_colorbuffer.getAccess()); };
   1267 
   1268    /**
   1269     * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   1270     */
   1271    sglrReferenceContext.ReferenceContextBuffers.prototype.getDepthbuffer = function() { return this.m_depthbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_depthbuffer.getAccess()) : null; };
   1272 
   1273    /**
   1274     * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   1275     */
   1276    sglrReferenceContext.ReferenceContextBuffers.prototype.getStencilbuffer = function() { return this.m_stencilbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_stencilbuffer.getAccess()) : null; };
   1277 
   1278    /**
   1279    * @param {sglrReferenceContext.ReferenceContextLimits} limits
   1280    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} colorbuffer
   1281    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} depthbuffer
   1282    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} stencilbuffer
   1283    * @constructor
   1284    */
   1285    sglrReferenceContext.ReferenceContext = function(limits, colorbuffer, depthbuffer, stencilbuffer) {
   1286        /** @type {sglrReferenceContext.ReferenceContextLimits} */ this.m_limits = limits;
   1287        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultColorbuffer = colorbuffer;
   1288        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultDepthbuffer = depthbuffer;
   1289        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultStencilbuffer = stencilbuffer;
   1290        /** @type {Array<number>} */ this.m_viewport = [0, 0, colorbuffer.raw().getHeight(), colorbuffer.raw().getDepth()];
   1291        /** @type {Array<sglrReferenceContext.TextureUnit>} */ this.m_textureUnits = [];
   1292        for (var i = 0; i < this.m_limits.maxTextureImageUnits; i++)
   1293            this.m_textureUnits.push(new sglrReferenceContext.TextureUnit());
   1294        /** @type {number} */ this.m_activeTexture = 0;
   1295        /** @type {number} */ this.m_lastError = gl.NO_ERROR;
   1296        // this.m_textures = new ObjectManager();
   1297        /** @type {number} */ this.m_pixelUnpackRowLength = 0;
   1298        /** @type {number} */ this.m_pixelUnpackSkipRows = 0;
   1299        /** @type {number} */ this.m_pixelUnpackSkipPixels = 0;
   1300        /** @type {number} */ this.m_pixelUnpackImageHeight = 0;
   1301        /** @type {number} */ this.m_pixelUnpackSkipImages = 0;
   1302        /** @type {number} */ this.m_pixelUnpackAlignment = 4;
   1303        /** @type {number} */ this.m_pixelPackAlignment = 4;
   1304        /** @type {Array<number>} */ this.m_clearColor = [0, 0, 0, 0];
   1305        /** @type {number} */ this.m_clearDepth = 1;
   1306        /** @type {number} */ this.m_clearStencil = 0;
   1307        /** @type {Array<number>} */ this.m_scissorBox = this.m_viewport;
   1308        /** @type {boolean} */ this.m_blendEnabled = false;
   1309        /** @type {boolean} */ this.m_scissorEnabled = false;
   1310        /** @type {boolean} */ this.m_depthTestEnabled = false;
   1311        /** @type {boolean} */ this.m_stencilTestEnabled = false;
   1312        /** @type {boolean} */ this.m_polygonOffsetFillEnabled = false;
   1313        /** @type {boolean} */ this.m_primitiveRestartFixedIndex = true; //always on
   1314        /** @type {boolean} */ this.m_primitiveRestartSettableIndex = true; //always on
   1315        /** @type {Array<sglrReferenceContext.StencilState>} */ this.m_stencil = [];
   1316        for (var type in rrDefs.FaceType)
   1317            this.m_stencil[rrDefs.FaceType[type]] = new sglrReferenceContext.StencilState();
   1318        /** @type {number} */ this.m_depthFunc = gl.LESS;
   1319        /** @type {number} */ this.m_depthRangeNear = 0;
   1320        /** @type {number} */ this.m_depthRangeFar = 1;
   1321        /** @type {number} */ this.m_polygonOffsetFactor = 0;
   1322        /** @type {number} */ this.m_polygonOffsetUnits = 0;
   1323        /** @type {number} */ this.m_blendModeRGB = gl.FUNC_ADD;
   1324        /** @type {number} */ this.m_blendModeAlpha = gl.FUNC_ADD;
   1325        /** @type {number} */ this.m_blendFactorSrcRGB = gl.ONE;
   1326        /** @type {number} */ this.m_blendFactorDstRGB = gl.ZERO;
   1327        /** @type {number} */ this.m_blendFactorSrcAlpha = gl.ONE;
   1328        /** @type {number} */ this.m_blendFactorDstAlpha = gl.ZERO;
   1329        /** @type {Array<number>} */ this.m_blendColor = [0, 0, 0, 0];
   1330        /** @type {boolean} */ this.m_sRGBUpdateEnabled = true;
   1331        /** @type {Array<boolean>} */ this.m_colorMask = [true, true, true, true];
   1332        /** @type {boolean} */ this.m_depthMask = true;
   1333        /** @type {sglrReferenceContext.VertexArray} */ this.m_defaultVAO = new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs);
   1334        /** @type {sglrReferenceContext.VertexArray} */ this.m_vertexArrayBinding = this.m_defaultVAO;
   1335        /** @type {sglrReferenceContext.DataBuffer} */ this.m_arrayBufferBinding = null;
   1336        /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyReadBufferBinding = null;
   1337        /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyWriteBufferBinding = null;
   1338        /** @type {sglrReferenceContext.DataBuffer} */ this.m_drawIndirectBufferBinding = null;
   1339        /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelPackBufferBinding = null;
   1340        /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelUnpackBufferBinding = null;
   1341        /** @type {sglrReferenceContext.DataBuffer} */ this.m_transformFeedbackBufferBinding = null;
   1342        /** @type {sglrReferenceContext.DataBuffer} */ this.m_uniformBufferBinding = null;
   1343        /** @type {sglrReferenceContext.Framebuffer} */ this.m_readFramebufferBinding = null;
   1344        /** @type {sglrReferenceContext.Framebuffer} */ this.m_drawFramebufferBinding = null;
   1345        /** @type {sglrReferenceContext.Renderbuffer} */ this.m_renderbufferBinding = null;
   1346        /** @type {sglrShaderProgram.ShaderProgram} */ this.m_currentProgram = null;
   1347        /** @type {Array<rrGenericVector.GenericVec4>} */ this.m_currentAttribs = [];
   1348        for (var i = 0; i < this.m_limits.maxVertexAttribs; i++)
   1349            this.m_currentAttribs.push(new rrGenericVector.GenericVec4());
   1350        /** @type {number} */ this.m_lineWidth = 1;
   1351 
   1352        /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2D = new sglrReferenceContext.TextureContainer();
   1353        this.m_emptyTex2D.init(gl.TEXTURE_2D);
   1354        this.m_emptyTex2D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1355        this.m_emptyTex2D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1356        this.m_emptyTex2D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
   1357        this.m_emptyTex2D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
   1358        this.m_emptyTex2D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
   1359        this.m_emptyTex2D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
   1360        this.m_emptyTex2D.texture.updateView();
   1361 
   1362        /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTexCube = new sglrReferenceContext.TextureContainer();
   1363        this.m_emptyTexCube.init(gl.TEXTURE_CUBE_MAP);
   1364        this.m_emptyTexCube.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1365        this.m_emptyTexCube.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1366        this.m_emptyTexCube.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
   1367        this.m_emptyTexCube.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
   1368 
   1369        for (var face in tcuTexture.CubeFace) {
   1370            this.m_emptyTexCube.texture.allocLevel(0, tcuTexture.CubeFace[face],
   1371                new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
   1372            this.m_emptyTexCube.texture.getFace(0, tcuTexture.CubeFace[face]).setPixel([0, 0, 0, 1], 0, 0);
   1373        }
   1374        this.m_emptyTexCube.texture.updateView();
   1375 
   1376        /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2DArray = new sglrReferenceContext.TextureContainer();
   1377        this.m_emptyTex2DArray.init(gl.TEXTURE_2D_ARRAY);
   1378        this.m_emptyTex2DArray.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1379        this.m_emptyTex2DArray.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1380        this.m_emptyTex2DArray.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1381        this.m_emptyTex2DArray.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
   1382        this.m_emptyTex2DArray.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
   1383        this.m_emptyTex2DArray.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
   1384        this.m_emptyTex2DArray.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
   1385        this.m_emptyTex2DArray.texture.updateView();
   1386 
   1387        /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex3D = new sglrReferenceContext.TextureContainer();
   1388        this.m_emptyTex3D.init(gl.TEXTURE_3D);
   1389        this.m_emptyTex3D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1390        this.m_emptyTex3D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1391        this.m_emptyTex3D.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   1392        this.m_emptyTex3D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
   1393        this.m_emptyTex3D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
   1394        this.m_emptyTex3D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
   1395        this.m_emptyTex3D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
   1396        this.m_emptyTex3D.texture.updateView();
   1397 
   1398        /** @type {sglrReferenceContext.TextureType} */ this.m_type;
   1399 
   1400        /** @type {boolean} */ this.m_immutable;
   1401 
   1402        /** @type {tcuTexture.Sampler} */ this.m_sampler;
   1403        /** @type {number} */ this.m_baseLevel;
   1404        /** @type {number} */ this.m_maxLevel;
   1405    };
   1406 
   1407    /**
   1408     * @return {number}
   1409     */
   1410    sglrReferenceContext.ReferenceContext.prototype.getWidth = function() { return this.m_defaultColorbuffer.raw().getHeight(); };
   1411 
   1412    /**
   1413    * @return {number}
   1414    */
   1415    sglrReferenceContext.ReferenceContext.prototype.getHeight = function() { return this.m_defaultColorbuffer.raw().getDepth(); };
   1416 
   1417    /**
   1418    * @param {number} x
   1419    * @param {number} y
   1420    * @param {number} width
   1421    * @param {number} height
   1422    */
   1423    sglrReferenceContext.ReferenceContext.prototype.viewport = function(x, y, width, height) { this.m_viewport = [x, y, width, height]; };
   1424 
   1425    /**
   1426    * @param {number} texture
   1427    */
   1428    sglrReferenceContext.ReferenceContext.prototype.activeTexture = function(texture) {
   1429        if (deMath.deInBounds32(texture, gl.TEXTURE0, gl.TEXTURE0 + this.m_textureUnits.length))
   1430            this.m_activeTexture = texture - gl.TEXTURE0;
   1431        else
   1432            this.setError(gl.INVALID_ENUM);
   1433    };
   1434 
   1435    /**
   1436    * @param {number} error
   1437    */
   1438    sglrReferenceContext.ReferenceContext.prototype.setError = function(error) {
   1439        if (this.m_lastError == gl.NO_ERROR)
   1440            this.m_lastError = error;
   1441    };
   1442 
   1443    /**
   1444    * @return {number} error
   1445    */
   1446    sglrReferenceContext.ReferenceContext.prototype.getError = function() {
   1447        /** @type {number} */ var err = this.m_lastError;
   1448        this.m_lastError = gl.NO_ERROR;
   1449        return err;
   1450    };
   1451 
   1452    /**
   1453     * @param {boolean} condition
   1454     * @param {number} error
   1455     */
   1456    sglrReferenceContext.ReferenceContext.prototype.conditionalSetError = function(condition, error) {
   1457        if (condition)
   1458            this.setError(error);
   1459        return condition;
   1460    };
   1461 
   1462    /**
   1463    * @param {number} target
   1464    * @param {sglrReferenceContext.TextureContainer} texture
   1465    * @throws {Error}
   1466    */
   1467    sglrReferenceContext.ReferenceContext.prototype.bindTexture = function(target, texture) {
   1468        /** @type {number} */ var unitNdx = this.m_activeTexture;
   1469 
   1470        if (this.conditionalSetError((target != gl.TEXTURE_2D &&
   1471                    target != gl.TEXTURE_CUBE_MAP &&
   1472                    target != gl.TEXTURE_2D_ARRAY &&
   1473                    target != gl.TEXTURE_3D), // &&
   1474                    // target != gl.TEXTURE_CUBE_MAP_ARRAY),
   1475                    gl.INVALID_ENUM))
   1476            return;
   1477 
   1478        if (!texture) {
   1479            // Clear binding.
   1480            switch (target) {
   1481                case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, null); break;
   1482                case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, null); break;
   1483                case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, null); break;
   1484                case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, null); break;
   1485                default:
   1486                    throw new Error('Unrecognized target: ' + target);
   1487            }
   1488        } else {
   1489            if (texture.textureType == null) {
   1490                texture.init(target);
   1491            } else {
   1492                // Validate type.
   1493                /** @type {sglrReferenceContext.TextureType} */ var expectedType;
   1494                switch (target) {
   1495                    case gl.TEXTURE_2D: expectedType = sglrReferenceContext.TextureType.TYPE_2D; break;
   1496                    case gl.TEXTURE_CUBE_MAP: expectedType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP; break;
   1497                    case gl.TEXTURE_2D_ARRAY: expectedType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY; break;
   1498                    case gl.TEXTURE_3D: expectedType = sglrReferenceContext.TextureType.TYPE_3D; break;
   1499                    default: throw new Error('Unrecognized target: ' + target);
   1500                }
   1501                if (this.conditionalSetError((texture.textureType != expectedType), gl.INVALID_OPERATION))
   1502                    return;
   1503            }
   1504            switch (target) {
   1505                case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, texture); break;
   1506                case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, texture); break;
   1507                case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, texture); break;
   1508                case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, texture); break;
   1509                default:
   1510                    throw new Error('Unrecognized target: ' + target);
   1511            }
   1512        }
   1513    };
   1514 
   1515    /**
   1516    * @param {number} unitNdx
   1517    * @param {?sglrReferenceContext.TextureContainer} texture
   1518    */
   1519    sglrReferenceContext.ReferenceContext.prototype.setTexCubeBinding = function(unitNdx, texture) {
   1520        if (this.m_textureUnits[unitNdx].texCubeBinding) {
   1521            this.m_textureUnits[unitNdx].texCubeBinding = null;
   1522        }
   1523 
   1524        if (texture) {
   1525            this.m_textureUnits[unitNdx].texCubeBinding = texture;
   1526        }
   1527    };
   1528 
   1529    /**
   1530    * @param {number} unitNdx
   1531    * @param {?sglrReferenceContext.TextureContainer} texture
   1532    */
   1533    sglrReferenceContext.ReferenceContext.prototype.setTex2DBinding = function(unitNdx, texture) {
   1534        if (this.m_textureUnits[unitNdx].tex2DBinding) {
   1535            // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DBinding);
   1536            this.m_textureUnits[unitNdx].tex2DBinding = null;
   1537        }
   1538 
   1539        if (texture) {
   1540            // this.m_textures.acquireReference(texture);
   1541            this.m_textureUnits[unitNdx].tex2DBinding = texture;
   1542        }
   1543    };
   1544 
   1545    /**
   1546    * @param {number} unitNdx
   1547    * @param {?sglrReferenceContext.TextureContainer} texture
   1548    */
   1549    sglrReferenceContext.ReferenceContext.prototype.setTex2DArrayBinding = function(unitNdx, texture) {
   1550        if (this.m_textureUnits[unitNdx].tex2DArrayBinding) {
   1551            // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DArrayBinding);
   1552            this.m_textureUnits[unitNdx].tex2DArrayBinding = null;
   1553        }
   1554 
   1555        if (texture) {
   1556            // this.m_textures.acquireReference(texture);
   1557            this.m_textureUnits[unitNdx].tex2DArrayBinding = texture;
   1558        }
   1559    };
   1560 
   1561    /**
   1562    * @param {number} unitNdx
   1563    * @param {?sglrReferenceContext.TextureContainer} texture
   1564    */
   1565    sglrReferenceContext.ReferenceContext.prototype.setTex3DBinding = function(unitNdx, texture) {
   1566        if (this.m_textureUnits[unitNdx].tex3DBinding) {
   1567            // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex3DBinding);
   1568            this.m_textureUnits[unitNdx].tex3DBinding = null;
   1569        }
   1570 
   1571        if (texture) {
   1572            // this.m_textures.acquireReference(texture);
   1573            this.m_textureUnits[unitNdx].tex3DBinding = texture;
   1574        }
   1575    };
   1576 
   1577    /**
   1578    * @return {sglrReferenceContext.TextureContainer}
   1579    */
   1580    sglrReferenceContext.ReferenceContext.prototype.createTexture = function() { return new sglrReferenceContext.TextureContainer(); };
   1581 
   1582    /**
   1583    * @param {sglrReferenceContext.Texture} texture
   1584    */
   1585    sglrReferenceContext.ReferenceContext.prototype.deleteTexture = function(texture) { /*empty*/ };
   1586 
   1587    /**
   1588    * @param {number} target
   1589    * @param {framework.opengl.simplereference.sglrReferenceContext.Framebuffer} fbo
   1590    */
   1591    sglrReferenceContext.ReferenceContext.prototype.bindFramebuffer = function(target, fbo) {
   1592        if (this.conditionalSetError((target != gl.FRAMEBUFFER &&
   1593                    target != gl.DRAW_FRAMEBUFFER &&
   1594                    target != gl.READ_FRAMEBUFFER), gl.INVALID_ENUM))
   1595                    return;
   1596        for (var ndx = 0; ndx < 2; ndx++) {
   1597            /** @type {number} */ var bindingTarget = ndx ? gl.DRAW_FRAMEBUFFER : gl.READ_FRAMEBUFFER;
   1598 
   1599            if (target != gl.FRAMEBUFFER && target != bindingTarget)
   1600                continue; // Doesn't match this target.
   1601 
   1602            if (ndx)
   1603                this.m_drawFramebufferBinding = fbo;
   1604            else
   1605                this.m_readFramebufferBinding = fbo;
   1606        }
   1607    };
   1608 
   1609    /**
   1610    * @return {sglrReferenceContext.Framebuffer}
   1611    */
   1612    sglrReferenceContext.ReferenceContext.prototype.createFramebuffer = function() { return new sglrReferenceContext.Framebuffer(); };
   1613 
   1614    /**
   1615    * @param {sglrReferenceContext.Framebuffer} fbo
   1616    */
   1617    sglrReferenceContext.ReferenceContext.prototype.deleteFramebuffer = function(fbo) { /*empty*/ };
   1618 
   1619    /**
   1620    * @param {number} target
   1621    * @param {sglrReferenceContext.Renderbuffer} rbo
   1622    */
   1623    sglrReferenceContext.ReferenceContext.prototype.bindRenderbuffer = function(target, rbo) {
   1624        if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM))
   1625            return;
   1626 
   1627        this.m_renderbufferBinding = rbo;
   1628    };
   1629 
   1630    /**
   1631    * @return {sglrReferenceContext.Renderbuffer}
   1632    */
   1633    sglrReferenceContext.ReferenceContext.prototype.createRenderbuffer = function() { return new sglrReferenceContext.Renderbuffer(); };
   1634 
   1635    /**
   1636    * @param {sglrReferenceContext.Renderbuffer} rbo
   1637    */
   1638    sglrReferenceContext.ReferenceContext.prototype.deleteRenderbuffer = function(rbo) { /*empty*/ };
   1639 
   1640    /**
   1641    * @param {number} pname
   1642    * @param {number} param
   1643    */
   1644    sglrReferenceContext.ReferenceContext.prototype.pixelStorei = function(pname, param) {
   1645        switch (pname) {
   1646            case gl.UNPACK_ALIGNMENT:
   1647                if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return;
   1648                this.m_pixelUnpackAlignment = param;
   1649                break;
   1650 
   1651            case gl.PACK_ALIGNMENT:
   1652                if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return;
   1653                this.m_pixelPackAlignment = param;
   1654                break;
   1655 
   1656            case gl.UNPACK_ROW_LENGTH:
   1657                if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
   1658                this.m_pixelUnpackRowLength = param;
   1659                break;
   1660 
   1661            case gl.UNPACK_SKIP_ROWS:
   1662                if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
   1663                this.m_pixelUnpackSkipRows = param;
   1664                break;
   1665 
   1666            case gl.UNPACK_SKIP_PIXELS:
   1667                if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
   1668                this.m_pixelUnpackSkipPixels = param;
   1669                break;
   1670 
   1671            case gl.UNPACK_IMAGE_HEIGHT:
   1672                if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
   1673                this.m_pixelUnpackImageHeight = param;
   1674                break;
   1675 
   1676            case gl.UNPACK_SKIP_IMAGES:
   1677                if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
   1678                this.m_pixelUnpackSkipImages = param;
   1679                break;
   1680 
   1681            default:
   1682                this.setError(gl.INVALID_ENUM);
   1683        }
   1684    };
   1685 
   1686    /**
   1687    * @param {number} red
   1688    * @param {number} green
   1689    * @param {number} blue
   1690    * @param {number} alpha
   1691    */
   1692    sglrReferenceContext.ReferenceContext.prototype.clearColor = function(red, green, blue, alpha) {
   1693        this.m_clearColor = [deMath.clamp(red, 0, 1),
   1694                            deMath.clamp(green, 0, 1),
   1695                            deMath.clamp(blue, 0, 1),
   1696                            deMath.clamp(alpha, 0, 1)];
   1697    };
   1698 
   1699    /**
   1700    * @param {number} depth
   1701    */
   1702    sglrReferenceContext.ReferenceContext.prototype.clearDepthf = function(depth) {
   1703        this.m_clearDepth = deMath.clamp(depth, 0, 1);
   1704    };
   1705 
   1706    /**
   1707    * @param {number} stencil
   1708    */
   1709    sglrReferenceContext.ReferenceContext.prototype.clearStencil = function(stencil) {
   1710        this.m_clearStencil = stencil;
   1711    };
   1712 
   1713    /**
   1714    * @param {number} x
   1715    * @param {number} y
   1716    * @param {number} width
   1717    * @param {number} height
   1718    */
   1719    sglrReferenceContext.ReferenceContext.prototype.scissor = function(x, y, width, height) {
   1720        if (this.conditionalSetError(width < 0 || height < 0, gl.INVALID_VALUE))
   1721            return;
   1722        this.m_scissorBox = [x, y, width, height];
   1723    };
   1724 
   1725    /**
   1726    * @param {number} cap
   1727    */
   1728    sglrReferenceContext.ReferenceContext.prototype.enable = function(cap) {
   1729        switch (cap) {
   1730            case gl.BLEND: this.m_blendEnabled = true; break;
   1731            case gl.SCISSOR_TEST: this.m_scissorEnabled = true; break;
   1732            case gl.DEPTH_TEST: this.m_depthTestEnabled = true; break;
   1733            case gl.STENCIL_TEST: this.m_stencilTestEnabled = true; break;
   1734            case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = true; break;
   1735 
   1736            case gl.DITHER:
   1737                // Not implemented - just ignored.
   1738                break;
   1739 
   1740            default:
   1741                this.setError(gl.INVALID_ENUM);
   1742                break;
   1743        }
   1744    };
   1745 
   1746    /**
   1747    * @param {number} cap
   1748    */
   1749    sglrReferenceContext.ReferenceContext.prototype.disable = function(cap) {
   1750        switch (cap) {
   1751            case gl.BLEND: this.m_blendEnabled = false; break;
   1752            case gl.SCISSOR_TEST: this.m_scissorEnabled = false; break;
   1753            case gl.DEPTH_TEST: this.m_depthTestEnabled = false; break;
   1754            case gl.STENCIL_TEST: this.m_stencilTestEnabled = false; break;
   1755            case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = false; break;
   1756 
   1757            case gl.DITHER:
   1758                // Not implemented - just ignored.
   1759                break;
   1760 
   1761            default:
   1762                this.setError(gl.INVALID_ENUM);
   1763                break;
   1764        }
   1765    };
   1766 
   1767    /**
   1768    * @param {number} func
   1769    * @param {number} ref
   1770    * @param {number} mask
   1771    */
   1772    sglrReferenceContext.ReferenceContext.prototype.stencilFunc = function(func, ref, mask) {
   1773        this.stencilFuncSeparate(gl.FRONT_AND_BACK, func, ref, mask);
   1774    };
   1775 
   1776    /**
   1777    * @param {number} face
   1778    * @param {number} func
   1779    * @param {number} ref
   1780    * @param {number} mask
   1781    */
   1782    sglrReferenceContext.ReferenceContext.prototype.stencilFuncSeparate = function(face, func, ref, mask) {
   1783        /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
   1784        /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
   1785 
   1786        if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM))
   1787            return;
   1788        if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
   1789            return;
   1790 
   1791        for (var key in rrDefs.FaceType) {
   1792            /** @type {number} */ var type = rrDefs.FaceType[key];
   1793            if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) ||
   1794                (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) {
   1795                this.m_stencil[type].func = func;
   1796                this.m_stencil[type].ref = ref;
   1797                this.m_stencil[type].opMask = mask;
   1798            }
   1799        }
   1800    };
   1801 
   1802    /**
   1803    * @param {number} func
   1804    * @return {boolean}
   1805    */
   1806    sglrReferenceContext.isValidCompareFunc = function(func) {
   1807        switch (func) {
   1808            case gl.NEVER:
   1809            case gl.LESS:
   1810            case gl.LEQUAL:
   1811            case gl.GREATER:
   1812            case gl.GEQUAL:
   1813            case gl.EQUAL:
   1814            case gl.NOTEQUAL:
   1815            case gl.ALWAYS:
   1816                return true;
   1817 
   1818            default:
   1819                return false;
   1820        }
   1821    };
   1822 
   1823    /**
   1824    * @param {number} op
   1825    * @return {boolean}
   1826    */
   1827    sglrReferenceContext.isValidStencilOp = function(op) {
   1828        switch (op) {
   1829            case gl.KEEP:
   1830            case gl.ZERO:
   1831            case gl.REPLACE:
   1832            case gl.INCR:
   1833            case gl.INCR_WRAP:
   1834            case gl.DECR:
   1835            case gl.DECR_WRAP:
   1836            case gl.INVERT:
   1837                return true;
   1838 
   1839            default:
   1840                return false;
   1841        }
   1842    };
   1843 
   1844    /**
   1845    * @param {number} sfail
   1846    * @param {number} dpfail
   1847    * @param {number} dppass
   1848    */
   1849    sglrReferenceContext.ReferenceContext.prototype.stencilOp = function(sfail, dpfail, dppass) {
   1850        this.stencilOpSeparate(gl.FRONT_AND_BACK, sfail, dpfail, dppass);
   1851    };
   1852 
   1853    /**
   1854    * @param {number} face
   1855    * @param {number} sfail
   1856    * @param {number} dpfail
   1857    * @param {number} dppass
   1858    */
   1859    sglrReferenceContext.ReferenceContext.prototype.stencilOpSeparate = function(face, sfail, dpfail, dppass) {
   1860        /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
   1861        /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
   1862 
   1863        if (this.conditionalSetError((!sglrReferenceContext.isValidStencilOp(sfail) ||
   1864                    !sglrReferenceContext.isValidStencilOp(dpfail) ||
   1865                    !sglrReferenceContext.isValidStencilOp(dppass)),
   1866                    gl.INVALID_ENUM))
   1867            return;
   1868 
   1869        if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
   1870            return;
   1871 
   1872    for (var key in rrDefs.FaceType) {
   1873            /** @type {number} */ var type = rrDefs.FaceType[key];
   1874            if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) ||
   1875                (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) {
   1876                this.m_stencil[type].opStencilFail = sfail;
   1877                this.m_stencil[type].opDepthFail = dpfail;
   1878                this.m_stencil[type].opDepthPass = dppass;
   1879            }
   1880        }
   1881    };
   1882 
   1883    /**
   1884    * @param {number} func
   1885    */
   1886    sglrReferenceContext.ReferenceContext.prototype.depthFunc = function(func) {
   1887        if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM))
   1888            return;
   1889        this.m_depthFunc = func;
   1890    };
   1891 
   1892    /**
   1893    * @param {number} n
   1894    * @param {number} f
   1895    */
   1896    sglrReferenceContext.ReferenceContext.prototype.depthRange = function(n, f) {
   1897        this.m_depthRangeNear = deMath.clamp(n, 0, 1);
   1898        this.m_depthRangeFar = deMath.clamp(f, 0, 1);
   1899    };
   1900 
   1901    /**
   1902    * @param {number} factor
   1903    * @param {number} units
   1904    */
   1905    sglrReferenceContext.ReferenceContext.prototype.polygonOffset = function(factor, units) {
   1906        this.m_polygonOffsetFactor = factor;
   1907        this.m_polygonOffsetUnits = units;
   1908    };
   1909 
   1910    /**
   1911    * @param {number} mode
   1912    * @return {boolean}
   1913    */
   1914    sglrReferenceContext.isValidBlendEquation = function(mode) {
   1915        return mode == gl.FUNC_ADD ||
   1916            mode == gl.FUNC_SUBTRACT ||
   1917            mode == gl.FUNC_REVERSE_SUBTRACT ||
   1918            mode == gl.MIN ||
   1919            mode == gl.MAX;
   1920    };
   1921 
   1922    /**
   1923    * @param {number} factor
   1924    * @return {boolean}
   1925    */
   1926    sglrReferenceContext.isValidBlendFactor = function(factor) {
   1927        switch (factor) {
   1928            case gl.ZERO:
   1929            case gl.ONE:
   1930            case gl.SRC_COLOR:
   1931            case gl.ONE_MINUS_SRC_COLOR:
   1932            case gl.DST_COLOR:
   1933            case gl.ONE_MINUS_DST_COLOR:
   1934            case gl.SRC_ALPHA:
   1935            case gl.ONE_MINUS_SRC_ALPHA:
   1936            case gl.DST_ALPHA:
   1937            case gl.ONE_MINUS_DST_ALPHA:
   1938            case gl.CONSTANT_COLOR:
   1939            case gl.ONE_MINUS_CONSTANT_COLOR:
   1940            case gl.CONSTANT_ALPHA:
   1941            case gl.ONE_MINUS_CONSTANT_ALPHA:
   1942            case gl.SRC_ALPHA_SATURATE:
   1943                return true;
   1944 
   1945            default:
   1946                return false;
   1947        }
   1948    };
   1949 
   1950    /**
   1951    * @param {number} mode
   1952    */
   1953    sglrReferenceContext.ReferenceContext.prototype.blendEquation = function(mode) {
   1954        if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(mode), gl.INVALID_ENUM))
   1955            return;
   1956        this.m_blendModeRGB = mode;
   1957        this.m_blendModeAlpha = mode;
   1958    };
   1959 
   1960    /**
   1961    * @param {number} modeRGB
   1962    * @param {number} modeAlpha
   1963    */
   1964    sglrReferenceContext.ReferenceContext.prototype.blendEquationSeparate = function(modeRGB, modeAlpha) {
   1965        if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(modeRGB) ||
   1966                    !sglrReferenceContext.isValidBlendEquation(modeAlpha),
   1967                    gl.INVALID_ENUM))
   1968            return;
   1969 
   1970        this.m_blendModeRGB = modeRGB;
   1971        this.m_blendModeAlpha = modeAlpha;
   1972    };
   1973 
   1974    /**
   1975    * @param {number} src
   1976    * @param {number} dst
   1977    */
   1978    sglrReferenceContext.ReferenceContext.prototype.blendFunc = function(src, dst) {
   1979        if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(src) ||
   1980                    !sglrReferenceContext.isValidBlendFactor(dst),
   1981                    gl.INVALID_ENUM))
   1982            return;
   1983 
   1984        this.m_blendFactorSrcRGB = src;
   1985        this.m_blendFactorSrcAlpha = src;
   1986        this.m_blendFactorDstRGB = dst;
   1987        this.m_blendFactorDstAlpha = dst;
   1988    };
   1989 
   1990    /**
   1991    * @param {number} srcRGB
   1992    * @param {number} dstRGB
   1993    * @param {number} srcAlpha
   1994    * @param {number} dstAlpha
   1995    */
   1996    sglrReferenceContext.ReferenceContext.prototype.blendFuncSeparate = function(srcRGB, dstRGB, srcAlpha, dstAlpha) {
   1997        if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(srcRGB) ||
   1998                    !sglrReferenceContext.isValidBlendFactor(dstRGB) ||
   1999                    !sglrReferenceContext.isValidBlendFactor(srcAlpha) ||
   2000                    !sglrReferenceContext.isValidBlendFactor(dstAlpha),
   2001                    gl.INVALID_ENUM))
   2002            return;
   2003 
   2004        this.m_blendFactorSrcRGB = srcRGB;
   2005        this.m_blendFactorSrcAlpha = srcAlpha;
   2006        this.m_blendFactorDstRGB = dstRGB;
   2007        this.m_blendFactorDstAlpha = dstAlpha;
   2008    };
   2009 
   2010    /**
   2011    * @param {number} red
   2012    * @param {number} green
   2013    * @param {number} blue
   2014    * @param {number} alpha
   2015    */
   2016    sglrReferenceContext.ReferenceContext.prototype.blendColor = function(red, green, blue, alpha) {
   2017        this.m_blendColor = [deMath.clamp(red, 0, 1),
   2018                            deMath.clamp(green, 0, 1),
   2019                            deMath.clamp(blue, 0, 1),
   2020                            deMath.clamp(alpha, 0, 1)];
   2021    };
   2022 
   2023    /**
   2024    * @param {boolean} r
   2025    * @param {boolean} g
   2026    * @param {boolean} b
   2027    * @param {boolean} a
   2028    */
   2029    sglrReferenceContext.ReferenceContext.prototype.colorMask = function(r, g, b, a) {
   2030        this.m_colorMask = [r, g, b, a];
   2031    };
   2032 
   2033    /**
   2034    * @param {boolean} mask
   2035    */
   2036    sglrReferenceContext.ReferenceContext.prototype.depthMask = function(mask) {
   2037        this.m_depthMask = mask;
   2038    };
   2039 
   2040    /**
   2041    * @param {number} mask
   2042    */
   2043    sglrReferenceContext.ReferenceContext.prototype.stencilMask = function(mask) {
   2044        this.stencilMaskSeparate(gl.FRONT_AND_BACK, mask);
   2045    };
   2046 
   2047    /**
   2048    * @param {number} face
   2049    * @param {number} mask
   2050    */
   2051    sglrReferenceContext.ReferenceContext.prototype.stencilMaskSeparate = function(face, mask) {
   2052        /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
   2053        /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
   2054 
   2055        if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
   2056            return;
   2057 
   2058        if (setFront) this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask = mask;
   2059        if (setBack) this.m_stencil[rrDefs.FaceType.FACETYPE_BACK].writeMask = mask;
   2060    };
   2061 
   2062    /**
   2063    * @param {sglrReferenceContext.VertexArray} array
   2064    */
   2065    sglrReferenceContext.ReferenceContext.prototype.bindVertexArray = function(array) {
   2066        if (array)
   2067            this.m_vertexArrayBinding = array;
   2068        else
   2069            this.m_vertexArrayBinding = this.m_defaultVAO;
   2070    };
   2071 
   2072    /**
   2073    * @return {sglrReferenceContext.VertexArray}
   2074    */
   2075    sglrReferenceContext.ReferenceContext.prototype.createVertexArray = function() { return new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs); };
   2076 
   2077    /**
   2078    * @param {number} array
   2079    */
   2080    sglrReferenceContext.ReferenceContext.prototype.deleteVertexArray = function(array) {};
   2081 
   2082    /**
   2083    * @param {number} index
   2084    * @param {number} rawSize
   2085    * @param {number} type
   2086    * @param {boolean} normalized
   2087    * @param {number} stride
   2088    * @param {number} offset
   2089    */
   2090    sglrReferenceContext.ReferenceContext.prototype.vertexAttribPointer = function(index, rawSize, type, normalized, stride, offset) {
   2091        /** @type {boolean} */ var allowBGRA = false;
   2092        /** @type {number} */ var effectiveSize = rawSize;
   2093 
   2094        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2095            return;
   2096        if (this.conditionalSetError(effectiveSize <= 0 || effectiveSize > 4, gl.INVALID_VALUE))
   2097            return;
   2098        if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE &&
   2099                    type != gl.SHORT && type != gl.UNSIGNED_SHORT &&
   2100                    type != gl.INT && type != gl.UNSIGNED_INT &&
   2101                    type != gl.FLOAT && type != gl.HALF_FLOAT &&
   2102                    type != gl.INT_2_10_10_10_REV && type != gl.UNSIGNED_INT_2_10_10_10_REV, gl.INVALID_ENUM))
   2103            return;
   2104        if (this.conditionalSetError(normalized != true && normalized != false, gl.INVALID_ENUM))
   2105            return;
   2106        if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE))
   2107            return;
   2108        if (this.conditionalSetError((type == gl.INT_2_10_10_10_REV || type == gl.UNSIGNED_INT_2_10_10_10_REV) && effectiveSize != 4, gl.INVALID_OPERATION))
   2109            return;
   2110        if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION))
   2111            return;
   2112 
   2113        /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type
   2114 
   2115        array_.size = rawSize;
   2116        array_.stride = stride;
   2117        array_.type = type;
   2118        array_.normalized = normalized;
   2119        array_.integer = false;
   2120        array_.offset = offset;
   2121 
   2122        array_.bufferBinding = this.m_arrayBufferBinding;
   2123    };
   2124 
   2125    /**
   2126    * @param {number} index
   2127    * @param {number} size
   2128    * @param {number} type
   2129    * @param {number} stride
   2130    * @param {number} offset
   2131    */
   2132    sglrReferenceContext.ReferenceContext.prototype.vertexAttribIPointer = function(index, size, type, stride, offset) {
   2133        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2134            return;
   2135        if (this.conditionalSetError(size <= 0 || size > 4, gl.INVALID_VALUE))
   2136            return;
   2137        if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE &&
   2138                    type != gl.SHORT && type != gl.UNSIGNED_SHORT &&
   2139                    type != gl.INT && type != gl.UNSIGNED_INT, gl.INVALID_ENUM))
   2140            return;
   2141        if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE))
   2142            return;
   2143        if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION))
   2144            return;
   2145 
   2146        /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type
   2147 
   2148        array_.size = size;
   2149        array_.stride = stride;
   2150        array_.type = type;
   2151        array_.normalized = false;
   2152        array_.integer = true;
   2153        array_.offset = offset;
   2154 
   2155        array_.bufferBinding = this.m_arrayBufferBinding;
   2156    };
   2157 
   2158    /**
   2159    * @param {number} index
   2160    */
   2161    sglrReferenceContext.ReferenceContext.prototype.enableVertexAttribArray = function(index) {
   2162        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2163            return;
   2164 
   2165        this.m_vertexArrayBinding.m_arrays[index].enabled = true;
   2166    };
   2167 
   2168    /**
   2169    * @param {number} index
   2170    */
   2171    sglrReferenceContext.ReferenceContext.prototype.disableVertexAttribArray = function(index) {
   2172        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2173            return;
   2174 
   2175        this.m_vertexArrayBinding.m_arrays[index].enabled = false;
   2176    };
   2177 
   2178    /**
   2179    * @param {number} index
   2180    * @param {number} divisor
   2181    */
   2182    sglrReferenceContext.ReferenceContext.prototype.vertexAttribDivisor = function(index, divisor) {
   2183        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2184            return;
   2185 
   2186        this.m_vertexArrayBinding.m_arrays[index].divisor = divisor;
   2187    };
   2188 
   2189    /**
   2190    * @param {number} index
   2191    * @param {number} x
   2192    */
   2193    sglrReferenceContext.ReferenceContext.prototype.vertexAttrib1f = function(index, x) {
   2194        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2195            return;
   2196 
   2197        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, 0, 0, 1);
   2198    };
   2199 
   2200    /**
   2201    * @param {number} index
   2202    * @param {number} x
   2203    * @param {number} y
   2204    */
   2205    sglrReferenceContext.ReferenceContext.prototype.vertexAttrib2f = function(index, x, y) {
   2206        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2207            return;
   2208 
   2209        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, 0, 1);
   2210    };
   2211 
   2212    /**
   2213    * @param {number} index
   2214    * @param {number} x
   2215    * @param {number} y
   2216    * @param {number} z
   2217    */
   2218    sglrReferenceContext.ReferenceContext.prototype.vertexAttrib3f = function(index, x, y, z) {
   2219        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2220            return;
   2221 
   2222        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, 1);
   2223    };
   2224 
   2225    /**
   2226    * @param {number} index
   2227    * @param {number} x
   2228    * @param {number} y
   2229    * @param {number} z
   2230    * @param {number} w
   2231    */
   2232    sglrReferenceContext.ReferenceContext.prototype.vertexAttrib4f = function(index, x, y, z, w) {
   2233        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2234            return;
   2235 
   2236        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
   2237    };
   2238 
   2239    /**
   2240    * @param {number} index
   2241    * @param {number} x
   2242    * @param {number} y
   2243    * @param {number} z
   2244    * @param {number} w
   2245    */
   2246    sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4i = function(index, x, y, z, w) {
   2247        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2248            return;
   2249 
   2250        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
   2251    };
   2252 
   2253    /**
   2254    * @param {number} index
   2255    * @param {number} x
   2256    * @param {number} y
   2257    * @param {number} z
   2258    * @param {number} w
   2259    */
   2260    sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4ui = function(index, x, y, z, w) {
   2261        if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
   2262            return;
   2263 
   2264        this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
   2265    };
   2266 
   2267    /**
   2268    * @param {sglrShaderProgram.ShaderProgram} program
   2269    * @param {string} name
   2270    * @return {number}
   2271    */
   2272    sglrReferenceContext.ReferenceContext.prototype.getAttribLocation = function(program, name) {
   2273        if (this.conditionalSetError(!(program), gl.INVALID_OPERATION))
   2274            return -1;
   2275 
   2276        for (var i = 0; i < program.m_attributeNames.length; i++)
   2277            if (program.m_attributeNames[i] === name)
   2278                return i;
   2279 
   2280        return -1;
   2281    };
   2282 
   2283   /**
   2284    * @param {number} pname
   2285    */
   2286    sglrReferenceContext.ReferenceContext.prototype.getParameter = function(pname) {
   2287        switch (pname) {
   2288            case (gl.VIEWPORT): return new Int32Array(this.m_viewport);
   2289            case (gl.SCISSOR_BOX): return new Int32Array(this.m_scissorBox);
   2290            default:
   2291                throw new Error('Unimplemented');
   2292        }
   2293    };
   2294 
   2295    /**
   2296    * @param {number} location
   2297    * @param {gluShaderUtil.DataType} type
   2298    * @param {Array<number>} value
   2299    */
   2300    sglrReferenceContext.ReferenceContext.prototype.uniformValue = function(location, type, value) {
   2301        if (this.conditionalSetError(!this.m_currentProgram, gl.INVALID_OPERATION))
   2302            return;
   2303 
   2304        if (location === null)
   2305            return;
   2306 
   2307        /** @type {sglrShaderProgram.Uniform} */ var uniform = this.m_currentProgram.m_uniforms[location];
   2308 
   2309        if (this.conditionalSetError(!uniform, gl.INVALID_OPERATION))
   2310            return;
   2311 
   2312        if (gluShaderUtil.isDataTypeSampler(uniform.type)) {
   2313            if (this.conditionalSetError(type != gluShaderUtil.DataType.INT, gl.INVALID_OPERATION))
   2314                return;
   2315        } else if (this.conditionalSetError(uniform.type != type, gl.INVALID_OPERATION))
   2316            return;
   2317        /* TODO: Do we need to copy objects? */
   2318        uniform.value = value;
   2319    };
   2320 
   2321    /**
   2322     * @param {number} location
   2323     * @param {number} x
   2324     */
   2325    sglrReferenceContext.ReferenceContext.prototype.uniform1f = function(location, x) {
   2326        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, [x]);
   2327    };
   2328 
   2329    /**
   2330     * @param {number} location
   2331     * @param {Array<number>} x
   2332     */
   2333    sglrReferenceContext.ReferenceContext.prototype.uniform1fv = function(location, x) {
   2334        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, x);
   2335    };
   2336 
   2337    /**
   2338     * @param {number} location
   2339     * @param {number} x
   2340     */
   2341    sglrReferenceContext.ReferenceContext.prototype.uniform1i = function(location, x) {
   2342        return this.uniformValue(location, gluShaderUtil.DataType.INT, [x]);
   2343    };
   2344 
   2345    /**
   2346     * @param {number} location
   2347     * @param {Array<number>} x
   2348     */
   2349    sglrReferenceContext.ReferenceContext.prototype.uniform1iv = function(location, x) {
   2350        return this.uniformValue(location, gluShaderUtil.DataType.INT, x);
   2351    };
   2352 
   2353    /**
   2354     * @param {number} location
   2355     * @param {number} x
   2356     * @param {number} y
   2357     */
   2358    sglrReferenceContext.ReferenceContext.prototype.uniform2f = function(location, x, y) {
   2359        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, [x, y]);
   2360    };
   2361 
   2362    /**
   2363     * @param {number} location
   2364     * @param {Array<number>} x
   2365     */
   2366    sglrReferenceContext.ReferenceContext.prototype.uniform2fv = function(location, x) {
   2367        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, x);
   2368    };
   2369 
   2370    /**
   2371     * @param {number} location
   2372     * @param {number} x
   2373     * @param {number} y
   2374     */
   2375    sglrReferenceContext.ReferenceContext.prototype.uniform2i = function(location, x, y) {
   2376        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, [x, y]);
   2377    };
   2378 
   2379    /**
   2380     * @param {number} location
   2381     * @param {Array<number>} x
   2382     */
   2383    sglrReferenceContext.ReferenceContext.prototype.uniform2iv = function(location, x) {
   2384        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, x);
   2385    };
   2386 
   2387    /**
   2388     * @param {number} location
   2389     * @param {number} x
   2390     * @param {number} y
   2391     * @param {number} z
   2392     */
   2393    sglrReferenceContext.ReferenceContext.prototype.uniform3f = function(location, x, y, z) {
   2394        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, [x, y, z]);
   2395    };
   2396 
   2397    /**
   2398     * @param {number} location
   2399     * @param {Array<number>} x
   2400     */
   2401    sglrReferenceContext.ReferenceContext.prototype.uniform3fv = function(location, x) {
   2402        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, x);
   2403    };
   2404 
   2405    /**
   2406     * @param {number} location
   2407     * @param {number} x
   2408     * @param {number} y
   2409     * @param {number} z
   2410     */
   2411    sglrReferenceContext.ReferenceContext.prototype.uniform3i = function(location, x, y, z) {
   2412        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, [x, y, z]);
   2413    };
   2414 
   2415    /**
   2416     * @param {number} location
   2417     * @param {Array<number>} x
   2418     */
   2419    sglrReferenceContext.ReferenceContext.prototype.uniform3iv = function(location, x) {
   2420        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, x);
   2421    };
   2422 
   2423    /**
   2424     * @param {number} location
   2425     * @param {number} x
   2426     * @param {number} y
   2427     * @param {number} z
   2428     * @param {number} w
   2429     */
   2430    sglrReferenceContext.ReferenceContext.prototype.uniform4f = function(location, x, y, z, w) {
   2431        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, [x, y, z, w]);
   2432    };
   2433 
   2434    /**
   2435     * @param {number} location
   2436     * @param {Array<number>} x
   2437     */
   2438    sglrReferenceContext.ReferenceContext.prototype.uniform4fv = function(location, x) {
   2439        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, x);
   2440    };
   2441 
   2442    /**
   2443     * @param {number} location
   2444     * @param {number} x
   2445     * @param {number} y
   2446     * @param {number} z
   2447     * @param {number} w
   2448     */
   2449    sglrReferenceContext.ReferenceContext.prototype.uniform4i = function(location, x, y, z, w) {
   2450        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, [x, y, z, w]);
   2451    };
   2452 
   2453    /**
   2454     * @param {number} location
   2455     * @param {Array<number>} x
   2456     */
   2457    sglrReferenceContext.ReferenceContext.prototype.uniform4iv = function(location, x) {
   2458        return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, x);
   2459    };
   2460 
   2461    /**
   2462     * @return {Array<string>}
   2463     */
   2464    sglrReferenceContext.ReferenceContext.prototype.getSupportedExtensions = function() {
   2465        var extensions = gl.getSupportedExtensions(); //TODO: Let's just return gl's supported extensions for now
   2466        return extensions;
   2467    };
   2468 
   2469    /**
   2470     * @param {string} name
   2471     * @return {*}
   2472     */
   2473    sglrReferenceContext.ReferenceContext.prototype.getExtension = function(name) {
   2474        return gl.getExtension(name); //TODO: Let's just return gl's supported extensions for now
   2475    };
   2476 
   2477    /** transpose matrix 'x' of 'size' columns and rows
   2478     * @param {number} size
   2479     * @param {Array<number>} x
   2480     * @return {Array<number>}
   2481     */
   2482    sglrReferenceContext.trans = function(size, x) {
   2483        /** @type {Array<number>} */ var result = [];
   2484        for (var row = 0; row < size; ++row)
   2485            for (var col = 0; col < size; ++col)
   2486            result[row * size + col] = x[col * size + row];
   2487 
   2488        return result;
   2489    };
   2490 
   2491    /**
   2492     * @param {number} location
   2493     * @param {Array<number>} x
   2494     */
   2495    sglrReferenceContext.ReferenceContext.prototype.uniformMatrix2fv = function(location, transpose, x) {
   2496        /* change from column-major to internal row-major if transpose if FALSE */
   2497        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT2, !transpose ? sglrReferenceContext.trans(2, x) : x);
   2498    };
   2499 
   2500    /**
   2501     * @param {number} location
   2502     * @param {Array<number>} x
   2503     */
   2504    sglrReferenceContext.ReferenceContext.prototype.uniformMatrix3fv = function(location, transpose, x) {
   2505        /* change from column-major to internal row-major if transpose if FALSE */
   2506        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT3, !transpose ? sglrReferenceContext.trans(3, x) : x);
   2507    };
   2508 
   2509    /**
   2510     * @param {number} location
   2511     * @param {Array<number>} x
   2512     */
   2513    sglrReferenceContext.ReferenceContext.prototype.uniformMatrix4fv = function(location, transpose, x) {
   2514        /* change from column-major to internal row-major if transpose if FALSE */
   2515        return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT4, !transpose ? sglrReferenceContext.trans(4, x) : x);
   2516    };
   2517 
   2518    /**
   2519    * @param {sglrShaderProgram.ShaderProgram} program
   2520    * @param {string} name
   2521    * @return {number}
   2522    */
   2523    sglrReferenceContext.ReferenceContext.prototype.getUniformLocation = function(program, name) {
   2524        if (this.conditionalSetError(!program, gl.INVALID_OPERATION))
   2525            return -1;
   2526 
   2527        for (var i = 0; i < program.m_uniforms.length; i++)
   2528            if (program.m_uniforms[i].name === name)
   2529                return i;
   2530 
   2531        return -1;
   2532    };
   2533 
   2534    /**
   2535    * @param {number} w
   2536    */
   2537    sglrReferenceContext.ReferenceContext.prototype.lineWidth = function(w) {
   2538        if (this.conditionalSetError(w < 0, gl.INVALID_VALUE))
   2539            return;
   2540        this.m_lineWidth = w;
   2541    };
   2542 
   2543    /**
   2544    * @param {number} target
   2545    * @return {boolean}
   2546    */
   2547    sglrReferenceContext.isValidBufferTarget = function(target) {
   2548        switch (target) {
   2549            case gl.ARRAY_BUFFER:
   2550            case gl.COPY_READ_BUFFER:
   2551            case gl.COPY_WRITE_BUFFER:
   2552            case gl.ELEMENT_ARRAY_BUFFER:
   2553            case gl.PIXEL_PACK_BUFFER:
   2554            case gl.PIXEL_UNPACK_BUFFER:
   2555            case gl.TRANSFORM_FEEDBACK_BUFFER:
   2556            case gl.UNIFORM_BUFFER:
   2557                return true;
   2558 
   2559            default:
   2560                return false;
   2561        }
   2562    };
   2563 
   2564    /**
   2565    * @param {number} target
   2566    * @param {sglrReferenceContext.DataBuffer} buffer
   2567    * @throws {Error}
   2568    */
   2569    sglrReferenceContext.ReferenceContext.prototype.setBufferBinding = function(target, buffer) {
   2570        switch (target) {
   2571            case gl.ARRAY_BUFFER: this.m_arrayBufferBinding = buffer; break;
   2572            case gl.COPY_READ_BUFFER: this.m_copyReadBufferBinding = buffer; break;
   2573            case gl.COPY_WRITE_BUFFER: this.m_copyWriteBufferBinding = buffer; break;
   2574            case gl.ELEMENT_ARRAY_BUFFER: this.m_vertexArrayBinding.m_elementArrayBufferBinding = buffer; break;
   2575            case gl.PIXEL_PACK_BUFFER: this.m_pixelPackBufferBinding = buffer; break;
   2576            case gl.PIXEL_UNPACK_BUFFER: this.m_pixelUnpackBufferBinding = buffer; break;
   2577            case gl.TRANSFORM_FEEDBACK_BUFFER: this.m_transformFeedbackBufferBinding = buffer; break;
   2578            case gl.UNIFORM_BUFFER: this.m_uniformBufferBinding = buffer; break;
   2579            default:
   2580                throw new Error('Unrecognized target: ' + target);
   2581        }
   2582    };
   2583 
   2584    /**
   2585    * @param {number} target
   2586    * @return {sglrReferenceContext.DataBuffer}
   2587    * @throws {Error}
   2588    */
   2589    sglrReferenceContext.ReferenceContext.prototype.getBufferBinding = function(target) {
   2590        switch (target) {
   2591            case gl.ARRAY_BUFFER: return this.m_arrayBufferBinding;
   2592            case gl.COPY_READ_BUFFER: return this.m_copyReadBufferBinding;
   2593            case gl.COPY_WRITE_BUFFER: return this.m_copyWriteBufferBinding;
   2594            case gl.ELEMENT_ARRAY_BUFFER: return this.m_vertexArrayBinding.m_elementArrayBufferBinding;
   2595            case gl.PIXEL_PACK_BUFFER: return this.m_pixelPackBufferBinding;
   2596            case gl.PIXEL_UNPACK_BUFFER: return this.m_pixelUnpackBufferBinding;
   2597            case gl.TRANSFORM_FEEDBACK_BUFFER: return this.m_transformFeedbackBufferBinding;
   2598            case gl.UNIFORM_BUFFER: return this.m_uniformBufferBinding;
   2599            default:
   2600                throw new Error('Unrecognized target: ' + target);
   2601        }
   2602    };
   2603 
   2604    /**
   2605    * @param {number} target
   2606    * @param {sglrReferenceContext.DataBuffer} buffer
   2607    */
   2608    sglrReferenceContext.ReferenceContext.prototype.bindBuffer = function(target, buffer) {
   2609        if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
   2610            return;
   2611 
   2612        this.setBufferBinding(target, buffer);
   2613    };
   2614 
   2615    /**
   2616    * @return {sglrReferenceContext.DataBuffer}
   2617    */
   2618    sglrReferenceContext.ReferenceContext.prototype.createBuffer = function() { return new sglrReferenceContext.DataBuffer(); };
   2619 
   2620    /**
   2621    * @param {number} buffer
   2622    */
   2623    sglrReferenceContext.ReferenceContext.prototype.deleteBuffer = function(buffer) {};
   2624 
   2625    /**
   2626    * @param {number} target
   2627    * @param {number|goog.NumberArray} input
   2628    * @param {number} usage
   2629    */
   2630    sglrReferenceContext.ReferenceContext.prototype.bufferData = function(target, input, usage) {
   2631        if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
   2632            return;
   2633        /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target);
   2634        if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION))
   2635            return;
   2636 
   2637        if (typeof input == 'number') {
   2638            if (this.conditionalSetError(input < 0, gl.INVALID_VALUE))
   2639                return;
   2640            buffer.setStorage(input);
   2641        } else {
   2642            buffer.setData(input);
   2643        }
   2644    };
   2645 
   2646    /**
   2647    * @param {number} target
   2648    * @param {number} offset
   2649    * @param {goog.NumberArray} data
   2650    */
   2651    sglrReferenceContext.ReferenceContext.prototype.bufferSubData = function(target, offset, data) {
   2652        if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
   2653            return;
   2654        if (this.conditionalSetError(offset < 0, gl.INVALID_VALUE))
   2655            return;
   2656        /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target);
   2657        if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION))
   2658            return;
   2659 
   2660        if (this.conditionalSetError(offset + data.byteLength > buffer.getSize(), gl.INVALID_VALUE))
   2661            return;
   2662        buffer.setSubData(offset, data);
   2663    };
   2664 
   2665    /**
   2666    * @param {number} x
   2667    * @param {number} y
   2668    * @param {number} width
   2669    * @param {number} height
   2670    * @param {number} format
   2671    * @param {number} type
   2672    * @param {goog.NumberArray} pixels
   2673    */
   2674    sglrReferenceContext.ReferenceContext.prototype.readPixels = function(x, y, width, height, format, type, pixels) {
   2675        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
   2676 
   2677        // Map transfer format.
   2678        /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
   2679 
   2680        // Clamp input values
   2681        /** @type {number} */ var copyX = deMath.clamp(x, 0, src.raw().getHeight());
   2682        /** @type {number} */ var copyY = deMath.clamp(y, 0, src.raw().getDepth());
   2683        /** @type {number} */ var copyWidth = deMath.clamp(width, 0, src.raw().getHeight() - x);
   2684        /** @type {number} */ var copyHeight = deMath.clamp(height, 0, src.raw().getDepth() - y);
   2685 
   2686        /** @type {?ArrayBuffer} */ var data;
   2687        /** @type {number} */ var offset;
   2688        if (this.m_pixelPackBufferBinding) {
   2689            if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
   2690                return;
   2691            data = this.m_pixelPackBufferBinding.getData();
   2692            offset = pixels.byteOffset;
   2693        } else {
   2694            if (pixels instanceof ArrayBuffer) {
   2695                data = pixels;
   2696                offset = 0;
   2697            } else {
   2698                data = pixels.buffer;
   2699                offset = pixels.byteOffset;
   2700            }
   2701        }
   2702 
   2703        /** @type {tcuTexture.PixelBufferAccess} */
   2704        var dst = new tcuTexture.PixelBufferAccess({
   2705            format: transferFmt,
   2706            width: width,
   2707            height: height,
   2708            depth: 1,
   2709            rowPitch: deMath.deAlign32(width * transferFmt.getPixelSize(), this.m_pixelPackAlignment),
   2710            slicePitch: 0,
   2711            data: data,
   2712            offset: offset});
   2713 
   2714        src = src.getSubregion([copyX, copyY, copyWidth, copyHeight]);
   2715        src.resolveMultisampleColorBuffer(tcuTextureUtil.getSubregion(dst, 0, 0, 0, copyWidth, copyHeight, 1));
   2716    };
   2717 
   2718    /**
   2719    * @return {number}
   2720    */
   2721    sglrReferenceContext.ReferenceContext.prototype.getType = function() {
   2722        return this.m_type;
   2723    };
   2724 
   2725    /**
   2726    * @return {tcuTexture.PixelBufferAccess}
   2727    */
   2728    sglrReferenceContext.nullAccess = function() {
   2729        return new tcuTexture.PixelBufferAccess({
   2730            width: 0,
   2731            height: 0});
   2732    };
   2733 
   2734    /**
   2735    * @param {sglrReferenceContext.Framebuffer} framebuffer
   2736    * @param {sglrReferenceContext.AttachmentPoint} point
   2737    * @return {tcuTexture.PixelBufferAccess}
   2738    */
   2739    sglrReferenceContext.ReferenceContext.prototype.getFboAttachment = function(framebuffer, point) {
   2740        /** @type {sglrReferenceContext.Attachment} */ var attachment = framebuffer.getAttachment(point);
   2741 
   2742        switch (attachment.type) {
   2743            case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE: {
   2744                var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object);
   2745                /** @type {?sglrReferenceContext.TextureType} */ var type = container.getType();
   2746                var texture = container.texture;
   2747 
   2748                if (type == sglrReferenceContext.TextureType.TYPE_2D)
   2749                    return texture.getLevel(attachment.level);
   2750                else if (type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP)
   2751                    return texture.getFace(attachment.level, sglrReferenceContext.texTargetToFace(attachment.texTarget));
   2752                else if (type == sglrReferenceContext.TextureType.TYPE_2D_ARRAY ||
   2753                        type == sglrReferenceContext.TextureType.TYPE_3D ||
   2754                        type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) {
   2755                    /** @type {tcuTexture.PixelBufferAccess} */ var level = texture.getLevel(attachment.level);
   2756 
   2757                    return new tcuTexture.PixelBufferAccess({
   2758                        format: level.getFormat(),
   2759                        width: level.getWidth(),
   2760                        height: level.getHeight(),
   2761                        depth: 1,
   2762                        rowPitch: level.getRowPitch(),
   2763                        slicePitch: 0,
   2764                        data: level.getBuffer(),
   2765                        offset: level.getSlicePitch() * attachment.layer});
   2766                } else
   2767                    return sglrReferenceContext.nullAccess();
   2768            }
   2769 
   2770            case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER: {
   2771                var rbo = /** @type {sglrReferenceContext.Renderbuffer} */ (attachment.object);
   2772                return rbo.getAccess();
   2773            }
   2774 
   2775            default:
   2776                return sglrReferenceContext.nullAccess();
   2777        }
   2778    };
   2779 
   2780    /**
   2781    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   2782    */
   2783    sglrReferenceContext.ReferenceContext.prototype.getReadColorbuffer = function() {
   2784        if (this.m_readFramebufferBinding)
   2785            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0));
   2786        else
   2787            return this.m_defaultColorbuffer;
   2788    };
   2789 
   2790    // sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(mode, first, count) {
   2791    //     this.drawArraysInstanced(mode, first, count, 1);
   2792    // };
   2793 
   2794    /**
   2795     * @param {number} target
   2796     * @return {number}
   2797     * @throws {Error}
   2798     */
   2799    sglrReferenceContext.ReferenceContext.prototype.checkFramebufferStatus = function(target) {
   2800        if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
   2801                    target != gl.DRAW_FRAMEBUFFER &&
   2802                    target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
   2803            return 0;
   2804 
   2805        // Select binding point.
   2806        /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
   2807 
   2808        // Default framebuffer is always complete.
   2809        if (!framebufferBinding)
   2810            return gl.FRAMEBUFFER_COMPLETE;
   2811 
   2812        /** @type {number} */ var width = -1;
   2813        /** @type {number} */ var height = -1;
   2814        /** @type {boolean} */ var hasAttachment = false;
   2815        /** @type {boolean} */ var attachmentComplete = true;
   2816        /** @type {boolean} */ var dimensionsOk = true;
   2817 
   2818        for (var key in sglrReferenceContext.AttachmentPoint) {
   2819            /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.AttachmentPoint[key];
   2820            /** @type {sglrReferenceContext.Attachment} */ var attachment = framebufferBinding.getAttachment(point);
   2821            /** @type {number} */ var attachmentWidth = 0;
   2822            /** @type {number} */ var attachmentHeight = 0;
   2823            /** @type {tcuTexture.TextureFormat} */ var attachmentFormat;
   2824 
   2825            if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE) {
   2826                var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object);
   2827                /** @type {tcuTexture.ConstPixelBufferAccess} */ var level;
   2828 
   2829                if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D) {
   2830                    DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D);
   2831                    /** @type {sglrReferenceContext.Texture2D} */ var tex2D = /** @type {sglrReferenceContext.Texture2D} */ (container.texture);
   2832 
   2833                    if (tex2D.hasLevel(attachment.level))
   2834                        level = tex2D.getLevel(attachment.level);
   2835                // TODO: implement CUBE_MAP, 2D_ARRAY, 3D, CUBE_MAP_ARRAY
   2836                } else if (deMath.deInRange32(attachment.texTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X,
   2837                                                        sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z)) {
   2838                    DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP);
   2839 
   2840                    var texCube = /** @type {sglrReferenceContext.TextureCube} */ (container.texture);
   2841                    var face = sglrReferenceContext.texTargetToFace(attachment.texTarget);
   2842 
   2843                    if (texCube.hasFace(attachment.level, face))
   2844                        level = texCube.getFace(attachment.level, face);
   2845                } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY) {
   2846                    DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
   2847                    var tex2DArr = /** @type {sglrReferenceContext.Texture2DArray} */ (container.texture);
   2848 
   2849                    if (tex2DArr.hasLevel(attachment.level))
   2850                        level = tex2DArr.getLevel(attachment.level); // \note Slice doesn't matter here.
   2851                } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_3D) {
   2852                    DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_3D);
   2853                    var tex3D = /** @type {sglrReferenceContext.Texture3D} */ (container.texture);
   2854 
   2855                    if (tex3D.hasLevel(attachment.level))
   2856                        level = tex3D.getLevel(attachment.level); // \note Slice doesn't matter here.
   2857                // } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY) {
   2858                //     DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY);
   2859                //     var texCubeArr = container.texture;
   2860                //
   2861                //     if (texCubeArr.hasLevel(attachment.level))
   2862                //         level = texCubeArr.getLevel(attachment.level); // \note Slice doesn't matter here.
   2863                } else
   2864                    throw new Error('sglrReferenceContext.Framebuffer attached to a texture but no valid target specified.');
   2865 
   2866                attachmentWidth = level.getWidth();
   2867                attachmentHeight = level.getHeight();
   2868                attachmentFormat = level.getFormat();
   2869            } else if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER) {
   2870                var renderbuffer = attachment.object;
   2871 
   2872                attachmentWidth = renderbuffer.getWidth();
   2873                attachmentHeight = renderbuffer.getHeight();
   2874                attachmentFormat = renderbuffer.getFormat();
   2875            } else
   2876                continue; // Skip rest of checks.
   2877 
   2878            if (!hasAttachment && attachmentWidth > 0 && attachmentHeight > 0) {
   2879                width = attachmentWidth;
   2880                height = attachmentHeight;
   2881                hasAttachment = true;
   2882            } else if (attachmentWidth != width || attachmentHeight != height)
   2883                dimensionsOk = false;
   2884 
   2885            // Validate attachment point compatibility.
   2886            switch (attachmentFormat.order) {
   2887                case tcuTexture.ChannelOrder.R:
   2888                case tcuTexture.ChannelOrder.RG:
   2889                case tcuTexture.ChannelOrder.RGB:
   2890                case tcuTexture.ChannelOrder.RGBA:
   2891                case tcuTexture.ChannelOrder.sRGB:
   2892                case tcuTexture.ChannelOrder.sRGBA:
   2893                    if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0)
   2894                        attachmentComplete = false;
   2895                    break;
   2896 
   2897                case tcuTexture.ChannelOrder.D:
   2898                    if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH)
   2899                        attachmentComplete = false;
   2900                    break;
   2901 
   2902                case tcuTexture.ChannelOrder.S:
   2903                    if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)
   2904                        attachmentComplete = false;
   2905                    break;
   2906 
   2907                case tcuTexture.ChannelOrder.DS:
   2908                    if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH &&
   2909                        point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)
   2910                        attachmentComplete = false;
   2911                    break;
   2912 
   2913                default:
   2914                    throw new Error('Unsupported attachment channel order:' + attachmentFormat.order);
   2915            }
   2916        }
   2917 
   2918        if (!attachmentComplete)
   2919            return gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
   2920        else if (!hasAttachment)
   2921            return gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
   2922        else if (!dimensionsOk)
   2923            return gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
   2924        else
   2925            return gl.FRAMEBUFFER_COMPLETE;
   2926    };
   2927 
   2928    /**
   2929     * @param {number} mode
   2930     * @return {boolean}
   2931     */
   2932    sglrReferenceContext.ReferenceContext.prototype.predrawErrorChecks = function(mode) {
   2933        if (this.conditionalSetError(mode != gl.POINTS &&
   2934                    mode != gl.LINE_STRIP && mode != gl.LINE_LOOP && mode != gl.LINES &&
   2935                    mode != gl.TRIANGLE_STRIP && mode != gl.TRIANGLE_FAN && mode != gl.TRIANGLES,
   2936                    gl.INVALID_ENUM))
   2937            return false;
   2938 
   2939        // \todo [jarkko] Uncomment following code when the buffer mapping support is added
   2940        //for (size_t ndx = 0; ndx < vao.m_arrays.length; ++ndx)
   2941        //  if (vao.m_arrays[ndx].enabled && vao.m_arrays[ndx].bufferBinding && vao.m_arrays[ndx].bufferBinding->isMapped)
   2942        //      RC_ERROR_RET(gl.INVALID_OPERATION, RC_RET_VOID);
   2943 
   2944        if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_FRAMEBUFFER_OPERATION))
   2945            return false;
   2946 
   2947        return true;
   2948    };
   2949 
   2950    /**
   2951    * Draws quads from vertex arrays
   2952    * @param {number} mode GL primitive type to draw with.
   2953    * @param {number} first First vertex to begin drawing with
   2954    * @param {number} count How many vertices to draw (not counting vertices before first)
   2955    * @param {number} instanceCount
   2956    */
   2957    sglrReferenceContext.ReferenceContext.prototype.drawArraysInstanced = function(mode, first, count, instanceCount) {
   2958        if (this.conditionalSetError(first < 0 || count < 0 || instanceCount < 0, gl.INVALID_VALUE))
   2959            return;
   2960 
   2961        if (!this.predrawErrorChecks(mode))
   2962            return;
   2963 
   2964        // All is ok
   2965        this.drawQuads(mode, first, count, instanceCount);
   2966    };
   2967 
   2968    /**
   2969    * @param {number} mode GL primitive type to draw with.
   2970    * @param {number} start
   2971    * @param {number} end
   2972    * @param {number} count How many vertices to draw (not counting vertices before first)
   2973    * @param {number} type Data type
   2974    * @param {number} offset
   2975    */
   2976    sglrReferenceContext.ReferenceContext.prototype.drawRangeElements = function(mode, start, end, count, type, offset) {
   2977        if (this.conditionalSetError(end < start, gl.INVALID_VALUE))
   2978            return;
   2979 
   2980        this.drawElements(mode, count, type, offset);
   2981    };
   2982 
   2983    /**
   2984    * @param {number} mode GL primitive type to draw with.
   2985    * @param {number} count How many vertices to draw (not counting vertices before first)
   2986    * @param {number} type Data type
   2987    * @param {number} offset
   2988    */
   2989    sglrReferenceContext.ReferenceContext.prototype.drawElements = function(mode, count, type, offset) {
   2990        this.drawElementsInstanced(mode, count, type, offset, 1);
   2991    };
   2992 
   2993    /**
   2994    * @param {number} mode GL primitive type to draw with.
   2995    * @param {number} count How many vertices to draw (not counting vertices before first)
   2996    * @param {number} type Data type
   2997    * @param {number} offset
   2998    * @param {number} instanceCount
   2999    */
   3000    sglrReferenceContext.ReferenceContext.prototype.drawElementsInstanced = function(mode, count, type, offset, instanceCount) {
   3001        this.drawElementsInstancedBaseVertex(mode, count, type, offset, instanceCount, 0);
   3002    };
   3003 
   3004    /**
   3005    * @param {number} mode GL primitive type to draw with.
   3006    * @param {number} count How many vertices to draw (not counting vertices before first)
   3007    * @param {number} type Data type
   3008    * @param {number} offset
   3009    * @param {number} instanceCount
   3010    * @param {number} baseVertex
   3011    */
   3012    sglrReferenceContext.ReferenceContext.prototype.drawElementsInstancedBaseVertex = function(mode, count, type, offset, instanceCount, baseVertex) {
   3013        var vao = this.m_vertexArrayBinding;
   3014 
   3015        if (this.conditionalSetError(type != gl.UNSIGNED_BYTE &&
   3016                    type != gl.UNSIGNED_SHORT &&
   3017                    type != gl.UNSIGNED_INT, gl.INVALID_ENUM))
   3018            return;
   3019        if (this.conditionalSetError(count < 0 || instanceCount < 0, gl.INVALID_VALUE))
   3020            return;
   3021 
   3022        if (!this.predrawErrorChecks(mode))
   3023            return;
   3024 
   3025        if (this.conditionalSetError(count > 0 && !vao.m_elementArrayBufferBinding, gl.INVALID_OPERATION))
   3026            return;
   3027        // All is ok
   3028        var data = vao.m_elementArrayBufferBinding.getData();
   3029        var indices = new rrRenderer.DrawIndices(data, sglrReferenceUtils.mapGLIndexType(type), offset, baseVertex);
   3030 
   3031        this.drawQuads(mode, indices, count, instanceCount);
   3032    };
   3033 
   3034    /**
   3035    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
   3036    * @return {Array<number>}
   3037    */
   3038    sglrReferenceContext.getBufferRect = function(access) { return [0, 0, access.raw().getHeight(), access.raw().getDepth()]; };
   3039 
   3040    /**
   3041    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   3042    */
   3043    sglrReferenceContext.ReferenceContext.prototype.getDrawColorbuffer = function() {
   3044        if (this.m_drawFramebufferBinding)
   3045            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0));
   3046        return this.m_defaultColorbuffer;
   3047    };
   3048 
   3049    /**
   3050    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   3051    */
   3052    sglrReferenceContext.ReferenceContext.prototype.getDrawDepthbuffer = function() {
   3053        if (this.m_drawFramebufferBinding)
   3054            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH));
   3055        return this.m_defaultDepthbuffer;
   3056    };
   3057 
   3058    /**
   3059    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   3060    */
   3061    sglrReferenceContext.ReferenceContext.prototype.getDrawStencilbuffer = function() {
   3062        if (this.m_drawFramebufferBinding)
   3063            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL));
   3064        return this.m_defaultStencilbuffer;
   3065    };
   3066 
   3067    /**
   3068    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   3069    */
   3070    sglrReferenceContext.ReferenceContext.prototype.getReadDepthbuffer = function() {
   3071        if (this.m_readFramebufferBinding)
   3072            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH));
   3073        return this.m_defaultDepthbuffer;
   3074    };
   3075 
   3076    /**
   3077    * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
   3078    */
   3079    sglrReferenceContext.ReferenceContext.prototype.getReadStencilbuffer = function() {
   3080        if (this.m_readFramebufferBinding)
   3081            return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL));
   3082        return this.m_defaultStencilbuffer;
   3083    };
   3084 
   3085    /**
   3086    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
   3087    * @param {number} s
   3088    * @param {number} x
   3089    * @param {number} y
   3090    * @param {number} depth
   3091    */
   3092    sglrReferenceContext.writeDepthOnly = function(access, s, x, y, depth) { access.raw().setPixDepth(depth, s, x, y); };
   3093 
   3094    /**
   3095    * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
   3096    * @param {number} s
   3097    * @param {number} x
   3098    * @param {number} y
   3099    * @param {number} stencil
   3100    * @param {number} writeMask
   3101    */
   3102    sglrReferenceContext.writeStencilOnly = function(access, s, x, y, stencil, writeMask) {
   3103        /** @type {number} */ var oldVal = access.raw().getPixelInt(s, x, y)[3];
   3104        access.raw().setPixStencil((oldVal & ~writeMask) | (stencil & writeMask), s, x, y);
   3105    };
   3106 
   3107    /**
   3108    * @param {number} bits
   3109    * @param {number} s
   3110    * @return {number}
   3111    */
   3112    sglrReferenceContext.maskStencil = function(bits, s) { return s & ((1 << bits) - 1); };
   3113 
   3114    /**
   3115    * @param {number} buffers
   3116    */
   3117    sglrReferenceContext.ReferenceContext.prototype.clear = function(buffers) {
   3118        if (this.conditionalSetError((buffers & ~(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0, gl.INVALID_VALUE))
   3119            return;
   3120 
   3121        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer();
   3122        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
   3123        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
   3124        /** @type {boolean} */ var hasColor0 = /** @type {!boolean} */ (colorBuf0 && !colorBuf0.isEmpty());
   3125        /** @type {boolean} */ var hasDepth = /** @type {!boolean} */ (depthBuf && !depthBuf.isEmpty());
   3126        /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty());
   3127        /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
   3128 
   3129        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
   3130        /** @type {boolean} */ var isSharedDepthStencil;
   3131 
   3132        if (hasColor0 && (buffers & gl.COLOR_BUFFER_BIT) != 0) {
   3133            /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf0));
   3134            access = colorBuf0.getSubregion(colorArea);
   3135            /** @type {boolean} */ var isSRGB = colorBuf0.raw().getFormat().isSRGB();
   3136            /** @type {Array<number>} */ var c = (isSRGB && this.m_sRGBUpdateEnabled) ? tcuTextureUtil.linearToSRGB(this.m_clearColor) : this.m_clearColor;
   3137            /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
   3138            /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
   3139 
   3140            if (!maskUsed)
   3141                access.clear(c);
   3142            else if (!maskZero) {
   3143                for (var y = 0; y < access.raw().getDepth(); y++)
   3144                    for (var x = 0; x < access.raw().getHeight(); x++)
   3145                        for (var s = 0; s < access.getNumSamples(); s++)
   3146                            access.raw().setPixel(tcuTextureUtil.select(c, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
   3147            }
   3148            // else all channels masked out
   3149        }
   3150 
   3151        if (hasDepth && (buffers & gl.DEPTH_BUFFER_BIT) != 0 && this.m_depthMask) {
   3152            /** @type {Array<number>} */ var depthArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf));
   3153            access = depthBuf.getSubregion(depthArea);
   3154            isSharedDepthStencil = depthBuf.raw().getFormat().order != tcuTexture.ChannelOrder.D;
   3155 
   3156            if (isSharedDepthStencil) {
   3157                // Slow path where stencil is masked out in write.
   3158                for (var y = 0; y < access.raw().getDepth(); y++)
   3159                    for (var x = 0; x < access.raw().getHeight(); x++)
   3160                        for (var s = 0; s < access.getNumSamples(); s++)
   3161                            sglrReferenceContext.writeDepthOnly(access, s, x, y, this.m_clearDepth);
   3162            } else
   3163                access.clear([this.m_clearDepth, 0, 0, 0]);
   3164        }
   3165 
   3166        if (hasStencil && (buffers & gl.STENCIL_BUFFER_BIT) != 0) {
   3167            /** @type {Array<number>} */ var stencilArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf));
   3168            access = stencilBuf.getSubregion(stencilArea);
   3169            /** @type {number} */ var stencilBits = stencilBuf.raw().getFormat().getNumStencilBits();
   3170            /** @type {number} */ var stencil = sglrReferenceContext.maskStencil(stencilBits, this.m_clearStencil);
   3171            isSharedDepthStencil = stencilBuf.raw().getFormat().order != tcuTexture.ChannelOrder.S;
   3172 
   3173            if (isSharedDepthStencil || ((this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask & ((1 << stencilBits) - 1)) != ((1 << stencilBits) - 1))) {
   3174                // Slow path where depth or stencil is masked out in write.
   3175                for (var y = 0; y < access.raw().getDepth(); y++)
   3176                    for (var x = 0; x < access.raw().getHeight(); x++)
   3177                        for (var s = 0; s < access.getNumSamples(); s++)
   3178                            sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
   3179            } else
   3180                access.clear([0, 0, 0, stencil]);
   3181        }
   3182    };
   3183 
   3184    /**
   3185    * @param {number} buffer
   3186    * @param {number} drawbuffer
   3187    * @param {Array<number>} value
   3188    * @throws {Error}
   3189    */
   3190    sglrReferenceContext.ReferenceContext.prototype.clearBufferiv = function(buffer, drawbuffer, value) {
   3191        if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.STENCIL, gl.INVALID_ENUM))
   3192            return;
   3193        if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
   3194            return;
   3195 
   3196        /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
   3197 
   3198        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
   3199 
   3200        if (buffer == gl.COLOR) {
   3201            /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
   3202            /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
   3203            /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
   3204 
   3205            if (!colorBuf.isEmpty() && !maskZero) {
   3206                /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
   3207                access = colorBuf.getSubregion(colorArea);
   3208 
   3209                    if (!maskUsed)
   3210                        access.clear(value);
   3211                    else {
   3212                    for (var y = 0; y < access.raw().getDepth(); y++)
   3213                        for (var x = 0; x < access.raw().getHeight(); x++)
   3214                            for (var s = 0; s < access.getNumSamples(); s++)
   3215                                access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
   3216                    }
   3217            }
   3218        } else {
   3219            if (buffer !== gl.STENCIL)
   3220                throw new Error('Unexpected buffer type: ' + buffer);
   3221 
   3222                /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
   3223 
   3224            if (!stencilBuf.isEmpty() && this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask != 0) {
   3225                /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf));
   3226                access = stencilBuf.getSubregion(area);
   3227                /** @type {number} */ var stencil = value[0];
   3228 
   3229            for (var y = 0; y < access.raw().getDepth(); y++)
   3230                    for (var x = 0; x < access.raw().getHeight(); x++)
   3231                        for (var s = 0; s < access.getNumSamples(); s++)
   3232                            sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
   3233            }
   3234        }
   3235    };
   3236 
   3237    /**
   3238    * @param {number} buffer
   3239    * @param {number} drawbuffer
   3240    * @param {Array<number>} value
   3241    * @throws {Error}
   3242    */
   3243    sglrReferenceContext.ReferenceContext.prototype.clearBufferfv = function(buffer, drawbuffer, value) {
   3244        if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.DEPTH, gl.INVALID_ENUM))
   3245            return;
   3246        if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
   3247            return;
   3248 
   3249        /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
   3250        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
   3251        if (buffer == gl.COLOR) {
   3252            /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
   3253            /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
   3254            /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
   3255 
   3256            if (!colorBuf.isEmpty() && !maskZero) {
   3257                /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
   3258                access = colorBuf.getSubregion(colorArea);
   3259                var color = value;
   3260 
   3261                if (this.m_sRGBUpdateEnabled && access.raw().getFormat().isSRGB())
   3262                    color = tcuTextureUtil.linearToSRGB(color);
   3263 
   3264                if (!maskUsed)
   3265                    access.clear(color);
   3266                else {
   3267                    for (var y = 0; y < access.raw().getDepth(); y++)
   3268                        for (var x = 0; x < access.raw().getHeight(); x++)
   3269                            for (var s = 0; s < access.getNumSamples(); s++)
   3270                                access.raw().setPixel(tcuTextureUtil.select(color, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
   3271                }
   3272            }
   3273        } else {
   3274            if (buffer !== gl.DEPTH)
   3275                throw new Error('Unexpected buffer type: ' + buffer);
   3276 
   3277            /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
   3278 
   3279            if (!depthBuf.isEmpty() && this.m_depthMask) {
   3280                /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf));
   3281                access = depthBuf.getSubregion(area);
   3282                /** @type {number} */ var depth = value[0];
   3283 
   3284                for (var y = 0; y < access.raw().getDepth(); y++)
   3285                    for (var x = 0; x < access.raw().getHeight(); x++)
   3286                        for (var s = 0; s < access.getNumSamples(); s++)
   3287                            sglrReferenceContext.writeDepthOnly(access, s, x, y, depth);
   3288            }
   3289        }
   3290    };
   3291 
   3292    /**
   3293    * @param {number} buffer
   3294    * @param {number} drawbuffer
   3295    * @param {Array<number>} value
   3296    */
   3297    sglrReferenceContext.ReferenceContext.prototype.clearBufferuiv = function(buffer, drawbuffer, value) {
   3298        if (this.conditionalSetError(buffer != gl.COLOR, gl.INVALID_ENUM))
   3299            return;
   3300        if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
   3301            return;
   3302 
   3303        /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
   3304 
   3305        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
   3306        /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
   3307        /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
   3308 
   3309        if (!colorBuf.isEmpty() && !maskZero) {
   3310            /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
   3311            /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access = colorBuf.getSubregion(colorArea);
   3312 
   3313            if (!maskUsed)
   3314                access.clear(value);
   3315            else {
   3316            for (var y = 0; y < access.raw().getDepth(); y++)
   3317                for (var x = 0; x < access.raw().getHeight(); x++)
   3318                    for (var s = 0; s < access.getNumSamples(); s++)
   3319                        access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
   3320            }
   3321        }
   3322    };
   3323 
   3324    /**
   3325    * @param {number} buffer
   3326    * @param {number} drawbuffer
   3327    * @param {number} depth
   3328    * @param {number} stencil
   3329    */
   3330    sglrReferenceContext.ReferenceContext.prototype.clearBufferfi = function(buffer, drawbuffer, depth, stencil) {
   3331        if (this.conditionalSetError(buffer != gl.DEPTH_STENCIL, gl.INVALID_ENUM))
   3332            return;
   3333        this.clearBufferfv(gl.DEPTH, drawbuffer, [depth]);
   3334        this.clearBufferiv(gl.STENCIL, drawbuffer, [stencil]);
   3335    };
   3336 
   3337    /**
   3338    * @param {number} target
   3339    * @param {number} attachment
   3340    * @param {sglrReferenceContext.TexTarget} textarget
   3341    * @param {sglrReferenceContext.TextureContainer} texture
   3342    * @param {number} level
   3343    * @throws {Error}
   3344    */
   3345    sglrReferenceContext.ReferenceContext.prototype.framebufferTexture2D = function(target, attachment, textarget, texture, level) {
   3346        if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
   3347            // Attach to both depth and stencil.
   3348            this.framebufferTexture2D(target, gl.DEPTH_ATTACHMENT, textarget, texture, level);
   3349            this.framebufferTexture2D(target, gl.STENCIL_ATTACHMENT, textarget, texture, level);
   3350        } else {
   3351            /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
   3352            /** @type {sglrReferenceContext.TexTarget} */ var fboTexTarget = sglrReferenceContext.mapGLFboTexTarget(textarget);
   3353 
   3354            if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
   3355                        target != gl.DRAW_FRAMEBUFFER &&
   3356                        target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
   3357                return;
   3358            if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM))
   3359                return;
   3360 
   3361            // Select binding point.
   3362            /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
   3363            if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
   3364                return;
   3365 
   3366            if (texture) {
   3367                if (this.conditionalSetError(level != 0, gl.INVALID_VALUE))
   3368                    return;
   3369 
   3370                if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D) {
   3371                    if (this.conditionalSetError(fboTexTarget != sglrReferenceContext.TexTarget.TEXTARGET_2D, gl.INVALID_OPERATION))
   3372                        return;
   3373                } else {
   3374                    if (!texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP)
   3375                        throw new Error('Unsupported texture type');
   3376                    if (this.conditionalSetError(!deMath.deInRange32(fboTexTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z), gl.INVALID_OPERATION))
   3377                        return;
   3378                }
   3379            }
   3380 
   3381            /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
   3382 
   3383            if (texture) {
   3384                fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE;
   3385                fboAttachment.object = texture;
   3386                fboAttachment.texTarget = fboTexTarget;
   3387                fboAttachment.level = level;
   3388            }
   3389            framebufferBinding.setAttachment(point, fboAttachment);
   3390        }
   3391    };
   3392 
   3393    /**
   3394    * @param {number} target
   3395    * @param {number} attachment
   3396    * @param {sglrReferenceContext.TextureContainer} texture
   3397    * @param {number} level
   3398    * @param {number} layer
   3399    * @throws {Error}
   3400    */
   3401    sglrReferenceContext.ReferenceContext.prototype.framebufferTextureLayer = function(target, attachment, texture, level, layer) {
   3402        if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
   3403            // Attach to both depth and stencil.
   3404            this.framebufferTextureLayer(target, gl.DEPTH_ATTACHMENT, texture, level, layer);
   3405            this.framebufferTextureLayer(target, gl.STENCIL_ATTACHMENT, texture, level, layer);
   3406        } else {
   3407            /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
   3408 
   3409            if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
   3410                        target != gl.DRAW_FRAMEBUFFER &&
   3411                        target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
   3412                return;
   3413            if (this.conditionalSetError(point === undefined, gl.INVALID_ENUM))
   3414                return;
   3415 
   3416            // Select binding point.
   3417            /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
   3418            if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
   3419                return;
   3420 
   3421            if (texture) {
   3422                if (this.conditionalSetError(level != 0, gl.INVALID_VALUE))
   3423                    return;
   3424 
   3425                if (this.conditionalSetError(texture.getType() != sglrReferenceContext.TextureType.TYPE_2D_ARRAY &&
   3426                            texture.getType() != sglrReferenceContext.TextureType.TYPE_3D &&
   3427                            texture.getType() != sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY, gl.INVALID_OPERATION))
   3428                    return;
   3429 
   3430                if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D_ARRAY || texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) {
   3431                    if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_ARRAY_TEXTURE_LAYERS), gl.INVALID_VALUE))
   3432                        return;
   3433                    if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_TEXTURE_SIZE))), gl.INVALID_VALUE))
   3434                        return;
   3435                } else if (texture.getType() == sglrReferenceContext.TextureType.TYPE_3D) {
   3436                    if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_3D_TEXTURE_SIZE), gl.INVALID_VALUE))
   3437                        return;
   3438                    if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_3D_TEXTURE_SIZE))), gl.INVALID_VALUE))
   3439                        return;
   3440                }
   3441            }
   3442 
   3443            /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
   3444 
   3445            if (texture) {
   3446                fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE;
   3447                fboAttachment.object = texture;
   3448                fboAttachment.texTarget = sglrReferenceContext.texLayeredTypeToTarget(texture.getType());
   3449                fboAttachment.level = level;
   3450                fboAttachment.layer = layer;
   3451            }
   3452            framebufferBinding.setAttachment(point, fboAttachment);
   3453 
   3454        }
   3455    };
   3456 
   3457    /**
   3458    * @param {number} target
   3459    * @param {number} attachment
   3460    * @param {number} renderbuffertarget
   3461    * @param {sglrReferenceContext.Renderbuffer} renderbuffer
   3462    */
   3463    sglrReferenceContext.ReferenceContext.prototype.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) {
   3464        if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
   3465            // Attach both to depth and stencil.
   3466            this.framebufferRenderbuffer(target, gl.DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer);
   3467            this.framebufferRenderbuffer(target, gl.STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer);
   3468        } else {
   3469            /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
   3470 
   3471            if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
   3472                        target != gl.DRAW_FRAMEBUFFER &&
   3473                        target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
   3474                return;
   3475            if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM))
   3476                return;
   3477 
   3478            // Select binding point.
   3479            /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
   3480            if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
   3481                return;
   3482 
   3483            if (renderbuffer) {
   3484                if (this.conditionalSetError(renderbuffertarget != gl.RENDERBUFFER, gl.INVALID_ENUM))
   3485                    return;
   3486            }
   3487 
   3488            /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
   3489 
   3490            if (renderbuffer) {
   3491                fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER;
   3492                fboAttachment.object = renderbuffer;
   3493            }
   3494            framebufferBinding.setAttachment(point, fboAttachment);
   3495        }
   3496    };
   3497 
   3498    /**
   3499    * @param {number} target
   3500    * @param {number} internalformat
   3501    * @param {number} width
   3502    * @param {number} height
   3503    */
   3504    sglrReferenceContext.ReferenceContext.prototype.renderbufferStorage = function(target, internalformat, width, height) {
   3505        /** @type {tcuTexture.TextureFormat} */ var format = gluTextureUtil.mapGLInternalFormat(internalformat);
   3506 
   3507        if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM))
   3508            return;
   3509        if (this.conditionalSetError(!this.m_renderbufferBinding, gl.INVALID_OPERATION))
   3510            return;
   3511        if (this.conditionalSetError(!deMath.deInRange32(width, 0, this.m_limits.maxRenderbufferSize) ||
   3512                    !deMath.deInRange32(height, 0, this.m_limits.maxRenderbufferSize),
   3513                    gl.INVALID_OPERATION))
   3514            return;
   3515        if (this.conditionalSetError(!format, gl.INVALID_ENUM))
   3516            return;
   3517 
   3518        this.m_renderbufferBinding.setStorage(format, width, height);
   3519    };
   3520 
   3521    /**
   3522     * @param {number} target
   3523     * @param {number} samples
   3524     * @param {number} internalformat
   3525     * @param {number} width
   3526     * @param {number} height
   3527     */
   3528    sglrReferenceContext.ReferenceContext.prototype.renderbufferStorageMultisample = function(target, samples, internalformat, width, height) {
   3529        this.renderbufferStorage(target, internalformat, width, height);
   3530    };
   3531 
   3532    /**
   3533    * @param {rrRenderer.PrimitiveType} derivedType
   3534    * @return {rrRenderer.PrimitiveType}
   3535    * @throws {Error}
   3536    */
   3537    sglrReferenceContext.getPrimitiveBaseType = function(derivedType) {
   3538        switch (derivedType) {
   3539            case rrRenderer.PrimitiveType.TRIANGLES:
   3540            case rrRenderer.PrimitiveType.TRIANGLE_STRIP:
   3541            case rrRenderer.PrimitiveType.TRIANGLE_FAN:
   3542                return rrRenderer.PrimitiveType.TRIANGLES;
   3543 
   3544            case rrRenderer.PrimitiveType.LINES:
   3545            case rrRenderer.PrimitiveType.LINE_STRIP:
   3546            case rrRenderer.PrimitiveType.LINE_LOOP:
   3547                return rrRenderer.PrimitiveType.LINES;
   3548 
   3549            case rrRenderer.PrimitiveType.POINTS:
   3550                return rrRenderer.PrimitiveType.POINTS;
   3551 
   3552            default:
   3553                throw new Error('Unrecognized primitive type:' + derivedType);
   3554        }
   3555    };
   3556 
   3557    /**
   3558    * createProgram
   3559    * @param {sglrShaderProgram.ShaderProgram} program
   3560    * @return {sglrShaderProgram.ShaderProgram}
   3561    */
   3562    sglrReferenceContext.ReferenceContext.prototype.createProgram = function(program) {
   3563        return program;
   3564    };
   3565 
   3566    /**
   3567     * deleteProgram
   3568     * @param {sglrShaderProgram.ShaderProgram} program
   3569     */
   3570    sglrReferenceContext.ReferenceContext.prototype.deleteProgram = function(program) {};
   3571 
   3572    /**
   3573    * @param {sglrShaderProgram.ShaderProgram} program
   3574    */
   3575    sglrReferenceContext.ReferenceContext.prototype.useProgram = function(program) {
   3576        this.m_currentProgram = program;
   3577    };
   3578 
   3579    /**
   3580    * Draws quads from vertex arrays
   3581    * @param {number} primitive GL primitive type to draw with.
   3582    * @param {number} first First vertex to begin drawing with
   3583    * @param {number} count How many vertices to draw (not counting vertices before first)
   3584    */
   3585    sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(primitive, first, count) {
   3586        this.drawQuads(primitive, first, count, 1);
   3587    };
   3588 
   3589    /**
   3590    * Draws quads from vertex arrays
   3591    * @param {number} primitive GL primitive type to draw with.
   3592    * @param {(number|rrRenderer.DrawIndices)} first First vertex to begin drawing with
   3593    * @param {number} count Number of vertices
   3594    * @param {number=} instances Number of instances
   3595    */
   3596    sglrReferenceContext.ReferenceContext.prototype.drawQuads = function(primitive, first, count, instances) {
   3597        // undefined results
   3598        if (!this.m_currentProgram)
   3599            return;
   3600 
   3601        if (typeof instances === 'undefined')
   3602            instances = 1;
   3603 
   3604        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer();
   3605        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
   3606        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
   3607        /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty());
   3608        /** @type {number} */ var stencilBits = (hasStencil) ? stencilBuf.raw().getFormat().getNumStencilBits() : 0;
   3609 
   3610        /** @type {rrRenderer.RenderTarget} */ var renderTarget = new rrRenderer.RenderTarget(colorBuf0,
   3611                                                    depthBuf,
   3612                                                    stencilBuf);
   3613        /** @type {sglrShaderProgram.ShaderProgram} */ var program = this.m_currentProgram;
   3614 
   3615        /*new rrRenderer.Program(
   3616        *   this.m_currentProgram.getVertexShader(),
   3617        *   this.m_currentProgram.getFragmentShader());*/
   3618 
   3619        /** @type {rrRenderState.ViewportState} */ var viewportState = new rrRenderState.ViewportState(colorBuf0);
   3620        /** @type {rrRenderState.RenderState} */ var state = new rrRenderState.RenderState(viewportState);
   3621 
   3622        /** @type {Array<rrVertexAttrib.VertexAttrib>} */ var vertexAttribs = [];
   3623 
   3624        // Gen state
   3625        /** @type {rrRenderer.PrimitiveType} */ var baseType = rrRenderer.PrimitiveType.TRIANGLES;
   3626        /** @type {boolean} */ var polygonOffsetEnabled =
   3627            (baseType == rrRenderer.PrimitiveType.TRIANGLES) ?
   3628            (this.m_polygonOffsetFillEnabled) :
   3629            (false);
   3630 
   3631        //state.cullMode = m_cullMode
   3632 
   3633        state.fragOps.scissorTestEnabled = this.m_scissorEnabled;
   3634        state.fragOps.scissorRectangle = new rrRenderState.WindowRectangle(this.m_scissorBox);
   3635 
   3636        state.fragOps.numStencilBits = stencilBits;
   3637        state.fragOps.stencilTestEnabled = this.m_stencilTestEnabled;
   3638 
   3639        for (var key in rrDefs.FaceType) {
   3640            /** @type {number} */ var faceType = rrDefs.FaceType[key];
   3641            state.fragOps.stencilStates[faceType].compMask = this.m_stencil[faceType].opMask;
   3642            state.fragOps.stencilStates[faceType].writeMask = this.m_stencil[faceType].writeMask;
   3643            state.fragOps.stencilStates[faceType].ref = this.m_stencil[faceType].ref;
   3644            state.fragOps.stencilStates[faceType].func = sglrReferenceUtils.mapGLTestFunc(this.m_stencil[faceType].func);
   3645            state.fragOps.stencilStates[faceType].sFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opStencilFail);
   3646            state.fragOps.stencilStates[faceType].dpFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthFail);
   3647            state.fragOps.stencilStates[faceType].dpPass = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthPass);
   3648        }
   3649 
   3650        state.fragOps.depthTestEnabled = this.m_depthTestEnabled;
   3651        state.fragOps.depthFunc = sglrReferenceUtils.mapGLTestFunc(this.m_depthFunc);
   3652        state.fragOps.depthMask = this.m_depthMask;
   3653 
   3654        state.fragOps.blendMode = this.m_blendEnabled ? rrRenderState.BlendMode.STANDARD : rrRenderState.BlendMode.NONE;
   3655        state.fragOps.blendRGBState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeRGB);
   3656        state.fragOps.blendRGBState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcRGB);
   3657        state.fragOps.blendRGBState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstRGB);
   3658        state.fragOps.blendAState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeAlpha);
   3659        state.fragOps.blendAState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcAlpha);
   3660        state.fragOps.blendAState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstAlpha);
   3661        state.fragOps.blendColor = this.m_blendColor;
   3662 
   3663        state.fragOps.colorMask = this.m_colorMask;
   3664 
   3665        state.viewport.rect = new rrRenderState.WindowRectangle(this.m_viewport);
   3666        state.viewport.zn = this.m_depthRangeNear;
   3667        state.viewport.zf = this.m_depthRangeFar;
   3668 
   3669        //state.point.pointSize = this.m_pointSize;
   3670        state.line.lineWidth = this.m_lineWidth;
   3671 
   3672        state.fragOps.polygonOffsetEnabled = polygonOffsetEnabled;
   3673        state.fragOps.polygonOffsetFactor = this.m_polygonOffsetFactor;
   3674        state.fragOps.polygonOffsetUnits = this.m_polygonOffsetUnits;
   3675 
   3676        state.provokingVertexConvention = (this.m_provokingFirstVertexConvention) ? (rrDefs.ProvokingVertex.PROVOKINGVERTEX_FIRST) : (rrDefs.ProvokingVertex.PROVOKINGVERTEX_LAST);
   3677 
   3678        // gen attributes
   3679        /** @type {sglrReferenceContext.VertexArray} */ var vao = this.m_vertexArrayBinding;
   3680        for (var ndx = 0; ndx < vao.m_arrays.length; ++ndx) {
   3681            vertexAttribs[ndx] = new rrVertexAttrib.VertexAttrib();
   3682            if (!vao.m_arrays[ndx].enabled) {
   3683                vertexAttribs[ndx].type = rrVertexAttrib.VertexAttribType.DONT_CARE; // reading with wrong type is allowed, but results are undefined
   3684                vertexAttribs[ndx].generic = this.m_currentAttribs[ndx];
   3685            } else {
   3686                vertexAttribs[ndx].type = (vao.m_arrays[ndx].integer) ?
   3687                (sglrReferenceUtils.mapGLPureIntegerVertexAttributeType(vao.m_arrays[ndx].type)) :
   3688                (sglrReferenceUtils.mapGLFloatVertexAttributeType(vao.m_arrays[ndx].type, vao.m_arrays[ndx].normalized, vao.m_arrays[ndx].size));
   3689                vertexAttribs[ndx].size = sglrReferenceUtils.mapGLSize(vao.m_arrays[ndx].size);
   3690                vertexAttribs[ndx].stride = vao.m_arrays[ndx].stride;
   3691                vertexAttribs[ndx].instanceDivisor = vao.m_arrays[ndx].divisor;
   3692                vertexAttribs[ndx].pointer = vao.m_arrays[ndx].bufferBinding.getData();
   3693                vertexAttribs[ndx].offset = vao.m_arrays[ndx].offset;
   3694                vertexAttribs[ndx].componentCount = vao.m_arrays[ndx].size;
   3695            }
   3696        }
   3697 
   3698        // Set shader samplers
   3699        for (var uniformNdx = 0; uniformNdx < this.m_currentProgram.m_uniforms.length; ++uniformNdx) {
   3700            /** @type {number} */ var texNdx = this.m_currentProgram.m_uniforms[uniformNdx].value[0];
   3701 
   3702            switch (this.m_currentProgram.m_uniforms[uniformNdx].type) {
   3703                case gluShaderUtil.DataType.SAMPLER_2D:
   3704                case gluShaderUtil.DataType.UINT_SAMPLER_2D:
   3705                case gluShaderUtil.DataType.INT_SAMPLER_2D: {
   3706                    /** @type {sglrReferenceContext.Texture2D} */ var tex;
   3707 
   3708                    if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
   3709                        tex = /** @type {sglrReferenceContext.Texture2D} */ (this.m_textureUnits[texNdx].tex2DBinding.texture);
   3710 
   3711                    if (tex && tex.isComplete()) {
   3712                        tex.updateView();
   3713                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex;
   3714                    } else
   3715                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2D.texture;
   3716 
   3717                    break;
   3718                }
   3719                case gluShaderUtil.DataType.SAMPLER_CUBE:
   3720                case gluShaderUtil.DataType.UINT_SAMPLER_CUBE:
   3721                case gluShaderUtil.DataType.INT_SAMPLER_CUBE: {
   3722                    /** @type {sglrReferenceContext.TextureCube} */ var texCube;
   3723 
   3724                    if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
   3725                        texCube = /** @type {sglrReferenceContext.TextureCube} */ (this.m_textureUnits[texNdx].texCubeBinding.texture);
   3726 
   3727                    if (texCube && texCube.isComplete()) {
   3728                        texCube.updateView();
   3729                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = texCube;
   3730                    } else
   3731                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTexCube.texture;
   3732 
   3733                    break;
   3734                }
   3735                case gluShaderUtil.DataType.SAMPLER_2D_ARRAY:
   3736                case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY:
   3737                case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: {
   3738                    /** @type {sglrReferenceContext.Texture2DArray} */ var tex2DArray;
   3739 
   3740                    if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
   3741                        tex2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (this.m_textureUnits[texNdx].tex2DArrayBinding.texture);
   3742 
   3743                    if (tex2DArray && tex2DArray.isComplete()) {
   3744                        tex2DArray.updateView();
   3745                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex2DArray;
   3746                    } else
   3747                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2DArray.texture;
   3748 
   3749                    break;
   3750                }
   3751                case gluShaderUtil.DataType.SAMPLER_3D:
   3752                case gluShaderUtil.DataType.UINT_SAMPLER_3D:
   3753                case gluShaderUtil.DataType.INT_SAMPLER_3D: {
   3754                    /** @type {sglrReferenceContext.Texture3D} */ var tex3D;
   3755 
   3756                    if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
   3757                        tex3D = /** @type {sglrReferenceContext.Texture3D} */ (this.m_textureUnits[texNdx].tex3DBinding.texture);
   3758 
   3759                    if (tex3D && tex3D.isComplete()) {
   3760                        tex3D.updateView();
   3761                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex3D;
   3762                    } else
   3763                        this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex3D.texture;
   3764 
   3765                    break;
   3766                }
   3767                /* TODO: Port
   3768                case gluShaderUtil.DataType.SAMPLER_CUBE_ARRAY:
   3769                case gluShaderUtil.DataType.UINT_SAMPLER_CUBE_ARRAY:
   3770                case gluShaderUtil.DataType.INT_SAMPLER_CUBE_ARRAY:{
   3771                    rc::TextureCubeArray* tex = DE_NULL;
   3772 
   3773                    if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.length)
   3774                        tex = (this.m_textureUnits[texNdx].texCubeArrayBinding) ? (this.m_textureUnits[texNdx].texCubeArrayBinding) : (&this.m_textureUnits[texNdx].defaultCubeArrayTex);
   3775 
   3776                    if (tex && tex.isComplete()) {
   3777                        tex.updateView();
   3778                        this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = tex;
   3779                    } else
   3780                        this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = &this.m_emptyTexCubeArray;
   3781 
   3782                    break;
   3783                }
   3784                */
   3785                default:
   3786                    // nothing
   3787                    break;
   3788            }
   3789        }
   3790 
   3791        var primitiveType = sglrReferenceUtils.mapGLPrimitiveType(primitive);
   3792 
   3793        var renderFunction = rrRenderer.drawTriangles;
   3794        if (primitiveType == rrRenderer.PrimitiveType.LINES ||
   3795            primitiveType == rrRenderer.PrimitiveType.LINE_STRIP ||
   3796            primitiveType == rrRenderer.PrimitiveType.LINE_LOOP)
   3797            renderFunction = rrRenderer.drawLines;
   3798        else if (primitiveType == rrRenderer.PrimitiveType.POINTS)
   3799            renderFunction = rrRenderer.drawPoints;
   3800 
   3801        for (var instanceID = 0; instanceID < instances; instanceID++)
   3802            renderFunction(state, renderTarget, program, vertexAttribs, primitiveType, first, count, instanceID);
   3803    };
   3804 
   3805    /**
   3806    * @param {Array<number>} rect
   3807    * @return {boolean}
   3808    */
   3809    sglrReferenceContext.isEmpty = function(rect) { return rect[2] == 0 || rect[3] == 0; };
   3810 
   3811    /**
   3812    * @param {number} mask
   3813    * @param {Array<number>} srcRect
   3814    * @param {Array<number>} dstRect
   3815    * @param {boolean} flipX
   3816    * @param {boolean} flipY
   3817    * @throws {Error}
   3818    */
   3819    sglrReferenceContext.ReferenceContext.prototype.blitResolveMultisampleFramebuffer = function(mask, srcRect, dstRect, flipX, flipY) {
   3820        throw new Error('Unimplemented');
   3821    };
   3822 
   3823    /**
   3824    * @param {number} srcX0
   3825    * @param {number} srcY0
   3826    * @param {number} srcX1
   3827    * @param {number} srcY1
   3828    * @param {number} dstX0
   3829    * @param {number} dstY0
   3830    * @param {number} dstX1
   3831    * @param {number} dstY1
   3832    * @param {number} mask
   3833    * @param {number} filter
   3834    */
   3835    sglrReferenceContext.ReferenceContext.prototype.blitFramebuffer = function(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
   3836        // p0 in inclusive, p1 exclusive.
   3837        // Negative width/height means swap.
   3838        /** @type {boolean} */ var swapSrcX = srcX1 < srcX0;
   3839        /** @type {boolean} */ var swapSrcY = srcY1 < srcY0;
   3840        /** @type {boolean} */ var swapDstX = dstX1 < dstX0;
   3841        /** @type {boolean} */ var swapDstY = dstY1 < dstY0;
   3842        /** @type {number} */ var srcW = Math.abs(srcX1 - srcX0);
   3843        /** @type {number} */ var srcH = Math.abs(srcY1 - srcY0);
   3844        /** @type {number} */ var dstW = Math.abs(dstX1 - dstX0);
   3845        /** @type {number} */ var dstH = Math.abs(dstY1 - dstY0);
   3846        /** @type {boolean} */ var scale = srcW != dstW || srcH != dstH;
   3847        /** @type {number} */ var srcOriginX = swapSrcX ? srcX1 : srcX0;
   3848        /** @type {number} */ var srcOriginY = swapSrcY ? srcY1 : srcY0;
   3849        /** @type {number} */ var dstOriginX = swapDstX ? dstX1 : dstX0;
   3850        /** @type {number} */ var dstOriginY = swapDstY ? dstY1 : dstY0;
   3851        /** @type {Array<number>} */ var srcRect = [srcOriginX, srcOriginY, srcW, srcH];
   3852        /** @type {Array<number>} */ var dstRect = [dstOriginX, dstOriginY, dstW, dstH];
   3853 
   3854        if (this.conditionalSetError(filter != gl.NEAREST && filter != gl.LINEAR, gl.INVALID_ENUM))
   3855            return;
   3856        if (this.conditionalSetError((mask & (gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0 && filter != gl.NEAREST, gl.INVALID_OPERATION))
   3857            return;
   3858 
   3859        // Validate that both targets are complete.
   3860        if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
   3861                    this.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_OPERATION))
   3862            return;
   3863 
   3864        // Check samples count is valid
   3865        if (this.conditionalSetError(this.getDrawColorbuffer().getNumSamples() != 1, gl.INVALID_OPERATION))
   3866            return;
   3867 
   3868        // Check size restrictions of multisampled case
   3869        if (this.getReadColorbuffer().getNumSamples() != 1) {
   3870            // Src and Dst rect dimensions must be the same
   3871            if (this.conditionalSetError(srcW != dstW || srcH != dstH, gl.INVALID_OPERATION))
   3872                return;
   3873 
   3874            // sglrReferenceContext.Framebuffer formats must match
   3875            if (mask & gl.COLOR_BUFFER_BIT)
   3876                if (this.conditionalSetError(this.getReadColorbuffer().raw().getFormat() != this.getDrawColorbuffer().raw().getFormat(), gl.INVALID_OPERATION))
   3877                    return;
   3878            if (mask & gl.DEPTH_BUFFER_BIT)
   3879                if (this.conditionalSetError(this.getReadDepthbuffer().raw().getFormat() != this.getDrawDepthbuffer().raw().getFormat(), gl.INVALID_OPERATION))
   3880                    return;
   3881            if (mask & gl.STENCIL_BUFFER_BIT)
   3882            if (this.conditionalSetError(this.getReadStencilbuffer().raw().getFormat() != this.getDrawStencilbuffer().raw().getFormat(), gl.INVALID_OPERATION))
   3883                return;
   3884        }
   3885 
   3886        // Compute actual source rect.
   3887        srcRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadColorbuffer())) : srcRect;
   3888        srcRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadDepthbuffer())) : srcRect;
   3889        srcRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadStencilbuffer())) : srcRect;
   3890 
   3891        // Compute destination rect.
   3892        dstRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawColorbuffer())) : dstRect;
   3893        dstRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawDepthbuffer())) : dstRect;
   3894        dstRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawStencilbuffer())) : dstRect;
   3895        dstRect = this.m_scissorEnabled ? deMath.intersect(dstRect, this.m_scissorBox) : dstRect;
   3896 
   3897        if (sglrReferenceContext.isEmpty(srcRect) || sglrReferenceContext.isEmpty(dstRect))
   3898            return; // Don't attempt copy.
   3899 
   3900        // Multisampled read buffer is a special case
   3901        if (this.getReadColorbuffer().getNumSamples() != 1) {
   3902            /** @type {boolean} */ var swapX = swapSrcX ^ swapDstX ? true : false;
   3903            /** @type {boolean} */ var swapY = swapSrcY ^ swapDstY ? true : false;
   3904            var error = this.blitResolveMultisampleFramebuffer(mask, srcRect, dstRect, swapX, swapY);
   3905 
   3906            if (error != gl.NO_ERROR)
   3907                this.setError(error);
   3908 
   3909            return;
   3910        }
   3911 
   3912        // \note Multisample pixel buffers can now be accessed like non-multisampled because multisample read buffer case is already handled. => sample count must be 1
   3913 
   3914        // Coordinate transformation:
   3915        // Dst offset space -> dst rectangle space -> src rectangle space -> src offset space.
   3916        /** @type {tcuMatrix.Matrix} */ var matrix = tcuMatrixUtil.translationMatrix([srcX0 - srcRect[0], srcY0 - srcRect[1]]);
   3917        matrix = tcuMatrix.multiply(matrix, tcuMatrix.matrixFromVector(3, 3, [(srcX1 - srcX0) / (dstX1 - dstX0), (srcY1 - srcY0) / (dstY1 - dstY0), 1]));
   3918        matrix = tcuMatrix.multiply(matrix, tcuMatrixUtil.translationMatrix([dstRect[0] - dstX0, dstRect[1] - dstY0]));
   3919 
   3920        /**
   3921         * @param {number} x
   3922         * @param {number} y
   3923         * @return {number}
   3924         */
   3925        var transform = function(x, y) { return matrix.get(x, y); };
   3926 
   3927        /** @type {number} */ var dX;
   3928        /** @type {number} */ var dY;
   3929        /** @type {number} */ var sX;
   3930        /** @type {number} */ var sY;
   3931        /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src;
   3932        /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var dst;
   3933 
   3934        if (mask & gl.COLOR_BUFFER_BIT) {
   3935            src = tcuTextureUtil.getSubregion(this.getReadColorbuffer().toSinglesampleAccess(), srcRect[0], srcRect[1], 0, srcRect[2], srcRect[3], 1);
   3936            dst = tcuTextureUtil.getSubregion(this.getDrawColorbuffer().toSinglesampleAccess(), dstRect[0], dstRect[1], 0, dstRect[2], dstRect[3], 1);
   3937            /** @type {tcuTexture.TextureChannelClass} */ var dstClass = tcuTexture.getTextureChannelClass(dst.getFormat().type);
   3938            /** @type {boolean} */ var dstIsFloat = dstClass == tcuTexture.TextureChannelClass.FLOATING_POINT ||
   3939                                                        dstClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT ||
   3940                                                        dstClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
   3941            /** @type {tcuTexture.FilterMode} */ var sFilter = (scale && filter == gl.LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   3942            /** @type {tcuTexture.Sampler} */ var sampler = new tcuTexture.Sampler(tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE,
   3943                                                        sFilter, sFilter, 0.0 /* lod threshold */, false /* non-normalized coords */);
   3944            /** @type {boolean} */ var srcIsSRGB = src.getFormat().order == tcuTexture.ChannelOrder.sRGB || src.getFormat().order == tcuTexture.ChannelOrder.sRGBA;
   3945            /** @type {boolean} */ var dstIsSRGB = dst.getFormat().order == tcuTexture.ChannelOrder.sRGB || dst.getFormat().order == tcuTexture.ChannelOrder.sRGBA;
   3946            /** @type {boolean} */ var convertSRGB = this.m_sRGBUpdateEnabled;
   3947 
   3948            // \note We don't check for unsupported conversions, unlike spec requires.
   3949 
   3950            for (var yo = 0; yo < dstRect[3]; yo++) {
   3951                for (var xo = 0; xo < dstRect[2]; xo++) {
   3952                    dX = xo + 0.5;
   3953                    dY = yo + 0.5;
   3954 
   3955                    // \note Only affine part is used.
   3956                    sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
   3957                    sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
   3958 
   3959                    // do not copy pixels outside the modified source region (modified by buffer intersection)
   3960                    if (sX < 0.0 || sX >= srcRect[2] ||
   3961                        sY < 0.0 || sY >= srcRect[3])
   3962                        continue;
   3963 
   3964                    if (dstIsFloat || srcIsSRGB || filter == tcuTexture.FilterMode.LINEAR) {
   3965                        /** @type {Array<number>} */ var p = src.sample2D(sampler, sampler.minFilter, sX, sY, 0);
   3966                        dst.setPixel((dstIsSRGB && convertSRGB) ? tcuTextureUtil.linearToSRGB(p) : p, xo, yo);
   3967                    } else
   3968                        dst.setPixelInt(src.getPixelInt(Math.floor(sX), Math.floor(sY)), xo, yo);
   3969                }
   3970            }
   3971        }
   3972 
   3973        if ((mask & gl.DEPTH_BUFFER_BIT) && this.m_depthMask) {
   3974            src = this.getReadDepthbuffer().getSubregion(srcRect);
   3975            dst = this.getDrawDepthbuffer().getSubregion(dstRect);
   3976 
   3977            for (var yo = 0; yo < dstRect[3]; yo++) {
   3978                for (var xo = 0; xo < dstRect[2]; xo++) {
   3979                    var sampleNdx = 0; // multisample read buffer case is already handled
   3980 
   3981                    dX = xo + 0.5;
   3982                    dY = yo + 0.5;
   3983                    sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
   3984                    sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
   3985 
   3986                    sglrReferenceContext.writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixel(sampleNdx, Math.floor(sX), Math.floor(sY))[0]);
   3987                }
   3988            }
   3989        }
   3990 
   3991        if (mask & gl.STENCIL_BUFFER_BIT) {
   3992            src = this.getReadStencilbuffer().getSubregion(srcRect);
   3993            dst = this.getDrawStencilbuffer().getSubregion(dstRect);
   3994 
   3995            for (var yo = 0; yo < dstRect[3]; yo++) {
   3996                for (var xo = 0; xo < dstRect[2]; xo++) {
   3997                    var sampleNdx = 0; // multisample read buffer case is already handled
   3998 
   3999                    dX = xo + 0.5;
   4000                    dY = yo + 0.5;
   4001                    sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
   4002                    sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
   4003 
   4004                    sglrReferenceContext.writeStencilOnly(dst, sampleNdx, xo, yo, src.raw().getPixelInt(sampleNdx, Math.floor(sX), Math.floor(sY))[3], this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
   4005                }
   4006            }
   4007        }
   4008    };
   4009 
   4010    /**
   4011    * @param {number} internalFormat
   4012    * @return {tcuTexture.TextureFormat}
   4013    */
   4014    sglrReferenceContext.mapInternalFormat = function(internalFormat) {
   4015        switch (internalFormat) {
   4016            case gl.ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.A, tcuTexture.ChannelType.UNORM_INT8);
   4017            case gl.LUMINANCE: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.L, tcuTexture.ChannelType.UNORM_INT8);
   4018            case gl.LUMINANCE_ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.LA, tcuTexture.ChannelType.UNORM_INT8);
   4019            case gl.RGB: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
   4020            case gl.RGBA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
   4021 
   4022            default:
   4023                return gluTextureUtil.mapGLInternalFormat(internalFormat);
   4024        }
   4025    };
   4026 
   4027    /**
   4028    * @param {tcuTexture.PixelBufferAccess} dst
   4029    * @param {tcuTexture.ConstPixelBufferAccess} src
   4030    */
   4031    sglrReferenceContext.depthValueFloatClampCopy = function(dst, src) {
   4032        /** @type {number} */ var width = dst.getWidth();
   4033        /** @type {number} */ var height = dst.getHeight();
   4034        /** @type {number} */ var depth = dst.getDepth();
   4035 
   4036        DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
   4037 
   4038        // clamping copy
   4039        for (var z = 0; z < depth; z++)
   4040        for (var y = 0; y < height; y++)
   4041        for (var x = 0; x < width; x++) {
   4042            /** @type {Array<number>} */ var data = src.getPixel(x, y, z);
   4043            dst.setPixel([deMath.clamp(data[0], 0.0, 1.0), data[1], data[2], data[3]], x, y, z);
   4044        }
   4045    };
   4046 
   4047    /**
   4048    * @param {number} target
   4049    * @param {number} level
   4050    * @param {number} internalFormat
   4051    * @param {number} width
   4052    * @param {number} height
   4053    */
   4054    sglrReferenceContext.ReferenceContext.prototype.texImage2DDelegate = function (target, level, internalFormat, width, height) {
   4055        var format;
   4056        var dataType;
   4057 
   4058        switch (internalFormat)
   4059        {
   4060            case gl.ALPHA:
   4061            case gl.LUMINANCE:
   4062            case gl.LUMINANCE_ALPHA:
   4063            case gl.RGB:
   4064            case gl.RGBA:
   4065                format = internalFormat;
   4066                dataType = GL.UNSIGNED_BYTE;
   4067                break;
   4068            default:
   4069            {
   4070                var transferFmt = gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(internalFormat));
   4071                format = transferFmt.format;
   4072                dataType = transferFmt.dataType;
   4073                break;
   4074            }
   4075        }
   4076        this.texImage2D(target, level, internalFormat, width, height, 0, format, dataType, null);
   4077    };
   4078 
   4079    /**
   4080    * @param {number} target
   4081    * @param {number} level
   4082    * @param {number} internalFormat
   4083    * @param {number} width
   4084    * @param {number} height
   4085    * @param {number} border
   4086    * @param {number} format
   4087    * @param {number} type
   4088    * @param {number} pixels
   4089    */
   4090    sglrReferenceContext.ReferenceContext.prototype.texImage2D = function(target, level, internalFormat, width, height, border, format, type, pixels) {
   4091        this.texImage3D(target, level, internalFormat, width, height, 1, border, format, type, pixels);
   4092    };
   4093 
   4094    sglrReferenceContext.ReferenceContext.prototype.texImage3D = function(target, level, internalFormat, width, height, depth, border, format, type, pixels) {
   4095        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4096        /** @type {ArrayBuffer} */ var data = null;
   4097        /** @type {number} */ var offset = 0;
   4098        /** @type {tcuTexture.PixelBufferAccess} */ var dst;
   4099        /** @type {tcuTexture.ConstPixelBufferAccess} */ var src;
   4100        if (this.m_pixelUnpackBufferBinding) {
   4101            if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
   4102                return;
   4103            data = this.m_pixelUnpackBufferBinding.getData();
   4104            offset = pixels;
   4105        } else if (pixels) {
   4106            if (pixels instanceof ArrayBuffer) {
   4107                data = pixels;
   4108                offset = 0;
   4109            } else {
   4110                data = pixels.buffer;
   4111                offset = pixels.byteOffset;
   4112            }
   4113        }
   4114        /** @type {boolean} */ var isDstFloatDepthFormat = (internalFormat == gl.DEPTH_COMPONENT32F || internalFormat == gl.DEPTH32F_STENCIL8); // depth components are limited to [0,1] range
   4115 
   4116        if (this.conditionalSetError(border != 0, gl.INVALID_VALUE))
   4117            return;
   4118        if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE))
   4119            return;
   4120 
   4121        // Map storage format.
   4122        /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
   4123        if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
   4124            return;
   4125 
   4126        // Map transfer format.
   4127        /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
   4128        if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM))
   4129            return;
   4130 
   4131        if (target == gl.TEXTURE_2D) {
   4132            // Validate size and level.
   4133            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE))
   4134                return;
   4135            if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE))
   4136                return;
   4137 
   4138            /** @type {sglrReferenceContext.Texture2D} */
   4139            var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
   4140 
   4141            if (texture.isImmutable()) {
   4142                if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
   4143                    return;
   4144 
   4145                //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
   4146                dst = texture.getLevel(level);
   4147 
   4148                if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
   4149                            width != dst.getWidth() ||
   4150                            height != dst.getHeight(), gl.INVALID_OPERATION))
   4151                    return;
   4152            } else
   4153                texture.allocLevel(level, storageFmt, width, height);
   4154 
   4155            if (data) {
   4156                var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4157                var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4158                var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4159                src = new tcuTexture.ConstPixelBufferAccess({
   4160                    format: transferFmt,
   4161                    width: width,
   4162                    height: height,
   4163                    rowPitch: rowPitch,
   4164                    data: data,
   4165                    offset: offset + skip});
   4166 
   4167                //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
   4168                dst = texture.getLevel(level);
   4169 
   4170                if (isDstFloatDepthFormat)
   4171                    sglrReferenceContext.depthValueFloatClampCopy(dst, src);
   4172                else
   4173                    tcuTextureUtil.copy(dst, src);
   4174            } else {
   4175                // No data supplied, clear to black.
   4176 
   4177                //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
   4178                dst = texture.getLevel(level);
   4179                dst.clear([0.0, 0.0, 0.0, 1.0]);
   4180            }
   4181        } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
   4182                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
   4183                 target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
   4184                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
   4185                 target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
   4186                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
   4187            // Validate size and level.
   4188            if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize || depth != 1, gl.INVALID_VALUE))
   4189                return;
   4190            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE))
   4191                return;
   4192 
   4193            var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
   4194 
   4195            var face = sglrReferenceContext.mapGLCubeFace(target);
   4196 
   4197            if (textureCube.isImmutable()) {
   4198                if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION))
   4199                    return;
   4200 
   4201                dst = textureCube.getFace(level, face);
   4202 
   4203                if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
   4204                            width != dst.getWidth() ||
   4205                            height != dst.getHeight(), gl.INVALID_OPERATION))
   4206                    return;
   4207            } else
   4208                textureCube.allocLevel(level, face, storageFmt, width, height);
   4209 
   4210            if (data) {
   4211                var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4212                var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4213                var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4214                src = new tcuTexture.ConstPixelBufferAccess({
   4215                    format: transferFmt,
   4216                    width: width,
   4217                    height: height,
   4218                    rowPitch: rowPitch,
   4219                    data: data,
   4220                    offset: offset + skip});
   4221 
   4222                dst = textureCube.getFace(level, face);
   4223 
   4224                if (isDstFloatDepthFormat)
   4225                    sglrReferenceContext.depthValueFloatClampCopy(dst, src);
   4226                else
   4227                    tcuTextureUtil.copy(dst, src);
   4228            } else {
   4229                // No data supplied, clear to black.
   4230                dst = textureCube.getFace(level, face);
   4231                dst.clear([0.0, 0.0, 0.0, 1.0]);
   4232            }
   4233        } else if (target == gl.TEXTURE_2D_ARRAY) {
   4234            // Validate size and level.
   4235            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
   4236                        height > this.m_limits.maxTexture2DSize ||
   4237                        depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
   4238                return;
   4239            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
   4240                return;
   4241 
   4242            /** @type {sglrReferenceContext.Texture2DArray} */
   4243            var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
   4244 
   4245            if (texture2DArray.isImmutable()) {
   4246                if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION))
   4247                    return;
   4248 
   4249                dst = texture2DArray.getLevel(level);
   4250                if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
   4251                            width != dst.getWidth() ||
   4252                            height != dst.getHeight() ||
   4253                            depth != dst.getDepth(), gl.INVALID_OPERATION))
   4254                    return;
   4255            } else
   4256                texture2DArray.allocLevel(level, storageFmt, width, height, depth);
   4257 
   4258            if (data) {
   4259                var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4260                var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
   4261                var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4262                var slicePitch = imageHeight * rowPitch;
   4263                var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
   4264                    this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4265                src = new tcuTexture.ConstPixelBufferAccess({
   4266                    format: transferFmt,
   4267                    width: width,
   4268                    height: height,
   4269                    depth: depth,
   4270                    rowPitch: rowPitch,
   4271                    slicePitch: slicePitch,
   4272                    data: data,
   4273                    offset: offset + skip});
   4274 
   4275                dst = texture2DArray.getLevel(level);
   4276 
   4277                if (isDstFloatDepthFormat)
   4278                    sglrReferenceContext.depthValueFloatClampCopy(dst, src);
   4279                else
   4280                    tcuTextureUtil.copy(dst, src);
   4281            } else {
   4282                // No data supplied, clear to black.
   4283                dst = texture2DArray.getLevel(level);
   4284                dst.clear([0.0, 0.0, 0.0, 1.0]);
   4285            }
   4286        } else if (target == gl.TEXTURE_3D) {
   4287            // Validate size and level.
   4288            if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize ||
   4289                        height > this.m_limits.maxTexture3DSize ||
   4290                        depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
   4291                return;
   4292            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE))
   4293                return;
   4294 
   4295            var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
   4296 
   4297            if (texture3D.isImmutable()) {
   4298                if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION))
   4299                    return;
   4300 
   4301                dst = texture3D.getLevel(level);
   4302                if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
   4303                            width != dst.getWidth() ||
   4304                            height != dst.getHeight() ||
   4305                            depth != dst.getDepth(), gl.INVALID_OPERATION))
   4306                    return;
   4307            } else
   4308                texture3D.allocLevel(level, storageFmt, width, height, depth);
   4309 
   4310            if (data) {
   4311                var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4312                var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
   4313                var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4314                var slicePitch = imageHeight * rowPitch;
   4315                var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
   4316                    this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4317                src = new tcuTexture.ConstPixelBufferAccess({
   4318                    format: transferFmt,
   4319                    width: width,
   4320                    height: height,
   4321                    depth: depth,
   4322                    rowPitch: rowPitch,
   4323                    slicePitch: slicePitch,
   4324                    data: data,
   4325                    offset: offset + skip});
   4326 
   4327                dst = texture3D.getLevel(level);
   4328 
   4329                if (isDstFloatDepthFormat)
   4330                    sglrReferenceContext.depthValueFloatClampCopy(dst, src);
   4331                else
   4332                    tcuTextureUtil.copy(dst, src);
   4333 
   4334            } else {
   4335                // No data supplied, clear to black.
   4336                dst = texture3D.getLevel(level);
   4337                dst.clear([0.0, 0.0, 0.0, 1.0]);
   4338            }
   4339        }
   4340        // else if (target == gl.TEXTURE_CUBE_MAP_ARRAY)
   4341        // {
   4342        //     // Validate size and level.
   4343        //     RC_IF_ERROR(width != height ||
   4344        //                 width > m_limits.maxTexture2DSize ||
   4345        //                 depth % 6 != 0 ||
   4346        //                 depth > m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE, RC_RET_VOID);
   4347        //     RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), gl.INVALID_VALUE, RC_RET_VOID);
   4348 
   4349        //     TextureCubeArray* texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex;
   4350 
   4351        //     if (texture->isImmutable())
   4352        //     {
   4353        //         RC_IF_ERROR(!texture->hasLevel(level), gl.INVALID_OPERATION, RC_RET_VOID);
   4354 
   4355        //         ConstPixelBufferAccess dst(texture->getLevel(level));
   4356        //         RC_IF_ERROR(storageFmt != dst.getFormat() ||
   4357        //                     width != dst.getWidth() ||
   4358        //                     height != dst.getHeight() ||
   4359        //                     depth != dst.getDepth(), gl.INVALID_OPERATION, RC_RET_VOID);
   4360        //     }
   4361        //     else
   4362        //         texture->allocLevel(level, storageFmt, width, height, depth);
   4363 
   4364        //     if (unpackPtr)
   4365        //     {
   4366        //         ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr);
   4367        //         PixelBufferAccess dst (texture->getLevel(level));
   4368 
   4369        //         if (isDstFloatDepthFormat)
   4370        //             sglrReferenceContext.depthValueFloatClampCopy(dst, src);
   4371        //         else
   4372        //             tcu::copy(dst, src);
   4373        //     }
   4374        //     else
   4375        //     {
   4376        //         // No data supplied, clear to black.
   4377        //         PixelBufferAccess dst = texture->getLevel(level);
   4378        //         tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
   4379        //     }
   4380        // } /**/
   4381        else
   4382            this.setError(gl.INVALID_ENUM);
   4383    };
   4384 
   4385    sglrReferenceContext.ReferenceContext.prototype.texSubImage2D = function(target, level, xoffset, yoffset, width, height, format, type, pixels) {
   4386        this.texSubImage3D(target, level, xoffset, yoffset, 0, width, height, 1, format, type, pixels);
   4387    };
   4388 
   4389    sglrReferenceContext.ReferenceContext.prototype.texSubImage3D = function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) {
   4390        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4391        /** @type {ArrayBuffer} */ var data = null;
   4392        /** @type {number} */ var offset = 0;
   4393        /** @type {tcuTexture.PixelBufferAccess} */ var dst;
   4394        /** @type {tcuTexture.PixelBufferAccess} */ var sub;
   4395        /** @type {tcuTexture.ConstPixelBufferAccess} */ var src;
   4396        /** @type {boolean} */ var isDstFloatDepthFormat;
   4397        if (this.m_pixelUnpackBufferBinding) {
   4398            if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
   4399                return;
   4400            data = this.m_pixelUnpackBufferBinding.getData();
   4401            offset = pixels;
   4402        } else if (pixels) {
   4403            if (pixels instanceof ArrayBuffer) {
   4404                data = pixels;
   4405                offset = 0;
   4406            } else {
   4407                data = pixels.buffer;
   4408                offset = pixels.byteOffset;
   4409            }
   4410        }
   4411 
   4412        if (this.conditionalSetError(xoffset < 0 || yoffset < 0 || zoffset < 0, gl.INVALID_VALUE))
   4413            return;
   4414        if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE))
   4415            return;
   4416 
   4417        // Map transfer format.
   4418        /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
   4419        if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM))
   4420            return;
   4421 
   4422        if (target == gl.TEXTURE_2D) {
   4423            // Validate size and level.
   4424            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE))
   4425                return;
   4426            if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE))
   4427                return;
   4428 
   4429            /** @type {sglrReferenceContext.Texture2D} */
   4430            var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
   4431 
   4432            if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
   4433                return;
   4434 
   4435            //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
   4436            dst = texture.getLevel(level);
   4437 
   4438            if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
   4439                                        yoffset + height > dst.getHeight() ||
   4440                                        zoffset + depth > dst.getDepth(),
   4441                                        gl.INVALID_VALUE))
   4442                return;
   4443 
   4444            var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4445            var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4446            var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4447            src = new tcuTexture.ConstPixelBufferAccess({
   4448                format: transferFmt,
   4449                width: width,
   4450                height: height,
   4451                rowPitch: rowPitch,
   4452                data: data,
   4453                offset: offset + skip});
   4454 
   4455            sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
   4456            isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
   4457 
   4458            if (isDstFloatDepthFormat)
   4459                sglrReferenceContext.depthValueFloatClampCopy(sub, src);
   4460            else
   4461                tcuTextureUtil.copy(sub, src);
   4462        } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
   4463                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
   4464                 target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
   4465                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
   4466                 target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
   4467                 target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
   4468            var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
   4469 
   4470            var face = sglrReferenceContext.mapGLCubeFace(target);
   4471 
   4472            if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION))
   4473                return;
   4474 
   4475            dst = textureCube.getFace(level, face);
   4476 
   4477            if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
   4478                                        yoffset + height > dst.getHeight() ||
   4479                                        zoffset + depth > dst.getDepth(),
   4480                                        gl.INVALID_VALUE))
   4481                return;
   4482 
   4483            var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4484            var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4485            var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4486            src = new tcuTexture.ConstPixelBufferAccess({
   4487                format: transferFmt,
   4488                width: width,
   4489                height: height,
   4490                rowPitch: rowPitch,
   4491                slicePitach: slicePitch,
   4492                data: data,
   4493                offset: offset + skip});
   4494 
   4495            sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
   4496            isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
   4497 
   4498            if (isDstFloatDepthFormat)
   4499                sglrReferenceContext.depthValueFloatClampCopy(sub, src);
   4500            else
   4501                tcuTextureUtil.copy(sub, src);
   4502        } else if (target == gl.TEXTURE_2D_ARRAY) {
   4503            // Validate size and level.
   4504            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
   4505                        height > this.m_limits.maxTexture2DSize ||
   4506                        depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
   4507                return;
   4508            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
   4509                return;
   4510 
   4511            /** @type {sglrReferenceContext.Texture2DArray} */
   4512            var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
   4513 
   4514            if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION))
   4515                return;
   4516 
   4517            dst = texture2DArray.getLevel(level);
   4518            if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
   4519                                        yoffset + height > dst.getHeight() ||
   4520                                        zoffset + depth > dst.getDepth(),
   4521                                        gl.INVALID_VALUE))
   4522                return;
   4523 
   4524            var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4525            var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
   4526            var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4527            var slicePitch = imageHeight * rowPitch;
   4528            var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
   4529                this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4530            src = new tcuTexture.ConstPixelBufferAccess({
   4531                format: transferFmt,
   4532                width: width,
   4533                height: height,
   4534                depth: depth,
   4535                rowPitch: rowPitch,
   4536                slicePitch: slicePitch,
   4537                data: data,
   4538                offset: offset + skip});
   4539 
   4540            sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
   4541            isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
   4542 
   4543            if (isDstFloatDepthFormat)
   4544                sglrReferenceContext.depthValueFloatClampCopy(sub, src);
   4545            else
   4546                tcuTextureUtil.copy(sub, src);
   4547        } else if (target == gl.TEXTURE_3D) {
   4548            // Validate size and level.
   4549            if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize ||
   4550                        height > this.m_limits.maxTexture3DSize ||
   4551                        depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
   4552                return;
   4553            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE))
   4554                return;
   4555 
   4556            var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
   4557 
   4558            if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION))
   4559                return;
   4560 
   4561            dst = texture3D.getLevel(level);
   4562            if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
   4563                                        yoffset + height > dst.getHeight() ||
   4564                                        zoffset + depth > dst.getDepth(),
   4565                                        gl.INVALID_VALUE))
   4566                return;
   4567 
   4568            var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
   4569            var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
   4570            var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
   4571            var slicePitch = imageHeight * rowPitch;
   4572            var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
   4573                this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
   4574            src = new tcuTexture.ConstPixelBufferAccess({
   4575                format: transferFmt,
   4576                width: width,
   4577                height: height,
   4578                depth: depth,
   4579                rowPitch: rowPitch,
   4580                slicePitch: slicePitch,
   4581                data: data,
   4582                offset: offset + skip});
   4583 
   4584            sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
   4585 
   4586            isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
   4587            if (isDstFloatDepthFormat)
   4588                sglrReferenceContext.depthValueFloatClampCopy(sub, src);
   4589            else
   4590                tcuTextureUtil.copy(sub, src);
   4591        } else
   4592            this.setError(gl.INVALID_ENUM);
   4593    };
   4594 
   4595    /**
   4596    * @param {number} target
   4597    * @param {number} level
   4598    * @param {number} internalFormat
   4599    * @param {number} x
   4600    * @param {number} y
   4601    * @param {number} width
   4602    * @param {number} height
   4603    * @param {number} border
   4604    */
   4605    sglrReferenceContext.ReferenceContext.prototype.copyTexImage2D = function(target, level, internalFormat, x, y, width, height, border) {
   4606        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4607        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
   4608 
   4609        if (this.conditionalSetError(border != 0, gl.INVALID_VALUE))
   4610            return;
   4611        if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE))
   4612            return;
   4613        if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION))
   4614            return;
   4615 
   4616        // Map storage format.
   4617        /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
   4618        if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
   4619            return;
   4620 
   4621        if (target == gl.TEXTURE_2D) {
   4622            // Validate size and level.
   4623            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE))
   4624                return;
   4625            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
   4626                return;
   4627 
   4628            /** @type {sglrReferenceContext.Texture2D} */
   4629            var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
   4630 
   4631            if (texture.isImmutable()) {
   4632                if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
   4633                    return;
   4634 
   4635                /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
   4636                if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION))
   4637                    return;
   4638            } else {
   4639                texture.allocLevel(level, storageFmt, width, height);
   4640            }
   4641 
   4642            // Copy from current framebuffer.
   4643            /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
   4644            for (var yo = 0; yo < height; yo++) {
   4645                for (var xo = 0; xo < width; xo++) {
   4646                    if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
   4647                        continue; // Undefined pixel.
   4648 
   4649                    dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo);
   4650                }
   4651            }
   4652        } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
   4653                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
   4654                   target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
   4655                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
   4656                   target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
   4657                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
   4658            // Validate size and level.
   4659            if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE))
   4660                return;
   4661            if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE))
   4662                return;
   4663 
   4664            /** @type {sglrReferenceContext.TextureCube} */
   4665            var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
   4666            var face = sglrReferenceContext.mapGLCubeFace(target);
   4667 
   4668            if (texture.isImmutable()) {
   4669                if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_OPERATION))
   4670                    return;
   4671 
   4672                /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
   4673                if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION))
   4674                    return;
   4675            } else {
   4676                texture.allocLevel(level, face, storageFmt, width, height);
   4677            }
   4678 
   4679            // Copy from current framebuffer.
   4680            /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
   4681            for (var yo = 0; yo < height; yo++) {
   4682                for (var xo = 0; xo < width; xo++) {
   4683                    if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
   4684                        continue; // Undefined pixel.
   4685 
   4686                    dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo);
   4687                }
   4688            }
   4689        } else {
   4690            this.setError(gl.INVALID_ENUM);
   4691        }
   4692    }
   4693 
   4694    /**
   4695    * @param {number} target
   4696    * @param {number} level
   4697    * @param {number} xoffset
   4698    * @param {number} yoffset
   4699    * @param {number} x
   4700    * @param {number} y
   4701    * @param {number} width
   4702    * @param {number} height
   4703    */
   4704    sglrReferenceContext.ReferenceContext.prototype.copyTexSubImage2D = function(target, level, xoffset, yoffset, x, y, width, height) {
   4705        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4706        /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
   4707 
   4708        if (this.conditionalSetError(xoffset < 0 || yoffset < 0, gl.INVALID_VALUE))
   4709            return;
   4710        if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE))
   4711            return;
   4712        if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION))
   4713            return;
   4714 
   4715        if (target == gl.TEXTURE_2D) {
   4716            /** @type {sglrReferenceContext.Texture2D} */
   4717            var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
   4718 
   4719            if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_VALUE))
   4720                return;
   4721 
   4722            /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
   4723 
   4724            if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE))
   4725                return;
   4726 
   4727            for (var yo = 0; yo < height; yo++) {
   4728                for (var xo = 0; xo < width; xo++) {
   4729                    if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
   4730                        continue;
   4731 
   4732                    dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset);
   4733                }
   4734            }
   4735        } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
   4736                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
   4737                   target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
   4738                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
   4739                   target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
   4740                   target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
   4741            /** @type {sglrReferenceContext.TextureCube} */
   4742            var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
   4743            var face = sglrReferenceContext.mapGLCubeFace(target);
   4744 
   4745            if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_VALUE))
   4746                return;
   4747 
   4748            /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
   4749 
   4750            if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE))
   4751                return;
   4752 
   4753            for (var yo = 0; yo < height; yo++) {
   4754                for (var xo = 0; xo < width; xo++) {
   4755                    if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
   4756                        continue;
   4757 
   4758                    dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset);
   4759                }
   4760            }
   4761        } else {
   4762            this.setError(gl.INVALID_ENUM);
   4763        }
   4764    }
   4765 
   4766    sglrReferenceContext.ReferenceContext.prototype.texStorage3D = function(target, levels, internalFormat, width, height, depth) {
   4767        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4768 
   4769        if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE))
   4770            return;
   4771        if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE))
   4772            return;
   4773 
   4774        // Map storage format.
   4775        /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
   4776        if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
   4777            return;
   4778 
   4779        if (target == gl.TEXTURE_2D_ARRAY) {
   4780            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
   4781                                        height > this.m_limits.maxTexture2DSize ||
   4782                                        depth >= this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
   4783                return;
   4784 
   4785            /** @type {sglrReferenceContext.Texture2DArray} */
   4786            var textureArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
   4787            if (this.conditionalSetError(textureArray.isImmutable(), gl.INVALID_OPERATION))
   4788                return;
   4789 
   4790            textureArray.clearLevels();
   4791            textureArray.setImmutable();
   4792 
   4793            for (var level = 0; level < levels; level++) {
   4794                var levelW = Math.max(1, width >> level);
   4795                var levelH = Math.max(1, height >> level);
   4796 
   4797                textureArray.allocLevel(level, storageFmt, levelW, levelH, depth);
   4798            }
   4799        } else if (target == gl.TEXTURE_3D) {
   4800            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
   4801                                        height > this.m_limits.maxTexture2DSize ||
   4802                                        depth >= this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
   4803                return;
   4804 
   4805            /** @type {sglrReferenceContext.Texture3D} */
   4806            var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
   4807            if (this.conditionalSetError(texture3D.isImmutable(), gl.INVALID_OPERATION))
   4808                return;
   4809 
   4810            texture3D.clearLevels();
   4811            texture3D.setImmutable();
   4812 
   4813            for (var level = 0; level < levels; level++) {
   4814                var levelW = Math.max(1, width >> level);
   4815                var levelH = Math.max(1, height >> level);
   4816                var levelD = Math.max(1, depth >> level);
   4817 
   4818                texture3D.allocLevel(level, storageFmt, levelW, levelH, levelD);
   4819            }
   4820        } else
   4821            this.setError(gl.INVALID_ENUM);
   4822    };
   4823 
   4824    sglrReferenceContext.ReferenceContext.prototype.texStorage2D = function(target, levels, internalFormat, width, height) {
   4825        /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
   4826 
   4827        if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE))
   4828            return;
   4829        if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE))
   4830            return;
   4831 
   4832        // Map storage format.
   4833        /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
   4834        if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
   4835            return;
   4836 
   4837        if (target == gl.TEXTURE_2D) {
   4838            if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE))
   4839                return;
   4840 
   4841                /** @type {sglrReferenceContext.Texture2D} */
   4842            var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
   4843            if (this.conditionalSetError(texture.isImmutable(), gl.INVALID_OPERATION))
   4844                return;
   4845 
   4846            texture.clearLevels();
   4847            texture.setImmutable();
   4848 
   4849            for (var level = 0; level < levels; level++) {
   4850                var levelW = Math.max(1, width >> level);
   4851                var levelH = Math.max(1, height >> level);
   4852 
   4853                texture.allocLevel(level, storageFmt, levelW, levelH);
   4854            }
   4855        } else if (target == gl.TEXTURE_CUBE_MAP) {
   4856            if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE))
   4857                return;
   4858            var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
   4859            if (this.conditionalSetError(textureCube.isImmutable(), gl.INVALID_OPERATION))
   4860                return;
   4861 
   4862            textureCube.clearLevels();
   4863            textureCube.setImmutable();
   4864 
   4865            for (var level = 0; level < levels; level++) {
   4866                var levelW = Math.max(1, width >> level);
   4867                var levelH = Math.max(1, height >> level);
   4868 
   4869                for (var face in tcuTexture.CubeFace)
   4870                    textureCube.allocLevel(level, tcuTexture.CubeFace[face], storageFmt, levelW, levelH);
   4871            }
   4872        } else
   4873            this.setError(gl.INVALID_ENUM);
   4874    };
   4875 
   4876    /**
   4877     * @param {number} value
   4878     * @return {?tcuTexture.WrapMode}
   4879     */
   4880    sglrReferenceContext.mapGLWrapMode = function(value) {
   4881        switch (value) {
   4882            case gl.CLAMP_TO_EDGE: return tcuTexture.WrapMode.CLAMP_TO_EDGE;
   4883            case gl.REPEAT: return tcuTexture.WrapMode.REPEAT_GL;
   4884            case gl.MIRRORED_REPEAT: return tcuTexture.WrapMode.MIRRORED_REPEAT_GL;
   4885        }
   4886        return null;
   4887    };
   4888 
   4889     /**
   4890     * @param {number} value
   4891     * @return {?tcuTexture.FilterMode}
   4892     */
   4893    sglrReferenceContext.mapGLFilterMode = function(value) {
   4894        switch (value) {
   4895            case gl.NEAREST: return tcuTexture.FilterMode.NEAREST;
   4896            case gl.LINEAR: return tcuTexture.FilterMode.LINEAR;
   4897            case gl.NEAREST_MIPMAP_NEAREST: return tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST;
   4898            case gl.NEAREST_MIPMAP_LINEAR: return tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR;
   4899            case gl.LINEAR_MIPMAP_NEAREST: return tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST;
   4900            case gl.LINEAR_MIPMAP_LINEAR: return tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR;
   4901        }
   4902        return null;
   4903    };
   4904 
   4905    /**
   4906    * @param {number} target
   4907    * @param {number} pname
   4908    * @param {number} value
   4909    */
   4910    sglrReferenceContext.ReferenceContext.prototype.texParameteri = function(target, pname, value) {
   4911        /** @type {sglrReferenceContext.TextureUnit} */ var unit = this.m_textureUnits[this.m_activeTexture];
   4912        /** @type {sglrReferenceContext.TextureContainer} */ var container = null;
   4913 
   4914        switch (target) {
   4915            case gl.TEXTURE_2D: container = unit.tex2DBinding; break;
   4916            case gl.TEXTURE_CUBE_MAP: container = unit.texCubeBinding; break;
   4917            case gl.TEXTURE_2D_ARRAY: container = unit.tex2DArrayBinding; break;
   4918            case gl.TEXTURE_3D: container = unit.tex3DBinding; break;
   4919 
   4920            default: this.setError(gl.INVALID_ENUM);
   4921        }
   4922 
   4923        if (!container)
   4924            return;
   4925 
   4926        /** @type {sglrReferenceContext.Texture} */
   4927        var texture = container.texture;
   4928 
   4929        switch (pname) {
   4930            case gl.TEXTURE_WRAP_S: {
   4931                /** @type {?tcuTexture.WrapMode} */ var wrapS = sglrReferenceContext.mapGLWrapMode(value);
   4932                if (this.conditionalSetError(null == wrapS, gl.INVALID_VALUE))
   4933                    return;
   4934                texture.getSampler().wrapS = /** @type {tcuTexture.WrapMode} */ (wrapS);
   4935                break;
   4936            }
   4937 
   4938            case gl.TEXTURE_WRAP_T: {
   4939                /** @type {?tcuTexture.WrapMode} */ var wrapT = sglrReferenceContext.mapGLWrapMode(value);
   4940                if (this.conditionalSetError(null == wrapT, gl.INVALID_VALUE))
   4941                    return;
   4942                texture.getSampler().wrapT = /** @type {tcuTexture.WrapMode} */ (wrapT);
   4943                break;
   4944            }
   4945 
   4946            case gl.TEXTURE_WRAP_R: {
   4947                /** @type {?tcuTexture.WrapMode} */ var wrapR = sglrReferenceContext.mapGLWrapMode(value);
   4948                if (this.conditionalSetError(null == wrapR, gl.INVALID_VALUE))
   4949                    return;
   4950                texture.getSampler().wrapR = /** @type {tcuTexture.WrapMode} */ (wrapR);
   4951                break;
   4952            }
   4953 
   4954            case gl.TEXTURE_MIN_FILTER: {
   4955                /** @type {?tcuTexture.FilterMode} */ var minMode = sglrReferenceContext.mapGLFilterMode(value);
   4956                if (this.conditionalSetError(null == minMode, gl.INVALID_VALUE))
   4957                    return;
   4958                texture.getSampler().minFilter = /** @type {tcuTexture.FilterMode} */ (minMode);
   4959                break;
   4960            }
   4961 
   4962            case gl.TEXTURE_MAG_FILTER: {
   4963                /** @type {?tcuTexture.FilterMode} */ var magMode = sglrReferenceContext.mapGLFilterMode(value);
   4964                if (this.conditionalSetError(null == magMode, gl.INVALID_VALUE))
   4965                    return;
   4966                texture.getSampler().magFilter = /** @type {tcuTexture.FilterMode} */ (magMode);
   4967                break;
   4968            }
   4969 
   4970            case gl.TEXTURE_MAX_LEVEL: {
   4971                if (this.conditionalSetError(value < 0, gl.INVALID_VALUE))
   4972                    return;
   4973                texture.setMaxLevel(value);
   4974                break;
   4975            }
   4976 
   4977            default:
   4978                this.setError(gl.INVALID_ENUM);
   4979                return;
   4980        }
   4981    };
   4982 
   4983    sglrReferenceContext.ReferenceContext.prototype.invalidateFramebuffer = function(target, attachments) {};
   4984    sglrReferenceContext.ReferenceContext.prototype.invalidateSubFramebuffer = function(target, attachments, x, y, width, height) {};
   4985 
   4986 });