<html>
<head>
<script type="text/javascript">
var canvas;
var w, h;
var gl;
var extension;
function testHorizontalBands() {
gl.enable(gl.SCISSOR_TEST);
gl.clearColor(1, 0, 0, 1);
gl.scissor(0, 0, w, h/2);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.clearColor(0, 1, 0, 1);
gl.scissor(0, h/2, w, h/2);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.SCISSOR_TEST);
var size = w * h * 4;
var array = new Uint8Array(size);
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, array);
return array[0] == 255 && array[1] == 0 &&
array[size - 4] == 0 && array[size - 3] == 255;
}
function testContextLost(e) {
e.preventDefault();
if (extension) {
setTimeout(function() {
extension.restoreContext();
extension = null;
}, 0);
}
}
function testContextRestored() {
gl = canvas.getContext("experimental-webgl");
if (!gl || gl.isContextLost()) {
// Might just be blocked because of infobar.
return;
}
gl.clearColor(0, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var a = new Uint8Array(w * h * 4);
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, a);
if (a[0] == 0 && a[1] == 0 && a[2] == 255)
window.domAutomationController.send("SUCCESS");
else
window.domAutomationController.send("FAILED");
}
function testQuantityLoss() {
var count = 0;
var iterations = 128;
var garbageCanvases = [];
function createAndDiscardContext() {
count++;
var c = document.createElement("canvas");
c.width = 1;
c.height = 1;
garbageCanvases.push(c);
var ctx = c.getContext("experimental-webgl");
if (!ctx) {
console.log("Failed to fetch WebGL context number " + count);
window.domAutomationController.send("LOADED");
window.domAutomationController.send("FAILED");
return false;
}
ctx.clear(gl.COLOR_BUFFER_BIT);
if (count < iterations) {
window.requestAnimationFrame(createAndDiscardContext);
} else {
// Remove the references to the garbage canvases, then attempt to trigger
// a garbage collect.
garbageCanvases = null;
window.domAutomationController.send("LOADED");
// Trying to provoke garbage collection through excessive allocations.
setInterval(function() {
var garbageArray = new Uint8Array(1024 * 1024);
garbageArray[0] = 255;
}, 10);
}
};
createAndDiscardContext();
}
function getLoseContextExtension()
{
return gl.getExtension("WEBKIT_WEBGL_lose_context") ||
gl.getExtension("WEBGL_lose_context");
}
function loseContextUsingExtension()
{
getLoseContextExtension().loseContext();
// Report success at the next frame to give the compositor a chance to draw
// using the lost context.
window.requestAnimationFrame(function() {
window.domAutomationController.send("SUCCESS");
});
}
function contextLostTest(kind)
{
switch (kind) {
case "WEBGL_lose_context": {
extension = getLoseContextExtension();
extension.loseContext();
break;
}
case "kill":
// nothing -- the browser test navigates to about:gpucrash and kills
// the GPU process.
break;
case "kill_after_notification":
// The browser test waits for notification from the page that it
// has been loaded before navigating to about:gpucrash.
window.domAutomationController.send("LOADED");
break;
case "forced_quantity_loss":
// Test creates many new contexts, forcing the original context to be
// lost. Then a garbage collect is triggered and the original context is
// watched to ensure it restores properly.
testQuantityLoss();
break;
}
}
function onLoad() {
canvas = document.getElementById("canvas1");
w = canvas.width;
h = canvas.height;
if (!canvas)
return;
canvas.addEventListener("webglcontextlost", testContextLost, false);
canvas.addEventListener("webglcontextrestored", testContextRestored, false);
gl = canvas.getContext("experimental-webgl");
if (!gl)
return;
if (!testHorizontalBands())
return;
const query = new URLSearchParams(window.location.search).get('query');
if (query)
contextLostTest(query);
}
</script>
</head>
<body onload="onLoad()">
<canvas id="canvas1" width="16px" height="32px">
</canvas>
</body>
</html>