tor-browser

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

angle-instanced-arrays.html (27748B)


      1 <!--
      2 Copyright (c) 2019 The Khronos Group Inc.
      3 Use of this source code is governed by an MIT-style license that can be
      4 found in the LICENSE.txt file.
      5 -->
      6 
      7 <!DOCTYPE html>
      8 <html>
      9 <head>
     10 <meta charset="utf-8">
     11 <title>WebGL ANGLE_instanced_arrays Conformance Tests</title>
     12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     13 <script src="../../js/desktop-gl-constants.js"></script>
     14 <script src="../../js/js-test-pre.js"></script>
     15 <script src="../../js/webgl-test-utils.js"></script>
     16 <script src="../../js/tests/compositing-test.js"></script>
     17 <script src="../../js/tests/invalid-vertex-attrib-test.js"></script>
     18 </head>
     19 <body>
     20 <div id="description"></div>
     21 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
     22 <div id="console"></div>
     23 <!-- Shaders for testing instanced draws -->
     24 <script id="outputVertexShader" type="x-shader/x-vertex">
     25 attribute vec4 aPosition;
     26 attribute vec2 aOffset;
     27 attribute vec4 aColor;
     28 varying vec4 vColor;
     29 void main() {
     30    vColor = aColor;
     31    gl_Position = aPosition + vec4(aOffset, 0.0, 0.0);
     32 }
     33 </script>
     34 
     35 <script id="outputFragmentShader" type="x-shader/x-fragment">
     36 precision mediump float;
     37 varying vec4 vColor;
     38 void main() {
     39    gl_FragColor = vColor;
     40 }
     41 </script>
     42 
     43 <script id="drawArraysTestVertexShader" type="x-shader/x-vertex">
     44 attribute vec3 aPosition;
     45 attribute vec3 aInstancePos;
     46 uniform vec3 uOffset;
     47 void main() {
     48    gl_Position = vec4(aPosition.xyz + aInstancePos.xyz + uOffset, 1.0);
     49 }
     50 </script>
     51 
     52 <script id="drawArraysTestFragmentShader" type="x-shader/x-fragment">
     53 void main() {
     54    gl_FragColor = vec4(1.0, 0, 0, 1.0);
     55 }
     56 </script>
     57 
     58 <script>
     59 "use strict";
     60 description("This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available.");
     61 
     62 debug("");
     63 
     64 const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
     65 
     66 var wtu = WebGLTestUtils;
     67 var canvas = document.getElementById("canvas");
     68 var gl = wtu.create3DContext(canvas);
     69 var ext = null;
     70 var vaoext = null;
     71 
     72 var positionLoc = 0;
     73 var offsetLoc = 2;
     74 var colorLoc = 3;
     75 var program;
     76 
     77 if (!gl) {
     78    testFailed("WebGL context does not exist");
     79    finishTest();
     80 } else {
     81    testPassed("WebGL context exists");
     82 
     83    runDivisorTestDisabled();
     84 
     85    // Query the extension and store globally so shouldBe can access it
     86    ext = wtu.getExtensionWithKnownPrefixes(gl, "ANGLE_instanced_arrays");
     87    if (!ext) {
     88        testPassed("No ANGLE_instanced_arrays support -- this is legal");
     89 
     90        runSupportedTest(false);
     91        finishTest();
     92    } else {
     93        testPassed("Successfully enabled ANGLE_instanced_arrays extension");
     94 
     95        (async function() {
     96            runSupportedTest(true);
     97 
     98            runDivisorTestEnabled();
     99            runUniqueObjectTest();
    100 
    101            setupCanvas();
    102            runOutputTests();
    103            runDrawArraysWithOffsetTest();
    104            runVAOInstancingInteractionTest();
    105            await runANGLECorruptionTest();
    106            await runInvalidAttribTests(gl);
    107            await runCompositingTests();
    108            finishTest();
    109        }());
    110    }
    111 }
    112 
    113 function runSupportedTest(extensionEnabled) {
    114    var supported = gl.getSupportedExtensions();
    115    if (supported.indexOf("ANGLE_instanced_arrays") >= 0) {
    116        if (extensionEnabled) {
    117            testPassed("ANGLE_instanced_arrays listed as supported and getExtension succeeded");
    118        } else {
    119            testFailed("ANGLE_instanced_arrays listed as supported but getExtension failed");
    120        }
    121    } else {
    122        if (extensionEnabled) {
    123            testFailed("ANGLE_instanced_arrays not listed as supported but getExtension succeeded");
    124        } else {
    125            testPassed("ANGLE_instanced_arrays not listed as supported and getExtension failed -- this is legal");
    126        }
    127    }
    128 }
    129 
    130 function runDivisorTestDisabled() {
    131    debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled");
    132 
    133    var VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
    134 
    135    gl.getVertexAttrib(0, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
    136    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should not be queryable if extension is disabled");
    137 }
    138 
    139 function runDivisorTestEnabled() {
    140    debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled");
    141 
    142    shouldBe("ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "0x88FE");
    143 
    144    var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
    145 
    146    for (var i = 0; i < max_vertex_attribs; ++i) {
    147        var queried_value = gl.getVertexAttrib(i, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
    148        if(queried_value == 0){
    149            testPassed("Vertex attribute " + i + " must has a default divisor of 0");
    150        }
    151        else{
    152            testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value);
    153        }
    154    }
    155 
    156    ext.vertexAttribDivisorANGLE(max_vertex_attribs, 2);
    157    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "vertexAttribDivisorANGLE index set greater than or equal to MAX_VERTEX_ATTRIBS should be an invalid value");
    158 
    159    ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 2);
    160    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertexAttribDivisorANGLE index set less than MAX_VERTEX_ATTRIBS should succeed");
    161 
    162    var queried_value = gl.getVertexAttrib(max_vertex_attribs-1, ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
    163    if(queried_value == 2){
    164        testPassed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE matches expecation");
    165    }
    166    else{
    167        testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should be: 2, returned value was: " + queried_value);
    168    }
    169 
    170    // Reset vertex attrib divisors so they cannot affect following subtests.
    171    ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 0);
    172 }
    173 
    174 function setupCanvas() {
    175    canvas.width = 50; canvas.height = 50;
    176    gl.viewport(0, 0, canvas.width, canvas.height);
    177    gl.clearColor(0, 0, 0, 0);
    178 
    179    program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]);
    180    ext = gl.getExtension("ANGLE_instanced_arrays");
    181 }
    182 
    183 function runOutputTests() {
    184    var instanceCount = 4;
    185 
    186    debug("Testing various draws for valid built-in function behavior");
    187 
    188    var offsets = new Float32Array([
    189        -1.0,  1.0,
    190         1.0,  1.0,
    191        -1.0, -1.0,
    192         1.0, -1.0,
    193    ]);
    194    var offsetBuffer = gl.createBuffer();
    195    gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
    196    gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
    197    gl.enableVertexAttribArray(offsetLoc);
    198    gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0);
    199    ext.vertexAttribDivisorANGLE(offsetLoc, 1);
    200 
    201    var colors = new Float32Array([
    202        1.0, 0.0, 0.0, 1.0, // Red
    203        0.0, 1.0, 0.0, 1.0, // Green
    204        0.0, 0.0, 1.0, 1.0, // Blue
    205        1.0, 1.0, 0.0, 1.0, // Yellow
    206        // extra data when colorLoc divisor is set back to 0
    207        1.0, 1.0, 0.0, 1.0, // Yellow
    208        1.0, 1.0, 0.0, 1.0, // Yellow
    209    ]);
    210    var colorBuffer = gl.createBuffer();
    211    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    212    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
    213    gl.enableVertexAttribArray(colorLoc);
    214    gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
    215    ext.vertexAttribDivisorANGLE(colorLoc, 1);
    216 
    217    wtu.setupUnitQuad(gl, 0);
    218 
    219    // Draw 1: Regular drawArrays
    220    debug("");
    221    debug("Testing drawArrays with non-zero divisor");
    222    gl.clear(gl.COLOR_BUFFER_BIT);
    223    gl.drawArrays(gl.TRIANGLES, 0, 6);
    224    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawArrays when the extension is enabled");
    225    wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
    226 
    227    // Draw 2: Draw Non-indexed instances
    228    debug("");
    229    debug("Testing drawArraysInstancedANGLE");
    230    gl.clear(gl.COLOR_BUFFER_BIT);
    231 
    232    // Test drawArraysInstancedANGLE error conditions
    233    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
    234    wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
    235    wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
    236    wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
    237    wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
    238 
    239    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, -1);
    240    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a primcount less than 0");
    241 
    242    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, -1, instanceCount);
    243    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a count less than 0");
    244 
    245    ext.vertexAttribDivisorANGLE(positionLoc, 1);
    246    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
    247    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawArraysInstancedANGLE");
    248    ext.vertexAttribDivisorANGLE(positionLoc, 0);
    249 
    250    ext.drawArraysInstancedANGLE(gl.POINTS, 0, 6, instanceCount);
    251    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with POINTS should succeed");
    252    ext.drawArraysInstancedANGLE(gl.LINES, 0, 6, instanceCount);
    253    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINES should succeed");
    254    ext.drawArraysInstancedANGLE(gl.LINE_LIST, 0, 6, instanceCount);
    255    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with LINE_LIST should return succeed");
    256    ext.drawArraysInstancedANGLE(gl.TRIANGLE_LIST, 0, 6, instanceCount);
    257    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE with TRIANGLE_LIST should succeed");
    258 
    259    ext.drawArraysInstancedANGLE(desktopGL['QUAD_STRIP'], 0, 6, instanceCount);
    260    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
    261    ext.drawArraysInstancedANGLE(desktopGL['QUADS'], 0, 6, instanceCount);
    262    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with QUADS should return INVALID_ENUM");
    263    ext.drawArraysInstancedANGLE(desktopGL['POLYGON'], 0, 6, instanceCount);
    264    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstancedANGLE with POLYGON should return INVALID_ENUM");
    265 
    266    debug("");
    267    debug("Testing drawArraysInstancedANGLE with param 'first' > 0");
    268    gl.clear(gl.COLOR_BUFFER_BIT);
    269    wtu.setupQuad(gl, {
    270        positionLocation: 0,
    271        scale: 0.5
    272    });
    273    var offsetsHalf = new Float32Array([
    274        -0.5,  0.5,
    275         0.5,  0.5,
    276        -0.5, -0.5,
    277         0.5, -0.5
    278    ]);
    279    gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
    280    gl.bufferData(gl.ARRAY_BUFFER, offsetsHalf, gl.STATIC_DRAW);
    281 
    282    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount);
    283    var w = Math.floor(0.25*canvas.width),
    284        h = Math.floor(0.25*canvas.height);
    285    wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 0, 0, 255]);
    286    wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [0, 255, 0, 255]);
    287    wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [0, 0, 255, 255]);
    288    wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
    289 
    290    debug("");
    291    debug("Testing drawArraysInstancedANGLE with attributes 'divisor' reset to 0");
    292    debug("Correct rendering output: 4 yellow triangles");
    293    debug("Possible incorrect rendering output: missing triangles, or triangles with different color at each vertex");
    294    ext.vertexAttribDivisorANGLE(colorLoc, 0);
    295    gl.clear(gl.COLOR_BUFFER_BIT);
    296    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount);
    297    wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
    298    wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
    299    wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [255, 255, 0, 255]);
    300    wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
    301    ext.vertexAttribDivisorANGLE(colorLoc, 1);
    302 
    303    wtu.setupUnitQuad(gl, 0);
    304    wtu.setupIndexedQuad(gl, 1, 0);
    305    gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
    306    gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
    307 
    308    // Draw 3: Regular drawElements
    309    debug("");
    310    debug("Testing drawElements with non-zero divisor");
    311    gl.clear(gl.COLOR_BUFFER_BIT);
    312    // Point to another location in the buffer so that the draw would overflow without the divisor
    313    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    314    gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 48);
    315    gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
    316    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex attrib divisor should affect regular drawElements when the extension is enabled");
    317    wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
    318    // Restore the vertex attrib pointer
    319    gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
    320 
    321    // Draw 4: Draw indexed instances
    322    debug("");
    323    debug("Testing drawElementsInstancedANGLE");
    324    gl.clear(gl.COLOR_BUFFER_BIT);
    325    ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    326    wtu.checkCanvasRect(gl, 0, canvas.height/2, canvas.width/2, canvas.height/2, [255, 0, 0, 255]);
    327    wtu.checkCanvasRect(gl, canvas.width/2, canvas.height/2, canvas.width/2, canvas.height/2, [0, 255, 0, 255]);
    328    wtu.checkCanvasRect(gl, 0, 0, canvas.width/2, canvas.height/2, [0, 0, 255, 255]);
    329    wtu.checkCanvasRect(gl, canvas.width/2, 0, canvas.width/2, canvas.height/2, [255, 255, 0, 255]);
    330 
    331    // Test drawElementsInstancedANGLE error conditions
    332    ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, -1);
    333    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a primcount less than 0");
    334 
    335    ext.drawElementsInstancedANGLE(gl.TRIANGLES, -1, gl.UNSIGNED_SHORT, 0, instanceCount);
    336    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawElementsInstancedANGLE cannot have a count less than 0");
    337 
    338    ext.vertexAttribDivisorANGLE(positionLoc, 1);
    339    ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    340    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "There must be at least one vertex attribute with a divisor of zero when calling drawElementsInstancedANGLE");
    341    ext.vertexAttribDivisorANGLE(positionLoc, 0);
    342 
    343    ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount);
    344    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed");
    345 
    346    ext.drawElementsInstancedANGLE(gl.POINTS, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    347    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with POINTS should succeed");
    348    ext.drawElementsInstancedANGLE(gl.LINES, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    349    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINES should succeed");
    350    ext.drawElementsInstancedANGLE(gl.LINE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    351    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with LINE_LIST should return succeed");
    352    ext.drawElementsInstancedANGLE(gl.TRIANGLE_LIST, 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    353    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with TRIANGLE_LIST should succeed");
    354 
    355    ext.drawElementsInstancedANGLE(desktopGL['QUAD_STRIP'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    356    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUAD_STRIP should return INVALID_ENUM");
    357    ext.drawElementsInstancedANGLE(desktopGL['QUADS'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    358    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with QUADS should return INVALID_ENUM");
    359    ext.drawElementsInstancedANGLE(desktopGL['POLYGON'], 6, gl.UNSIGNED_SHORT, 0, instanceCount);
    360    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawElementsInstancedANGLE with POLYGON should return INVALID_ENUM");
    361 
    362    // Reset vertex attrib divisors so they cannot affect following subtests.
    363    ext.vertexAttribDivisorANGLE(colorLoc, 0);
    364    ext.vertexAttribDivisorANGLE(offsetLoc, 0);
    365 }
    366 
    367 function runDrawArraysTest(program, first, count, instanceCount, offset)
    368 {
    369    // Get the attribute and uniform locations
    370    var positionLoc = gl.getAttribLocation(program, "aPosition");
    371    var instancePosLoc = gl.getAttribLocation(program, "aInstancePos");
    372    var uniformLoc = gl.getUniformLocation(program, "uOffset");
    373 
    374    // Load the vertex positions
    375    var positions = new Float32Array([
    376        -1, -1,
    377        -1,  0,
    378         0,  0,
    379 
    380         0,  0,
    381         0, -1,
    382        -1, -1,
    383 
    384         1, -1,
    385         1,  0,
    386         0,  0,
    387 
    388         0,  0,
    389         0, -1,
    390         1, -1,
    391    ]);
    392    var positionBuffer = gl.createBuffer();
    393    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    394    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
    395    gl.enableVertexAttribArray(positionLoc);
    396    gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
    397 
    398    // Load the instance positions
    399    var instancePositions = new Float32Array([
    400         0, 0,
    401         1, 0
    402    ]);
    403    var instancePositionBuffer = gl.createBuffer();
    404    gl.bindBuffer(gl.ARRAY_BUFFER, instancePositionBuffer);
    405    gl.bufferData(gl.ARRAY_BUFFER, instancePositions, gl.STATIC_DRAW);
    406    gl.enableVertexAttribArray(instancePosLoc);
    407    gl.vertexAttribPointer(instancePosLoc, 2, gl.FLOAT, false, 0, 0);
    408 
    409    // Enable instancing
    410    ext.vertexAttribDivisorANGLE(instancePosLoc, 1);
    411 
    412    // Offset
    413    gl.uniform3fv(uniformLoc, offset);
    414 
    415    // Do the instanced draw
    416    ext.drawArraysInstancedANGLE(gl.TRIANGLES, first, count, instanceCount);
    417    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE should succeed");
    418 
    419    // Reset vertex attrib divisors so they cannot affect following subtests.
    420    ext.vertexAttribDivisorANGLE(instancePosLoc, 0);
    421 }
    422 
    423 function runDrawArraysWithOffsetTest()
    424 {
    425    debug("");
    426    debug("Testing that the 'first' parameter to drawArraysInstancedANGLE is only an offset into the non-instanced vertex attributes.");
    427    // See: http://crbug.com/457269 and http://crbug.com/447140
    428 
    429    var drawArraysProgram = wtu.setupProgram(gl, ["drawArraysTestVertexShader", "drawArraysTestFragmentShader"]);
    430 
    431    gl.clear(gl.COLOR_BUFFER_BIT);
    432 
    433    runDrawArraysTest(drawArraysProgram, 0, 6, 2, [0, 0, 0]);
    434 
    435    runDrawArraysTest(drawArraysProgram, 6, 6, 2, [-1, 1, 0]);
    436 
    437    wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
    438 }
    439 
    440 function runUniqueObjectTest()
    441 {
    442    debug("");
    443    debug("Testing that getExtension() returns the same object each time");
    444    ext = null;
    445    gl.getExtension("ANGLE_instanced_arrays").myProperty = 2;
    446    webglHarnessCollectGarbage();
    447    shouldBe('gl.getExtension("ANGLE_instanced_arrays").myProperty', '2');
    448 }
    449 
    450 function runVAOInstancingInteractionTest()
    451 {
    452    debug("")
    453    debug("Testing that ANGLE_instanced_arrays interacts correctly with OES_vertex_array_object if present");
    454    // See: https://github.com/KhronosGroup/WebGL/issues/1228
    455 
    456    // Query the extension and store globally so shouldBe can access it
    457    vaoext = gl.getExtension("OES_vertex_array_object");
    458    if (!vaoext) {
    459        testPassed("No OES_vertex_array_object support -- this is legal");
    460        return;
    461    }
    462 
    463    testPassed("Successfully enabled OES_vertex_array_object extension");
    464 
    465    gl.useProgram(program);
    466 
    467    var positions = new Float32Array([
    468         0.0,  1.0, // Left quad
    469        -1.0,  1.0,
    470        -1.0, -1.0,
    471         0.0,  1.0,
    472        -1.0, -1.0,
    473         0.0, -1.0,
    474 
    475         1.0,  1.0, // Right quad
    476         0.0,  1.0,
    477         0.0, -1.0,
    478         1.0,  1.0,
    479         0.0, -1.0,
    480         1.0, -1.0
    481    ]);
    482    var positionBuffer = gl.createBuffer();
    483    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    484    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
    485 
    486    var colors = new Float32Array([
    487        1.0, 0.0, 0.0, 1.0, // Red
    488        1.0, 0.0, 0.0, 1.0,
    489        1.0, 0.0, 0.0, 1.0,
    490        1.0, 0.0, 0.0, 1.0,
    491        1.0, 0.0, 0.0, 1.0,
    492        1.0, 0.0, 0.0, 1.0,
    493 
    494        0.0, 0.0, 1.0, 1.0, // Blue
    495        0.0, 0.0, 1.0, 1.0,
    496        0.0, 0.0, 1.0, 1.0,
    497        0.0, 0.0, 1.0, 1.0,
    498        0.0, 0.0, 1.0, 1.0,
    499        0.0, 0.0, 1.0, 1.0,
    500    ]);
    501    var colorBuffer = gl.createBuffer();
    502    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    503    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
    504 
    505    // Reset the divisor of the default VAO to 0
    506    ext.vertexAttribDivisorANGLE(colorLoc, 0);
    507 
    508    // Set up VAO with an attrib divisor
    509    var vao1 = vaoext.createVertexArrayOES();
    510    vaoext.bindVertexArrayOES(vao1);
    511    {
    512        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    513        gl.enableVertexAttribArray(positionLoc);
    514        gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
    515 
    516        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    517        gl.enableVertexAttribArray(colorLoc);
    518        gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
    519        ext.vertexAttribDivisorANGLE(colorLoc, 1);
    520 
    521        gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
    522    }
    523    vaoext.bindVertexArrayOES(null);
    524 
    525    // Set up VAO with no attrib divisor
    526    var vao2 = vaoext.createVertexArrayOES();
    527    vaoext.bindVertexArrayOES(vao2);
    528    {
    529        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    530        gl.enableVertexAttribArray(positionLoc);
    531        gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
    532 
    533        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    534        gl.enableVertexAttribArray(colorLoc);
    535        gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
    536        // Note that no divisor is set here, which implies that it's 0
    537 
    538        gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
    539    }
    540    vaoext.bindVertexArrayOES(null);
    541 
    542    debug("");
    543    debug("Ensure that Vertex Array Objects retain attrib divisors");
    544 
    545    vaoext.bindVertexArrayOES(vao1);
    546    gl.clear(gl.COLOR_BUFFER_BIT);
    547    gl.drawArrays(gl.TRIANGLES, 0, 12);
    548    // If the divisor is properly managed by the VAO a single red quad will be drawn
    549    wtu.checkCanvas(gl, [255, 0, 0, 255], "entire canvas should be red");
    550 
    551    vaoext.bindVertexArrayOES(vao2);
    552    gl.clear(gl.COLOR_BUFFER_BIT);
    553    gl.drawArrays(gl.TRIANGLES, 0, 12);
    554    // If the divisor is properly managed by the VAO a red and blue quad will be drawn.
    555    wtu.checkCanvasRects(gl, [
    556        wtu.makeCheckRect(0, 0, canvas.width * 0.5, canvas.height, [255, 0, 0, 255], "left half of canvas should be red", 1),
    557        wtu.makeCheckRect(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height, [0, 0, 255, 255], "right half of canvas should be blue", 1)
    558    ]);
    559 
    560    vaoext.bindVertexArrayOES(null);
    561 }
    562 
    563 async function runANGLECorruptionTest()
    564 {
    565    debug("")
    566    debug("Testing to ensure that rendering isn't corrupt due to an ANGLE bug");
    567    // See: https://code.google.com/p/angleproject/issues/detail?id=467
    568 
    569    setupCanvas();
    570 
    571    var tolerance = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
    572    var instanceCount = 10; // Must be higher than 6
    573 
    574    var offsets = new Float32Array([
    575        0.0, 0.0,
    576        0.2, 0.0,
    577        0.4, 0.0,
    578        0.6, 0.0,
    579        0.8, 0.0,
    580        1.0, 0.0,
    581        1.2, 0.0,
    582        1.4, 0.0,
    583        1.6, 0.0,
    584        1.8, 0.0,
    585    ]);
    586    var offsetBuffer = gl.createBuffer();
    587    gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
    588    gl.bufferData(gl.ARRAY_BUFFER, offsets.byteLength * 2, gl.STATIC_DRAW);
    589    gl.bufferSubData(gl.ARRAY_BUFFER, 0, offsets);
    590    gl.enableVertexAttribArray(offsetLoc);
    591    gl.vertexAttribPointer(offsetLoc, 2, gl.FLOAT, false, 0, 0);
    592    ext.vertexAttribDivisorANGLE(offsetLoc, 1);
    593 
    594    var colors = new Float32Array([
    595        1.0, 0.0, 0.0, 1.0,
    596        1.0, 1.0, 0.0, 1.0,
    597        0.0, 1.0, 0.0, 1.0,
    598        0.0, 1.0, 1.0, 1.0,
    599        0.0, 0.0, 1.0, 1.0,
    600        1.0, 0.0, 1.0, 1.0,
    601        1.0, 0.0, 0.0, 1.0,
    602        1.0, 1.0, 0.0, 1.0,
    603        0.0, 1.0, 0.0, 1.0,
    604        0.0, 1.0, 1.0, 1.0,
    605    ]);
    606    var colorBuffer = gl.createBuffer();
    607    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    608    gl.bufferData(gl.ARRAY_BUFFER, colors.byteLength * 2, gl.STATIC_DRAW);
    609    gl.bufferSubData(gl.ARRAY_BUFFER, 0, colors);
    610    gl.enableVertexAttribArray(colorLoc);
    611    gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
    612    ext.vertexAttribDivisorANGLE(colorLoc, 1);
    613 
    614    gl.clear(gl.COLOR_BUFFER_BIT);
    615    wtu.setupUnitQuad(gl, 0);
    616 
    617    const totalIterations = 10;
    618    for (let iteration = 0; iteration < totalIterations; ++iteration)
    619    {
    620        // Update the instanced data buffers outside the accessed range.
    621        // This, plus rendering more instances than vertices, triggers the bug.
    622        var nullData = new Float32Array(offsets.length);
    623        gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
    624        gl.bufferSubData(gl.ARRAY_BUFFER, offsets.byteLength, nullData);
    625 
    626        nullData = new Float32Array(colors.length);
    627        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    628        gl.bufferSubData(gl.ARRAY_BUFFER, colors.byteLength, nullData);
    629 
    630        ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
    631 
    632        // Make sure each color was drawn correctly
    633        var i;
    634        var passed = true;
    635        for (i = 0; i < instanceCount; ++i) {
    636            var w = canvas.width / instanceCount;
    637            var x = w * i;
    638            var color =  [colors[(i*4)] * 255, colors[(i*4)+1] * 255, colors[(i*4)+2] * 255, 255]
    639 
    640            wtu.checkCanvasRectColor(
    641                gl, x, 0, w, canvas.height, color, tolerance,
    642                function() {},
    643                function() {
    644                    passed = false;
    645                }, debug);
    646        }
    647 
    648        if (passed) {
    649            testPassed("Passed test " + iteration + " of " + totalIterations);
    650        } else {
    651            testFailed("Failed test " + iteration + " of " + totalIterations);
    652            break;
    653        }
    654        await wait();
    655    }
    656    ext.vertexAttribDivisorANGLE(offsetLoc, 0);
    657    ext.vertexAttribDivisorANGLE(colorLoc, 0);
    658 }
    659 
    660 async function runDrawTests(testFn) {
    661    function drawArrays(gl) {
    662      gl.drawArrays(gl.TRIANGLES, 0, 6);
    663    }
    664 
    665    function drawElements(gl) {
    666      gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
    667    }
    668 
    669    function drawArraysInstancedANGLE(gl) {
    670      const ext = gl.getExtension('ANGLE_instanced_arrays');
    671      if (!ext) {
    672        return true;
    673      }
    674 
    675      ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 1);
    676    }
    677 
    678    function drawElementsInstancedANGLE(gl) {
    679      const ext = gl.getExtension('ANGLE_instanced_arrays');
    680      if (!ext) {
    681        return true;
    682      }
    683 
    684      ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 1);
    685    }
    686 
    687    await testFn(drawArrays);             // sanity check
    688    await testFn(drawElements);           // sanity check
    689 
    690    await testFn(drawArraysInstancedANGLE);
    691    await testFn(drawElementsInstancedANGLE);
    692 }
    693 
    694 async function runCompositingTests() {
    695    const compositingTestFn = createCompositingTestFn({
    696      webglVersion: 1,
    697      shadersFn(gl) {
    698        const vs = `\
    699        attribute vec4 position;
    700        void main() {
    701          gl_Position = position;
    702        }
    703        `;
    704        const fs = `\
    705        precision mediump float;
    706        void main() {
    707          gl_FragColor = vec4(1, 0, 0, 1);
    708        }
    709        `;
    710        return [vs, fs];
    711      },
    712    });
    713    await runDrawTests(compositingTestFn);
    714 }
    715 
    716 async function runInvalidAttribTests(gl) {
    717  const invalidAttribTestFn = createInvalidAttribTestFn(gl);
    718  await runDrawTests(invalidAttribTestFn);
    719 }
    720 
    721 </script>
    722 </body>
    723 </html>