Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Call to glClientWaitSync blocks forever

  1. #1
    Junior Member Newbie
    Join Date
    Feb 2018
    Posts
    8

    Call to glClientWaitSync blocks forever

    Greetings,

    I'm trying to synchronize buffer uploads of a glBufferData call using fences. However, it occasionally happens that the program stops inside the glClientWaitSync function and remains there forever. This is the callstack:

    1 sched_yield syscall-template.S 84 0x7ffff3fcca37
    2 ?? 0x7fffd5259ea4
    3 ?? 0x7fffd4efa083
    4 ?? 0x7fffd4e6dea2
    return ( ::glClientWaitSync ( m_BufferUploadSync, 0, 1 ) == GL_ALREADY_SIGNALED ); // this is to check if the buffer has already uploaded and is probed once per frame.

    This i how the fence is initialized before:

    glBufferData(...)
    m_BufferUploadSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

    It usually happens when I upload/render lots of stuff. Is this normal?

    Regards

  2. #2
    Senior Member OpenGL Lord
    Join Date
    May 2009
    Posts
    6,064
    Did you ever flush the fence? I know you're not doing it in your `glClientWaitSync` call, but you may have explicitly flushed somewhere else.

    Also, if all you want to do is check to see if it completed, use a timeout of 0, not 1.

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,568
    Try adding a glFlush() after your glFenceSync(). Either immediately afterwards (on the same thread of course), or somewhere after that before you expect the glClientWaitSync() to see the completion.

    Because GL calls are queued on a command queue, basically you can end up with a situation where your glFenceSync call was queued but not yet processed by the driver/GPU. Since no other GL commands are getting pushed onto this queue, your FenceSync is "stuck" in the queue.

    The glFlush() says to the driver "get to work on all those commands I've queued, but don't block this CPU thread waiting on it all to finish."

    Ordinarily you don't have to do any manual flushing (when doing double buffered rendering single-thread via a single GL context) because the *SwapBuffers does the only explicit glFlush required -- at the end. With multithread, you have to start thinking about such things.

    For more details, see:

    Last edited by Dark Photon; 02-19-2018 at 08:22 AM.

  4. #4
    Junior Member Regular Contributor
    Join Date
    May 2013
    Posts
    144
    Do I understand it correctly that a status pull of a sync object can block the whole thread just because the command queue is full?

    So basically every time you risk a death lock if you not at last have one flush before or at the status pull?

  5. #5
    Senior Member OpenGL Lord
    Join Date
    May 2009
    Posts
    6,064
    Do I understand it correctly that a status pull of a sync object can block the whole thread just because the command queue is full?
    Yes. This is why the extension, the OpenGL specification, and the Wiki article on sync objects all explicitly warn you about this. This is also why `glClientWaitSync` has the `GL_SYNC_FLUSH_COMMANDS_BIT` flag to begin with.

    The ARB really isn't trying to hide something from you here. It's simply a consequence of the way GPUs have to interact with the CPU.

    If the GPU queue is full when you add a sync, then that sync (and any other commands) have to sit somewhere and be added to the GPU's queue when there's room for it. But since that is a CPU operation, only a CPU process can push the data to the GPU, something has to tell the CPU to actually do it. After all, the driver cannot just hijack the CPU when the GPU gets some queue space.

    `glClientWaitSync` stops the CPU thread from doing things until the GPU has processed something. But since the GPU processing that thing can't happen until the CPU adds more stuff to the GPU queue... oops.

    The only way to remove this from the API would be to make `glFenceSync` implicitly perform a flush. That's like using a sledgehammer to kill a fly; sure, it may work, but the wall the fly is on isn't likely to survive.

    A flush needs to happen. Since this is a performance-critical thing, OpenGL requires that you take care of deciding when that will be.

    So basically every time you risk a death lock if you not at last have one flush before or at the status pull?
    Or you could just use the `GL_SYNC_FLUSH_COMMANDS_BIT`. Which again is why it's there.

    There is no risk if you use use the API correctly.

  6. #6
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    3,002
    Quote Originally Posted by Alfonse Reinheart View Post
    Or you could just use the `GL_SYNC_FLUSH_COMMANDS_BIT`. Which again is why it's there.
    Note that this isn't sufficient if you're using multiple contexts and the glClientWaitSync() is issued for a different context to the glFenceSync(). In that case, you need glFlush() (or something else which is guaranteed to flush the command queue) on the context where the glFenceSync() was issued.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •