blob: 94dd9f3d3e81be0d785ba7021f0d501b4ebde3d1 [file] [edit]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL default framebuffer is not allocated by resizing a canvas that is not drawn to</title>
<script src="../resources/js-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script>
description("Tests that resizing a canvas that has not been drawn to does not allocate the default framebuffer storage, also after the next rendering update and after a context restore, and that resizing a canvas that has been drawn to reallocates the storage at the next rendering update.");
jsTestIsAsync = true;
// The errors that the GPU process reports are printed asynchronously, which would make the output
// depend on timing. The tests check the errors with getError().
if (window.internals)
internals.settings.setWebGLErrorsToConsoleEnabled(false);
var canvas;
var gl;
var extension;
var pixel;
function allocatedSize()
{
return internals.webglDefaultFramebufferAllocatedSize(gl).join("x");
}
function readPixel(x, y)
{
var result = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, result);
return result.toString();
}
// The animation frame callbacks run before the canvases are presented in the rendering update. A
// task posted from the callback runs after the rendering update.
function afterNextRenderingUpdate()
{
return new Promise(resolve => requestAnimationFrame(() => setTimeout(resolve, 0)));
}
function loseAndRestoreContext()
{
return new Promise(function(resolve, reject) {
canvas.addEventListener("webglcontextlost", function(event) {
event.preventDefault();
setTimeout(function() { extension.restoreContext(); }, 0);
}, { once: true });
canvas.addEventListener("webglcontextrestored", function() { resolve(); }, { once: true });
setTimeout(function() { reject(new Error("timed out waiting for the context to be restored")); }, 10000);
extension.loseContext();
});
}
function releaseContext()
{
if (gl && !gl.isContextLost())
extension.loseContext();
if (canvas && canvas.parentNode)
canvas.parentNode.removeChild(canvas);
canvas = null;
gl = null;
extension = null;
pixel = null;
gc();
}
// The canvas is in the document, so that the rendering update prepares it for display.
function createContext(version, parameters)
{
releaseContext();
canvas = document.createElement("canvas");
canvas.width = 4;
canvas.height = 4;
document.body.appendChild(canvas);
gl = canvas.getContext(version == 2 ? "webgl2" : "webgl", parameters);
if (!gl) {
testFailed("Unable to create the context.");
return false;
}
extension = gl.getExtension("WEBGL_lose_context");
return true;
}
async function testResizeWithoutDrawing(version, parameters)
{
debug("");
debug("WebGL " + version + " " + JSON.stringify(parameters) + ": resizing a canvas that has not been drawn to does not allocate the default framebuffer.");
if (!createContext(version, parameters))
return;
shouldBeEqualToString("allocatedSize()", "0x0");
canvas.width = 8;
canvas.height = 6;
shouldBe("gl.drawingBufferWidth", "8");
shouldBe("gl.drawingBufferHeight", "6");
shouldBeEqualToString("allocatedSize()", "0x0");
await afterNextRenderingUpdate();
shouldBeEqualToString("allocatedSize()", "0x0");
// A smaller size does not allocate the storage either.
canvas.width = 2;
canvas.height = 2;
await afterNextRenderingUpdate();
shouldBeEqualToString("allocatedSize()", "0x0");
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
shouldBeEqualToString("allocatedSize()", "2x2");
pixel = readPixel(1, 1);
shouldBeEqualToString("pixel", "0,255,0,255");
shouldBe("gl.getError()", "gl.NO_ERROR");
shouldBeFalse("gl.isContextLost()");
}
async function testResizeAfterContextRestore(version, parameters)
{
debug("");
debug("WebGL " + version + " " + JSON.stringify(parameters) + ": resizing a canvas that has not been drawn to since the context was restored does not allocate the default framebuffer.");
if (!createContext(version, parameters))
return;
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
shouldBeEqualToString("allocatedSize()", "4x4");
await loseAndRestoreContext();
shouldBeEqualToString("allocatedSize()", "0x0");
canvas.width = 8;
canvas.height = 6;
await afterNextRenderingUpdate();
shouldBeEqualToString("allocatedSize()", "0x0");
shouldBeFalse("gl.isContextLost()");
}
async function testResizeAfterDrawing(version, parameters)
{
debug("");
debug("WebGL " + version + " " + JSON.stringify(parameters) + ": resizing a canvas that has been drawn to reallocates the default framebuffer at the next rendering update.");
if (!createContext(version, parameters))
return;
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
shouldBeEqualToString("allocatedSize()", "4x4");
await afterNextRenderingUpdate();
// The new size does not shrink the storage, so the storage is not reallocated right away.
canvas.width = 8;
canvas.height = 6;
shouldBeEqualToString("allocatedSize()", "4x4");
// The display buffer is replaced with the cleared drawing buffer of the new size.
await afterNextRenderingUpdate();
shouldBeEqualToString("allocatedSize()", "8x6");
pixel = readPixel(7, 5);
shouldBeEqualToString("pixel", "0,0,0,0");
shouldBe("gl.getError()", "gl.NO_ERROR");
}
var configurations = [
{ antialias: false, preserveDrawingBuffer: false },
{ antialias: true, preserveDrawingBuffer: false },
{ antialias: false, preserveDrawingBuffer: true },
{ antialias: true, preserveDrawingBuffer: true },
];
(async () => {
if (!window.internals) {
testFailed("This test requires internals.webglDefaultFramebufferAllocatedSize().");
finishJSTest();
return;
}
for (var parameters of configurations) {
for (var version of [1, 2]) {
await testResizeWithoutDrawing(version, parameters);
await testResizeAfterContextRestore(version, parameters);
await testResizeAfterDrawing(version, parameters);
}
}
releaseContext();
finishJSTest();
})();
</script>
</body>
</html>