EXT_disjoint_timer_query_webgl2
WebGL working group (public_webgl 'at' khronos.org)
Contributors to ARB_occlusion_query
Contributors to EXT_timer_query
Contributors to ARB_timer_query
Ben Vanik, Google Inc.
Daniel Koch, TransGaming Inc.
Florian Boesch (pyalot 'at' gmail.com)
Members of the WebGL working group
Last modified date: June 01, 2023
Revision: 4
WebGL extension #33
Written against the WebGL API 2.0 specification.
This extension exposes the EXT_disjoint_timer_query functionality to WebGL.
The following WebGL-specific behavioral changes apply:
Consult the above extension for documentation, issues and new functions and enumerants.
When this extension is enabled:
[Exposed=(Window,Worker), LegacyNoInterfaceObject]
interface EXT_disjoint_timer_query_webgl2 {
const GLenum QUERY_COUNTER_BITS_EXT = 0x8864;
const GLenum TIME_ELAPSED_EXT = 0x88BF;
const GLenum TIMESTAMP_EXT = 0x8E28;
const GLenum GPU_DISJOINT_EXT = 0x8FBB;
undefined queryCounterEXT(WebGLQuery query, GLenum target);
};
If query was generated by a different
WebGL2RenderingContext than this one, generates
an INVALID_OPERATION error.
target accepts TIMESTAMP_EXT.
target accepts TIME_ELAPSED_EXT.
target accepts TIME_ELAPSED_EXT.
target and pname accept the following combinations of
parameters. The return type of this method now depends on the parameter queried.
| target | pname | returned type |
|---|---|---|
| TIME_ELAPSED_EXT | CURRENT_QUERY | WebGLQuery? |
| TIMESTAMP_EXT | CURRENT_QUERY | null |
| TIME_ELAPSED_EXT | QUERY_COUNTER_BITS_EXT | GLint |
| TIMESTAMP_EXT | QUERY_COUNTER_BITS_EXT | GLint |
pname accepts TIMESTAMP_EXT or GPU_DISJOINT_EXT.
| pname | returned type |
|---|---|
| TIMESTAMP_EXT | GLuint64 |
| GPU_DISJOINT_EXT | boolean |
// Example (1) -- uses beginQuery/endQuery.
let ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
let query = gl.createQuery();
gl.beginQuery(ext.TIME_ELAPSED_EXT, query);
// Draw object
gl.drawElements(...);
gl.endQuery(ext.TIME_ELAPSED_EXT);
// ...at some point in the future, after returning control to the browser and being called again:
// (Note that this code might be called multiple times)
if (query) {
let available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
let disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (available && !disjoint) {
// See how much time the rendering of the object took in nanoseconds.
let timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
// Do something useful with the time. Note that care should be
// taken to use all significant bits of the result, not just the
// least significant 32 bits.
adjustObjectLODBasedOnDrawTime(timeElapsed);
}
if (available || disjoint) {
// Clean up the query object.
gl.deleteQuery(query);
// Don't re-enter this polling loop.
query = null;
}
}
//----------------------------------------------------------------------
// Example (2) -- same as the example above, but uses queryCounterEXT instead.
let ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
let startQuery = gl.createQuery();
let endQuery = gl.createQuery();
ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
// Draw object
gl.drawElements(...);
ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
// ...at some point in the future, after returning control to the browser and being called again:
// (Note that this code might be called multiple times)
if (startQuery) {
let available = gl.getQueryParameter(endQuery, gl.QUERY_RESULT_AVAILABLE);
let disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (available && !disjoint) {
// See how much time the rendering of the object took in nanoseconds.
let timeStart = gl.getQueryParameter(startQuery, gl.QUERY_RESULT);
let timeEnd = gl.getQueryParameter(endQuery, gl.QUERY_RESULT);
// Do something useful with the time. Note that care should be
// taken to use all significant bits of the result, not just the
// least significant 32 bits.
adjustObjectLODBasedOnDrawTime(timeEnd - timeStart);
}
if (available || disjoint) {
// Clean up the query objects.
gl.deleteQuery(startQuery);
gl.deleteQuery(endQuery);
// Don't re-enter this polling loop.
startQuery = null;
endQuery = null;
}
}
//----------------------------------------------------------------------
// Example (3) -- check the number of timestamp bits to determine how to best
// measure elapsed time.
let ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
let timeElapsedQuery;
let startQuery;
let endQuery;
let useTimestamps = false;
if (gl.getQuery(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) > 0) {
useTimestamps = true;
}
// Clear the disjoint state before starting to work with queries to increase
// the chances that the results will be valid.
gl.getParameter(ext.GPU_DISJOINT_EXT);
if (useTimestamps) {
startQuery = gl.createQuery();
endQuery = gl.createQuery();
ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
} else {
timeElapsedQuery = gl.createQuery();
gl.beginQuery(ext.TIME_ELAPSED_EXT, timeElapsedQuery);
}
// Draw object
gl.drawElements(...);
if (useTimestamps) {
ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
} else {
gl.endQuery(ext.TIME_ELAPSED_EXT);
}
// ...at some point in the future, after returning control to the browser and being called again:
// (Note that this code might be called multiple times)
if (startQuery || endQuery || timeElapsedQuery) {
let disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
let available;
if (disjoint) {
// Have to redo all of the measurements.
} else {
if (useTimestamps) {
available = gl.getQueryParameter(endQuery, gl.QUERY_RESULT_AVAILABLE);
} else {
available = gl.getQueryParameter(timeElapsedQuery, gl.QUERY_RESULT_AVAILABLE);
}
if (available) {
let timeElapsed;
if (useTimestamps) {
// See how much time the rendering of the object took in nanoseconds.
let timeStart = gl.getQueryParameter(startQuery, gl.QUERY_RESULT);
let timeEnd = gl.getQueryParameter(endQuery, gl.QUERY_RESULT);
timeElapsed = timeEnd - timeStart;
} else {
timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
}
// Do something useful with the time. Note that care should be
// taken to use all significant bits of the result, not just the
// least significant 32 bits.
adjustObjectLODBasedOnDrawTime(timeElapsed);
}
}
if (available || disjoint) {
// Clean up the query objects.
if (useTimestamps) {
gl.deleteQuery(startQuery);
gl.deleteQuery(endQuery);
// Don't re-enter the polling loop above.
startQuery = null;
endQuery = null;
} else {
gl.deleteQuery(timeElapsedQuery);
// Don't re-enter the polling loop above.
timeElapsedQuery = null;
}
}
}
Revision 1, 2016/09/30
Revision 2, 2016/10/11
Revision 3, 2021/04/01
Revision 4, 2023/06/01