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.
10 <meta charset=
"utf-8">
11 <title>WebGL OES_element_index_uint 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>
16 <script id=
"vs" type=
"x-shader/x-vertex">
17 attribute vec4 vPosition;
18 attribute vec4 vColor;
21 gl_Position = vPosition;
25 <script id=
"fs" type=
"x-shader/x-fragment">
26 precision mediump float;
35 <div id=
"description"></div>
36 <div id=
"console"></div>
39 description("This test verifies the functionality of the OES_element_index_uint extension, if it is available.");
43 var wtu
= WebGLTestUtils
;
48 // Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test
49 // for a bug in ANGLE which has since been fixed.
50 for (var ii
= 0; ii
< 2; ++ii
) {
51 canvas
= document
.createElement("canvas");
55 gl
= wtu
.create3DContext(canvas
);
58 testFailed("WebGL context does not exist");
60 testPassed("WebGL context exists");
62 var drawType
= (ii
== 0) ? gl
.STATIC_DRAW
: gl
.DYNAMIC_DRAW
;
63 debug("Testing " + ((ii
== 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW"));
66 // Query the extension and store globally so shouldBe can access it
67 ext
= gl
.getExtension("OES_element_index_uint");
69 testPassed("No OES_element_index_uint support -- this is legal");
71 runSupportedTest(false);
73 testPassed("Successfully enabled OES_element_index_uint extension");
75 runSupportedTest(true);
77 runDrawTests(drawType
);
79 // These tests are tweaked duplicates of the buffers/index-validation* tests
80 // using unsigned int indices to ensure that behavior remains consistent
81 runIndexValidationTests(drawType
);
82 runCopiesIndicesTests(drawType
);
83 runResizedBufferTests(drawType
);
84 runVerifiesTooManyIndicesTests(drawType
);
85 runCrashWithBufferSubDataTests(drawType
);
87 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
92 function runSupportedTest(extensionEnabled
) {
93 var supported
= gl
.getSupportedExtensions();
94 if (supported
.indexOf("OES_element_index_uint") >= 0) {
95 if (extensionEnabled
) {
96 testPassed("OES_element_index_uint listed as supported and getExtension succeeded");
98 testFailed("OES_element_index_uint listed as supported but getExtension failed");
101 if (extensionEnabled
) {
102 testFailed("OES_element_index_uint not listed as supported but getExtension succeeded");
104 testPassed("OES_element_index_uint not listed as supported and getExtension failed -- this is legal");
109 function runDrawTests(drawType
) {
110 debug("Test that draws with unsigned integer indices produce the expected results");
112 canvas
.width
= 50; canvas
.height
= 50;
113 gl
.viewport(0, 0, canvas
.width
, canvas
.height
);
115 var program
= wtu
.setupSimpleColorProgram(gl
);
117 function setupDraw(s
) {
118 // Create a vertex buffer that cannot be fully indexed via shorts
119 var quadArrayLen
= 65537 * 3;
120 var quadArray
= new Float32Array(quadArrayLen
);
122 // Leave all but the last 4 values zero-ed out
123 var idx
= quadArrayLen
- 12;
125 // Initialized the last 4 values to a quad
126 quadArray
[idx
++] = 1.0 * s
;
127 quadArray
[idx
++] = 1.0 * s
;
128 quadArray
[idx
++] = 0.0;
130 quadArray
[idx
++] = -1.0 * s
;
131 quadArray
[idx
++] = 1.0 * s
;
132 quadArray
[idx
++] = 0.0;
134 quadArray
[idx
++] = -1.0 * s
;
135 quadArray
[idx
++] = -1.0 * s
;
136 quadArray
[idx
++] = 0.0;
138 quadArray
[idx
++] = 1.0 * s
;
139 quadArray
[idx
++] = -1.0 * s
;
140 quadArray
[idx
++] = 0.0;
142 var vertexObject
= gl
.createBuffer();
143 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
144 gl
.bufferData(gl
.ARRAY_BUFFER
, quadArray
, drawType
);
146 // Create an unsigned int index buffer that indexes the last 4 vertices
147 var baseIndex
= (quadArrayLen
/ 3) - 4;
149 var indexObject
= gl
.createBuffer();
150 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
151 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, new Uint32Array([
157 baseIndex
+ 0]), drawType
);
159 var opt_positionLocation
= 0;
160 gl
.enableVertexAttribArray(opt_positionLocation
);
161 gl
.vertexAttribPointer(opt_positionLocation
, 3, gl
.FLOAT
, false, 0, 0);
163 function testPixel(blockList
, allowList
) {
164 function testList(list
, expected
) {
165 for (var n
= 0; n
< list
.length
; n
++) {
167 var x
= -Math
.floor(l
* canvas
.width
/ 2) + canvas
.width
/ 2;
168 var y
= -Math
.floor(l
* canvas
.height
/ 2) + canvas
.height
/ 2;
169 wtu
.checkCanvasRect(gl
, x
, y
, 1, 1, [expected
, expected
, expected
],
170 "Draw should pass", 2);
173 testList(blockList
, 0);
174 testList(allowList
, 255);
176 function verifyDraw(s
) {
177 gl
.clearColor(1.0, 1.0, 1.0, 1.0);
178 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
179 wtu
.setFloatDrawColor(gl
, [0.0, 0.0, 0.0, 1.0]);
180 gl
.drawElements(gl
.TRIANGLES
, 6, gl
.UNSIGNED_INT
, 0);
184 var points
= [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
185 for (var n
= 0; n
< points
.length
; n
++) {
186 if (points
[n
] <= s
) {
187 blockList
.push(points
[n
]);
189 allowList
.push(points
[n
]);
192 testPixel(blockList
, allowList
);
199 function runIndexValidationTests(drawType
) {
200 description("Tests that index validation verifies the correct number of indices");
202 function sizeInBytes(type
) {
205 case gl
.UNSIGNED_BYTE
:
208 case gl
.UNSIGNED_SHORT
:
211 case gl
.UNSIGNED_INT
:
215 throw "unknown type";
219 var program
= wtu
.loadStandardProgram(gl
);
221 // 3 vertices => 1 triangle, interleaved data
222 var dataComplete
= new Float32Array([0, 0, 0, 1,
228 var dataIncomplete
= new Float32Array([0, 0, 0, 1,
233 var indices
= new Uint32Array([0, 1, 2]);
235 debug("Testing with valid indices");
237 var bufferComplete
= gl
.createBuffer();
238 gl
.bindBuffer(gl
.ARRAY_BUFFER
, bufferComplete
);
239 gl
.bufferData(gl
.ARRAY_BUFFER
, dataComplete
, drawType
);
240 var elements
= gl
.createBuffer();
241 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, elements
);
242 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, drawType
);
243 gl
.useProgram(program
);
244 var vertexLoc
= gl
.getAttribLocation(program
, "a_vertex");
245 var normalLoc
= gl
.getAttribLocation(program
, "a_normal");
246 gl
.vertexAttribPointer(vertexLoc
, 4, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 0);
247 gl
.enableVertexAttribArray(vertexLoc
);
248 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
249 gl
.enableVertexAttribArray(normalLoc
);
250 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
251 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
252 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
253 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
255 debug("Testing with out-of-range indices");
257 var bufferIncomplete
= gl
.createBuffer();
258 gl
.bindBuffer(gl
.ARRAY_BUFFER
, bufferIncomplete
);
259 gl
.bufferData(gl
.ARRAY_BUFFER
, dataIncomplete
, drawType
);
260 gl
.vertexAttribPointer(vertexLoc
, 4, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 0);
261 gl
.enableVertexAttribArray(vertexLoc
);
262 gl
.disableVertexAttribArray(normalLoc
);
263 debug("Enable vertices, valid");
264 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
265 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
266 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
267 debug("Enable normals, out-of-range");
268 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
269 gl
.enableVertexAttribArray(normalLoc
);
270 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
271 wtu
.shouldGenerateGLError(gl
, [gl
.INVALID_OPERATION
, gl
.NO_ERROR
],
272 'gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
274 debug("Test with enabled attribute that does not belong to current program");
276 gl
.disableVertexAttribArray(normalLoc
);
277 var extraLoc
= Math
.max(vertexLoc
, normalLoc
) + 1;
278 gl
.enableVertexAttribArray(extraLoc
);
279 debug("Enable an extra attribute with null");
280 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
281 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
282 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
283 debug("Enable an extra attribute with insufficient data buffer");
284 gl
.vertexAttribPointer(extraLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
285 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
286 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
287 debug("Pass large negative index to vertexAttribPointer");
288 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), -2000000000 * sizeInBytes(gl
.FLOAT
));
289 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
290 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
293 function runCopiesIndicesTests(drawType
) {
294 debug("Test that client data is always copied during bufferData and bufferSubData calls");
296 var program
= wtu
.loadStandardProgram(gl
);
298 gl
.useProgram(program
);
299 var vertexObject
= gl
.createBuffer();
300 gl
.enableVertexAttribArray(0);
301 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
302 // 4 vertices -> 2 triangles
303 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType
);
304 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
306 var indexObject
= gl
.createBuffer();
308 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
309 var indices
= new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]);
310 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, drawType
);
311 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
312 var indexValidationError
= wtu
.shouldGenerateGLError(gl
, [gl
.INVALID_OPERATION
, gl
.NO_ERROR
],
313 "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
314 wtu
.shouldGenerateGLError(gl
, indexValidationError
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
317 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
318 wtu
.shouldGenerateGLError(gl
, indexValidationError
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
319 wtu
.shouldGenerateGLError(gl
, indexValidationError
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
322 function runResizedBufferTests(drawType
) {
323 debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation.");
325 var program
= wtu
.setupProgram(gl
, ["vs", "fs"], ["vPosition", "vColor"]);
326 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after initialization");
328 var vertexObject
= gl
.createBuffer();
329 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
330 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array(
331 [-1,1,0, 1,1,0, -1,-1,0,
332 -1,-1,0, 1,1,0, 1,-1,0]), drawType
);
333 gl
.enableVertexAttribArray(0);
334 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
335 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after vertex setup");
337 var texCoordObject
= gl
.createBuffer();
338 gl
.bindBuffer(gl
.ARRAY_BUFFER
, texCoordObject
);
339 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array(
341 0,1, 1,0, 1,1]), drawType
);
342 gl
.enableVertexAttribArray(1);
343 gl
.vertexAttribPointer(1, 2, gl
.FLOAT
, false, 0, 0);
344 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after texture coord setup");
346 // Now resize these buffers because we want to change what we're drawing.
347 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
348 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([
349 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0,
350 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), drawType
);
351 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after vertex redefinition");
352 gl
.bindBuffer(gl
.ARRAY_BUFFER
, texCoordObject
);
353 gl
.bufferData(gl
.ARRAY_BUFFER
, new Uint8Array([
361 0, 255, 0, 255]), drawType
);
362 gl
.vertexAttribPointer(1, 4, gl
.UNSIGNED_BYTE
, false, 0, 0);
363 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after texture coordinate / color redefinition");
366 var indices
= new Uint32Array(numQuads
* 6);
367 for (var ii
= 0; ii
< numQuads
; ++ii
) {
369 var quad
= (ii
== (numQuads
- 1)) ? 4 : 0;
370 indices
[offset
+ 0] = quad
+ 0;
371 indices
[offset
+ 1] = quad
+ 1;
372 indices
[offset
+ 2] = quad
+ 2;
373 indices
[offset
+ 3] = quad
+ 2;
374 indices
[offset
+ 4] = quad
+ 1;
375 indices
[offset
+ 5] = quad
+ 3;
377 var indexObject
= gl
.createBuffer();
378 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
379 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, drawType
);
380 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after setting up indices");
381 gl
.drawElements(gl
.TRIANGLES
, numQuads
* 6, gl
.UNSIGNED_INT
, 0);
382 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "after drawing");
385 function runVerifiesTooManyIndicesTests(drawType
) {
386 description("Tests that index validation for drawElements does not examine too many indices");
388 var program
= wtu
.loadStandardProgram(gl
);
390 gl
.useProgram(program
);
391 var vertexObject
= gl
.createBuffer();
392 gl
.enableVertexAttribArray(0);
393 gl
.disableVertexAttribArray(1);
394 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
395 // 4 vertices -> 2 triangles
396 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType
);
397 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
399 var indexObject
= gl
.createBuffer();
401 debug("Test out of range indices")
402 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
403 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]), drawType
);
404 wtu
.shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
405 var indexValidationError
= wtu
.shouldGenerateGLError(gl
, [gl
.INVALID_OPERATION
, gl
.NO_ERROR
],
406 "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
407 wtu
.shouldGenerateGLError(gl
, indexValidationError
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
410 function runCrashWithBufferSubDataTests(drawType
) {
411 debug('Verifies that the index validation code which is within bufferSubData does not crash.')
413 var elementBuffer
= gl
.createBuffer();
414 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, elementBuffer
);
415 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, 256, drawType
);
416 var data
= new Uint32Array(127);
417 gl
.bufferSubData(gl
.ELEMENT_ARRAY_BUFFER
, 64, data
);
418 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "after attempting to update a buffer outside of the allocated bounds");
419 testPassed("bufferSubData, when buffer object was initialized with null, did not crash");
423 var successfullyParsed
= true;
425 <script src=
"../../js/js-test-post.js"></script>