Multi threading and opengl

Started by
7 comments, last by Lord_Evil 17 years, 2 months ago
Hey folks, I am writing on a project where I would like to have multiple threads interfacing with my opengl window. My question: Is it possible/allowed/permitted to call OpenGL functions from another thread? How can I make it work if it doesnt? I alter the objects I want to render and then set a global flag, that swaps the buffers? What exactly is critical when I call OpenGL functions and especially SwapBuffers? Sorry for this kinda weird and unstructored posting, but I hope you can help me clear things up! Thx in advance regards Woltan
Advertisement
The OpenGL-context by default is owned by the thread that created it (i.e. created the window). Only the thread that ownes the context should call OpenGL functions.
It is possible to have the context switch threads, but this is quite a costly operation and stalls the GPU.

My advise is to carefully look at the reasons why you would want multiple threads to call OpenGL. A cycle where you update objects, then render them might be sufficient and will save you the trouble of making things thread safe.
Like DaBono said, you should have only one thread calling OpenGL functions.

Whether to use multiple threads for updating and rendering depends on what you want to achieve.

In an editor which doesn't require constant screen updates but rerenders the scene if something has changed or the window needs to be repainted, I'd say it is sufficient to have a single thread that alters your scene (geometry, camera position, etc.) and then renders it.

A game engine might want to have multiple threads. One could do AI and update an entity's position, speed etc., another could do physics simulation and update an object's position, orientation and even shape, while yet another thread handles data transfer, i.e. storing and loading data to and from disk (or other locations). Then you have one rendering thread that draws the scene and makes OpenGL calls. Of course you have to coordinate OpenGL calls for uploading data to video memory (you could have a copy of the data in system memory while loading it from disk, then granting access to the render thread which uploads it to video memory). With this approach you'd have multiple threads running distinct tasks at different frequencies (rendering being the fastest, then phyics simulation followed by AI and data transfer for example).
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
Hey DaBono,
thx for your reply and the info.
I want to create a second thread because I want to export quit a bit of programming into a dll which operates kinda on its own. However in there are some operations that could change some textures on my models. Since I am not rendering all the time but only when something is updated, I need this other thread tell the main thread, that there was something updated.
Anyhow this question seems to be more about threading than opengl. But is it possible to send a window message of some sort, that can switch from the "extern" thread into the window thread? Like that the other thread could tell the window to render and paint itself.
But maybe I am not seeing the simple solution lying right in front of me.
But for that I got you!
help me ;)
cherio Woltan
Well, afaik you could give the second thread a handle to the window and post a "(re)paint" message, but I don't have the details right now.

As for your textures: You could have copy of the textures in system memory, set a flag if this copy is altered, provide some information on which portion was altered and let the rendering thread upload the altered portion to OpenGL just before rendering.


Got some information now (from Windows Platform SDK):

SendMessage Function



--------------------------------------------------------------------------------

The SendMessage function sends the specified message to a window or windows. It calls the window procedure for the specified window and does not return until the window procedure has processed the message.

To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's message queue and return immediately, use the PostMessage or PostThreadMessage function.


Syntax

LRESULT SendMessage( HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);

PostMessage Function



The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

To post a message in the message queue associate with a thread, use the PostThreadMessage function.


Syntax

BOOL PostMessage( HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);



I'd say PostMessage is the way to go with multithreading. Pass the HWND handle to your "external" thread and have it call PostMessage(hwnd, WM_PAINT, 0, 0) (wParam and lParam seem not be used here).
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
Quote:Original post by DaBono
My advise is to carefully look at the reasons why you would want multiple threads to call OpenGL. A cycle where you update objects, then render them might be sufficient and will save you the trouble of making things thread safe.


There can be reasons to have multiple game state update threads (like multiprocessor utilization, masochism, exercising a threading library, or peculiar architectural orientations), but the multiple threads don't really need to issue OpenGL calls.

For example, there can be a thread-safe queue where multiple threads post objects representing low-level and hopefully coarse-grained units of work (e.g. draw a triangle strip with a certain vertex buffer) as they compute them and a single thread executes the corresponding OpenGL calls.
Or for usually better performance, begin the drawing calls from a single special thread only after every state update thread is finished, so that whatever needs to be drawn can be sorted and collected in large batches and OpenGL calls can take place in a predictable order.

If performance is so limited by call overhead or bandwidth that one needs to start early and overlap OpenGL calls with updates, a humble optimization and redesign of the graphics is better than adopting complex multithreaded designs of dubious performance.

Omae Wa Mou Shindeiru

If you create your own message, you can use the parameters in the message to tell the other thread what happened. So you'd have a message of "HEY_TEXTURE_CHANGED" which you post to the GUI thread, and you could put a pointer to the main memory texture object in the message.

If you use your own message in this way rather than using the windows MW_PAINT, your main rendering thread can be smarter about how it handles the repainting for example it can say Aha! -- But that texture's not /visible/ so I get away with just uploading it and not re-render the scene...

Passing in (say) the texture id in the parameter means a lot less faffing about trying to find out /what/ changed when you parse the message at the other end.
Hey ho yall,
I was pretty busy so I didnt have a chance to read the replys up until now. And I think I'll use the PostMessage option. I am just not 100% sure that this really is one clean way to do it. I mean, most of the time, even if you call opengl function from an other thread, it works, but it might just as well crash at some point or do undefined weird stuff. So what I will do:
I will make my model available for both threads so that it can be altered. And for every time a change took place I send a PostMessage to the window that holdes the context.
Are there any objections? Am I doing this correctly? Is there maybe another better way to do it?
Thx for your help so far!
cherio Woltan
I'd say there shouldn't be a problem if both threads have access to the model's data unless you employ some locking mechanism.

Since PostMessage puts the message in the message queue of the window-owning thread this thread can re-render the scene whenever the data is ready (not locked). This thread should however be the only one to actually call OpenGL.
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!

This topic is closed to new replies.

Advertisement