libgstgl: cocoa, eagl: don't marshal GL calls to the context thread
authorAlessandro Decina <alessandro.d@gmail.com>
Mon, 7 Mar 2016 05:03:25 +0000 (16:03 +1100)
committerAlessandro Decina <alessandro.d@gmail.com>
Mon, 7 Mar 2016 05:20:17 +0000 (16:20 +1100)
Execute GL calls without marshalling them to the context thread. In the cocoa
and eagl backends calling gst_gl_context_activate is cheap and therefore calling
it on the current thread and serializing GL calls with a per-context lock is
more efficient (faster and has less overhead) than marshalling everything to the
context thread.

This optimization cuts a large overhead in g_poll (continuously waking up the
context thread) and in g_mutex_*/g_cond_* (waiting for results from the context
thread).

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
gst-libs/gst/gl/eagl/gstglcontext_eagl.h
gst-libs/gst/gl/eagl/gstglcontext_eagl.m
gst-libs/gst/gl/eagl/gstglwindow_eagl.m

index ae7abc8a6ec4b6d1052465b38b34a918301f337c..2459e2a284a8d8cbd1062617f8e2b15b836eb295 100644 (file)
@@ -40,6 +40,7 @@ struct _GstGLContextCocoaPrivate
   GstGLAPI context_api;
 
   gint source_id;
+  GRecMutex current_lock;
 };
 
 
@@ -59,8 +60,13 @@ struct _GstGLContextCocoaPrivate
 
 gboolean gst_gl_window_cocoa_create_window (GstGLWindowCocoa *window_cocoa);
 
+
 void _invoke_on_main (GstGLWindowCB func, gpointer data);
 
+typedef void (*GstGLContextCocoaInvokeFunc) (gpointer data);
+void _gst_gl_context_cocoa_invoke (GstGLContext * context,
+    GstGLContextCocoaInvokeFunc func, gpointer data, GDestroyNotify notify);
+
 G_END_DECLS
 
 #endif /* __GST_GL_COCOA_PRIVATE_H__ */
index ac1e0d6928d9c2bcecad11423a8109a6216c19ac..c50d0069f1703ff3a739d3f54a88b4f49fbd2e3e 100644 (file)
@@ -43,14 +43,18 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_context_cocoa_debug);
 
 G_DEFINE_TYPE_WITH_CODE (GstGLContextCocoa, gst_gl_context_cocoa,
     GST_GL_TYPE_CONTEXT, GST_DEBUG_CATEGORY_INIT (gst_gl_context_cocoa_debug, "glcontext_cocoa", 0, "Cocoa GL Context"); );
+static void gst_gl_context_cocoa_finalize (GObject * object);
 
 static void
 gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass)
 {
+  GObjectClass *gobject_class = (GObjectClass *) klass;
   GstGLContextClass *context_class = (GstGLContextClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GstGLContextCocoaPrivate));
 
+  gobject_class->finalize = gst_gl_context_cocoa_finalize;
+
   context_class->destroy_context =
       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_destroy_context);
   context_class->create_context =
@@ -68,6 +72,13 @@ static void
 gst_gl_context_cocoa_init (GstGLContextCocoa * context)
 {
   context->priv = GST_GL_CONTEXT_COCOA_GET_PRIVATE (context);
+  g_rec_mutex_init (&context->priv->current_lock);
+}
+
+static void gst_gl_context_cocoa_finalize (GObject * object)
+{
+  g_rec_mutex_clear (&GST_GL_CONTEXT_COCOA (object)->priv->current_lock);
+  G_OBJECT_CLASS (gst_gl_context_cocoa_parent_class)->finalize (object);
 }
 
 /* Must be called in the gl thread */
@@ -327,3 +338,17 @@ gst_gl_context_cocoa_get_current_context (void)
 {
   return (guintptr) CGLGetCurrentContext ();
 }
+
+void
+_gst_gl_context_cocoa_invoke (GstGLContext * context,
+        GstGLContextCocoaInvokeFunc func, gpointer data, GDestroyNotify destroy)
+{
+  GstGLContextCocoa *context_cocoa = (GstGLContextCocoa *) context;
+
+  g_rec_mutex_lock (&context_cocoa->priv->current_lock);
+  gst_gl_context_activate (context, TRUE);
+  func (data);
+  if (destroy)
+    destroy (data);
+  g_rec_mutex_unlock (&context_cocoa->priv->current_lock);
+}
index 0d027c5a1aece4bbd0ea217bc3c1ef4595923bc5..3d771fb6d6b5193c4d7dc075307a886af0a3b05c 100644 (file)
@@ -77,6 +77,10 @@ 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);
+static void gst_gl_window_cocoa_send_message (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data);
 
 struct _GstGLWindowCocoaPrivate
 {
@@ -111,6 +115,10 @@ 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);
+  window_class->send_message =
+      GST_DEBUG_FUNCPTR (gst_gl_window_cocoa_send_message);
 
   gobject_class->finalize = gst_gl_window_cocoa_finalize;
 }
@@ -370,6 +378,24 @@ 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)
+{
+  GstGLContext *context = gst_gl_window_get_context (window);
+  _gst_gl_context_cocoa_invoke (context, callback, data, destroy);
+  gst_object_unref (context);
+}
+
+static void
+gst_gl_window_cocoa_send_message (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data)
+{
+  GstGLContext *context = gst_gl_window_get_context (window);
+  _gst_gl_context_cocoa_invoke (context, callback, data, NULL);
+  gst_object_unref (context);
+}
+
 /* =============================================================*/
 /*                                                              */
 /*                    GstGLNSWindow implementation              */
