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
|
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Check for contextlost/restored events after GPU process restart</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="512" height="512"></canvas>
<script type="application/javascript">
function waitRAF() {
return new Promise((resolve, reject) => {
window.requestAnimationFrame(resolve);
});
}
async function restartGPUProcess() {
return await SpecialPowers.spawnChrome([], async () => {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
if (gfxInfo.usingGPUProcess) {
const { TestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TestUtils.sys.mjs"
);
let promise = TestUtils.topicObserved("compositor-reinitialized");
const remoteCanvas = gfxInfo.usingRemoteCanvas;
const acceleratedCanvas = gfxInfo.usingAcceleratedCanvas;
ok(true, "Restarting GPU process, remote canvas " + remoteCanvas + ", accelerated canvas " + acceleratedCanvas);
gfxInfo.killGPUProcessForTests();
await promise;
return remoteCanvas || acceleratedCanvas;
}
ok(true, "Not using GPU process");
return false;
});
}
const canvas = document.getElementById("c");
const context = canvas.getContext("2d");
let restoredPromiseResolve;
let restoredPromiseReject;
const restoredPromise = new Promise((resolve, reject) => {
restoredPromiseResolve = resolve;
restoredPromiseReject = reject;
});
let countLostEvents = 0;
let countRestoredEvents = 0;
function onContextLost() {
ok(context.isContextLost(), "Canvas context should be lost during contextlost event");
try {
let transform = context.getTransform();
ok(transform.isIdentity, "Canvas context should return identity transform while context lost");
} catch (e) {}
countLostEvents += 1;
}
function onContextRestored() {
ok(!context.isContextLost(), "Canvas context should not be lost during contextrestored event");
countRestoredEvents += 1;
restoredPromiseResolve(true);
}
function waitContextRestored() {
let timeoutId = window.setTimeout(restoredPromiseReject, 5000);
return restoredPromise.then(() => {
window.clearTimeout(timeoutId);
});
}
async function start() {
try {
canvas.addEventListener("contextlost", onContextLost);
canvas.addEventListener("contextrestored", onContextRestored);
ok(!context.isContextLost(), "Canvas context should not be lost before initial fill");
context.fillStyle = 'red';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost after initial fill");
let transform = context.getTransform();
ok(transform.isIdentity, "Canvas context should default to identity transform");
context.setTransform(2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
transform = context.getTransform();
ok(!transform.isIdentity, "Canvas context should have non-identity transform");
const restarted = await restartGPUProcess();
const expectedEvents = restarted ? 1 : 0;
if (expectedEvents) {
await waitContextRestored();
}
await waitRAF();
is(countLostEvents, expectedEvents, "Should have fired " + expectedEvents + " contextlost events");
is(countRestoredEvents, expectedEvents, "Should have fired " + expectedEvents + " contextrestored events");
ok(!context.isContextLost(), "Canvas context should not be lost after restoration");
context.fillStyle = 'green';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost at completion");
} catch (err) {
ok(false, "Caught exception " + err);
} finally {
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Wait for failure condition");
start();
</script>
</body>
</html>
|