tor-browser

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

glsFboUtil.js (44890B)


      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program OpenGL ES Utilities
      3 * ------------------------------------------------
      4 *
      5 * Copyright 2014 The Android Open Source Project
      6 *
      7 * Licensed under the Apache License, Version 2.0 (the "License");
      8 * you may not use this file except in compliance with the License.
      9 * You may obtain a copy of the License at
     10 *
     11 *      http://www.apache.org/licenses/LICENSE-2.0
     12 *
     13 * Unless required by applicable law or agreed to in writing, software
     14 * distributed under the License is distributed on an "AS IS" BASIS,
     15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 * See the License for the specific language governing permissions and
     17 * limitations under the License.
     18 *
     19 */
     20 
     21 'use strict';
     22 goog.provide('modules.shared.glsFboUtil');
     23 goog.require('framework.opengl.gluTextureUtil');
     24 goog.require('framework.opengl.gluStrUtil');
     25 
     26 goog.scope(function() {
     27 
     28    var glsFboUtil = modules.shared.glsFboUtil;
     29    var gluTextureUtil = framework.opengl.gluTextureUtil;
     30    var gluStrUtil = framework.opengl.gluStrUtil;
     31    var DE_ASSERT = function(x) {
     32        if (!x)
     33            throw new Error('Assert failed');
     34    };
     35 
     36    /**
     37    * @constructor
     38    * @template KeyT
     39    * @template ValueT
     40    * @param {function(!KeyT, !KeyT):boolean} comparefnc
     41    */
     42    glsFboUtil.Map = function(comparefnc) {
     43        /** @type {Array<{first: !KeyT, second: ValueT}>} */
     44        this.store = [];
     45        this.compare = comparefnc;
     46        this.length = 0;
     47    };
     48 
     49    /**
     50    * @param {number} num1
     51    * @param {number} num2
     52    * @return {boolean}
     53    */
     54    glsFboUtil.Map.compareNumber = function(num1, num2) {
     55        return num1 < num2;
     56    };
     57 
     58    /**
     59    * @param {!KeyT} key
     60    * @param {ValueT} value
     61    * @return {{first: !KeyT, second: ValueT}}
     62    */
     63    glsFboUtil.Map.prototype.pair = function(key, value) {
     64        return {
     65            first: key,
     66            second: value
     67        };
     68    };
     69 
     70    /**
     71    * @protected
     72    * @param {!KeyT} key
     73    * @return {number}
     74    */
     75    glsFboUtil.Map.prototype.findInsertionPoint = function(key) {
     76        var /** @type {number} */i, /** @type {number} */length;
     77        for (i = 0, length = this.store.length; i < length; ++i) {
     78            if (!this.compare(key, this.store[i].first)) break;
     79        }
     80        return i;
     81    };
     82 
     83    /**
     84    * index should be a value returned from findInsertionPoint.
     85    * returns true if the compare function returns false reflexively
     86    * (i.e. no matter the order in which the keys are passed as arguments).
     87    * @protected
     88    * @param {!KeyT} key
     89    * @param {number} index
     90    * @return {boolean}
     91    */
     92    glsFboUtil.Map.prototype.foundIndexMatches = function(key, index) {
     93        return (
     94            this.store[index] !== undefined &&
     95            !this.compare(this.store[index].first, key)
     96        );
     97    };
     98 
     99    /**
    100    * @param {!KeyT} key
    101    * @return {boolean}
    102    */
    103    glsFboUtil.Map.prototype.isset = function(key) {
    104        return this.foundIndexMatches(key, this.findInsertionPoint(key));
    105    };
    106 
    107    /**
    108    * @param {!KeyT} key
    109    * @param {ValueT} value
    110    */
    111    glsFboUtil.Map.prototype.set = function(key, value) {
    112        var index = this.findInsertionPoint(key);
    113        if (this.foundIndexMatches(key, index)) {
    114            this.store[index].second = value;
    115        } else {
    116            this.store.splice(index, 0, this.pair(key, value));
    117            ++this.length;
    118        }
    119    };
    120 
    121    /**
    122    * @param {!KeyT} key
    123    * @return {?ValueT}
    124    */
    125    glsFboUtil.Map.prototype.remove = function(key) {
    126        var index = this.findInsertionPoint(key);
    127        /** @type {?ValueT} */ var ret = null;
    128        if (this.foundIndexMatches(key, index)) {
    129            ret = this.store[index].second;
    130            this.store.splice(index, 1);
    131            --this.length;
    132        }
    133        return ret;
    134    };
    135 
    136    /**
    137    * @param {KeyT} key
    138    * @return {?{first: KeyT, second: ValueT}}
    139    */
    140    glsFboUtil.Map.prototype.get = function(key) {
    141        var index = this.findInsertionPoint(key);
    142        if (this.foundIndexMatches(key, index)) return this.store[index];
    143        return null;
    144    };
    145 
    146    /**
    147    * @param {KeyT} key
    148    * @return {?ValueT}
    149    */
    150    glsFboUtil.Map.prototype.getValue = function(key) {
    151        var index = this.findInsertionPoint(key);
    152        if (this.foundIndexMatches(key, index)) return this.store[index].second;
    153        return null;
    154    };
    155 
    156    /**
    157    * @param {!KeyT} key
    158    * @param {ValueT} fallback
    159    * @return {ValueT}
    160    */
    161    glsFboUtil.Map.prototype.lookupDefault = function(key, fallback) {
    162        var index = this.findInsertionPoint(key);
    163        if (this.foundIndexMatches(key, index)) return this.store[index].second;
    164        return fallback;
    165    };
    166 
    167    /**
    168    * @param {number} index
    169    * @return {{first: KeyT, second: ValueT}|undefined}
    170    */
    171    glsFboUtil.Map.prototype.getIndex = function(index) {
    172        return this.store[index];
    173    };
    174 
    175    /**
    176    * Use the callback to set the value to be identified by key.
    177    * If a value is already identified by the key, it will be passed to the callback
    178    * @param {!KeyT} key
    179    * @param {function(ValueT=):!ValueT} callback
    180    */
    181    glsFboUtil.Map.prototype.transform = function(key, callback) {
    182        var index = this.findInsertionPoint(key);
    183        if (this.foundIndexMatches(key, index)) {
    184            this.store[index].second = callback(this.store[index].second);
    185        } else {
    186            this.store.splice(index, 0, this.pair(key, callback()));
    187            ++this.length;
    188        }
    189    };
    190 
    191    /**
    192    * removed all elements from the Map
    193    */
    194    glsFboUtil.Map.prototype.clear = function() {
    195        this.store.splice(0, this.length);
    196        this.length = 0;
    197    };
    198 
    199    /**
    200    * @constructor
    201    */
    202    glsFboUtil.FormatDB = function() {
    203        this.m_map = /** @type {glsFboUtil.Map<glsFboUtil.ImageFormat,number>} */(
    204            new glsFboUtil.Map(glsFboUtil.ImageFormat.lessthan)
    205        );
    206    };
    207 
    208    /**
    209    * @param {glsFboUtil.ImageFormat} format
    210    * @param {number} newFlags
    211    */
    212    glsFboUtil.FormatDB.prototype.addFormat = function(format, newFlags) {
    213        this.m_map.transform(format, function(flags) {
    214            return flags | newFlags;
    215        });
    216    };
    217 
    218    /**
    219    * @param {number} requirements
    220    * @return {Array<glsFboUtil.ImageFormat>}
    221    */
    222    glsFboUtil.FormatDB.prototype.getFormats = function(requirements) {
    223        /** @type {Array<glsFboUtil.ImageFormat>} */ var ret = [];
    224        for (var i = 0; i < this.m_map.length; ++i) {
    225            var pair = this.m_map.getIndex(i);
    226            if ((pair.second & requirements) == requirements)
    227            ret.push(pair.first);
    228        }
    229 
    230        return ret;
    231    };
    232 
    233    /**
    234    * @param {glsFboUtil.ImageFormat} format
    235    * @param {number} fallback
    236    * @return {number}
    237    */
    238    glsFboUtil.FormatDB.prototype.getFormatInfo = function(format, fallback) {
    239        return this.m_map.lookupDefault(format, fallback);
    240    };
    241 
    242    /**
    243    * @param {Object} map
    244    * @param {number} key
    245    * @param {number} fallback
    246    * @return {number}
    247    */
    248    glsFboUtil.lookupDefault = function(map, key, fallback) {
    249        return (map[key] !== undefined) ? map[key] : fallback;
    250    };
    251 
    252    /**
    253    * @param {Array<number>} array
    254    * @param {number} item
    255    * @return {boolean}
    256    */
    257    glsFboUtil.contains = function(array, item) {
    258        var l = array.length;
    259        for (var i = 0; i < l; ++i)
    260            if (array[i] == item) return true;
    261        return false;
    262    };
    263 
    264    /**
    265    * @typedef {Array<(number | glsFboUtil.Range<number>)>}
    266    */
    267    glsFboUtil.formatT;
    268 
    269    /**
    270    * @param {glsFboUtil.FormatDB} db
    271    * @param {glsFboUtil.Range<glsFboUtil.formatT>} stdFmts
    272    */
    273    glsFboUtil.addFormats = function(db, stdFmts) {
    274        for (var set = stdFmts.reset(); set = stdFmts.current(); stdFmts.next()) {
    275            for (var fmt = set[1].reset(); fmt = set[1].current(); set[1].next()) {
    276                db.addFormat(glsFboUtil.formatKeyInfo(fmt), set[0]);
    277            }
    278        }
    279    };
    280 
    281    /**
    282    * @param {glsFboUtil.FormatDB} db
    283    * @param {glsFboUtil.Range} extFmts
    284    * @param {WebGLRenderingContextBase=} gl
    285    * @throws {Error}
    286    */
    287    glsFboUtil.addExtFormats = function(db, extFmts, gl) {
    288        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    289        var extensions = gl.getSupportedExtensions();
    290 
    291        // loop through the range, looking at the extentions.
    292        for (var ext = extFmts.reset(); ext = extFmts.current(); extFmts.next()) {
    293            var tokens = ext.extensions.split(/\s+/);
    294 
    295            var supported = function() {
    296                for (var i = 0, l = tokens.length; i < l; ++i)
    297                    if (extensions.indexOf(tokens[i]) === -1) return false;
    298                return true;
    299            }();
    300 
    301            if (supported) {
    302                for (var format = ext.formats.reset(); format = ext.formats.current(); ext.formats.next()) {
    303                    db.addFormat(glsFboUtil.formatKeyInfo(format), ext.flags);
    304                }
    305            }
    306 
    307        }
    308 
    309    };
    310 
    311    /**
    312    * @param {number} glenum
    313    * @param {WebGLRenderingContextBase=} gl
    314    * @return {number}
    315    * @throws {Error}
    316    */
    317    glsFboUtil.formatFlag = function(glenum, gl) {
    318        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    319 
    320        switch (glenum) {
    321         case gl.NONE:
    322            return glsFboUtil.FormatFlags.ANY_FORMAT;
    323         case gl.RENDERBUFFER:
    324            return glsFboUtil.FormatFlags.RENDERBUFFER_VALID;
    325         case gl.TEXTURE:
    326            return glsFboUtil.FormatFlags.TEXTURE_VALID;
    327         case gl.STENCIL_ATTACHMENT:
    328            return glsFboUtil.FormatFlags.STENCIL_RENDERABLE;
    329         case gl.DEPTH_ATTACHMENT:
    330            return glsFboUtil.FormatFlags.DEPTH_RENDERABLE;
    331         default:
    332            if (glenum < gl.COLOR_ATTACHMENT0 || glenum > gl.COLOR_ATTACHMENT15) {
    333                throw new Error('glenum out of range');
    334            }
    335        }
    336        return glsFboUtil.FormatFlags.COLOR_RENDERABLE;
    337    };
    338 
    339    /**
    340    * Remove value from array
    341    * @param {Array} array
    342    * @param {number} value
    343    */
    344    glsFboUtil.remove_from_array = function(array, value) {
    345        var index = 0;
    346        while ((index = array.indexOf(value)) != -1) {
    347            array.splice(index, 1);
    348        }
    349    };
    350 
    351    /**
    352     * glsFboUtil.FormatExtEntry
    353     * @constructor
    354     * @struct
    355     * @param {string=} extensions
    356     * @param {number=} flags
    357     * @param {glsFboUtil.Range=} formats
    358     */
    359    glsFboUtil.FormatExtEntry = function(extensions, flags, formats) {
    360        this.extensions = null;
    361        this.flags = null;
    362        this.formats = null;
    363 
    364        if (extensions !== undefined) {
    365            this.extensions = extensions;
    366            if (flags !== undefined) {
    367                this.flags = flags;
    368                if (formats !== undefined)
    369                    this.formats = formats;
    370            }
    371        }
    372 
    373    };
    374 
    375    /**
    376     * glsFboUtil.Range
    377     * @constructor
    378     * @struct
    379     * @template T
    380     * @param {Array<T>} array
    381     * @param {number=} begin
    382     * @param {number=} end
    383     */
    384    glsFboUtil.Range = function(array, begin, end) {
    385        // @private
    386        this.m_begin = (begin === undefined ? 0 : begin);
    387        // @private
    388        this.m_end = end || array.length;
    389        /**
    390        * @private
    391        * @type {Array<T>}
    392        */
    393        this.m_array = array;
    394        // @private
    395        this.m_index = this.m_begin;
    396    };
    397 
    398    /**
    399    * @return {Array<T>}
    400    */
    401    glsFboUtil.Range.prototype.array = function() {
    402        return this.m_array;
    403    };
    404 
    405    /**
    406    * @return {number}
    407    */
    408    glsFboUtil.Range.prototype.begin = function() {
    409        return this.m_begin;
    410    };
    411 
    412    /**  *generated by script*
    413    * @return {number}
    414    */
    415    glsFboUtil.Range.prototype.end = function() {
    416        return this.m_end;
    417    };
    418 
    419    /**
    420    * Returns the current pointer index as well as the current object
    421    * @param {number} id
    422    * @return {{first: number, second: T}}
    423    */
    424    glsFboUtil.Range.prototype.get = function(id) {
    425        return {
    426            first: id,
    427            second: this.m_array[id]
    428        };
    429    };
    430 
    431    /**
    432    * Sets the internal pointer to the beginning of the range, and returns the first object.
    433    * @return {T}
    434    */
    435    glsFboUtil.Range.prototype.reset = function() {
    436        this.m_index = this.m_begin;
    437        return this.current();
    438    };
    439 
    440    /**
    441    * returns the current object within the specified range. The internal pointer is unaltered.
    442    * @return {T}
    443    */
    444    glsFboUtil.Range.prototype.current = function() {
    445        return this.m_index < this.m_end ? this.m_array[this.m_index] : null;
    446    };
    447 
    448    /**
    449    * Increments the internal pointer
    450    */
    451    glsFboUtil.Range.prototype.next = function() {
    452        ++this.m_index;
    453    };
    454 
    455    /**
    456     * glsFboUtil.rangeArray
    457     * replaces the macro GLS_ARRAY_RANGE
    458     * Creates a new Range object from the specified array, spanning the whole array.
    459     * @template T
    460     * @param {Array<T>} array
    461     * @return {glsFboUtil.Range<T>}
    462     */
    463    glsFboUtil.rangeArray = function(array) {
    464        return new glsFboUtil.Range(array);
    465    };
    466 
    467    /**
    468    * @constructor
    469    * @struct
    470    * @param {number=} format
    471    * @param {number=} unsizedType
    472    */
    473    glsFboUtil.ImageFormat = function(format, unsizedType) {
    474        this.format = format || 0;
    475        //! Type if format is unsized, gl.NONE if sized.
    476        this.unsizedType = unsizedType || 0;
    477 
    478    };
    479 
    480    /**
    481    * @param {!glsFboUtil.ImageFormat} obj1
    482    * @param {!glsFboUtil.ImageFormat} obj2
    483    * @return {boolean}
    484    */
    485    glsFboUtil.ImageFormat.lessthan = function(obj1, obj2) {
    486        return (
    487            (obj1.format < obj2.format) ||
    488            (obj1.format == obj2.format && obj1.unsizedType < obj2.unsizedType)
    489        );
    490    };
    491 
    492    /**
    493    * Sets the object's parameters to gl.NONE
    494    */
    495    glsFboUtil.ImageFormat.prototype.none = function() {
    496        this.format = 0;
    497        this.unsizedType = 0;
    498    };
    499 
    500    /**
    501    * @return {glsFboUtil.ImageFormat}
    502    */
    503    glsFboUtil.ImageFormat.none = function() {
    504        var obj = new glsFboUtil.ImageFormat();
    505        obj.none();
    506        return obj;
    507    };
    508 
    509    // where key is a FormatKey, and a FormatKey is a unsigned 32bit int.
    510 
    511    /**
    512    * @param {number} key
    513    * @return {glsFboUtil.ImageFormat}
    514    */
    515    glsFboUtil.formatKeyInfo = function(key) {
    516        return new glsFboUtil.ImageFormat(
    517            (key & 0x0000ffff),
    518            (key & 0xffff0000) >>> 16
    519        );
    520    };
    521 
    522    /**
    523     * glsFboUtil.Config Class.
    524     * @constructor
    525     */
    526    glsFboUtil.Config = function() {
    527        this.type = glsFboUtil.Config.s_types.CONFIG;
    528        this.target = glsFboUtil.Config.s_target.NONE;
    529    };
    530    /**
    531     * @enum {number}
    532     */
    533    glsFboUtil.Config.s_target = {
    534        NONE: 0,
    535        RENDERBUFFER: 0x8D41,
    536        TEXTURE_2D: 0x0DE1,
    537        TEXTURE_CUBE_MAP: 0x8513,
    538        TEXTURE_3D: 0x806F,
    539        TEXTURE_2D_ARRAY: 0x8C1A,
    540 
    541        FRAMEBUFFER: 0x8D40
    542    };
    543 
    544    // the c++ uses dynamic casts to determain if an object inherits from a
    545    // given class. Here, each class' constructor assigns a bit to obj.type.
    546    // look for the bit to see if an object inherits that class.
    547 
    548    /**
    549    * @enum
    550    */
    551    glsFboUtil.Config.s_types = {
    552        CONFIG: 0x000001,
    553 
    554        IMAGE: 0x000010,
    555        RENDERBUFFER: 0x000020,
    556        TEXTURE: 0x000040,
    557        TEXTURE_FLAT: 0x000080,
    558        TEXTURE_2D: 0x000100,
    559        TEXTURE_CUBE_MAP: 0x000200,
    560        TEXTURE_LAYERED: 0x000400,
    561        TEXTURE_3D: 0x000800,
    562        TEXTURE_2D_ARRAY: 0x001000,
    563 
    564        ATTACHMENT: 0x010000,
    565        ATT_RENDERBUFFER: 0x020000,
    566        ATT_TEXTURE: 0x040000,
    567        ATT_TEXTURE_FLAT: 0x080000,
    568        ATT_TEXTURE_LAYER: 0x100000,
    569 
    570        UNUSED: 0xFFE0E00E
    571    };
    572 
    573    /**
    574     * glsFboUtil.Image Class.
    575     * @constructor
    576     * @extends {glsFboUtil.Config}
    577     */
    578    glsFboUtil.Image = function() {
    579        glsFboUtil.Config.call(this);
    580        this.type |= glsFboUtil.Config.s_types.IMAGE;
    581        this.width = 0;
    582        this.height = 0;
    583        this.internalFormat = new glsFboUtil.ImageFormat();
    584    };
    585 
    586    /**
    587     * glsFboUtil.Renderbuffer Class.
    588     * @constructor
    589     * @extends {glsFboUtil.Image}
    590     */
    591    glsFboUtil.Renderbuffer = function() {
    592        glsFboUtil.Image.call(this);
    593        this.type |= glsFboUtil.Config.s_types.RENDERBUFFER;
    594        this.target = glsFboUtil.Config.s_target.RENDERBUFFER;
    595        this.numSamples = 0;
    596    };
    597 
    598    /**
    599     * glsFboUtil.Texture Class.
    600     * @constructor
    601     * @extends {glsFboUtil.Image}
    602     */
    603    glsFboUtil.Texture = function() {
    604        glsFboUtil.Image.call(this);
    605        this.type |= glsFboUtil.Config.s_types.TEXTURE;
    606        this.numLevels = 1;
    607    };
    608 
    609    /**
    610     * glsFboUtil.TextureFlat Class.
    611     * @constructor
    612     * @extends {glsFboUtil.Texture}
    613     */
    614    glsFboUtil.TextureFlat = function() {
    615        glsFboUtil.Texture.call(this);
    616        this.type |= glsFboUtil.Config.s_types.TEXTURE_FLAT;
    617    };
    618 
    619    /**
    620     * glsFboUtil.Texture2D Class.
    621     * @constructor
    622     * @extends {glsFboUtil.TextureFlat}
    623     */
    624    glsFboUtil.Texture2D = function() {
    625        glsFboUtil.TextureFlat.call(this);
    626        this.type |= glsFboUtil.Config.s_types.TEXTURE_2D;
    627        this.target = glsFboUtil.Config.s_target.TEXTURE_2D;
    628    };
    629 
    630    /**
    631     * glsFboUtil.TextureCubeMap Class.
    632     * @constructor
    633     * @extends {glsFboUtil.TextureFlat}
    634     */
    635    glsFboUtil.TextureCubeMap = function() {
    636        glsFboUtil.TextureFlat.call(this);
    637        this.type |= glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP;
    638        this.target = glsFboUtil.Config.s_target.TEXTURE_CUBE_MAP;
    639    };
    640 
    641    /**
    642     * glsFboUtil.TextureLayered Class.
    643     * @constructor
    644     * @extends {glsFboUtil.Texture}
    645     */
    646    glsFboUtil.TextureLayered = function() {
    647        glsFboUtil.Texture.call(this);
    648        this.type |= glsFboUtil.Config.s_types.TEXTURE_LAYERED;
    649        this.numLayers = 1;
    650    };
    651 
    652    /**
    653     * glsFboUtil.Texture3D Class.
    654     * @constructor
    655     * @extends {glsFboUtil.TextureLayered}
    656     */
    657    glsFboUtil.Texture3D = function() {
    658        glsFboUtil.TextureLayered.call(this);
    659        this.type |= glsFboUtil.Config.s_types.TEXTURE_3D;
    660        this.target = glsFboUtil.Config.s_target.TEXTURE_3D;
    661    };
    662 
    663    /**
    664     * glsFboUtil.Texture2DArray Class.
    665     * @constructor
    666     * @extends {glsFboUtil.TextureLayered}
    667     */
    668    glsFboUtil.Texture2DArray = function() {
    669        glsFboUtil.TextureLayered.call(this);
    670        this.type |= glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY;
    671        this.target = glsFboUtil.Config.s_target.TEXTURE_2D_ARRAY;
    672    };
    673 
    674    /**
    675     * glsFboUtil.Attachment Class.
    676     * @constructor
    677     * @extends {glsFboUtil.Config}
    678     */
    679    glsFboUtil.Attachment = function() {
    680        glsFboUtil.Config.call(this);
    681 
    682        this.type |= glsFboUtil.Config.s_types.ATTACHMENT;
    683 
    684        /** @type {glsFboUtil.Config.s_target} */
    685        this.target = glsFboUtil.Config.s_target.FRAMEBUFFER;
    686 
    687        /** @type {WebGLObject} */
    688        this.imageName = null;
    689    };
    690 
    691    /**
    692    * this function is declared, but has no definition/is unused in the c++
    693    * @param {number} attPoint
    694    * @param {number} image
    695    * @param {number} vfr
    696    */
    697    glsFboUtil.Attachment.prototype.isComplete = function(attPoint, image, vfr) { };
    698 
    699    /**
    700     * glsFboUtil.RenderBufferAttachments Class.
    701     * @constructor
    702     * @extends {glsFboUtil.Attachment}
    703     */
    704    glsFboUtil.RenderbufferAttachment = function() {
    705        glsFboUtil.Attachment.call(this);
    706        this.type |= glsFboUtil.Config.s_types.ATT_RENDERBUFFER;
    707        this.renderbufferTarget = glsFboUtil.Config.s_target.RENDERBUFFER;
    708    };
    709    glsFboUtil.RenderbufferAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
    710    glsFboUtil.RenderbufferAttachment.prototype.constructor = glsFboUtil.RenderbufferAttachment;
    711 
    712    /**
    713     * glsFboUtil.TextureAttachment Class.
    714     * @constructor
    715     * @extends {glsFboUtil.Attachment}
    716     */
    717    glsFboUtil.TextureAttachment = function() {
    718        glsFboUtil.Attachment.call(this);
    719        this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE;
    720        this.level = 0;
    721    };
    722    glsFboUtil.TextureAttachment.prototype = Object.create(glsFboUtil.Attachment.prototype);
    723    glsFboUtil.TextureAttachment.prototype.constructor = glsFboUtil.TextureAttachment;
    724 
    725    /**
    726     * glsFboUtil.TextureFlatAttachment Class.
    727     * @constructor
    728     * @extends {glsFboUtil.TextureAttachment}
    729     */
    730    glsFboUtil.TextureFlatAttachment = function() {
    731        glsFboUtil.TextureAttachment.call(this);
    732        this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT;
    733        this.texTarget = glsFboUtil.Config.s_target.NONE;
    734    };
    735    glsFboUtil.TextureFlatAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
    736    glsFboUtil.TextureFlatAttachment.prototype.constructor = glsFboUtil.TextureFlatAttachment;
    737 
    738    /**
    739     * glsFboUtil.TextureLayerAttachment Class.
    740     * @constructor
    741     * @extends {glsFboUtil.TextureAttachment}
    742     */
    743    glsFboUtil.TextureLayerAttachment = function() {
    744        glsFboUtil.TextureAttachment.call(this);
    745        this.type |= glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER;
    746        this.layer = 0;
    747    };
    748    glsFboUtil.TextureLayerAttachment.prototype = Object.create(glsFboUtil.TextureAttachment.prototype);
    749    glsFboUtil.TextureLayerAttachment.prototype.constructor = glsFboUtil.TextureLayerAttachment;
    750 
    751    // these are a collection of helper functions for creating various gl textures.
    752    glsFboUtil.glsup = function() {
    753 
    754        var glInit = function(cfg, gl) {
    755            if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D) != 0) {
    756                glInitFlat(cfg, glTarget(cfg, gl), gl);
    757 
    758            } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP) != 0) {
    759                for (var i = gl.TEXTURE_CUBE_MAP_NEGATIVE_X; i <= gl.TEXTURE_CUBE_MAP_POSITIVE_Z; ++i)
    760                    glInitFlat(cfg, i, gl);
    761            } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_3D) != 0) {
    762                glInitLayered(cfg, 2, gl);
    763 
    764            } else if ((cfg.type & glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY) != 0) {
    765                glInitLayered(cfg, 1, gl);
    766            }
    767        };
    768 
    769        var glInitFlat = function(cfg, target, gl) {
    770            var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
    771            var w = cfg.width;
    772            var h = cfg.height;
    773            for (var level = 0; level < cfg.numLevels; ++level) {
    774                gl.texImage2D(
    775                    target, level, cfg.internalFormat.format,
    776                    w, h, 0, format.format, format.dataType, null
    777                );
    778                w = Math.max(1, w / 2);
    779                h = Math.max(1, h / 2);
    780            }
    781        };
    782 
    783        var glInitLayered = function(cfg, depth_divider, gl) {
    784            var format = glsFboUtil.transferImageFormat(cfg.internalFormat, gl);
    785            var w = cfg.width;
    786            var h = cfg.height;
    787            var depth = cfg.numLayers;
    788            for (var level = 0; level < cfg.numLevels; ++level) {
    789                gl.texImage3D(
    790                    glTarget(cfg, gl), level, cfg.internalFormat.format,
    791                    w, h, depth, 0, format.format, format.dataType, null
    792                );
    793                w = Math.max(1, w / 2);
    794                h = Math.max(1, h / 2);
    795                depth = Math.max(1, depth / depth_divider);
    796            }
    797        };
    798 
    799        var glCreate = function(cfg, gl) {
    800            if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    801 
    802            if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER) {
    803                var ret = gl.createRenderbuffer();
    804                gl.bindRenderbuffer(gl.RENDERBUFFER, ret);
    805 
    806                if (cfg.numSamples == 0) {
    807                    gl.renderbufferStorage(
    808                        gl.RENDERBUFFER,
    809                        cfg.internalFormat.format,
    810                        cfg.width, cfg.height
    811                    );
    812                } else {
    813                    gl.renderbufferStorageMultisample(
    814                        gl.RENDERBUFFER,
    815                        cfg.numSamples,
    816                        cfg.internalFormat.format,
    817                        cfg.width, cfg.height
    818                    );
    819                }
    820                gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    821 
    822            } else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE) {
    823                var ret = gl.createTexture();
    824                gl.bindTexture(glTarget(cfg, gl), ret);
    825                glInit(cfg, gl);
    826                gl.bindTexture(glTarget(cfg, gl), null);
    827 
    828            } else {
    829                throw new Error('Impossible image type');
    830            }
    831            return ret;
    832        };
    833 
    834        var glTarget = function(cfg, gl) {
    835            if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    836            var mask = (
    837                glsFboUtil.Config.s_types.RENDERBUFFER |
    838                glsFboUtil.Config.s_types.TEXTURE_2D |
    839                glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP |
    840                glsFboUtil.Config.s_types.TEXTURE_3D |
    841                glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY
    842            );
    843            switch (cfg.type & mask) {
    844                case glsFboUtil.Config.s_types.RENDERBUFFER: return gl.RENDERBUFFER;
    845                case glsFboUtil.Config.s_types.TEXTURE_2D: return gl.TEXTURE_2D;
    846                case glsFboUtil.Config.s_types.TEXTURE_CUBE_MAP: return gl.TEXTURE_CUBE_MAP;
    847                case glsFboUtil.Config.s_types.TEXTURE_3D: return gl.TEXTURE_3D;
    848                case glsFboUtil.Config.s_types.TEXTURE_2D_ARRAY: return gl.TEXTURE_2D_ARRAY;
    849                default: break;
    850            }
    851            throw new Error('Impossible image type.');
    852        };
    853 
    854        var glDelete = function(cfg, img, gl) {
    855            if (cfg.type & glsFboUtil.Config.s_types.RENDERBUFFER)
    856                gl.deleteRenderbuffer(img);
    857            else if (cfg.type & glsFboUtil.Config.s_types.TEXTURE)
    858                gl.deleteTexture(img);
    859            else
    860                throw new Error('Impossible image type');
    861        };
    862 
    863        return {
    864            create: glCreate,
    865            remove: glDelete
    866        };
    867 
    868    }();
    869 
    870    /**  *generated by script*
    871    * @param {number} img
    872    * @return {number}
    873    */
    874    glsFboUtil.imageNumSamples = function(img) {
    875        return (img.numSamples != undefined) ? img.numSamples : 0;
    876    };
    877 
    878    /**  *generated by script*
    879    * @param {glsFboUtil.Attachment} att
    880    * @param {number} attPoint
    881    * @param {WebGLRenderingContextBase=} gl
    882    * @throws {Error}
    883    */
    884    glsFboUtil.attachAttachment = function(att, attPoint, gl) {
    885        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    886 
    887        var mask = (
    888            glsFboUtil.Config.s_types.ATT_RENDERBUFFER |
    889            glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT |
    890            glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER
    891        );
    892 
    893        switch (att.type & mask) {
    894            case glsFboUtil.Config.s_types.ATT_RENDERBUFFER:
    895                gl.framebufferRenderbuffer(
    896                    att.target, attPoint, att.renderbufferTarget, /** @type {WebGLRenderbuffer} */(att.imageName)
    897                );
    898                break;
    899            case glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT:
    900                gl.framebufferTexture2D(
    901                    att.target, attPoint, att.texTarget, /** @type {WebGLTexture} */(att.imageName), att.level
    902                );
    903                break;
    904            case glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER:
    905                gl.framebufferTextureLayer(
    906                    att.target, attPoint, /** @type {WebGLTexture} */(att.imageName), att.level, att.layer
    907                );
    908                break;
    909            default:
    910                throw new Error('Impossible attachment type');
    911        }
    912 
    913    };
    914 
    915    /**  *generated by script*
    916    * @param {glsFboUtil.Attachment} att
    917    * @param {WebGLRenderingContextBase=} gl
    918    * @return {number}
    919    * @throws {Error}
    920    */
    921    glsFboUtil.attachmentType = function(att, gl) {
    922        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    923 
    924        if (att.type & glsFboUtil.Config.s_types.ATT_RENDERBUFFER) {
    925            return gl.RENDERBUFFER;
    926        }
    927        if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) {
    928            return gl.TEXTURE;
    929        }
    930        throw new Error('Impossible attachment type.');
    931 
    932    };
    933 
    934    /**
    935    * @param {glsFboUtil.Attachment} att
    936    * @return {number}
    937    * @throws {Error}
    938    */
    939    glsFboUtil.textureLayer = function(att) {
    940        if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_FLAT) return 0;
    941        if (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE_LAYER) return att.layer;
    942        throw new Error('Impossible attachment type.');
    943    };
    944 
    945    /**
    946    * @param {glsFboUtil.Checker} cctx
    947    * @param {glsFboUtil.Attachment} att
    948    * @param {number} attPoint
    949    * @param {glsFboUtil.Image} image
    950    * @param {glsFboUtil.FormatDB} db
    951    * @param {WebGLRenderingContextBase=} gl
    952    * @throws {Error}
    953    */
    954    glsFboUtil.checkAttachmentCompleteness = function(cctx, att, attPoint, image, db, gl) {
    955        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
    956 
    957        // GLES2 4.4.5 / GLES3 4.4.4, "glsFboUtil.Framebuffer attachment completeness"
    958        if (
    959            (att.type & glsFboUtil.Config.s_types.ATT_TEXTURE) &&
    960            (image.type & glsFboUtil.Config.s_types.TEXTURE_LAYERED)
    961        ) {
    962            // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
    963            // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
    964            // three-dimensional texture, then the value of
    965            // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
    966            // of the texture.
    967            //
    968            // GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
    969            // TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
    970            // two-dimensional array texture, then the value of
    971            // FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
    972            // number of layers in the texture.
    973            cctx.addFBOStatus(
    974                glsFboUtil.textureLayer(att) < image.numLayers,
    975                gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
    976            );
    977        }
    978 
    979        // "The width and height of image are non-zero."
    980        cctx.addFBOStatus(
    981            image.width > 0 && image.height > 0,
    982            gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
    983        );
    984 
    985        // Check for renderability
    986        var flags = db.getFormatInfo(image.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
    987 
    988        // If the format does not have the proper renderability flag, the
    989        // completeness check _must_ fail.
    990        cctx.addFBOStatus(
    991            (flags & glsFboUtil.formatFlag(attPoint)) != 0,
    992            gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
    993        );
    994 
    995        // If the format is only optionally renderable, the completeness check _can_ fail.
    996        cctx.addPotentialFBOStatus(
    997            (flags & glsFboUtil.FormatFlags.REQUIRED_RENDERABLE) != 0,
    998            gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
    999        );
   1000 
   1001    };
   1002 
   1003    // replaces GLS_UNSIZED_FORMATKEY
   1004 
   1005    /**
   1006    * All params and return types for this function are 32 bit
   1007    * @param {number} format
   1008    * @param {number} type
   1009    * @return {number}
   1010    */
   1011    glsFboUtil.formatkey = function(format, type) {
   1012        // The formatkey value should be 32-bit unsigned int.
   1013        return ((type << 16) >>> 0 | format) & 0xFFFFFFFF;
   1014    };
   1015 
   1016    /**
   1017    * @enum
   1018    */
   1019    glsFboUtil.FormatFlags = {
   1020        ANY_FORMAT: 0x00,
   1021        COLOR_RENDERABLE: 0x01,
   1022        DEPTH_RENDERABLE: 0x02,
   1023        STENCIL_RENDERABLE: 0x04,
   1024        RENDERBUFFER_VALID: 0x08,
   1025        TEXTURE_VALID: 0x10,
   1026        REQUIRED_RENDERABLE: 0x20 //< Without this, renderability is allowed, not required.
   1027    };
   1028 
   1029    /**
   1030    * A framebuffer configuration
   1031    * @constructor
   1032    * @param {WebGLRenderingContextBase=} gl
   1033    */
   1034    glsFboUtil.Framebuffer = function(gl) {
   1035        this.m_gl = gl || window.gl;
   1036        this.fbid = 0;
   1037 
   1038        var fbidCompare = function(obj1, obj2) {
   1039            return obj1._fbid < obj2._fbid;
   1040        };
   1041 
   1042        this.attachments = /** @type {glsFboUtil.Map<number,glsFboUtil.Attachment>} */(
   1043            new glsFboUtil.Map(glsFboUtil.Map.compareNumber)
   1044        );
   1045        this.textures = /** @type {glsFboUtil.Map<Object,glsFboUtil.Texture>} */(
   1046            new glsFboUtil.Map(fbidCompare)
   1047        );
   1048        this.rbos = /** @type {glsFboUtil.Map<Object,glsFboUtil.Renderbuffer>} */(
   1049            new glsFboUtil.Map(fbidCompare)
   1050        );
   1051    };
   1052 
   1053    /**
   1054    * @param {number} attPoint
   1055    * @param {glsFboUtil.Attachment} att
   1056    */
   1057    glsFboUtil.Framebuffer.prototype.attach = function(attPoint, att) {
   1058        if (!att) {
   1059            this.attachments.remove(attPoint);
   1060        } else {
   1061            this.attachments.set(attPoint, att);
   1062        }
   1063    };
   1064 
   1065    /**
   1066    * @param {WebGLTexture} texName
   1067    * @param {glsFboUtil.Texture} texCfg
   1068    */
   1069    glsFboUtil.Framebuffer.prototype.setTexture = function(texName, texCfg) {
   1070        texName._fbid = this.fbid++;
   1071        this.textures.set(texName, texCfg);
   1072    };
   1073 
   1074    /**
   1075    * @param {WebGLRenderbuffer} rbName
   1076    * @param {glsFboUtil.Renderbuffer} rbCfg
   1077    */
   1078    glsFboUtil.Framebuffer.prototype.setRbo = function(rbName, rbCfg) {
   1079        rbName._fbid = this.fbid++;
   1080        this.rbos.set(rbName, rbCfg);
   1081    };
   1082 
   1083    /**
   1084    * @param {number} type
   1085    * @param {WebGLObject} imgName
   1086    * @return {glsFboUtil.Image}
   1087    * @throws {Error}
   1088    */
   1089    glsFboUtil.Framebuffer.prototype.getImage = function(type, imgName) {
   1090        switch (type) {
   1091            case this.m_gl.TEXTURE: return this.textures.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
   1092            case this.m_gl.RENDERBUFFER: return this.rbos.lookupDefault(/** @type {WebGLTexture} */(imgName), null);
   1093            default: break;
   1094        }
   1095        throw new Error('Bad image type.');
   1096    };
   1097 
   1098    /**
   1099    * @constructor
   1100    * @extends {glsFboUtil.Framebuffer}
   1101    * @param {WebGLFramebuffer} fbo
   1102    * @param {number} target
   1103    * @param {WebGLRenderingContextBase=} gl
   1104    */
   1105    glsFboUtil.FboBuilder = function(fbo, target, gl) {
   1106        glsFboUtil.Framebuffer.call(this, gl);
   1107 
   1108        this.m_gl = gl || window.gl;
   1109        this.m_target = target;
   1110        this.m_configs = [];
   1111        this.m_error = this.m_gl.NO_ERROR;
   1112 
   1113        this.m_gl.bindFramebuffer(this.m_target, fbo);
   1114 
   1115    };
   1116 
   1117    glsFboUtil.FboBuilder.prototype = Object.create(glsFboUtil.Framebuffer.prototype);
   1118    glsFboUtil.FboBuilder.prototype.constructor = glsFboUtil.FboBuilder;
   1119 
   1120    glsFboUtil.FboBuilder.prototype.deinit = function() {
   1121 
   1122        var pair;
   1123        for (var i = 0; i < this.textures.length; ++i) {
   1124            pair = this.textures.getIndex(i);
   1125            glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
   1126        }
   1127        this.textures.clear();
   1128 
   1129        for (var i = 0; i < this.rbos.length; ++i) {
   1130            pair = this.rbos.getIndex(i);
   1131            glsFboUtil.glsup.remove(pair.second, pair.first, this.m_gl);
   1132        }
   1133        this.rbos.clear();
   1134 
   1135        this.m_gl.bindFramebuffer(this.m_target, null);
   1136 /*
   1137        for (var i = 0 ; i < this.m_configs.length ; ++i) {
   1138            delete this.m_configs[i];
   1139        }
   1140 //*/
   1141    };
   1142 
   1143    /**
   1144    * @param {number} attPoint
   1145    * @param {glsFboUtil.Attachment} att
   1146    */
   1147    glsFboUtil.FboBuilder.prototype.glAttach = function(attPoint, att) {
   1148        if (!att) {
   1149            this.m_gl.framebufferRenderbuffer(this.m_target, attPoint, this.m_gl.RENDERBUFFER, null);
   1150        } else {
   1151            glsFboUtil.attachAttachment(att, attPoint, this.m_gl);
   1152        }
   1153        this.checkError();
   1154        this.attach(attPoint, att);
   1155    };
   1156 
   1157    /**
   1158    * @param {glsFboUtil.Texture} texCfg
   1159    * @return {WebGLTexture}
   1160    */
   1161    glsFboUtil.FboBuilder.prototype.glCreateTexture = function(texCfg) {
   1162        var texName = glsFboUtil.glsup.create(texCfg, this.m_gl);
   1163        this.checkError();
   1164        this.setTexture(texName, texCfg);
   1165        return texName;
   1166    };
   1167 
   1168    /**  *generated by script*
   1169    * @param {glsFboUtil.Renderbuffer} rbCfg
   1170    * @return {WebGLRenderbuffer}
   1171    */
   1172    glsFboUtil.FboBuilder.prototype.glCreateRbo = function(rbCfg) {
   1173        var rbName = glsFboUtil.glsup.create(rbCfg, this.m_gl);
   1174        this.checkError();
   1175        this.setRbo(rbName, rbCfg);
   1176        return rbName;
   1177    };
   1178 
   1179    /**
   1180    * @param {function(new:glsFboUtil.Config)} Definition
   1181    * @return {glsFboUtil.Config}
   1182    */
   1183    glsFboUtil.FboBuilder.prototype.makeConfig = function(Definition) {
   1184        var cfg = new Definition();
   1185        this.m_configs.push(cfg);
   1186        return cfg;
   1187    };
   1188 
   1189    /**
   1190    */
   1191    glsFboUtil.FboBuilder.prototype.checkError = function() {
   1192        var error = this.m_gl.getError();
   1193        if (error != this.m_gl.NO_ERROR && this.m_error == this.m_gl.NO_ERROR) {
   1194            this.m_error = error;
   1195        }
   1196    };
   1197 
   1198    /**  *generated by script*
   1199    * @return {number}
   1200    */
   1201    glsFboUtil.FboBuilder.prototype.getError = function() {
   1202        return this.m_error;
   1203    };
   1204 
   1205    glsFboUtil.isFramebufferStatus = function(fboStatus) {
   1206        return gluStrUtil.getFramebufferStatusName(fboStatus) != '';
   1207    }
   1208 
   1209    glsFboUtil.isErrorCode = function(errorCode) {
   1210        return gluStrUtil.getErrorName(errorCode) != '';
   1211    }
   1212 
   1213    /**
   1214    * @typedef {funcion(): glsFboUtil.ValidStatusCodes}
   1215    */
   1216    glsFboUtil.ValidStatusCodes = function() {
   1217        this.m_errorCodes = [];
   1218        this.m_errorStatusCodes = [];
   1219        this.m_allowComplete = false;
   1220    };
   1221 
   1222    glsFboUtil.ValidStatusCodes.prototype.isFBOStatusValid = function(fboStatus) {
   1223        if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
   1224            return this.m_allowComplete;
   1225        else {
   1226            for(var ndx = 0; ndx < this.m_errorStatusCodes.length; ++ndx) {
   1227                if (this.m_errorStatusCodes[ndx] == fboStatus)
   1228                    return true;
   1229            }
   1230            return false;
   1231        }
   1232    };
   1233 
   1234    glsFboUtil.ValidStatusCodes.prototype.isFBOStatusRequired = function(fboStatus) {
   1235        if (fboStatus == gl.FRAMEBUFFER_COMPLETE)
   1236            return this.m_allowComplete && this.m_errorStatusCodes.length == 0;
   1237        else
   1238            // fboStatus is the only allowed error status and succeeding is forbidden
   1239            return !this.m_allowComplete && this.m_errorStatusCodes.length == 1 && this.m_errorStatusCodes[0] == fboStatus;
   1240    };
   1241 
   1242    glsFboUtil.ValidStatusCodes.prototype.isErrorCodeValid = function(errorCode) {
   1243        if (errorCode == gl.NO_ERROR)
   1244            return this.m_errorCodes.length == 0;
   1245        else {
   1246            // rule violation exists?
   1247            for (var ndx = 0; ndx < this.m_errorCodes.length; ++ndx) {
   1248                if (this.m_errorCodes[ndx] == errorCode)
   1249                    return true;
   1250            }
   1251            return false;
   1252        }
   1253    };
   1254 
   1255    glsFboUtil.ValidStatusCodes.prototype.isErrorCodeRequired = function(errorCode) {
   1256        if (this.m_errorCodes.length == 0 && errorCode == gl.NO_ERROR)
   1257            return true;
   1258        else
   1259            // only this error code listed
   1260            return this.m_errorCodes.length == 1 && merrorCodes[0] == errorCode;
   1261    };
   1262 
   1263    glsFboUtil.ValidStatusCodes.prototype.addErrorCode = function(error) {
   1264        DE_ASSERT(glsFboUtil.isErrorCode(error));
   1265        DE_ASSERT(error != gl.NO_ERROR)
   1266        this.m_errorCodes.push(error);
   1267    };
   1268 
   1269    glsFboUtil.ValidStatusCodes.prototype.addFBOErrorStatus = function(status) {
   1270        DE_ASSERT(glsFboUtil.isFramebufferStatus(status));
   1271        DE_ASSERT(status != gl.FRAMEBUFFER_COMPLETE)
   1272        this.m_errorStatusCodes.push(status);
   1273    };
   1274 
   1275    glsFboUtil.ValidStatusCodes.prototype.setAllowComplete = function(b) {
   1276        this.m_allowComplete = b;
   1277    };
   1278 
   1279    /**
   1280    * @typedef {function(): glsFboUtil.Checker}
   1281    */
   1282    glsFboUtil.CheckerFactory;
   1283 
   1284    /**
   1285    * @constructor
   1286    * @param {WebGLRenderingContextBase=} gl
   1287    * @throws {Error}
   1288    */
   1289    glsFboUtil.Checker = function(gl) {
   1290        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
   1291 
   1292        this.m_statusCodes = new glsFboUtil.ValidStatusCodes();
   1293        this.m_statusCodes.setAllowComplete(true);
   1294 
   1295        if (typeof(this.check) != 'function')
   1296            throw new Error('Constructor called on virtual class: glsFboUtil.Checker');
   1297    };
   1298 
   1299    /**
   1300    * @param {boolean} condition
   1301    * @param {number} error
   1302    */
   1303    glsFboUtil.Checker.prototype.addGLError = function(condition, error) {
   1304        if (!condition) {
   1305            this.m_statusCodes.addErrorCode(error);
   1306            this.m_statusCodes.setAllowComplete(false);
   1307        }
   1308    };
   1309 
   1310    /**
   1311    * @param {boolean} condition
   1312    * @param {number} error
   1313    */
   1314    glsFboUtil.Checker.prototype.addPotentialGLError = function(condition, error) {
   1315        if (!condition) {
   1316            this.m_statusCodes.addErrorCode(error);
   1317        }
   1318    };
   1319 
   1320    /**
   1321    * @param {boolean} condition
   1322    * @param {number} status
   1323    */
   1324    glsFboUtil.Checker.prototype.addFBOStatus = function(condition, status) {
   1325        if (!condition) {
   1326            this.m_statusCodes.addFBOErrorStatus(status);
   1327            this.m_statusCodes.setAllowComplete(false);
   1328        }
   1329    };
   1330 
   1331    /**
   1332    * @param {boolean} condition
   1333    * @param {number} status
   1334    */
   1335    glsFboUtil.Checker.prototype.addPotentialFBOStatus = function(condition, status) {
   1336        if (!condition) {
   1337            this.m_statusCodes.addFBOErrorStatus(status);
   1338        }
   1339    };
   1340 
   1341    /**
   1342    * @return {Array<number>}
   1343    */
   1344    glsFboUtil.Checker.prototype.getStatusCodes = function () {
   1345        return this.m_statusCodes;
   1346    };
   1347 
   1348    /**
   1349    * @param {glsFboUtil.ImageFormat} imgFormat
   1350    * @param {WebGLRenderingContextBase=} gl
   1351    * @return {gluTextureUtil.TransferFormat}
   1352    * @throws {Error}
   1353    */
   1354    glsFboUtil.transferImageFormat = function(imgFormat, gl) {
   1355        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
   1356        if (imgFormat.unsizedType == gl.NONE)
   1357            return gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(imgFormat.format));
   1358        else
   1359            return new gluTextureUtil.TransferFormat(imgFormat.format, imgFormat.unsizedType);
   1360    };
   1361 
   1362    // FormatDB, CheckerFactory
   1363 
   1364    /**
   1365    * @constructor
   1366    * @param {glsFboUtil.FormatDB} formats
   1367    * @param {glsFboUtil.CheckerFactory} factory
   1368    */
   1369    glsFboUtil.FboVerifier = function(formats, factory) {
   1370        this.m_formats = formats;
   1371        this.m_factory = factory;
   1372    };
   1373    // config::Framebuffer
   1374    glsFboUtil.FboVerifier.prototype.validStatusCodes = function(cfg, gl) {
   1375        if (!(gl = gl || window.gl)) throw new Error('Invalid gl object');
   1376 
   1377        /** @type {glsFboUtil.Checker} */
   1378        var cctx = this.m_factory();
   1379 
   1380        for (var id = 0; id < cfg.textures.length; ++id) {
   1381            var flags = this.m_formats.getFormatInfo(cfg.textures.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
   1382            var textureIsValid = (flags & glsFboUtil.FormatFlags.TEXTURE_VALID) != 0;
   1383            cctx.addGLError(textureIsValid, gl.INVALID_ENUM);
   1384            cctx.addGLError(textureIsValid, gl.INVALID_OPERATION);
   1385            cctx.addGLError(textureIsValid, gl.INVALID_VALUE);
   1386        }
   1387 
   1388        for (var id = 0; id < cfg.rbos.length; ++id) {
   1389            var flags = this.m_formats.getFormatInfo(cfg.rbos.getIndex(id).second.internalFormat, glsFboUtil.FormatFlags.ANY_FORMAT);
   1390            var rboIsValid = (flags & glsFboUtil.FormatFlags.RENDERBUFFER_VALID) != 0;
   1391            cctx.addGLError(rboIsValid, gl.INVALID_ENUM);
   1392        }
   1393 
   1394        var count = 0;
   1395        for (var index = 0; index < cfg.attachments.length; ++index) {
   1396            var attPoint = cfg.attachments.getIndex(index).first;
   1397            var att = cfg.attachments.getIndex(index).second;
   1398            /** @type {glsFboUtil.Image}*/
   1399            var image = cfg.getImage(glsFboUtil.attachmentType(att, gl), att.imageName);
   1400            glsFboUtil.checkAttachmentCompleteness(cctx, att, attPoint, image, this.m_formats, gl);
   1401            cctx.check(attPoint, att, image);
   1402            ++count;
   1403        }
   1404 
   1405        // "There is at least one image attached to the framebuffer."
   1406        // TODO: support XXX_framebuffer_no_attachments
   1407        cctx.addFBOStatus(count > 0, gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
   1408 
   1409        return cctx.getStatusCodes();
   1410 
   1411    };
   1412 
   1413 });