From 6539d101f32c6d75856882032ce61fd3ad2eb35b Mon Sep 17 00:00:00 2001
From: Doug Binks <doug@enkisoftware.com>
Date: Wed, 15 Jul 2020 13:19:14 +0100
Subject: [PATCH] Added TLS for current user context and simplified code

---
 src/context.c        | 11 +++++++++++
 src/egl_context.c    | 34 ++++++++++------------------------
 src/glx_context.c    | 20 ++++++--------------
 src/init.c           |  4 +++-
 src/internal.h       |  1 +
 src/nsgl_context.m   |  6 ++----
 src/osmesa_context.c | 19 +++++++++----------
 src/wgl_context.c    | 20 ++++++--------------
 8 files changed, 48 insertions(+), 67 deletions(-)

diff --git a/src/context.c b/src/context.c
index 5bab2d01..6e558d55 100644
--- a/src/context.c
+++ b/src/context.c
@@ -617,6 +617,8 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
 
     _GLFW_REQUIRE_INIT();
 
+    _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
+
     if (window && window->context.client == GLFW_NO_API)
     {
         _glfwInputError(GLFW_NO_WINDOW_CONTEXT,
@@ -773,11 +775,17 @@ GLFWAPI GLFWusercontext* glfwCreateUserContext(GLFWwindow* handle)
 GLFWAPI void glfwDestroyUserContext(GLFWusercontext* handle)
 {
     _GLFWusercontext* context = (_GLFWusercontext*)handle;
+    _GLFWusercontext* prev = _glfwPlatformGetTls(&_glfw.usercontextSlot);
 
     _GLFW_REQUIRE_INIT();
 
     if (context)
+    {
+        if(prev==context)
+            _glfwPlatformSetTls(&_glfw.usercontextSlot,NULL);
+
         context->destroy(context);
+    }
 }
 
 GLFWAPI void glfwMakeUserContextCurrent(GLFWusercontext* handle)
@@ -786,6 +794,9 @@ GLFWAPI void glfwMakeUserContextCurrent(GLFWusercontext* handle)
 
     _GLFW_REQUIRE_INIT();
 
+    // Call glfwMakeContextCurrent(NULL) to both clear context TLS and set
+    // context to NULL if required by platform & context, and this
+    // handles case of calling glfwMakeUserContextCurrent(NULL)
     glfwMakeContextCurrent(NULL);
 
     if (context)
diff --git a/src/egl_context.c b/src/egl_context.c
index eb8d6a74..43615794 100644
--- a/src/egl_context.c
+++ b/src/egl_context.c
@@ -817,32 +817,18 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
 
 static void _glfwMakeUserContextCurrentEGL(_GLFWusercontext* context)
 {
-    if(context)
+    if (!eglMakeCurrent(_glfw.egl.display,
+                        context->window->context.egl.surface,
+                        context->window->context.egl.surface,
+                        context->egl.handle))
     {
-        if (!eglMakeCurrent(_glfw.egl.display,
-                            context->window->context.egl.surface,
-                            context->window->context.egl.surface,
-                            context->egl.handle))
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "EGL: Failed to make context current: %s",
-                            getEGLErrorString(eglGetError()));
-            return;
-        }
-    }
-    else
-    {
-        if (!eglMakeCurrent(_glfw.egl.display,
-                            EGL_NO_SURFACE,
-                            EGL_NO_SURFACE,
-                            EGL_NO_CONTEXT))
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "EGL: Failed to clear current context: %s",
-                            getEGLErrorString(eglGetError()));
-            return;
-        }
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "EGL: Failed to make user context current: %s",
+                        getEGLErrorString(eglGetError()));
+        _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
+        return;
     }
+    _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
 }
 
 static void _glfwDestroyUserContextEGL(_GLFWusercontext* context)
diff --git a/src/glx_context.c b/src/glx_context.c
index 19ccf7f9..957be797 100644
--- a/src/glx_context.c
+++ b/src/glx_context.c
@@ -680,22 +680,14 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
 
 static void _glfwMakeUserContextCurrentGLX(_GLFWusercontext* context)
 {
-    if(context)
+    if(!glXMakeCurrent(_glfw.x11.display, context->window->context.glx.window,context->glx.handle))
     {
-        if(!glXMakeCurrent(_glfw.x11.display, context->window->context.glx.window,context->glx.handle))
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                                 "GLX: Failed to set current user context");
-        }
-    }
-    else
-    {
-        if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                                 "GLX: Failed to clear current context");
-        }
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "GLX: Failed to make user context current");
+        _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
+        return;
     }
