diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c index 736e9c04f3..f103146b8f 100644 --- a/gst-libs/gst/gl/gstglcontext.c +++ b/gst-libs/gst/gl/gstglcontext.c @@ -138,35 +138,52 @@ 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; - -static guint -_new_sharegroup_id (void) +struct ContextShareGroup { - guint current, ret; + volatile int refcount; +}; - do { - current = g_atomic_int_get (&sharegroup_idx); - ret = current + 1; +static struct ContextShareGroup * +_context_share_group_new (void) +{ + struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1); - /* 0 is special */ - if (ret == 0) - ret++; - } while (!g_atomic_int_compare_and_exchange (&sharegroup_idx, current, ret)); - - GST_TRACE ("generated new share group id %u", ret); + ret->refcount = 1; return ret; } +static struct ContextShareGroup * +_context_share_group_ref (struct ContextShareGroup *share) +{ + g_atomic_int_inc (&share->refcount); + return share; +} + +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 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); @@ -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 (¤t_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) { diff --git a/gst-libs/gst/gl/gstglcontext.h b/gst-libs/gst/gl/gstglcontext.h index 04cf3a5777..64464aa2c3 100644 --- a/gst-libs/gst/gl/gstglcontext.h +++ b/gst-libs/gst/gl/gstglcontext.h @@ -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 */ diff --git a/tests/check/libs/gstglcontext.c b/tests/check/libs/gstglcontext.c index edbf9f90f1..e626f2a7da 100644 --- a/tests/check/libs/gstglcontext.c +++ b/tests/check/libs/gstglcontext.c @@ -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; }