Backed out changeset 8fc3326bce7f (bug 1943032) for causing failures at browser_tab_g...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance2 / rendering / element-index-uint.html
blob123254f4cd8afc37b5b8dc301f820575aad038b4
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 Uint element indices 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;
19 varying vec4 color;
20 void main() {
21 gl_Position = vPosition;
22 color = vColor;
24 </script>
25 <script id="fs" type="x-shader/x-fragment">
26 precision mediump float;
27 varying vec4 color;
28 void main() {
29 gl_FragColor = color;
31 </script>
32 <script id="vsCheckOutOfBounds" type="x-shader/x-vertex">
33 precision mediump float;
34 attribute vec2 position;
35 attribute vec4 vecRandom;
36 varying vec4 v_color;
38 // Per the spec, each component can either contain existing contents
39 // of the buffer or 0.
40 bool testFloatComponent(float component) {
41 return (component == 0.2 || component == 0.0);
43 // The last component is additionally allowed to be 1.0.
44 bool testLastFloatComponent(float component) {
45 return testFloatComponent(component) || component == 1.0;
48 void main() {
49 if (testFloatComponent(vecRandom.x) &&
50 testFloatComponent(vecRandom.y) &&
51 testFloatComponent(vecRandom.z) &&
52 testLastFloatComponent(vecRandom.w)) {
53 v_color = vec4(0.0, 1.0, 0.0, 1.0); // green -- Out of range
54 } else {
55 v_color = vec4(1.0, 0.0, 0.0, 1.0); // red -- Unexpected value
57 gl_Position = vec4(position, 0.0, 1.0);
59 </script>
61 </head>
62 <body>
63 <div id="description"></div>
64 <div id="console"></div>
65 <script>
66 "use strict";
67 description("This test verifies the functionality of the Uint element indices.");
69 debug("");
71 var wtu = WebGLTestUtils;
72 var gl = null;
73 var canvas = null;
75 // Test both STATIC_DRAW and DYNAMIC_DRAW as a regression test
76 // for a bug in ANGLE which has since been fixed.
77 for (var ii = 0; ii < 2; ++ii) {
78 canvas = document.createElement("canvas");
79 canvas.width = 50;
80 canvas.height = 50;
82 gl = wtu.create3DContext(canvas, null, 2);
84 if (!gl) {
85 testFailed("WebGL context does not exist");
86 } else {
87 testPassed("WebGL context exists");
89 var drawType = (ii == 0) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;
90 debug("Testing " + ((ii == 0) ? "STATIC_DRAW" : "DYNAMIC_DRAW"));
92 runDrawTests(drawType);
94 // These tests are tweaked duplicates of the buffers/index-validation* tests
95 // using unsigned int indices to ensure that behavior remains consistent
96 runIndexValidationTests(drawType);
97 runIndexOutOfRangeTests(drawType);
98 runResizedBufferTests(drawType);
99 runCrashWithBufferSubDataTests(drawType);
101 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
105 function runDrawTests(drawType) {
106 debug("Test that draws with unsigned integer indices produce the expected results");
108 canvas.width = 50; canvas.height = 50;
109 gl.viewport(0, 0, canvas.width, canvas.height);
111 var program = wtu.setupNoTexCoordTextureProgram(gl);
113 function setupDraw(s) {
114 // Create a vertex buffer that cannot be fully indexed via shorts
115 var quadArrayLen = 65537 * 3;
116 var quadArray = new Float32Array(quadArrayLen);
118 // Leave all but the last 4 values zero-ed out
119 var idx = quadArrayLen - 12;
121 // Initialized the last 4 values to a quad
122 quadArray[idx++] = 1.0 * s;
123 quadArray[idx++] = 1.0 * s;
124 quadArray[idx++] = 0.0;
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 var vertexObject = gl.createBuffer();
139 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
140 gl.bufferData(gl.ARRAY_BUFFER, quadArray, drawType);
142 // Create an unsigned int index buffer that indexes the last 4 vertices
143 var baseIndex = (quadArrayLen / 3) - 4;
145 var indexObject = gl.createBuffer();
146 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
147 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array([
148 baseIndex + 0,
149 baseIndex + 1,
150 baseIndex + 2,
151 baseIndex + 2,
152 baseIndex + 3,
153 baseIndex + 0]), drawType);
155 var opt_positionLocation = 0;
156 gl.enableVertexAttribArray(opt_positionLocation);
157 gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
159 function readLocation(x, y) {
160 var pixels = new Uint8Array(1 * 1 * 4);
161 gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
162 return pixels;
164 function testPixel(blockList, allowList) {
165 function testList(list, expected) {
166 for (var n = 0; n < list.length; n++) {
167 var l = list[n];
168 var x = -Math.floor(l * canvas.width / 2) + canvas.width / 2;
169 var y = -Math.floor(l * canvas.height / 2) + canvas.height / 2;
170 var source = readLocation(x, y);
171 if (Math.abs(source[0] - expected) > 2) {
172 return false;
175 return true;
177 return testList(blockList, 0) && testList(allowList, 255);
179 function verifyDraw(drawNumber, s) {
180 gl.clearColor(1.0, 1.0, 1.0, 1.0);
181 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
182 gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
184 var blockList = [];
185 var allowList = [];
186 var points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
187 for (var n = 0; n < points.length; n++) {
188 if (points[n] <= s) {
189 blockList.push(points[n]);
190 } else {
191 allowList.push(points[n]);
194 if (testPixel(blockList, allowList)) {
195 testPassed("Draw " + drawNumber + " passed pixel test");
196 } else {
197 testFailed("Draw " + drawNumber + " failed pixel test");
201 setupDraw(0.5);
202 verifyDraw(0, 0.5);
205 function runIndexValidationTests(drawType) {
206 description("Tests that index validation verifies the correct number of indices");
208 function sizeInBytes(type) {
209 switch (type) {
210 case gl.BYTE:
211 case gl.UNSIGNED_BYTE:
212 return 1;
213 case gl.SHORT:
214 case gl.UNSIGNED_SHORT:
215 return 2;
216 case gl.INT:
217 case gl.UNSIGNED_INT:
218 case gl.FLOAT:
219 return 4;
220 default:
221 throw "unknown type";
225 var program = wtu.loadStandardProgram(gl);
227 // 3 vertices => 1 triangle, interleaved data
228 var dataComplete = new Float32Array([0, 0, 0, 1,
229 0, 0, 1,
230 1, 0, 0, 1,
231 0, 0, 1,
232 1, 1, 1, 1,
233 0, 0, 1]);
234 var dataIncomplete = new Float32Array([0, 0, 0, 1,
235 0, 0, 1,
236 1, 0, 0, 1,
237 0, 0, 1,
238 1, 1, 1, 1]);
239 var indices = new Uint32Array([0, 1, 2]);
241 debug("Testing with valid indices");
243 var bufferComplete = gl.createBuffer();
244 gl.bindBuffer(gl.ARRAY_BUFFER, bufferComplete);
245 gl.bufferData(gl.ARRAY_BUFFER, dataComplete, drawType);
246 var elements = gl.createBuffer();
247 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements);
248 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
249 gl.useProgram(program);
250 var vertexLoc = gl.getAttribLocation(program, "a_vertex");
251 var normalLoc = gl.getAttribLocation(program, "a_normal");
252 gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
253 gl.enableVertexAttribArray(vertexLoc);
254 gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
255 gl.enableVertexAttribArray(normalLoc);
256 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
257 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
258 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
259 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
261 var bufferIncomplete = gl.createBuffer();
262 gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete);
263 gl.bufferData(gl.ARRAY_BUFFER, dataIncomplete, drawType);
264 gl.vertexAttribPointer(vertexLoc, 4, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 0);
265 gl.enableVertexAttribArray(vertexLoc);
266 gl.disableVertexAttribArray(normalLoc);
267 debug("Enable vertices, valid");
268 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
269 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
270 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
272 debug("Test with enabled attribute that does not belong to current program");
274 gl.disableVertexAttribArray(normalLoc);
275 var extraLoc = Math.max(vertexLoc, normalLoc) + 1;
276 gl.enableVertexAttribArray(extraLoc);
277 debug("Enable an extra attribute with null");
278 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
279 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
280 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
281 debug("Enable an extra attribute with insufficient data buffer");
282 gl.vertexAttribPointer(extraLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), 4 * sizeInBytes(gl.FLOAT));
283 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
284 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
285 debug("Pass large negative index to vertexAttribPointer");
286 gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 7 * sizeInBytes(gl.FLOAT), -2000000000 * sizeInBytes(gl.FLOAT));
287 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
288 shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, 0)');
291 function runIndexOutOfRangeTests(drawType) {
292 debug("Testing with out-of-range indices");
294 var bufferPos = gl.createBuffer();
295 gl.bindBuffer(gl.ARRAY_BUFFER, bufferPos);
296 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
297 1.0, 1.0,
298 -1.0, 1.0,
299 -1.0, -1.0,
300 1.0, -1.0]), drawType);
301 gl.enableVertexAttribArray(0);
302 gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
304 var bufferIncomplete = gl.createBuffer();
305 gl.bindBuffer(gl.ARRAY_BUFFER, bufferIncomplete);
306 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]), drawType);
307 gl.enableVertexAttribArray(1);
308 gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
310 var glProgram = wtu.setupProgram(gl, ["vsCheckOutOfBounds", wtu.simpleVertexColorFragmentShader], ["position", "vecRandom"]);
311 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Shader and buffer setup successfully");
313 var indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
314 var elements = gl.createBuffer();
315 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements);
316 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
318 gl.clearColor(0.0, 0.0, 1.0, 1.0); // Start with blue to indicate no pixels touched.
319 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
323 gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
324 var error = gl.getError();
325 if (error === gl.INVALID_OPERATION) {
326 testPassed("drawElements flagged INVALID_OPERATION, which is valid so long as all canvas pixels were not touched.");
327 wtu.checkCanvas(gl, [0, 0, 255, 255]);
328 } else if (error === gl.NO_ERROR) {
329 testPassed("drawElements flagged NO_ERROR, which is valid so long as all canvas pixels are green.");
330 wtu.checkCanvas(gl, [0, 255, 0, 255]);
331 } else {
332 testFailed("Invalid error flagged by drawElements. Should be INVALID_OPERATION or NO_ERROR");
335 debug("Test that client data is always copied during bufferData and bufferSubData calls");
337 indices[5] = 1;
338 gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
339 var error = gl.getError();
340 if (error === gl.INVALID_OPERATION) {
341 testPassed("drawElements flagged INVALID_OPERATION, which is valid so long as all canvas pixels were not touched.");
342 wtu.checkCanvas(gl, [0, 0, 255, 255]);
343 } else if (error === gl.NO_ERROR) {
344 testPassed("drawElements flagged NO_ERROR, which is valid so long as all canvas pixels are green.");
345 wtu.checkCanvas(gl, [0, 255, 0, 255]);
346 } else {
347 testFailed("Invalid error flagged by drawElements. Should be INVALID_OPERATION or NO_ERROR");
351 function runResizedBufferTests(drawType) {
352 debug("Test that updating the size of a vertex buffer is properly noticed by the WebGL implementation.");
354 var program = wtu.setupProgram(gl, ["vs", "fs"], ["vPosition", "vColor"]);
355 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after initialization");
357 var vertexObject = gl.createBuffer();
358 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
359 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
360 [-1,1,0, 1,1,0, -1,-1,0,
361 -1,-1,0, 1,1,0, 1,-1,0]), drawType);
362 gl.enableVertexAttribArray(0);
363 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
364 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex setup");
366 var texCoordObject = gl.createBuffer();
367 gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
368 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
369 [0,0, 1,0, 0,1,
370 0,1, 1,0, 1,1]), drawType);
371 gl.enableVertexAttribArray(1);
372 gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
373 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coord setup");
375 // Now resize these buffers because we want to change what we're drawing.
376 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
377 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
378 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0,
379 -1,1,0, 1,1,0, -1,-1,0, 1,-1,0]), drawType);
380 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after vertex redefinition");
381 gl.bindBuffer(gl.ARRAY_BUFFER, texCoordObject);
382 gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([
383 255, 0, 0, 255,
384 255, 0, 0, 255,
385 255, 0, 0, 255,
386 255, 0, 0, 255,
387 0, 255, 0, 255,
388 0, 255, 0, 255,
389 0, 255, 0, 255,
390 0, 255, 0, 255]), drawType);
391 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, false, 0, 0);
392 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after texture coordinate / color redefinition");
394 var numQuads = 2;
395 var indices = new Uint32Array(numQuads * 6);
396 for (var ii = 0; ii < numQuads; ++ii) {
397 var offset = ii * 6;
398 var quad = (ii == (numQuads - 1)) ? 4 : 0;
399 indices[offset + 0] = quad + 0;
400 indices[offset + 1] = quad + 1;
401 indices[offset + 2] = quad + 2;
402 indices[offset + 3] = quad + 2;
403 indices[offset + 4] = quad + 1;
404 indices[offset + 5] = quad + 3;
406 var indexObject = gl.createBuffer();
407 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
408 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, drawType);
409 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setting up indices");
410 gl.drawElements(gl.TRIANGLES, numQuads * 6, gl.UNSIGNED_INT, 0);
411 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawing");
414 function runCrashWithBufferSubDataTests(drawType) {
415 debug('Verifies that the index validation code which is within bufferSubData does not crash.')
417 var elementBuffer = gl.createBuffer();
418 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
419 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 256, drawType);
420 var data = new Uint32Array(127);
421 gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 64, data);
422 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "after attempting to update a buffer outside of the allocated bounds");
423 testPassed("bufferSubData, when buffer object was initialized with null, did not crash");
426 debug("");
427 var successfullyParsed = true;
428 </script>
429 <script src="../../js/js-test-post.js"></script>
431 </body>
432 </html>