+    _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
 }
 
 static void _glfwDestroyUserContextGLX(_GLFWusercontext* context)
diff --git a/src/init.c b/src/init.c
index f9ce336a..5df22d0e 100644
--- a/src/init.c
+++ b/src/init.c
@@ -102,6 +102,7 @@ static void terminate(void)
         free(error);
     }
 
+    _glfwPlatformDestroyTls(&_glfw.usercontextSlot);
     _glfwPlatformDestroyTls(&_glfw.contextSlot);
     _glfwPlatformDestroyTls(&_glfw.errorSlot);
     _glfwPlatformDestroyMutex(&_glfw.errorLock);
@@ -244,7 +245,8 @@ GLFWAPI int glfwInit(void)
 
     if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
         !_glfwPlatformCreateTls(&_glfw.errorSlot) ||
-        !_glfwPlatformCreateTls(&_glfw.contextSlot))
+        !_glfwPlatformCreateTls(&_glfw.contextSlot) ||
+        !_glfwPlatformCreateTls(&_glfw.usercontextSlot))
     {
         terminate();
         return GLFW_FALSE;
diff --git a/src/internal.h b/src/internal.h
index bf99478e..ab6c9471 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -564,6 +564,7 @@ struct _GLFWlibrary
 
     _GLFWtls            errorSlot;
     _GLFWtls            contextSlot;
+    _GLFWtls            usercontextSlot;
     _GLFWmutex          errorLock;
 
     struct {
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
index 29430060..866cb4bd 100644
--- a/src/nsgl_context.m
+++ b/src/nsgl_context.m
@@ -353,10 +353,9 @@ static void _glfwMakeUserContextCurrentNSGL(_GLFWusercontext* context)
 {
     @autoreleasepool {
 
-    if (context)
         [context->nsgl.object makeCurrentContext];
-    else
-        [NSOpenGLContext clearCurrentContext];
+
+        _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
 
     } // autoreleasepool
 }
@@ -365,7 +364,6 @@ static void _glfwDestroyUserContextNSGL(_GLFWusercontext* context)
 {
     @autoreleasepool {
 
-    if (context->nsgl.object)
         [context->nsgl.object release];
 
     } // autoreleasepool
diff --git a/src/osmesa_context.c b/src/osmesa_context.c
index 69ae4e2e..95b4017f 100644
--- a/src/osmesa_context.c
+++ b/src/osmesa_context.c
@@ -301,18 +301,17 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
 
 static void _glfwMakeUserContextCurrentOSMesa(_GLFWusercontext* context)
 {
-    if(context)
+    if (!OSMesaMakeCurrent(context->osmesa.handle,
+                            context->window->context.osmesa.buffer,
+                            GL_UNSIGNED_BYTE,
+                            context->window->context.osmesa.width, context->window->context.osmesa.height))
     {
-        if (!OSMesaMakeCurrent(context->osmesa.handle,
-                               context->window->context.osmesa.buffer,
-                               GL_UNSIGNED_BYTE,
-                               context->window->context.osmesa.width, context->window->context.osmesa.height))
-        {
-            _glfwInputError(GLFW_PLATFORM_ERROR,
-                            "OSMesa: Failed to make context current");
-            return;
-        }
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "OSMesa: Failed to make user context current");
+        _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
+        return;
     }
+    _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
 }
 
 static void _glfwDestroyUserContextOSMesa(_GLFWusercontext* context)
diff --git a/src/wgl_context.c b/src/wgl_context.c
index d6d668ad..d0702b66 100644
--- a/src/wgl_context.c
+++ b/src/wgl_context.c
@@ -792,22 +792,14 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
 
 static void _glfwMakeUserContextCurrentWGL(_GLFWusercontext* context)
 {
-    if(context)
+    if(!wglMakeCurrent(context->window->context.wgl.dc,context->wgl.handle))
     {
-        if(!wglMakeCurrent(context->window->context.wgl.dc,context->wgl.handle))
-        {
-            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
-                                 "WGL: Failed to set current user context");
-        }
-    }
-    else
-    {
-        if (!wglMakeCurrent(NULL, NULL))
-        {
-            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
-                                 "WGL: Failed to clear current context");
-        }
+        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
+                             "WGL: Failed to make user context current");
+        _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
+        return;
     }
+    _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
 }
 
 static void _glfwDestroyUserContextWGL(_GLFWusercontext* context)