summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/uniform-buffers.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/buffers/uniform-buffers.html576
1 files changed, 576 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/uniform-buffers.html b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/uniform-buffers.html
new file mode 100644
index 0000000000..a6bd1b4bc9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/buffers/uniform-buffers.html
@@ -0,0 +1,576 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Uniform Buffers Conformance Tests</title>
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../js/js-test-pre.js"></script>
+<script src="../../js/webgl-test-utils.js"></script>
+<script id='vshader' type='x-shader/x-vertex'>#version 300 es
+layout(location=0) in vec3 p;
+void main()
+{
+ gl_Position = vec4(p.xyz, 1.0);
+}
+</script>
+<script id='fbadshader' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+uniform UBOData {
+ float UBORed;
+ float UBOGreen;
+ float UBOBlue;
+};
+
+uniform Color {
+ float Red;
+ float UBOGreen;
+ float Blue;
+};
+
+void main()
+{
+ oColor = vec4(UBORed * Red, UBOGreen * UBOGreen, UBOBlue * Blue, 1.0);
+}
+</script>
+<script id='fshader' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+uniform UBOData {
+ float UBORed;
+ float UBOGreen;
+ float UBOBlue;
+};
+
+uniform UBOD {
+ float UBOR;
+ float UBOG;
+ float UBOB;
+};
+
+void main()
+{
+ oColor = vec4(UBORed * UBOR, UBOGreen * UBOG, UBOBlue * UBOB, 1.0);
+}
+</script>
+<script id='fshadernamed' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+uniform UBOData {
+ float Red;
+ float Green;
+ float Blue;
+} UBOA;
+
+void main()
+{
+ oColor = vec4(UBOA.Red, UBOA.Green, UBOA.Blue, 1.0);
+}
+</script>
+<script id='fshadernamedarray' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+uniform UBOData {
+ float Red;
+ float Green;
+ float Blue;
+} UBOA[2];
+
+void main()
+{
+ oColor = vec4((UBOA[0].Red + UBOA[1].Red) / 2.0,
+ (UBOA[0].Green + UBOA[1].Green) / 2.0,
+ (UBOA[0].Blue + UBOA[1].Blue) / 2.0, 1.0);
+}
+</script>
+<script id='fshadernestedstruct' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+struct color_t {
+ float red;
+ float green;
+ float blue;
+};
+
+struct wrapper_t {
+ color_t color;
+};
+
+uniform UBOData {
+ wrapper_t UBOStruct;
+};
+
+// This is intended to reproduce a specific ANGLE bug that triggers when the wrapper struct is passed to a function.
+// https://bugs.chromium.org/p/angleproject/issues/detail?id=2084
+void processColor(wrapper_t wrapper) {
+ oColor = vec4(wrapper.color.red, wrapper.color.green, wrapper.color.blue, 1.0);
+}
+
+void main()
+{
+ processColor(UBOStruct);
+}
+</script>
+<script id='fshaderarrayofstructs' type='x-shader/x-fragment'>#version 300 es
+precision mediump float;
+layout(location=0) out vec4 oColor;
+
+struct color_t {
+ float red;
+ float green;
+ float blue;
+};
+
+uniform UBOData {
+ color_t UBOColors[2];
+};
+
+// 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.
+// https://bugs.chromium.org/p/angleproject/issues/detail?id=2084
+vec3 processColor(color_t color) {
+ return vec3(color.red, color.green, color.blue);
+}
+
+void main()
+{
+ oColor = vec4(processColor(UBOColors[0]) + processColor(UBOColors[1]), 1.0);
+}
+</script>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the Uniform Buffer objects");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+var b1 = null;
+var b2 = null;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ wtu.setupUnitQuad(gl);
+
+ runBindingTest();
+ runBadShaderTest();
+ runUniformBufferOffsetAlignmentTest();
+ runDrawTest();
+ runNamedDrawTest();
+ runNamedArrayDrawTest();
+ runNestedStructsDrawTest();
+ runArrayOfStructsDrawTest();
+}
+
+function runBindingTest() {
+ debug("");
+ debug("Testing uniform buffer binding behavior");
+ shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "UNIFORM_BUFFER_BINDING query should succeed");
+
+ debug("Testing basic uniform buffer binding and unbinding");
+ b1 = gl.createBuffer();
+ b2 = gl.createBuffer();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createBuffer should not set an error");
+ shouldBeNonNull("b1");
+ shouldBeNonNull("b2");
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to bind uniform buffer");
+ shouldBe("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)", "b1");
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to update uniform buffer binding");
+ shouldBe("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)", "b2");
+ gl.bindBuffer(gl.UNIFORM_BUFFER, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to unbind uniform buffer");
+
+ debug("Testing deleting uniform buffers");
+ gl.deleteBuffer(b1);
+ gl.deleteBuffer(b2);
+ shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
+
+ // Shouldn't be able to bind a deleted buffer.
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "binding a deleted buffer should generate INVALID_OPERATION");
+ shouldBeNull("gl.getParameter(gl.UNIFORM_BUFFER_BINDING)");
+}
+
+function runBadShaderTest() {
+ debug("");
+ var testProgram = wtu.setupProgram(gl, ['vshader', 'fbadshader']);
+ if (testProgram) {
+ testFailed("To define the same uniform in two uniform blocks should fail");
+ } else {
+ testPassed("To define the same uniform in two uniform blocks should fail");
+ }
+}
+
+function runUniformBufferOffsetAlignmentTest() {
+ debug("");
+ var offsetAlignment = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
+
+ if (offsetAlignment % 4 != 0) {
+ testFailed("Unexpected UNIFORM_BUFFER_OFFSET_ALIGNMENT - should be aligned on a 4-byte boundary");
+ } else {
+ testPassed("UNIFORM_BUFFER_OFFSET_ALIGNMENT is divisible by four");
+ }
+}
+
+function setRGBValuesToFloat32Array(floatView, red, green, blue) {
+ floatView[0] = red;
+ floatView[1] = green;
+ floatView[2] = blue;
+}
+
+function checkFloat32UniformOffsetsInStd140Layout(uniformOffsets, expectedInitialOffset) {
+ if (expectedInitialOffset === undefined)
+ {
+ expectedInitialOffset = 0;
+ }
+ // Verify that the uniform offsets are set according to the std140 layout, which WebGL enforces.
+ // This function checks this for 32-bit float values, which are expected to be tightly packed.
+ for (var i = 0; i < uniformOffsets.length; ++i)
+ {
+ if (uniformOffsets[i] != expectedInitialOffset + i * Float32Array.BYTES_PER_ELEMENT)
+ {
+ testFailed("Uniform offsets are not according to std140 layout");
+ return false;
+ }
+ }
+ return true;
+}
+
+function runDrawTest() {
+ debug("");
+ debug("Testing drawing with uniform buffers");
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshader']);
+ if (!program) {
+ testFailed("Could not compile shader with uniform blocks without error");
+ return;
+ }
+
+ var blockIndex_1 = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize_1 = gl.getActiveUniformBlockParameter(program, blockIndex_1, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices_1 = gl.getUniformIndices(program, ["UBORed", "UBOGreen", "UBOBlue"]);
+ var uniformOffsets_1 = gl.getActiveUniforms(program, uniformIndices_1, gl.UNIFORM_OFFSET);
+ var blockIndex_2 = gl.getUniformBlockIndex(program, "UBOD");
+ var blockSize_2 = gl.getActiveUniformBlockParameter(program, blockIndex_2, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices_2 = gl.getUniformIndices(program, ["UBOR", "UBOG", "UBOB"]);
+ var uniformOffsets_2 = gl.getActiveUniforms(program, uniformIndices_2, gl.UNIFORM_OFFSET);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
+
+ if (uniformOffsets_1.length < 3 || uniformOffsets_2.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_1) || !checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_2))
+ {
+ return;
+ }
+
+ var uboArray_1 = new ArrayBuffer(blockSize_1);
+ var uboFloatView_1 = new Float32Array(uboArray_1);
+ setRGBValuesToFloat32Array(uboFloatView_1, 1.0, 0.0, 0.0); // UBORed, UBOGreen, UBOBlue
+ var uboArray_2 = new ArrayBuffer(blockSize_2);
+ var uboFloatView_2 = new Float32Array(uboArray_2);
+ setRGBValuesToFloat32Array(uboFloatView_2, 1.0, 1.0, 1.0); // UBOR, UBOG, UBOB
+
+ var b_1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b_1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_1, gl.DYNAMIC_DRAW);
+ var b_2 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b_2);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_2, gl.DYNAMIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
+
+ var bindings = [1, 2];
+ gl.uniformBlockBinding(program, blockIndex_1, bindings[0]);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, bindings[0], b_1);
+ gl.uniformBlockBinding(program, blockIndex_2, bindings[1]);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, bindings[1], b_2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+
+ debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
+ setRGBValuesToFloat32Array(uboFloatView_1, 0.0, 0.0, 1.0); // UBORed, UBOGreen, UBOBlue
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b_1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboFloatView_1, gl.DYNAMIC_DRAW);
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runNamedDrawTest() {
+ debug("");
+ debug("Testing drawing with named uniform buffers");
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshadernamed']);
+ if (!program) {
+ testFailed("Could not compile shader with named uniform blocks without error");
+ return;
+ }
+
+ var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices = gl.getUniformIndices(program, ["UBOData.Red", "UBOData.Green", "UBOData.Blue"]);
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
+
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
+ {
+ return;
+ }
+
+ var uboArray = new ArrayBuffer(blockSize);
+ var uboFloatView = new Float32Array(uboArray);
+ setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
+
+ b1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
+
+ var binding = 3;
+ gl.uniformBlockBinding(program, blockIndex, binding);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "draw call should set canvas to red", 2);
+
+ debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
+ setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.0, 1.0);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runNamedArrayDrawTest() {
+ debug("");
+ debug("Testing drawing with named uniform buffer arrays");
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshadernamedarray']);
+ if (!program) {
+ testFailed("could not compile shader with named uniform block arrays without error");
+ return;
+ }
+
+ var blockIndex = [gl.getUniformBlockIndex(program, "UBOData[0]"),
+ gl.getUniformBlockIndex(program, "UBOData[1]")];
+ if (blockIndex[0] == gl.INVALID_INDEX ||
+ blockIndex[1] == gl.INVALID_INDEX) {
+ testFailed("Could not query uniform block index");
+ return;
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block indices without error");
+ var blockSize = [gl.getActiveUniformBlockParameter(program, blockIndex[0], gl.UNIFORM_BLOCK_DATA_SIZE),
+ gl.getActiveUniformBlockParameter(program, blockIndex[1], gl.UNIFORM_BLOCK_DATA_SIZE)];
+ if (blockSize[0] != blockSize[1]) {
+ testFailed("uniform block instance array with different block sizes");
+ }
+ var uniformIndices = gl.getUniformIndices(program, ["UBOData.Red", "UBOData.Green", "UBOData.Blue"]);
+ if (uniformIndices < 3 ||
+ uniformIndices[0] == gl.INVALID_INDEX ||
+ uniformIndices[1] == gl.INVALID_INDEX ||
+ uniformIndices[2] == gl.INVALID_INDEX) {
+ testFailed("Could not query uniform indices");
+ return;
+ }
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
+ {
+ return;
+ }
+
+ var offsetAlignment = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
+ var offset = Math.ceil(blockSize[0] / offsetAlignment) * offsetAlignment;
+
+ var bufferSize = offset + blockSize[1];
+ var uboArray = new ArrayBuffer(bufferSize);
+ var uboFloatView = new Float32Array(uboArray);
+ setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
+ var uboFloatView2 = new Float32Array(uboArray, offset);
+ setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
+
+ b1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
+
+ var bindings = [4, 5];
+ gl.uniformBlockBinding(program, blockIndex[0], bindings[0]);
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, bindings[0], b1, 0, blockSize[0]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferRange without errors");
+ gl.uniformBlockBinding(program, blockIndex[1], bindings[1]);
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, bindings[1], b1, offset, blockSize[1]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferRange without errors");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [127, 0, 127, 255], "draw call should set canvas to (0.5, 0, 0.5)", 2);
+
+ debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
+ setRGBValuesToFloat32Array(uboFloatView, 0.0, 1.0, 1.0);
+ setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 127, 255, 255], "draw call should set canvas to (0, 0.5, 1)", 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runNestedStructsDrawTest() {
+ debug("");
+ debug("Testing drawing with nested struct inside uniform block. The wrapper struct is passed to a function.");
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshadernestedstruct'], undefined, undefined, true);
+ if (!program) {
+ testFailed("Could not compile shader with nested structs without error");
+ return;
+ }
+
+ var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices = gl.getUniformIndices(program, ["UBOStruct.color.red", "UBOStruct.color.green", "UBOStruct.color.blue"]);
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
+
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
+ {
+ return;
+ }
+
+ var uboArray = new ArrayBuffer(blockSize);
+ var uboFloatView = new Float32Array(uboArray);
+ setRGBValuesToFloat32Array(uboFloatView, 0.0, 1.0, 0.0);
+
+ b1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
+
+ var binding = 3;
+ gl.uniformBlockBinding(program, blockIndex, binding);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "draw call should set canvas to green", 2);
+
+ debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
+ setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.0, 1.0);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 0, 255, 255], "draw call should set canvas to blue", 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runArrayOfStructsDrawTest() {
+ debug("");
+ debug("Testing drawing with array of structs inside uniform block. A struct in the block is passed to a function.");
+
+ var program = wtu.setupProgram(gl, ['vshader', 'fshaderarrayofstructs'], undefined, undefined, true);
+ if (!program) {
+ testFailed("Could not compile shader with an array of structs in an interface block without error");
+ return;
+ }
+
+ var blockIndex = gl.getUniformBlockIndex(program, "UBOData");
+ var blockSize = gl.getActiveUniformBlockParameter(program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE);
+ var uniformIndices = gl.getUniformIndices(program, ["UBOColors[0].red", "UBOColors[0].green", "UBOColors[0].blue"]);
+ var uniformOffsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ var uniformIndices_2 = gl.getUniformIndices(program, ["UBOColors[1].red", "UBOColors[1].green", "UBOColors[1].blue"]);
+ var uniformOffsets_2 = gl.getActiveUniforms(program, uniformIndices_2, gl.UNIFORM_OFFSET);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to query uniform block information without error");
+
+ if (uniformOffsets.length < 3) {
+ testFailed("Could not query uniform offsets");
+ return;
+ }
+
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets))
+ {
+ return;
+ }
+ if (!checkFloat32UniformOffsetsInStd140Layout(uniformOffsets_2, uniformOffsets_2[0]))
+ {
+ return;
+ }
+
+ var uboArray = new ArrayBuffer(blockSize);
+ var uboFloatView = new Float32Array(uboArray);
+ setRGBValuesToFloat32Array(uboFloatView, 0.0, 0.5, 0.0);
+ var uboFloatView2 = new Float32Array(uboArray, uniformOffsets_2[0]);
+ setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.5, 0.0);
+
+ b1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, b1);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to set UBO data with no errors");
+
+ var binding = 3;
+ gl.uniformBlockBinding(program, blockIndex, binding);
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, b1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be able to call bindBufferBase without errors");
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "draw call should set canvas to green", 2);
+
+ debug("Changing the data in the uniform buffer should automatically update the uniforms exposed to the draw call");
+ setRGBValuesToFloat32Array(uboFloatView, 1.0, 0.0, 0.0);
+ setRGBValuesToFloat32Array(uboFloatView2, 0.0, 0.0, 1.0);
+ gl.bufferData(gl.UNIFORM_BUFFER, uboArray, gl.DYNAMIC_DRAW);
+
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.checkCanvas(gl, [255, 0, 255, 255], "draw call should set canvas to purple", 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src="../../js/js-test-post.js"></script>
+
+</body>
+</html>