tor-browser

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

tcuTexture.js (145714B)


      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.common.tcuTexture');
     23 goog.require('framework.common.tcuFloat');
     24 goog.require('framework.delibs.debase.deMath');
     25 goog.require('framework.delibs.debase.deString');
     26 goog.require('framework.delibs.debase.deUtil');
     27 
     28 goog.scope(function() {
     29 
     30 var tcuTexture = framework.common.tcuTexture;
     31 var deMath = framework.delibs.debase.deMath;
     32 var tcuFloat = framework.common.tcuFloat;
     33 var deString = framework.delibs.debase.deString;
     34 var deUtil = framework.delibs.debase.deUtil;
     35 
     36 var DE_ASSERT = function(x) {
     37    if (!x)
     38        throw new Error('Assert failed');
     39 };
     40 
     41 /**
     42 * Texture tcuTexture.channel order
     43 * @enum
     44 */
     45 tcuTexture.ChannelOrder = {
     46    R: 0,
     47    A: 1,
     48    I: 2,
     49    L: 3,
     50    LA: 4,
     51    RG: 5,
     52    RA: 6,
     53    RGB: 7,
     54    RGBA: 8,
     55    ARGB: 9,
     56    BGRA: 10,
     57 
     58    sRGB: 11,
     59    sRGBA: 12,
     60 
     61    D: 13,
     62    S: 14,
     63    DS: 15
     64 };
     65 
     66 /**
     67 * Texture tcuTexture.channel type
     68 * @enum
     69 */
     70 tcuTexture.ChannelType = {
     71    SNORM_INT8: 0,
     72    SNORM_INT16: 1,
     73    SNORM_INT32: 2,
     74    UNORM_INT8: 3,
     75    UNORM_INT16: 4,
     76    UNORM_INT32: 5,
     77    UNORM_SHORT_565: 6,
     78    UNORM_SHORT_555: 7,
     79    UNORM_SHORT_4444: 8,
     80    UNORM_SHORT_5551: 9,
     81    UNORM_INT_101010: 10,
     82    UNORM_INT_1010102_REV: 11,
     83    UNSIGNED_INT_1010102_REV: 12,
     84    UNSIGNED_INT_11F_11F_10F_REV: 13,
     85    UNSIGNED_INT_999_E5_REV: 14,
     86    UNSIGNED_INT_24_8: 15,
     87    SIGNED_INT8: 16,
     88    SIGNED_INT16: 17,
     89    SIGNED_INT32: 18,
     90    UNSIGNED_INT8: 19,
     91    UNSIGNED_INT16: 20,
     92    UNSIGNED_INT32: 21,
     93    HALF_FLOAT: 22,
     94    FLOAT: 23,
     95    FLOAT_UNSIGNED_INT_24_8_REV: 24
     96 };
     97 
     98 /**
     99 * Enums for tcuTexture.TextureChannelClass
    100 * @enum {number}
    101 */
    102 tcuTexture.TextureChannelClass = {
    103 
    104    SIGNED_FIXED_POINT: 0,
    105    UNSIGNED_FIXED_POINT: 1,
    106    SIGNED_INTEGER: 2,
    107    UNSIGNED_INTEGER: 3,
    108    FLOATING_POINT: 4
    109 };
    110 
    111 /**
    112 * @param {?tcuTexture.ChannelType} channelType
    113 * @return {tcuTexture.TextureChannelClass}
    114 */
    115 tcuTexture.getTextureChannelClass = function(channelType) {
    116 
    117    switch (channelType) {
    118        case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
    119        case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
    120        case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    121        case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    122        case tcuTexture.ChannelType.UNORM_SHORT_565: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    123        case tcuTexture.ChannelType.UNORM_SHORT_555: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    124        case tcuTexture.ChannelType.UNORM_SHORT_4444: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    125        case tcuTexture.ChannelType.UNORM_SHORT_5551: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    126        case tcuTexture.ChannelType.UNORM_INT_101010: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    127        case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
    128        case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
    129        case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT;
    130        case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT;
    131        case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
    132        case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
    133        case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
    134        case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
    135        case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
    136        case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
    137        case tcuTexture.ChannelType.HALF_FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT;
    138        case tcuTexture.ChannelType.FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT;
    139        default: return /** @type {tcuTexture.TextureChannelClass<number>} */ (Object.keys(tcuTexture.ChannelType).length);
    140    }
    141 };
    142 
    143 /**
    144 * @param {tcuTexture.TextureFormat} format
    145 */
    146 tcuTexture.isFixedPointDepthTextureFormat = function(format) {
    147    var channelClass = tcuTexture.getTextureChannelClass(format.type);
    148 
    149    if (format.order == tcuTexture.ChannelOrder.D) {
    150        // depth internal formats cannot be non-normalized integers
    151        return channelClass != tcuTexture.TextureChannelClass.FLOATING_POINT;
    152    } else if (format.order == tcuTexture.ChannelOrder.DS) {
    153        // combined formats have no single channel class, detect format manually
    154        switch (format.type) {
    155            case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return false;
    156            case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return true;
    157 
    158            default:
    159                // unknown format
    160                DE_ASSERT(false);
    161                return true;
    162        }
    163    }
    164    return false;
    165 };
    166 
    167 /**
    168 * @param {Array<number>} color
    169 * @param {tcuTexture.CompareMode} compare
    170 * @param {number} chanNdx
    171 * @param {number} ref_
    172 * @param {boolean} isFixedPoint
    173 */
    174 tcuTexture.execCompare = function(color, compare, chanNdx, ref_, isFixedPoint) {
    175    var clampValues = isFixedPoint;
    176    var cmp = clampValues ? deMath.clamp(color[chanNdx], 0.0, 1.0) : color[chanNdx];
    177    var ref = clampValues ? deMath.clamp(ref_, 0.0, 1.0) : ref_;
    178    var res = false;
    179 
    180    switch (compare) {
    181        case tcuTexture.CompareMode.COMPAREMODE_LESS: res = ref < cmp; break;
    182        case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL: res = ref <= cmp; break;
    183        case tcuTexture.CompareMode.COMPAREMODE_GREATER: res = ref > cmp; break;
    184        case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL: res = ref >= cmp; break;
    185        case tcuTexture.CompareMode.COMPAREMODE_EQUAL: res = ref == cmp; break;
    186        case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL: res = ref != cmp; break;
    187        case tcuTexture.CompareMode.COMPAREMODE_ALWAYS: res = true; break;
    188        case tcuTexture.CompareMode.COMPAREMODE_NEVER: res = false; break;
    189        default:
    190            DE_ASSERT(false);
    191    }
    192 
    193    return res ? 1.0 : 0.0;
    194 };
    195 
    196 /**
    197 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
    198 * @param {number} numLevels
    199 * @param {tcuTexture.Sampler} sampler
    200 * @param {number} ref
    201 * @param {number} s
    202 * @param {number} t
    203 * @param {number} lod
    204 * @param {Array<number>} offset
    205 */
    206 tcuTexture.sampleLevelArray2DCompare = function(levels, numLevels, sampler, ref, s, t, lod, offset) {
    207    var magnified = lod <= sampler.lodThreshold;
    208    var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
    209 
    210    switch (filterMode) {
    211        case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
    212        case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
    213 
    214        case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
    215        case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
    216            var maxLevel = numLevels - 1;
    217            var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
    218            var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
    219 
    220            return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
    221        }
    222 
    223        case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
    224        case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
    225            var maxLevel = numLevels - 1;
    226            var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
    227            var level1 = Math.min(maxLevel, level0 + 1);
    228            var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
    229            var f = deMath.deFloatFrac(lod);
    230            var t0 = levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
    231            var t1 = levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
    232 
    233            return t0 * (1.0 - f) + t1 * f;
    234        }
    235 
    236        default:
    237            DE_ASSERT(false);
    238            return 0.0;
    239    }
    240 };
    241 
    242 /**
    243 * @param {tcuTexture.ConstPixelBufferAccess} access
    244 * @param {tcuTexture.Sampler} sampler
    245 * @param {number} ref
    246 * @param {number} u
    247 * @param {number} v
    248 * @param {Array<number>} offset
    249 * @param {boolean} isFixedPointDepthFormat
    250 * @return {number}
    251 */
    252 tcuTexture.sampleLinear2DCompare = function(access, sampler, ref, u, v, offset, isFixedPointDepthFormat) {
    253    var w = access.getWidth();
    254    var h = access.getHeight();
    255 
    256    var x0 = Math.floor(u - 0.5) + offset[0];
    257    var x1 = x0 + 1;
    258    var y0 = Math.floor(v - 0.5) + offset[1];
    259    var y1 = y0 + 1;
    260 
    261    var i0 = tcuTexture.wrap(sampler.wrapS, x0, w);
    262    var i1 = tcuTexture.wrap(sampler.wrapS, x1, w);
    263    var j0 = tcuTexture.wrap(sampler.wrapT, y0, h);
    264    var j1 = tcuTexture.wrap(sampler.wrapT, y1, h);
    265 
    266    var a = deMath.deFloatFrac(u - 0.5);
    267    var b = deMath.deFloatFrac(v - 0.5);
    268 
    269    var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w);
    270    var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w);
    271    var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h);
    272    var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h);
    273 
    274    // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
    275    var p00Clr = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, offset[2]);
    276    var p10Clr = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, offset[2]);
    277    var p01Clr = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, offset[2]);
    278    var p11Clr = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, offset[2]);
    279 
    280    // Execute comparisons.
    281    var p00 = tcuTexture.execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
    282    var p10 = tcuTexture.execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
    283    var p01 = tcuTexture.execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
    284    var p11 = tcuTexture.execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
    285 
    286    // Interpolate.
    287    return (p00 * (1.0 - a) * (1.0 - b)) +
    288           (p10 * (a) * (1.0 - b)) +
    289           (p01 * (1.0 - a) * (b)) +
    290           (p11 * (a) * (b));
    291 };
    292 
    293 /**
    294 * Construct texture format
    295 * @param {?tcuTexture.ChannelOrder} order
    296 * @param {?tcuTexture.ChannelType} type
    297 *
    298 * @constructor
    299 */
    300 tcuTexture.TextureFormat = function(order, type) {
    301    this.order = order;
    302    this.type = type;
    303 };
    304 
    305 /**
    306 * Compare two formats
    307 * @param {tcuTexture.TextureFormat} format Format to compare with
    308 * @return {boolean}
    309 */
    310 tcuTexture.TextureFormat.prototype.isEqual = function(format) {
    311    return this.order === format.order && this.type === format.type;
    312 };
    313 
    314 tcuTexture.TextureFormat.prototype.toString = function() {
    315    return 'TextureFormat(' + deString.enumToString(tcuTexture.ChannelOrder, this.order) + ', ' +
    316        deString.enumToString(tcuTexture.ChannelType, this.type) + ')';
    317 };
    318 
    319 /**
    320 * Is format sRGB?
    321 * @return {boolean}
    322 */
    323 tcuTexture.TextureFormat.prototype.isSRGB = function() {
    324    return this.order === tcuTexture.ChannelOrder.sRGB || this.order === tcuTexture.ChannelOrder.sRGBA;
    325 };
    326 
    327 tcuTexture.TextureFormat.prototype.getNumStencilBits = function() {
    328    switch (this.order) {
    329        case tcuTexture.ChannelOrder.S:
    330            switch (this.type) {
    331                case tcuTexture.ChannelType.UNSIGNED_INT8: return 8;
    332                case tcuTexture.ChannelType.UNSIGNED_INT16: return 16;
    333                case tcuTexture.ChannelType.UNSIGNED_INT32: return 32;
    334                default:
    335                    throw new Error('Wrong type: ' + this.type);
    336            }
    337 
    338        case tcuTexture.ChannelOrder.DS:
    339            switch (this.type) {
    340                case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return 8;
    341                case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return 8;
    342                default:
    343                    throw new Error('Wrong type: ' + this.type);
    344            }
    345 
    346        default:
    347            throw new Error('Wrong order: ' + this.order);
    348    }
    349 };
    350 
    351 /**
    352 * Get TypedArray type that can be used to access texture.
    353 * @param {?tcuTexture.ChannelType} type
    354 * @return TypedArray that supports the tcuTexture.channel type.
    355 */
    356 tcuTexture.getTypedArray = function(type) {
    357    switch (type) {
    358        case tcuTexture.ChannelType.SNORM_INT8: return Int8Array;
    359        case tcuTexture.ChannelType.SNORM_INT16: return Int16Array;
    360        case tcuTexture.ChannelType.SNORM_INT32: return Int32Array;
    361        case tcuTexture.ChannelType.UNORM_INT8: return Uint8Array;
    362        case tcuTexture.ChannelType.UNORM_INT16: return Uint16Array;
    363        case tcuTexture.ChannelType.UNORM_INT32: return Uint32Array;
    364        case tcuTexture.ChannelType.UNORM_SHORT_565: return Uint16Array;
    365        case tcuTexture.ChannelType.UNORM_SHORT_555: return Uint16Array;
    366        case tcuTexture.ChannelType.UNORM_SHORT_4444: return Uint16Array;
    367        case tcuTexture.ChannelType.UNORM_SHORT_5551: return Uint16Array;
    368        case tcuTexture.ChannelType.UNORM_INT_101010: return Uint32Array;
    369        case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return Uint32Array;
    370        case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return Uint32Array;
    371        case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return Uint32Array;
    372        case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return Uint32Array;
    373        case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return Uint32Array;
    374        case tcuTexture.ChannelType.FLOAT: return Float32Array;
    375        case tcuTexture.ChannelType.SIGNED_INT8: return Int8Array;
    376        case tcuTexture.ChannelType.SIGNED_INT16: return Int16Array;
    377        case tcuTexture.ChannelType.SIGNED_INT32: return Int32Array;
    378        case tcuTexture.ChannelType.UNSIGNED_INT8: return Uint8Array;
    379        case tcuTexture.ChannelType.UNSIGNED_INT16: return Uint16Array;
    380        case tcuTexture.ChannelType.UNSIGNED_INT32: return Uint32Array;
    381        case tcuTexture.ChannelType.HALF_FLOAT: return Uint16Array;
    382        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return Float32Array; /* this type is a special case */
    383    }
    384 
    385    throw new Error('Unrecognized type ' + type);
    386 };
    387 
    388 /**
    389 * @return {number} pixel size in bytes
    390 */
    391 tcuTexture.TextureFormat.prototype.getPixelSize = function() {
    392    if (this.type == null || this.order == null) {
    393        // Invalid/empty format.
    394        return 0;
    395    } else if (this.type == tcuTexture.ChannelType.UNORM_SHORT_565 ||
    396             this.type == tcuTexture.ChannelType.UNORM_SHORT_555 ||
    397             this.type == tcuTexture.ChannelType.UNORM_SHORT_4444 ||
    398             this.type == tcuTexture.ChannelType.UNORM_SHORT_5551) {
    399        DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB || this.order == tcuTexture.ChannelOrder.RGBA);
    400        return 2;
    401    } else if (this.type == tcuTexture.ChannelType.UNORM_INT_101010 ||
    402             this.type == tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV ||
    403             this.type == tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV) {
    404        DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB);
    405        return 4;
    406    } else if (this.type == tcuTexture.ChannelType.UNORM_INT_1010102_REV ||
    407             this.type == tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV) {
    408        DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGBA);
    409        return 4;
    410    } else if (this.type == tcuTexture.ChannelType.UNSIGNED_INT_24_8) {
    411        DE_ASSERT(this.order == tcuTexture.ChannelOrder.D || this.order == tcuTexture.ChannelOrder.DS);
    412        return 4;
    413    } else if (this.type == tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV) {
    414        DE_ASSERT(this.order == tcuTexture.ChannelOrder.DS);
    415        return 8;
    416    } else {
    417        var numChannels;
    418        var channelSize;
    419 
    420        switch (this.order) {
    421            case tcuTexture.ChannelOrder.R: numChannels = 1; break;
    422            case tcuTexture.ChannelOrder.A: numChannels = 1; break;
    423            case tcuTexture.ChannelOrder.I: numChannels = 1; break;
    424            case tcuTexture.ChannelOrder.L: numChannels = 1; break;
    425            case tcuTexture.ChannelOrder.LA: numChannels = 2; break;
    426            case tcuTexture.ChannelOrder.RG: numChannels = 2; break;
    427            case tcuTexture.ChannelOrder.RA: numChannels = 2; break;
    428            case tcuTexture.ChannelOrder.RGB: numChannels = 3; break;
    429            case tcuTexture.ChannelOrder.RGBA: numChannels = 4; break;
    430            case tcuTexture.ChannelOrder.ARGB: numChannels = 4; break;
    431            case tcuTexture.ChannelOrder.BGRA: numChannels = 4; break;
    432            case tcuTexture.ChannelOrder.sRGB: numChannels = 3; break;
    433            case tcuTexture.ChannelOrder.sRGBA: numChannels = 4; break;
    434            case tcuTexture.ChannelOrder.D: numChannels = 1; break;
    435            case tcuTexture.ChannelOrder.S: numChannels = 1; break;
    436            case tcuTexture.ChannelOrder.DS: numChannels = 2; break;
    437            default: DE_ASSERT(false);
    438        }
    439 
    440        switch (this.type) {
    441            case tcuTexture.ChannelType.SNORM_INT8: channelSize = 1; break;
    442            case tcuTexture.ChannelType.SNORM_INT16: channelSize = 2; break;
    443            case tcuTexture.ChannelType.SNORM_INT32: channelSize = 4; break;
    444            case tcuTexture.ChannelType.UNORM_INT8: channelSize = 1; break;
    445            case tcuTexture.ChannelType.UNORM_INT16: channelSize = 2; break;
    446            case tcuTexture.ChannelType.UNORM_INT32: channelSize = 4; break;
    447            case tcuTexture.ChannelType.SIGNED_INT8: channelSize = 1; break;
    448            case tcuTexture.ChannelType.SIGNED_INT16: channelSize = 2; break;
    449            case tcuTexture.ChannelType.SIGNED_INT32: channelSize = 4; break;
    450            case tcuTexture.ChannelType.UNSIGNED_INT8: channelSize = 1; break;
    451            case tcuTexture.ChannelType.UNSIGNED_INT16: channelSize = 2; break;
    452            case tcuTexture.ChannelType.UNSIGNED_INT32: channelSize = 4; break;
    453            case tcuTexture.ChannelType.HALF_FLOAT: channelSize = 2; break;
    454            case tcuTexture.ChannelType.FLOAT: channelSize = 4; break;
    455            default: DE_ASSERT(false);
    456        }
    457 
    458        return numChannels * channelSize;
    459    }
    460 };
    461 
    462 /**
    463 * @enum
    464 */
    465 tcuTexture.CubeFace = {
    466    CUBEFACE_NEGATIVE_X: 0,
    467    CUBEFACE_POSITIVE_X: 1,
    468    CUBEFACE_NEGATIVE_Y: 2,
    469    CUBEFACE_POSITIVE_Y: 3,
    470    CUBEFACE_NEGATIVE_Z: 4,
    471    CUBEFACE_POSITIVE_Z: 5
    472 };
    473 
    474 /**
    475 * Renamed from ArrayBuffer due to name clash
    476 * Wraps ArrayBuffer.
    477 * @constructor
    478 * @param {number=} numElements
    479 */
    480 tcuTexture.DeqpArrayBuffer = function(numElements) {
    481    if (numElements)
    482        this.m_ptr = new ArrayBuffer(numElements);
    483 };
    484 
    485 /**
    486 * Set array size
    487 * @param {number} numElements Size in bytes
    488 */
    489 tcuTexture.DeqpArrayBuffer.prototype.setStorage = function(numElements) {
    490    this.m_ptr = new ArrayBuffer(numElements);
    491 };
    492 
    493 /**
    494 * @return {number} Buffer size
    495 */
    496 tcuTexture.DeqpArrayBuffer.prototype.size = function() {
    497    if (this.m_ptr)
    498        return this.m_ptr.byteLength;
    499 
    500    return 0;
    501 };
    502 
    503 /**
    504 * Is the buffer empty (zero size)?
    505 * @return {boolean}
    506 */
    507 tcuTexture.DeqpArrayBuffer.prototype.empty = function() {
    508    if (!this.m_ptr)
    509        return true;
    510    return this.size() == 0;
    511 };
    512 
    513 /**
    514 * @enum
    515 * The values are negative to avoid conflict with channels 0 - 3
    516 */
    517 tcuTexture.channel = {
    518    ZERO: -1,
    519    ONE: -2
    520 };
    521 
    522 /**
    523 * @param {tcuTexture.ChannelOrder} order
    524 * @return {Array<Number|tcuTexture.channel>}
    525 */
    526 tcuTexture.getChannelReadMap = function(order) {
    527    switch (order) {
    528    /*static const Channel INV[] = { tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE }; */
    529 
    530    case tcuTexture.ChannelOrder.R: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
    531    case tcuTexture.ChannelOrder.A: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0];
    532    case tcuTexture.ChannelOrder.I: return [0, 0, 0, 0];
    533    case tcuTexture.ChannelOrder.L: return [0, 0, 0, tcuTexture.channel.ONE];
    534    case tcuTexture.ChannelOrder.LA: return [0, 0, 0, 1];
    535    case tcuTexture.ChannelOrder.RG: return [0, 1, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
    536    case tcuTexture.ChannelOrder.RA: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1];
    537    case tcuTexture.ChannelOrder.RGB: return [0, 1, 2, tcuTexture.channel.ONE];
    538    case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3];
    539    case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3];
    540    case tcuTexture.ChannelOrder.ARGB: return [1, 2, 3, 0];
    541    case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2, tcuTexture.channel.ONE];
    542    case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3];
    543    case tcuTexture.ChannelOrder.D: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
    544    case tcuTexture.ChannelOrder.S: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0];
    545    case tcuTexture.ChannelOrder.DS: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1];
    546    }
    547 
    548    throw new Error('Unrecognized order ' + order);
    549 };
    550 
    551 /**
    552 * @param {tcuTexture.ChannelOrder} order
    553 * @return {Array<number>}
    554 */
    555 tcuTexture.getChannelWriteMap = function(order) {
    556    switch (order) {
    557        case tcuTexture.ChannelOrder.R: return [0];
    558        case tcuTexture.ChannelOrder.A: return [3];
    559        case tcuTexture.ChannelOrder.I: return [0];
    560        case tcuTexture.ChannelOrder.L: return [0];
    561        case tcuTexture.ChannelOrder.LA: return [0, 3];
    562        case tcuTexture.ChannelOrder.RG: return [0, 1];
    563        case tcuTexture.ChannelOrder.RA: return [0, 3];
    564        case tcuTexture.ChannelOrder.RGB: return [0, 1, 2];
    565        case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3];
    566        case tcuTexture.ChannelOrder.ARGB: return [3, 0, 1, 2];
    567        case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3];
    568        case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2];
    569        case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3];
    570        case tcuTexture.ChannelOrder.D: return [0];
    571        case tcuTexture.ChannelOrder.S: return [3];
    572        case tcuTexture.ChannelOrder.DS: return [0, 3];
    573    }
    574    throw new Error('Unrecognized order ' + order);
    575 };
    576 
    577 /**
    578 * @param {tcuTexture.ChannelType} type
    579 * @return {number}
    580 */
    581 tcuTexture.getChannelSize = function(type) {
    582    switch (type) {
    583        case tcuTexture.ChannelType.SNORM_INT8: return 1;
    584        case tcuTexture.ChannelType.SNORM_INT16: return 2;
    585        case tcuTexture.ChannelType.SNORM_INT32: return 4;
    586        case tcuTexture.ChannelType.UNORM_INT8: return 1;
    587        case tcuTexture.ChannelType.UNORM_INT16: return 2;
    588        case tcuTexture.ChannelType.UNORM_INT32: return 4;
    589        case tcuTexture.ChannelType.SIGNED_INT8: return 1;
    590        case tcuTexture.ChannelType.SIGNED_INT16: return 2;
    591        case tcuTexture.ChannelType.SIGNED_INT32: return 4;
    592        case tcuTexture.ChannelType.UNSIGNED_INT8: return 1;
    593        case tcuTexture.ChannelType.UNSIGNED_INT16: return 2;
    594        case tcuTexture.ChannelType.UNSIGNED_INT32: return 4;
    595        case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return 4;
    596        case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return 4;
    597        case tcuTexture.ChannelType.HALF_FLOAT: return 2;
    598        case tcuTexture.ChannelType.FLOAT: return 4;
    599 
    600    }
    601    throw new Error('Unrecognized type ' + deString.enumToString(tcuTexture.ChannelType, type));
    602 };
    603 
    604 /**
    605 * @param {number} src Source value
    606 * @param {number} bits Source value size in bits
    607 * @return {number} Normalized value
    608 */
    609 tcuTexture.channelToNormFloat = function(src, bits) {
    610    var maxVal = (1 << bits) - 1;
    611    return src / maxVal;
    612 };
    613 
    614 /**
    615 * @param {number} value Source value
    616 * @param {tcuTexture.ChannelType} type
    617 * @return {number} Source value converted to float
    618 */
    619 tcuTexture.channelToFloat = function(value, type) {
    620    switch (type) {
    621        case tcuTexture.ChannelType.SNORM_INT8: return Math.max(-1, value / 127);
    622        case tcuTexture.ChannelType.SNORM_INT16: return Math.max(-1, value / 32767);
    623        case tcuTexture.ChannelType.SNORM_INT32: return Math.max(-1, value / 2147483647);
    624        case tcuTexture.ChannelType.UNORM_INT8: return value / 255;
    625        case tcuTexture.ChannelType.UNORM_INT16: return value / 65535;
    626        case tcuTexture.ChannelType.UNORM_INT32: return value / 4294967295;
    627        case tcuTexture.ChannelType.SIGNED_INT8: return value;
    628        case tcuTexture.ChannelType.SIGNED_INT16: return value;
    629        case tcuTexture.ChannelType.SIGNED_INT32: return value;
    630        case tcuTexture.ChannelType.UNSIGNED_INT8: return value;
    631        case tcuTexture.ChannelType.UNSIGNED_INT16: return value;
    632        case tcuTexture.ChannelType.UNSIGNED_INT32: return value;
    633        case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.halfFloatToNumber(value);
    634        case tcuTexture.ChannelType.FLOAT: return value;
    635    }
    636    throw new Error('Unrecognized tcuTexture.channel type ' + type);
    637 };
    638 
    639 /**
    640 * @param {number} value Source value
    641 * @param {tcuTexture.ChannelType} type
    642 * @return {number} Source value converted to int
    643 */
    644 tcuTexture.channelToInt = function(value, type) {
    645    switch (type) {
    646        case tcuTexture.ChannelType.HALF_FLOAT: return Math.round(tcuFloat.halfFloatToNumber(value));
    647        case tcuTexture.ChannelType.FLOAT: return Math.round(value);
    648        default:
    649            return value;
    650    }
    651 };
    652 
    653 /**
    654 * @param {tcuTexture.ChannelOrder} order
    655 * @return {number}
    656 */
    657 tcuTexture.getNumUsedChannels = function(order) {
    658    switch (order) {
    659        case tcuTexture.ChannelOrder.R: return 1;
    660        case tcuTexture.ChannelOrder.A: return 1;
    661        case tcuTexture.ChannelOrder.I: return 1;
    662        case tcuTexture.ChannelOrder.L: return 1;
    663        case tcuTexture.ChannelOrder.LA: return 2;
    664        case tcuTexture.ChannelOrder.RG: return 2;
    665        case tcuTexture.ChannelOrder.RA: return 2;
    666        case tcuTexture.ChannelOrder.RGB: return 3;
    667        case tcuTexture.ChannelOrder.RGBA: return 4;
    668        case tcuTexture.ChannelOrder.ARGB: return 4;
    669        case tcuTexture.ChannelOrder.BGRA: return 4;
    670        case tcuTexture.ChannelOrder.sRGB: return 3;
    671        case tcuTexture.ChannelOrder.sRGBA: return 4;
    672        case tcuTexture.ChannelOrder.D: return 1;
    673        case tcuTexture.ChannelOrder.S: return 1;
    674        case tcuTexture.ChannelOrder.DS: return 2;
    675    }
    676    throw new Error('Unrecognized tcuTexture.channel order ' + order);
    677 };
    678 
    679 /**
    680 * @enum
    681 */
    682 tcuTexture.WrapMode = {
    683    CLAMP_TO_EDGE: 0, //! Clamp to edge
    684    CLAMP_TO_BORDER: 1, //! Use border color at edge
    685    REPEAT_GL: 2, //! Repeat with OpenGL semantics
    686    REPEAT_CL: 3, //! Repeat with OpenCL semantics
    687    MIRRORED_REPEAT_GL: 4, //! Mirrored repeat with OpenGL semantics
    688    MIRRORED_REPEAT_CL: 5 //! Mirrored repeat with OpenCL semantics
    689 };
    690 
    691 /**
    692 * @enum
    693 */
    694 tcuTexture.FilterMode = {
    695    NEAREST: 0,
    696    LINEAR: 1,
    697 
    698    NEAREST_MIPMAP_NEAREST: 2,
    699    NEAREST_MIPMAP_LINEAR: 3,
    700    LINEAR_MIPMAP_NEAREST: 4,
    701    LINEAR_MIPMAP_LINEAR: 5
    702 };
    703 
    704 /**
    705 * @enum
    706 */
    707 tcuTexture.CompareMode = {
    708    COMPAREMODE_NONE: 0,
    709    COMPAREMODE_LESS: 1,
    710    COMPAREMODE_LESS_OR_EQUAL: 2,
    711    COMPAREMODE_GREATER: 3,
    712    COMPAREMODE_GREATER_OR_EQUAL: 4,
    713    COMPAREMODE_EQUAL: 5,
    714    COMPAREMODE_NOT_EQUAL: 6,
    715    COMPAREMODE_ALWAYS: 7,
    716    COMPAREMODE_NEVER: 8
    717 };
    718 
    719 /**
    720 * @constructor
    721 * @param {!tcuTexture.WrapMode} wrapS
    722 * @param {!tcuTexture.WrapMode} wrapT
    723 * @param {!tcuTexture.WrapMode} wrapR
    724 * @param {!tcuTexture.FilterMode} minFilter
    725 * @param {!tcuTexture.FilterMode} magFilter
    726 * @param {number=} lodThreshold
    727 * @param {boolean=} normalizedCoords
    728 * @param {tcuTexture.CompareMode=} compare
    729 * @param {number=} compareChannel
    730 * @param {Array<number>=} borderColor
    731 * @param {boolean=} seamlessCubeMap
    732 */
    733 tcuTexture.Sampler = function(wrapS, wrapT, wrapR, minFilter, magFilter, lodThreshold, normalizedCoords, compare, compareChannel, borderColor, seamlessCubeMap) {
    734    /** @type {!tcuTexture.WrapMode} */ this.wrapS = wrapS;
    735    /** @type {!tcuTexture.WrapMode} */ this.wrapT = wrapT;
    736    /** @type {!tcuTexture.WrapMode} */ this.wrapR = wrapR;
    737    /** @type {!tcuTexture.FilterMode} */ this.minFilter = minFilter;
    738    /** @type {!tcuTexture.FilterMode} */ this.magFilter = magFilter;
    739    this.lodThreshold = lodThreshold || 0;
    740    this.normalizedCoords = normalizedCoords === undefined ? true : normalizedCoords;
    741    /** @type {tcuTexture.CompareMode} */ this.compare = compare || tcuTexture.CompareMode.COMPAREMODE_NONE;
    742    this.compareChannel = compareChannel || 0;
    743    this.borderColor = borderColor || [0, 0, 0, 0];
    744    this.seamlessCubeMap = seamlessCubeMap || false;
    745 };
    746 
    747 /**
    748 * Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL tcuTexture.wrap modes; otherwise ordinary unnormalization.
    749 * @param {tcuTexture.WrapMode} mode
    750 * @param {number} c Value to tcuTexture.unnormalize
    751 * @param {number} size Unnormalized type size (integer)
    752 * @return {number}
    753 */
    754 tcuTexture.unnormalize = function(mode, c, size) {
    755    switch (mode) {
    756        case tcuTexture.WrapMode.CLAMP_TO_EDGE:
    757        case tcuTexture.WrapMode.CLAMP_TO_BORDER:
    758        case tcuTexture.WrapMode.REPEAT_GL:
    759        case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: // Fall-through (ordinary case).
    760            return size * c;
    761 
    762        case tcuTexture.WrapMode.REPEAT_CL:
    763            return size * (c - Math.floor(c));
    764 
    765        case tcuTexture.WrapMode.MIRRORED_REPEAT_CL:
    766            return size * Math.abs(c - 2 * deMath.rint(0.5 * c));
    767    }
    768    throw new Error('Unrecognized tcuTexture.wrap mode ' + mode);
    769 };
    770 
    771 /**
    772 * @param {tcuTexture.WrapMode} mode
    773 * @param {number} c Source value (integer)
    774 * @param {number} size Type size (integer)
    775 * @return {number}
    776 */
    777 tcuTexture.wrap = function(mode, c, size) {
    778    switch (mode) {
    779        case tcuTexture.WrapMode.CLAMP_TO_BORDER:
    780            return deMath.clamp(c, -1, size);
    781 
    782        case tcuTexture.WrapMode.CLAMP_TO_EDGE:
    783            return deMath.clamp(c, 0, size - 1);
    784 
    785        case tcuTexture.WrapMode.REPEAT_GL:
    786            return deMath.imod(c, size);
    787 
    788        case tcuTexture.WrapMode.REPEAT_CL:
    789            return deMath.imod(c, size);
    790 
    791        case tcuTexture.WrapMode.MIRRORED_REPEAT_GL:
    792            return (size - 1) - deMath.mirror(deMath.imod(c, 2 * size) - size);
    793 
    794        case tcuTexture.WrapMode.MIRRORED_REPEAT_CL:
    795            return deMath.clamp(c, 0, size - 1); // \note Actual mirroring done already in unnormalization function.
    796    }
    797    throw new Error('Unrecognized tcuTexture.wrap mode ' + mode);
    798 };
    799 
    800 /**
    801 * @param {number} cs
    802 * @return {number}
    803 */
    804 tcuTexture.sRGBChannelToLinear = function(cs) {
    805    if (cs <= 0.04045)
    806        return cs / 12.92;
    807    else
    808        return Math.pow((cs + 0.055) / 1.055, 2.4);
    809 };
    810 
    811 /**
    812 * Convert sRGB to linear colorspace
    813 * @param {Array<number>} cs Vec4
    814 * @return {Array<number>} Vec4
    815 */
    816 tcuTexture.sRGBToLinear = function(cs) {
    817    return [
    818        tcuTexture.sRGBChannelToLinear(cs[0]),
    819        tcuTexture.sRGBChannelToLinear(cs[1]),
    820        tcuTexture.sRGBChannelToLinear(cs[2]),
    821        cs[3]
    822        ];
    823 };
    824 
    825 /**
    826 * Texel tcuTexture.lookup with color conversion.
    827 * @param {tcuTexture.ConstPixelBufferAccess} access
    828 * @param {number} i
    829 * @param {number} j
    830 * @param {number} k
    831 * @return {Array<number>} Vec4 pixel color
    832 */
    833 tcuTexture.lookup = function(access, i, j, k) {
    834    var p = access.getPixel(i, j, k);
    835    return access.getFormat().isSRGB() ? tcuTexture.sRGBToLinear(p) : p;
    836 };
    837 
    838 /**
    839 * @param {tcuTexture.ConstPixelBufferAccess} access
    840 * @param {tcuTexture.Sampler} sampler
    841 * @param {number} u
    842 * @param {number} v
    843 * @param {(number|Array<number>)} depthOrOffset depth (int) or offset (ivec3)
    844 * @return {Array<number>} Vec4 pixel color
    845 */
    846 tcuTexture.sampleLinear2D = function(access, sampler, u, v, depthOrOffset) {
    847    /** @type {number} */ var xOffset = 0;
    848    /** @type {number} */ var yOffset = 0;
    849    /** @type {number} */ var value;
    850    if (Array.isArray(depthOrOffset)) {
    851        xOffset = depthOrOffset[0];
    852        yOffset = depthOrOffset[1];
    853        value = depthOrOffset[2];
    854    } else {
    855        value = /** @type {number} */ (depthOrOffset);
    856    }
    857 
    858    /**
    859     * @param {Array<number>} p00
    860     * @param {Array<number>} p10
    861     * @param {Array<number>} p01
    862     * @param {Array<number>} p11
    863     * @param {number} a
    864     * @param {number} b
    865     */
    866    var interpolateQuad = function(p00, p10, p01, p11, a, b) {
    867        var s00 = (1 - a) * (1 - b);
    868        var s10 = a * (1 - b);
    869        var s01 = (1 - a) * b;
    870        var s11 = a * b;
    871 
    872        return [
    873            (p00[0] * s00) + (p10[0] * s10) + (p01[0] * s01) + (p11[0] * s11),
    874            (p00[1] * s00) + (p10[1] * s10) + (p01[1] * s01) + (p11[1] * s11),
    875            (p00[2] * s00) + (p10[2] * s10) + (p01[2] * s01) + (p11[2] * s11),
    876            (p00[3] * s00) + (p10[3] * s10) + (p01[3] * s01) + (p11[3] * s11)
    877        ];
    878    };
    879 
    880    var w = access.getWidth();
    881    var h = access.getHeight();
    882 
    883    var x0 = Math.floor(u - 0.5) + xOffset;
    884    var x1 = x0 + 1;
    885    var y0 = Math.floor(v - 0.5) + yOffset;
    886    var y1 = y0 + 1;
    887 
    888    var i0 = tcuTexture.wrap(sampler.wrapS, x0, w);
    889    var i1 = tcuTexture.wrap(sampler.wrapS, x1, w);
    890    var j0 = tcuTexture.wrap(sampler.wrapT, y0, h);
    891    var j1 = tcuTexture.wrap(sampler.wrapT, y1, h);
    892 
    893    var a = deMath.deFloatFrac(u - 0.5);
    894    var b = deMath.deFloatFrac(v - 0.5);
    895 
    896    var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w);
    897    var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w);
    898    var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h);
    899    var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h);
    900 
    901    // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
    902    var p00 = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, value);
    903    var p10 = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, value);
    904    var p01 = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, value);
    905    var p11 = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, value);
    906 
    907    // Interpolate.
    908    return interpolateQuad(p00, p10, p01, p11, a, b);
    909 };
    910 
    911 /**
    912 * @param {tcuTexture.ConstPixelBufferAccess} access
    913 * @param {tcuTexture.Sampler} sampler
    914 * @param {number} u
    915 * @param {number} v
    916 * @param {number} w
    917 * @param {Array<number>=} offset
    918 * @return {Array<number>} Vec4 pixel color
    919 */
    920 tcuTexture.sampleLinear3D = function(access, sampler, u, v, w, offset) {
    921    /**
    922     * @param {Array<number>} p000
    923     * @param {Array<number>} p100
    924     * @param {Array<number>} p010
    925     * @param {Array<number>} p110
    926     * @param {Array<number>} p001
    927     * @param {Array<number>} p101
    928     * @param {Array<number>} p011
    929     * @param {Array<number>} p111
    930     * @param {number} a
    931     * @param {number} b
    932     * @param {number} c
    933     */
    934    var interpolateCube = function(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c) {
    935        var s000 = (1 - a) * (1 - b) * (1 - c);
    936        var s100 = a * (1 - b) * (1 - c);
    937        var s010 = (1 - a) * b * (1 - c);
    938        var s110 = a * b * (1 - c);
    939        var s001 = (1 - a) * (1 - b) * c;
    940        var s101 = a * (1 - b) * c;
    941        var s011 = (1 - a) * b * c;
    942        var s111 = a * b * c;
    943 
    944        return [
    945            (p000[0] * s000) + (p100[0] * s100) + (p010[0] * s010) + (p110[0] * s110) + (p001[0] * s001) + (p101[0] * s101) + (p011[0] * s011) + (p111[0] * s111),
    946            (p000[1] * s000) + (p100[1] * s100) + (p010[1] * s010) + (p110[1] * s110) + (p001[1] * s001) + (p101[1] * s101) + (p011[1] * s011) + (p111[1] * s111),
    947            (p000[2] * s000) + (p100[2] * s100) + (p010[2] * s010) + (p110[2] * s110) + (p001[2] * s001) + (p101[2] * s101) + (p011[2] * s011) + (p111[2] * s111),
    948            (p000[3] * s000) + (p100[3] * s100) + (p010[3] * s010) + (p110[3] * s110) + (p001[3] * s001) + (p101[3] * s101) + (p011[3] * s011) + (p111[3] * s111)
    949        ];
    950    };
    951 
    952    var width = access.getWidth();
    953    var height = access.getHeight();
    954    var depth = access.getDepth();
    955 
    956    /** @type {number} */ var xOffset = 0;
    957    /** @type {number} */ var yOffset = 0;
    958    /** @type {number} */ var zOffset = 0;
    959 
    960    if (offset !== undefined && offset.length === 3) {
    961        xOffset = offset[0];
    962        yOffset = offset[1];
    963        zOffset = offset[2];
    964    }
    965 
    966    var x0 = Math.floor(u - 0.5) + xOffset;
    967    var x1 = x0 + 1;
    968    var y0 = Math.floor(v - 0.5) + yOffset;
    969    var y1 = y0 + 1;
    970    var z0 = Math.floor(w - 0.5) + zOffset;
    971    var z1 = z0 + 1;
    972 
    973    var i0 = tcuTexture.wrap(sampler.wrapS, x0, width);
    974    var i1 = tcuTexture.wrap(sampler.wrapS, x1, width);
    975    var j0 = tcuTexture.wrap(sampler.wrapT, y0, height);
    976    var j1 = tcuTexture.wrap(sampler.wrapT, y1, height);
    977    var k0 = tcuTexture.wrap(sampler.wrapR, z0, depth);
    978    var k1 = tcuTexture.wrap(sampler.wrapR, z1, depth);
    979 
    980    var a = deMath.deFloatFrac(u - 0.5);
    981    var b = deMath.deFloatFrac(v - 0.5);
    982    var c = deMath.deFloatFrac(w - 0.5);
    983 
    984    var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, width);
    985    var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, width);
    986    var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, height);
    987    var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, height);
    988    var k0UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k0, 0, depth);
    989    var k1UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k1, 0, depth);
    990 
    991    // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
    992    var p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k0);
    993    var p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k0);
    994    var p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k0);
    995    var p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k0);
    996    var p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k1);
    997    var p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k1);
    998    var p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k1);
    999    var p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k1);
   1000 
   1001    // Interpolate.
   1002    return interpolateCube(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c);
   1003 };
   1004 
   1005 /**
   1006 * @param {tcuTexture.ConstPixelBufferAccess} access
   1007 * @param {tcuTexture.Sampler} sampler
   1008 * @param {number} u
   1009 * @param {number} v
   1010 * @param {(number|Array<number>)} depthOrOffset depth (integer) or offset (ivec3)
   1011 * @return {Array<number>} Vec4 pixel color
   1012 */
   1013 tcuTexture.sampleNearest2D = function(access, sampler, u, v, depthOrOffset) {
   1014    /** @type {number} */ var xOffset = 0;
   1015    /** @type {number} */ var yOffset = 0;
   1016    /** @type {number} */ var value;
   1017    if (Array.isArray(depthOrOffset)) {
   1018        xOffset = depthOrOffset[0];
   1019        yOffset = depthOrOffset[1];
   1020        value = depthOrOffset[2];
   1021    } else {
   1022        value = /** @type {number} */ (depthOrOffset);
   1023    }
   1024 
   1025    var width = access.getWidth();
   1026    var height = access.getHeight();
   1027 
   1028    var x = Math.floor(u) + xOffset;
   1029    var y = Math.floor(v) + yOffset;
   1030 
   1031    // Check for CLAMP_TO_BORDER.
   1032    if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) ||
   1033        (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height)))
   1034        return sampler.borderColor;
   1035 
   1036    var i = tcuTexture.wrap(sampler.wrapS, x, width);
   1037    var j = tcuTexture.wrap(sampler.wrapT, y, height);
   1038 
   1039    return tcuTexture.lookup(access, i, j, value);
   1040 };
   1041 
   1042 /**
   1043 * @param {tcuTexture.ConstPixelBufferAccess} access
   1044 * @param {tcuTexture.Sampler} sampler
   1045 * @param {number} u
   1046 * @param {number} v
   1047 * @param {number} w
   1048 * @param {Array<number>=} offset
   1049 * @return {Array<number>} Vec4 pixel color
   1050 */
   1051 tcuTexture.sampleNearest3D = function(access, sampler, u, v, w, offset) {
   1052    var width = access.getWidth();
   1053    var height = access.getHeight();
   1054    var depth = access.getDepth();
   1055    /** @type {number} */ var xOffset = 0;
   1056    /** @type {number} */ var yOffset = 0;
   1057    /** @type {number} */ var zOffset = 0;
   1058 
   1059    if (offset !== undefined && offset.length === 3) {
   1060        xOffset = offset[0];
   1061        yOffset = offset[1];
   1062        zOffset = offset[2];
   1063    }
   1064 
   1065    var x = Math.floor(u) + xOffset;
   1066    var y = Math.floor(v) + yOffset;
   1067    var z = Math.floor(w) + zOffset;
   1068 
   1069    // Check for CLAMP_TO_BORDER.
   1070    if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) ||
   1071        (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height)) ||
   1072        (sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(z, 0, depth)))
   1073        return sampler.borderColor;
   1074 
   1075    var i = tcuTexture.wrap(sampler.wrapS, x, width);
   1076    var j = tcuTexture.wrap(sampler.wrapT, y, height);
   1077    var k = tcuTexture.wrap(sampler.wrapR, z, depth);
   1078 
   1079    return tcuTexture.lookup(access, i, j, k);
   1080 };
   1081 
   1082 /**
   1083 * @param {Array<number>} color Vec4 color
   1084 * @return {number} The color in packed 32 bit format
   1085 */
   1086 tcuTexture.packRGB999E5 = function(color) {
   1087    /** @const */ var mBits = 9;
   1088    /** @const */ var eBits = 5;
   1089    /** @const */ var eBias = 15;
   1090    /** @const */ var eMax = (1 << eBits) - 1;
   1091    /** @const */ var maxVal = (((1 << mBits) - 1) * (1 << (eMax - eBias))) / (1 << mBits);
   1092 
   1093    var rc = deMath.clamp(color[0], 0, maxVal);
   1094    var gc = deMath.clamp(color[1], 0, maxVal);
   1095    var bc = deMath.clamp(color[2], 0, maxVal);
   1096    var maxc = Math.max(rc, gc, bc);
   1097    var expp = Math.max(-eBias - 1, Math.floor(Math.log2(maxc))) + 1 + eBias;
   1098    var e = Math.pow(2, expp - eBias - mBits);
   1099    var maxs = Math.floor(maxc / e + 0.5);
   1100 
   1101    var exps = maxs == (1 << mBits) ? expp + 1 : expp;
   1102    var rs = deMath.clamp(Math.floor(rc / e + 0.5), 0, (1 << 9) - 1);
   1103    var gs = deMath.clamp(Math.floor(gc / e + 0.5), 0, (1 << 9) - 1);
   1104    var bs = deMath.clamp(Math.floor(bc / e + 0.5), 0, (1 << 9) - 1);
   1105 
   1106    DE_ASSERT((exps & ~((1 << 5) - 1)) == 0);
   1107    DE_ASSERT((rs & ~((1 << 9) - 1)) == 0);
   1108    DE_ASSERT((gs & ~((1 << 9) - 1)) == 0);
   1109    DE_ASSERT((bs & ~((1 << 9) - 1)) == 0);
   1110 
   1111    return rs | (gs << 9) | (bs << 18) | (exps << 27);
   1112 };
   1113 
   1114 /**
   1115 * @param {number} color Color in packed 32 bit format
   1116 * @return {Array<number>} The color in unpacked format
   1117 */
   1118 tcuTexture.unpackRGB999E5 = function(color) {
   1119    var mBits = 9;
   1120    var eBias = 15;
   1121 
   1122    var exp = (color >> 27) & ((1 << 5) - 1);
   1123    var bs = (color >> 18) & ((1 << 9) - 1);
   1124    var gs = (color >> 9) & ((1 << 9) - 1);
   1125    var rs = color & ((1 << 9) - 1);
   1126 
   1127    var e = Math.pow(2, (exp - eBias - mBits));
   1128    var r = rs * e;
   1129    var g = gs * e;
   1130    var b = bs * e;
   1131 
   1132    return [r, g, b, 1];
   1133 };
   1134 
   1135 /**
   1136 * \brief Read-only pixel data access
   1137 *
   1138 * tcuTexture.ConstPixelBufferAccess encapsulates pixel data pointer along with
   1139 * format and layout information. It can be used for read-only access
   1140 * to arbitrary pixel buffers.
   1141 *
   1142 * Access objects are like iterators or pointers. They can be passed around
   1143 * as values and are valid as long as the storage doesn't change.
   1144 * @constructor
   1145 */
   1146 tcuTexture.ConstPixelBufferAccess = function(descriptor) {
   1147    if (descriptor) {
   1148        this.m_offset = descriptor.offset || 0;
   1149        this.m_format = descriptor.format || new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT);
   1150        this.m_width = descriptor.width;
   1151        this.m_height = descriptor.height;
   1152        if (descriptor.depth)
   1153            this.m_depth = descriptor.depth;
   1154        else
   1155            this.m_depth = 1;
   1156        this.m_data = descriptor.data;
   1157        if (descriptor.rowPitch)
   1158            this.m_rowPitch = descriptor.rowPitch;
   1159        else
   1160            this.m_rowPitch = this.m_width * this.m_format.getPixelSize();
   1161 
   1162        if (descriptor.slicePitch)
   1163            this.m_slicePitch = descriptor.slicePitch;
   1164        else
   1165            this.m_slicePitch = this.m_rowPitch * this.m_height;
   1166 
   1167        if (this.m_format.isEqual(new tcuTexture.TextureFormat(
   1168            tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8)))
   1169            this.m_rgba8View = new tcuTexture.RGBA8View(this);
   1170        else if (this.m_format.isEqual(new tcuTexture.TextureFormat(
   1171            tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8)))
   1172            this.m_rgb8View = new tcuTexture.RGBA8View(this);
   1173 
   1174    }
   1175 
   1176    this.m_dataPtrType = null;
   1177    this.m_dataPtr = null;
   1178 };
   1179 
   1180 tcuTexture.ConstPixelBufferAccess.prototype.toString = function() {
   1181    var str = 'BufferAccess(format: ' + this.m_format +
   1182        ', width: ' + this.m_width +
   1183        ', height: ' + this.m_height;
   1184    if (this.m_depth > 1)
   1185        str += ', depth: ' + this.m_depth;
   1186    if (this.m_rowPitch != this.m_width * this.m_format.getPixelSize())
   1187        str += ', row pitch: ' + this.m_rowPitch;
   1188    if (this.m_slicePitch != this.m_rowPitch * this.m_height)
   1189        str += ', slice pitch: ' + this.m_slicePitch;
   1190    if (this.m_offset > 0)
   1191        str += ', offset: ' + this.m_offset;
   1192    str += ')';
   1193    return str;
   1194 };
   1195 
   1196 /** @return {number} */
   1197 tcuTexture.ConstPixelBufferAccess.prototype.getDataSize = function() { return this.m_depth * this.m_slicePitch; };
   1198 tcuTexture.ConstPixelBufferAccess.prototype.isEmpty = function() { return this.m_width == 0 || this.m_height == 0 || this.m_depth == 0; };
   1199 /** @return {goog.TypedArray} */
   1200 tcuTexture.ConstPixelBufferAccess.prototype.getDataPtr = function() {
   1201    if (this.m_dataPtrType != this.m_format.type) {
   1202        this.m_dataPtrType = this.m_format.type;
   1203        var arrayType = tcuTexture.getTypedArray(this.m_format.type);
   1204        this.m_dataPtr = new arrayType(this.m_data, this.m_offset);
   1205    }
   1206    return this.m_dataPtr;
   1207 };
   1208 /** @return {ArrayBuffer} */
   1209 tcuTexture.ConstPixelBufferAccess.prototype.getBuffer = function() {
   1210    return this.m_data;
   1211 };
   1212 /** @return {number} */
   1213 tcuTexture.ConstPixelBufferAccess.prototype.getRowPitch = function() { return this.m_rowPitch; };
   1214 /** @return {number} */
   1215 tcuTexture.ConstPixelBufferAccess.prototype.getWidth = function() { return this.m_width; };
   1216 /** @return {number} */
   1217 tcuTexture.ConstPixelBufferAccess.prototype.getHeight = function() { return this.m_height; };
   1218 /** @return {number} */
   1219 tcuTexture.ConstPixelBufferAccess.prototype.getDepth = function() { return this.m_depth; };
   1220 /** @return {number} */
   1221 tcuTexture.ConstPixelBufferAccess.prototype.getSlicePitch = function() { return this.m_slicePitch; };
   1222 /** @return {tcuTexture.TextureFormat} */
   1223 tcuTexture.ConstPixelBufferAccess.prototype.getFormat = function() { return this.m_format; };
   1224 
   1225 /**
   1226 * @param {number} x
   1227 * @param {number} y
   1228 * @param {number=} z
   1229 * @return {number} stencil value
   1230 */
   1231 tcuTexture.ConstPixelBufferAccess.prototype.getPixStencil = function(x, y, z) {
   1232    z = z || 0;
   1233 
   1234    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1235    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1236    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1237 
   1238    // Make sure that the position is 'integer'
   1239    x = Math.round(x);
   1240    y = Math.round(y);
   1241    z = Math.round(z);
   1242 
   1243    var pixelSize = this.m_format.getPixelSize();
   1244    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1245    var pixelPtr = this.getDataPtr();
   1246    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1247 
   1248    switch (this.m_format.type) {
   1249        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1250            switch (this.m_format.order) {
   1251                case tcuTexture.ChannelOrder.S: return (pixelPtr[pixelPtrOffset] >> 8) & 0xff;
   1252                case tcuTexture.ChannelOrder.DS: return pixelPtr[pixelPtrOffset] & 0xff;
   1253 
   1254                default:
   1255                    DE_ASSERT(false);
   1256                    return 0;
   1257            }
   1258 
   1259        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV:
   1260            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   1261            var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1);
   1262            return u32array[0] & 0xff;
   1263 
   1264        default: {
   1265            if (this.m_format.order == tcuTexture.ChannelOrder.S)
   1266                return tcuTexture.channelToInt(pixelPtr[pixelPtrOffset], this.m_format.type);
   1267            else {
   1268                DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   1269                var stencilChannelIndex = 3;
   1270                return tcuTexture.channelToInt(pixelPtr[stencilChannelIndex + pixelPtrOffset], this.m_format.type);
   1271            }
   1272        }
   1273    }
   1274 };
   1275 
   1276 /**
   1277 * @param {number} x
   1278 * @param {number} y
   1279 * @param {number=} z
   1280 * @return {number}
   1281 */
   1282 tcuTexture.ConstPixelBufferAccess.prototype.getPixDepth = function(x, y, z) {
   1283    if (z == null)
   1284        z = 0;
   1285    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1286    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1287    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1288 
   1289    // Make sure that the position is 'integer'
   1290    x = Math.round(x);
   1291    y = Math.round(y);
   1292    z = Math.round(z);
   1293 
   1294    var pixelSize = this.m_format.getPixelSize();
   1295    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1296    var pixelPtr = this.getDataPtr();
   1297    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1298 
   1299    var ub = function(pixel, offset, count) {
   1300        return (pixel >> offset) & ((1 << count) - 1);
   1301    };
   1302    var nb = function(pixel, offset, count) {
   1303        return tcuTexture.channelToNormFloat(ub(pixel, offset, count), count);
   1304    };
   1305 
   1306    // Packed formats.
   1307    switch (this.m_format.type) {
   1308        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1309            switch (this.m_format.order) {
   1310                case tcuTexture.ChannelOrder.D: // fall-through
   1311                case tcuTexture.ChannelOrder.DS:
   1312                    return nb(pixelPtr[pixelPtrOffset], 8, 24);
   1313                default:
   1314                    throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
   1315            }
   1316            break;
   1317 
   1318        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   1319            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   1320            return pixelPtr[pixelPtrOffset];
   1321            break;
   1322        }
   1323 
   1324        default: {
   1325            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS);
   1326            return tcuTexture.channelToFloat(pixelPtr[pixelPtrOffset], this.m_format.type);
   1327        }
   1328    }
   1329 };
   1330 
   1331 /**
   1332 * @param {number} x
   1333 * @param {number} y
   1334 * @param {number=} z
   1335 * @return {Array<number>} Pixel value as Vec4
   1336 */
   1337 tcuTexture.ConstPixelBufferAccess.prototype.getPixel = function(x, y, z) {
   1338    z = z || 0;
   1339 
   1340    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1341    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1342    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1343 
   1344    // Make sure that the position is 'integer'
   1345    return this._getPixelInternal(Math.round(x), Math.round(y), Math.round(z));
   1346 };
   1347 
   1348 // NOTE: getPixel has been broken into getPixel, _getPixelInternal, and _getPixelPacked
   1349 // because having them combined previously was causing V8 depots
   1350 tcuTexture.ConstPixelBufferAccess.prototype._getPixelInternal = function(x, y, z) {
   1351    // Quick paths
   1352    if (z == 0) {
   1353        if (this.m_rgba8View) {
   1354            var color = this.m_rgba8View.read(x, y, 4);
   1355            color[0] /= 255;
   1356            color[1] /= 255;
   1357            color[2] /= 255;
   1358            color[3] /= 255;
   1359            return color;
   1360        } else if (this.m_rgb8View) {
   1361            var color = this.m_rgb8View.read(x, y, 3);
   1362            color[0] /= 255;
   1363            color[1] /= 255;
   1364            color[2] /= 255;
   1365            color[3] = 1;
   1366            return color;
   1367        }
   1368    }
   1369 
   1370    var pixelSize = this.m_format.getPixelSize();
   1371    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1372 
   1373    var pixelPtr = this.getDataPtr();
   1374    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1375 
   1376    return this._getPixelPacked(pixelPtr, pixelPtrOffset);
   1377 };
   1378 
   1379 tcuTexture.ConstPixelBufferAccess.prototype._getPixelPacked = (function() {
   1380 
   1381    var ub = function(pixel, offset, count) {
   1382        return (pixel >> offset) & ((1 << count) - 1);
   1383    };
   1384    var nb = function(pixel, offset, count) {
   1385        var maxVal = (1 << count) - 1;
   1386        return ((pixel >> offset) & ((1 << count) - 1)) / maxVal;
   1387    };
   1388    var f11 = tcuFloat.float11ToNumber;
   1389    var f10 = tcuFloat.float10ToNumber;
   1390 
   1391    return function tcuTexture_ConstPixelBufferAccess_getPixelPacked(pixelPtr, pixelPtrOffset) {
   1392        var pixel = pixelPtr[pixelPtrOffset];
   1393 
   1394        // Packed formats.
   1395        switch (this.m_format.type) {
   1396            case tcuTexture.ChannelType.UNORM_SHORT_565: return [nb(pixel, 11, 5), nb(pixel, 5, 6), nb(pixel, 0, 5), 1];
   1397            case tcuTexture.ChannelType.UNORM_SHORT_555: return [nb(pixel, 10, 5), nb(pixel, 5, 5), nb(pixel, 0, 5), 1];
   1398            case tcuTexture.ChannelType.UNORM_SHORT_4444: return [nb(pixel, 12, 4), nb(pixel, 8, 4), nb(pixel, 4, 4), nb(pixel, 0, 4)];
   1399            case tcuTexture.ChannelType.UNORM_SHORT_5551: return [nb(pixel, 11, 5), nb(pixel, 6, 5), nb(pixel, 1, 5), nb(pixel, 0, 1)];
   1400            case tcuTexture.ChannelType.UNORM_INT_101010: return [nb(pixel, 22, 10), nb(pixel, 12, 10), nb(pixel, 2, 10), 1];
   1401            case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [nb(pixel, 0, 10), nb(pixel, 10, 10), nb(pixel, 20, 10), nb(pixel, 30, 2)];
   1402            case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
   1403            case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.unpackRGB999E5(pixel);
   1404 
   1405            case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1406                switch (this.m_format.order) {
   1407                    // \note Stencil is always ignored.
   1408                    case tcuTexture.ChannelOrder.D: return [nb(pixel, 8, 24), 0, 0, 1];
   1409                    case tcuTexture.ChannelOrder.DS: return [nb(pixel, 8, 24), 0, 0, 1 /* (float)ub(0, 8) */];
   1410                    default:
   1411                        DE_ASSERT(false);
   1412                }
   1413 
   1414            case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   1415                DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   1416                // \note Stencil is ignored.
   1417                return [pixel, 0, 0, 1];
   1418            }
   1419 
   1420            case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: {
   1421                return [f11(ub(pixel, 0, 11)), f11(ub(pixel, 11, 11)), f10(ub(pixel, 22, 10)), 1];
   1422            }
   1423 
   1424            default:
   1425                break;
   1426        }
   1427 
   1428        // Generic path.
   1429        var result = [0, 0, 0, 0];
   1430        var channelMap = tcuTexture.getChannelReadMap(this.m_format.order);
   1431        var channelSize = tcuTexture.getChannelSize(this.m_format.type);
   1432 
   1433        for (var c = 0; c < 4; c++) {
   1434            var map = channelMap[c];
   1435            if (map == tcuTexture.channel.ZERO)
   1436                result[c] = 0;
   1437            else if (map == tcuTexture.channel.ONE)
   1438                result[c] = 1;
   1439            else
   1440                result[c] = tcuTexture.channelToFloat(pixelPtr[map + pixelPtrOffset], this.m_format.type);
   1441        }
   1442 
   1443        return result;
   1444    };
   1445 })();
   1446 
   1447 /**
   1448 * @param {number} x
   1449 * @param {number} y
   1450 * @param {number=} z
   1451 * @return {Array<number>} Pixel value as Vec4
   1452 */
   1453 tcuTexture.ConstPixelBufferAccess.prototype.getPixelInt = function(x, y, z) {
   1454    z = z || 0;
   1455    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1456    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1457    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1458 
   1459    // Make sure that the position is 'integer'
   1460    x = Math.round(x);
   1461    y = Math.round(y);
   1462    z = Math.round(z);
   1463 
   1464    // Quick paths
   1465    if (z == 0) {
   1466        if (this.m_rgba8View)
   1467            return this.m_rgba8View.read(x, y, 4);
   1468        else if (this.m_rgb8View)
   1469            return this.m_rgb8View.read(x, y, 3);
   1470    }
   1471 
   1472    var pixelSize = this.m_format.getPixelSize();
   1473    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1474 
   1475    var pixelPtr = this.getDataPtr();
   1476    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1477    var pixel = pixelPtr[pixelPtrOffset];
   1478 
   1479    var ub = function(pixel, offset, count) {
   1480        return (pixel >> offset) & ((1 << count) - 1);
   1481    };
   1482 
   1483    // Packed formats.
   1484    switch (this.m_format.type) {
   1485        case tcuTexture.ChannelType.UNORM_SHORT_565: return [ub(pixel, 11, 5), ub(pixel, 5, 6), ub(pixel, 0, 5), 1];
   1486        case tcuTexture.ChannelType.UNORM_SHORT_555: return [ub(pixel, 10, 5), ub(pixel, 5, 5), ub(pixel, 0, 5), 1];
   1487        case tcuTexture.ChannelType.UNORM_SHORT_4444: return [ub(pixel, 12, 4), ub(pixel, 8, 4), ub(pixel, 4, 4), ub(pixel, 0, 4)];
   1488        case tcuTexture.ChannelType.UNORM_SHORT_5551: return [ub(pixel, 11, 5), ub(pixel, 6, 5), ub(pixel, 1, 5), ub(pixel, 0, 1)];
   1489        case tcuTexture.ChannelType.UNORM_INT_101010: return [ub(pixel, 22, 10), ub(pixel, 12, 10), ub(pixel, 2, 10), 1];
   1490        case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
   1491        case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
   1492 
   1493        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1494            switch (this.m_format.order) {
   1495                case tcuTexture.ChannelOrder.D: return [ub(pixel, 8, 24), 0, 0, 1];
   1496                case tcuTexture.ChannelOrder.S: return [0, 0, 0, ub(pixel, 8, 24)];
   1497                case tcuTexture.ChannelOrder.DS: return [ub(pixel, 8, 24), 0, 0, ub(pixel, 0, 8)];
   1498                default:
   1499                    DE_ASSERT(false);
   1500            }
   1501 
   1502        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   1503            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   1504            var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1);
   1505            return [pixel, 0, 0, ub(u32array[0], 0, 8)];
   1506        }
   1507 
   1508        default:
   1509            break;
   1510    }
   1511 
   1512    // Generic path.
   1513    var result = [];
   1514    result.length = 4;
   1515    var channelMap = tcuTexture.getChannelReadMap(this.m_format.order);
   1516    var channelSize = tcuTexture.getChannelSize(this.m_format.type);
   1517 
   1518    for (var c = 0; c < 4; c++) {
   1519        var map = channelMap[c];
   1520        if (map == tcuTexture.channel.ZERO)
   1521            result[c] = 0;
   1522        else if (map == tcuTexture.channel.ONE)
   1523            result[c] = 1;
   1524        else
   1525            result[c] = tcuTexture.channelToInt(pixelPtr[map + pixelPtrOffset], this.m_format.type);
   1526    }
   1527 
   1528    return result;
   1529 };
   1530 
   1531 /**
   1532 * @param {tcuTexture.Sampler} sampler
   1533 * @param {?tcuTexture.FilterMode} filter
   1534 * @param {number} s
   1535 * @param {number} t
   1536 * @param {number} depth (integer)
   1537 * @return {Array<number>} Sample color
   1538 */
   1539 tcuTexture.ConstPixelBufferAccess.prototype.sample2D = function(sampler, filter, s, t, depth) {
   1540    DE_ASSERT(deMath.deInBounds32(depth, 0, this.m_depth));
   1541 
   1542    // Non-normalized coordinates.
   1543    var u = s;
   1544    var v = t;
   1545 
   1546    if (sampler.normalizedCoords) {
   1547        u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
   1548        v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
   1549    }
   1550 
   1551    switch (filter) {
   1552        case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, depth);
   1553        case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, depth);
   1554        default:
   1555            throw new Error('Invalid filter:' + filter);
   1556    }
   1557    throw new Error('Unimplemented');
   1558 };
   1559 
   1560 /**
   1561 * @param {tcuTexture.Sampler} sampler
   1562 * @param {?tcuTexture.FilterMode} filter
   1563 * @param {number} s
   1564 * @param {number} t
   1565 * @param {Array<number>} offset
   1566 * @return {Array<number>} Sample color
   1567 */
   1568 tcuTexture.ConstPixelBufferAccess.prototype.sample2DOffset = function(sampler, filter, s, t, offset) {
   1569    DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth));
   1570 
   1571    // Non-normalized coordinates.
   1572    var u = s;
   1573    var v = t;
   1574 
   1575    if (sampler.normalizedCoords) {
   1576        u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
   1577        v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
   1578    }
   1579 
   1580    switch (filter) {
   1581        case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, offset);
   1582        case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, offset);
   1583        default:
   1584            throw new Error('Invalid filter:' + filter);
   1585    }
   1586 };
   1587 
   1588 /**
   1589 * @param {tcuTexture.Sampler} sampler
   1590 * @param {?tcuTexture.FilterMode} filter
   1591 * @param {number} s
   1592 * @param {number} t
   1593 * @param {number} r
   1594 * @param {Array<number>} offset
   1595 * @return {Array<number>} Sample color
   1596 */
   1597 tcuTexture.ConstPixelBufferAccess.prototype.sample3DOffset = function(sampler, filter, s, t, r, offset) {
   1598    // Non-normalized coordinates.
   1599    /** @type {number} */ var u = s;
   1600    /** @type {number} */ var v = t;
   1601    /** @type {number} */ var w = r;
   1602 
   1603    if (sampler.normalizedCoords) {
   1604        u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
   1605        v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
   1606        w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth);
   1607    }
   1608 
   1609    switch (filter) {
   1610        case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w, offset);
   1611        case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w, offset);
   1612        default:
   1613            throw new Error('Invalid filter:' + filter);
   1614    }
   1615 };
   1616 
   1617 /**
   1618 * @param {tcuTexture.Sampler} sampler
   1619 * @param {tcuTexture.FilterMode} filter
   1620 * @param {number} ref
   1621 * @param {number} s
   1622 * @param {number} t
   1623 * @param {Array<number>} offset
   1624 * @return {number}
   1625 */
   1626 tcuTexture.ConstPixelBufferAccess.prototype.sample2DCompare = function(sampler, filter, ref, s, t, offset) {
   1627    DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth));
   1628 
   1629    // Format information for comparison function
   1630    var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(this.m_format);
   1631 
   1632    // Non-normalized coordinates.
   1633    var u = s;
   1634    var v = t;
   1635 
   1636    if (sampler.normalizedCoords) {
   1637        u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
   1638        v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
   1639    }
   1640 
   1641    switch (filter) {
   1642        case tcuTexture.FilterMode.NEAREST: return tcuTexture.execCompare(tcuTexture.sampleNearest2D(this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
   1643        case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2DCompare(this, sampler, ref, u, v, offset, isFixedPointDepth);
   1644        default:
   1645            DE_ASSERT(false);
   1646            return 0.0;
   1647    }
   1648 };
   1649 
   1650 /**
   1651 * @param {tcuTexture.Sampler} sampler
   1652 * @param {tcuTexture.FilterMode} filter
   1653 * @param {number} s
   1654 * @param {number} t
   1655 * @param {number} r
   1656 * @return {Array<number>} Sample color
   1657 */
   1658 tcuTexture.ConstPixelBufferAccess.prototype.sample3D = function(sampler, filter, s, t, r) {
   1659    // Non-normalized coordinates.
   1660    var u = s;
   1661    var v = t;
   1662    var w = r;
   1663 
   1664    if (sampler.normalizedCoords) {
   1665        u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
   1666        v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
   1667        w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth);
   1668    }
   1669 
   1670    switch (filter) {
   1671        case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w);
   1672        case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w);
   1673        default:
   1674            throw new Error('Invalid filter:' + filter);
   1675    }
   1676    throw new Error('Unimplemented');
   1677 };
   1678 
   1679    /* TODO: do we need any of these? */ {
   1680        // template<typename T>
   1681        // Vector<T, 4> getPixelT (int x, int y, int z = 0) const;
   1682 
   1683        // Vec4 sample3D (const tcuTexture.Sampler& sampler, tcuTexture.tcuTexture.Sampler.tcuTexture.FilterMode filter, float s, float t, float r) const;
   1684 
   1685        // Vec4 sample2DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, const IVec3& offset) const;
   1686        // Vec4 sample3DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, float r, const IVec3& offset) const;
   1687 
   1688        // float sample2DCompare (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float ref, float s, float t, const IVec3& offset) const;
   1689    };
   1690 
   1691 /** Common type limits
   1692 *
   1693 */
   1694 tcuTexture.deTypes = {
   1695    deInt8: {min: -(1 << 7), max: (1 << 7) - 1},
   1696    deInt16: {min: -(1 << 15), max: (1 << 15) - 1},
   1697    deInt32: {min: -2147483648, max: 2147483647},
   1698    deUint8: {min: 0, max: (1 << 8) - 1},
   1699    deUint16: {min: 0, max: (1 << 16) - 1},
   1700    deUint32: {min: 0, max: 4294967295}
   1701 };
   1702 
   1703 /**
   1704 * Round to even and saturate
   1705 * @param {{max: number, min: number}} deType from tcuTexture.deTypes
   1706 * @param {number} value
   1707 * @return {number}
   1708 */
   1709 tcuTexture.convertSatRte = function(deType, value) {
   1710    var minVal = deType.min;
   1711    var maxVal = deType.max;
   1712    var floor = Math.floor(value);
   1713    var frac = value - floor;
   1714    if (frac == 0.5) {
   1715        if (floor % 2 != 0)
   1716            floor += 1;
   1717    } else if (frac > 0.5) {
   1718        floor += 1;
   1719    }
   1720 
   1721    return Math.max(minVal, Math.min(maxVal, floor));
   1722 };
   1723 
   1724 /**
   1725 * Saturate value to type range
   1726 * @param { {max: number, min: number}} deType from tcuTexture.deTypes
   1727 * @param {number} src
   1728 * @return {number}
   1729 */
   1730 tcuTexture.convertSat = function(deType, src) {
   1731    var minVal = deType.min;
   1732    var maxVal = deType.max;
   1733    if (src < minVal)
   1734        return minVal;
   1735    else if (src > maxVal)
   1736        return maxVal;
   1737    else
   1738        return src;
   1739 };
   1740 
   1741 /**
   1742 * @param {number} src Input integer value
   1743 * @param {tcuTexture.ChannelType} type
   1744 * @return {number}
   1745 */
   1746 tcuTexture.intToChannel = function(src, type) {
   1747    var dst;
   1748    switch (type) {
   1749        case tcuTexture.ChannelType.SNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break;
   1750        case tcuTexture.ChannelType.SNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break;
   1751        case tcuTexture.ChannelType.UNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break;
   1752        case tcuTexture.ChannelType.UNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break;
   1753        case tcuTexture.ChannelType.SIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break;
   1754        case tcuTexture.ChannelType.SIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break;
   1755        case tcuTexture.ChannelType.SIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt32, src); break;
   1756        case tcuTexture.ChannelType.UNSIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break;
   1757        case tcuTexture.ChannelType.UNSIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break;
   1758        case tcuTexture.ChannelType.UNSIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint32, src); break;
   1759        case tcuTexture.ChannelType.HALF_FLOAT: dst = tcuFloat.numberToHalfFloat(src); break;
   1760        case tcuTexture.ChannelType.FLOAT: dst = src; break;
   1761        default:
   1762            throw new Error('Unrecognized tcuTexture.channel type: ' + type);
   1763    }
   1764    return dst;
   1765 };
   1766 
   1767 /**
   1768 * @param {number} src
   1769 * @param {number} bits
   1770 * @return {number}
   1771 */
   1772 tcuTexture.normFloatToChannel = function(src, bits) {
   1773    var maxVal = (1 << bits) - 1;
   1774    var intVal = tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * maxVal);
   1775    return Math.min(maxVal, intVal);
   1776 };
   1777 
   1778 /**
   1779 * @param {number} src
   1780 * @param {number} bits
   1781 * @return {number}
   1782 */
   1783 tcuTexture.uintToChannel = function(src, bits) {
   1784    var maxVal = (1 << bits) - 1;
   1785    return Math.min(maxVal, src);
   1786 };
   1787 
   1788 /**
   1789 * @param {number} src
   1790 * @param {tcuTexture.ChannelType} type
   1791 * @return {number} Converted src color value
   1792 */
   1793 tcuTexture.floatToChannel = function(src, type) {
   1794    switch (type) {
   1795        case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src * 127);
   1796        case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src * 32767);
   1797        case tcuTexture.ChannelType.SNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src * 2147483647);
   1798        case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src * 255);
   1799        case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src * 65535);
   1800        case tcuTexture.ChannelType.UNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * 4294967295);
   1801        case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src);
   1802        case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src);
   1803        case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src);
   1804        case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src);
   1805        case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src);
   1806        case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src);
   1807        case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.numberToHalfFloat(src);
   1808        case tcuTexture.ChannelType.FLOAT: return src;
   1809    }
   1810    throw new Error('Unrecognized type ' + type);
   1811 };
   1812 
   1813 /**
   1814 * \brief Read-write pixel data access
   1815 *
   1816 * This class extends read-only access object by providing write functionality.
   1817 *
   1818 * \note tcuTexture.PixelBufferAccess may not have any data members nor add any
   1819 *         virtual functions. It must be possible to reinterpret_cast<>
   1820 *         tcuTexture.PixelBufferAccess to tcuTexture.ConstPixelBufferAccess.
   1821 * @constructor
   1822 * @extends {tcuTexture.ConstPixelBufferAccess}
   1823 *
   1824 */
   1825 tcuTexture.PixelBufferAccess = function(descriptor) {
   1826    tcuTexture.ConstPixelBufferAccess.call(this, descriptor);
   1827 };
   1828 
   1829 tcuTexture.PixelBufferAccess.prototype = Object.create(tcuTexture.ConstPixelBufferAccess.prototype);
   1830 tcuTexture.PixelBufferAccess.prototype.constructor = tcuTexture.PixelBufferAccess;
   1831 
   1832 /**
   1833 * @param {Array<number>} color Vec4 color to set
   1834 * @param {number} x
   1835 * @param {number} y
   1836 * @param {number=} z
   1837 */
   1838 tcuTexture.PixelBufferAccess.prototype.setPixel = function(color, x, y, z) {
   1839    z = z || 0;
   1840    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1841    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1842    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1843 
   1844    // Make sure that the position is 'integer'
   1845    this._setPixelInternal(color, Math.round(x), Math.round(y), Math.round(z));
   1846 };
   1847 
   1848 // NOTE: setPixel has been broken into setPixel, _setPixelInternal, and _setPixelPacked
   1849 // because having them combined previously was causing V8 depots
   1850 tcuTexture.PixelBufferAccess.prototype._setPixelInternal = function(color, x, y, z) {
   1851    // Quick paths
   1852    if (z == 0) {
   1853        if (this.m_rgba8View) {
   1854            color = deMath.toIVec(color);
   1855            this.m_rgba8View.write(x, y, color, 4);
   1856            return;
   1857        } else if (this.m_rgb8View) {
   1858            color = deMath.toIVec(color);
   1859            this.m_rgb8View.write(x, y, color, 3);
   1860            return;
   1861        }
   1862    }
   1863 
   1864    var pixelSize = this.m_format.getPixelSize();
   1865    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1866    var pixelPtr = this.getDataPtr();
   1867    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1868 
   1869    return this._setPixelPacked(color, pixelPtr, pixelPtrOffset);
   1870 };
   1871 
   1872 tcuTexture.PixelBufferAccess.prototype._setPixelPacked = (function () {
   1873    var pn = function(val, offs, bits) {
   1874        return tcuTexture.normFloatToChannel(val, bits) << offs;
   1875    };
   1876 
   1877    var pu = function(val, offs, bits) {
   1878        return tcuTexture.uintToChannel(val, bits) << offs;
   1879    };
   1880 
   1881    return function tcuTexture_PixelBufferAccess_setPixelPacked(color, pixelPtr, pixelPtrOffset) {
   1882        // Packed formats.
   1883        switch (this.m_format.type) {
   1884            case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 5, 6) | pn(color[2], 0, 5); break;
   1885            case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pn(color[0], 10, 5) | pn(color[1], 5, 5) | pn(color[2], 0, 5); break;
   1886            case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pn(color[0], 12, 4) | pn(color[1], 8, 4) | pn(color[2], 4, 4) | pn(color[3], 0, 4); break;
   1887            case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 6, 5) | pn(color[2], 1, 5) | pn(color[3], 0, 1); break;
   1888            case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pn(color[0], 22, 10) | pn(color[1], 12, 10) | pn(color[2], 2, 10); break;
   1889            case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pn(color[0], 0, 10) | pn(color[1], 10, 10) | pn(color[2], 20, 10) | pn(color[3], 30, 2); break;
   1890            case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
   1891            case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: pixelPtr[pixelPtrOffset] = tcuTexture.packRGB999E5(color); break;
   1892 
   1893            case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1894                switch (this.m_format.order) {
   1895                    // \note Stencil is always ignored.
   1896                    case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24); break;
   1897                    case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pn(color[3], 8, 24); break;
   1898                    case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24) | pu(color[3], 0, 8); break;
   1899                    default:
   1900                        throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
   1901                }
   1902                break;
   1903 
   1904            case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   1905                pixelPtr[pixelPtrOffset] = color[0];
   1906                var u32array = new Uint32Array(this.m_data, (pixelPtrOffset * pixelPtr.BYTES_PER_ELEMENT) + this.m_offset + 4, 1);
   1907                u32array[0] = pu(color[3], 0, 8);
   1908                break;
   1909            }
   1910 
   1911            case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: {
   1912                var f11 = function(value) {
   1913                    return tcuFloat.numberToFloat11(value);
   1914                };
   1915                var f10 = function(value) {
   1916                    return tcuFloat.numberToFloat10(value);
   1917                };
   1918 
   1919                pixelPtr[pixelPtrOffset] = f11(color[0]) | (f11(color[1]) << 11) | (f10(color[2]) << 22);
   1920                break;
   1921            }
   1922            case tcuTexture.ChannelType.FLOAT:
   1923                if (this.m_format.order == tcuTexture.ChannelOrder.D) {
   1924                    pixelPtr[pixelPtrOffset] = color[0];
   1925                    break;
   1926                }
   1927                // else fall-through to default case!
   1928 
   1929            default: {
   1930                // Generic path.
   1931                var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order);
   1932                var map = tcuTexture.getChannelWriteMap(this.m_format.order);
   1933 
   1934                for (var c = 0; c < numChannels; c++)
   1935                    pixelPtr[c + pixelPtrOffset] = tcuTexture.floatToChannel(color[map[c]], this.m_format.type);
   1936            }
   1937        }
   1938    };
   1939 })();
   1940 
   1941 /**
   1942 * @param {Array<number>} color Vec4 color to set (unnormalized)
   1943 * @param {number} x
   1944 * @param {number} y
   1945 * @param {number=} z
   1946 */
   1947 tcuTexture.PixelBufferAccess.prototype.setPixelInt = function(color, x, y, z) {
   1948    z = z || 0;
   1949    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   1950    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   1951    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   1952 
   1953    // Make sure that the position is 'integer'
   1954    x = Math.round(x);
   1955    y = Math.round(y);
   1956    z = Math.round(z);
   1957 
   1958    // Quick paths
   1959    if (z == 0) {
   1960        if (this.m_rgba8View) {
   1961            this.m_rgba8View.write(x, y, color, 4);
   1962            return;
   1963        } else if (this.m_rgb8View) {
   1964            this.m_rgb8View.write(x, y, color, 3);
   1965            return;
   1966        }
   1967    }
   1968 
   1969    var pixelSize = this.m_format.getPixelSize();
   1970    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   1971    var pixelPtr = this.getDataPtr();
   1972    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   1973 
   1974    var pu = function(val, offs, bits) {
   1975        return tcuTexture.uintToChannel(val, bits) << offs;
   1976    };
   1977 
   1978    // Packed formats.
   1979    switch (this.m_format.type) {
   1980        case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 5, 6) | pu(color[2], 0, 5); break;
   1981        case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pu(color[0], 10, 5) | pu(color[1], 5, 5) | pu(color[2], 0, 5); break;
   1982        case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pu(color[0], 12, 4) | pu(color[1], 8, 4) | pu(color[2], 4, 4) | pu(color[3], 0, 4); break;
   1983        case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 6, 5) | pu(color[2], 1, 5) | pu(color[3], 0, 1); break;
   1984        case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pu(color[0], 22, 10) | pu(color[1], 12, 10) | pu(color[2], 2, 10); break;
   1985        case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
   1986        case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
   1987 
   1988        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   1989            switch (this.m_format.order) {
   1990                // \note Stencil is always ignored.
   1991                case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24); break;
   1992                case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(color[3], 8, 24); break;
   1993                case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24) | pu(color[3], 0, 8); break;
   1994                default:
   1995                    throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
   1996            }
   1997            break;
   1998 
   1999        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   2000            pixelPtr[pixelPtrOffset] = color[0];
   2001            var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1);
   2002            u32array[pixelPtrOffset] = pu(color[3], 0, 8);
   2003            break;
   2004        }
   2005 
   2006        default: {
   2007            // Generic path.
   2008            var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order);
   2009            var map = tcuTexture.getChannelWriteMap(this.m_format.order);
   2010 
   2011            for (var c = 0; c < numChannels; c++)
   2012                pixelPtr[c + pixelPtrOffset] = tcuTexture.intToChannel(color[map[c]], this.m_format.type);
   2013        }
   2014    }
   2015 };
   2016 
   2017 /**
   2018 * @param {Array<number>=} color Vec4 color to set, optional.
   2019 * @param {Array<number>=} x Range in x axis, optional.
   2020 * @param {Array<number>=} y Range in y axis, optional.
   2021 * @param {Array<number>=} z Range in z axis, optional.
   2022 */
   2023 tcuTexture.PixelBufferAccess.prototype.clear = function(color, x, y, z) {
   2024    var c = color || [0, 0, 0, 0];
   2025    var arrayType = tcuTexture.getTypedArray(this.m_format.type);
   2026    var range_x = x || [0, this.m_width];
   2027    var range_y = y || [0, this.m_height];
   2028    var range_z = z || [0, this.m_depth];
   2029    var pixelSize = this.m_format.getPixelSize();
   2030    var numElements = pixelSize / arrayType.BYTES_PER_ELEMENT;
   2031    var width = range_x[1] - range_x[0];
   2032    var height = range_y[1] - range_y[0];
   2033    var depth = range_z[1] - range_z[0];
   2034    if (x === undefined && y === undefined && z === undefined &&
   2035        c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0) {
   2036        var pixelPtr = new arrayType(this.m_data, this.m_offset);
   2037        pixelPtr.fill(0);
   2038        return;
   2039    }
   2040 
   2041    //copy first pixel over other pixels in the row
   2042    var fillRow = function(pixelPtr, numElements, width) {
   2043        for (var i = 1; i < width; i++)
   2044            for (var c = 0; c < numElements; c++)
   2045                pixelPtr[i * numElements + c] = pixelPtr[c];
   2046    };
   2047    // copy first row to other rows in all planes
   2048    var fillPlanes = function(buffer, arrayType, src, offset, rowStride, planeStride, width, height, depth) {
   2049        for (var j = 0; j < depth; j++)
   2050        for (var i = (j == 0 ? 1 : 0); i < height; i++) {
   2051            var dst = new arrayType(buffer, offset + i * rowStride + j * planeStride, width);
   2052            dst.set(src);
   2053        }
   2054    };
   2055 
   2056    this.setPixel(c, range_x[0], range_y[0], range_z[0]);
   2057 
   2058    var offset = range_z[0] * this.m_slicePitch + range_y[0] * this.m_rowPitch + range_x[0] * pixelSize;
   2059    var pixelPtr = new arrayType(this.m_data, offset + this.m_offset, width * numElements);
   2060 
   2061    fillRow(pixelPtr, numElements, width);
   2062    fillPlanes(this.m_data, arrayType, pixelPtr, offset + this.m_offset, this.m_rowPitch, this.m_slicePitch, width * numElements, height, depth);
   2063 };
   2064 
   2065 /**
   2066 * @param {number} depth to set
   2067 * @param {number} x
   2068 * @param {number} y
   2069 * @param {number=} z
   2070 */
   2071 tcuTexture.PixelBufferAccess.prototype.setPixDepth = function(depth, x, y, z) {
   2072    if (z == null)
   2073        z = 0;
   2074    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   2075    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   2076    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   2077 
   2078    // Make sure that the position is 'integer'
   2079    x = Math.round(x);
   2080    y = Math.round(y);
   2081    z = Math.round(z);
   2082 
   2083    var pixelSize = this.m_format.getPixelSize();
   2084    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   2085    var pixelPtr = this.getDataPtr();
   2086    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   2087 
   2088    var pn = function(val, offs, bits) {
   2089        return tcuTexture.normFloatToChannel(val, bits) << offs;
   2090    };
   2091 
   2092    // Packed formats.
   2093    switch (this.m_format.type) {
   2094        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   2095            switch (this.m_format.order) {
   2096                case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24); break;
   2097                case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24) | (pixelPtr[pixelPtrOffset] & 0xFF); break;
   2098                default:
   2099                    throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
   2100            }
   2101            break;
   2102 
   2103        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   2104            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   2105            pixelPtr[pixelPtrOffset] = depth;
   2106            break;
   2107        }
   2108 
   2109        default: {
   2110            DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS);
   2111            pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(depth, this.m_format.type);
   2112        }
   2113    }
   2114 };
   2115 
   2116 /**
   2117 * @param {number} stencil to set
   2118 * @param {number} x
   2119 * @param {number} y
   2120 * @param {number=} z
   2121 */
   2122 tcuTexture.PixelBufferAccess.prototype.setPixStencil = function(stencil, x, y, z) {
   2123    if (z == null)
   2124        z = 0;
   2125    DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
   2126    DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
   2127    DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
   2128 
   2129    // Make sure that the position is 'integer'
   2130    x = Math.round(x);
   2131    y = Math.round(y);
   2132    z = Math.round(z);
   2133 
   2134    var pixelSize = this.m_format.getPixelSize();
   2135    var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
   2136    var pixelPtr = this.getDataPtr();
   2137    var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
   2138 
   2139    var pu = function(val, offs, bits) {
   2140        return tcuTexture.uintToChannel(val, bits) << offs;
   2141    };
   2142 
   2143    // Packed formats.
   2144    switch (this.m_format.type) {
   2145        case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
   2146            switch (this.m_format.order) {
   2147                case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(stencil, 8, 24); break;
   2148                case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(stencil, 0, 8) | (pixelPtr[pixelPtrOffset] & 0xFFFFFF00); break;
   2149                default:
   2150                    throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
   2151            }
   2152            break;
   2153 
   2154        case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
   2155            var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1);
   2156            u32array[0] = pu(stencil, 0, 8);
   2157            break;
   2158        }
   2159 
   2160        default: {
   2161            if (this.m_format.order == tcuTexture.ChannelOrder.S)
   2162                pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type);
   2163            else {
   2164                DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
   2165                pixelPtr[3 + pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type);
   2166            }
   2167        }
   2168    }
   2169 };
   2170 
   2171 /**
   2172 * newFromTextureLevel
   2173 * @param {tcuTexture.TextureLevel} level
   2174 * @return {tcuTexture.PixelBufferAccess}
   2175 */
   2176 tcuTexture.PixelBufferAccess.newFromTextureLevel = function(level) {
   2177    var descriptor = new Object();
   2178    descriptor.format = level.getFormat();
   2179    descriptor.width = level.getWidth();
   2180    descriptor.height = level.getHeight();
   2181    descriptor.depth = level.m_depth;
   2182    descriptor.data = level.m_data.m_ptr;
   2183 
   2184    return new tcuTexture.PixelBufferAccess(descriptor);
   2185 };
   2186 
   2187 /**
   2188 * newFromTextureFormat
   2189 * @param {tcuTexture.TextureFormat} format
   2190 * @param {number} width
   2191 * @param {number} height
   2192 * @param {number} depth
   2193 * @param {number} rowPitch
   2194 * @param {number} slicePitch
   2195 * @param {ArrayBuffer} data
   2196 */
   2197 tcuTexture.PixelBufferAccess.newFromTextureFormat = function(format, width, height, depth, rowPitch, slicePitch, data) {
   2198    var descriptor = new Object();
   2199    descriptor.format = format;
   2200    descriptor.width = width;
   2201    descriptor.height = height;
   2202    descriptor.depth = depth;
   2203    descriptor.rowPitch = rowPitch;
   2204    descriptor.slicePitch = slicePitch;
   2205    descriptor.data = data;
   2206 
   2207    return new tcuTexture.PixelBufferAccess(descriptor);
   2208 };
   2209 
   2210 /* TODO: Port */
   2211 // {
   2212 // public:
   2213 //                             tcuTexture.PixelBufferAccess (void) {}
   2214 //                             tcuTexture.PixelBufferAccess (const tcuTexture.TextureFormat& format, int width, int height, int depth, void* data);
   2215 
   2216 //     void*                    getDataPtr (void) const { return m_data; }
   2217 
   2218 //     void setPixels (const void* buf, int bufSize) const;
   2219 //     void setPixel (const tcu::Vec4& color, int x, int y, int z = 0) const;
   2220 //     void setPixel (const tcu::IVec4& color, int x, int y, int z = 0) const;
   2221 //     void setPixel (const tcu::UVec4& color, int x, int y, int z = 0) const { setPixel(color.cast<int>(), x, y, z); }
   2222 
   2223 //     void setPixDepth (float depth, int x, int y, int z = 0) const;
   2224 //     void setPixStencil (int stencil, int x, int y, int z = 0) const;
   2225 // };
   2226 
   2227 /**
   2228 * @constructor
   2229 * @param {tcuTexture.TextureFormat} format
   2230 * @param {number} numLevels
   2231 */
   2232 tcuTexture.TextureLevelPyramid = function(format, numLevels) {
   2233    /* tcuTexture.TextureFormat */this.m_format = format;
   2234    /* LevelData */ this.m_data = [];
   2235    for (var i = 0; i < numLevels; i++)
   2236        this.m_data.push(new tcuTexture.DeqpArrayBuffer());
   2237    /* {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = [];
   2238    this.m_access.length = numLevels;
   2239 };
   2240 
   2241 /** @return {boolean} */
   2242 tcuTexture.TextureLevelPyramid.prototype.isLevelEmpty = function(levelNdx) { return this.m_data[levelNdx].empty(); };
   2243 /** @return {tcuTexture.TextureFormat} */
   2244 tcuTexture.TextureLevelPyramid.prototype.getFormat = function() { return this.m_format; };
   2245 /** @return {number} */
   2246 tcuTexture.TextureLevelPyramid.prototype.getNumLevels = function() { return this.m_access.length; };
   2247 /** @return {tcuTexture.PixelBufferAccess} */
   2248 tcuTexture.TextureLevelPyramid.prototype.getLevel = function(ndx) { return this.m_access[ndx]; };
   2249 /** @return {Array<tcuTexture.PixelBufferAccess>} */
   2250 tcuTexture.TextureLevelPyramid.prototype.getLevels = function() { return this.m_access; };
   2251 
   2252 /**
   2253 * @param {number} levelNdx
   2254 * @param {number} width
   2255 * @param {number} height
   2256 * @param {number} depth
   2257 */
   2258 tcuTexture.TextureLevelPyramid.prototype.allocLevel = function(levelNdx, width, height, depth) {
   2259    var size = this.m_format.getPixelSize() * width * height * depth;
   2260 
   2261    DE_ASSERT(this.isLevelEmpty(levelNdx));
   2262 
   2263    this.m_data[levelNdx].setStorage(size);
   2264    this.m_access[levelNdx] = new tcuTexture.PixelBufferAccess({
   2265        format: this.m_format,
   2266        width: width,
   2267        height: height,
   2268        depth: depth,
   2269        data: this.m_data[levelNdx].m_ptr
   2270    });
   2271 };
   2272 
   2273 tcuTexture.TextureLevelPyramid.prototype.clearLevel = function(levelNdx) {
   2274    /* TODO: Implement */
   2275    throw new Error('Not implemented');
   2276 };
   2277 
   2278 /**
   2279 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2280 * @param {number} numLevels
   2281 * @param {tcuTexture.Sampler} sampler
   2282 * @param {number} s
   2283 * @param {number} t
   2284 * @param {number} depth (integer)
   2285 * @param {number=} lod
   2286 * @return {Array<number>} Vec4 pixel color
   2287 */
   2288 tcuTexture.sampleLevelArray2D = function(levels, numLevels, sampler, s, t, depth, lod) {
   2289    // z-offset in 2D textures is layer selector
   2290    return tcuTexture.sampleLevelArray2DOffset(levels, numLevels, sampler, [s, t], lod, [0, 0, depth]);
   2291 };
   2292 
   2293 /**
   2294 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2295 * @param {number} numLevels
   2296 * @param {tcuTexture.Sampler} sampler
   2297 * @param {number} s
   2298 * @param {number} t
   2299 * @param {number} r
   2300 * @param {number} lod
   2301 * @return {Array<number>} Vec4 pixel color
   2302 */
   2303 tcuTexture.sampleLevelArray3D = function(levels, numLevels, sampler, s, t, r, lod) {
   2304    return tcuTexture.sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, [0, 0, 0]);
   2305 };
   2306 
   2307 /**
   2308 * @constructor
   2309 * @param {tcuTexture.CubeFace} face
   2310 * @param {Array<number>} coords
   2311 */
   2312 tcuTexture.CubeFaceCoords = function(face, coords) {
   2313    this.face = face;
   2314    this.s = coords[0];
   2315    this.t = coords[1];
   2316 };
   2317 
   2318 /**
   2319 * \brief 2D Texture View
   2320 * @constructor
   2321 * @param {number} numLevels
   2322 * @param {?Array<tcuTexture.ConstPixelBufferAccess>} levels
   2323 */
   2324 tcuTexture.Texture2DView = function(numLevels, levels) {
   2325    this.m_numLevels = numLevels;
   2326    this.m_levels = levels;
   2327 };
   2328 
   2329 /** @return {number} */
   2330 tcuTexture.Texture2DView.prototype.getNumLevels = function() { return this.m_numLevels; };
   2331 /** @return {number} */
   2332 tcuTexture.Texture2DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
   2333 /** @return {number} */
   2334 tcuTexture.Texture2DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
   2335 /**
   2336 * @param {number} ndx
   2337 * @return {tcuTexture.ConstPixelBufferAccess}
   2338 */
   2339 tcuTexture.Texture2DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
   2340 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
   2341 tcuTexture.Texture2DView.prototype.getLevels = function() { return this.m_levels; };
   2342 
   2343 /**
   2344 * @param {number} baseLevel
   2345 * @param {number} maxLevel
   2346 * return {tcuTexture.Texture2DView}
   2347 */
   2348 tcuTexture.Texture2DView.prototype.getSubView = function(baseLevel, maxLevel) {
   2349    var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
   2350    var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
   2351    var numLevels = clampedMax - clampedBase + 1;
   2352    return new tcuTexture.Texture2DView(numLevels, this.m_levels.slice(clampedBase, numLevels));
   2353 };
   2354 
   2355 /**
   2356 * @param {tcuTexture.Sampler} sampler
   2357 * @param {Array<number>} texCoord
   2358 * @param {number=} lod
   2359 * @return {Array<number>} Pixel color
   2360 */
   2361 tcuTexture.Texture2DView.prototype.sample = function(sampler, texCoord, lod) {
   2362    return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], 0 /* depth */, lod);
   2363 };
   2364 
   2365 /**
   2366 * @param {tcuTexture.Sampler} sampler
   2367 * @param {Array<number>} texCoord
   2368 * @param {number} lod
   2369 * @param {Array<number>} offset
   2370 * @return {Array<number>} Pixel color
   2371 */
   2372 tcuTexture.Texture2DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
   2373    return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], 0]);
   2374 };
   2375 
   2376 /**
   2377 * @param {tcuTexture.Sampler} sampler
   2378 * @param {number} ref
   2379 * @param {Array<number>} texCoord
   2380 * @param {number} lod
   2381 * @return {number}
   2382 */
   2383 tcuTexture.Texture2DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
   2384    return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, 0]);
   2385 };
   2386 
   2387 /**
   2388 * @param {tcuTexture.Sampler} sampler
   2389 * @param {number} ref
   2390 * @param {Array<number>} texCoord
   2391 * @param {number} lod
   2392 * @param {Array<number>} offset
   2393 * @return {number}
   2394 */
   2395 tcuTexture.Texture2DView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) {
   2396    return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], 0]);
   2397 };
   2398 
   2399    /* TODO: Port
   2400    Vec4 sample (const tcuTexture.Sampler& sampler, float s, float t, float lod) const;
   2401    Vec4 sampleOffset (const tcuTexture.Sampler& sampler, float s, float t, float lod, const IVec2& offset) const;
   2402    float sampleCompare (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod) const;
   2403    float sampleCompareOffset (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod, const IVec2& offset) const;
   2404 
   2405    Vec4 gatherOffsets (const tcuTexture.Sampler& sampler, float s, float t, int componentNdx, const IVec2 (&offsets)[4]) const;
   2406    Vec4 gatherOffsetsCompare(const tcuTexture.Sampler& sampler, float ref, float s, float t, const IVec2 (&offsets)[4]) const;
   2407    */
   2408 
   2409 /**
   2410 * @constructor
   2411 * @param {number} numLevels
   2412 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2413 */
   2414 tcuTexture.Texture2DArrayView = function(numLevels, levels) {
   2415    this.m_numLevels = numLevels;
   2416    this.m_levels = levels;
   2417 };
   2418 
   2419 /** @return {number} */
   2420 tcuTexture.Texture2DArrayView.prototype.getNumLevels = function() { return this.m_numLevels; };
   2421 /** @return {number} */
   2422 tcuTexture.Texture2DArrayView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
   2423 /** @return {number} */
   2424 tcuTexture.Texture2DArrayView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
   2425 /** @return {number} */
   2426 tcuTexture.Texture2DArrayView.prototype.getNumLayers = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; };
   2427 /**
   2428 * @param {number} ndx
   2429 * @return {tcuTexture.ConstPixelBufferAccess}
   2430 */
   2431 tcuTexture.Texture2DArrayView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
   2432 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
   2433 tcuTexture.Texture2DArrayView.prototype.getLevels = function() { return this.m_levels; };
   2434 
   2435 /**
   2436 * @param {number} r
   2437 * @return {number} layer corresponding to requested sampling 'r' coordinate
   2438 */
   2439 tcuTexture.Texture2DArrayView.prototype.selectLayer = function(r) {
   2440    DE_ASSERT(this.m_numLevels > 0 && this.m_levels);
   2441    return deMath.clamp(Math.round(r), 0, this.m_levels[0].getDepth() - 1);
   2442 };
   2443 
   2444 /**
   2445 * @param {tcuTexture.Sampler} sampler
   2446 * @param {Array<number>} texCoord
   2447 * @param {number=} lod
   2448 * @return {Array<number>} Pixel color
   2449 */
   2450 tcuTexture.Texture2DArrayView.prototype.sample = function(sampler, texCoord, lod) {
   2451    lod = lod || 0;
   2452    return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], this.selectLayer(texCoord[2]), lod);
   2453 };
   2454 
   2455 /**
   2456 * @param {tcuTexture.Sampler} sampler
   2457 * @param {Array<number>} texCoord
   2458 * @param {number} lod
   2459 * @param {Array<number>} offset
   2460 * @return {Array<number>}
   2461 */
   2462 tcuTexture.Texture2DArrayView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
   2463    return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]);
   2464 };
   2465 
   2466 /**
   2467 * @param {tcuTexture.Sampler} sampler
   2468 * @param {number} ref
   2469 * @param {Array<number>} texCoord
   2470 * @param {number} lod
   2471 * @param {Array<number>} offset
   2472 * @return {number}
   2473 */
   2474 tcuTexture.Texture2DArrayView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) {
   2475    return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]);
   2476 };
   2477 
   2478 /**
   2479 * @param {tcuTexture.Sampler} sampler
   2480 * @param {number} ref
   2481 * @param {Array<number>} texCoord
   2482 * @param {number} lod
   2483 * @return {number}
   2484 */
   2485 tcuTexture.Texture2DArrayView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
   2486    return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, this.selectLayer(texCoord[2])]);
   2487 };
   2488 
   2489 /**
   2490 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2491 * @param {number} numLevels
   2492 * @param {tcuTexture.Sampler} sampler
   2493 * @param {Array<number>} texCoord
   2494 * @param {number} lod
   2495 * @param {Array<number>} offset
   2496 * @return {Array<number>}
   2497 */
   2498 tcuTexture.sampleLevelArray2DOffset = function(levels, numLevels, sampler, texCoord, lod, offset) {
   2499    /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold;
   2500    /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
   2501    /** @type {number} */ var maxLevel;
   2502    /** @type {tcuTexture.FilterMode} */ var levelFilter;
   2503    switch (filterMode) {
   2504        case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset);
   2505        case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset);
   2506 
   2507        case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
   2508        case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST:
   2509            maxLevel = numLevels - 1;
   2510            /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
   2511            levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2512 
   2513            return levels[level].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
   2514 
   2515        case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
   2516        case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR:
   2517            maxLevel = numLevels - 1;
   2518            /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
   2519            /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1);
   2520            levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2521            /** @type {number} */ var f = deMath.deFloatFrac(lod);
   2522            /** @type {Array<number>} */ var t0 = levels[level0].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
   2523            /** @type {Array<number>} */ var t1 = levels[level1].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
   2524 
   2525            return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
   2526 
   2527        default:
   2528            return [0.0, 0.0, 0.0, 0.0];
   2529    }
   2530 };
   2531 
   2532 /**
   2533 * @constructor
   2534 * @param {number} numLevels
   2535 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2536 */
   2537 tcuTexture.Texture3DView = function(numLevels, levels) {
   2538    this.m_numLevels = numLevels;
   2539    this.m_levels = levels;
   2540 };
   2541 
   2542 /** @return {number} */
   2543 tcuTexture.Texture3DView.prototype.getNumLevels = function() { return this.m_numLevels; };
   2544 /** @return {number} */
   2545 tcuTexture.Texture3DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
   2546 /** @return {number} */
   2547 tcuTexture.Texture3DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
   2548 /** @return {number} */
   2549 tcuTexture.Texture3DView.prototype.getDepth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; };
   2550 /**
   2551 * @param {number} ndx
   2552 * @return {tcuTexture.ConstPixelBufferAccess}
   2553 */
   2554 tcuTexture.Texture3DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
   2555 /** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
   2556 tcuTexture.Texture3DView.prototype.getLevels = function() { return this.m_levels; };
   2557 
   2558 /**
   2559 * @param {number} baseLevel
   2560 * @param {number} maxLevel
   2561 * return {tcuTexture.Texture3DView}
   2562 */
   2563 tcuTexture.Texture3DView.prototype.getSubView = function(baseLevel, maxLevel) {
   2564    var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
   2565    var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
   2566    var numLevels = clampedMax - clampedBase + 1;
   2567    return new tcuTexture.Texture3DView(numLevels, this.m_levels.slice(clampedBase, numLevels));
   2568 };
   2569 
   2570 /**
   2571 * @param {tcuTexture.Sampler} sampler
   2572 * @param {Array<number>} texCoord
   2573 * @param {number=} lod
   2574 * @return {Array<number>} Pixel color
   2575 */
   2576 tcuTexture.Texture3DView.prototype.sample = function(sampler, texCoord, lod) {
   2577    lod = lod || 0;
   2578    return tcuTexture.sampleLevelArray3D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod);
   2579 };
   2580 
   2581 /**
   2582 * @param {tcuTexture.Sampler} sampler
   2583 * @param {number} ref
   2584 * @param {Array<number>} texCoord
   2585 * @param {number} lod
   2586 * @return {number}
   2587 */
   2588 tcuTexture.Texture3DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
   2589    throw new Error('Unimplemented');
   2590 };
   2591 
   2592 /**
   2593 * @param {tcuTexture.Sampler} sampler
   2594 * @param {Array<number>} texCoord
   2595 * @param {number} lod
   2596 * @param {Array<number>} offset
   2597 * @return {Array<number>}
   2598 */
   2599 tcuTexture.Texture3DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
   2600    return tcuTexture.sampleLevelArray3DOffset(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod, offset);
   2601 };
   2602 
   2603 /* TODO: All view classes are very similar. They should have a common base class */
   2604 
   2605 /**
   2606 * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
   2607 * @param {number} numLevels
   2608 * @param {tcuTexture.Sampler} sampler
   2609 * @param {number} s
   2610 * @param {number} t
   2611 * @param {number} r
   2612 * @param {number} lod
   2613 * @param {Array<number>} offset
   2614 * @return {Array<number>}
   2615 */
   2616 tcuTexture.sampleLevelArray3DOffset = function(levels, numLevels, sampler, s, t, r, lod, offset) {
   2617    /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold;
   2618    /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
   2619    /** @type {number} */ var maxLevel;
   2620    /** @type {tcuTexture.FilterMode} */ var levelFilter;
   2621    switch (filterMode) {
   2622        case tcuTexture.FilterMode.NEAREST: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
   2623        case tcuTexture.FilterMode.LINEAR: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
   2624 
   2625        case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
   2626        case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST:
   2627            maxLevel = numLevels - 1;
   2628            /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
   2629            levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2630 
   2631            return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2632 
   2633        case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
   2634        case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR:
   2635            maxLevel = numLevels - 1;
   2636            /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
   2637            /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1);
   2638            levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2639            /** @type {number} */ var f = deMath.deFloatFrac(lod);
   2640            /** @type {Array<number>} */ var t0 = levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2641            /** @type {Array<number>} */ var t1 = levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
   2642 
   2643            return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
   2644 
   2645        default:
   2646            throw new Error('Filter mode not supported');
   2647    }
   2648 };
   2649 
   2650 /**
   2651 * @param {number} width
   2652 * @param {number=} height
   2653 * @param {number=} depth
   2654 * @return {number} Number of pyramid levels
   2655 */
   2656 tcuTexture.computeMipPyramidLevels = function(width, height, depth) {
   2657    if (depth !== undefined)
   2658        return Math.floor(Math.log2(Math.max(width, Math.max(height, depth)))) + 1;
   2659    else if (height !== undefined)
   2660        return Math.floor(Math.log2(Math.max(width, height))) + 1;
   2661    else
   2662        return Math.floor(Math.log2(width)) + 1;
   2663 };
   2664 
   2665 /**
   2666 * @param {number} baseLevelSize
   2667 * @param {number} levelNdx
   2668 */
   2669 tcuTexture.getMipPyramidLevelSize = function(baseLevelSize, levelNdx) {
   2670    return Math.max(baseLevelSize >> levelNdx, 1);
   2671 };
   2672 
   2673 /**
   2674 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
   2675 * @param {tcuTexture.CubeFace} baseFace
   2676 * @param {number} u
   2677 * @param {number} v
   2678 * @param {number} depth
   2679 * @return {Array<Array<number>>}
   2680 */
   2681 tcuTexture.getCubeLinearSamples = function(faceAccesses, baseFace, u, v, depth) {
   2682    DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2683    /** @type {Array<Array<number>>} */ var dst = [];
   2684    var size = faceAccesses[0].getWidth();
   2685    var x0 = Math.floor(u - 0.5);
   2686    var x1 = x0 + 1;
   2687    var y0 = Math.floor(v - 0.5);
   2688    var y1 = y0 + 1;
   2689    var baseSampleCoords =
   2690    [
   2691        [x0, y0],
   2692        [x1, y0],
   2693        [x0, y1],
   2694        [x1, y1]
   2695    ];
   2696    /** @type {Array<Array<number>>} */ var sampleColors = [];
   2697    /** @type {Array<boolean>} */ var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
   2698 
   2699    // Find correct faces and coordinates for out-of-bounds sample coordinates.
   2700 
   2701    for (var i = 0; i < 4; i++) {
   2702        /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size);
   2703        hasBothCoordsOutOfBounds[i] = coords == null;
   2704        if (!hasBothCoordsOutOfBounds[i])
   2705            sampleColors[i] = tcuTexture.lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
   2706    }
   2707 
   2708    // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
   2709    // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
   2710    //         requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
   2711    //         must have this color as well.
   2712 
   2713    var bothOutOfBoundsNdx = -1;
   2714    for (var i = 0; i < 4; i++) {
   2715        if (hasBothCoordsOutOfBounds[i]) {
   2716            DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
   2717            bothOutOfBoundsNdx = i;
   2718        }
   2719    }
   2720    if (bothOutOfBoundsNdx != -1) {
   2721        sampleColors[bothOutOfBoundsNdx] = [0, 0, 0, 0];
   2722        for (var i = 0; i < 4; i++)
   2723            if (i != bothOutOfBoundsNdx)
   2724                sampleColors[bothOutOfBoundsNdx] = deMath.add(sampleColors[bothOutOfBoundsNdx], sampleColors[i]);
   2725 
   2726        sampleColors[bothOutOfBoundsNdx] = deMath.scale(sampleColors[bothOutOfBoundsNdx], (1.0 / 3.0));
   2727    }
   2728 
   2729    for (var i = 0; i < sampleColors.length; i++)
   2730        dst[i] = sampleColors[i];
   2731 
   2732    return dst;
   2733 };
   2734 
   2735 // \todo [2014-02-19 pyry] Optimize faceAccesses
   2736 /**
   2737 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
   2738 * @param {tcuTexture.CubeFace} baseFace
   2739 * @param {tcuTexture.Sampler} sampler
   2740 * @param {number} s
   2741 * @param {number} t
   2742 * @param {number} depth
   2743 * @return {Array<number>}
   2744 */
   2745 tcuTexture.sampleCubeSeamlessLinear = function(faceAccesses, baseFace, sampler, s, t, depth) {
   2746    DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2747 
   2748    var size = faceAccesses[0].getWidth();
   2749    // Non-normalized coordinates.
   2750    var u = s;
   2751    var v = t;
   2752 
   2753    if (sampler.normalizedCoords) {
   2754        u = tcuTexture.unnormalize(sampler.wrapS, s, size);
   2755        v = tcuTexture.unnormalize(sampler.wrapT, t, size);
   2756    }
   2757 
   2758    // Get sample colors.
   2759 
   2760    /** @type {Array<Array<number>>} */ var sampleColors = tcuTexture.getCubeLinearSamples(faceAccesses, baseFace, u, v, depth);
   2761 
   2762    // Interpolate.
   2763 
   2764    var a = deMath.deFloatFrac(u - 0.5);
   2765    var b = deMath.deFloatFrac(v - 0.5);
   2766 
   2767    return deMath.add((deMath.scale(deMath.scale(sampleColors[0], (1.0 - a)), (1.0 - b))),
   2768           deMath.add((deMath.scale(deMath.scale(sampleColors[1], (a)), (1.0 - b))),
   2769           deMath.add((deMath.scale(deMath.scale(sampleColors[2], (1.0 - a)), (b))),
   2770                      (deMath.scale(deMath.scale(sampleColors[3], (a)), (b))))));
   2771 };
   2772 
   2773 /**
   2774 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces
   2775 * @param {number} numLevels
   2776 * @param {tcuTexture.CubeFace} face
   2777 * @param {tcuTexture.Sampler} sampler
   2778 * @param {number} s
   2779 * @param {number} t
   2780 * @param {number} depth
   2781 * @param {number=} lod
   2782 * @return {Array<number>}
   2783 */
   2784 tcuTexture.sampleLevelArrayCubeSeamless = function(faces, numLevels, face, sampler, s, t, depth, lod) {
   2785    lod = lod || 0;
   2786    var magnified = lod <= sampler.lodThreshold;
   2787    /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
   2788    /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = [];
   2789    /** @type {tcuTexture.FilterMode}*/ var levelFilter;
   2790 
   2791    switch (filterMode) {
   2792        case tcuTexture.FilterMode.NEAREST:
   2793            return tcuTexture.sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
   2794 
   2795        case tcuTexture.FilterMode.LINEAR: {
   2796            faceAccesses = [];
   2797            for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
   2798                faceAccesses[i] = faces[i][0];
   2799 
   2800            return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
   2801        }
   2802 
   2803        case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
   2804        case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
   2805            var maxLevel = numLevels - 1;
   2806            var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
   2807            levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2808 
   2809            if (levelFilter == tcuTexture.FilterMode.NEAREST)
   2810                return tcuTexture.sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
   2811            else {
   2812                DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
   2813 
   2814                faceAccesses = [];
   2815                for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
   2816                    faceAccesses[i] = faces[i][level];
   2817 
   2818                return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
   2819            }
   2820        }
   2821 
   2822        case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
   2823        case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
   2824            var maxLevel = numLevels - 1;
   2825            var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
   2826            var level1 = Math.min(maxLevel, level0 + 1);
   2827            levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   2828            var f = deMath.deFloatFrac(lod);
   2829            var t0 = [];
   2830            var t1 = [];
   2831 
   2832            if (levelFilter == tcuTexture.FilterMode.NEAREST) {
   2833                t0 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
   2834                t1 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
   2835            } else {
   2836                DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
   2837 
   2838                /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses0 = [];
   2839                /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses1 = [];
   2840                for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) {
   2841                    faceAccesses0[i] = faces[i][level0];
   2842                    faceAccesses1[i] = faces[i][level1];
   2843                }
   2844 
   2845                t0 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
   2846                t1 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
   2847            }
   2848 
   2849            return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
   2850        }
   2851 
   2852        default:
   2853            throw new Error('Unsupported filter mode');
   2854    }
   2855 };
   2856 
   2857 /**
   2858 * @param {tcuTexture.ConstPixelBufferAccess} faceAccess
   2859 * @param {tcuTexture.Sampler} sampler
   2860 * @param {number} ref
   2861 * @param {number} s
   2862 * @param {number} t
   2863 * @param {number=} depth
   2864 * @return {number}
   2865 */
   2866 tcuTexture.sampleCubeSeamlessNearestCompare = function(faceAccess, sampler, ref, s, t, depth) {
   2867    depth = depth ? depth : 0;
   2868    /** @type {tcuTexture.Sampler} */ var clampingSampler = deUtil.clone(sampler);
   2869    clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   2870    clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   2871    return faceAccess.sample2DCompare(clampingSampler, tcuTexture.FilterMode.NEAREST, ref, s, t, [0, 0, depth]);
   2872 };
   2873 
   2874 /**
   2875 * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
   2876 * @param {tcuTexture.CubeFace} baseFace
   2877 * @param {tcuTexture.Sampler} sampler
   2878 * @param {number} ref
   2879 * @param {number} s
   2880 * @param {number} t
   2881 * @return {number}
   2882 */
   2883 tcuTexture.sampleCubeSeamlessLinearCompare = function(faceAccesses, baseFace, sampler, ref, s, t) {
   2884    DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
   2885 
   2886    var size = faceAccesses[0].getWidth();
   2887    // Non-normalized coordinates.
   2888    var u = s;
   2889    var v = t;
   2890 
   2891    if (sampler.normalizedCoords) {
   2892        u = tcuTexture.unnormalize(sampler.wrapS, s, size);
   2893        v = tcuTexture.unnormalize(sampler.wrapT, t, size);
   2894    }
   2895 
   2896    var x0 = Math.floor(u - 0.5);
   2897    var x1 = x0 + 1;
   2898    var y0 = Math.floor(v - 0.5);
   2899    var y1 = y0 + 1;
   2900    var baseSampleCoords = [
   2901        [x0, y0],
   2902        [x1, y0],
   2903        [x0, y1],
   2904        [x1, y1]
   2905    ];
   2906    var sampleRes = [];
   2907    var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
   2908 
   2909    // Find correct faces and coordinates for out-of-bounds sample coordinates.
   2910 
   2911    for (var i = 0; i < 4; i++) {
   2912        /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size);
   2913        hasBothCoordsOutOfBounds[i] = coords == null;
   2914 
   2915        if (!hasBothCoordsOutOfBounds[i]) {
   2916            var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
   2917 
   2918            sampleRes[i] = tcuTexture.execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
   2919        }
   2920    }
   2921 
   2922    // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
   2923    // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
   2924    //         requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
   2925    //         must have this color as well.
   2926 
   2927    var bothOutOfBoundsNdx = -1;
   2928    for (var i = 0; i < 4; i++) {
   2929        if (hasBothCoordsOutOfBounds[i]) {
   2930            DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
   2931            bothOutOfBoundsNdx = i;
   2932        }
   2933    }
   2934    if (bothOutOfBoundsNdx != -1) {
   2935        sampleRes[bothOutOfBoundsNdx] = 0.0;
   2936        for (var i = 0; i < 4; i++)
   2937            if (i != bothOutOfBoundsNdx)
   2938                sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
   2939 
   2940        sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0 / 3.0);
   2941    }
   2942 
   2943    // Interpolate.
   2944 
   2945    var a = deMath.deFloatFrac(u - 0.5);
   2946    var b = deMath.deFloatFrac(v - 0.5);
   2947 
   2948    return (sampleRes[0] * (1.0 - a) * (1.0 - b)) +
   2949           (sampleRes[1] * (a) * (1.0 - b)) +
   2950           (sampleRes[2] * (1.0 - a) * (b)) +
   2951           (sampleRes[3] * (a) * (b));
   2952 };
   2953 
   2954 /**
   2955 * @param {tcuTexture.ConstPixelBufferAccess} faceAccess
   2956 * @param {tcuTexture.Sampler} sampler
   2957 * @param {number} s
   2958 * @param {number} t
   2959 * @param {number} depth
   2960 * @return {Array<number>}
   2961 */
   2962 tcuTexture.sampleCubeSeamlessNearest = function(faceAccess, sampler, s, t, depth) {
   2963    /** @type {tcuTexture.Sampler} */ var clampingSampler = sampler;
   2964    clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   2965    clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
   2966    return faceAccess.sample2D(clampingSampler, tcuTexture.FilterMode.NEAREST, s, t, depth);
   2967 };
   2968 
   2969 /**
   2970 * @param {Array<number>} coords Vec3 cube coordinates
   2971 * @return {tcuTexture.CubeFaceCoords}
   2972 */
   2973 tcuTexture.getCubeFaceCoords = function(coords) {
   2974    var face = tcuTexture.selectCubeFace(coords);
   2975    return new tcuTexture.CubeFaceCoords(face, tcuTexture.projectToFace(face, coords));
   2976 };
   2977 
   2978 /**
   2979 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces
   2980 * @param {number} numLevels
   2981 * @param {tcuTexture.CubeFace} face
   2982 * @param {tcuTexture.Sampler} sampler
   2983 * @param {number} ref
   2984 * @param {number} s
   2985 * @param {number} t
   2986 * @param {number} lod
   2987 * @return {number}
   2988 */
   2989 tcuTexture.sampleLevelArrayCubeSeamlessCompare = function(faces, numLevels, face, sampler, ref, s, t, lod) {
   2990    var magnified = lod <= sampler.lodThreshold;
   2991    /** @type {tcuTexture.FilterMode}*/ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
   2992    /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = [];
   2993    /** @type {tcuTexture.FilterMode} */ var levelFilter;
   2994 
   2995    switch (filterMode) {
   2996        case tcuTexture.FilterMode.NEAREST:
   2997            return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
   2998 
   2999        case tcuTexture.FilterMode.LINEAR: {
   3000            faceAccesses = [];
   3001            for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
   3002                faceAccesses[i] = faces[i][0];
   3003 
   3004            return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   3005        }
   3006 
   3007        case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
   3008        case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
   3009            var maxLevel = numLevels - 1;
   3010            var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
   3011            levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   3012 
   3013            if (levelFilter == tcuTexture.FilterMode.NEAREST)
   3014                return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
   3015            else {
   3016                DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
   3017 
   3018                faceAccesses = [];
   3019                for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
   3020                    faceAccesses[i] = faces[i][level];
   3021 
   3022                return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
   3023            }
   3024        }
   3025 
   3026        case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
   3027        case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
   3028            var maxLevel = numLevels - 1;
   3029            var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
   3030            var level1 = Math.min(maxLevel, level0 + 1);
   3031            levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
   3032            var f = deMath.deFloatFrac(lod);
   3033            var t0;
   3034            var t1;
   3035 
   3036            if (levelFilter == tcuTexture.FilterMode.NEAREST) {
   3037                t0 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
   3038                t1 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
   3039            } else {
   3040                DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
   3041 
   3042                /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses0 = [];
   3043                /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses1 = [];
   3044                for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) {
   3045                    faceAccesses0[i] = faces[i][level0];
   3046                    faceAccesses1[i] = faces[i][level1];
   3047                }
   3048 
   3049                t0 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
   3050                t1 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
   3051            }
   3052 
   3053            return t0 * (1.0 - f) + t1 * f;
   3054        }
   3055 
   3056        default:
   3057            throw new Error('Unsupported filter mode');
   3058    }
   3059 };
   3060 
   3061 /**
   3062 * @constructor
   3063 * @extends {tcuTexture.TextureLevelPyramid}
   3064 * @param {tcuTexture.TextureFormat} format
   3065 * @param {number} width
   3066 * @param {number} height
   3067 */
   3068 tcuTexture.Texture2D = function(format, width, height) {
   3069    tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height));
   3070    this.m_width = width;
   3071    this.m_height = height;
   3072    this.m_view = new tcuTexture.Texture2DView(this.getNumLevels(), this.getLevels());
   3073 };
   3074 
   3075 tcuTexture.Texture2D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
   3076 tcuTexture.Texture2D.prototype.constructor = tcuTexture.Texture2D;
   3077 
   3078 tcuTexture.Texture2D.prototype.getWidth = function() { return this.m_width; };
   3079 tcuTexture.Texture2D.prototype.getHeight = function() { return this.m_height; };
   3080 /** @return {tcuTexture.Texture2DView} */
   3081 tcuTexture.Texture2D.prototype.getView = function() { return this.m_view; };
   3082 
   3083 /**
   3084 * @param {number} baseLevel
   3085 * @param {number} maxLevel
   3086 * @return {tcuTexture.Texture2DView}
   3087 */
   3088 tcuTexture.Texture2D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
   3089 
   3090 /**
   3091 * @param {number} levelNdx
   3092 */
   3093 tcuTexture.Texture2D.prototype.allocLevel = function(levelNdx) {
   3094    DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
   3095 
   3096    var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
   3097    var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
   3098 
   3099    tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, 1);
   3100 };
   3101 
   3102 /**
   3103 * @constructor
   3104 * @extends {tcuTexture.TextureLevelPyramid}
   3105 * @param {tcuTexture.TextureFormat} format
   3106 * @param {number} width
   3107 * @param {number} height
   3108 * @param {number} numLayers
   3109 */
   3110 tcuTexture.Texture2DArray = function(format, width, height, numLayers) {
   3111    tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height));
   3112    this.m_width = width;
   3113    this.m_height = height;
   3114    this.m_numLayers = numLayers;
   3115    this.m_view = new tcuTexture.Texture2DArrayView(this.getNumLevels(), this.getLevels());
   3116 };
   3117 
   3118 tcuTexture.Texture2DArray.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
   3119 tcuTexture.Texture2DArray.prototype.constructor = tcuTexture.Texture2DArray;
   3120 /** @return {tcuTexture.Texture2DArrayView} */
   3121 tcuTexture.Texture2DArray.prototype.getView = function() { return this.m_view; };
   3122 
   3123 /** @return {number} */
   3124 tcuTexture.Texture2DArray.prototype.getWidth = function() { return this.m_width; };
   3125 
   3126 /** @return {number} */
   3127 tcuTexture.Texture2DArray.prototype.getHeight = function() { return this.m_height; };
   3128 
   3129 /**
   3130 * @param {number} levelNdx
   3131 */
   3132 tcuTexture.Texture2DArray.prototype.allocLevel = function(levelNdx) {
   3133    DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
   3134 
   3135    var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
   3136    var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
   3137 
   3138    tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, this.m_numLayers);
   3139 };
   3140 
   3141 /**
   3142 * @constructor
   3143 * @extends {tcuTexture.TextureLevelPyramid}
   3144 * @param {tcuTexture.TextureFormat} format
   3145 * @param {number} width
   3146 * @param {number} height
   3147 * @param {number} depth
   3148 */
   3149 tcuTexture.Texture3D = function(format, width, height, depth) {
   3150    tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height, depth));
   3151    this.m_width = width;
   3152    this.m_height = height;
   3153    this.m_depth = depth;
   3154    this.m_view = new tcuTexture.Texture3DView(this.getNumLevels(), this.getLevels());
   3155 };
   3156 
   3157 tcuTexture.Texture3D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
   3158 tcuTexture.Texture3D.prototype.constructor = tcuTexture.Texture3D;
   3159 
   3160 tcuTexture.Texture3D.prototype.getWidth = function() { return this.m_width; };
   3161 tcuTexture.Texture3D.prototype.getHeight = function() { return this.m_height; };
   3162 tcuTexture.Texture3D.prototype.getDepth = function() { return this.m_depth; };
   3163 tcuTexture.Texture3D.prototype.getView = function() { return this.m_view; };
   3164 /**
   3165 * @param {number} baseLevel
   3166 * @param {number} maxLevel
   3167 * @return {tcuTexture.Texture3DView}
   3168 */
   3169 tcuTexture.Texture3D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
   3170 
   3171 /**
   3172 * @param {number} levelNdx
   3173 */
   3174 tcuTexture.Texture3D.prototype.allocLevel = function(levelNdx) {
   3175    DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
   3176 
   3177    var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
   3178    var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
   3179    var depth = tcuTexture.getMipPyramidLevelSize(this.m_depth, levelNdx);
   3180 
   3181    tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, depth);
   3182 };
   3183 
   3184 /**
   3185 * @constructor
   3186 * @param {number} numLevels
   3187 * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} levels
   3188 */
   3189 tcuTexture.TextureCubeView = function(numLevels, levels) {
   3190    this.m_numLevels = numLevels;
   3191    this.m_levels = levels;
   3192 };
   3193 
   3194 /**
   3195 * @param {tcuTexture.Sampler} sampler
   3196 * @param {Array<number>} texCoord
   3197 * @param {number=} lod
   3198 * @return {Array<number>} Pixel color
   3199 */
   3200 tcuTexture.TextureCubeView.prototype.sample = function(sampler, texCoord, lod) {
   3201    DE_ASSERT(sampler.compare == tcuTexture.CompareMode.COMPAREMODE_NONE);
   3202 
   3203    // Computes (face, s, t).
   3204    var coords = tcuTexture.getCubeFaceCoords(texCoord);
   3205    if (sampler.seamlessCubeMap)
   3206        return tcuTexture.sampleLevelArrayCubeSeamless(this.m_levels, this.m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod);
   3207    else
   3208        return tcuTexture.sampleLevelArray2D(this.m_levels[coords.face], this.m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod);
   3209 };
   3210 
   3211 /**
   3212 * @param {tcuTexture.Sampler} sampler
   3213 * @param {number} ref
   3214 * @param {Array<number>} texCoord
   3215 * @param {number} lod
   3216 * @return {number}
   3217 */
   3218 tcuTexture.TextureCubeView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
   3219    DE_ASSERT(sampler.compare != tcuTexture.CompareMode.COMPAREMODE_NONE);
   3220 
   3221    // Computes (face, s, t).
   3222    var coords = tcuTexture.getCubeFaceCoords(texCoord);
   3223    if (sampler.seamlessCubeMap)
   3224        return tcuTexture.sampleLevelArrayCubeSeamlessCompare(this.m_levels, this.m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
   3225    else
   3226        return tcuTexture.sampleLevelArray2DCompare(this.m_levels[coords.face], this.m_numLevels, sampler, ref, coords.s, coords.t, lod, [0, 0, 0]);
   3227 };
   3228 
   3229 /**
   3230 * @param {tcuTexture.CubeFace} face
   3231 * @return {Array<tcuTexture.ConstPixelBufferAccess>}
   3232 */
   3233 tcuTexture.TextureCubeView.prototype.getFaceLevels = function(face) { return this.m_levels[face]; };
   3234 /** @return {number} */
   3235 tcuTexture.TextureCubeView.prototype.getSize = function() { return this.m_numLevels > 0 ? this.m_levels[0][0].getWidth() : 0; };
   3236 
   3237 /** @return {number} */
   3238 tcuTexture.TextureCubeView.prototype.getNumLevels = function() { return this.m_numLevels; };
   3239 
   3240 /**
   3241 * @param {number} ndx
   3242 * @param {tcuTexture.CubeFace} face
   3243 * @return {tcuTexture.ConstPixelBufferAccess}
   3244 */
   3245 tcuTexture.TextureCubeView.prototype.getLevelFace = function(ndx, face) {
   3246    assertMsgOptions(0 <= ndx && ndx < this.m_numLevels, '', false, true);
   3247    return this.m_levels[face][ndx];
   3248 };
   3249 
   3250 /**
   3251 * @param {number} baseLevel
   3252 * @param {number} maxLevel
   3253 * @return {tcuTexture.TextureCubeView}
   3254 */
   3255 tcuTexture.TextureCubeView.prototype.getSubView = function(baseLevel, maxLevel) {
   3256    var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
   3257    var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
   3258    var numLevels = clampedMax - clampedBase + 1;
   3259    var levels = [];
   3260    for (var face in tcuTexture.CubeFace)
   3261        levels.push(this.getFaceLevels(tcuTexture.CubeFace[face]).slice(clampedBase, numLevels));
   3262 
   3263    return new tcuTexture.TextureCubeView(numLevels, levels);
   3264 };
   3265 
   3266 /**
   3267 * @constructor
   3268 * @param {tcuTexture.TextureFormat} format
   3269 * @param {number} size
   3270 */
   3271 tcuTexture.TextureCube = function(format, size) {
   3272    this.m_format = format;
   3273    this.m_size = size;
   3274    this.m_data = [];
   3275    this.m_data.length = Object.keys(tcuTexture.CubeFace).length;
   3276    this.m_access = [];
   3277    this.m_access.length = Object.keys(tcuTexture.CubeFace).length;
   3278 
   3279    var numLevels = tcuTexture.computeMipPyramidLevels(this.m_size);
   3280    var levels = [];
   3281    levels.length = Object.keys(tcuTexture.CubeFace).length;
   3282 
   3283    for (var face in tcuTexture.CubeFace) {
   3284        this.m_data[tcuTexture.CubeFace[face]] = [];
   3285        for (var i = 0; i < numLevels; i++)
   3286            this.m_data[tcuTexture.CubeFace[face]].push(new tcuTexture.DeqpArrayBuffer());
   3287        this.m_access[tcuTexture.CubeFace[face]] = [];
   3288        this.m_access[tcuTexture.CubeFace[face]].length = numLevels;
   3289        levels[tcuTexture.CubeFace[face]] = this.m_access[tcuTexture.CubeFace[face]];
   3290    }
   3291 
   3292    this.m_view = new tcuTexture.TextureCubeView(numLevels, levels);
   3293 };
   3294 
   3295 /** @return {tcuTexture.TextureFormat} */
   3296 tcuTexture.TextureCube.prototype.getFormat = function() { return this.m_format; };
   3297 /** @return {number} */
   3298 tcuTexture.TextureCube.prototype.getSize = function() { return this.m_size; };
   3299 /** @return {tcuTexture.TextureCubeView} */
   3300 tcuTexture.TextureCube.prototype.getView = function() { return this.m_view; };
   3301 /**
   3302 * @param {number} ndx Level index
   3303 * @param {tcuTexture.CubeFace} face
   3304 * @return {tcuTexture.PixelBufferAccess}
   3305 */
   3306 tcuTexture.TextureCube.prototype.getLevelFace = function(ndx, face) { return this.m_access[face][ndx]; };
   3307 /** @return {number} */
   3308 tcuTexture.TextureCube.prototype.getNumLevels = function() { return this.m_access[0].length; };
   3309 
   3310 /**
   3311 * @param {tcuTexture.Sampler} sampler
   3312 * @param {Array<number>} texCoord
   3313 * @param {number} lod
   3314 * @return {Array<number>} Pixel color
   3315 */
   3316 tcuTexture.TextureCube.prototype.sample = function(sampler, texCoord, lod) {
   3317    return this.m_view.sample(sampler, texCoord, lod);
   3318 };
   3319 
   3320 /**
   3321 * @param {number} baseLevel
   3322 * @param {number} maxLevel
   3323 * @return {tcuTexture.TextureCubeView}
   3324 */
   3325 tcuTexture.TextureCube.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
   3326 
   3327 /**
   3328 * @param {tcuTexture.CubeFace} face
   3329 * @param {number} levelNdx
   3330 * @return {boolean}
   3331 */
   3332 tcuTexture.TextureCube.prototype.isLevelEmpty = function(face, levelNdx) {
   3333    return this.m_data[face][levelNdx].empty();
   3334 };
   3335 
   3336 /**
   3337 * @param {tcuTexture.CubeFace} face
   3338 * @param {number} levelNdx
   3339 */
   3340 tcuTexture.TextureCube.prototype.allocLevel = function(face, levelNdx) {
   3341    /** @const */ var size = tcuTexture.getMipPyramidLevelSize(this.m_size, levelNdx);
   3342    /** @const*/ var dataSize = this.m_format.getPixelSize() * size * size;
   3343    DE_ASSERT(this.isLevelEmpty(face, levelNdx));
   3344 
   3345    this.m_data[face][levelNdx].setStorage(dataSize);
   3346    this.m_access[face][levelNdx] = new tcuTexture.PixelBufferAccess({
   3347        format: this.m_format,
   3348        width: size,
   3349        height: size,
   3350        depth: 1,
   3351        data: this.m_data[face][levelNdx].m_ptr
   3352    });
   3353 };
   3354 
   3355 /**
   3356 * @param {Array<number>} coords Cube coordinates
   3357 * @return {tcuTexture.CubeFace}
   3358 */
   3359 tcuTexture.selectCubeFace = function(coords) {
   3360    var x = coords[0];
   3361    var y = coords[1];
   3362    var z = coords[2];
   3363    var ax = Math.abs(x);
   3364    var ay = Math.abs(y);
   3365    var az = Math.abs(z);
   3366 
   3367    if (ay < ax && az < ax)
   3368        return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
   3369    else if (ax < ay && az < ay)
   3370        return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
   3371    else if (ax < az && ay < az)
   3372        return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
   3373    else {
   3374        // Some of the components are equal. Use tie-breaking rule.
   3375        if (ax == ay) {
   3376            if (ax < az)
   3377                return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
   3378            else
   3379                return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
   3380        } else if (ax == az) {
   3381            if (az < ay)
   3382                return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
   3383            else
   3384                return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
   3385        } else if (ay == az) {
   3386            if (ay < ax)
   3387                return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
   3388            else
   3389                return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
   3390        } else
   3391            return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
   3392    }
   3393 };
   3394 
   3395 /**
   3396 * @param {tcuTexture.CubeFace} face
   3397 * @param {Array<number>} coord Cube coordinates (Vec3)
   3398 * @return {Array<number>} face coordinates (Vec2)
   3399 */
   3400 tcuTexture.projectToFace = function(face, coord) {
   3401    var rx = coord[0];
   3402    var ry = coord[1];
   3403    var rz = coord[2];
   3404    var sc = 0;
   3405    var tc = 0;
   3406    var ma = 0;
   3407 
   3408    switch (face) {
   3409        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
   3410        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
   3411        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
   3412        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
   3413        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
   3414        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
   3415        default:
   3416            throw new Error('Unrecognized face ' + face);
   3417    }
   3418 
   3419    // Compute s, t
   3420    var s = ((sc / ma) + 1) / 2;
   3421    var t = ((tc / ma) + 1) / 2;
   3422 
   3423    return [s, t];
   3424 };
   3425 
   3426 /**
   3427 * @constructor
   3428 * @param {tcuTexture.TextureFormat} format
   3429 * @param {number=} width
   3430 * @param {number=} height
   3431 * @param {number=} depth
   3432 */
   3433 tcuTexture.TextureLevel = function(format, width, height, depth) {
   3434    this.m_format = format;
   3435    this.m_width = width || 0;
   3436    this.m_height = height || 0;
   3437    this.m_depth = depth === undefined ? 1 : depth;
   3438    this.m_data = new tcuTexture.DeqpArrayBuffer();
   3439    this.setSize(this.m_width, this.m_height, this.m_depth);
   3440 };
   3441 
   3442 tcuTexture.TextureLevel.prototype.constructor = tcuTexture.TextureLevel;
   3443 
   3444 /**
   3445 * @param {tcuTexture.TextureFormat} format
   3446 * @param {number=} width
   3447 * @param {number=} height
   3448 * @param {number=} depth
   3449 */
   3450 tcuTexture.TextureLevel.prototype.setStorage = function(format, width, height, depth) {
   3451    this.m_format = format;
   3452    this.setSize(width, height, depth);
   3453 };
   3454 
   3455 /**
   3456 * @param {number=} width
   3457 * @param {number=} height
   3458 * @param {number=} depth
   3459 */
   3460 tcuTexture.TextureLevel.prototype.setSize = function(width, height, depth) {
   3461    var pixelSize = this.m_format.getPixelSize();
   3462 
   3463    this.m_width = width || 0;
   3464    this.m_height = height || 0;
   3465    this.m_depth = depth === undefined ? 1 : depth;
   3466 
   3467    this.m_data.setStorage(this.m_width * this.m_height * this.m_depth * pixelSize);
   3468 };
   3469 
   3470 /**
   3471 * @return {tcuTexture.PixelBufferAccess}
   3472 */
   3473 tcuTexture.TextureLevel.prototype.getAccess = function() {
   3474    return new tcuTexture.PixelBufferAccess({
   3475                    format: this.m_format,
   3476                    width: this.m_width,
   3477                    height: this.m_height,
   3478                    depth: this.m_depth,
   3479                    data: this.m_data.m_ptr
   3480                });
   3481 
   3482 };
   3483 
   3484 /**
   3485 * @return {number}
   3486 */
   3487 tcuTexture.TextureLevel.prototype.getWidth = function() {
   3488    return this.m_width;
   3489 };
   3490 
   3491 /**
   3492 * @return {number}
   3493 */
   3494 tcuTexture.TextureLevel.prototype.getHeight = function() {
   3495    return this.m_height;
   3496 };
   3497 
   3498 /**
   3499 * @return {number}
   3500 */
   3501 tcuTexture.TextureLevel.prototype.getDepth = function() {
   3502    return this.m_depth;
   3503 };
   3504 
   3505 /**
   3506 * @return {?tcuTexture.TextureFormat}
   3507 */
   3508 tcuTexture.TextureLevel.prototype.getFormat = function() {
   3509    return this.m_format;
   3510 };
   3511 
   3512 /**
   3513 * Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceCoords with face set to the appropriate neighboring face and coords transformed accordingly.
   3514 * \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
   3515 * @param {tcuTexture.CubeFaceCoords} origCoords
   3516 * @param {number} size
   3517 * @return {tcuTexture.CubeFaceCoords}
   3518 */
   3519 tcuTexture.remapCubeEdgeCoords = function(origCoords, size) {
   3520    var uInBounds = deMath.deInBounds32(origCoords.s, 0, size);
   3521    var vInBounds = deMath.deInBounds32(origCoords.t, 0, size);
   3522 
   3523    if (uInBounds && vInBounds)
   3524        return origCoords;
   3525 
   3526    if (!uInBounds && !vInBounds)
   3527        return null;
   3528 
   3529    var coords = [
   3530        tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.s, size),
   3531        tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.t, size)];
   3532    var canonizedCoords = [];
   3533 
   3534    // Map the uv coordinates to canonized 3d coordinates.
   3535 
   3536    switch (origCoords.face) {
   3537        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: canonizedCoords = [0, size - 1 - coords[1], coords[0]]; break;
   3538        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: canonizedCoords = [size - 1, size - 1 - coords[1], size - 1 - coords[0]]; break;
   3539        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: canonizedCoords = [coords[0], 0, size - 1 - coords[1]]; break;
   3540        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: canonizedCoords = [coords[0], size - 1, coords[1]]; break;
   3541        case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: canonizedCoords = [size - 1 - coords[0], size - 1 - coords[1], 0]; break;
   3542        case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: canonizedCoords = [coords[0], size - 1 - coords[1], size - 1]; break;
   3543        default: throw new Error('Invalid cube face:' + origCoords.face);
   3544    }
   3545 
   3546    // Find an appropriate face to re-map the coordinates to.
   3547 
   3548    if (canonizedCoords[0] == -1)
   3549        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, [canonizedCoords[2], size - 1 - canonizedCoords[1]]);
   3550 
   3551    if (canonizedCoords[0] == size)
   3552        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, [size - 1 - canonizedCoords[2], size - 1 - canonizedCoords[1]]);
   3553 
   3554    if (canonizedCoords[1] == -1)
   3555        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, [canonizedCoords[0], size - 1 - canonizedCoords[2]]);
   3556 
   3557    if (canonizedCoords[1] == size)
   3558        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, [canonizedCoords[0], canonizedCoords[2]]);
   3559 
   3560    if (canonizedCoords[2] == -1)
   3561        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z, [size - 1 - canonizedCoords[0], size - 1 - canonizedCoords[1]]);
   3562 
   3563    if (canonizedCoords[2] == size)
   3564        return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, [canonizedCoords[0], size - 1 - canonizedCoords[1]]);
   3565 
   3566    throw new Error('Cannot remap cube coordinates');
   3567 };
   3568 
   3569 /**
   3570 * @constructor
   3571 * @param {tcuTexture.ConstPixelBufferAccess} src
   3572 */
   3573 tcuTexture.RGBA8View = function(src) {
   3574    this.src = src;
   3575    this.data = new Uint8Array(src.getBuffer(), src.m_offset);
   3576    this.stride = src.getRowPitch();
   3577    this.width = src.getWidth();
   3578    this.height = src.getHeight();
   3579    this.pixelSize = src.getFormat().getPixelSize();
   3580 };
   3581 
   3582 /**
   3583 * @return {tcuTexture.TextureFormat}
   3584 */
   3585 tcuTexture.RGBA8View.prototype.getFormat = function() { return this.src.getFormat(); };
   3586 
   3587 /**
   3588 * Read a pixel
   3589 * @param {number} x
   3590 * @param {number} y
   3591 * @param {number=} numChannels
   3592 * @return {Array<number>}
   3593 */
   3594 tcuTexture.RGBA8View.prototype.read = function(x, y, numChannels) {
   3595    numChannels = numChannels || 4;
   3596    var offset = y * this.stride + x * this.pixelSize;
   3597    /* Always return a vec4 */
   3598    var result = [0, 0, 0, 255];
   3599    for (var i = 0; i < numChannels; i++)
   3600        result[i] = this.data[offset + i];
   3601    return result;
   3602 };
   3603 
   3604 /**
   3605 * Read a pixel into a Uint32
   3606 * @param {number} x
   3607 * @param {number} y
   3608 * @return {number}
   3609 */
   3610 tcuTexture.RGBA8View.prototype.readUintRGBA8 = function(x, y) {
   3611    var offset = y * this.stride + x * this.pixelSize;
   3612    return ((this.data[offset] & 0xff) << 24) +
   3613        ((this.data[offset + 1] & 0xff) << 16) +
   3614        ((this.data[offset + 2] & 0xff) << 8) +
   3615        (this.data[offset + 3] & 0xff);
   3616 };
   3617 
   3618 /**
   3619 * Write a pixel
   3620 * @param {number} x
   3621 * @param {number} y
   3622 * @param {Array<number>} value
   3623 * @param {number=} numChannels
   3624 */
   3625 tcuTexture.RGBA8View.prototype.write = function(x, y, value, numChannels) {
   3626    numChannels = numChannels || 4;
   3627    var offset = y * this.stride + x * this.pixelSize;
   3628    for (var i = 0; i < numChannels; i++)
   3629        this.data[offset + i] = value[i];
   3630 };
   3631 
   3632 tcuTexture.RGBA8View.prototype.getWidth = function() { return this.width; };
   3633 
   3634 tcuTexture.RGBA8View.prototype.getHeight = function() { return this.height; };
   3635 
   3636 });