JTalton's picture

Multithreaded OpenGL

I had an inquiry about my GTK GLWidget supporting OpenGL calls from a second thread. I had been under the assumption that OpenGL calls always had to be made on the main thread. The person who made the inquiry said that they got the OpenTK GLControl to work fine from a second thread.

I did some looking and found the following blog about how to get multithreaded OpenGL calls working on different platforms:

Has anyone played with this much?

In my code I am currently using two queues, one for CPU tasks and one for GPU tasks. I spawn threads that handle the CPU tasks and the main thread handles any GPU tasks. I am wondering if creating GL objects on the separate threads and then rendering them on the main thread would be better. The problem there is that OpenGL is asynchronous and you have to do a glFlush to make sure the objects have actually been created, and the glFlush can add extra overhead.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Delegating GPU tasks to a secondary shared context should result in better performance - in theory. Unfortunately, it's one of those dark parts that depend on the driver, the phase of the moon and the profiler.

For example, Nvidia used to have a "multithreaded" option in their drivers - did that play a role on such optimizations? I've seen people mention that some drivers use global locks that cause all contexts to wait when one is executing specific tasks (I think he was talking about uploading textures). It's also likely that workstation-class video cards are better tuned for such scenarios compared to gaming cards.

The question is, are there any tasks that can be done without using GL.Flush? One idea would be to load textures mipmap by mipmap, lowest ones first - unfortunately I don't think this is possible in GL2. Another idea is to go the other way round: skip rendering for objects that aren't fully loaded yet, instead of waiting for them to load. This could create a smoother user-experience at the expense of slight visual glitches (the Unreal3 and the GTA3+ engine seem to do something similar).

It's one of those things that take experimentation to get right, but can potentially yield big benefits.

martinsm's picture

One idea would be to load textures mipmap by mipmap, lowest ones first - unfortunately I don't think this is possible in GL2.
Yes, it is possible. In main thread you map pixel buffer (using GL_ARB_pixelbuffer_object) thus getting raw pointer. This pointer you pass to worker thread to fill up (by decompessing jpeg for example). And after that in main thread just unmap pointer and call glTexSubImage2D.


the Fiddler's picture

Thanks for the link. The discussion didn't quite cover this, but is it possible to fill the mipmap pyramid from the top? (smallest mipmap first) I've always thought you need to specify the bottom (largest) mipmap before moving to the smaller ones.

martinsm's picture

Dunno, never needed such thing (usually I set GENERATE_MIPMAP_SGIS texture paramater to GL_TRUE when uploading level 0).

I think when you allocate texture data (glTexImage2D with NULL value in pixels argument) then OpenGL automatically allocates memory for all mipmap levels. So maybe it would be possible to fill mipmap levels in any order after that.