From 35275fc71433292416f7b830a759ee572b1f8a09 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 11 Jul 2013 22:59:20 -0700 Subject: [PATCH] Fixed bug 1946 - OpenGL contexts in threads 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. --- include/SDL_video.h | 10 +++++ src/video/SDL_sysvideo.h | 3 +- src/video/SDL_video.c | 55 +++++++++++++++++++-------- src/video/cocoa/SDL_cocoaopengl.m | 2 +- src/video/windows/SDL_windowsopengl.c | 2 +- src/video/x11/SDL_x11opengl.c | 6 +-- 6 files changed, 57 insertions(+), 21 deletions(-) diff --git a/include/SDL_video.h b/include/SDL_video.h index 66815197c..39e01c465 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -889,6 +889,16 @@ extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_CreateContext(SDL_Window * extern DECLSPEC int SDLCALL SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext context); +/** + * \brief Get the currently active OpenGL window. + */ +extern DECLSPEC SDL_Window* SDLCALL SDL_GL_GetCurrentWindow(void); + +/** + * \brief Get the currently active OpenGL context. + */ +extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void); + /** * \brief Set the swap interval for the current OpenGL context. * diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index cd3fa2717..3020bc773 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -302,7 +302,8 @@ struct SDL_VideoDevice /* Cache current GL context; don't call the OS when it hasn't changed. */ SDL_Window *current_glwin; SDL_GLContext current_glctx; - SDL_threadID current_glthread; + SDL_TLSID current_glwin_tls; + SDL_TLSID current_glctx_tls; /* * * */ /* Data private to this driver */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 1a3fbda8b..40060237e 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -500,6 +500,9 @@ SDL_VideoInit(const char *driver_name) _this->gl_config.profile_mask = 0; _this->gl_config.share_with_current_context = 0; + _this->current_glwin_tls = SDL_TLSCreate(); + _this->current_glctx_tls = SDL_TLSCreate(); + /* Initialize the video subsystem */ if (_this->VideoInit(_this) < 0) { SDL_VideoQuit(); @@ -2738,7 +2741,8 @@ SDL_GL_CreateContext(SDL_Window * window) /* Creating a context is assumed to make it current in the SDL driver. */ _this->current_glwin = window; _this->current_glctx = ctx; - _this->current_glthread = SDL_ThreadID(); + SDL_TLSSet(_this->current_glwin_tls, window, NULL); + SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); return ctx; } @@ -2747,7 +2751,12 @@ int SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) { int retval; - SDL_threadID thread = SDL_ThreadID(); + + if (window == SDL_GL_GetCurrentWindow() && + ctx == SDL_GL_GetCurrentContext()) { + /* We're already current. */ + return 0; + } if (!ctx) { window = NULL; @@ -2759,26 +2768,42 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) } } - if ((window == _this->current_glwin) && (ctx == _this->current_glctx) && (thread == _this->current_glthread)) { - retval = 0; /* we're already current. */ - } else { - retval = _this->GL_MakeCurrent(_this, window, ctx); - if (retval == 0) { - _this->current_glwin = window; - _this->current_glctx = ctx; - _this->current_glthread = thread; - } + retval = _this->GL_MakeCurrent(_this, window, ctx); + if (retval == 0) { + _this->current_glwin = window; + _this->current_glctx = ctx; + SDL_TLSSet(_this->current_glwin_tls, window, NULL); + SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); } - return retval; } +SDL_Window * +SDL_GL_GetCurrentWindow(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls); +} + +SDL_GLContext +SDL_GL_GetCurrentContext(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls); +} + int SDL_GL_SetSwapInterval(int interval) { if (!_this) { return SDL_UninitializedVideo(); - } else if (_this->current_glctx == NULL) { + } else if (SDL_GL_GetCurrentContext() == NULL) { return SDL_SetError("No OpenGL context has been made current"); } else if (_this->GL_SetSwapInterval) { return _this->GL_SetSwapInterval(_this, interval); @@ -2792,7 +2817,7 @@ SDL_GL_GetSwapInterval(void) { if (!_this) { return 0; - } else if (_this->current_glctx == NULL) { + } else if (SDL_GL_GetCurrentContext() == NULL) { return 0; } else if (_this->GL_GetSwapInterval) { return _this->GL_GetSwapInterval(_this); @@ -2820,7 +2845,7 @@ SDL_GL_DeleteContext(SDL_GLContext context) return; } - if (_this->current_glctx == context) { + if (SDL_GL_GetCurrentContext() == context) { SDL_GL_MakeCurrent(NULL, NULL); } diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m index 35e74e328..8289107e3 100644 --- a/src/video/cocoa/SDL_cocoaopengl.m +++ b/src/video/cocoa/SDL_cocoaopengl.m @@ -178,7 +178,7 @@ Cocoa_GL_CreateContext(_THIS, SDL_Window * window) } if (_this->gl_config.share_with_current_context) { - share_context = (NSOpenGLContext*)(_this->current_glctx); + share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); } context = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share_context]; diff --git a/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c index ec9f34a63..583220d83 100644 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -535,7 +535,7 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) HGLRC context, share_context; if (_this->gl_config.share_with_current_context) { - share_context = (HGLRC)(_this->current_glctx); + share_context = (HGLRC)SDL_GL_GetCurrentContext(); } else { share_context = 0; } diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 1e1078eff..c8ef1f156 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -532,7 +532,7 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) GLXContext context = NULL, share_context; if (_this->gl_config.share_with_current_context) { - share_context = (GLXContext)(_this->current_glctx); + share_context = SDL_GL_GetCurrentContext(); } else { share_context = NULL; } @@ -683,7 +683,7 @@ X11_GL_SetSwapInterval(_THIS, int interval) } else if (_this->gl_data->glXSwapIntervalEXT) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; const SDL_WindowData *windowdata = (SDL_WindowData *) - _this->current_glwin->driverdata; + SDL_GL_GetCurrentWindow()->driverdata; Window drawable = windowdata->xwindow; @@ -727,7 +727,7 @@ X11_GL_GetSwapInterval(_THIS) if (_this->gl_data->glXSwapIntervalEXT) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; const SDL_WindowData *windowdata = (SDL_WindowData *) - _this->current_glwin->driverdata; + SDL_GL_GetCurrentWindow()->driverdata; Window drawable = windowdata->xwindow; unsigned int allow_late_swap_tearing = 0; unsigned int interval = 0;