Fixed bug 1946 - OpenGL contexts in threads
authorSam Lantinga <slouken@libsdl.org>
Thu, 11 Jul 2013 22:59:20 -0700
changeset 741250211a1fd557
parent 7410 a9878830f05e
child 7413 30d42f6f2e8d
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
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/cocoa/SDL_cocoaopengl.m
src/video/windows/SDL_windowsopengl.c
src/video/x11/SDL_x11opengl.c
     1.1 --- a/include/SDL_video.h	Fri Jul 12 01:26:43 2013 -0400
     1.2 +++ b/include/SDL_video.h	Thu Jul 11 22:59:20 2013 -0700
     1.3 @@ -890,6 +890,16 @@
     1.4                                                 SDL_GLContext context);
     1.5  
     1.6  /**
     1.7 + *  \brief Get the currently active OpenGL window.
     1.8 + */
     1.9 +extern DECLSPEC SDL_Window* SDLCALL SDL_GL_GetCurrentWindow(void);
    1.10 +
    1.11 +/**
    1.12 + *  \brief Get the currently active OpenGL context.
    1.13 + */
    1.14 +extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void);
    1.15 +
    1.16 +/**
    1.17   *  \brief Set the swap interval for the current OpenGL context.
    1.18   *
    1.19   *  \param interval 0 for immediate updates, 1 for updates synchronized with the
     2.1 --- a/src/video/SDL_sysvideo.h	Fri Jul 12 01:26:43 2013 -0400
     2.2 +++ b/src/video/SDL_sysvideo.h	Thu Jul 11 22:59:20 2013 -0700
     2.3 @@ -302,7 +302,8 @@
     2.4      /* Cache current GL context; don't call the OS when it hasn't changed. */
     2.5      SDL_Window *current_glwin;
     2.6      SDL_GLContext current_glctx;
     2.7 -    SDL_threadID current_glthread;
     2.8 +    SDL_TLSID current_glwin_tls;
     2.9 +    SDL_TLSID current_glctx_tls;
    2.10  
    2.11      /* * * */
    2.12      /* Data private to this driver */
     3.1 --- a/src/video/SDL_video.c	Fri Jul 12 01:26:43 2013 -0400
     3.2 +++ b/src/video/SDL_video.c	Thu Jul 11 22:59:20 2013 -0700
     3.3 @@ -500,6 +500,9 @@
     3.4      _this->gl_config.profile_mask = 0;
     3.5      _this->gl_config.share_with_current_context = 0;
     3.6  
     3.7 +    _this->current_glwin_tls = SDL_TLSCreate();
     3.8 +    _this->current_glctx_tls = SDL_TLSCreate();
     3.9 +
    3.10      /* Initialize the video subsystem */
    3.11      if (_this->VideoInit(_this) < 0) {
    3.12          SDL_VideoQuit();
    3.13 @@ -2738,7 +2741,8 @@
    3.14      /* Creating a context is assumed to make it current in the SDL driver. */
    3.15      _this->current_glwin = window;
    3.16      _this->current_glctx = ctx;
    3.17 -    _this->current_glthread = SDL_ThreadID();
    3.18 +    SDL_TLSSet(_this->current_glwin_tls, window, NULL);
    3.19 +    SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
    3.20  
    3.21      return ctx;
    3.22  }
    3.23 @@ -2747,7 +2751,12 @@
    3.24  SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
    3.25  {
    3.26      int retval;
    3.27 -    SDL_threadID thread = SDL_ThreadID();
    3.28 +
    3.29 +    if (window == SDL_GL_GetCurrentWindow() &&
    3.30 +        ctx == SDL_GL_GetCurrentContext()) {
    3.31 +        /* We're already current. */
    3.32 +        return 0;
    3.33 +    }
    3.34  
    3.35      if (!ctx) {
    3.36          window = NULL;
    3.37 @@ -2759,26 +2768,42 @@
    3.38          }
    3.39      }
    3.40  
    3.41 -    if ((window == _this->current_glwin) && (ctx == _this->current_glctx) && (thread == _this->current_glthread)) {
    3.42 -        retval = 0;  /* we're already current. */
    3.43 -    } else {
    3.44 -        retval = _this->GL_MakeCurrent(_this, window, ctx);
    3.45 -        if (retval == 0) {
    3.46 -            _this->current_glwin = window;
    3.47 -            _this->current_glctx = ctx;
    3.48 -            _this->current_glthread = thread;
    3.49 -        }
    3.50 +    retval = _this->GL_MakeCurrent(_this, window, ctx);
    3.51 +    if (retval == 0) {
    3.52 +        _this->current_glwin = window;
    3.53 +        _this->current_glctx = ctx;
    3.54 +        SDL_TLSSet(_this->current_glwin_tls, window, NULL);
    3.55 +        SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
    3.56      }
    3.57 -
    3.58      return retval;
    3.59  }
    3.60  
    3.61 +SDL_Window *
    3.62 +SDL_GL_GetCurrentWindow(void)
    3.63 +{
    3.64 +    if (!_this) {
    3.65 +        SDL_UninitializedVideo();
    3.66 +        return NULL;
    3.67 +    }
    3.68 +    return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
    3.69 +}
    3.70 +
    3.71 +SDL_GLContext
    3.72 +SDL_GL_GetCurrentContext(void)
    3.73 +{
    3.74 +    if (!_this) {
    3.75 +        SDL_UninitializedVideo();
    3.76 +        return NULL;
    3.77 +    }
    3.78 +    return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
    3.79 +}
    3.80 +
    3.81  int
    3.82  SDL_GL_SetSwapInterval(int interval)
    3.83  {
    3.84      if (!_this) {
    3.85          return SDL_UninitializedVideo();
    3.86 -    } else if (_this->current_glctx == NULL) {
    3.87 +    } else if (SDL_GL_GetCurrentContext() == NULL) {
    3.88          return SDL_SetError("No OpenGL context has been made current");
    3.89      } else if (_this->GL_SetSwapInterval) {
    3.90          return _this->GL_SetSwapInterval(_this, interval);
    3.91 @@ -2792,7 +2817,7 @@
    3.92  {
    3.93      if (!_this) {
    3.94          return 0;
    3.95 -    } else if (_this->current_glctx == NULL) {
    3.96 +    } else if (SDL_GL_GetCurrentContext() == NULL) {
    3.97          return 0;
    3.98      } else if (_this->GL_GetSwapInterval) {
    3.99          return _this->GL_GetSwapInterval(_this);
   3.100 @@ -2820,7 +2845,7 @@
   3.101          return;
   3.102      }
   3.103  
   3.104 -    if (_this->current_glctx == context) {
   3.105 +    if (SDL_GL_GetCurrentContext() == context) {
   3.106          SDL_GL_MakeCurrent(NULL, NULL);
   3.107      }
   3.108  
     4.1 --- a/src/video/cocoa/SDL_cocoaopengl.m	Fri Jul 12 01:26:43 2013 -0400
     4.2 +++ b/src/video/cocoa/SDL_cocoaopengl.m	Thu Jul 11 22:59:20 2013 -0700
     4.3 @@ -178,7 +178,7 @@
     4.4      }
     4.5  
     4.6      if (_this->gl_config.share_with_current_context) {
     4.7 -        share_context = (NSOpenGLContext*)(_this->current_glctx);
     4.8 +        share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
     4.9      }
    4.10  
    4.11      context = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
     5.1 --- a/src/video/windows/SDL_windowsopengl.c	Fri Jul 12 01:26:43 2013 -0400
     5.2 +++ b/src/video/windows/SDL_windowsopengl.c	Thu Jul 11 22:59:20 2013 -0700
     5.3 @@ -535,7 +535,7 @@
     5.4      HGLRC context, share_context;
     5.5  
     5.6      if (_this->gl_config.share_with_current_context) {
     5.7 -        share_context = (HGLRC)(_this->current_glctx);
     5.8 +        share_context = (HGLRC)SDL_GL_GetCurrentContext();
     5.9      } else {
    5.10          share_context = 0;
    5.11      }
     6.1 --- a/src/video/x11/SDL_x11opengl.c	Fri Jul 12 01:26:43 2013 -0400
     6.2 +++ b/src/video/x11/SDL_x11opengl.c	Thu Jul 11 22:59:20 2013 -0700
     6.3 @@ -532,7 +532,7 @@
     6.4      GLXContext context = NULL, share_context;
     6.5  
     6.6      if (_this->gl_config.share_with_current_context) {
     6.7 -        share_context = (GLXContext)(_this->current_glctx);
     6.8 +        share_context = SDL_GL_GetCurrentContext();
     6.9      } else {
    6.10          share_context = NULL;
    6.11      }
    6.12 @@ -683,7 +683,7 @@
    6.13      } else if (_this->gl_data->glXSwapIntervalEXT) {
    6.14          Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    6.15          const SDL_WindowData *windowdata = (SDL_WindowData *)
    6.16 -            _this->current_glwin->driverdata;
    6.17 +            SDL_GL_GetCurrentWindow()->driverdata;
    6.18  
    6.19          Window drawable = windowdata->xwindow;
    6.20  
    6.21 @@ -727,7 +727,7 @@
    6.22      if (_this->gl_data->glXSwapIntervalEXT) {
    6.23          Display *display = ((SDL_VideoData *) _this->driverdata)->display;
    6.24          const SDL_WindowData *windowdata = (SDL_WindowData *)
    6.25 -            _this->current_glwin->driverdata;
    6.26 +            SDL_GL_GetCurrentWindow()->driverdata;
    6.27          Window drawable = windowdata->xwindow;
    6.28          unsigned int allow_late_swap_tearing = 0;
    6.29          unsigned int interval = 0;