I am working on a webgl2 app that renders using the webgl.drawArrays() function. It seems that this is an asynchronous function. I need to be able to get it to render synchronously, or at least be able to detect somehow when it finishes updating its output buffer (on or off screen). I'm trying to use the EXT_disjoint_timer_query_webgl2 extension to do this, as described in...
https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query_webgl2/
Here is my code...
// EXT_disjoint_timer_query_webgl2
const ext = gWebGL.getExtension('EXT_disjoint_timer_query_webgl2');
const query = gWebGL.createQuery();
gWebGL.beginQuery(ext.TIME_ELAPSED_EXT, query);
/* Draw the triangle. */
gWebGL.drawArrays(gWebGL.TRIANGLE_STRIP, 0, 4);
// EXT_disjoint_timer_query_webgl2
gWebGL.endQuery(ext.TIME_ELAPSED_EXT);
// EXT_disjoint_timer_query_webgl2
let available = gWebGL.getQueryParameter(query, gWebGL.QUERY_RESULT_AVAILABLE);
let disjoint = gWebGL.getParameter(ext.GPU_DISJOINT_EXT);
while(!available)
available = gWebGL.getQueryParameter(query, gWebGL.QUERY_RESULT_AVAILABLE);
if (available && !disjoint) {
// See how much time the rendering of the object took in nanoseconds.
let timeElapsed = gl.getQueryParameter(query, gWebGL.QUERY_RESULT);
console.log(timeElapsed);
}
When I run this the 'available' variable is always false. It never becomes true. What am I doing wrong?
If there is another way to get drawArrays() (or similar function) to render synchronously, that would be ok too.
I should note that this is for an event driven scientific application, not a game with a render loop. The requestAnimationFrame() function is not useful to me.
Thanks for any help.
This is an infinite loop, because according to the WebGL specification
and
So you have to call
setTimeout,setInterval,requestAnimationFrame, or something similar to get back the result.You can try
setTimeout, but as the specification says, a simplesetTimeout(()=>{...}, 0)might not be enough.In my experience, in the next frame the result will be available (again, this is not necessarily true), so a single
requestAnimationFramecall should be enough (but in the 2nd frame, you don't callrequestAnimationFrameagain, so there is no render loop).I'm not sure exactly what is the use-case, however, if you want to wait until the drawing of the image is finished (and not until it is displayed on the screen), you have yet another option. You can render into a texture using a framebuffer, (and if you want, you can still render that texture onto the screen). This is a good tutorial about how to render into a texture. The advantage of this method is that after calling
drawArrays, you can use the texture.A bit about the synchronous/asynchronous situation. First of all, none of the WebGL functions use the JavaScript
asyncandawaitkeywords, so in that sense, they are synchronous. However, under the hood, a lot of function calls are executed asynchronously on the GPU. Usually, the OpenGL (WebGL) driver sends a command to the GPU, and it doesn't wait until the GPU finishes the task. However, the API is designed in a way, that it hides this asynchronous behaviour from you. So if you call a WebGL function, after it returns, you can access the related resources, because the driver makes sure, that the commands already finished the time it lets you access.