tor-browser

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

glsBufferTestUtil.js (41334B)


      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.glsBufferTestUtil');
     23 goog.require('framework.common.tcuImageCompare');
     24 goog.require('framework.common.tcuRGBA');
     25 goog.require('framework.common.tcuSurface');
     26 goog.require('framework.common.tcuTestCase');
     27 goog.require('framework.common.tcuTexture');
     28 goog.require('framework.delibs.debase.deMath');
     29 goog.require('framework.delibs.debase.deRandom');
     30 goog.require('framework.delibs.debase.deString');
     31 goog.require('framework.delibs.debase.deUtil');
     32 goog.require('framework.opengl.gluDrawUtil');
     33 goog.require('framework.opengl.gluShaderProgram');
     34 goog.require('framework.opengl.gluShaderUtil');
     35 
     36 goog.scope(function() {
     37 
     38    var glsBufferTestUtil = modules.shared.glsBufferTestUtil;
     39    var tcuImageCompare = framework.common.tcuImageCompare;
     40    var tcuRGBA = framework.common.tcuRGBA;
     41    var tcuSurface = framework.common.tcuSurface;
     42    var tcuTestCase = framework.common.tcuTestCase;
     43    var tcuTexture = framework.common.tcuTexture;
     44    var gluShaderProgram = framework.opengl.gluShaderProgram;
     45    var gluShaderUtil = framework.opengl.gluShaderUtil;
     46    var gluDrawUtil = framework.opengl.gluDrawUtil;
     47    var deUtil = framework.delibs.debase.deUtil;
     48    var deMath = framework.delibs.debase.deMath;
     49    var deRandom = framework.delibs.debase.deRandom;
     50    var deString = framework.delibs.debase.deString;
     51 
     52    glsBufferTestUtil.VERIFY_QUAD_SIZE = 8; //!< Quad size in VertexArrayVerifier
     53    glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW = 128; //!< Maximum number of lines per one draw in IndexArrayVerifier
     54    glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH = 128;
     55    glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT = 128;
     56 
     57    // Helper functions.
     58 
     59    /**
     60     * @param {Uint8Array} ptr
     61     * @param {number} numBytes
     62     * @param {number} seed
     63     */
     64    glsBufferTestUtil.fillWithRandomBytes = function(ptr, numBytes, seed) {
     65        var rnd = new deRandom.Random(seed);
     66        for (var left = numBytes; left > 0; left--)
     67            ptr[left - 1] = rnd.getInt();
     68    };
     69 
     70    /**
     71     * @param {Uint8Array} resPtr
     72     * @param {Uint8Array} refPtr
     73     * @param {number} numBytes
     74     * @return {boolean}
     75     */
     76    glsBufferTestUtil.compareByteArrays = function(resPtr, refPtr, numBytes) {
     77        var isOk = true;
     78        var maxSpanLen = 8;
     79        var maxDiffSpans = 4;
     80        var numDiffSpans = 0;
     81        var diffSpanStart = -1;
     82        var ndx = 0;
     83 
     84        var log = 'Verification result: ';
     85 
     86        for (; ndx < numBytes; ndx++) {
     87            if (resPtr[ndx] != refPtr[ndx]) {
     88                if (diffSpanStart < 0)
     89                    diffSpanStart = ndx;
     90 
     91                isOk = false;
     92            } else if (diffSpanStart >= 0) {
     93                if (numDiffSpans < maxDiffSpans) {
     94                    var len = ndx - diffSpanStart;
     95                    var printLen = Math.min(len, maxSpanLen);
     96 
     97                    log += len + ' byte difference at offset ' + diffSpanStart + '\n' +
     98                        ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) +
     99                        ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen);
    100                } else
    101                    log += '(output too long, truncated)';
    102 
    103                numDiffSpans += 1;
    104                diffSpanStart = -1;
    105            }
    106        }
    107 
    108        if (diffSpanStart >= 0) {
    109            if (numDiffSpans < maxDiffSpans) {
    110                var len = ndx - diffSpanStart;
    111                var printLen = Math.min(len, maxSpanLen);
    112 
    113                log += len + ' byte difference at offset ' + diffSpanStart + '\n' +
    114                    ' expected ' + refPtr.subarray(diffSpanStart, diffSpanStart + printLen) +
    115                    ' got ' + resPtr.subarray(diffSpanStart, diffSpanStart + printLen);
    116            } else
    117                log += '(output too long, truncated)';
    118        }
    119 
    120        log += (isOk ? 'Verification passed.' : 'Verification FAILED!');
    121 
    122        bufferedLogToConsole(log);
    123 
    124        return isOk;
    125    };
    126 
    127    /**
    128     * @param {number} target
    129     * @return {string}
    130     */
    131    glsBufferTestUtil.getBufferTargetName = function(target) {
    132        switch (target) {
    133            case gl.ARRAY_BUFFER: return 'array';
    134            case gl.COPY_READ_BUFFER: return 'copy_read';
    135            case gl.COPY_WRITE_BUFFER: return 'copy_write';
    136            case gl.ELEMENT_ARRAY_BUFFER: return 'element_array';
    137            case gl.PIXEL_PACK_BUFFER: return 'pixel_pack';
    138            case gl.PIXEL_UNPACK_BUFFER: return 'pixel_unpack';
    139            //case gl.TEXTURE_BUFFER: return "texture"; //TODO: Unimplemented in WebGL 2. Remove?
    140            case gl.TRANSFORM_FEEDBACK_BUFFER: return 'transform_feedback';
    141            case gl.UNIFORM_BUFFER: return 'uniform';
    142            default:
    143                throw new Error('Invalid buffer target');
    144        }
    145    };
    146 
    147    /**
    148     * @param {number} hint
    149     * @return {string}
    150     */
    151    glsBufferTestUtil.getUsageHintName = function(hint) {
    152        switch (hint) {
    153            case gl.STREAM_DRAW: return 'stream_draw';
    154            case gl.STREAM_READ: return 'stream_read';
    155            case gl.STREAM_COPY: return 'stream_copy';
    156            case gl.STATIC_DRAW: return 'static_draw';
    157            case gl.STATIC_READ: return 'static_read';
    158            case gl.STATIC_COPY: return 'static_copy';
    159            case gl.DYNAMIC_DRAW: return 'dynamic_draw';
    160            case gl.DYNAMIC_READ: return 'dynamic_read';
    161            case gl.DYNAMIC_COPY: return 'dynamic_copy';
    162            default:
    163            throw new Error('Invalid buffer usage hint');
    164        }
    165    };
    166 
    167    // Base class for buffer cases.
    168    // BufferCase
    169 
    170    /**
    171     * @constructor
    172     * @extends {tcuTestCase.DeqpTest}
    173     * @param {string} name
    174     * @param {string} description
    175     */
    176    glsBufferTestUtil.BufferCase = function(name, description) {
    177        tcuTestCase.DeqpTest.call(this, name, description);
    178        /** @type {Array<WebGLBuffer>} */ this.m_allocatedBuffers = [];
    179    };
    180 
    181    glsBufferTestUtil.BufferCase.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
    182    glsBufferTestUtil.BufferCase.prototype.constructor = glsBufferTestUtil.BufferCase;
    183 
    184    /**
    185     * init
    186     */
    187    glsBufferTestUtil.BufferCase.prototype.init = function() {};
    188 
    189    /**
    190     * deinit
    191     */
    192    glsBufferTestUtil.BufferCase.prototype.deinit = function() {
    193        for (var ndx = 0; ndx < this.m_allocatedBuffers.length; ndx++)
    194            this.deleteBuffer(this.m_allocatedBuffers[ndx]);
    195    };
    196 
    197    /**
    198     * @return {WebGLBuffer}
    199     */
    200    glsBufferTestUtil.BufferCase.prototype.genBuffer = function() {
    201        var buf = 0;
    202        buf = gl.createBuffer();
    203        if (buf != 0) {
    204            try {
    205                deUtil.dePushUniqueToArray(this.m_allocatedBuffers, buf);
    206            }
    207            catch (err) {
    208                gl.deleteBuffer(buf);
    209                throw err;
    210            }
    211        }
    212        return buf;
    213    };
    214 
    215    /**
    216     * @param {WebGLBuffer} buffer
    217     */
    218    glsBufferTestUtil.BufferCase.prototype.deleteBuffer = function(buffer) {
    219        gl.deleteBuffer(buffer);
    220        this.m_allocatedBuffers.splice(this.m_allocatedBuffers.indexOf(buffer), 1);
    221    };
    222 
    223    glsBufferTestUtil.BufferCase.prototype.checkError = function() {
    224        /** @type {number} */ var err = gl.getError();
    225        if (err != gl.NO_ERROR)
    226            throw new TestFailedException('Got ' + WebGLTestUtils.glEnumToString(gl, err));
    227    };
    228 
    229    // Reference buffer.
    230 
    231    /**
    232     * @constructor
    233     */
    234    glsBufferTestUtil.ReferenceBuffer = function() {
    235        /** @type {ArrayBuffer} */ this.m_data;
    236    };
    237 
    238    /**
    239     * @param {number=} offset
    240     * @return {Uint8Array}
    241     */
    242    glsBufferTestUtil.ReferenceBuffer.prototype.getPtr = function(offset) {
    243        offset = offset ? offset : 0; return new Uint8Array(this.m_data, offset);
    244    };
    245 
    246    /**
    247     * @param {number} numBytes
    248     */
    249    glsBufferTestUtil.ReferenceBuffer.prototype.setSize = function(numBytes) {
    250        this.m_data = new ArrayBuffer(numBytes);
    251    };
    252 
    253    /**
    254     * @param {number} numBytes
    255     * @param {Uint8Array} bytes
    256     */
    257    glsBufferTestUtil.ReferenceBuffer.prototype.setData = function(numBytes, bytes) {
    258        this.setSize(numBytes);
    259        var dst = new Uint8Array(this.m_data);
    260        dst.set(bytes.subarray(numBytes));
    261    };
    262 
    263    /**
    264     * @param {number} offset
    265     * @param {number} numBytes
    266     * @param {Uint8Array} bytes
    267     */
    268    glsBufferTestUtil.ReferenceBuffer.prototype.setSubData = function(offset, numBytes, bytes) {
    269        assertMsgOptions(deMath.deInBounds32(offset, 0, this.m_data.byteLength) && deMath.deInRange32(offset + numBytes, offset, this.m_data.byteLength),
    270            'Parameters not in buffer bounds or range', false, true);
    271        var dst = new Uint8Array(this.m_data, offset);
    272        dst.set(bytes.subarray(offset, offset + numBytes));
    273    };
    274 
    275    // Buffer writer system.
    276 
    277    /**
    278     * @enum {number}
    279     */
    280    glsBufferTestUtil.WriteType = {
    281        BUFFER_SUB_DATA: 0,
    282        BUFFER_WRITE_MAP: 1,
    283        TRANSFORM_FEEDBACK: 2,
    284        PIXEL_PACK: 3
    285    };
    286 
    287    /**
    288     * @param {glsBufferTestUtil.WriteType} write
    289     * @return {string}
    290     */
    291    glsBufferTestUtil.getWriteTypeDescription = function(write) {
    292        /** @type {Array<string>} */ var s_desc = [
    293            'gl.bufferSubData()',
    294            'gl.mapBufferRange()',
    295            'transform feedback',
    296            'gl.readPixels() into PBO binding'
    297        ];
    298        return /** @type {string} */ (deUtil.getArrayElement(s_desc, write));
    299    };
    300 
    301    // BufferWriterBase
    302 
    303    /**
    304     * @constructor
    305     */
    306    glsBufferTestUtil.BufferWriterBase = function() {};
    307 
    308    /**
    309     * //Meant to be overriden
    310     * @return {number}
    311     */
    312    glsBufferTestUtil.BufferWriterBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); };
    313 
    314    /**
    315     * //Meant to be overriden
    316     * @return {number}
    317     */
    318    glsBufferTestUtil.BufferWriterBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); };
    319 
    320    /**
    321     * //Meant to be overriden
    322     * @param {WebGLBuffer} buffer
    323     * @param {number} offset
    324     * @param {number} numBytes
    325     * @param {Uint8Array} bytes
    326     */
    327    glsBufferTestUtil.BufferWriterBase.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) { throw new Error('Must be overriden'); };
    328 
    329    /**
    330     * @param {WebGLBuffer} buffer
    331     * @param {number} offset
    332     * @param {number} numBytes
    333     * @param {Uint8Array} bytes
    334     * @param {number} targetHint
    335     */
    336    glsBufferTestUtil.BufferWriterBase.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) {
    337        this.writeNoTarget(buffer, offset, numBytes, bytes);
    338    };
    339 
    340    // BufferWriter
    341 
    342    /**
    343     * @constructor
    344     * @param {glsBufferTestUtil.WriteType} writeType
    345     */
    346    glsBufferTestUtil.BufferWriter = function(writeType) {
    347        /** @type {glsBufferTestUtil.BufferWriterBase} */ this.m_writer = null;
    348        switch (writeType) {
    349            case glsBufferTestUtil.WriteType.BUFFER_SUB_DATA: this.m_writer = new glsBufferTestUtil.BufferSubDataWriter(); break;
    350            default:
    351                testFailed('Unsupported writer');
    352        }
    353    };
    354 
    355    /**
    356     * @return {number}
    357     */
    358    glsBufferTestUtil.BufferWriter.prototype.getMinSize = function() {return this.m_writer.getMinSize();};
    359 
    360    /**
    361     * @return {number}
    362     */
    363    glsBufferTestUtil.BufferWriter.prototype.getAlignment = function() {return this.m_writer.getAlignment();};
    364 
    365    /**
    366     * @param {WebGLBuffer} buffer
    367     * @param {number} offset
    368     * @param {number} numBytes
    369     * @param {Uint8Array} bytes
    370     */
    371    glsBufferTestUtil.BufferWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) {
    372        assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
    373        assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
    374        assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
    375        return this.m_writer.writeNoTarget(buffer, offset, numBytes, bytes);
    376    };
    377 
    378    /**
    379     * @param {WebGLBuffer} buffer
    380     * @param {number} offset
    381     * @param {number} numBytes
    382     * @param {Uint8Array} bytes
    383     * @param {number} targetHint
    384     */
    385    glsBufferTestUtil.BufferWriter.prototype.write = function(buffer, offset, numBytes, bytes, targetHint) {
    386        assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
    387        assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
    388        assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
    389        return this.m_writer.write(buffer, offset, numBytes, bytes, targetHint);
    390    };
    391 
    392    // BufferSubDataWriter
    393 
    394    /**
    395     * @constructor
    396     * @extends {glsBufferTestUtil.BufferWriterBase}
    397     */
    398    glsBufferTestUtil.BufferSubDataWriter = function() {
    399        glsBufferTestUtil.BufferWriterBase.call(this);
    400    };
    401 
    402    glsBufferTestUtil.BufferSubDataWriter.prototype = Object.create(glsBufferTestUtil.BufferWriterBase.prototype);
    403    glsBufferTestUtil.BufferSubDataWriter.prototype.constructor = glsBufferTestUtil.BufferSubDataWriter;
    404 
    405    /**
    406     * @return {number}
    407     */
    408    glsBufferTestUtil.BufferSubDataWriter.prototype.getMinSize = function() { return 1; };
    409 
    410    /**
    411     * @return {number}
    412     */
    413    glsBufferTestUtil.BufferSubDataWriter.prototype.getAlignment = function() { return 1; };
    414 
    415    /**
    416     * @param {WebGLBuffer} buffer
    417     * @param {number} offset
    418     * @param {number} numBytes
    419     * @param {Uint8Array} bytes
    420     */
    421    glsBufferTestUtil.BufferSubDataWriter.prototype.writeNoTarget = function(buffer, offset, numBytes, bytes) {
    422        this.write(buffer, offset, numBytes, bytes, gl.ARRAY_BUFFER);
    423    };
    424 
    425    /**
    426     * @param {WebGLBuffer} buffer
    427     * @param {number} offset
    428     * @param {number} numBytes
    429     * @param {Uint8Array} bytes
    430     * @param {number} target
    431     */
    432    glsBufferTestUtil.BufferSubDataWriter.prototype.write = function(buffer, offset, numBytes, bytes, target) {
    433        gl.bindBuffer(target, buffer);
    434        gl.bufferSubData(target, offset, bytes);
    435        gl.bindBuffer(target, null);
    436    };
    437 
    438    // Buffer verifier system.
    439 
    440    /**
    441     * @enum {number}
    442     */
    443    glsBufferTestUtil.VerifyType = {
    444        AS_VERTEX_ARRAY: 0,
    445        AS_INDEX_ARRAY: 1,
    446        AS_UNIFORM_BUFFER: 2,
    447        AS_PIXEL_UNPACK_BUFFER: 3,
    448        BUFFER_READ_MAP: 4
    449    };
    450 
    451    /**
    452     * @param {glsBufferTestUtil.VerifyType} verify
    453     * @return {string}
    454     */
    455    glsBufferTestUtil.getVerifyTypeDescription = function(verify) {
    456        /** @type {Array<string>} */ var s_desc =
    457        [
    458            'rendering as vertex data',
    459            'rendering as index data',
    460            'reading in shader as uniform buffer data',
    461            'using as PBO and uploading to texture',
    462            'reading back using glMapBufferRange()'
    463        ];
    464 
    465        return /** @type {string} */ (deUtil.getArrayElement(s_desc, verify));
    466    };
    467 
    468    /**
    469     * @constructor
    470     */
    471    glsBufferTestUtil.BufferVerifierBase = function() {};
    472 
    473    /**
    474     * //Meant to be overriden
    475     * @return {number}
    476     */
    477    glsBufferTestUtil.BufferVerifierBase.prototype.getMinSize = function() { throw new Error('Must be overriden'); };
    478 
    479    /**
    480     * //Meant to be overriden
    481     * @return {number}
    482     */
    483    glsBufferTestUtil.BufferVerifierBase.prototype.getAlignment = function() { throw new Error('Must be overriden'); };
    484 
    485    /**
    486     * @param {WebGLBuffer} buffer
    487     * @param {Uint8Array} reference
    488     * @param {number} offset
    489     * @param {number} numBytes
    490     * @return {boolean}
    491     */
    492    glsBufferTestUtil.BufferVerifierBase.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) {
    493        throw new Error('Must be overriden');
    494    };
    495 
    496    /**
    497     * //Meant to be overriden
    498     * @param {WebGLBuffer} buffer
    499     * @param {Uint8Array} reference
    500     * @param {number} offset
    501     * @param {number} numBytes
    502     * @param {number} targetHint
    503     * @return {boolean}
    504     */
    505    glsBufferTestUtil.BufferVerifierBase.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) {
    506        //In WebGL 2, ELEMENT_ARRAY_BUFFER and TRANSFORM_FEEDBACK_BUFFER cannot be rebound to a different
    507        //type of buffer, so, let's copy their data to an ARRAY BUFFER and pass that one instead to be verified.
    508        var wasReadBufferCreated = false;
    509        try {
    510            if (targetHint == gl.ELEMENT_ARRAY_BUFFER || targetHint == gl.TRANSFORM_FEEDBACK_BUFFER) {
    511                var readBuffer = new Uint8Array(offset + numBytes);
    512                gl.getBufferSubData(targetHint, 0, readBuffer);
    513                buffer = gl.createBuffer();
    514 
    515                wasReadBufferCreated = true;
    516 
    517                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    518                gl.bufferData(gl.ARRAY_BUFFER, readBuffer, gl.STATIC_DRAW);
    519            }
    520 
    521            var result = this.verifyNoTarget(buffer, reference, offset, numBytes);
    522 
    523            if (wasReadBufferCreated)
    524                gl.deleteBuffer(buffer);
    525 
    526            return result;
    527        } catch (err) {
    528            if (wasReadBufferCreated)
    529                gl.deleteBuffer(buffer);
    530            throw err;
    531        }
    532    };
    533 
    534    // BufferVerifier
    535 
    536    /**
    537     * @constructor
    538     * @param {glsBufferTestUtil.VerifyType} verifyType
    539     */
    540    glsBufferTestUtil.BufferVerifier = function(verifyType) {
    541        /** @type {glsBufferTestUtil.BufferVerifierBase} */ this.m_verifier = null;
    542        switch (verifyType) {
    543            case glsBufferTestUtil.VerifyType.AS_VERTEX_ARRAY: this.m_verifier = new glsBufferTestUtil.VertexArrayVerifier(); break;
    544            case glsBufferTestUtil.VerifyType.AS_INDEX_ARRAY: this.m_verifier = new glsBufferTestUtil.IndexArrayVerifier(); break;
    545            default:
    546                testFailed('Unsupported verifier type');
    547        }
    548    };
    549 
    550    /**
    551     * @return {number}
    552     */
    553    glsBufferTestUtil.BufferVerifier.prototype.getMinSize = function() { return this.m_verifier.getMinSize(); };
    554 
    555    /**
    556     * @return {number}
    557     */
    558    glsBufferTestUtil.BufferVerifier.prototype.getAlignment = function() { return this.m_verifier.getAlignment(); };
    559 
    560    /**
    561     * @param {WebGLBuffer} buffer
    562     * @param {Uint8Array} reference
    563     * @param {number} numBytes
    564     * @return {boolean}
    565     */
    566    glsBufferTestUtil.BufferVerifier.prototype.verifyNoTarget = function(buffer, reference, offset, numBytes) {
    567        assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
    568        assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
    569        assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
    570        return this.m_verifier.verifyNoTarget(buffer, reference, offset, numBytes);
    571    };
    572 
    573    /**
    574     * @param {WebGLBuffer} buffer
    575     * @param {Uint8Array} reference
    576     * @param {number} offset
    577     * @param {number} numBytes
    578     * @param {number} targetHint
    579     * @return {boolean}
    580     */
    581    glsBufferTestUtil.BufferVerifier.prototype.verify = function(buffer, reference, offset, numBytes, targetHint) {
    582        assertMsgOptions(numBytes >= this.getMinSize(), 'Number of bytes to write is smaller than the minimum size.', false, true);
    583        assertMsgOptions(offset % this.getAlignment() == 0, 'Offset is not aligned.', false, true);
    584        assertMsgOptions((offset + numBytes) % this.getAlignment() == 0, 'Buffer segment is not aligned', false, true);
    585        return this.m_verifier.verify(buffer, reference, offset, numBytes, targetHint);
    586    };
    587 
    588    // VertexArrayVerifier
    589 
    590    /**
    591     * @constructor
    592     * @extends {glsBufferTestUtil.BufferVerifierBase}
    593     */
    594    glsBufferTestUtil.VertexArrayVerifier = function() {
    595        glsBufferTestUtil.BufferVerifierBase.call(this);
    596        /** @type {gluShaderProgram.ShaderProgram} */ this.m_program = null;
    597        this.m_posLoc = 0;
    598        this.m_byteVecLoc = 0;
    599        /** @type {WebGLVertexArrayObject} */ this.m_vao = null;
    600 
    601        /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.getGLSLVersion(gl);
    602 
    603        assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'Unsupported GLSL version', false, true);
    604 
    605        this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(
    606            gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
    607            'in highp vec2 a_position;\n' +
    608            'in mediump vec3 a_byteVec;\n' +
    609            'out mediump vec3 v_byteVec;\n' +
    610            'void main (void)\n' +
    611            '{\n' +
    612            ' gl_Position = vec4(a_position, 0.0, 1.0);\n' +
    613            ' v_byteVec = a_byteVec;\n' +
    614            '}\n',
    615 
    616            gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
    617            'in mediump vec3 v_byteVec;\n' +
    618            'layout(location = 0) out mediump vec4 o_color;\n' +
    619            'void main (void)\n' +
    620            '{\n' +
    621            ' o_color = vec4(v_byteVec, 1.0);\n' +
    622            '}\n'
    623        ));
    624 
    625        if (!this.m_program.isOk()) {
    626            testFailed('Compile failed');
    627        }
    628 
    629        this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
    630        this.m_byteVecLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_byteVec');
    631 
    632        this.m_vao = gl.createVertexArray();
    633        this.m_positionBuf = gl.createBuffer();
    634        this.m_indexBuf = gl.createBuffer();
    635    };
    636 
    637    glsBufferTestUtil.VertexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype);
    638    glsBufferTestUtil.VertexArrayVerifier.prototype.constructor = glsBufferTestUtil.VertexArrayVerifier;
    639 
    640    /**
    641     * @return {number}
    642     */
    643    glsBufferTestUtil.VertexArrayVerifier.prototype.getMinSize = function() { return 3 * 4; };
    644 
    645    /**
    646     * @return {number}
    647     */
    648    glsBufferTestUtil.VertexArrayVerifier.prototype.getAlignment = function() { return 1; };
    649 
    650    /**
    651     * deinit
    652     */
    653    glsBufferTestUtil.VertexArrayVerifier.prototype.deinit = function() {
    654        if (this.m_vao) gl.deleteVertexArray(this.m_vao);
    655        if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf);
    656        if (this.m_indexBuf) gl.deleteBuffer(this.m_indexBuf);
    657    };
    658 
    659    /**
    660     * @param {number} gridSizeX
    661     * @param {number} gridSizeY
    662     * @return {Array<number>}
    663     */
    664    glsBufferTestUtil.computePositions = function(gridSizeX, gridSizeY) {
    665        var positions = [];
    666 
    667        for (var y = 0; y < gridSizeY; y++)
    668        for (var x = 0; x < gridSizeX; x++) {
    669            /** @type {number} */ var sx0 = (x + 0) / gridSizeX;
    670            /** @type {number} */ var sy0 = (y + 0) / gridSizeY;
    671            /** @type {number} */ var sx1 = (x + 1) / gridSizeX;
    672            /** @type {number} */ var sy1 = (y + 1) / gridSizeY;
    673            /** @type {number} */ var fx0 = 2.0 * sx0 - 1.0;
    674            /** @type {number} */ var fy0 = 2.0 * sy0 - 1.0;
    675            /** @type {number} */ var fx1 = 2.0 * sx1 - 1.0;
    676            /** @type {number} */ var fy1 = 2.0 * sy1 - 1.0;
    677            /** @type {number} */ var baseNdx = (y * gridSizeX + x) * 8;
    678 
    679            positions[baseNdx + 0] = fx0; positions[baseNdx + 1] = fy0;
    680            positions[baseNdx + 2] = fx0; positions[baseNdx + 3] = fy1;
    681            positions[baseNdx + 4] = fx1; positions[baseNdx + 5] = fy0;
    682            positions[baseNdx + 6] = fx1; positions[baseNdx + 7] = fy1;
    683        }
    684 
    685        return positions;
    686    };
    687 
    688    /**
    689     * @param {number} gridSizeX
    690     * @param {number} gridSizeY
    691     * @return {Uint16Array}
    692     */
    693    glsBufferTestUtil.computeIndices = function(gridSizeX, gridSizeY) {
    694        var indices = new Uint16Array(3 * 2 * gridSizeX * gridSizeY);
    695 
    696        for (var quadNdx = 0; quadNdx < gridSizeX * gridSizeY; quadNdx++) {
    697            /** @type {number} */ var v00 = quadNdx * 4 + 0;
    698            /** @type {number} */ var v01 = quadNdx * 4 + 1;
    699            /** @type {number} */ var v10 = quadNdx * 4 + 2;
    700            /** @type {number} */ var v11 = quadNdx * 4 + 3;
    701 
    702            assertMsgOptions(v11 < (1 << 16), 'Vertex index value won\'t fit into a 16-bit number', false, true);
    703 
    704            indices[quadNdx * 6 + 0] = v10;
    705            indices[quadNdx * 6 + 1] = v00;
    706            indices[quadNdx * 6 + 2] = v01;
    707 
    708            indices[quadNdx * 6 + 3] = v10;
    709            indices[quadNdx * 6 + 4] = v01;
    710            indices[quadNdx * 6 + 5] = v11;
    711        }
    712 
    713        return indices;
    714    };
    715 
    716    /**
    717     * @param {Uint8Array} ptr
    718     * @param {number} vtxNdx
    719     * @return {Array<number>}
    720     */
    721    glsBufferTestUtil.fetchVtxColor = function(ptr, vtxNdx) {
    722        return new tcuRGBA.RGBA([
    723            ptr[vtxNdx * 3 + 0],
    724            ptr[vtxNdx * 3 + 1],
    725            ptr[vtxNdx * 3 + 2],
    726            255]).toVec();
    727    };
    728 
    729    /**
    730     * @param {tcuSurface.Surface} dst
    731     * @param {number} numQuads
    732     * @param {number} rowLength
    733     * @param {Uint8Array} inPtr
    734     */
    735    glsBufferTestUtil.renderQuadGridReference = function(dst, numQuads, rowLength, inPtr) {
    736        dst.setSize(rowLength * glsBufferTestUtil.VERIFY_QUAD_SIZE, (Math.floor(numQuads / rowLength) + (numQuads % rowLength != 0 ? 1 : 0)) * glsBufferTestUtil.VERIFY_QUAD_SIZE);
    737 
    738        /** @type {tcuTexture.PixelBufferAccess} */ var dstAccess = dst.getAccess();
    739        dstAccess.clear([0, 0, 0, 1.0]);
    740 
    741        for (var quadNdx = 0; quadNdx < numQuads; quadNdx++) {
    742            /** @type {number} */ var x0 = (quadNdx % rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE;
    743            /** @type {number} */ var y0 = Math.floor(quadNdx / rowLength) * glsBufferTestUtil.VERIFY_QUAD_SIZE;
    744            /** @type {Array<number>} */ var v00 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 0);
    745            /** @type {Array<number>} */ var v10 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 1);
    746            /** @type {Array<number>} */ var v01 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 2);
    747            /** @type {Array<number>} */ var v11 = glsBufferTestUtil.fetchVtxColor(inPtr, quadNdx * 4 + 3);
    748 
    749            for (var y = 0; y < glsBufferTestUtil.VERIFY_QUAD_SIZE; y++)
    750            for (var x = 0; x < glsBufferTestUtil.VERIFY_QUAD_SIZE; x++) {
    751                /** @type {number} */ var fx = (x + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE;
    752                /** @type {number} */ var fy = (y + 0.5) / glsBufferTestUtil.VERIFY_QUAD_SIZE;
    753 
    754                /** @type {boolean} */ var tri = fx + fy <= 1.0;
    755                /** @type {number} */ var tx = tri ? fx : (1.0 - fx);
    756                /** @type {number} */ var ty = tri ? fy : (1.0 - fy);
    757                /** @type {Array<number>} */ var t0 = tri ? v00 : v11;
    758                /** @type {Array<number>} */ var t1 = tri ? v01 : v10;
    759                /** @type {Array<number>} */ var t2 = tri ? v10 : v01;
    760                /** @type {Array<number>} */ var color = deMath.add(
    761                    deMath.add(t0, deMath.scale(deMath.subtract(t1, t0), tx)),
    762                    deMath.scale(deMath.subtract(t2, t0), ty)
    763                );
    764 
    765                dstAccess.setPixel(color, x0 + x, y0 + y);
    766            }
    767        }
    768    };
    769 
    770    /**
    771     * @param {WebGLBuffer} buffer
    772     * @param {Uint8Array} refPtr
    773     * @param {number} offset
    774     * @param {number} numBytes
    775     * @return {boolean}
    776     */
    777    glsBufferTestUtil.VertexArrayVerifier.prototype.verifyNoTarget = function(buffer, refPtr, offset, numBytes) {
    778        var numBytesInVtx = 3;
    779        var numBytesInQuad = numBytesInVtx * 4;
    780        var maxQuadsX = Math.min(128, Math.floor(gl.drawingBufferWidth / glsBufferTestUtil.VERIFY_QUAD_SIZE));
    781        var maxQuadsY = Math.min(128, Math.floor(gl.drawingBufferHeight / glsBufferTestUtil.VERIFY_QUAD_SIZE));
    782        var maxQuadsPerBatch = maxQuadsX * maxQuadsY;
    783        var numVerified = 0;
    784        var program = this.m_program.getProgram();
    785        /** @type {tcuRGBA.RGBA} */ var threshold = /*TODO: renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(3,3,3,3);*/ new tcuRGBA.RGBA([3, 3, 3, 3]);
    786        var isOk = true;
    787 
    788        /** @type {Array<number>} */ var positions = [];
    789        /** @type {Uint16Array} */var indices;
    790 
    791        /** @type {tcuSurface.Surface} */ var rendered = new tcuSurface.Surface();
    792        /** @type {tcuSurface.Surface} */ var reference = new tcuSurface.Surface();
    793 
    794        // Can't render full quad with smaller buffers.
    795        assertMsgOptions(numBytes >= numBytesInQuad, 'Number of bytes must be bigger than number of bytes per quad', false, true);
    796 
    797        positions = glsBufferTestUtil.computePositions(maxQuadsX, maxQuadsY);
    798        indices = glsBufferTestUtil.computeIndices(maxQuadsX, maxQuadsY);
    799 
    800        // Reset buffer bindings.
    801        gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
    802 
    803        // Setup rendering state.
    804        gl.viewport(0, 0, maxQuadsX * glsBufferTestUtil.VERIFY_QUAD_SIZE, maxQuadsY * glsBufferTestUtil.VERIFY_QUAD_SIZE);
    805        gl.clearColor(0.0, 0.0, 0.0, 1.0);
    806        gl.useProgram(program);
    807        gl.bindVertexArray(this.m_vao);
    808 
    809        // Upload positions
    810        gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
    811        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
    812        gl.enableVertexAttribArray(this.m_posLoc);
    813        gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
    814 
    815        // Upload indices
    816        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_indexBuf);
    817        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    818 
    819        gl.enableVertexAttribArray(this.m_byteVecLoc);
    820 
    821        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    822 
    823        while (numVerified < numBytes) {
    824            /** @type {number} */ var numRemaining = numBytes - numVerified;
    825            var isLeftoverBatch = numRemaining < numBytesInQuad;
    826            /** @type {number} */ var numBytesToVerify = isLeftoverBatch ? numBytesInQuad : Math.min(maxQuadsPerBatch * numBytesInQuad, numRemaining - numRemaining % numBytesInQuad);
    827            /** @type {number} */ var curOffset = isLeftoverBatch ? (numBytes - numBytesInQuad) : numVerified;
    828            /** @type {number} */ var numQuads = Math.floor(numBytesToVerify / numBytesInQuad);
    829            /** @type {number} */ var numCols = Math.min(maxQuadsX, numQuads);
    830            /** @type {number} */ var numRows = Math.floor(numQuads / maxQuadsX) + (numQuads % maxQuadsX != 0 ? 1 : 0);
    831            /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1);
    832 
    833            assertMsgOptions(numBytesToVerify > 0 && numBytesToVerify % numBytesInQuad == 0, 'Bytes to verify must be greater than zero and must be a multiple of the bytes per quad', false, true);
    834            assertMsgOptions(deMath.deInBounds32(curOffset, 0, numBytes), 'Offset out of bounds', false, true);
    835            assertMsgOptions(deMath.deInRange32(curOffset + numBytesToVerify, curOffset, numBytes), 'Range of bytes to verify outside of bounds', false, true);
    836 
    837            // Render batch.
    838            gl.clear(gl.COLOR_BUFFER_BIT);
    839            gl.vertexAttribPointer(this.m_byteVecLoc, 3, gl.UNSIGNED_BYTE, true, 0, offset + curOffset);
    840            gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_SHORT, 0);
    841 
    842            glsBufferTestUtil.renderQuadGridReference(reference, numQuads, numCols, refPtr.subarray(offset + curOffset));
    843 
    844            rendered.setSize(numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE);
    845            rendered.readViewport(gl, [0, 0, numCols * glsBufferTestUtil.VERIFY_QUAD_SIZE, numRows * glsBufferTestUtil.VERIFY_QUAD_SIZE]);
    846 
    847            if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, reference, rendered, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) {
    848                isOk = false;
    849                break;
    850            }
    851 
    852            numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
    853        }
    854 
    855        gl.bindVertexArray(null);
    856 
    857        return isOk;
    858    };
    859 
    860    // IndexArrayVerifier
    861 
    862    /**
    863     * @constructor
    864     * @extends {glsBufferTestUtil.BufferVerifierBase}
    865     */
    866    glsBufferTestUtil.IndexArrayVerifier = function() {
    867        glsBufferTestUtil.BufferVerifierBase.call(this);
    868 
    869        this.m_program = null;
    870        this.m_posLoc = 0;
    871        this.m_colorLoc = 0;
    872 
    873        /** @type {gluShaderUtil.GLSLVersion} */ var glslVersion = gluShaderUtil.GLSLVersion.V300_ES;
    874 
    875        assertMsgOptions(gluShaderUtil.isGLSLVersionSupported(gl, glslVersion), 'GLSL version not supported', false, true);
    876 
    877        this.m_program = new gluShaderProgram.ShaderProgram(gl, gluShaderProgram.makeVtxFragSources(
    878            gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
    879            'in highp vec2 a_position;\n' +
    880            'in mediump vec3 a_color;\n' +
    881            'out mediump vec3 v_color;\n' +
    882            'void main (void)\n' +
    883            '{\n' +
    884            ' gl_Position = vec4(a_position, 0.0, 1.0);\n' +
    885            ' v_color = a_color;\n' +
    886            '}\n',
    887 
    888            gluShaderUtil.getGLSLVersionDeclaration(glslVersion) + '\n' +
    889            'in mediump vec3 v_color;\n' +
    890            'layout(location = 0) out mediump vec4 o_color;\n' +
    891            'void main (void)\n' +
    892            '{\n' +
    893            ' o_color = vec4(v_color, 1.0);\n' +
    894            '}\n'));
    895 
    896        if (!this.m_program.isOk()) {
    897            testFailed('Compile failed');
    898        }
    899 
    900        this.m_posLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_position');
    901        this.m_colorLoc = gl.getAttribLocation(this.m_program.getProgram(), 'a_color');
    902 
    903        this.m_vao = gl.createVertexArray();
    904        this.m_positionBuf = gl.createBuffer();
    905        this.m_colorBuf = gl.createBuffer();
    906    };
    907 
    908    glsBufferTestUtil.IndexArrayVerifier.prototype = Object.create(glsBufferTestUtil.BufferVerifierBase.prototype);
    909    glsBufferTestUtil.IndexArrayVerifier.prototype.constructor = glsBufferTestUtil.IndexArrayVerifier;
    910 
    911    /**
    912     * deinit
    913     */
    914    glsBufferTestUtil.IndexArrayVerifier.prototype.deinit = function() {
    915        if (this.m_vao) gl.deleteVertexArray(this.m_vao);
    916        if (this.m_positionBuf) gl.deleteBuffer(this.m_positionBuf);
    917        if (this.m_colorBuf) gl.deleteBuffer(this.m_colorBuf);
    918    };
    919 
    920    /**
    921     * @return {Array<number>}
    922     */
    923    glsBufferTestUtil.computeIndexVerifierPositions = function() {
    924        var numPosX = 16;
    925        var numPosY = 16;
    926 
    927        var dst = [];
    928 
    929        for (var y = 0; y < numPosY; y++) {
    930            for (var x = 0; x < numPosX; x++) {
    931                var xf = x / (numPosX - 1);
    932                var yf = y / (numPosY - 1);
    933 
    934                var offset = 2 * (y * numPosX + x);
    935                dst[offset] = 2.0 * xf - 1.0;
    936                dst[offset + 1] = 2.0 * yf - 1.0;
    937            }
    938        }
    939 
    940        return dst;
    941    };
    942 
    943    /**
    944     * @return {Array<number>}
    945     */
    946    glsBufferTestUtil.computeIndexVerifierColors = function() {
    947        /** @type {number} */ var numColors = 256;
    948        /** @type {number} */ var minVal = 0.1;
    949        /** @type {number} */ var maxVal = 0.5;
    950        var rnd = new deRandom.Random(0xabc231);
    951 
    952        var dst = [];
    953 
    954        for (var i = 0; i < numColors; ++i) {
    955            dst[3 * i] = rnd.getFloat(minVal, maxVal);
    956            dst[3 * i + 1] = rnd.getFloat(minVal, maxVal);
    957            dst[3 * i + 2] = rnd.getFloat(minVal, maxVal);
    958        }
    959 
    960        return dst;
    961    };
    962 
    963    /**
    964     * @param {Array<number>} dst
    965     * @param {Array<number>} src
    966     * @param {Uint8Array} indices
    967     * @param {number} numIndices
    968     */
    969    glsBufferTestUtil.execVertexFetch = function(dst, src, indices, numIndices) {
    970        for (var i = 0; i < numIndices; ++i)
    971            dst[i] = src[indices[i]];
    972    };
    973 
    974    /**
    975     * @param {WebGLBuffer} buffer
    976     * @param {Uint8Array} refPtr
    977     * @param {number} offset
    978     * @param {number} numBytes
    979     * @return {boolean}
    980     */
    981    glsBufferTestUtil.IndexArrayVerifier.prototype.verify = function(buffer, refPtr, offset, numBytes) {
    982        var viewportW = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_WIDTH, gl.drawingBufferWidth);
    983        var viewportH = Math.min(glsBufferTestUtil.INDEX_ARRAY_DRAW_VIEWPORT_HEIGHT, gl.drawingBufferHeight);
    984        var minBytesPerBatch = 2;
    985        /** @type {tcuRGBA.RGBA} */ var threshold = new tcuRGBA.RGBA([0, 0, 0, 0]);
    986 
    987        var positions = [];
    988        var colors = [];
    989 
    990        var fetchedPos = [];
    991        var fetchedColor = [];
    992 
    993        /** @type {tcuSurface.Surface} */ var indexBufferImg = new tcuSurface.Surface(viewportW, viewportH);
    994        /** @type {tcuSurface.Surface} */ var referenceImg = new tcuSurface.Surface(viewportW, viewportH);
    995 
    996        var numVerified = 0;
    997        var isOk = true;
    998 
    999        positions = glsBufferTestUtil.computeIndexVerifierPositions();
   1000        colors = glsBufferTestUtil.computeIndexVerifierColors();
   1001 
   1002        // Reset buffer bindings.
   1003        gl.bindVertexArray(this.m_vao);
   1004        gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
   1005        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
   1006 
   1007        // Setup rendering state.
   1008        gl.viewport(0, 0, viewportW, viewportH);
   1009        gl.clearColor(0.0, 0.0, 0.0, 1.0);
   1010        gl.useProgram(this.m_program.getProgram());
   1011        gl.enableVertexAttribArray(this.m_posLoc);
   1012        gl.enableVertexAttribArray(this.m_colorLoc);
   1013        gl.enable(gl.BLEND);
   1014        gl.blendFunc(gl.ONE, gl.ONE);
   1015        gl.blendEquation(gl.FUNC_ADD);
   1016 
   1017        while (numVerified < numBytes) {
   1018            var numRemaining = numBytes - numVerified;
   1019            var isLeftoverBatch = numRemaining < minBytesPerBatch;
   1020            var numBytesToVerify = isLeftoverBatch ? minBytesPerBatch : Math.min(glsBufferTestUtil.MAX_LINES_PER_INDEX_ARRAY_DRAW + 1, numRemaining);
   1021            var curOffset = isLeftoverBatch ? (numBytes - minBytesPerBatch) : numVerified;
   1022            /** @type {string} */ var imageSetDesc = 'Bytes ' + (offset + curOffset) + ' to ' + (offset + curOffset + numBytesToVerify - 1);
   1023 
   1024            // Step 1: Render using index buffer.
   1025            gl.clear(gl.COLOR_BUFFER_BIT);
   1026 
   1027            gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
   1028            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STREAM_DRAW);
   1029            gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
   1030 
   1031            gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf);
   1032            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STREAM_DRAW);
   1033            gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0);
   1034 
   1035            gl.drawElements(gl.LINE_STRIP, numBytesToVerify, gl.UNSIGNED_BYTE, offset + curOffset);
   1036            indexBufferImg.readViewport(gl);
   1037 
   1038            // Step 2: Do manual fetch and render without index buffer.
   1039            glsBufferTestUtil.execVertexFetch(fetchedPos, positions, refPtr.subarray(offset + curOffset), numBytesToVerify);
   1040            glsBufferTestUtil.execVertexFetch(fetchedColor, colors, refPtr.subarray(offset + curOffset), numBytesToVerify);
   1041 
   1042            gl.clear(gl.COLOR_BUFFER_BIT);
   1043 
   1044            gl.bindBuffer(gl.ARRAY_BUFFER, this.m_positionBuf);
   1045            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedPos), gl.STREAM_DRAW);
   1046            gl.vertexAttribPointer(this.m_posLoc, 2, gl.FLOAT, false, 0, 0);
   1047 
   1048            gl.bindBuffer(gl.ARRAY_BUFFER, this.m_colorBuf);
   1049            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fetchedColor), gl.STREAM_DRAW);
   1050            gl.vertexAttribPointer(this.m_colorLoc, 3, gl.FLOAT, false, 0, 0);
   1051 
   1052            gl.drawArrays(gl.LINE_STRIP, 0, numBytesToVerify);
   1053            referenceImg.readViewport(gl, [0, 0, viewportW, viewportH]);
   1054 
   1055            if (!tcuImageCompare.pixelThresholdCompare('RenderResult', imageSetDesc, referenceImg, indexBufferImg, threshold.toIVec(), tcuImageCompare.CompareLogMode.RESULT)) {
   1056                isOk = false;
   1057                break;
   1058            }
   1059 
   1060            numVerified += isLeftoverBatch ? numRemaining : numBytesToVerify;
   1061        }
   1062 
   1063        gl.bindVertexArray(null);
   1064 
   1065        return isOk;
   1066    };
   1067 
   1068 });