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>Buffer allocation test
</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>
17 <div id=
"canvasParent"></div>
18 <div id=
"description"></div>
19 <div id=
"console"></div>
20 <script id=
"vshader" type=
"x-shader/x-vertex">
21 attribute vec2 inPosition;
22 attribute vec4 inColor0;
23 attribute vec4 inColor1;
24 attribute vec4 inColor2;
25 attribute vec4 inColor3;
26 attribute vec4 inColor4;
27 attribute vec4 inColor5;
28 attribute vec4 inColor6;
29 attribute vec4 inColor7;
35 color = abs(inColor0) + abs(inColor1) + abs(inColor2) + abs(inColor3) +
36 abs(inColor4) + abs(inColor5) + abs(inColor6) + abs(inColor7);
38 color = clamp(color, vec4(
0.0), vec4(
1.0));
40 gl_Position = vec4(inPosition,
0.0,
1.0);
43 <script id=
"fshader" type=
"x-shader/x-fragment">
44 precision mediump float;
50 if (color == vec4(
0.0))
58 description("Allocates a number of different sized buffers and checks that the buffers are cleared " +
59 "OR that the allocation results in gl.OUT_OF_MEMORY or context loss.");
60 var wtu
= WebGLTestUtils
;
62 // The shader processes eight vec4 attributes at once to reduce the amount of
64 var numColorAttrs
= 8;
66 // Process 64 squares at once to also reduce the amount of draw calls.
69 for (var x
= -1; x
< 1; x
+= w
) {
70 for (var y
= -1; y
< 1; y
+= w
) {
71 vertices
.push(x
+ w
, y
+ w
);
72 vertices
.push(x
, y
+ w
);
75 vertices
.push(x
+ w
, y
+ w
);
77 vertices
.push(x
+ w
, y
);
80 var numVertices
= (vertices
.length
/ 2);
85 var expectContextLost
= false;
87 function initGLForBufferSizesTest() {
88 var canvas
= document
.createElement("canvas");
91 var parent
= document
.getElementById("canvasParent");
92 parent
.innerHTML
= '';
93 parent
.appendChild(canvas
);
94 gl
= wtu
.create3DContext(canvas
);
95 var attribs
= ["inPosition", "inColor0", "inColor1", "inColor2", "inColor3",
96 "inColor4", "inColor5", "inColor6", "inColor7"];
97 wtu
.setupProgram(gl
, ["vshader", "fshader"], attribs
);
98 gl
.enableVertexAttribArray(0);
99 for (var i
= 0; i
< numColorAttrs
; i
++) {
100 gl
.enableVertexAttribArray(1 + i
);
102 gl
.disable(gl
.DEPTH_TEST
);
103 gl
.disable(gl
.BLEND
);
105 squareBuffer
= gl
.createBuffer();
107 gl
.bindBuffer(gl
.ARRAY_BUFFER
, squareBuffer
);
108 gl
.bufferData(gl
.ARRAY_BUFFER
, new Float32Array(vertices
), gl
.STATIC_DRAW
);
111 function createBuffer(size
, allowedToFail
) {
112 var msg
= "Calling bufferData with size=" + size
;
113 var buffer
= gl
.createBuffer();
115 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buffer
);
116 gl
.bufferData(gl
.ARRAY_BUFFER
, size
, gl
.STATIC_DRAW
);
118 error
= gl
.getError();
119 if (error
!== gl
.NO_ERROR
) {
120 gl
.deleteBuffer(buffer
);
122 if (error
=== gl
.OUT_OF_MEMORY
) {
123 testPassed(msg
+ " failed with gl.OUT_OF_MEMORY (this is allowed)");
125 } else if (error
=== gl
.CONTEXT_LOST_WEBGL
) {
126 testPassed(msg
+ " failed with gl.CONTEXT_LOST_WEBGL (this is allowed)");
130 testFailed(msg
+ " failed with error " + wtu
.glEnumToString(gl
, error
));
134 testPassed(msg
+ " did not result in any errors");
135 var reportedSize
= gl
.getBufferParameter(gl
.ARRAY_BUFFER
, gl
.BUFFER_SIZE
);
136 expectContextLost
= false;
137 if (reportedSize
=== null) {
138 testPassed("Null size reported by gl, this should happen if the context is lost which is allowed.");
139 expectContextLost
= true;
140 } else if (reportedSize
!== size
) {
141 if (size
> Math
.pow(2, 32)) {
142 testPassed("gl reported different size " + reportedSize
+ " for the buffer, but this is expected since " +
143 "the requested size was above what the return value of getBufferParameter can represent.");
145 testFailed("gl reported different size " + reportedSize
+ " for the buffer.");
148 testPassed("Size reported by gl was the same as the requested size.");
154 // Draw a square on the canvas using attributes from the clear buffer created with bufferData.
155 function drawWithBuffer(buffer
, allowedToFail
) {
156 gl
.clearColor(0, 1, 0, 1);
157 gl
.clear(gl
.COLOR_BUFFER_BIT
);
159 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buffer
);
160 var size
= gl
.getBufferParameter(gl
.ARRAY_BUFFER
, gl
.BUFFER_SIZE
);
161 // Each vec4 is 16 bytes
162 var increment
= numVertices
* numColorAttrs
* 16;
163 for (var offset
= 0; offset
+ increment
<= size
; offset
+= increment
) {
164 gl
.bindBuffer(gl
.ARRAY_BUFFER
, squareBuffer
);
165 gl
.vertexAttribPointer(0, 2, gl
.FLOAT
, false, 0, 0);
167 for (var i
= 0; i
< numColorAttrs
; i
++) {
168 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buffer
);
169 gl
.vertexAttribPointer(1 + i
, 4, gl
.FLOAT
, false, 0,
170 offset
+ increment
* i
/ numColorAttrs
);
172 gl
.drawArrays(gl
.TRIANGLES
, 0, numVertices
);
173 error
= gl
.getError();
175 if (error
!== gl
.NO_ERROR
) {
177 if (error
=== gl
.OUT_OF_MEMORY
) {
178 testPassed("drawArrays failed with gl.OUT_OF_MEMORY (this is allowed)");
180 } else if (error
=== gl
.CONTEXT_LOST_WEBGL
) {
181 testPassed("drawArrays failed with gl.CONTEXT_LOST_WEBGL (this is allowed)");
185 testFailed("drawArrays failed with error " + wtu
.glEnumToString(gl
, error
));
189 wtu
.checkCanvas(gl
, [0, 255, 0, 255], "should be green");
193 // To be able to confirm the whole buffer has been cleared, the size needs to
194 // be divisible by the amount of vertices. Thus most sizes are multiples of 3.
196 // Reasonable sized buffers.
197 { size
: 3 * 1024, allowedToFail
: false, tryDrawing
: true },
198 { size
: 3 * 1024 * 1024, allowedToFail
: false, tryDrawing
: true },
199 { size
: 3 * 1024 * 1024 * 16, allowedToFail
: false, tryDrawing
: true },
201 // Huge buffers, which are meant to test out of memory handling.
202 // Allowed failures are gl.OUT_OF_MEMORY or context loss.
203 // Succeeding in the allocations is allowed as well for forward compatibility.
205 // 1.5 GB allocation for stressing lower-end 32-bit systems.
206 // Allocation is likely to succeed on higher-end hardware.
207 { size
: 3 * 1024 * 1024 * 512, allowedToFail
: true, tryDrawing
: true },
208 // A buffer that no implementation will be able to allocate for some time
209 // to come. To do this, we use half of the lower 43-bit half of a 44-bit
210 // memory address space, so that the size is still valid on current common
211 // 64-bit implementations, and also below 52-bit limit for exact conversion
212 // from float to long long in WebIDL (though 2^n should be safe anyway).
213 // The 4 TB size is large enough that even extrapolating the historical
214 // exponential growth trend of memory sizes, hardware in 2020's should
215 // still have some trouble actually doing the allocation.
216 { size
: (1 << 12) * (1 << 30), allowedToFail
: true, tryDrawing
: false }
219 function finishBufferSizesTest() {
220 gl
.deleteBuffer(squareBuffer
);
225 function runNextTest() {
227 if (testIndex
> 0 && tests
[testIndex
- 1].allowedToFail
) {
228 if (gl
.isContextLost() || error
=== gl
.OUT_OF_MEMORY
) {
229 initGLForBufferSizesTest();
230 } else if (expectContextLost
) {
231 testFailed("Context was not lost after timeout even though gl.getBufferParameter returned null.");
234 var buffer
= createBuffer(tests
[testIndex
].size
, tests
[testIndex
].allowedToFail
);
236 if (tests
[testIndex
].tryDrawing
) {
237 drawWithBuffer(buffer
, tests
[testIndex
].allowedToFail
);
239 gl
.deleteBuffer(buffer
);
242 if (testIndex
+ 1 >= tests
.length
) {
243 finishBufferSizesTest();
245 if (tests
[testIndex
+ 1].allowedToFail
&& !tests
[testIndex
].allowedToFail
) {
246 if (!confirm("The following tests can cause unresponsiveness or instability. Press OK to continue.")) {
247 testFailed("Tests aborted");
251 if (tests
[testIndex
].allowedToFail
) {
252 // Give plenty of time for possible context loss
253 setTimeout(runNextTest(), 5000);
260 initGLForBufferSizesTest();
263 var successfullyParsed
= true;