gl/cocoa: don't deadlock if the dispatch_sync is called from the main thread
authorMatthew Waters <matthew@centricular.com>
Tue, 17 Feb 2015 07:17:59 +0000 (18:17 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:55 +0000 (19:31 +0000)
Provide a helper function to check whether we are being called from
the main thread and act appropriately.

gst-libs/gst/gl/cocoa/gstgl_cocoa_private.h
gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m
gst-libs/gst/gl/cocoa/gstglwindow_cocoa.m

index df00a38..ae7abc8 100644 (file)
@@ -59,6 +59,8 @@ struct _GstGLContextCocoaPrivate
 
 gboolean gst_gl_window_cocoa_create_window (GstGLWindowCocoa *window_cocoa);
 
+void _invoke_on_main (GstGLWindowCB func, gpointer data);
+
 G_END_DECLS
 
 #endif /* __GST_GL_COCOA_PRIVATE_H__ */
index 8298b3d..e7c5722 100644 (file)
@@ -290,6 +290,18 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
   GstGLWindow *window = gst_gl_context_get_window (context);
   GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (window);
   const GLint swapInterval = 1;
+  NSAutoreleasePool *pool;
+  CGLPixelFormatObj fmt = NULL;
+  CGLContextObj glContext;
+  CGLPixelFormatAttribute attribs[] = {
+    kCGLPFADoubleBuffer,
+    kCGLPFAAccumSize, 32,
+    0
+  };
+  CGLError ret;
+  gint npix;
+
+  pool = [[NSAutoreleasePool alloc] init];
 
 #ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
   priv->source_id = g_timeout_add (200, gst_gl_window_cocoa_nsapp_iteration, NULL);
@@ -301,58 +313,40 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
   else
     priv->external_gl_context = NULL;
 
-  dispatch_sync (dispatch_get_main_queue (), ^{
-    NSAutoreleasePool *pool;
-    CGLPixelFormatObj fmt = NULL;
-    CGLContextObj glContext;
-    CGLPixelFormatAttribute attribs[] = {
-      kCGLPFADoubleBuffer,
-      kCGLPFAAccumSize, 32,
-      0
-    };
-    CGLError ret;
-    gint npix;
-
-    pool = [[NSAutoreleasePool alloc] init];
-
-    if (priv->external_gl_context) {
-      fmt = CGLGetPixelFormat (priv->external_gl_context);
-    }
-
-    if (!fmt) {
-      ret = CGLChoosePixelFormat (attribs, &fmt, &npix);
-      if (ret != kCGLNoError) {
-        gst_object_unref (window);
-        g_set_error (error, GST_GL_CONTEXT_ERROR,
-            GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "cannot choose a pixel format: %s", CGLErrorString (ret));
-        return;
-      }
-    }
-
-    gst_gl_context_cocoa_dump_pixel_format (fmt);
+  if (priv->external_gl_context) {
+    fmt = CGLGetPixelFormat (priv->external_gl_context);
+  }
 
-    ret = CGLCreateContext (fmt, priv->external_gl_context, &glContext);
+  if (!fmt) {
+    ret = CGLChoosePixelFormat (attribs, &fmt, &npix);
     if (ret != kCGLNoError) {
-      g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
-          "failed to create context: %s", CGLErrorString (ret));
-      gst_object_unref (window);
-      return;
+      g_set_error (error, GST_GL_CONTEXT_ERROR,
+          GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "cannot choose a pixel format: %s", CGLErrorString (ret));
+      goto error;
     }
+  }
+
+  gst_gl_context_cocoa_dump_pixel_format (fmt);
 
-    context_cocoa->priv->pixel_format = fmt;
-    context_cocoa->priv->gl_context = glContext;
+  ret = CGLCreateContext (fmt, priv->external_gl_context, &glContext);
+  if (ret != kCGLNoError) {
+    g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
+        "failed to create context: %s", CGLErrorString (ret));
+    goto error;
+  }
 
-    gst_gl_window_cocoa_create_window (window_cocoa);
+  context_cocoa->priv->pixel_format = fmt;
+  context_cocoa->priv->gl_context = glContext;
 
-    [pool release];
-  });
+  _invoke_on_main ((GstGLWindowCB) gst_gl_window_cocoa_create_window,
+      window_cocoa);
 
   if (!context_cocoa->priv->gl_context) {
 #ifndef GSTREAMER_GLIB_COCOA_NSAPPLICATION
     g_source_remove (priv->source_id);
     priv->source_id = 0;
 #endif
-    return FALSE;
+    goto error;
   }
 
   GST_INFO_OBJECT (context, "GL context created: %p", context_cocoa->priv->gl_context);
@@ -365,8 +359,14 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
   CGLSetParameter (context_cocoa->priv->gl_context, kCGLCPSwapInterval, &swapInterval);
 
   gst_object_unref (window);
+  [pool release];
 
   return TRUE;
+
+error:
+  gst_object_unref (window);
+  [pool release];
+  return FALSE;
 }
 
 static void
index 229948a..17ded04 100644 (file)
@@ -238,6 +238,20 @@ gst_gl_window_cocoa_set_window_handle (GstGLWindow * window, guintptr handle)
 }
 
 static void
+_show_window (gpointer data)
+{
+  GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (data);
+  GstGLWindowCocoaPrivate *priv = window_cocoa->priv;
+
+  GST_DEBUG_OBJECT (window_cocoa, "make the window available\n");
+  [priv->internal_win_id makeMainWindow];
+  [priv->internal_win_id orderFrontRegardless];
+  [priv->internal_win_id setViewsNeedDisplay:YES];
+
+  priv->visible = TRUE;
+}
+
+static void
 gst_gl_window_cocoa_show (GstGLWindow * window)
 {
   GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (window);
@@ -252,17 +266,8 @@ gst_gl_window_cocoa_show (GstGLWindow * window)
       return;
     }
 
-    dispatch_sync (dispatch_get_main_queue(), ^{
-      if (!priv->external_view && !priv->visible) {
-
-        GST_DEBUG_OBJECT (window_cocoa, "make the window available\n");
-        [priv->internal_win_id makeMainWindow];
-        [priv->internal_win_id orderFrontRegardless];
-        [priv->internal_win_id setViewsNeedDisplay:YES];
-
-        priv->visible = TRUE;
-      }
-    });
+    if (!priv->external_view && !priv->visible)
+      _invoke_on_main ((GstGLWindowCB) _show_window, window);
   }
 }
 
@@ -561,3 +566,15 @@ close_window_cb (gpointer data)
 
 @end
 
+void
+_invoke_on_main (GstGLWindowCB func, gpointer data)
+{
+  if ([NSThread isMainThread]) {
+    func (data);
+  } else {
+    dispatch_sync (dispatch_get_main_queue (), ^{
+      func (data);
+    });
+  }
+}
+