1

Looking for some patterns/code examples/best practices of appropriate usage of fences in webgl2 (gl.fenceSync) - best if it would be non blocking of JS thread.

    var fence = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);

    setTimeout(() => {
      gl.clientWaitSync(fence, gl.SYNC_FLUSH_COMMANDS_BIT, 1000000);
      gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, dataOut);
    }, 0);

1 Answers1

2

I'm just guessing to be honest, I'm not actually sure how useful syncs are in WebGL2 but I'd think you don't want to block then the pattern would be like this

function main() {
  const gl = document.createElement('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  
  callbackOnSync(gl, () => {
    console.log("done");
  });
  
  function callbackOnSync(gl, callback) {
    const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
    gl.flush();  // make sure the sync command is read

    setTimeout(checkSync);  

    function checkSync() {
      const timeout = 0;   // 0 = just check the status
      const bitflags = 0;
      const status = gl.clientWaitSync(sync, bitflags, timeout);
      switch (status) {
        case gl.TIMEOUT_EXPIRED:
          // it's not done, check again next time
          return setTimeout(checkSync);
        case gl.WAIT_FAILED:
          throw new Error('should never get here');
        default:
          // it's done!
          gl.deleteSync(sync);

          callback();
      }
    }
  }
}

main();
gman
  • 100,619
  • 31
  • 269
  • 393
  • But as far as Khronos documentation states: "Finish does not return until all effects from previously issued commands on GL client and server state and the framebuffer are fully realized." so using gl.flush() blocks JS in my opinion – user3924684 Feb 03 '19 at 12:22
  • 1
    flush != finish – gman Feb 03 '19 at 12:44
  • clientWaitSync is blocking by definition. You should check getSyncParameter( SYNC_STATUS ) == SIGNALED – pleup Feb 03 '19 at 12:52
  • 2
    read the spec. It is not blocking by definition. From the spec "If the value of timeout is zero, then ClientWaitSync does not block, but simply tests the current state of sync" – gman Feb 03 '19 at 12:52
  • I'm so sorry @gman, mea culpea! :-) Had a quick look on doc and Flush is just next to Finish. Sorry again! – user3924684 Feb 03 '19 at 15:46
  • haha, well, just for fun, [here's a version that counts the number of setTimeouts](https://jsfiddle.net/greggman/6ow8x1da/). The time comes from sizing the canvas. you could add some other commands in there. In any case if you change the flush to a finish you'll notice at least in Chrome there is no difference because finish is a no-op in Chrome. If you change the flush to a `gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4))` which has to block you'll see the count drop to 1. – gman Feb 03 '19 at 15:47