Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance / extensions / angle-instanced-arrays.html
blobf96c732bb23d4da5750d816f27019eca2f9d9686
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 -->
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);
33 </script>
35 <script id="outputFragmentShader" type="x-shader/x-fragment">
36 precision mediump float;
37 varying vec4 vColor;
38 void main() {
39 gl_FragColor = vColor;
41 </script>
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);
50 </script>
52 <script id="drawArraysTestFragmentShader" type="x-shader/x-fragment">
53 void main() {
54 gl_FragColor = vec4(1.0, 0, 0, 1.0);
56 </script>
58 <script>
59 "use strict";
60 description("This test verifies the functionality of the ANGLE_instanced_arrays extension, if it is available.");
62 debug("");
64 const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
66 var wtu = WebGLTestUtils;
67 var canvas = document.getElementById("canvas");
68 var gl = wtu.create3DContext(canvas);
69 var ext = null;
70 var vaoext = null;
72 var positionLoc = 0;
73 var offsetLoc = 2;
74 var colorLoc = 3;
75 var program;
77 if (!gl) {
78 testFailed("WebGL context does not exist");
79 finishTest();
80 } else {
81 testPassed("WebGL context exists");
83 runDivisorTestDisabled();
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");
90 runSupportedTest(false);
91 finishTest();
92 } else {
93 testPassed("Successfully enabled ANGLE_instanced_arrays extension");
95 (async function() {
96 runSupportedTest(true);
98 runDivisorTestEnabled();
99 runUniqueObjectTest();
101 setupCanvas();
102 runOutputTests();
103 runDrawArraysWithOffsetTest();
104 runVAOInstancingInteractionTest();
105 await runANGLECorruptionTest();
106 await runInvalidAttribTests(gl);
107 await runCompositingTests();
108 finishTest();
109 }());
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");
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");
130 function runDivisorTestDisabled() {
131 debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension disabled");
133 var VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
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");
139 function runDivisorTestEnabled() {
140 debug("Testing VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE with extension enabled");
142 shouldBe("ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "0x88FE");
144 var max_vertex_attribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
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");
151 else{
152 testFailed("Default divisor of vertex attribute " + i + " should be: 0, returned value was: " + queried_value);
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");
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");
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");
166 else{
167 testFailed("Set value of VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE should be: 2, returned value was: " + queried_value);
170 // Reset vertex attrib divisors so they cannot affect following subtests.
171 ext.vertexAttribDivisorANGLE(max_vertex_attribs-1, 0);
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);
179 program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"], ['aPosition', 'aOffset', 'aColor'], [positionLoc, offsetLoc, colorLoc]);
180 ext = gl.getExtension("ANGLE_instanced_arrays");
183 function runOutputTests() {
184 var instanceCount = 4;
186 debug("Testing various draws for valid built-in function behavior");
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,
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);
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
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);
217 wtu.setupUnitQuad(gl, 0);
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]);
227 // Draw 2: Draw Non-indexed instances
228 debug("");
229 debug("Testing drawArraysInstancedANGLE");
230 gl.clear(gl.COLOR_BUFFER_BIT);
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]);
239 ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, -1);
240 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a primcount less than 0");
242 ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, -1, instanceCount);
243 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "drawArraysInstancedANGLE cannot have a count less than 0");
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);
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");
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");
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
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
279 gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
280 gl.bufferData(gl.ARRAY_BUFFER, offsetsHalf, gl.STATIC_DRAW);
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]);
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);
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);
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);
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]);
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");
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");
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);
343 ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, instanceCount);
344 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstancedANGLE with UNSIGNED_BYTE should succeed");
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");
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");
362 // Reset vertex attrib divisors so they cannot affect following subtests.
363 ext.vertexAttribDivisorANGLE(colorLoc, 0);
364 ext.vertexAttribDivisorANGLE(offsetLoc, 0);
367 function runDrawArraysTest(program, first, count, instanceCount, offset)
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");
374 // Load the vertex positions
375 var positions = new Float32Array([
376 -1, -1,
377 -1, 0,
378 0, 0,
380 0, 0,
381 0, -1,
382 -1, -1,
384 1, -1,
385 1, 0,
386 0, 0,
388 0, 0,
389 0, -1,
390 1, -1,
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);
398 // Load the instance positions
399 var instancePositions = new Float32Array([
400 0, 0,
401 1, 0
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);
409 // Enable instancing
410 ext.vertexAttribDivisorANGLE(instancePosLoc, 1);
412 // Offset
413 gl.uniform3fv(uniformLoc, offset);
415 // Do the instanced draw
416 ext.drawArraysInstancedANGLE(gl.TRIANGLES, first, count, instanceCount);
417 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstancedANGLE should succeed");
419 // Reset vertex attrib divisors so they cannot affect following subtests.
420 ext.vertexAttribDivisorANGLE(instancePosLoc, 0);
423 function runDrawArraysWithOffsetTest()
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
429 var drawArraysProgram = wtu.setupProgram(gl, ["drawArraysTestVertexShader", "drawArraysTestFragmentShader"]);
431 gl.clear(gl.COLOR_BUFFER_BIT);
433 runDrawArraysTest(drawArraysProgram, 0, 6, 2, [0, 0, 0]);
435 runDrawArraysTest(drawArraysProgram, 6, 6, 2, [-1, 1, 0]);
437 wtu.checkCanvasRect(gl, 0, 0, canvas.width, canvas.height, [255, 0, 0, 255]);
440 function runUniqueObjectTest()
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');
450 function runVAOInstancingInteractionTest()
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
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;
463 testPassed("Successfully enabled OES_vertex_array_object extension");
465 gl.useProgram(program);
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,
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
482 var positionBuffer = gl.createBuffer();
483 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
484 gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
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,
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,
501 var colorBuffer = gl.createBuffer();
502 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
503 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
505 // Reset the divisor of the default VAO to 0
506 ext.vertexAttribDivisorANGLE(colorLoc, 0);
508 // Set up VAO with an attrib divisor
509 var vao1 = vaoext.createVertexArrayOES();
510 vaoext.bindVertexArrayOES(vao1);
512 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
513 gl.enableVertexAttribArray(positionLoc);
514 gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
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);
521 gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
523 vaoext.bindVertexArrayOES(null);
525 // Set up VAO with no attrib divisor
526 var vao2 = vaoext.createVertexArrayOES();
527 vaoext.bindVertexArrayOES(vao2);
529 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
530 gl.enableVertexAttribArray(positionLoc);
531 gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
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
538 gl.vertexAttrib2fv(offsetLoc, [0.0, 0.0]);
540 vaoext.bindVertexArrayOES(null);
542 debug("");
543 debug("Ensure that Vertex Array Objects retain attrib divisors");
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");
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)
560 vaoext.bindVertexArrayOES(null);
563 async function runANGLECorruptionTest()
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
569 setupCanvas();
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
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,
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);
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,
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);
614 gl.clear(gl.COLOR_BUFFER_BIT);
615 wtu.setupUnitQuad(gl, 0);
617 const totalIterations = 10;
618 for (let iteration = 0; iteration < totalIterations; ++iteration)
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);
626 nullData = new Float32Array(colors.length);
627 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
628 gl.bufferSubData(gl.ARRAY_BUFFER, colors.byteLength, nullData);
630 ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, instanceCount);
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]
640 wtu.checkCanvasRectColor(
641 gl, x, 0, w, canvas.height, color, tolerance,
642 function() {},
643 function() {
644 passed = false;
645 }, debug);
648 if (passed) {
649 testPassed("Passed test " + iteration + " of " + totalIterations);
650 } else {
651 testFailed("Failed test " + iteration + " of " + totalIterations);
652 break;
654 await wait();
656 ext.vertexAttribDivisorANGLE(offsetLoc, 0);
657 ext.vertexAttribDivisorANGLE(colorLoc, 0);
660 async function runDrawTests(testFn) {
661 function drawArrays(gl) {
662 gl.drawArrays(gl.TRIANGLES, 0, 6);
665 function drawElements(gl) {
666 gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
669 function drawArraysInstancedANGLE(gl) {
670 const ext = gl.getExtension('ANGLE_instanced_arrays');
671 if (!ext) {
672 return true;
675 ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, 1);
678 function drawElementsInstancedANGLE(gl) {
679 const ext = gl.getExtension('ANGLE_instanced_arrays');
680 if (!ext) {
681 return true;
684 ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 1);
687 await testFn(drawArrays); // sanity check
688 await testFn(drawElements); // sanity check
690 await testFn(drawArraysInstancedANGLE);
691 await testFn(drawElementsInstancedANGLE);
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;
704 const fs = `\
705 precision mediump float;
706 void main() {
707 gl_FragColor = vec4(1, 0, 0, 1);
710 return [vs, fs];
713 await runDrawTests(compositingTestFn);
716 async function runInvalidAttribTests(gl) {
717 const invalidAttribTestFn = createInvalidAttribTestFn(gl);
718 await runDrawTests(invalidAttribTestFn);
721 </script>
722 </body>
723 </html>