glcontext: implement checking whether a context has been shared
authorMatthew Waters <matthew@centricular.com>
Thu, 7 Jan 2016 03:02:52 +0000 (14:02 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:14 +0000 (19:32 +0000)
Some operations are unnecessary when running with only a single GL
context.
e.g. glFlush when setting a fence object as the flush happens on wait.

API: gst_gl_context_is_shared

gst-libs/gst/gl/gstglcontext.c
gst-libs/gst/gl/gstglcontext.h
tests/check/libs/gstglcontext.c

index 736e9c0..f103146 100644 (file)
@@ -138,33 +138,50 @@ load_self_module (gpointer user_data)
 #error "Add module loading support for GLES3"
 #endif
 
-/* Context sharedness es tracked by a unique id stored in each context object
- * in order track complex creation/deletion scenarios.  As a result, sharedness
- * can only be successfully validated between two GstGLContext's where one is
- * not a wrapped context.
+/* Context sharedness is tracked by a refcounted pointer stored in each context
+ * object to track complex creation/deletion scenarios.  As a result,
+ * sharedness can only be successfully validated between two GstGLContext's
+ * where one is not a wrapped context.
  *
  * As there is no API at the winsys level to tell whether two OpenGL contexts
  * can share GL resources, this is the next best thing.
+ *
+ * XXX: we may need a way to associate two wrapped GstGLContext's as being
+ * shared however I have not come across a use case that requries this yet.
  */
-static volatile guint sharegroup_idx;
+struct ContextShareGroup
+{
+  volatile int refcount;
+};
 
-static guint
-_new_sharegroup_id (void)
+static struct ContextShareGroup *
+_context_share_group_new (void)
 {
-  guint current, ret;
+  struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1);
 
-  do {
-    current = g_atomic_int_get (&sharegroup_idx);
-    ret = current + 1;
+  ret->refcount = 1;
 
-    /* 0 is special */
-    if (ret == 0)
-      ret++;
-  } while (!g_atomic_int_compare_and_exchange (&sharegroup_idx, current, ret));
+  return ret;
+}
 
-  GST_TRACE ("generated new share group id %u", ret);
+static struct ContextShareGroup *
+_context_share_group_ref (struct ContextShareGroup *share)
+{
+  g_atomic_int_inc (&share->refcount);
+  return share;
+}
 
-  return ret;
+static void
+_context_share_group_unref (struct ContextShareGroup *share)
+{
+  if (g_atomic_int_dec_and_test (&share->refcount))
+    g_free (share);
+}
+
+static gboolean
+_context_share_group_is_shared (struct ContextShareGroup *share)
+{
+  return g_atomic_int_get (&share->refcount) > 1;
 }
 
 #define GST_CAT_DEFAULT gst_gl_context_debug
@@ -194,7 +211,7 @@ struct _GstGLContextPrivate
   gboolean alive;
 
   GWeakRef other_context_ref;
-  guint sharegroup_id;
+  struct ContextShareGroup *sharegroup;
   GError **error;
 
   gint gl_major;
@@ -389,7 +406,7 @@ gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
   context = (GstGLContext *) context_wrap;
 
   context->display = gst_object_ref (display);
-  context->priv->sharegroup_id = _new_sharegroup_id ();
+  context->priv->sharegroup = _context_share_group_new ();
   context_wrap->handle = handle;
   context_wrap->platform = context_type;
   context_wrap->available_apis = available_apis;
@@ -638,6 +655,9 @@ gst_gl_context_finalize (GObject * object)
     gst_object_unref (context->window);
   }
 
+  if (context->priv->sharegroup)
+    _context_share_group_unref (context->priv->sharegroup);
+
   gst_object_unref (context->display);
 
   if (context->gl_vtable) {
@@ -887,8 +907,8 @@ gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
   g_return_val_if_fail (GST_IS_GL_CONTEXT (other_context), FALSE);
 
   /* check if the contexts are descendants or the root nodes are the same */
-  return context->priv->sharegroup_id != 0
-      && context->priv->sharegroup_id == other_context->priv->sharegroup_id;
+  return context->priv->sharegroup != NULL
+      && context->priv->sharegroup == other_context->priv->sharegroup;
 }
 
 /**
@@ -929,9 +949,10 @@ gst_gl_context_create (GstGLContext * context,
     g_weak_ref_set (&context->priv->other_context_ref, other_context);
     context->priv->error = error;
     if (other_context == NULL)
-      context->priv->sharegroup_id = _new_sharegroup_id ();
+      context->priv->sharegroup = _context_share_group_new ();
     else
-      context->priv->sharegroup_id = other_context->priv->sharegroup_id;
+      context->priv->sharegroup =
+          _context_share_group_ref (other_context->priv->sharegroup);
 
     context->priv->gl_thread = g_thread_new ("gstglcontext",
         (GThreadFunc) gst_gl_context_create_thread, context);
@@ -1590,6 +1611,23 @@ gst_gl_context_get_current (void)
   return g_private_get (&current_context_key);
 }
 
+/**
+ * gst_gl_context_is_shared:
+ * @context: a #GstGLContext
+ *
+ * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
+ *
+ * Since: 1.8
+ */
+gboolean
+gst_gl_context_is_shared (GstGLContext * context)
+{
+  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
+  g_return_val_if_fail (context->priv->alive, FALSE);
+
+  return _context_share_group_is_shared (context->priv->sharegroup);
+}
+
 static GstGLAPI
 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
 {
index 04cf3a5..64464aa 100644 (file)
@@ -148,6 +148,8 @@ gboolean      gst_gl_context_check_feature (GstGLContext *context, const gchar *
 guintptr      gst_gl_context_get_current_gl_context     (GstGLPlatform platform);
 GstGLAPI      gst_gl_context_get_current_gl_api         (GstGLPlatform platform, guint *major, guint *minor);
 
+gboolean      gst_gl_context_is_shared                  (GstGLContext * context);
+
 gboolean gst_gl_context_fill_info (GstGLContext * context, GError ** error);
 
 /* FIXME: remove */
index edbf9f9..e626f2a 100644 (file)
@@ -489,6 +489,34 @@ GST_START_TEST (test_context_can_share)
 
 GST_END_TEST;
 
+GST_START_TEST (test_is_shared)
+{
+  GstGLContext *c1, *c2;
+  GError *error = NULL;
+
+  c1 = gst_gl_context_new (display);
+  gst_gl_context_create (c1, NULL, &error);
+  fail_if (error != NULL, "Error creating context %s\n",
+      error ? error->message : "Unknown Error");
+
+  c2 = gst_gl_context_new (display);
+  gst_gl_context_create (c2, c1, &error);
+  fail_if (error != NULL, "Error creating context %s\n",
+      error ? error->message : "Unknown Error");
+
+  fail_unless (gst_gl_context_is_shared (c1));
+  fail_unless (gst_gl_context_is_shared (c2));
+
+  gst_object_unref (c2);
+  c2 = NULL;
+
+  fail_unless (!gst_gl_context_is_shared (c1));
+
+  gst_object_unref (c1);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_gl_context_suite (void)
 {
@@ -501,6 +529,7 @@ gst_gl_context_suite (void)
   tcase_add_test (tc_chain, test_wrapped_context);
   tcase_add_test (tc_chain, test_current_context);
   tcase_add_test (tc_chain, test_context_can_share);
+  tcase_add_test (tc_chain, test_is_shared);
 
   return s;
 }