libgstgl: cocoa, eagl: use libdispatch to schedule GL calls
authorAlessandro Decina <alessandro.d@gmail.com>
Sun, 10 Apr 2016 22:34:00 +0000 (08:34 +1000)
committerAlessandro Decina <alessandro.d@gmail.com>
Sun, 10 Apr 2016 22:40:03 +0000 (08:40 +1000)
Use libdispatch instead of GMainLoop to dispatch GL calls. libdispatch is more
optimized and cuts a lot of poll()/pthread_* overhead.

gst-libs/gst/gl/cocoa/gstglwindow_cocoa.m
gst-libs/gst/gl/eagl/gstglwindow_eagl.m

index 0d027c5a1aece4bbd0ea217bc3c1ef4595923bc5..e1996cf063e097988c75e7cd1552ed3f23741dc4 100644 (file)
@@ -77,6 +77,8 @@ static void gst_gl_window_cocoa_set_preferred_size (GstGLWindow * window,
     gint width, gint height);
 static void gst_gl_window_cocoa_show (GstGLWindow * window);
 static void gst_gl_window_cocoa_queue_resize (GstGLWindow * window);
+static void gst_gl_window_cocoa_send_message_async (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data, GDestroyNotify destroy);
 
 struct _GstGLWindowCocoaPrivate
 {
@@ -90,6 +92,8 @@ struct _GstGLWindowCocoaPrivate
 
   /* atomic set when the internal NSView has been created */
   int view_ready;
+
+  dispatch_queue_t gl_queue;
 };
 
 static void
@@ -111,6 +115,8 @@ gst_gl_window_cocoa_class_init (GstGLWindowCocoaClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_window_cocoa_set_preferred_size);
   window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_cocoa_show);
   window_class->queue_resize = GST_DEBUG_FUNCPTR (gst_gl_window_cocoa_queue_resize);
+  window_class->send_message_async =
+      GST_DEBUG_FUNCPTR (gst_gl_window_cocoa_send_message_async);
 
   gobject_class->finalize = gst_gl_window_cocoa_finalize;
 }
@@ -122,11 +128,15 @@ gst_gl_window_cocoa_init (GstGLWindowCocoa * window)
 
   window->priv->preferred_width = 320;
   window->priv->preferred_height = 240;
+  window->priv->gl_queue =
+      dispatch_queue_create ("org.freedesktop.gstreamer.glwindow", NULL);
 }
 
 static void
 gst_gl_window_cocoa_finalize (GObject * object)
 {
+  GstGLWindowCocoa *window = GST_GL_WINDOW_COCOA (object);
+  dispatch_release (window->priv->gl_queue);
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -370,6 +380,30 @@ gst_gl_cocoa_resize_cb (GstGLNSView * view, guint width, guint height)
   [pool release];
 }
 
+static void
+gst_gl_window_cocoa_send_message_async (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data, GDestroyNotify destroy)
+{
+  GstGLWindowCocoa *window_cocoa = (GstGLWindowCocoa *) window;
+  GstGLContext *context = gst_gl_window_get_context (window);
+
+  if (gst_gl_context_get_thread (context) == g_thread_self()) {
+    /* this case happens for nested calls happening from inside the GCD queue */
+    callback (data);
+    if (destroy)
+      destroy (data);
+    gst_object_unref (context);
+  } else {
+    dispatch_async (window_cocoa->priv->gl_queue, ^{
+      gst_gl_context_activate (context, TRUE);
+      gst_object_unref (context);
+      callback (data);
+      if (destroy)
+        destroy (data);
+    });
+  }
+}
+
 /* =============================================================*/
 /*                                                              */
 /*                    GstGLNSWindow implementation              */
index eb9d4f7f4a3c10bede91d93bb811937ab251b269..f130cc015fe65014fcb6f18e36d9d991124a9dc0 100644 (file)
@@ -40,6 +40,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 #define gst_gl_window_eagl_parent_class parent_class
 G_DEFINE_TYPE_WITH_CODE (GstGLWindowEagl, gst_gl_window_eagl,
     GST_GL_TYPE_WINDOW, DEBUG_INIT);
+static void gst_gl_window_eagl_finalize (GObject * object);
 
 static guintptr gst_gl_window_eagl_get_display (GstGLWindow * window);
 static guintptr gst_gl_window_eagl_get_window_handle (GstGLWindow * window);
@@ -48,21 +49,27 @@ static void gst_gl_window_eagl_set_window_handle (GstGLWindow * window,
 static void gst_gl_window_eagl_set_preferred_size (GstGLWindow * window,
     gint width, gint height);
 static void gst_gl_window_eagl_draw (GstGLWindow * window);
+static void gst_gl_window_eagl_send_message_async (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data, GDestroyNotify destroy);
 
 struct _GstGLWindowEaglPrivate
 {
   UIView *view;
   gint window_width, window_height;
   gint preferred_width, preferred_height;
+  dispatch_queue_t gl_queue;
 };
 
 static void
 gst_gl_window_eagl_class_init (GstGLWindowEaglClass * klass)
 {
+  GObjectClass *gobject_class = (GObjectClass *) klass;
   GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GstGLWindowEaglPrivate));
 
+  gobject_class->finalize = gst_gl_window_eagl_finalize;
+
   window_class->get_display =
       GST_DEBUG_FUNCPTR (gst_gl_window_eagl_get_display);
   window_class->get_window_handle =
@@ -72,13 +79,24 @@ gst_gl_window_eagl_class_init (GstGLWindowEaglClass * klass)
   window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_eagl_draw);
   window_class->set_preferred_size =
       GST_DEBUG_FUNCPTR (gst_gl_window_eagl_set_preferred_size);
+  window_class->send_message_async =
+      GST_DEBUG_FUNCPTR (gst_gl_window_eagl_send_message_async);
 }
 
 static void
 gst_gl_window_eagl_init (GstGLWindowEagl * window)
 {
   window->priv = GST_GL_WINDOW_EAGL_GET_PRIVATE (window);
+  window->priv->gl_queue =
+      dispatch_queue_create ("org.freedesktop.gstreamer.glwindow", NULL);
+}
 
+static void
+gst_gl_window_eagl_finalize (GObject * object)
+{
+  GstGLWindowEagl *window = GST_GL_WINDOW_EAGL (object);
+  dispatch_release (window->priv->gl_queue);
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 /* Must be called in the gl thread */
@@ -126,6 +144,30 @@ gst_gl_window_eagl_set_preferred_size (GstGLWindow * window, gint width, gint he
   window_eagl->priv->preferred_height = height;
 }
 
+static void
+gst_gl_window_eagl_send_message_async (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data, GDestroyNotify destroy)
+{
+  GstGLWindowEagl *window_eagl = (GstGLWindowEagl *) window;
+  GstGLContext *context = gst_gl_window_get_context (window);
+
+  if (gst_gl_context_get_thread (context) == g_thread_self()) {
+    /* this case happens for nested calls happening from inside the GCD queue */
+    callback (data);
+    if (destroy)
+      destroy (data);
+    gst_object_unref (context);
+  } else {
+    dispatch_async (window_eagl->priv->gl_queue, ^{
+      gst_gl_context_activate (context, TRUE);
+      gst_object_unref (context);
+      callback (data);
+      if (destroy)
+        destroy (data);
+    });
+  }
+}
+
 static void
 draw_cb (gpointer data)
 {