1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Buffer allocation test</title>
<link rel="stylesheet" href="../resources/js-test-style.css"/>
<script src="../js/js-test-pre.js"></script>
<script src="../js/webgl-test-utils.js"> </script>
</head>
<body>
<div id="canvasParent"></div>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
attribute vec2 inPosition;
attribute vec4 inColor0;
attribute vec4 inColor1;
attribute vec4 inColor2;
attribute vec4 inColor3;
attribute vec4 inColor4;
attribute vec4 inColor5;
attribute vec4 inColor6;
attribute vec4 inColor7;
varying vec4 color;
void main()
{
color = abs(inColor0) + abs(inColor1) + abs(inColor2) + abs(inColor3) +
abs(inColor4) + abs(inColor5) + abs(inColor6) + abs(inColor7);
color = clamp(color, vec4(0.0), vec4(1.0));
gl_Position = vec4(inPosition, 0.0, 1.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 color;
void main()
{
if (color == vec4(0.0))
discard;
gl_FragColor = color;
}
</script>
<script>
description("Allocates a number of different sized buffers and checks that the buffers are cleared " +
"OR that the allocation results in gl.OUT_OF_MEMORY or context loss.");
var wtu = WebGLTestUtils;
// The shader processes eight vec4 attributes at once to reduce the amount of
// draw calls.
var numColorAttrs = 8;
// Process 64 squares at once to also reduce the amount of draw calls.
var vertices = [];
var w = 0.25;
for (var x = -1; x < 1; x += w) {
for (var y = -1; y < 1; y += w) {
vertices.push(x + w, y + w);
vertices.push(x, y + w);
vertices.push(x, y );
vertices.push(x + w, y + w);
vertices.push(x, y );
vertices.push(x + w, y );
}
}
var numVertices = (vertices.length / 2);
var gl;
var squareBuffer;
var error = 0;
var expectContextLost = false;
function initGLForBufferSizesTest() {
var canvas = document.createElement("canvas");
canvas.width = 40;
canvas.height = 40;
var parent = document.getElementById("canvasParent");
parent.innerHTML = '';
parent.appendChild(canvas);
gl = wtu.create3DContext(canvas);
var attribs = ["inPosition", "inColor0", "inColor1", "inColor2", "inColor3",
"inColor4", "inColor5", "inColor6", "inColor7"];
wtu.setupProgram(gl, ["vshader", "fshader"], attribs);
gl.enableVertexAttribArray(0);
for (var i = 0; i < numColorAttrs; i++) {
gl.enableVertexAttribArray(1 + i);
}
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
squareBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}
function createBuffer(size, allowedToFail) {
var msg = "Calling bufferData with size=" + size;
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, size, gl.STATIC_DRAW);
error = gl.getError();
if (error !== gl.NO_ERROR) {
gl.deleteBuffer(buffer);
if (allowedToFail) {
if (error === gl.OUT_OF_MEMORY) {
testPassed(msg + " failed with gl.OUT_OF_MEMORY (this is allowed)");
return null;
} else if (error === gl.CONTEXT_LOST_WEBGL) {
testPassed(msg + " failed with gl.CONTEXT_LOST_WEBGL (this is allowed)");
return null;
}
}
testFailed(msg + " failed with error " + wtu.glEnumToString(gl, error));
return null;
}
testPassed(msg + " did not result in any errors");
var reportedSize = gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
expectContextLost = false;
if (reportedSize === null) {
testPassed("Null size reported by gl, this should happen if the context is lost which is allowed.");
expectContextLost = true;
} else if (reportedSize !== size) {
if (size > Math.pow(2, 32)) {
testPassed("gl reported different size " + reportedSize + " for the buffer, but this is expected since " +
"the requested size was above what the return value of getBufferParameter can represent.");
} else {
testFailed("gl reported different size " + reportedSize + " for the buffer.");
}
} else {
testPassed("Size reported by gl was the same as the requested size.");
}
return buffer;
}
// Draw a square on the canvas using attributes from the clear buffer created with bufferData.
function drawWithBuffer(buffer, allowedToFail) {
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
var size = gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
// Each vec4 is 16 bytes
var increment = numVertices * numColorAttrs * 16;
for (var offset = 0; offset + increment <= size; offset += increment) {
gl.bindBuffer(gl.ARRAY_BUFFER, squareBuffer);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
for (var i = 0; i < numColorAttrs; i++) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(1 + i, 4, gl.FLOAT, false, 0,
offset + increment * i / numColorAttrs);
}
gl.drawArrays(gl.TRIANGLES, 0, numVertices);
error = gl.getError();
if (error !== gl.NO_ERROR) {
if (allowedToFail) {
if (error === gl.OUT_OF_MEMORY) {
testPassed("drawArrays failed with gl.OUT_OF_MEMORY (this is allowed)");
return;
} else if (error === gl.CONTEXT_LOST_WEBGL) {
testPassed("drawArrays failed with gl.CONTEXT_LOST_WEBGL (this is allowed)");
return;
}
}
testFailed("drawArrays failed with error " + wtu.glEnumToString(gl, error));
return;
}
}
wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
}
// To be able to confirm the whole buffer has been cleared, the size needs to
// be divisible by the amount of vertices. Thus most sizes are multiples of 3.
var tests = [
// Reasonable sized buffers.
{ size: 3 * 1024, allowedToFail: false, tryDrawing: true },
{ size: 3 * 1024 * 1024, allowedToFail: false, tryDrawing: true },
{ size: 3 * 1024 * 1024 * 16, allowedToFail: false, tryDrawing: true },
// Huge buffers, which are meant to test out of memory handling.
// Allowed failures are gl.OUT_OF_MEMORY or context loss.
// Succeeding in the allocations is allowed as well for forward compatibility.
// 1.5 GB allocation for stressing lower-end 32-bit systems.
// Allocation is likely to succeed on higher-end hardware.
{ size: 3 * 1024 * 1024 * 512, allowedToFail: true, tryDrawing: true },
// A buffer that no implementation will be able to allocate for some time
// to come. To do this, we use half of the lower 43-bit half of a 44-bit
// memory address space, so that the size is still valid on current common
// 64-bit implementations, and also below 52-bit limit for exact conversion
// from float to long long in WebIDL (though 2^n should be safe anyway).
// The 4 TB size is large enough that even extrapolating the historical
// exponential growth trend of memory sizes, hardware in 2020's should
// still have some trouble actually doing the allocation.
{ size: (1 << 12) * (1 << 30), allowedToFail: true, tryDrawing: false }
];
function finishBufferSizesTest() {
gl.deleteBuffer(squareBuffer);
finishTest();
}
var testIndex = -1;
function runNextTest() {
++testIndex;
if (testIndex > 0 && tests[testIndex - 1].allowedToFail) {
if (gl.isContextLost() || error === gl.OUT_OF_MEMORY) {
initGLForBufferSizesTest();
} else if (expectContextLost) {
testFailed("Context was not lost after timeout even though gl.getBufferParameter returned null.");
}
}
var buffer = createBuffer(tests[testIndex].size, tests[testIndex].allowedToFail);
if (buffer) {
if (tests[testIndex].tryDrawing) {
drawWithBuffer(buffer, tests[testIndex].allowedToFail);
}
gl.deleteBuffer(buffer);
}
if (testIndex + 1 >= tests.length) {
finishBufferSizesTest();
} else {
if (tests[testIndex + 1].allowedToFail && !tests[testIndex].allowedToFail) {
if (!confirm("The following tests can cause unresponsiveness or instability. Press OK to continue.")) {
testFailed("Tests aborted");
return;
}
}
if (tests[testIndex].allowedToFail) {
// Give plenty of time for possible context loss
setTimeout(runNextTest(), 5000);
} else {
runNextTest();
}
}
};
initGLForBufferSizesTest();
runNextTest();
var successfullyParsed = true;
</script>
</body>
</html>
|