index 262281029cebf0f6f2fc88c2287cd0f532fdb72a..0a36cb9e49b00d3e77817aa3108d59aae269aba2 100644 (file)
@@ -65,6 +65,10 @@ void gst_gl_context_eagl_prepare_draw (GstGLContextEagl * context);
 void gst_gl_context_eagl_finish_draw (GstGLContextEagl * context);
 guintptr gst_gl_context_eagl_get_current_context (void);
 
+/* private */
+typedef void (*GstGLContextEaglInvokeFunc) (gpointer data);
+void _gst_gl_context_eagl_invoke (GstGLContext * context,
+    GstGLContextEaglInvokeFunc func, gpointer data, GDestroyNotify destroy);
 G_END_DECLS
 
 #endif /* __GST_GL_CONTEXT_EAGL_H__ */
index 42dde56cf4611b7833dd104a8bf011173369edb2..293a80d9c6218699e0b9cda9c82fd3cda15557d1 100644 (file)
@@ -31,6 +31,7 @@
 
 #define GST_CAT_DEFAULT gst_gl_context_debug
 
+static void gst_gl_context_eagl_finalize (GObject * object);
 static gboolean gst_gl_context_eagl_create_context (GstGLContext * context,
     GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
 static void gst_gl_context_eagl_destroy_context (GstGLContext * context);
@@ -53,6 +54,7 @@ struct _GstGLContextEaglPrivate
   GLuint framebuffer;
   GLuint color_renderbuffer;
   GLuint depth_renderbuffer;
+  GRecMutex current_lock;
 };
 
 #define GST_GL_CONTEXT_EAGL_GET_PRIVATE(o)  \
@@ -63,12 +65,13 @@ G_DEFINE_TYPE (GstGLContextEagl, gst_gl_context_eagl, GST_GL_TYPE_CONTEXT);
 static void
 gst_gl_context_eagl_class_init (GstGLContextEaglClass * klass)
 {
-  GstGLContextClass *context_class;
-
-  context_class = (GstGLContextClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstGLContextClass *context_class = (GstGLContextClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GstGLContextEaglPrivate));
 
+  gobject_class->finalize = gst_gl_context_eagl_finalize;
+
   context_class->destroy_context =
       GST_DEBUG_FUNCPTR (gst_gl_context_eagl_destroy_context);
   context_class->create_context =
@@ -90,6 +93,14 @@ static void
 gst_gl_context_eagl_init (GstGLContextEagl * context)
 {
   context->priv = GST_GL_CONTEXT_EAGL_GET_PRIVATE (context);
+  g_rec_mutex_init (&context->priv->current_lock);
+}
+
+static void
+gst_gl_context_eagl_finalize (GObject * object)
+{
+  g_rec_mutex_clear (&GST_GL_CONTEXT_EAGL (object)->priv->current_lock);
+  G_OBJECT_CLASS (gst_gl_context_eagl_parent_class)->finalize (object);
 }
 
 /* Must be called in the gl thread */
@@ -363,6 +374,20 @@ gst_gl_context_eagl_activate (GstGLContext * context, gboolean activate)
   return TRUE;
 }
 
+void
+_gst_gl_context_eagl_invoke (GstGLContext * context,
+        GstGLContextEaglInvokeFunc func, gpointer data, GDestroyNotify destroy)
+{
+  GstGLContextEagl *context_eagl = (GstGLContextEagl *) context;
+
+  g_rec_mutex_lock (&context_eagl->priv->current_lock);
+  gst_gl_context_activate (context, TRUE);
+  func (data);
+  if (destroy)
+    destroy (data);
+  g_rec_mutex_unlock (&context_eagl->priv->current_lock);
+}
+
 static GstGLAPI
 gst_gl_context_eagl_get_gl_api (GstGLContext * context)
 {
index eb9d4f7f4a3c10bede91d93bb811937ab251b269..c90a3816d1ba0885c375d0822098f2b1db9b17dd 100644 (file)
@@ -48,6 +48,10 @@ 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);
+static void gst_gl_window_eagl_send_message (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data);
 
 struct _GstGLWindowEaglPrivate
 {
@@ -72,6 +76,10 @@ 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);
+  window_class->send_message =
+      GST_DEBUG_FUNCPTR (gst_gl_window_eagl_send_message);
 }
 
 static void
@@ -125,6 +133,25 @@ gst_gl_window_eagl_set_preferred_size (GstGLWindow * window, gint width, gint he
   window_eagl->priv->preferred_width = width;
   window_eagl->priv->preferred_height = height;
 }
+static void
+gst_gl_window_eagl_send_message_async (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data, GDestroyNotify destroy)
+{
+  GstGLContext *context = gst_gl_window_get_context (window);
+  _gst_gl_context_eagl_invoke (context, callback, data, destroy);
+  gst_object_unref (context);
+}
+
+static void
+gst_gl_window_eagl_send_message (GstGLWindow * window,
+    GstGLWindowCB callback, gpointer data)
+{
+  GstGLContext *context = gst_gl_window_get_context (window);
+  _gst_gl_context_eagl_invoke (context, callback, data, NULL);
+  gst_object_unref (context);
+}
+
 
 static void
 draw_cb (gpointer data)