We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 1946

Summary: OpenGL contexts in threads
Product: SDL Reporter: Alex Szpakowski <amaranth72>
Component: videoAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2    
Version: HG 2.0   
Hardware: All   
OS: All   

Description Alex Szpakowski 2013-07-08 18:14:23 UTC
OpenGL contexts in all underlying OpenGL windowing interfaces (WGL, GLX, CGL, EGL, EAGL) are designed such that only one single context can be active in a particular thread at any given moment, but multiple contexts may be active at the same time in a program if each context is made active in a separate thread - that is, context activeness/currentness is thread-local rather than global.

SDL 2's code does not recognize this. It keeps a global variable containing the last context set with SDL_GL_MakeCurrent, despite the fact that a context made current in one thread is not current in any other thread, and a context made current in one thread will not deactivate any current context in another thread.

If thread A calls SDL_GL_MakeCurrent(window, contextA) and thread B calls SDL_GL_MakeCurrent(window, contextB) after, SDL will think contextB is current in thread A, even though contextA is actually current in thread A.

SDL2's code uses this extremely unreliable global variable to early-exit from SDL_GL_MakeCurrent if the supplied context is the same as the stored one, even in different threads. If the supplied context is different from the stored one, it will overwrite the stored variable with the new context in all threads, even though all underlying MakeCurrent implementations only set the current context for the calling thread.

The code uses this bad global variable in several other places, for example it checks what it thinks is the current context before calling the system implementation of SDL_GL_SetSwapInterval and SDL_GL_DeleteContext.

Another example of where this might lead to unexpected behaviour is in the system-dependent code for SDL_GL_CreateContext when SDL_GL_SHARE_WITH_CURRENT_CONTEXT is specified. In the Cocoa code, SDL uses the last active context is knows about, regardless of whether it was actually the last active context in the current thread or not. This particular case might be useful, but it goes against the fact that context currentness is thread-local rather than global.

The current_glctx variable is used in some other places where it may be an issue: SDL's cocoa video/window code uses current_glctx variable to call [context update] when a window position or size or fullscreen-status changes, despite the fact that the current_glctx variable might not be current for that particular thread, or it may be in use in another thread, or it may not even be related to that window at all.

As an aside, if this gets properly resolved then it might be useful to expose a (properly thread-aware) SDL_GL_GetCurrentContext or SDL_GL_IsCurrent function. :)
Comment 1 (disabled) Jørgen Tjernø 2013-07-09 16:01:04 UTC
Part of this has been addressed, where SDL_GL_MakeCurrent only early exits if it's called on the same thread: http://hg.libsdl.org/SDL/rev/e4b98404baa4
Comment 2 (disabled) Jørgen Tjernø 2013-07-09 16:01:19 UTC
There is obviously more work to do to properly handle threads.
Comment 3 Sam Lantinga 2013-07-12 02:03:14 UTC
This is fixed with changeset:
http://hg.libsdl.org/SDL/rev/50211a1fd557

The SDL OpenGL context code is now properly thread aware.  There are two new functions which return the current OpenGL window and context for the current thread.

There are still places in the cocoa driver where the OpenGL context needs to be updated when the view changes.  These will need a different solution and still use the last globally set context to avoid changing behavior.

Thanks!