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 10 of 11

Thread: SwapBuffers() in another thread

Hybrid View

  1. #1
    Junior Member Regular Contributor
    Join Date
    Aug 2003
    Location
    Toronto, Canada
    Posts
    159

    SwapBuffers() in another thread

    I know, I know. This is a topic that has been discussed a lot. I've never seen a solution suggested like the one I'm trying to do though, so bare with me.

    In the past I did all the GL calls and SwapBuffers() calls in a single thread and everything was great. However my windows were actually created in another thread so that all the windows event and the message pump is handled by that other thread.
    When Kepler cards came along under certain conditions (certain Quadro profiles + Mosaic) my SwapBuffers() calls would hang. Nvidia told me this was because DeviceContexts are actually thread-affine, and GDI functions should only be called on them in the threads that created them. Quote from Nvidia "Calling GDI functions using an HDC from the non-hdc-affine thread has always been wrong (OpenGL is a GDI api and GDI objects like HDCs are thread-affine), but the failure cases are in general hard to repro."

    So I moved my SwapBuffers() to the window's thread with it's own GL context, and using GLsync objects and a renderbuffer I do all my rendering in the main thread still, and blit a framebuffer onto the DeviceContext before doing the SwapBuffers() in the window's threads. This works, but seems to have a large performance impact.

    My new idea is to actually only do the SwapBuffers() in the window's thread, and not have a 2nd GL context at all. My theory is that since SwapBuffers() is actually a GDI function, and doesn't care about GL at all.
    So I've tried it out and it actually works. I now do all my rendering in my main thread with a single context, including blitting the final image to the DC, then I call SwapBuffers() from the window's thread. No GL context is ever made current in the window's thread. I had update issues to start, but as a test I used glFinish before I sent the message to the window's thread telling it to swap the buffers, and the update issues went away, which makes sense.

    The question is:
    1. Am I just lucky that this is working, and will it not work on other random drivers/GPUs?
    2. How do I properly synchronize this method, so SwapBuffers() happens after the blit is finished, and I don't start blitting before the previous SwapBuffers() has finished? Since I don't have a 2nd GL context in the window's thread I can't use GLsync objects there, although I can use them in the main thread. For the 2nd part, will attempting to blit to the DC from the main thread implicitly synchronize with the SwapBuffers()?

    Thoughts? I'm also asking Nvidia this and will respond with anything they give me.

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    1,104
    I don't quite understand your original problem. I create all my windows in the main thread but create their OpenGL context in the render thread. I handle the GUI events in the main thread and the rendering in the render thread.

    As for you questions, I don't know the answer to the first and without a glFinish or GLsyn how you can know when to issue the swap.

  3. #3
    Junior Member Regular Contributor
    Join Date
    Aug 2003
    Location
    Toronto, Canada
    Posts
    159
    I do something similar to you, but not quite. It works, but the performance is far worse than if 100% of the OpenGL calls occur in a single thread. (22 fps vs. 30 fps in one sample file I have)

  4. #4
    Senior Member OpenGL Pro
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    1,104
    All my calls are in 1 thread. In the render thread, each timestep, I loop through each window calling its render function. In fact we only render a window if some data has changed.

    My pseudo code is like this

    Code :
    GUI thread
     
    check for mouse event (or keyboard etc)
     
    update camera or other data for that window
    flag window as dirty
     
    loop
     
    Render Thread
     
    Is is time to render? 
     
    for each window
      has something changed?, yes render
     
    loop

  5. #5
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    474
    Quote Originally Posted by MalcolmB View Post
    2. How do I properly synchronize this method, so SwapBuffers() happens after the blit is finished, and I don't start blitting before the previous SwapBuffers() has finished?
    Use a synchronisation object such as an event object or a condition variable. After the rendering thread has sent the message to the main thread, it should wait upon the object. The main thread should signal the object after SwapBuffers() has completed.

  6. #6
    Junior Member Regular Contributor
    Join Date
    Aug 2003
    Location
    Toronto, Canada
    Posts
    159
    tonyo_au : Which thread does the swap buffers occur in for each window? If it's in the Render Thread then that is *technically* illegal according to Nvidia, although I've only ever found one case where it doesn't work. However since this particular case matters to me I need to have a solution that has the SwapBuffers() occur in your equivalent of the 'GUI thread'.

    GClements : Is it guaranteed that the buffer swap will have occurred when that function returns? Or is it possible it'll happen sometime later in the driver's thread? If it's guaranteed then yes your suggestion is the solution. I'll try it out and see if anomalies show up. Thanks

  7. #7
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    474
    Quote Originally Posted by MalcolmB View Post
    Is it guaranteed that the buffer swap will have occurred when that function returns?
    I suppose it depends upon what you mean by "occurred".

    It's implicit that any rendering commands performed after SwapBuffers() will occur on a different buffer to those performed before it (assuming that the context isn't single-buffered). If triple-buffering is enabled, the previous back buffer won't necessarily be displayed immediately, but it shouldn't be affected by subsequent rendering commands.

    However: I suppose that it's possible that the assignment of front/back buffers is per device context, in which case there's no guarantee that calling SwapBuffers() for one device context will necessarily swap them for another device context, let alone synchronously.

    Also, the comment about not using a device context from a thread other than the one which created it contradicts what Microsoft sayshere, which is that device contexts can be shared between threads so long as access is synchronised.

  8. #8
    Junior Member Regular Contributor
    Join Date
    Aug 2003
    Location
    Toronto, Canada
    Posts
    159
    Yes, the requirement given from that Nvidia dev surprised me also, and does seem to contradict that article and other articles I've found. Trying to get reconfirmation of this from them, but I'm deferring to them for now.

    So far my tests with this new solution have been positive. My performance is back up on par with the fully single threaded solution for the test cases I've tried, and I haven't seen any visual artifacts yet. I'm doing SwapBuffers() in the window's thread, with no GL context used at all. Still need to use a high speed camera to ensure all my frames are getting shown on the display correctly. Need to test this on more GPUs/driver versions also.

  9. #9
    Senior Member OpenGL Pro
    Join Date
    Jan 2012
    Location
    Australia
    Posts
    1,104
    Which thread does the swap buffers occur in for each window?


    I swap in the render thread. Are you saying on 600 series nVidia cards this will fail? I have been using this code for a couple of years on a range of ATI and nVidia cards but I don't have any 600 cards.

    What card is causing the problem?
    Last edited by tonyo_au; 07-12-2013 at 07:49 PM.

Posting Permissions

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