Jump to content


OpenGL and Multi-Threading


10 replies to this topic

#1 goruka

    Member

  • Members
  • PipPip
  • 34 posts

Posted 21 February 2008 - 05:47 PM

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!

#2 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 21 February 2008 - 06:16 PM

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.
My music: http://myspace.com/planetarchh <-- my music

My stuff: torus.untergrund.net <-- some diy electronic stuff and more.

#3 goruka

    Member

  • Members
  • PipPip
  • 34 posts

Posted 21 February 2008 - 07:03 PM

Nils Pipenbrinck said:

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?

#4 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 21 February 2008 - 07:19 PM

goruka said:

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.
My music: http://myspace.com/planetarchh <-- my music

My stuff: torus.untergrund.net <-- some diy electronic stuff and more.

#5 Reedbeta

    DevMaster Staff

  • Administrators
  • 5306 posts
  • LocationBellevue, WA

Posted 21 February 2008 - 07:20 PM

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.
reedbeta.com - developer blog, OpenGL demos, and other projects

#6 Wernaeh

    Senior Member

  • Members
  • PipPipPipPip
  • 368 posts

Posted 22 February 2008 - 09:21 AM

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:

Quote

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
Some call me mathematician, some just call me computer guy. Yet, I prefer the term professional weirdo :)

#7 polyvertex

    Member

  • Members
  • PipPip
  • 32 posts

Posted 23 February 2008 - 11:26 PM

Nils Pipenbrinck said:

... 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 :) )...

#8 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 24 February 2008 - 01:11 PM

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:

Quote

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.
My music: http://myspace.com/planetarchh <-- my music

My stuff: torus.untergrund.net <-- some diy electronic stuff and more.

#9 kusma

    Valued Member

  • Members
  • PipPipPip
  • 163 posts

Posted 24 February 2008 - 06:57 PM

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 ;)

#10 kusma

    Valued Member

  • Members
  • PipPipPip
  • 163 posts

Posted 24 February 2008 - 07:04 PM

polyvertex said:

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.

#11 kenpex

    New Member

  • Members
  • PipPip
  • 10 posts

Posted 25 February 2008 - 06:54 AM

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





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users