tor-browser

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

oes-vertex-array-object.html (28249B)


      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 OES_vertex_array_object Conformance Tests</title>
     12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
     13 <script src="../../js/js-test-pre.js"></script>
     14 <script src="../../js/webgl-test-utils.js"></script>
     15 <!-- comment in the script tag below to test through JS emulation of the extension. -->
     16 <!--
     17 <script src="../../../demos/google/resources/OESVertexArrayObject.js"></script>
     18 -->
     19 </head>
     20 <body>
     21 <div id="description"></div>
     22 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
     23 <div id="console"></div>
     24 <script id="vshader" type="x-shader/x-vertex">
     25 attribute vec4 a_position;
     26 attribute vec4 a_color;
     27 varying vec4 v_color;
     28 void main(void) {
     29    gl_Position = a_position;
     30    v_color = a_color;
     31 }
     32 </script>
     33 <script id="fshader" type="x-shader/x-fragment">
     34 precision mediump float;
     35 varying vec4 v_color;
     36 void main(void) {
     37    gl_FragColor = v_color;
     38 }
     39 </script>
     40 <script>
     41 "use strict";
     42 description("This test verifies the functionality of the OES_vertex_array_object extension, if it is available.");
     43 
     44 debug("");
     45 
     46 var wtu = WebGLTestUtils;
     47 var canvas = document.getElementById("canvas");
     48 var gl = wtu.create3DContext(canvas);
     49 var ext = null;
     50 var vao = null;
     51 
     52 var contextA;
     53 var contextB;
     54 var extA;
     55 var extB;
     56 var vertexArrayA;
     57 var vertexArrayB;
     58 
     59 if (!gl) {
     60    testFailed("WebGL context does not exist");
     61 } else {
     62    testPassed("WebGL context exists");
     63 
     64    // Setup emulated OESVertexArrayObject if it has been included.
     65    if (window.setupVertexArrayObject) {
     66        debug("using emulated OES_vertex_array_object");
     67        setupVertexArrayObject(gl);
     68    }
     69 
     70    // Run tests with extension disabled
     71    runBindingTestDisabled();
     72 
     73    // Query the extension and store globally so shouldBe can access it
     74    ext = gl.getExtension("OES_vertex_array_object");
     75    if (!ext) {
     76        testPassed("No OES_vertex_array_object support -- this is legal");
     77 
     78        runSupportedTest(false);
     79    } else {
     80        testPassed("Successfully enabled OES_vertex_array_object extension");
     81 
     82        runSupportedTest(true);
     83        runBindingTestEnabled();
     84        runObjectTest();
     85        runAttributeTests();
     86        runAttributeValueTests();
     87        runDrawTests();
     88        runUnboundDeleteTests();
     89        runBoundDeleteTests();
     90        runArrayBufferBindTests();
     91        runInvalidContextTests();
     92        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
     93    }
     94 }
     95 
     96 function runSupportedTest(extensionEnabled) {
     97    var supported = gl.getSupportedExtensions();
     98    if (supported.indexOf("OES_vertex_array_object") >= 0) {
     99        if (extensionEnabled) {
    100            testPassed("OES_vertex_array_object listed as supported and getExtension succeeded");
    101        } else {
    102            testFailed("OES_vertex_array_object listed as supported but getExtension failed");
    103        }
    104    } else {
    105        if (extensionEnabled) {
    106            testFailed("OES_vertex_array_object not listed as supported but getExtension succeeded");
    107        } else {
    108            testPassed("OES_vertex_array_object not listed as supported and getExtension failed -- this is legal");
    109        }
    110    }
    111 }
    112 
    113 function runBindingTestDisabled() {
    114    debug("");
    115    debug("Testing binding enum with extension disabled");
    116 
    117    // Use the constant directly as we don't have the extension
    118    var VERTEX_ARRAY_BINDING_OES = 0x85B5;
    119 
    120    gl.getParameter(VERTEX_ARRAY_BINDING_OES);
    121    wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "VERTEX_ARRAY_BINDING_OES should not be queryable if extension is disabled");
    122 }
    123 
    124 function runBindingTestEnabled() {
    125    debug("");
    126    debug("Testing binding enum with extension enabled");
    127 
    128    shouldBe("ext.VERTEX_ARRAY_BINDING_OES", "0x85B5");
    129 
    130    gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES);
    131    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "VERTEX_ARRAY_BINDING_OES query should succeed if extension is enabled");
    132 
    133    // Default value is null
    134    if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) === null) {
    135        testPassed("Default value of VERTEX_ARRAY_BINDING_OES is null");
    136    } else {
    137        testFailed("Default value of VERTEX_ARRAY_BINDING_OES is not null");
    138    }
    139 
    140    debug("");
    141    debug("Testing binding a VAO");
    142    var vao0 = ext.createVertexArrayOES();
    143    var vao1 = ext.createVertexArrayOES();
    144    shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
    145    ext.bindVertexArrayOES(vao0);
    146    if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) == vao0) {
    147        testPassed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is expected VAO");
    148    } else {
    149        testFailed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is not expected VAO")
    150    }
    151    ext.bindVertexArrayOES(vao1);
    152    if (gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) == vao1) {
    153        testPassed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is expected VAO");
    154    } else {
    155        testFailed("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES) is not expected VAO")
    156    }
    157    ext.deleteVertexArrayOES(vao1);
    158    shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
    159    ext.bindVertexArrayOES(vao1);
    160    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "binding a deleted vertex array object");
    161    ext.bindVertexArrayOES(null);
    162    shouldBeNull("gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)");
    163    ext.deleteVertexArrayOES(vao1);
    164 }
    165 
    166 function runObjectTest() {
    167    debug("");
    168    debug("Testing object creation");
    169 
    170    vao = ext.createVertexArrayOES();
    171    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createVertexArrayOES should not set an error");
    172    shouldBeNonNull("vao");
    173 
    174    // Expect false if never bound
    175    shouldBeFalse("ext.isVertexArrayOES(vao)");
    176    ext.bindVertexArrayOES(vao);
    177    shouldBeTrue("ext.isVertexArrayOES(vao)");
    178    ext.bindVertexArrayOES(null);
    179    shouldBeTrue("ext.isVertexArrayOES(vao)");
    180 
    181    shouldBeFalse("ext.isVertexArrayOES(null)");
    182 
    183    ext.deleteVertexArrayOES(vao);
    184    vao = null;
    185 }
    186 
    187 function runAttributeTests() {
    188    debug("");
    189    debug("Testing attributes work across bindings");
    190 
    191    var states = [];
    192 
    193    var attrCount = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
    194    for (var n = 0; n < attrCount; n++) {
    195        gl.bindBuffer(gl.ARRAY_BUFFER, null);
    196        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
    197 
    198        var state = {};
    199        states.push(state);
    200 
    201        var vao = state.vao = ext.createVertexArrayOES();
    202        ext.bindVertexArrayOES(vao);
    203 
    204        var enableArray = (n % 2 == 0);
    205        if (enableArray) {
    206            gl.enableVertexAttribArray(n);
    207        } else {
    208            gl.disableVertexAttribArray(n);
    209        }
    210 
    211        if (enableArray) {
    212            var buffer = state.buffer = gl.createBuffer();
    213            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    214            gl.bufferData(gl.ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
    215 
    216            gl.vertexAttribPointer(n, 1 + n % 4, gl.FLOAT, true, n * 4, n * 4);
    217        }
    218 
    219        if (enableArray) {
    220            var elbuffer = state.elbuffer = gl.createBuffer();
    221            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elbuffer);
    222            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 1024, gl.STATIC_DRAW);
    223        }
    224 
    225        ext.bindVertexArrayOES(null);
    226    }
    227 
    228    var anyMismatch = false;
    229    for (var n = 0; n < attrCount; n++) {
    230        var state = states[n];
    231 
    232        ext.bindVertexArrayOES(state.vao);
    233 
    234        var shouldBeEnabled = (n % 2 == 0);
    235        var isEnabled = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
    236        if (shouldBeEnabled != isEnabled) {
    237            testFailed("VERTEX_ATTRIB_ARRAY_ENABLED not preserved");
    238            anyMismatch = true;
    239        }
    240 
    241        var buffer = gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
    242        if (shouldBeEnabled) {
    243            if (buffer == state.buffer) {
    244                // Matched
    245                if ((gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_SIZE) == 1 + n % 4) &&
    246                    (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_TYPE) == gl.FLOAT) &&
    247                    (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED) == true) &&
    248                    (gl.getVertexAttrib(n, gl.VERTEX_ATTRIB_ARRAY_STRIDE) == n * 4) &&
    249                    (gl.getVertexAttribOffset(n, gl.VERTEX_ATTRIB_ARRAY_POINTER) == n * 4)) {
    250                    // Matched
    251                } else {
    252                    testFailed("VERTEX_ATTRIB_ARRAY_* not preserved");
    253                    anyMismatch = true;
    254                }
    255            } else {
    256                testFailed("VERTEX_ATTRIB_ARRAY_BUFFER_BINDING not preserved");
    257                anyMismatch = true;
    258            }
    259        } else {
    260            // GL_CURRENT_VERTEX_ATTRIB is not preserved
    261            if (buffer) {
    262                testFailed("VERTEX_ATTRIB_ARRAY_BUFFER_BINDING not preserved");
    263                anyMismatch = true;
    264            }
    265        }
    266 
    267        var elbuffer = gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING);
    268        if (shouldBeEnabled) {
    269            if (elbuffer == state.elbuffer) {
    270                // Matched
    271            } else {
    272                testFailed("ELEMENT_ARRAY_BUFFER_BINDING not preserved");
    273                anyMismatch = true;
    274            }
    275        } else {
    276            if (elbuffer == null) {
    277                // Matched
    278            } else {
    279                testFailed("ELEMENT_ARRAY_BUFFER_BINDING not preserved");
    280                anyMismatch = true;
    281            }
    282        }
    283    }
    284    ext.bindVertexArrayOES(null);
    285    if (!anyMismatch) {
    286        testPassed("All attributes preserved across bindings");
    287    }
    288 
    289    for (var n = 0; n < attrCount; n++) {
    290        var state = states[n];
    291        ext.deleteVertexArrayOES(state.vao);
    292    }
    293 }
    294 
    295 function runAttributeValueTests() {
    296    debug("");
    297    debug("Testing that attribute values are not attached to bindings");
    298 
    299    var v;
    300    var vao0 = ext.createVertexArrayOES();
    301    var anyFailed = false;
    302 
    303    ext.bindVertexArrayOES(null);
    304    gl.vertexAttrib4f(0, 0, 1, 2, 3);
    305 
    306    v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
    307    if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
    308        testFailed("Vertex attrib value not round-tripped?");
    309        anyFailed = true;
    310    }
    311 
    312    ext.bindVertexArrayOES(vao0);
    313 
    314    v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
    315    if (!(v[0] == 0 && v[1] == 1 && v[2] == 2 && v[3] == 3)) {
    316        testFailed("Vertex attrib value reset across bindings");
    317        anyFailed = true;
    318    }
    319 
    320    gl.vertexAttrib4f(0, 4, 5, 6, 7);
    321    ext.bindVertexArrayOES(null);
    322 
    323    v = gl.getVertexAttrib(0, gl.CURRENT_VERTEX_ATTRIB);
    324    if (!(v[0] == 4 && v[1] == 5 && v[2] == 6 && v[3] == 7)) {
    325        testFailed("Vertex attrib value bound to buffer");
    326        anyFailed = true;
    327    }
    328 
    329    if (!anyFailed) {
    330        testPassed("Vertex attribute values are not attached to bindings")
    331    }
    332 
    333    ext.bindVertexArrayOES(null);
    334    ext.deleteVertexArrayOES(vao0);
    335 }
    336 
    337 function runDrawTests() {
    338    debug("");
    339    debug("Testing draws with various VAO bindings");
    340 
    341    canvas.width = 50; canvas.height = 50;
    342    gl.viewport(0, 0, canvas.width, canvas.height);
    343 
    344    var vao0 = ext.createVertexArrayOES();
    345    var vao1 = ext.createVertexArrayOES();
    346    var vao2 = ext.createVertexArrayOES();
    347 
    348    var positionLocation = 0;
    349    var colorLocation = 1;
    350 
    351    var program = wtu.setupSimpleVertexColorProgram(gl, positionLocation, colorLocation);
    352 
    353    function setupQuad(s, colorsInArray) {
    354        var vertexObject = gl.createBuffer();
    355        gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
    356        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    357             1.0 * s,  1.0 * s, 0.0,
    358            -1.0 * s,  1.0 * s, 0.0,
    359            -1.0 * s, -1.0 * s, 0.0,
    360             1.0 * s,  1.0 * s, 0.0,
    361            -1.0 * s, -1.0 * s, 0.0,
    362             1.0 * s, -1.0 * s, 0.0]), gl.STATIC_DRAW);
    363        gl.enableVertexAttribArray(positionLocation);
    364        gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
    365 
    366        // Test switching between VAOs that have different number of enabled arrays
    367        if (colorsInArray) {
    368            var vertexObject = gl.createBuffer();
    369            gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
    370            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    371                0.0, 0.0, 0.0, 1.0,
    372                0.0, 0.0, 0.0, 1.0,
    373                0.0, 0.0, 0.0, 1.0,
    374                0.0, 0.0, 0.0, 1.0,
    375                0.0, 0.0, 0.0, 1.0,
    376                0.0, 0.0, 0.0, 1.0]), gl.STATIC_DRAW);
    377            gl.enableVertexAttribArray(colorLocation);
    378            gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
    379        } else {
    380            gl.disableVertexAttribArray(colorLocation);
    381        }
    382    };
    383 
    384    function verifyDiagonalPixels(s, expectedInside, drawDescription) {
    385        // Tests pixels along a diagonal running from the center of the canvas to the (0, 0) corner.
    386        // Values on the points list indicate relative position along this diagonal.
    387        var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
    388        for (var n = 0; n < points.length; n++) {
    389            var expected = points[n] <= s ? expectedInside : 255;
    390            var x = Math.round((1 - points[n]) * canvas.width / 2);
    391            var y = Math.round((1 - points[n]) * canvas.height / 2);
    392            wtu.checkCanvasRect(gl, x, y, 1, 1, [expected, expected, expected, 255],
    393                "Drawing " + drawDescription + " should pass", 2);
    394        }
    395    };
    396    function verifyDraw(drawDescription, s, colorsInArray) {
    397        wtu.clearAndDrawUnitQuad(gl);
    398        var expectedInside = colorsInArray ? 0 : 128;
    399        verifyDiagonalPixels(s, expectedInside, drawDescription);
    400    };
    401 
    402    // Setup all bindings
    403    setupQuad(1, true);
    404    ext.bindVertexArrayOES(vao0);
    405    setupQuad(0.5, true);
    406    ext.bindVertexArrayOES(vao1);
    407    setupQuad(0.25, true);
    408    ext.bindVertexArrayOES(vao2);
    409    setupQuad(0.75, false);
    410 
    411    gl.vertexAttrib4f(colorLocation, 0.5, 0.5, 0.5, 1);
    412 
    413    // Verify drawing
    414    ext.bindVertexArrayOES(null);
    415    verifyDraw("with the default VAO", 1, true);
    416    ext.bindVertexArrayOES(vao0);
    417    verifyDraw("with VAO #0", 0.5, true);
    418    ext.bindVertexArrayOES(vao1);
    419    verifyDraw("with VAO #1", 0.25, true);
    420    ext.bindVertexArrayOES(vao2);
    421    verifyDraw("with VAO that has the color array disabled", 0.75, false);
    422 
    423    // Verify bound VAO after delete
    424    ext.bindVertexArrayOES(vao1);
    425    ext.deleteVertexArrayOES(vao0);
    426    verifyDraw("after deleting another VAO", 0.25, true);
    427    ext.deleteVertexArrayOES(vao1);
    428    verifyDraw("after deleting the VAO that was bound", 1, true);
    429 
    430    // Disable global vertex attrib array
    431    gl.disableVertexAttribArray(positionLocation);
    432    gl.disableVertexAttribArray(colorLocation);
    433 
    434    // Check that constant values are treated correctly as not being part of VAO state.
    435    var positionLoc = 0;
    436    var colorLoc = 1;
    437    var gridRes = 1;
    438    wtu.setupIndexedQuad(gl, gridRes, positionLoc);
    439    // Set the vertex color to red.
    440    gl.vertexAttrib4f(colorLoc, 1, 0, 0, 1);
    441 
    442    var vao0 = ext.createVertexArrayOES();
    443    ext.bindVertexArrayOES(vao0);
    444    var program = wtu.setupSimpleVertexColorProgram(gl, positionLoc, colorLoc);
    445    wtu.setupIndexedQuad(gl, gridRes, positionLoc);
    446    // Set the vertex color to green.
    447    gl.vertexAttrib4f(colorLoc, 0, 1, 0, 1);
    448    wtu.clearAndDrawIndexedQuad(gl, gridRes);
    449    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    450    ext.deleteVertexArrayOES(vao0);
    451    wtu.clearAndDrawIndexedQuad(gl, gridRes);
    452    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    453 }
    454 
    455 function runUnboundDeleteTests() {
    456    debug("");
    457    debug("Testing using buffers that are deleted when attached to unbound VAOs");
    458 
    459    var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_position", "a_color"]);
    460    gl.useProgram(program);
    461 
    462    var positionBuffer = gl.createBuffer();
    463    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    464    gl.bufferData(
    465        gl.ARRAY_BUFFER,
    466        new Float32Array([
    467             1.0,  1.0,
    468            -1.0,  1.0,
    469            -1.0, -1.0,
    470             1.0, -1.0]),
    471        gl.STATIC_DRAW);
    472 
    473    var colors = [
    474        [255,   0,   0, 255],
    475        [  0, 255,   0, 255],
    476        [  0,   0, 255, 255],
    477        [  0, 255, 255, 255]
    478    ];
    479    var colorBuffers = [];
    480    var elementBuffers = [];
    481    var vaos = [];
    482    for (var ii = 0; ii < colors.length; ++ii) {
    483        var vao = ext.createVertexArrayOES();
    484        vaos.push(vao);
    485        ext.bindVertexArrayOES(vao);
    486        // Set the position buffer
    487        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    488        gl.enableVertexAttribArray(0);
    489        gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    490 
    491        var elementBuffer = gl.createBuffer();
    492        elementBuffers.push(elementBuffer);
    493        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
    494        gl.bufferData(
    495            gl.ELEMENT_ARRAY_BUFFER,
    496            new Uint8Array([0, 1, 2, 0, 2, 3]),
    497            gl.STATIC_DRAW);
    498 
    499        // Setup the color attrib
    500        var color = colors[ii];
    501        if (ii < 3) {
    502            var colorBuffer = gl.createBuffer();
    503            colorBuffers.push(colorBuffer);
    504            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    505            gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
    506                [ color[0], color[1], color[2], color[3],
    507                  color[0], color[1], color[2], color[3],
    508                  color[0], color[1], color[2], color[3],
    509                  color[0], color[1], color[2], color[3]
    510                ]), gl.STATIC_DRAW);
    511            gl.enableVertexAttribArray(1);
    512            gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
    513        } else {
    514            gl.vertexAttrib4f(1, color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255);
    515        }
    516    }
    517 
    518    // delete the color buffers AND the position buffer.
    519    ext.bindVertexArrayOES(null);
    520    for (var ii = 0; ii < colorBuffers.length; ++ii) {
    521        gl.deleteBuffer(colorBuffers[ii]);
    522        gl.deleteBuffer(elementBuffers[ii]);
    523        ext.bindVertexArrayOES(vaos[ii]);
    524        var boundBuffer = gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
    525        // The buffers should still be valid at this point, since it was attached to the VAO
    526        if(boundBuffer != colorBuffers[ii]) {
    527            testFailed("buffer removed even though it is still attached to a VAO");
    528        }
    529    }
    530 
    531    ext.bindVertexArrayOES(null);
    532    gl.deleteBuffer(positionBuffer);
    533 
    534    // Render with the deleted buffers. As they are referenced by VAOs they
    535    // must still be around.
    536    for (var ii = 0; ii < colors.length; ++ii) {
    537        var color = colors[ii];
    538        ext.bindVertexArrayOES(vaos[ii]);
    539        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
    540        wtu.checkCanvas(gl, color, "should be " + color);
    541    }
    542 
    543    // Clean up.
    544    for (var ii = 0; ii < colorBuffers.length; ++ii) {
    545        ext.deleteVertexArrayOES(vaos[ii]);
    546    }
    547 
    548    for (var ii = 0; ii < colorBuffers.length; ++ii) {
    549        // The buffers should no longer be valid now that the VAOs are deleted
    550        if(gl.isBuffer(colorBuffers[ii])) {
    551            testFailed("buffer not properly cleaned up after VAO deletion");
    552        }
    553    }
    554 }
    555 
    556 function runBoundDeleteTests() {
    557    debug("Testing using buffers that are deleted when attached to bound VAOs");
    558 
    559    var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_position", "a_color"]);
    560    gl.useProgram(program);
    561 
    562    var positionBuffer = gl.createBuffer();
    563    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    564    gl.bufferData(
    565        gl.ARRAY_BUFFER,
    566        new Float32Array([
    567             1.0,  1.0,
    568            -1.0,  1.0,
    569            -1.0, -1.0,
    570             1.0, -1.0]),
    571        gl.STATIC_DRAW);
    572 
    573    // Setup the color attrib
    574    var colorBuffer = gl.createBuffer();
    575    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    576    gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
    577        [ 255,   0,   0, 255,
    578            0, 255,   0, 255,
    579            0,   0, 255, 255,
    580            0, 255, 255, 255
    581        ]), gl.STATIC_DRAW);
    582 
    583    var vaos = [];
    584    var elementBuffers = [];
    585    for (var ii = 0; ii < 4; ++ii) {
    586        var vao = ext.createVertexArrayOES();
    587        vaos.push(vao);
    588        ext.bindVertexArrayOES(vao);
    589 
    590        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    591        gl.enableVertexAttribArray(0);
    592        gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    593 
    594        var elementBuffer = gl.createBuffer();
    595        elementBuffers.push(elementBuffer);
    596        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
    597        gl.bufferData(
    598            gl.ELEMENT_ARRAY_BUFFER,
    599            new Uint8Array([0, 1, 2, 0, 2, 3]),
    600            gl.STATIC_DRAW);
    601 
    602        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    603        gl.enableVertexAttribArray(1);
    604        gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
    605    }
    606 
    607    // delete the color buffers AND the position buffer, that are bound to the current VAO
    608    for (var ii = 0; ii < vaos.length; ++ii) {
    609        ext.bindVertexArrayOES(vaos[ii]);
    610 
    611        gl.deleteBuffer(colorBuffer);
    612        gl.deleteBuffer(positionBuffer);
    613 
    614        // After the first iteration, deleteBuffer will be a no-op, and will not unbind its matching
    615        // bind points on the now-bound VAO like it did on the first iteration.
    616        var expectRetained = (ii != 0);
    617        var shouldBeStr = (expectRetained ? "retained" : "cleared");
    618 
    619        var boundPositionBuffer = gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
    620        if (expectRetained != (boundPositionBuffer == positionBuffer)) {
    621            testFailed("Position attrib stored buffer should be " + shouldBeStr + ".");
    622        }
    623 
    624        var boundColorBuffer = gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
    625        if (expectRetained != (boundColorBuffer == colorBuffer)) {
    626            testFailed("Color attrib stored buffer should be " + shouldBeStr + ".");
    627        }
    628 
    629        // If retained, everything should still work. If cleared, drawing should now fail.
    630        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
    631        var expectedError = (expectRetained ? gl.NO_ERROR : gl.INVALID_OPERATION);
    632        wtu.glErrorShouldBe(gl, expectedError,
    633                            "Draw call should " + (expectRetained ? "not " : "") + "fail.");
    634 
    635        if (gl.isBuffer(positionBuffer)) {
    636            testFailed("References from unbound VAOs don't keep Position buffer alive.");
    637        }
    638        if (gl.isBuffer(colorBuffer)) {
    639            testFailed("References from unbound VAOs don't keep Color buffer alive");
    640        }
    641    }
    642 }
    643 
    644 function runArrayBufferBindTests() {
    645    debug("");
    646    debug("Testing that buffer bindings on VAOs don't affect default VAO ARRAY_BUFFER binding.");
    647 
    648    ext.bindVertexArrayOES(null);
    649 
    650    var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["a_color", "a_position"]);
    651    gl.useProgram(program);
    652 
    653    // create shared element buffer
    654    var elementBuffer = gl.createBuffer();
    655    // bind to default
    656    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
    657    gl.bufferData(
    658        gl.ELEMENT_ARRAY_BUFFER,
    659        new Uint8Array([0, 1, 2, 0, 2, 3]),
    660        gl.STATIC_DRAW);
    661 
    662    // first create the buffers for no VAO draw.
    663    var nonVAOColorBuffer = gl.createBuffer();
    664    gl.bindBuffer(gl.ARRAY_BUFFER, nonVAOColorBuffer);
    665    gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
    666        [ 0, 255, 0, 255,
    667          0, 255, 0, 255,
    668          0, 255, 0, 255,
    669          0, 255, 0, 255,
    670        ]), gl.STATIC_DRAW);
    671 
    672    // shared position buffer.
    673    var positionBuffer = gl.createBuffer();
    674    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    675    gl.bufferData(
    676        gl.ARRAY_BUFFER,
    677        new Float32Array([
    678             1.0,  1.0,
    679            -1.0,  1.0,
    680            -1.0, -1.0,
    681             1.0, -1.0]),
    682        gl.STATIC_DRAW);
    683 
    684    // attach position buffer to default
    685    gl.enableVertexAttribArray(1);
    686    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
    687 
    688    // now create VAO
    689    var vao = ext.createVertexArrayOES();
    690    ext.bindVertexArrayOES(vao);
    691 
    692    // attach the position buffer VAO
    693    gl.enableVertexAttribArray(1);
    694    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
    695 
    696    var vaoColorBuffer = gl.createBuffer();
    697    gl.bindBuffer(gl.ARRAY_BUFFER, vaoColorBuffer);
    698    gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(
    699        [ 255, 0, 0, 255,
    700          255, 0, 0, 255,
    701          255, 0, 0, 255,
    702          255, 0, 0, 255,
    703        ]), gl.STATIC_DRAW);
    704    gl.enableVertexAttribArray(0);
    705    gl.vertexAttribPointer(0, 4, gl.UNSIGNED_BYTE, true, 0, 0);
    706 
    707    // now set the buffer back to the nonVAOColorBuffer
    708    gl.bindBuffer(gl.ARRAY_BUFFER, nonVAOColorBuffer);
    709 
    710    // bind to VAO
    711    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
    712    gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
    713    wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
    714 
    715    // unbind VAO
    716    ext.bindVertexArrayOES(null);
    717 
    718    // At this point the nonVAOColorBuffer should be still be bound.
    719    // If the WebGL impl is emulating VAOs it must make sure
    720    // it correctly restores this binding.
    721    gl.enableVertexAttribArray(0);
    722    gl.vertexAttribPointer(0, 4, gl.UNSIGNED_BYTE, true, 0, 0);
    723    gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
    724    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
    725 }
    726 
    727 function runInvalidContextTests() {
    728    contextA = wtu.create3DContext(undefined, undefined, 1);
    729    contextB = wtu.create3DContext(undefined, undefined, 1);
    730    extA = contextA.getExtension("OES_vertex_array_object");
    731    extB = contextB.getExtension("OES_vertex_array_object");
    732    vertexArrayA = extA.createVertexArrayOES();
    733    vertexArrayB = extB.createVertexArrayOES();
    734 
    735    wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.bindVertexArrayOES(vertexArrayA)");
    736    wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.bindVertexArrayOES(null)");
    737    wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.bindVertexArrayOES(vertexArrayB)");
    738    wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.bindVertexArrayOES(null)");
    739 
    740    debug("")
    741    debug("State queries validate context");
    742    shouldBeFalse("extA.isVertexArrayOES(vertexArrayB)");
    743    wtu.glErrorShouldBe(contextA, gl.NO_ERROR, "there should be no errors from invalid request");
    744    shouldBeFalse("extB.isVertexArrayOES(vertexArrayA)");
    745    wtu.glErrorShouldBe(contextB, gl.NO_ERROR, "there should be no errors from invalid request");
    746    shouldBeTrue("extA.isVertexArrayOES(vertexArrayA)");
    747    wtu.glErrorShouldBe(contextA, gl.NO_ERROR, "there should be no errors from valid request");
    748    shouldBeTrue("extB.isVertexArrayOES(vertexArrayB)");
    749    wtu.glErrorShouldBe(contextB, gl.NO_ERROR, "there should be no errors from valid request");
    750 
    751    debug("")
    752    debug("Deleting an object from another context generates an error");
    753    wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.deleteVertexArrayOES(vertexArrayB)");
    754    wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.deleteVertexArrayOES(vertexArrayA)");
    755 
    756    debug("")
    757    debug("Invalid delete operations do not delete");
    758    shouldBeTrue("extA.isVertexArrayOES(vertexArrayA)");
    759    shouldBeTrue("extB.isVertexArrayOES(vertexArrayB)");
    760 
    761    debug("")
    762    debug("Cannot bind VAOs from other contexts");
    763    wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.bindVertexArrayOES(vertexArrayB)");
    764    wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.bindVertexArrayOES(vertexArrayA)");
    765 
    766    debug("")
    767    debug("Context checks happen even for deleted objects");
    768    wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "extA.deleteVertexArrayOES(vertexArrayA)");
    769    wtu.shouldGenerateGLError(contextB, contextB.NO_ERROR, "extB.deleteVertexArrayOES(vertexArrayB)");
    770    wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "extA.deleteVertexArrayOES(vertexArrayB)");
    771    wtu.shouldGenerateGLError(contextB, contextB.INVALID_OPERATION, "extB.deleteVertexArrayOES(vertexArrayA)");
    772 }
    773 
    774 debug("");
    775 var successfullyParsed = true;
    776 </script>
    777 <script src="../../js/js-test-post.js"></script>
    778 
    779 </body>
    780 </html>