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>