SDL: macOS: Add hint for blocking thread on OpenGL context update dispatch (#5708)

From b4660e9d8b633da9ef7b6ba39c83c0f7832e9a7d Mon Sep 17 00:00:00 2001
From: Salman Ahmed <[EMAIL REDACTED]>
Date: Wed, 10 Aug 2022 03:40:00 +0300
Subject: [PATCH] macOS: Add hint for blocking thread on OpenGL context update
 dispatch (#5708)

---
 include/SDL_hints.h               | 12 ++++++++++++
 src/video/cocoa/SDL_cocoaopengl.m | 23 ++++++++++++++++++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 1cb2cc2bdd5..b0e73386ca0 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -977,6 +977,18 @@ extern "C" {
  */
 #define SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"
 
+/**
+ *  \brief   A variable controlling whether dispatching OpenGL context updates should block the dispatching thread until the main thread finishes processing
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Dispatching OpenGL context updates will allow the dispatching thread to continue execution.
+ *    "1"       - Dispatching OpenGL context updates will block the dispatching thread until the main thread finishes processing.
+ *
+ *  This hint only applies to Mac OS X
+ *
+ */
+#define SDL_HINT_MAC_OPENGL_SYNC_DISPATCH "SDL_MAC_OPENGL_SYNC_DISPATCH"
+
 /**
  *  \brief  A variable setting the double click radius, in pixels.
  */
diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m
index 5b41b18222b..31fe948a8de 100644
--- a/src/video/cocoa/SDL_cocoaopengl.m
+++ b/src/video/cocoa/SDL_cocoaopengl.m
@@ -31,8 +31,10 @@
 #include <OpenGL/OpenGL.h>
 #include <OpenGL/CGLRenderers.h>
 
+#include "SDL_hints.h"
 #include "SDL_loadso.h"
 #include "SDL_opengl.h"
+#include "../../SDL_hints_c.h"
 
 #define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
 
@@ -42,6 +44,14 @@
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #endif
 
+static SDL_bool SDL_opengl_sync_dispatch = SDL_FALSE;
+
+static void SDLCALL
+SDL_OpenGLSyncDispatchChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    SDL_opengl_sync_dispatch = SDL_GetStringBoolean(hint, SDL_FALSE);
+}
+
 @implementation SDLOpenGLContext : NSOpenGLContext
 
 - (id)initWithFormat:(NSOpenGLPixelFormat *)format
@@ -52,6 +62,8 @@ - (id)initWithFormat:(NSOpenGLPixelFormat *)format
         SDL_AtomicSet(&self->dirty, 0);
         self->window = NULL;
     }
+
+    SDL_AddHintCallback(SDL_HINT_MAC_OPENGL_SYNC_DISPATCH, SDL_OpenGLSyncDispatchChanged, NULL);
     return self;
 }
 
@@ -135,10 +147,19 @@ - (void)explicitUpdate
     if ([NSThread isMainThread]) {
         [super update];
     } else {
-        dispatch_async(dispatch_get_main_queue(), ^{ [super update]; });
+        if (SDL_opengl_sync_dispatch) {
+            dispatch_sync(dispatch_get_main_queue(), ^{ [super update]; });
+        } else {
+            dispatch_async(dispatch_get_main_queue(), ^{ [super update]; });
+        }
     }
 }
 
+- (void)dealloc
+{
+    SDL_DelHintCallback(SDL_HINT_MAC_OPENGL_SYNC_DISPATCH, SDL_OpenGLSyncDispatchChanged, NULL);
+}
+
 @end