blob: b3a2126ecaddca4afcbcca16bb5e7d425345b732 [file] [log] [blame]
commit-queue@webkit.org56a36132022-03-18 12:18:00 +00001<!DOCTYPE html>
2<html>
3<head>
4<meta charset="utf-8">
5<link rel="stylesheet" href="resources/webgl_test_files/resources/js-test-style.css"/>
6<script src="resources/webgl_test_files/js/js-test-pre.js"></script>
7<script src="resources/webgl_test_files/js/webgl-test-utils.js"></script>
8</head>
9<body onload="test()">
10<div id="description"></div>
11<div id="console"></div>
commit-queue@webkit.org70e10862016-04-21 16:38:16 +000012<script>
commit-queue@webkit.org56a36132022-03-18 12:18:00 +000013"use strict";
14description("Test that first losing context, trying to restore it, and then doing something to really lose it does not crash.");
15
16// The test would crash with following sequence:
17// 1. Cause a real context lost. In this test, "gpuStatusFailure".
18// 2. Page would try to restore the context. This would start the restore timer.
19// 3. Before the restore timer fires, really lose the context. In this test, "manyContext".
20// 4. The restore timer would fire, and restore function would use nullptr context.
21
22var wtu = WebGLTestUtils;
23var gl;
24
25async function waitForEvent(element, eventName, timeoutMS)
26{
27 timeoutMS = timeoutMS || 2000;
28 return new Promise((resolve, reject) => {
29 function timeoutHandler() {
30 element.removeEventListener(eventName, handler, { once: true });
31 reject();
32 }
33 const rejectID = setTimeout(timeoutHandler, timeoutMS);
34 function handler(event) {
35 clearTimeout(rejectID);
36 resolve(event);
37 }
38 element.addEventListener(eventName, handler, { once: true });
39 });
commit-queue@webkit.org70e10862016-04-21 16:38:16 +000040}
41
commit-queue@webkit.org56a36132022-03-18 12:18:00 +000042async function waitForWebGLContextRestored(canvas, timeoutMS)
43{
44 await waitForEvent(canvas, "webglcontextrestored", timeoutMS);
45}
46
47async function waitForWebGLContextLostAndRestore(canvas, timeoutMS)
48{
49 let event = await waitForEvent(canvas, "webglcontextlost", timeoutMS);
50 event.preventDefault();
51}
52
53function testDescription(subcase) {
54 return Object.keys(subcase).map((k) => `${k}: ${typeof subcase[k] === "function" ? subcase[k].name : subcase[k]}`).join(", ");
55}
56
57async function runTest(subcase)
58{
59 debug(`Running test: ${testDescription(subcase)}`);
60
61 const canvas = document.createElement("canvas");
62 canvas.width = 1;
63 canvas.height = 1;
64 gl = wtu.create3DContext(canvas);
65 const WEBGL_lose_context = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
66
67 const webglcontextlostandrestore = waitForWebGLContextLostAndRestore(canvas);
68 const webglcontextrestored = waitForWebGLContextRestored(canvas);
69 let expectRestoreIgnored = subcase.loseMethod(gl, WEBGL_lose_context);
70
71 try {
72 await webglcontextlostandrestore;
73 testPassed("Got webglcontextlost and restore was attempted.");
74 wtu.glErrorShouldBe(gl, gl.CONTEXT_LOST_WEBGL);
75 } catch (e) {
76 if (e)
77 throw e;
78 testFailed("Timed out waiting webglcontextlost that would attempt to be restored.");
79 }
80 expectRestoreIgnored = subcase.loseMethod2(gl, WEBGL_lose_context) || expectRestoreIgnored;
81
82 try {
83 await webglcontextrestored;
84 if (expectRestoreIgnored)
85 testFailed("Expected restore be ignored, but it was not.");
86 else
87 shouldBeFalse("gl.isContextLost()");
88 } catch (e) {
89 if (e)
90 throw e;
91 if (!expectRestoreIgnored)
92 testFailed("Did not expect restore be ignored, but it was.");
93 else
94 shouldBeTrue("gl.isContextLost()");
95 }
96
97 wtu.glErrorShouldBe(gl, gl.NO_ERROR);
98}
99
100function loseContext(gl, WEBGL_lose_context)
101{
102 if (!WEBGL_lose_context) {
103 testFailed("Could not find WEBGL_lose_context extension");
104 return;
105 }
106 let wasLost = gl.isContextLost();
107 WEBGL_lose_context.loseContext();
108 if (wasLost)
109 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
110 return true; // Request for restore is ignored.
111}
112
113function manyContexts()
114{
115 // This causes the older contexts to be lost, including the first one we created
116 // for testing.
117 const contexts = []
118 for (let i = 0; i < 50; ++i)
119 contexts.push(document.createElement("canvas").getContext("webgl"));
120 return true; // Request for restore is ignored.
121}
122
123function gpuStatusFailure(gl)
124{
125 internals.simulateEventForWebGLContext("GPUStatusFailure", gl);
126 gl.clear(gl.COLOR_BUFFER_BIT);
127 return true; // Request for restore is honored.
128}
129
130function nothing()
131{
132 return false;
133}
134
135const loseMethods = [loseContext, manyContexts];
136if (window.internals)
137 loseMethods.push(gpuStatusFailure);
138
139const subcases = [];
140for (const loseMethod of loseMethods)
141 for (const loseMethod2 of loseMethods.concat(nothing))
142 subcases.push({loseMethod, loseMethod2});
143
144async function test()
145{
146 for (let subcase of subcases)
147 await runTest(subcase);
148 finishTest();
commit-queue@webkit.org70e10862016-04-21 16:38:16 +0000149}
150</script>
commit-queue@webkit.org56a36132022-03-18 12:18:00 +0000151</body>
152</html>