tor-browser

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

uniform-buffers.html (21510B)


      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 Uniform Buffers 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 <script id='vshader' type='x-shader/x-vertex'>#version 300 es
     16 layout(location=0) in vec3 p;
     17 void main()
     18 {
     19    gl_Position = vec4(p.xyz, 1.0);
     20 }
     21 </script>
     22 <script id='fbadshader' type='x-shader/x-fragment'>#version 300 es
     23 precision mediump float;
     24 layout(location=0) out vec4 oColor;
     25 
     26 uniform UBOData {
     27    float UBORed;
     28    float UBOGreen;
     29    float UBOBlue;
     30 };
     31 
     32 uniform Color {
     33    float Red;
     34    float UBOGreen;
     35    float Blue;
     36 };
     37 
     38 void main()
     39 {
     40    oColor = vec4(UBORed * Red, UBOGreen * UBOGreen, UBOBlue * Blue, 1.0);
     41 }
     42 </script>
     43 <script id='fshader' type='x-shader/x-fragment'>#version 300 es
     44 precision mediump float;
     45 layout(location=0) out vec4 oColor;
     46 
     47 uniform UBOData {
     48    float UBORed;
     49    float UBOGreen;
     50    float UBOBlue;
     51 };
     52 
     53 uniform UBOD {
     54    float UBOR;
     55    float UBOG;
     56    float UBOB;
     57 };
     58 
     59 void main()
     60 {
     61    oColor = vec4(UBORed * UBOR, UBOGreen * UBOG, UBOBlue * UBOB, 1.0);
     62 }
     63 </script>
     64 <script id='fshadernamed' type='x-shader/x-fragment'>#version 300 es
     65 precision mediump float;
     66 layout(location=0) out vec4 oColor;
     67 
     68 uniform UBOData {
     69    float Red;
     70    float Green;
     71    float Blue;
     72 } UBOA;
     73 
     74 void main()
     75 {
     76    oColor = vec4(UBOA.Red, UBOA.Green, UBOA.Blue, 1.0);
     77 }
     78 </script>
     79 <script id='fshadernamedarray' type='x-shader/x-fragment'>#version 300 es
     80 precision mediump float;
     81 layout(location=0) out vec4 oColor;
     82 
     83 uniform UBOData {
     84    float Red;
     85    float Green;
     86    float Blue;
     87 } UBOA[2];
     88 
     89 void main()
     90 {
     91    oColor = vec4((UBOA[0].Red + UBOA[1].Red) / 2.0,
     92                  (UBOA[0].Green + UBOA[1].Green) / 2.0,
     93                  (UBOA[0].Blue + UBOA[1].Blue) / 2.0, 1.0);
     94 }
     95 </script>
     96 <script id='fshadernestedstruct' type='x-shader/x-fragment'>#version 300 es
     97 precision mediump float;
     98 layout(location=0) out vec4 oColor;
     99 
    100 struct color_t {
    101    float red;
    102    float green;
    103    float blue;
    104 };
    105 
    106 struct wrapper_t {
    107    color_t color;
    108 };
    109 
    110 uniform UBOData {
    111    wrapper_t UBOStruct;
    112 };
    113 
    114 // This is intended to reproduce a specific ANGLE bug that triggers when the wrapper struct is passed to a function.
    115 // https://bugs.chromium.org/p/angleproject/issues/detail?id=2084
    116 void processColor(wrapper_t wrapper) {
    117    oColor = vec4(wrapper.color.red, wrapper.color.green, wrapper.color.blue, 1.0);
    118 }
    119 
    120 void main()
    121 {
    122    processColor(UBOStruct);
    123 }
    124 </script>
    125 <script id='fshaderarrayofstructs' type='x-shader/x-fragment'>#version 300 es
    126 precision mediump float;
    127 layout(location=0) out vec4 oColor;
    128 
    129 struct color_t {
    130    float red;
    131    float green;
    132    float blue;
    133 };
    134 
    135 uniform UBOData {
    136    color_t UBOColors[2];
    137 };
    138 
    139 // This is intended to reproduce a specific ANGLE bug that triggers when a struct from an array of structs in an interface block is passed to a function.
    140 // https://bugs.chromium.org/p/angleproject/issues/detail?id=2084
    141 vec3 processColor(color_t color) {
    142    return vec3(color.red, color.green, color.blue);
    143 }
    144 
    145 void main()
    146 {
    147    oColor = vec4(processColor(UBOColors[0]) + processColor(UBOColors[1]), 1.0);
    148 }
    149 </script>
    150 </head>
    151 <body>
    152 <div id="description"></div>
    153 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
    154 <div id="console"></div>
    155 <script>
    156 "use strict";
    157 description("This test verifies the functionality of the Uniform Buffer objects");
    158 
    159 debug("");
    160 
    161 var wtu = WebGLTestUtils;
    162 var canvas = document.getElementById("canvas");
    163 var gl = wtu.create3DContext(canvas, null, 2);
    164 var b1 = null;
    165 var b2 = null;
    166 
    167 if (!gl) {
    168    testFailed("WebGL context does not exist");
    169 } else {
    170    testPassed("WebGL context exists");
    171 
    172    wtu.setupUnitQuad(gl);
    173 
    174    runBindingTest();
    175    runBadShaderTest();
    176    runUniformBufferOffsetAlignmentTest();
    177    runDrawTest();
    178    runNamedDrawTest();
    179    runNamedArrayDrawTest();
    180    runNestedStructsDrawTest();
    181    runArrayOfStructsDrawTest();
    182 }
    183 
    184 function runBindingTest() {
    185    debug("");
    186    debug("Testing uniform buffer binding behavior");
    187    shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
    188    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "UNIFORM_BUFFER_BINDING query should succeed");
    189 
    190    debug("Testing basic uniform buffer binding and unbinding");
    191    b1 = gl.createBuffer();
    192    b2 = gl.createBuffer();
    193    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createBuffer should not set an error");
    194    shouldBeNonNull("b1");
    195    shouldBeNonNull("b2");
    196    gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
    197    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to bind uniform buffer");
    198    shouldBe("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)", "b1");
    199    gl.bindBuffer(gl.UNIFORM_BUFFER, b2);
    200    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to update uniform buffer binding");
    201    shouldBe("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)", "b2");
    202    gl.bindBuffer(gl.UNIFORM_BUFFER, null);
    203    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to unbind uniform buffer");
    204 
    205    debug("Testing deleting uniform buffers");
    206    gl.deleteBuffer(b1);
    207    gl.deleteBuffer(b2);
    208    shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
    209 
    210    // Shouldn't be able to bind a deleted buffer.
    211    gl.bindBuffer(gl.UNIFORM_BUFFER, b2);
    212    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "binding a deleted buffer should generate INVALID_OPERATION");
    213    shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
    214 }
    215 
    216 function runBadShaderTest() {
    217    debug("");
    218    var testProgram = wtu.setupProgram(gl, ['vshader', 'fbadshader']);
    219    if (testProgram) {
    220        testFailed("To define the same uniform in two uniform blocks should fail");
    221    } else {
    222        testPassed("To define the same uniform in two uniform blocks should fail");
    223    }
    224 }
    225 
    226 function runUniformBufferOffsetAlignmentTest() {
    227    debug("");
    228    var offsetAlignment = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
    229 
    230    if (offsetAlignment % 4 != 0) {
    231        testFailed("Unexpected UNIFORM_BUFFER_OFFSET_ALIGNMENT - should be aligned on a 4-byte boundary");
    232    } else {
    233        testPassed("UNIFORM_BUFFER_OFFSET_ALIGNMENT is divisible by four");
    234    }
    235 }
    236 
    237 function setRGBValuesToFloat32Array(floatView, red, green, blue) {
    238    floatView[0] = red;
    239    floatView[1] = green;
    240    floatView[2] = blue;
    241 }
    242 
    243 function checkFloat32UniformOffsetsInStd140Layout(uniformOffsets, expectedInitialOffset) {
    244    if (expectedInitialOffset === undefined)
    245    {
    246        expectedInitialOffset = 0;
    247    }
    248    // Verify that the uniform offsets are set according to the std140 layout, which WebGL enforces.
    249    // This function checks this for 32-bit float values, which are expected to be tightly packed.
    250    for (var i = 0; i < uniformOffsets.length; ++i)
    251    {
    252        if (uniformOffsets[i] != expectedInitialOffset + i * Float32Array.BYTES_PER_ELEMENT)
    253        {
    254            testFailed("Uniform offsets are not according to std140 layout");
    255            return false;
    256        }
    257    }
    258    return true;
    259 }
    260 
    261 function runDrawTest() {
    262    debug("");
    263    debug("Testing drawing with uniform buffers");
    264 
    265    var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
    266    if (!program) {
    267        testFailed("Could not compile shader with uniform blocks without error");
    268        return;
    269    }
    270 
    271    var blockIndex_1 = gl.getUniformBlockIndex(program, "UBOData");
    272    var blockSize_1 = gl.getActiveUniformBlockParameter(program, blockIndex_1, gl.UNIFORM_BLOCK_DATA_SIZE);
    273    var uniformIndices_1 = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]);
    274    var uniformOffsets_1 = gl.getActiveUniforms(program, uniformIndices_1, gl.UNIFORM_OFFSET);
    275    var blockIndex_2 = gl.getUniformBlockIndex(program, "UBOD");
    276    var blockSize_2 = gl.getActiveUniformBlockParameter(program, blockIndex_2, gl.UNIFORM_BLOCK_DATA_SIZE);
    277    var uniformIndices_2 = gl.getUniformIndices(program, ["UBOR", "UBOG", "UBOB"]);
    278    var uniformOffsets_2 = gl.getActiveUniforms(program, uniformIndices_2, gl.UNIFORM_OFFSET);
    279    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
    280 
    281    if (uniformOffsets_1.length < 3 || uniformOffsets_2.length < 3) {
    282        testFailed("Could not query uniform offsets");
    283        return;
    284    }
    285 
    286    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_1) || !checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_2))
    287    {
    288        return;
    289    }
    290 
    291    var uboArray_1 = new ArrayBuffer(blockSize_1);
    292    var uboFloatView_1 = new Float32Array(uboArray_1);
    293    setRGBValuesToFloat32Array(uboFloatView_1, 1.0, 0.0, 0.0); // UBORed, UBOGreen, UBOBlue
    294    var uboArray_2 = new ArrayBuffer(blockSize_2);
    295    var uboFloatView_2 = new Float32Array(uboArray_2);
    296    setRGBValuesToFloat32Array(uboFloatView_2, 1.0, 1.0, 1.0); // UBOR, UBOG, UBOB
    297 
    298    var b_1 = gl.createBuffer();
    299    gl.bindBuffer(gl.UNIFORM_BUFFER, b_1);
    300    gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_1, gl.DYNAMIC_DRAW);
    301    var b_2 = gl.createBuffer();
    302    gl.bindBuffer(gl.UNIFORM_BUFFER, b_2);
    303    gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_2, gl.DYNAMIC_DRAW);
    304    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
    305 
    306    var bindings = [1, 2];
    307    gl.uniformBlockBinding(program, blockIndex_1, bindings[0]);
    308    gl.bindBufferBase(gl.UNIFORM_BUFFER, bindings[0], b_1);
    309    gl.uniformBlockBinding(program, blockIndex_2, bindings[1]);
    310    gl.bindBufferBase(gl.UNIFORM_BUFFER, bindings[1], b_2);
    311    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
    312 
    313    wtu.clearAndDrawUnitQuad(gl);
    314    wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
    315 
    316    debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
    317    setRGBValuesToFloat32Array(uboFloatView_1, 0.0, 0.0, 1.0); // UBORed, UBOGreen, UBOBlue
    318    gl.bindBuffer(gl.UNIFORM_BUFFER, b_1);
    319    gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_1, gl.DYNAMIC_DRAW);
    320 
    321    wtu.clearAndDrawUnitQuad(gl);
    322    wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
    323    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    324 }
    325 
    326 function runNamedDrawTest() {
    327    debug("");
    328    debug("Testing drawing with named uniform buffers");
    329 
    330    var program = wtu.setupProgram(gl, ['vshader', 'fshadernamed']);
    331    if (!program) {
    332        testFailed("Could not compile shader with named uniform blocks without error");
    333        return;
    334    }
    335 
    336    var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
    337    var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
    338    var uniformIndices = gl.getUniformIndices(program, ["UBOData.Red", "UBOData.Green", "UBOData.Blue"]);
    339    var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
    340    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
    341 
    342    if (uniformOffsets.length < 3) {
    343        testFailed("Could not query uniform offsets");
    344        return;
    345    }
    346 
    347    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
    348    {
    349        return;
    350    }
    351 
    352    var uboArray = new ArrayBuffer(blockSize);
    353    var uboFloatView = new Float32Array(uboArray);
    354    setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
    355 
    356    b1 = gl.createBuffer();
    357    gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
    358    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    359    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
    360 
    361    var binding = 3;
    362    gl.uniformBlockBinding(program, blockIndex, binding);
    363    gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
    364    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
    365 
    366    wtu.clearAndDrawUnitQuad(gl);
    367    wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
    368 
    369    debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
    370    setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.0, 1.0);
    371    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    372 
    373    wtu.clearAndDrawUnitQuad(gl);
    374    wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
    375    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    376 }
    377 
    378 function runNamedArrayDrawTest() {
    379    debug("");
    380    debug("Testing drawing with named uniform buffer arrays");
    381 
    382    var program = wtu.setupProgram(gl, ['vshader', 'fshadernamedarray']);
    383    if (!program) {
    384        testFailed("could not compile shader with named uniform block arrays without error");
    385        return;
    386    }
    387 
    388    var blockIndex = [gl.getUniformBlockIndex(program, "UBOData[0]"),
    389                      gl.getUniformBlockIndex(program, "UBOData[1]")];
    390    if (blockIndex[0] == gl.INVALID_INDEX ||
    391        blockIndex[1] == gl.INVALID_INDEX) {
    392        testFailed("Could not query uniform block index");
    393        return;
    394    }
    395    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block indices without error");
    396    var blockSize = [gl.getActiveUniformBlockParameter(program, blockIndex[0], gl.UNIFORM_BLOCK_DATA_SIZE),
    397                     gl.getActiveUniformBlockParameter(program, blockIndex[1], gl.UNIFORM_BLOCK_DATA_SIZE)];
    398    if (blockSize[0] != blockSize[1]) {
    399        testFailed("uniform block instance array with different block sizes");
    400    }
    401    var uniformIndices = gl.getUniformIndices(program, ["UBOData.Red", "UBOData.Green", "UBOData.Blue"]);
    402    if (uniformIndices < 3 ||
    403        uniformIndices[0] == gl.INVALID_INDEX ||
    404        uniformIndices[1] == gl.INVALID_INDEX ||
    405        uniformIndices[2] == gl.INVALID_INDEX) {
    406        testFailed("Could not query uniform indices");
    407        return;
    408    }
    409    var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
    410    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
    411    if (uniformOffsets.length < 3) {
    412        testFailed("Could not query uniform offsets");
    413        return;
    414    }
    415 
    416    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
    417    {
    418        return;
    419    }
    420 
    421    var offsetAlignment = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
    422    var offset = Math.ceil(blockSize[0] / offsetAlignment) * offsetAlignment;
    423 
    424    var bufferSize = offset + blockSize[1];
    425    var uboArray = new ArrayBuffer(bufferSize);
    426    var uboFloatView = new Float32Array(uboArray);
    427    setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
    428    var uboFloatView2 = new Float32Array(uboArray, offset);
    429    setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
    430 
    431    b1 = gl.createBuffer();
    432    gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
    433    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    434    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
    435 
    436    var bindings = [4, 5];
    437    gl.uniformBlockBinding(program, blockIndex[0], bindings[0]);
    438    gl.bindBufferRange(gl.UNIFORM_BUFFER, bindings[0], b1, 0, blockSize[0]);
    439    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferRange without errors");
    440    gl.uniformBlockBinding(program, blockIndex[1], bindings[1]);
    441    gl.bindBufferRange(gl.UNIFORM_BUFFER, bindings[1], b1, offset, blockSize[1]);
    442    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferRange without errors");
    443 
    444    wtu.clearAndDrawUnitQuad(gl);
    445    wtu.checkCanvas(gl, [127, 0, 127, 255], "draw call should set canvas to (0.5, 0, 0.5)", 2);
    446 
    447    debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
    448    setRGBValuesToFloat32Array(uboFloatView, 0.0, 1.0, 1.0);
    449    setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
    450    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    451 
    452    wtu.clearAndDrawUnitQuad(gl);
    453    wtu.checkCanvas(gl, [0, 127, 255, 255], "draw call should set canvas to (0, 0.5, 1)", 2);
    454    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    455 }
    456 
    457 function runNestedStructsDrawTest() {
    458    debug("");
    459    debug("Testing drawing with nested struct inside uniform block. The wrapper struct is passed to a function.");
    460 
    461    var program = wtu.setupProgram(gl, ['vshader', 'fshadernestedstruct'], undefined, undefined, true);
    462    if (!program) {
    463        testFailed("Could not compile shader with nested structs without error");
    464        return;
    465    }
    466 
    467    var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
    468    var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
    469    var uniformIndices = gl.getUniformIndices(program, ["UBOStruct.color.red", "UBOStruct.color.green", "UBOStruct.color.blue"]);
    470    var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
    471    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
    472 
    473    if (uniformOffsets.length < 3) {
    474        testFailed("Could not query uniform offsets");
    475        return;
    476    }
    477 
    478    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
    479    {
    480        return;
    481    }
    482 
    483    var uboArray = new ArrayBuffer(blockSize);
    484    var uboFloatView = new Float32Array(uboArray);
    485    setRGBValuesToFloat32Array(uboFloatView, 0.0, 1.0, 0.0);
    486 
    487    b1 = gl.createBuffer();
    488    gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
    489    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    490    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
    491 
    492    var binding = 3;
    493    gl.uniformBlockBinding(program, blockIndex, binding);
    494    gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
    495    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
    496 
    497    wtu.clearAndDrawUnitQuad(gl);
    498    wtu.checkCanvas(gl, [0, 255, 0, 255], "draw call should set canvas to green", 2);
    499 
    500    debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
    501    setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.0, 1.0);
    502    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    503 
    504    wtu.clearAndDrawUnitQuad(gl);
    505    wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
    506    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    507 }
    508 
    509 function runArrayOfStructsDrawTest() {
    510    debug("");
    511    debug("Testing drawing with array of structs inside uniform block. A struct in the block is passed to a function.");
    512 
    513    var program = wtu.setupProgram(gl, ['vshader', 'fshaderarrayofstructs'], undefined, undefined, true);
    514    if (!program) {
    515        testFailed("Could not compile shader with an array of structs in an interface block without error");
    516        return;
    517    }
    518 
    519    var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
    520    var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
    521    var uniformIndices = gl.getUniformIndices(program, ["UBOColors[0].red", "UBOColors[0].green", "UBOColors[0].blue"]);
    522    var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
    523    var uniformIndices_2 = gl.getUniformIndices(program, ["UBOColors[1].red", "UBOColors[1].green", "UBOColors[1].blue"]);
    524    var uniformOffsets_2 = gl.getActiveUniforms(program, uniformIndices_2, gl.UNIFORM_OFFSET);
    525    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
    526 
    527    if (uniformOffsets.length < 3) {
    528        testFailed("Could not query uniform offsets");
    529        return;
    530    }
    531 
    532    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
    533    {
    534        return;
    535    }
    536    if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_2, uniformOffsets_2[0]))
    537    {
    538        return;
    539    }
    540 
    541    var uboArray = new ArrayBuffer(blockSize);
    542    var uboFloatView = new Float32Array(uboArray);
    543    setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.5, 0.0);
    544    var uboFloatView2 = new Float32Array(uboArray, uniformOffsets_2[0]);
    545    setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.5, 0.0);
    546 
    547    b1 = gl.createBuffer();
    548    gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
    549    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    550    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
    551 
    552    var binding = 3;
    553    gl.uniformBlockBinding(program, blockIndex, binding);
    554    gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
    555    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
    556 
    557    wtu.clearAndDrawUnitQuad(gl);
    558    wtu.checkCanvas(gl, [0, 255, 0, 255], "draw call should set canvas to green", 2);
    559 
    560    debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
    561    setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
    562    setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
    563    gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
    564 
    565    wtu.clearAndDrawUnitQuad(gl);
    566    wtu.checkCanvas(gl, [255, 0, 255, 255], "draw call should set canvas to purple", 2);
    567    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
    568 }
    569 
    570 debug("");
    571 var successfullyParsed = true;
    572 </script>
    573 <script src="../../js/js-test-post.js"></script>
    574 
    575 </body>
    576 </html>