blob: 64ff16c0619b6e5dba15c13ef59485ea627a82fe [file] [edit]
<!DOCTYPE html><!-- webkit-test-runner [ WebGLTimerQueriesEnabled=true ] -->
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="resources/webgl_test_files/resources/js-test-style.css"/>
<script src="resources/webgl_test_files/js/js-test-pre.js"></script>
<script src="resources/webgl_test_files/js/webgl-test-utils.js"></script>
</head>
<body onload="runTest()">
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description("Tests that query context loss and restore behavior");
const wtu = WebGLTestUtils;
var gl;
var query;
var lostQuery;
var newQuery;
function waitForEvent(target, eventName, handler) {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Timed out waiting for " + eventName)), 5000);
target.addEventListener(eventName, (e) => {
if (handler)
handler(e);
resolve(e);
}, { once: true });
});
}
async function testWebGL1TimerQuery(queryTarget, queryTargetName) {
debug(`Running test: contextType: webgl, queryTarget: ${queryTargetName}`);
const canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
gl = wtu.create3DContext(canvas);
if (!gl) {
testFailed("Could not create webgl context");
return;
}
const WEBGL_lose_context = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
if (!WEBGL_lose_context) {
testPassed("WEBGL_lose_context not available, skipping");
return;
}
let ext = gl.getExtension("EXT_disjoint_timer_query");
if (!ext) {
testPassed("EXT_disjoint_timer_query not available, skipping");
return;
}
query = ext.createQueryEXT();
shouldBeNonNull("query");
if (queryTarget == ext.TIME_ELAPSED_EXT) {
ext.beginQueryEXT(queryTarget, query);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `beginQueryEXT(${queryTargetName}) should succeed`);
} else {
ext.queryCounterEXT(query, queryTarget);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `queryCounterEXT(${queryTargetName}) should succeed`);
}
const weakQuery = new WeakRef(query);
query = null;
const contextLostPromise = waitForEvent(canvas, "webglcontextlost", (e) => e.preventDefault());
WEBGL_lose_context.loseContext();
await contextLostPromise;
shouldBeTrue("gl.isContextLost()");
lostQuery = ext.createQueryEXT();
shouldBeNonNull("lostQuery");
ext = null;
if (window.GCController)
GCController.collect();
else if (window.gc)
gc();
await new Promise(resolve => setTimeout(resolve, 0));
if (window.GCController)
GCController.collect();
else if (window.gc)
gc();
await new Promise(resolve => setTimeout(resolve, 0));
if (weakQuery.deref() === undefined)
testPassed("Active query was collected after context loss");
else
testFailed("Active query should have been collected after context loss but is still alive");
const contextRestoredPromise = waitForEvent(canvas, "webglcontextrestored");
await new Promise(resolve => setTimeout(resolve, 0));
WEBGL_lose_context.restoreContext();
await contextRestoredPromise;
shouldBeFalse("gl.isContextLost()");
ext = gl.getExtension("EXT_disjoint_timer_query");
if (!ext) {
testFailed("Could not re-enable EXT_disjoint_timer_query after restore");
return;
}
newQuery = ext.createQueryEXT();
shouldBeNonNull("newQuery");
if (queryTarget == ext.TIME_ELAPSED_EXT) {
ext.beginQueryEXT(queryTarget, newQuery);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `beginQueryEXT(${queryTargetName}) with new query should succeed after restore`);
ext.endQueryEXT(queryTarget);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `endQueryEXT(${queryTargetName}) should succeed`);
} else {
ext.queryCounterEXT(newQuery, queryTarget);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `queryCounterEXT(${queryTargetName}) with new query should succeed after restore`);
}
}
async function testWebGL2Query(queryTarget, queryTargetName, requiresExtension) {
debug(`Running test: contextType: webgl2, queryTarget: ${queryTargetName}`);
const canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
gl = wtu.create3DContext(canvas, undefined, 2);
if (!gl) {
testFailed("Could not create webgl2 context");
return;
}
const WEBGL_lose_context = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
if (!WEBGL_lose_context) {
testPassed("WEBGL_lose_context not available, skipping");
return;
}
if (requiresExtension) {
const ext = gl.getExtension(requiresExtension);
if (!ext) {
testPassed(`${requiresExtension} not available, skipping`);
return;
}
}
query = gl.createQuery();
shouldBeNonNull("query");
gl.beginQuery(queryTarget, query);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `beginQuery(${queryTargetName}) should succeed`);
const weakQuery = new WeakRef(query);
query = null;
const contextLostPromise = waitForEvent(canvas, "webglcontextlost", (e) => e.preventDefault());
WEBGL_lose_context.loseContext();
await contextLostPromise;
shouldBeTrue("gl.isContextLost()");
lostQuery = gl.createQuery();
shouldBeNonNull("lostQuery");
if (window.GCController)
GCController.collect();
else if (window.gc)
gc();
await new Promise(resolve => setTimeout(resolve, 0));
if (window.GCController)
GCController.collect();
else if (window.gc)
gc();
await new Promise(resolve => setTimeout(resolve, 0));
if (weakQuery.deref() === undefined)
testPassed(`Active ${queryTargetName} query was collected after context loss`);
else
testFailed(`Active ${queryTargetName} query should have been collected after context loss but is still alive`);
const contextRestoredPromise = waitForEvent(canvas, "webglcontextrestored");
await new Promise(resolve => setTimeout(resolve, 0));
WEBGL_lose_context.restoreContext();
await contextRestoredPromise;
shouldBeFalse("gl.isContextLost()");
if (requiresExtension) {
const ext = gl.getExtension(requiresExtension);
if (!ext) {
testFailed(`Could not re-enable ${requiresExtension} after restore`);
return;
}
}
newQuery = gl.createQuery();
shouldBeNonNull("newQuery");
gl.beginQuery(queryTarget, newQuery);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `beginQuery(${queryTargetName}) with new query should succeed after restore`);
gl.endQuery(queryTarget);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `endQuery(${queryTargetName}) should succeed`);
}
var WebGL1QueryTargets = {
TIME_ELAPSED_EXT : 0x88BF,
TIMESTAMP_EXT : 0x8E28,
};
var WebGL2QueryTargets = {
ANY_SAMPLES_PASSED : 0x8C2F,
ANY_SAMPLES_PASSED_CONSERVATIVE : 0x8D6A,
TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN : 0x8C88,
TIME_ELAPSED_EXT : 0x88BF,
};
async function runTest() {
await testWebGL1TimerQuery(WebGL1QueryTargets.TIME_ELAPSED_EXT, "TIME_ELAPSED_EXT");
await testWebGL1TimerQuery(WebGL1QueryTargets.TIMESTAMP_EXT, "TIMESTAMP_EXT");
await testWebGL2Query(WebGL2QueryTargets.ANY_SAMPLES_PASSED, "ANY_SAMPLES_PASSED", null);
await testWebGL2Query(WebGL2QueryTargets.ANY_SAMPLES_PASSED_CONSERVATIVE, "ANY_SAMPLES_PASSED_CONSERVATIVE", null);
await testWebGL2Query(WebGL2QueryTargets.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN", null);
await testWebGL2Query(WebGL2QueryTargets.TIME_ELAPSED_EXT, "TIME_ELAPSED_EXT", "EXT_disjoint_timer_query_webgl2");
finishTest();
}
</script>
</body>
</html>