openGL and threads

Started by
6 comments, last by RichardS 18 years, 1 month ago
All right, here goes the (evil) question: what is safe to do in openGL via threads and what is not? I ask becuase straight from Apple we have: "The Mac OS X OpenGL implementation is not thread-safe but you can still split your processing onto multiple threads. It is extremely important for developers not to issue OpenGL commands for a single context from multiple threads without proper thread synchronization." from http://developer.apple.com/graphicsimaging/opengl/optimizingdata.html maybe my question is a touch too broad... lets start with a (few) examples: 1) loading geomerty (i.e. VBO) and texture data to the card. Can this be done in a thread if the textures and geomerty being loaded are not at all used by any other threads while the loading thread is alive? my concern is that the driver may have some funky logic in it to decide when to send the data to the card, so if you are in thread A drawing stuff (but not using the VBO's and textures affected by thread B) and thread B starts it's loading thing and the driver may decided to move some stuff from card to memory or vica-versa which thread A is playing with, and then thread A might get trashed (i.e. a draw command is issues by thread A when the stuff is (say) in card memory, but when the card actaully does the command it has gotten moved back to system memory) Typical example of doing this is "nicer loading screens" and possible some "load stuff while playing scenarios" 2) FBO's and a simple windowing system: idea: each window renders to a texture .. now admittedly a fixed window may play with the openGL stte alot, so I am not saying do the drawing of each window in it's own thread, but, for each windows there is a Do() and Draw() function. The Do() function does stuff that _should_ not affect the openGL state that touches other windows, i.e. it can do things like change VBOs ann textures it owns, but it does not do any openGL state stuff (i.e. drawing, glMatrix*, ect). So the windowing system does the Do() in threads but the Draw()'s one at a time... would that be safe at all even? Best Regards -kRogue
Close this Gamedev account, I have outgrown Gamedev.
Advertisement
What they say about the OpenGL implementation not being thread safe means that you should use synchronization objects around all OpenGL API calls that might be called from multiple threads. What other processing you are doing with your data is up to you to choose how to synchronize.

I don't know anything about MAC, but in Windows OpenGL will crash badly if you don't do synchronizations across API calls. I hope in a future version you can set some flag to make OpenGL thread safe (like in DirectX), because the way I see it, implementors might have more access to lower synchronization overhead.
The long and short of the story is, don't make gl* calls, wgl* calls, glx* calls, or anything else of the sort from more than one thread. It doesn't matter what the usage patterns are. Just don't do it.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Well, Quake 3 is a nice example of using OpenGL in a threaded model :). I have been looking into the code only since yesterday so don't know much about it yet, but the idea I get is that carmack is not trying to call two gl functions in different threads without making sure that only one of them executes at any time.

Q3 is using Win32 events to achieve the functionality in the win32 version.

Also, making gl functions thread safe would be more than just making function calls thread safe. The entire states need to be made thread safe. What if one thread is in a glBegin/glEnd and the other one says glGet (no crashes, but invalid operation)?

Instead letting the programmer plan the synchronization constructs works better for me.
As Promit says, its just not a good idea todo it.
About the only place you could possibly gain a performance increase is by loading data, HOWEVER an OpenGL context is only current in one thread at a time (win32 at least), as such you'd have to swap the context between threads to upload the data, this is going to cost you performance wise.
so, therefore, the idea of doing this with threads is just begging for trouble:

threadA:
Draw a bar via openGL of % stuff loaded.

threadB:
actually load the stuff from disk and put then into openGL

or what I'd really like to do:

while game is running:
threadA:
the game, if a needed resource is not loaded then pause game and wait.

threadB:
checks if there are resources needed now or soon that have not been loaded yet, and loads them to openGL,

so this would be bad ;(

but this should be ok then:
threadA:
conceptionally owns the openGL

threadB:
checks if there are resources needed now or soon that have not been loaded yet, and loads them to memory, when a resource is ready in memory "send a message to threadA" saying to move the data from memory to openGL...


Close this Gamedev account, I have outgrown Gamedev.
Let me see if I can shed some light on this ... Problems with multi-threading in OpenGL stem from its state machine architecture. When the GL context is created, it is done so from within one thread. That thread is given its own stack space where the GL state variables are stored. If you attempt to access those state variables (e.g. gl*, wgl*, glx*) from a separate thread then the calling thread references the variables of the same name in their own stack space ... not in the thread of the GL context ... a completely different set of state variables.

This is why successful threaded GL apps typically use some sort of messaging or command loop running in the primary thread where external threads can post commands to be processed by the primary thread.

Multi-threading can be a great thing for a viz and can help in many ways. However, you had better know what you are doing or you will be in for a world of hurt. A guy I used to work for said it best ... "multithreading with OpenGl separates the men from the boys".
The slightly longer version is (on Mac OS X): Don't make any gl* or CGL* calls into same context from different threads, without synchronizing those calls. ie, it is OK to issue GL commands into the same context from multiple threads, BUT you must ensure that no more than one thread is actually in a gl* function at any time.

If each thread has a different current context (but those contexts are not shared), then you don't have to worry about anything.

What you want to do is to load resources in one thread, while rendering from the other. This can be done with shared contexts, although I'm not sure about the exact synchronization requirements.

This topic is closed to new replies.

Advertisement