buffer-sizes.html (9296B)
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 --> 6 7 <!DOCTYPE html> 8 <html> 9 <head> 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> 15 </head> 16 <body> 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; 30 31 varying vec4 color; 32 33 void main() 34 { 35 color = abs(inColor0) + abs(inColor1) + abs(inColor2) + abs(inColor3) + 36 abs(inColor4) + abs(inColor5) + abs(inColor6) + abs(inColor7); 37 38 color = clamp(color, vec4(0.0), vec4(1.0)); 39 40 gl_Position = vec4(inPosition, 0.0, 1.0); 41 } 42 </script> 43 <script id="fshader" type="x-shader/x-fragment"> 44 precision mediump float; 45 46 varying vec4 color; 47 48 void main() 49 { 50 if (color == vec4(0.0)) 51 discard; 52 53 gl_FragColor = color; 54 } 55 </script> 56 57 <script> 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; 61 62 // The shader processes eight vec4 attributes at once to reduce the amount of 63 // draw calls. 64 var numColorAttrs = 8; 65 66 // Process 64 squares at once to also reduce the amount of draw calls. 67 var vertices = []; 68 var w = 0.25; 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); 73 vertices.push(x, y ); 74 75 vertices.push(x + w, y + w); 76 vertices.push(x, y ); 77 vertices.push(x + w, y ); 78 } 79 } 80 var numVertices = (vertices.length / 2); 81 82 var gl; 83 var squareBuffer; 84 var error = 0; 85 var expectContextLost = false; 86 87 function initGLForBufferSizesTest() { 88 var canvas = document.createElement("canvas"); 89 canvas.width = 40; 90 canvas.height = 40; 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); 101 } 102 gl.disable(gl.DEPTH_TEST); 103 gl.disable(gl.BLEND); 104 105 squareBuffer = gl.createBuffer(); 106 107 gl.bindBuffer(gl.ARRAY_BUFFER, squareBuffer); 108 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 109 } 110 111 function createBuffer(size, allowedToFail) { 112 var msg = "Calling bufferData with size=" + size; 113 var buffer = gl.createBuffer(); 114 115 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 116 gl.bufferData(gl.ARRAY_BUFFER, size, gl.STATIC_DRAW); 117 118 error = gl.getError(); 119 if (error !== gl.NO_ERROR) { 120 gl.deleteBuffer(buffer); 121 if (allowedToFail) { 122 if (error === gl.OUT_OF_MEMORY) { 123 testPassed(msg + " failed with gl.OUT_OF_MEMORY (this is allowed)"); 124 return null; 125 } else if (error === gl.CONTEXT_LOST_WEBGL) { 126 testPassed(msg + " failed with gl.CONTEXT_LOST_WEBGL (this is allowed)"); 127 return null; 128 } 129 } 130 testFailed(msg + " failed with error " + wtu.glEnumToString(gl, error)); 131 return null; 132 } 133 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."); 144 } else { 145 testFailed("gl reported different size " + reportedSize + " for the buffer."); 146 } 147 } else { 148 testPassed("Size reported by gl was the same as the requested size."); 149 } 150 151 return buffer; 152 } 153 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); 158 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); 166 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); 171 } 172 gl.drawArrays(gl.TRIANGLES, 0, numVertices); 173 error = gl.getError(); 174 175 if (error !== gl.NO_ERROR) { 176 if (allowedToFail) { 177 if (error === gl.OUT_OF_MEMORY) { 178 testPassed("drawArrays failed with gl.OUT_OF_MEMORY (this is allowed)"); 179 return; 180 } else if (error === gl.CONTEXT_LOST_WEBGL) { 181 testPassed("drawArrays failed with gl.CONTEXT_LOST_WEBGL (this is allowed)"); 182 return; 183 } 184 } 185 testFailed("drawArrays failed with error " + wtu.glEnumToString(gl, error)); 186 return; 187 } 188 } 189 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green"); 190 } 191 192 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. 195 var tests = [ 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 }, 200 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. 204 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 } 217 ]; 218 219 function finishBufferSizesTest() { 220 gl.deleteBuffer(squareBuffer); 221 finishTest(); 222 } 223 224 var testIndex = -1; 225 function runNextTest() { 226 ++testIndex; 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."); 232 } 233 } 234 var buffer = createBuffer(tests[testIndex].size, tests[testIndex].allowedToFail); 235 if (buffer) { 236 if (tests[testIndex].tryDrawing) { 237 drawWithBuffer(buffer, tests[testIndex].allowedToFail); 238 } 239 gl.deleteBuffer(buffer); 240 } 241 242 if (testIndex + 1 >= tests.length) { 243 finishBufferSizesTest(); 244 } else { 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"); 248 return; 249 } 250 } 251 if (tests[testIndex].allowedToFail) { 252 // Give plenty of time for possible context loss 253 setTimeout(runNextTest(), 5000); 254 } else { 255 runNextTest(); 256 } 257 } 258 }; 259 260 initGLForBufferSizesTest(); 261 runNextTest(); 262 263 var successfullyParsed = true; 264 </script> 265 266 </body> 267 </html>