OpenGL and Multi-Threading

F690bff76d56cae6f65fb59b494809ea
0
goruka 101 Feb 21, 2008 at 17:47

Hi! I know that by design OpenGL is not designed for multi threading.
However, I want to ask if some operations are supposed to work.

First of all, is it possible to use OpenGL so while one thread renders polygons and stuff, the other thread allocates and deallocates textures/arrays (that of course are not in use by the rendering thread)?

I know Direct3D can do this fine, but I was wondering if it can be properly done in OpenGL.

Cheers!

10 Replies

Please log in or register to post a reply.

B91eae75cd6245bd8074bd0c3f1cc495
0
Nils_Pipenbrinck 101 Feb 21, 2008 at 18:16

OpenGL is not threadsave by itself.

However, OpenGL does not complain if you call it from multiple threads as long as you make sure that you never have two threads executing OpenGL-functions at the same time. In practice that means, that you have to wrap all your functions that contain OpenGL calls into critical sections / semaphores.

That approach works in practice, but it’s not guaranteed to work on each system.

F690bff76d56cae6f65fb59b494809ea
0
goruka 101 Feb 21, 2008 at 19:03

@Nils Pipenbrinck

OpenGL is not threadsave by itself. That approach works in practice, but it’s not guaranteed to work on each system.

Thanks for the answer! in theory, it seems to me that as long as you lock in the proper moment nothing should happen. Do you think if it works at least in modern PC OpenGL implementations?

B91eae75cd6245bd8074bd0c3f1cc495
0
Nils_Pipenbrinck 101 Feb 21, 2008 at 19:19

@goruka

Thanks for the answer! in theory, it seems to me that as long as you lock in the proper moment nothing should happen. Do you think if it works at least in modern PC OpenGL implementations?

I wouldn’t do it, even if it works on most systems. Who knows - there might be a driver out there which does not like to be called from multiple threads.

Imho the best thing you could do is to have one worker-thread that executes the OpenGL commands based on a simple message structure (a consumer thread9. Other threads can generate messages and pass them to the worker-thread via syncronized access (producer threads).

This may sound like a lot of overhead at first, but your message can be as complex as “render scene”, so it can be very fast. Also you can use OpenGL in a way that you never have to send return values back to the producer-threads. Calls like glGetxxx can often be avoided with a bit of caching, and even glGenTextures is purely optional. You’re free to manage the texture-names yourself. A simple counter is suitable for most applications.

Error-handling will become a challenge though.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Feb 21, 2008 at 19:20

To amplify on Nils’ statement, OpenGL is threadsafe if you use multiple rendering contexts (it has to be, else you couldn’t run two OpenGL apps at the same time!). Of course if you want to have two threads accessing the same rendering context then all the caveats mentioned apply.

B7568a7d781a2ebebe3fa176215ae667
0
Wernaeh 101 Feb 22, 2008 at 09:21

Hey there :)

On a practical note, I have a system up and running which uses several threads with a single OpenGl context (background texture loader, rendering system, and logics system, each of these may call varying GL commands), and I have yet to see any system this causes problems on.

There are a few things you need to be careful with, though:
- Be sure that all your threads always leave the GL system in some definite state (i.e. if the loader thread loads a new texture target, it changes the current binding => your renderer needs to rebind)
- Don’t forget to call wglMakeCurrent once before calling gl commands, that had me stumped for some time (just forgot about that once, and spend weeks debugging my texture loader :) )
- Make sure that you only release your critical section after you finished an entire group of gl commands (don’t, for example, exit between glBegin() and glEnd())

In regards to whether multiple threads are allowed for a single rendering context, check this quote from the MSDN:

A thread can have one current rendering context. A process can have multiple rendering contexts by means of multithreading. A thread must set a current rendering context before calling any OpenGL functions. Otherwise, all OpenGL calls are ignored.

A rendering context can be current to only one thread at a time. You cannot make a rendering context current to multiple threads.

An application can perform multithread drawing by making different rendering contexts current to different threads, supplying each thread with its own rendering context and device context.

The interesting bit is: “A rendering context can be current to only one thread at a time”, the “at a time” in particular. I think this means, in conclusion, that at different times, the context may be current to more than one thread.

The last part finally refers to multithread, multitarget rendering, I guess, considering they talk about per-thread unique DCs and RCs.

Cheers,
- Wernaeh

1b1be3e6a679f9e62120cf062f16e130
0
polyvertex 101 Feb 23, 2008 at 23:26

@Nils Pipenbrinck

… glGenTextures is purely optional. You’re free to manage the texture-names yourself. A simple counter is suitable for most applications. …

OT : Agreed about multhreading context vs. opengl, but about the glGenTextures stuff, are you sure it is correct (i.e.: i mean, not only ok) to generate your own OpenGL texture names on every implementations ?

OK the OpenGL book says it’s only “unique” integers but I’m not sure this is very “compliant”. I mean, it’s like creating a user manually in Linux by directly adding a line in /etc/passwd, it will be OK until the day the “createuser” command will be setup to make a call to a shell script to perform specific tasks at creation time (I know I could choose a better example :) )…

B91eae75cd6245bd8074bd0c3f1cc495
0
Nils_Pipenbrinck 101 Feb 24, 2008 at 13:11

It is complient.

OpenGL has to track which TextureNames are just used by the application and make sure these names aren’t returned by any glGenTexures command. This is not explicitly stated in the spec, but it’s said indirectly. Here is the relevant part:

glGenTextures returns n texture names in textures. There is no guarantee that the names form a contiguous set of integers; however, it is guaranteed that none of the returned names was in use immediately before the call to glGenTextures.

I’ve implemented an OpenGL-ES 1.1 API from scratch, and I can assure you that it is a major PITA to implement this detail in way that it does not start to suck performance in glGenTextures even if the application mixes glGenTextures and self-managed texturenames.

C4b4ac681e11772d2e07ed9a84cffe3f
0
kusma 101 Feb 24, 2008 at 18:57

Nils: Since you pulled in OpenGL ES into the discussion I’d like to point out that OpenGL ES is required, as long as interfaced through EGL, to be thread-safe. See section 2.5 of the EGL 1.3 specification for the wording. The OpenGL 2.1 specification also implies that OpenGL should be thread safe by explicitly defining multi-threaded behavior in section 2.9. You’re not the only one who’s been writing OpenGL ES implementations ;)

However, it should be noted that the OpenGL context will still remain global state to all threads, and you have to be careful not to get state-leaks. So don’t think you can put every second draw-call on a separate thread just like that ;)

C4b4ac681e11772d2e07ed9a84cffe3f
0
kusma 101 Feb 24, 2008 at 19:04

@polyvertex

are you sure it is correct (i.e.: i mean, not only ok) to generate your own OpenGL texture names on every implementations ?

Absolutely, and it is important to understand that glGenTextures() doesn’t actually create any textures - it create texture NAMES. The actual texture object is created the first time an unused texture name is bound. Note also that there ARE some APIs that looks and smells like OpenGL, but aren’t. As an example, I know videoGL (a homebrew API for OpenGL-alike programming on the Nintendo DS) differs from OpenGL a lot in these areas.

Eddf956306e6fb299f7291b4a2ccea11
0
kenpex 101 Feb 25, 2008 at 06:54

The best thing to do is to have a single rendering thread and bake stuff for that thread in the others. A nice way is to create displaylists. Multithread programming in OGl with multiple contextes is a REAL PAIN.

http://c0de517e.blogspot.com