| <!DOCTYPE html> | |
| <head> | |
| <script src="../resources/js-test.js"></script> | |
| <script src="../fast/canvas/webgl/resources/webgl-test.js"> </script> | |
| <script src="../fast/canvas/webgl/resources/webgl-test-utils.js"> </script> | |
| <script> | |
| var wtu = WebGLTestUtils; | |
| var gl; | |
| var canvas; | |
| window.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); | |
| if (window.initNonKhronosFramework) | |
| window.initNonKhronosFramework(false); | |
| debug("Checks that failing to allocate the default framebuffer storage after a resize loses the context. The storage is allocated when the default framebuffer is first used after the resize."); | |
| debug("NOTE: This only passes in the test harness because it requires Internals."); | |
| debug(""); | |
| function makeCanvas() { | |
| let canvas = document.createElement("canvas"); | |
| canvas.width = 20; | |
| canvas.height = 20; | |
| return canvas; | |
| } | |
| async function webGLContextLostOrTimeout(canvas) | |
| { | |
| return new Promise(resolve => { | |
| canvas.addEventListener("webglcontextlost", () => resolve(true)); | |
| setTimeout(() => resolve(false), 2000); | |
| }); | |
| } | |
| function releaseContext() { | |
| canvas = null; | |
| gl = null; | |
| gc(); | |
| } | |
| async function testAllocationFailure(contextType, event, attributes) { | |
| debug(""); | |
| debug(`Test ${contextType} ${event} ${JSON.stringify(attributes)}.`); | |
| releaseContext(); | |
| canvas = makeCanvas(); | |
| gl = canvas.getContext(contextType, attributes); | |
| shouldBeTrue("!!gl"); | |
| shouldBe("gl.getError()", "gl.NO_ERROR"); | |
| let lost = webGLContextLostOrTimeout(canvas); | |
| window.internals.simulateEventForWebGLContext(event, gl); | |
| canvas.width = 30; | |
| // The resize only sets the size. The storage is allocated when the default framebuffer is used. | |
| shouldBeFalse("gl.isContextLost()"); | |
| shouldBe("gl.drawingBufferWidth", "30"); | |
| // A failure in the GPU process is observed asynchronously. | |
| gl.clear(gl.COLOR_BUFFER_BIT); | |
| if (!await lost) | |
| testFailed("webglcontextlost was not dispatched."); | |
| shouldBeTrue("gl.isContextLost()"); | |
| shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL"); | |
| shouldBe("gl.getError()", "gl.NO_ERROR"); | |
| } | |
| async function testPendingErrorPreservedOverResize(contextType, attributes) { | |
| debug(""); | |
| debug(`Test ${contextType} pending error is preserved over a successful resize ${JSON.stringify(attributes)}.`); | |
| releaseContext(); | |
| canvas = makeCanvas(); | |
| gl = canvas.getContext(contextType, attributes); | |
| shouldBeTrue("!!gl"); | |
| gl.bindBuffer(0x1234, null); | |
| canvas.width = 30; | |
| shouldBeFalse("gl.isContextLost()"); | |
| shouldBe("gl.drawingBufferWidth", "30"); | |
| // The resize is applied at the clear. | |
| gl.clearColor(0, 1, 0, 1); | |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); | |
| shouldBe("gl.getError()", "gl.INVALID_ENUM"); | |
| shouldBe("gl.getError()", "gl.NO_ERROR"); | |
| wtu.checkCanvasRect(gl, 0, 0, 30, 20, [0, 255, 0, 255]); | |
| } | |
| // Each entry selects which default framebuffer storage allocation is the first renderbuffer allocation | |
| // done in the resize, i.e. the one RenderbufferAllocationFailure fails. | |
| const renderbufferAllocationCases = [ | |
| { antialias: true, depth: false, stencil: false }, // Multisampled color. | |
| { antialias: false, preserveDrawingBuffer: true, depth: false, stencil: false }, // Single-sampled color. | |
| { antialias: false, depth: true, stencil: false }, // Depth. | |
| { antialias: false, depth: false, stencil: true }, // Stencil. | |
| { antialias: false, depth: true, stencil: true }, // Depth-stencil. | |
| ]; | |
| async function runTest() { | |
| if (!window.internals) { | |
| testFailed("Test requires Internals."); | |
| finishTest(); | |
| return; | |
| } | |
| for (const contextType of ["webgl", "webgl2"]) { | |
| await testAllocationFailure(contextType, "DisplayBufferAllocationFailure", { antialias: false }); | |
| await testAllocationFailure(contextType, "DisplayBufferAllocationFailure", { antialias: true, depth: true, stencil: true }); | |
| for (const attributes of renderbufferAllocationCases) | |
| await testAllocationFailure(contextType, "RenderbufferAllocationFailure", attributes); | |
| await testPendingErrorPreservedOverResize(contextType, { antialias: false, depth: false, stencil: false }); | |
| await testPendingErrorPreservedOverResize(contextType, { antialias: true, depth: true, stencil: true }); | |
| } | |
| releaseContext(); | |
| finishTest(); | |
| } | |
| runTest(); | |
| var successfullyParsed = true; | |
| </script> | |
| <body> | |
| </body> |