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