5 <title>WebGL OES_element_index_uint Conformance Tests
</title>
6 <script src=
"resources/desktop-gl-constants.js" type=
"text/javascript"></script>
7 <script src=
"../../../resources/js-test.js"></script>
8 <script src=
"resources/webgl-test.js"></script>
9 <script src=
"resources/webgl-test-utils.js"></script>
12 <div id=
"description"></div>
13 <canvas id=
"canvas" style=
"width: 50px; height: 50px;"> </canvas>
14 <div id=
"console"></div>
15 <script id=
"vs" type=
"x-shader/x-vertex">
16 attribute vec4 vPosition;
17 attribute vec4 vColor;
20 gl_Position = vPosition;
24 <script id=
"fs" type=
"x-shader/x-fragment">
26 precision mediump float;
34 description("This test verifies the functionality of the OES_element_index_uint extension, if it is available.");
39 window
.internals
.settings
.setWebGLErrorsToConsoleEnabled(false);
41 var wtu
= WebGLTestUtils
;
42 var canvas
= document
.getElementById("canvas");
43 var gl
= create3DContext(canvas
);
48 testFailed("WebGL context does not exist");
50 testPassed("WebGL context exists");
52 // Query the extension and store globally so shouldBe can access it
53 ext
= gl
.getExtension("OES_element_index_uint");
55 testPassed("No OES_element_index_uint support -- this is legal");
57 runSupportedTest(false);
59 testPassed("Successfully enabled OES_element_index_uint extension");
61 runSupportedTest(true);
64 // These tests are tweaked duplicates of the buffers/index-validation* tests
65 // using unsigned int indices to ensure that behavior remains consistent
66 runIndexValidationTests();
67 runCopiesIndicesTests();
68 runResizedBufferTests();
69 runVerifiesTooManyIndicesTests();
70 runCrashWithBufferSubDataTests();
72 glErrorShouldBe(gl
, gl
.NO_ERROR
, "there should be no errors");
76 function runSupportedTest(extensionEnabled
) {
77 var supported
= gl
.getSupportedExtensions();
78 if (supported
.indexOf("OES_element_index_uint") >= 0) {
79 if (extensionEnabled
) {
80 testPassed("OES_element_index_uint listed as supported and getExtension succeeded");
82 testFailed("OES_element_index_uint listed as supported but getExtension failed");
85 if (extensionEnabled
) {
86 testFailed("OES_element_index_uint not listed as supported but getExtension succeeded");
88 testPassed("OES_element_index_uint not listed as supported and getExtension failed -- this is legal");
93 function runDrawTests() {
94 debug("Test that draws with unsigned integer indices produce the expected results");
96 canvas
.width
= 50; canvas
.height
= 50;
97 gl
.viewport(0, 0, canvas
.width
, canvas
.height
);
99 var program
= wtu
.setupSimpleTextureProgram(gl
);
101 function setupDraw(s
) {
102 // Create a vertex buffer that cannot be fully indexed via shorts
103 var quadArrayLen
= 65537 * 3;
104 var quadArray
= new Float32Array(quadArrayLen
);
106 // Leave all but the last 4 values zero-ed out
107 var idx
= quadArrayLen
- 12;
109 // Initialized the last 4 values to a quad
110 quadArray
[idx
++] = 1.0 * s
;
111 quadArray
[idx
++] = 1.0 * s
;
112 quadArray
[idx
++] = 0.0;
114 quadArray
[idx
++] = -1.0 * s
;
115 quadArray
[idx
++] = 1.0 * s
;
116 quadArray
[idx
++] = 0.0;
118 quadArray
[idx
++] = -1.0 * s
;
119 quadArray
[idx
++] = -1.0 * s
;
120 quadArray
[idx
++] = 0.0;
122 quadArray
[idx
++] = 1.0 * s
;
123 quadArray
[idx
++] = -1.0 * s
;
124 quadArray
[idx
++] = 0.0;
126 var vertexObject
= gl
.createBuffer();
127 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
128 gl
.bufferData(gl
.ARRAY_BUFFER
, quadArray
, gl
.STATIC_DRAW
);
130 // Create an unsigned int index buffer that indexes the last 4 vertices
131 var baseIndex
= (quadArrayLen
/ 3) - 4;
133 var indexObject
= gl
.createBuffer();
134 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
135 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, new Uint32Array([
141 baseIndex
+ 0]), gl
.STATIC_DRAW
);
143 var opt_positionLocation
= 0;
144 gl
.enableVertexAttribArray(opt_positionLocation
);
145 gl
.vertexAttribPointer(opt_positionLocation
, 3, gl
.FLOAT
, false, 0, 0);
147 function readLocation(x
, y
) {
148 var pixels
= new Uint8Array(1 * 1 * 4);
149 gl
.readPixels(x
, y
, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, pixels
);
152 function testPixel(blackList
, whiteList
) {
153 function testList(list
, expected
) {
154 for (var n
= 0; n
< list
.length
; n
++) {
156 var x
= -Math
.floor(l
* canvas
.width
/ 2) + canvas
.width
/ 2;
157 var y
= -Math
.floor(l
* canvas
.height
/ 2) + canvas
.height
/ 2;
158 var source
= readLocation(x
, y
);
159 if (Math
.abs(source
[0] - expected
) > 2) {
165 return testList(blackList
, 0) && testList(whiteList
, 255);
167 function verifyDraw(drawNumber
, s
) {
168 gl
.clearColor(1.0, 1.0, 1.0, 1.0);
169 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
170 gl
.drawElements(gl
.TRIANGLES
, 6, gl
.UNSIGNED_INT
, 0);
174 var points
= [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
175 for (var n
= 0; n
< points
.length
; n
++) {
176 if (points
[n
] <= s
) {
177 blackList
.push(points
[n
]);
179 whiteList
.push(points
[n
]);
182 if (testPixel(blackList
, whiteList
)) {
183 testPassed("Draw " + drawNumber
+ " passed pixel test");
185 testFailed("Draw " + drawNumber
+ " failed pixel test");
193 function runIndexValidationTests() {
194 description("Tests that index validation verifies the correct number of indices");
196 function sizeInBytes(type
) {
199 case gl
.UNSIGNED_BYTE
:
202 case gl
.UNSIGNED_SHORT
:
205 case gl
.UNSIGNED_INT
:
209 throw "unknown type";
213 var program
= loadStandardProgram(gl
);
215 // 3 vertices => 1 triangle, interleaved data
216 var dataComplete
= new Float32Array([0, 0, 0, 1,
222 var dataIncomplete
= new Float32Array([0, 0, 0, 1,
227 var indices
= new Uint32Array([0, 1, 2]);
229 debug("Testing with valid indices");
231 var bufferComplete
= gl
.createBuffer();
232 gl
.bindBuffer(gl
.ARRAY_BUFFER
, bufferComplete
);
233 gl
.bufferData(gl
.ARRAY_BUFFER
, dataComplete
, gl
.STATIC_DRAW
);
234 var elements
= gl
.createBuffer();
235 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, elements
);
236 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, gl
.STATIC_DRAW
);
237 gl
.useProgram(program
);
238 var vertexLoc
= gl
.getAttribLocation(program
, "a_vertex");
239 var normalLoc
= gl
.getAttribLocation(program
, "a_normal");
240 gl
.vertexAttribPointer(vertexLoc
, 4, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 0);
241 gl
.enableVertexAttribArray(vertexLoc
);
242 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
243 gl
.enableVertexAttribArray(normalLoc
);
244 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
245 glErrorShouldBe(gl
, gl
.NO_ERROR
);
246 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
247 glErrorShouldBe(gl
, gl
.NO_ERROR
);
249 debug("Testing with out-of-range indices");
251 var bufferIncomplete
= gl
.createBuffer();
252 gl
.bindBuffer(gl
.ARRAY_BUFFER
, bufferIncomplete
);
253 gl
.bufferData(gl
.ARRAY_BUFFER
, dataIncomplete
, gl
.STATIC_DRAW
);
254 gl
.vertexAttribPointer(vertexLoc
, 4, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 0);
255 gl
.enableVertexAttribArray(vertexLoc
);
256 gl
.disableVertexAttribArray(normalLoc
);
257 debug("Enable vertices, valid");
258 glErrorShouldBe(gl
, gl
.NO_ERROR
);
259 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
260 glErrorShouldBe(gl
, gl
.NO_ERROR
);
261 debug("Enable normals, out-of-range");
262 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
263 gl
.enableVertexAttribArray(normalLoc
);
264 glErrorShouldBe(gl
, gl
.NO_ERROR
);
265 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
266 glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
268 debug("Test with enabled attribute that does not belong to current program");
270 gl
.disableVertexAttribArray(normalLoc
);
271 var extraLoc
= Math
.max(vertexLoc
, normalLoc
) + 1;
272 gl
.enableVertexAttribArray(extraLoc
);
273 debug("Enable an extra attribute with null");
274 glErrorShouldBe(gl
, gl
.NO_ERROR
);
275 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
276 glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
277 debug("Enable an extra attribute with insufficient data buffer");
278 gl
.vertexAttribPointer(extraLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), 4 * sizeInBytes(gl
.FLOAT
));
279 glErrorShouldBe(gl
, gl
.NO_ERROR
);
280 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
281 debug("Pass large negative index to vertexAttribPointer");
282 gl
.vertexAttribPointer(normalLoc
, 3, gl
.FLOAT
, false, 7 * sizeInBytes(gl
.FLOAT
), -2000000000 * sizeInBytes(gl
.FLOAT
));
283 glErrorShouldBe(gl
, gl
.INVALID_VALUE
);
284 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
285 gl
.disableVertexAttribArray(vertexLoc
);
288 function runCopiesIndicesTests() {
289 debug("Test that client data is always copied during bufferData and bufferSubData calls");
291 var program
= loadStandardProgram(gl
);
293 gl
.useProgram(program
);
294 var vertexObject
= gl
.createBuffer();
295 gl
.enableVertexAttribArray(0);
296 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
297 // 4 vertices -> 2 triangles
298 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), gl
.STATIC_DRAW
);
299 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
301 var indexObject
= gl
.createBuffer();
303 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
304 var indices
= new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]);
305 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, gl
.STATIC_DRAW
);
306 shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
307 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
308 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
311 shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
312 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
313 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
316 function runResizedBufferTests() {
317 debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation.");
319 var program
= wtu
.setupProgram(gl
, ["vs", "fs"], ["vPosition", "vColor"]);
320 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after initialization");
322 var vertexObject
= gl
.createBuffer();
323 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
324 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array(
325 [-1,1,0, 1,1,0, -1,-1,0,
326 -1,-1,0, 1,1,0, 1,-1,0]), gl
.STATIC_DRAW
);
327 gl
.enableVertexAttribArray(0);
328 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
329 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after vertex setup");
331 var texCoordObject
= gl
.createBuffer();
332 gl
.bindBuffer(gl
.ARRAY_BUFFER
, texCoordObject
);
333 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array(
335 0,1, 1,0, 1,1]), gl
.STATIC_DRAW
);
336 gl
.enableVertexAttribArray(1);
337 gl
.vertexAttribPointer(1, 2, gl
.FLOAT
, false, 0, 0);
338 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after texture coord setup");
340 // Now resize these buffers because we want to change what we're drawing.
341 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
342 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([
343 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0,
344 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), gl
.STATIC_DRAW
);
345 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after vertex redefinition");
346 gl
.bindBuffer(gl
.ARRAY_BUFFER
, texCoordObject
);
347 gl
.bufferData(gl
.ARRAY_BUFFER
, new Uint8Array([
355 0, 255, 0, 255]), gl
.STATIC_DRAW
);
356 gl
.vertexAttribPointer(1, 4, gl
.UNSIGNED_BYTE
, false, 0, 0);
357 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after texture coordinate / color redefinition");
360 var indices
= new Uint32Array(numQuads
* 6);
361 for (var ii
= 0; ii
< numQuads
; ++ii
) {
363 var quad
= (ii
== (numQuads
- 1)) ? 4 : 0;
364 indices
[offset
+ 0] = quad
+ 0;
365 indices
[offset
+ 1] = quad
+ 1;
366 indices
[offset
+ 2] = quad
+ 2;
367 indices
[offset
+ 3] = quad
+ 2;
368 indices
[offset
+ 4] = quad
+ 1;
369 indices
[offset
+ 5] = quad
+ 3;
371 var indexObject
= gl
.createBuffer();
372 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
373 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, indices
, gl
.STATIC_DRAW
);
374 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after setting up indices");
375 gl
.drawElements(gl
.TRIANGLES
, numQuads
* 6, gl
.UNSIGNED_INT
, 0);
376 glErrorShouldBe(gl
, gl
.NO_ERROR
, "after drawing");
379 function runVerifiesTooManyIndicesTests() {
380 description("Tests that index validation for drawElements does not examine too many indices");
382 var program
= loadStandardProgram(gl
);
384 gl
.useProgram(program
);
385 var vertexObject
= gl
.createBuffer();
386 gl
.enableVertexAttribArray(0);
387 gl
.disableVertexAttribArray(1);
388 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vertexObject
);
389 // 4 vertices -> 2 triangles
390 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), gl
.STATIC_DRAW
);
391 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
393 var indexObject
= gl
.createBuffer();
395 debug("Test out of range indices")
396 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, indexObject
);
397 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]), gl
.STATIC_DRAW
);
398 shouldGenerateGLError(gl
, gl
.NO_ERROR
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
399 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
400 shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
403 function runCrashWithBufferSubDataTests() {
404 debug('Verifies that the index validation code which is within bufferSubData does not crash.')
406 var elementBuffer
= gl
.createBuffer();
407 gl
.bindBuffer(gl
.ELEMENT_ARRAY_BUFFER
, elementBuffer
);
408 gl
.bufferData(gl
.ELEMENT_ARRAY_BUFFER
, 256, gl
.STATIC_DRAW
);
409 var data
= new Uint32Array(127);
410 gl
.bufferSubData(gl
.ELEMENT_ARRAY_BUFFER
, 64, data
);
411 glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "after attempting to update a buffer outside of the allocated bounds");
412 testPassed("bufferSubData, when buffer object was initialized with null, did not crash");
416 successfullyParsed
= true;
417 isSuccessfullyParsed();