Forum Discussion

🚨 This forum is archived and read-only. To submit a forum post, please visit our new Developer Forum. 🚨
jspenguin's avatar
jspenguin
Explorer
12 years ago

Asynchronous timewarp - has anyone done it on Windows?

I'm currently working on adding Oculus support to a simple game I started working on years ago but never finished, and I realized that in order to use timewarp to increase the perceived frame rate, it would have to be done asynchronously. I modified my code to use 2 or 3 eye buffers (for double or triple buffering) and moved the calls to ovrHmd_BeginFrame, ovrHmd_EndFrame, etc., to a separate thread - it sits in a loop, waiting until the TimewarpPointSeconds value, then chooses the newest frame from the eye buffers and presents them to the Oculus SDK.

On Linux, this works great. I can enable options that kill the frame rate (such as not doing any visibility calculations and just drawing everything), and I can still look around fairly smoothly.

On Windows, however, doing this completely kills performance - it's worse than just doing it all in one thread. I traced the problem to the Windows SwapBuffer call - if VSync is enabled, it will cause all other OpenGL calls to hang until it returns, even ones that act on a different context. Turning VSync off "fixes" the problem because SwapBuffers returns immediately, but that can cause tearing.

Is there any other workaround for this problem other than disabling VSync?

Just for reference, my video card is an NVidia GTX 570 and the OS is Windows 7.

6 Replies

  • even ones that act on a different context.


    Yikes! :o I've not done anything with threading and OpenGL, but that doesn't sound right.

    Does this apply if the contexts are in separate applications?

    Do you have some minimal code we can test with? It might be a driver thing.
  • I think I've solved it. I played around in the NVidia control panel, and noticed "Threaded Optimization" was set to "auto". Thinking it might help, I tried setting it to "on", but that didn't change anything. However, turning it off solved the problem completely.

    The help string that pops up when you hover over it says "Allows applications to take advantage of multiple CPUs", which is exactly what I'm doing, so I don't know why turning it off helps.

    I guess I'll just have to include documentation for NVidia users to do this if they want asynchronous timewarp.

    EDIT: After reading some documentation, it looks like only functions that call "glGet*" functions will block while SwapBuffers is running. Since my game is quite old, it uses the old fixed-function pipeline and does a lot of crap like glPushAttrib and glPopAttrib. I really should clean out the code and re-write the renderer.
  • I'm glad you figured it out! Hopefully we can find a reliable way to detect it or hint to the nVidia driver that we want the feature off so end users don't need to deal with the setting.
  • I did a little more research into this issue, and it seems that it can be more common if you call any glGet functions, even glGetError. Do you happen to be using something that causes glGetError for debugging purposes a lot?

    Handling the Windows message pump in a non-standard way, such as from multiple threads, also seems to be problematic. This is probably because Windows boosts the priority of your UI thread when you have pending messages.

    Unfortunately I've not found a way to hint the driver that you don't want to get threading optimization, which is rather annoying because it forces us to ask the end user to change the setting. (Or ask for admin rights so we can force it off in the registry - also very unuser-friendly.) Before I hit submit I stumbled upon NVAPI, a fairly recent API from nVidia that allows you to do a lot of special stuff on their graphics cards. It looks like you could change the "Threaded Optimization" setting for just your app with it. Unfortunately, it isn't as simple as a single function call or something. It appears you have to add your app to the user's current profile, which looks fairly involved. The actual setting IDs and values are all in NvApiDriverSettings.h, the "Threaded Optimization" setting is called OGL_THREAD_CONTROL in there.
  • I'd love to do that in Dolphin (wii emulator). But my OpenGL and multi-threading skills aren't up to the task.