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 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;
21 gl_Position = vPosition;
25 <script id=
"fs" type=
"x-shader/x-fragment">
26 precision mediump float;
32 <script id=
"vsCheckOutOfBounds" type=
"x-shader/x-vertex">
33 precision mediump float;
34 attribute vec2 position;
35 attribute vec4 vecRandom;
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;
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
55 v_color = vec4(
1.0,
0.0,
0.0,
1.0); // red -- Unexpected value
57 gl_Position = vec4(position,
0.0,
1.0);
63 <div id=
"description"></div>
64 <div id=
"console"></div>
67 description("This test verifies the functionality of the Uint element indices.");
71 var wtu
= WebGLTestUtils
;
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");
82 gl
= wtu
.create3DContext(canvas
, null, 2);
85 testFailed("WebGL context does not exist");
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([
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
);
164 function testPixel(blockList
, allowList
) {
165 function testList(list
, expected
) {
166 for (var n
= 0; n
< list
.length
; 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) {
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);
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
]);
191 allowList
.push(points
[n
]);
194 if (testPixel(blockList
, allowList
)) {
195 testPassed("Draw " + drawNumber
+ " passed pixel test");
197 testFailed("Draw " + drawNumber
+ " failed pixel test");
205 function runIndexValidationTests(drawType
) {
206 description("Tests that index validation verifies the correct number of indices");
208 function sizeInBytes(type
) {
211 case gl
.UNSIGNED_BYTE
:
214 case gl
.UNSIGNED_SHORT
:
217 case gl
.UNSIGNED_INT
:
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,
234 var dataIncomplete
= new Float32Array([0, 0, 0, 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([
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]);
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");
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]);
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(
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([
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");
395 var indices
= new Uint32Array(numQuads
* 6);
396 for (var ii
= 0; ii
< numQuads
; ++ii
) {
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");
427 var successfullyParsed
= true;
429 <script src=
"../../js/js-test-post.js"></script>