4 ** Copyright (c) 2012 The Khronos Group Inc.
6 ** Permission is hereby granted, free of charge, to any person obtaining a
7 ** copy of this software and/or associated documentation files (the
8 ** "Materials"), to deal in the Materials without restriction, including
9 ** without limitation the rights to use, copy, modify, merge, publish,
10 ** distribute, sublicense, and/or sell copies of the Materials, and to
11 ** permit persons to whom the Materials are furnished to do so, subject to
12 ** the following conditions:
14 ** The above copyright notice and this permission notice shall be included
15 ** in all copies or substantial portions of the Materials.
17 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
31 <meta charset="utf-8">
32 <title>WebGL OES_element_index_uint Conformance Tests</title>
33 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
34 <script src="../../resources/js-test-pre.js"></script>
35 <script src="../resources/webgl-test-utils.js"></script>
37 <script id="vs" type="x-shader/x-vertex">
38 attribute vec4 vPosition;
39 attribute vec4 vColor;
42 gl_Position = vPosition;
46 <script id="fs" type="x-shader/x-fragment">
47 precision mediump float;
56 <div id="description"></div>
57 <div id="console"></div>
60 description("This test verifies the functionality of the OES_element_index_uint extension, if it is available.");
64 var wtu = WebGLTestUtils;
69 // Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test
70 // for a bug in ANGLE which has since been fixed.
71 for (var ii = 0; ii < 2; ++ii) {
72 canvas = document.createElement("canvas");
76 gl = wtu.create3DContext(canvas);
79 testFailed("WebGL context does not exist");
81 testPassed("WebGL context exists");
83 var drawType = (ii == 0) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;
84 debug("Testing " + ((ii == 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW"));
87 // Query the extension and store globally so shouldBe can access it
88 ext = gl.getExtension("OES_element_index_uint");
90 testPassed("No OES_element_index_uint support -- this is legal");
92 runSupportedTest(false);
94 testPassed("Successfully enabled OES_element_index_uint extension");
96 runSupportedTest(true);
98 runDrawTests(drawType);
100 // These tests are tweaked duplicates of the buffers/index-validation* tests
101 // using unsigned int indices to ensure that behavior remains consistent
102 runIndexValidationTests(drawType);
103 runCopiesIndicesTests(drawType);
104 runResizedBufferTests(drawType);
105 runVerifiesTooManyIndicesTests(drawType);
106 runCrashWithBufferSubDataTests(drawType);
108 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
113 function runSupportedTest(extensionEnabled) {
114 var supported = gl.getSupportedExtensions();
115 if (supported.indexOf("OES_element_index_uint") >= 0) {
116 if (extensionEnabled) {
117 testPassed("OES_element_index_uint listed as supported and getExtension succeeded");
119 testFailed("OES_element_index_uint listed as supported but getExtension failed");
122 if (extensionEnabled) {
123 testFailed("OES_element_index_uint not listed as supported but getExtension succeeded");
125 testPassed("OES_element_index_uint not listed as supported and getExtension failed -- this is legal");
130 function runDrawTests(drawType) {
131 debug("Test that draws with unsigned integer indices produce the expected results");
133 canvas.width = 50; canvas.height = 50;
134 gl.viewport(0, 0, canvas.width, canvas.height);
136 var program = wtu.setupNoTexCoordTextureProgram(gl);
138 function setupDraw(s) {
139 // Create a vertex buffer that cannot be fully indexed via shorts
140 var quadArrayLen = 65537 * 3;
141 var quadArray = new Float32Array(quadArrayLen);
143 // Leave all but the last 4 values zero-ed out
144 var idx = quadArrayLen - 12;
146 // Initialized the last 4 values to a quad
147 quadArray[idx++] = 1.0 * s;
148 quadArray[idx++] = 1.0 * s;
149 quadArray[idx++] = 0.0;
151 quadArray[idx++] = -1.0 * s;
152 quadArray[idx++] = 1.0 * s;
153 quadArray[idx++] = 0.0;
155 quadArray[idx++] = -1.0 * s;
156 quadArray[idx++] = -1.0 * s;
157 quadArray[idx++] = 0.0;
159 quadArray[idx++] = 1.0 * s;
160 quadArray[idx++] = -1.0 * s;
161 quadArray[idx++] = 0.0;
163 var vertexObject = gl.createBuffer();
164 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
165 gl.bufferData(gl.ARRAY_BUFFER, quadArray, drawType);
167 // Create an unsigned int index buffer that indexes the last 4 vertices
168 var baseIndex = (quadArrayLen / 3) - 4;
170 var indexObject = gl.createBuffer();
171 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
172 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([
178 baseIndex + 0]), drawType);
180 var opt_positionLocation = 0;
181 gl.enableVertexAttribArray(opt_positionLocation);
182 gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
184 function testPixel(blackList, whiteList) {
185 function testList(list, expected) {
186 for (var n = 0; n < list.length; n++) {
188 var x = -Math.floor(l * canvas.width / 2) + canvas.width / 2;
189 var y = -Math.floor(l * canvas.height / 2) + canvas.height / 2;
190 wtu.checkCanvasRect(gl, x, y, 1, 1, [expected, expected, expected],
191 "Draw should pass", 2);
194 testList(blackList, 0);
195 testList(whiteList, 255);
197 function verifyDraw(s) {
198 gl.clearColor(1.0, 1.0, 1.0, 1.0);
199 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
200 gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
204 var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
205 for (var n = 0; n < points.length; n++) {
206 if (points[n] <= s) {
207 blackList.push(points[n]);
209 whiteList.push(points[n]);
212 testPixel(blackList, whiteList);
219 function runIndexValidationTests(drawType) {
220 description("Tests that index validation verifies the correct number of indices");
222 function sizeInBytes(type) {
225 case gl.UNSIGNED_BYTE:
228 case gl.UNSIGNED_SHORT:
231 case gl.UNSIGNED_INT:
235 throw "unknown type";
239 var program = wtu.loadStandardProgram(gl);
241 // 3 vertices => 1 triangle, interleaved data
242 var dataComplete = new Float32Array([0, 0, 0, 1,
248 var dataIncomplete = new Float32Array([0, 0, 0, 1,
253 var indices = new Uint32Array([0, 1, 2]);
255 debug("Testing with valid indices");
257 var bufferComplete = gl.createBuffer();
258 gl.bindBuffer(gl.ARRAY_BUFFER, bufferComplete);
259 gl.bufferData(gl.ARRAY_BUFFER, dataComplete, drawType);
260 var elements = gl.createBuffer();
261 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements);
262 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
263 gl.useProgram(program);
264 var vertexLoc = gl.getAttribLocation(program, "a_vertex");
265 var normalLoc = gl.getAttribLocation(program, "a_normal");
266 gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
267 gl.enableVertexAttribArray(vertexLoc);
268 gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
269 gl.enableVertexAttribArray(normalLoc);
270 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
271 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
272 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
273 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
275 debug("Testing with out-of-range indices");
277 var bufferIncomplete = gl.createBuffer();
278 gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete);
279 gl.bufferData(gl.ARRAY_BUFFER, dataIncomplete, drawType);
280 gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
281 gl.enableVertexAttribArray(vertexLoc);
282 gl.disableVertexAttribArray(normalLoc);
283 debug("Enable vertices, valid");
284 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
285 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
286 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
287 debug("Enable normals, out-of-range");
288 gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
289 gl.enableVertexAttribArray(normalLoc);
290 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
291 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
292 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
294 debug("Test with enabled attribute that does not belong to current program");
296 gl.disableVertexAttribArray(normalLoc);
297 var extraLoc = Math.max(vertexLoc, normalLoc) + 1;
298 gl.enableVertexAttribArray(extraLoc);
299 debug("Enable an extra attribute with null");
300 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
301 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
302 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
303 debug("Enable an extra attribute with insufficient data buffer");
304 gl.vertexAttribPointer(extraLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
305 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
306 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
307 debug("Pass large negative index to vertexAttribPointer");
308 gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), -2000000000 * sizeInBytes(gl.FLOAT));
309 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
310 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
313 function runCopiesIndicesTests(drawType) {
314 debug("Test that client data is always copied during bufferData and bufferSubData calls");
316 var program = wtu.loadStandardProgram(gl);
318 gl.useProgram(program);
319 var vertexObject = gl.createBuffer();
320 gl.enableVertexAttribArray(0);
321 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
322 // 4 vertices -> 2 triangles
323 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType);
324 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
326 var indexObject = gl.createBuffer();
328 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
329 var indices = new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]);
330 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
331 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
332 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
333 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
336 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
337 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
338 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
341 function runResizedBufferTests(drawType) {
342 debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation.");
344 var program = wtu.setupProgram(gl, ["vs", "fs"], ["vPosition", "vColor"]);
345 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after initialization");
347 var vertexObject = gl.createBuffer();
348 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
349 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
350 [-1,1,0, 1,1,0, -1,-1,0,
351 -1,-1,0, 1,1,0, 1,-1,0]), drawType);
352 gl.enableVertexAttribArray(0);
353 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
354 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex setup");
356 var texCoordObject = gl.createBuffer();
357 gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
358 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
360 0,1, 1,0, 1,1]), drawType);
361 gl.enableVertexAttribArray(1);
362 gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
363 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coord setup");
365 // Now resize these buffers because we want to change what we're drawing.
366 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
367 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
368 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0,
369 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), drawType);
370 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex redefinition");
371 gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
372 gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([
380 0, 255, 0, 255]), drawType);
381 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, false, 0, 0);
382 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coordinate / color redefinition");
385 var indices = new Uint32Array(numQuads * 6);
386 for (var ii = 0; ii < numQuads; ++ii) {
388 var quad = (ii == (numQuads - 1)) ? 4 : 0;
389 indices[offset + 0] = quad + 0;
390 indices[offset + 1] = quad + 1;
391 indices[offset + 2] = quad + 2;
392 indices[offset + 3] = quad + 2;
393 indices[offset + 4] = quad + 1;
394 indices[offset + 5] = quad + 3;
396 var indexObject = gl.createBuffer();
397 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
398 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
399 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting up indices");
400 gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_INT, 0);
401 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
404 function runVerifiesTooManyIndicesTests(drawType) {
405 description("Tests that index validation for drawElements does not examine too many indices");
407 var program = wtu.loadStandardProgram(gl);
409 gl.useProgram(program);
410 var vertexObject = gl.createBuffer();
411 gl.enableVertexAttribArray(0);
412 gl.disableVertexAttribArray(1);
413 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
414 // 4 vertices -> 2 triangles
415 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0,0, 0,1,0, 1,0,0, 1,1,0 ]), drawType);
416 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
418 var indexObject = gl.createBuffer();
420 debug("Test out of range indices")
421 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
422 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([ 10000, 0, 1, 2, 3, 10000 ]), drawType);
423 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 4)");
424 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 0)");
425 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, "gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_INT, 8)");
428 function runCrashWithBufferSubDataTests(drawType) {
429 debug('Verifies that the index validation code which is within bufferSubData does not crash.')
431 var elementBuffer = gl.createBuffer();
432 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
433 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 256, drawType);
434 var data = new Uint32Array(127);
435 gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 64, data);
436 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "after attempting to update a buffer outside of the allocated bounds");
437 testPassed("bufferSubData, when buffer object was initialized with null, did not crash");
441 var successfullyParsed = true;
443 <script src="../../resources/js-test-post.js"></script>