<html> <head> <script type="text/javascript"> var canvas; var w, h; var gl; var extension; var alreadySetAutomationId = false; 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 (!alreadySetAutomationId) window.domAutomationController.setAutomationId(1); 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) { 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.setAutomationId(1); alreadySetAutomationId = true; 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 contextLostTest(kind) { switch (kind) { case "WEBGL_lose_context": { extension = gl.getExtension("WEBKIT_WEBGL_lose_context") || gl.getExtension("WEBGL_lose_context"); 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.setAutomationId(1); alreadySetAutomationId = true; 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; var query = /query=(.*)/.exec(window.location.href); if (query) contextLostTest(query[1]); } </script> </head> <body onload="onLoad()"> <canvas id="canvas1" width="16px" height="32px"> </canvas> </body> </html>