Search code examples
javascriptwebgl2

WebGLSync is always UNSIGNALED


I'm trying to play around with WebGLSyncs and I'm having a hard time getting a WebGLSync to be signaled.

The following is unsignaled on all browsers supporting WebGL2 (Chrome, Opera, Firefox):

function test() {
    let canvas = document.createElement('canvas');
    let gl = canvas.getContext('webgl2');
    let sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
    gl.flush();
    gl.finish();

    let status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
    console.log(sync, status, status === gl.UNSIGNALED);  // logs "true"
    gl.deleteSync(sync);
}

I'm expecting this to work, since gl.finish() should wait until all GPU commands have been processed - but it looks like the sync fence was not.

I would very much appreciate a minimal, working WebGLSync example that actually gets signaled. I searched GitHub for such but I found nothing.


EDIT

Based on the answer from pleup, I put together this code sample which works fine in my environment (Windows + Chrome).

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function test() {
    let canvas = document.createElement('canvas');
    let gl = canvas.getContext('webgl2');
    let sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
    gl.flush();

    while (gl.getSyncParameter(sync, gl.SYNC_STATUS) === gl.UNSIGNALED) {
        await sleep(100);
    }

    let status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
    console.log(sync, status, status === gl.SIGNALED);
    gl.deleteSync(sync);
}

test()

Solution

  • You have to wait for a tick to see the sync signaled. The sync status will never change during JS execution frame.

    https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14

    In order to ensure consistent behavior across platforms, sync objects may only transition to the signaled state when the user agent's event loop is not executing a task. In other words:

    A sync object must not become signaled until control has returned to the user agent's main loop. Repeatedly fetching a sync object's SYNC_STATUS parameter in a loop, without returning control to the user agent, must always return the same value.