glcontext: implement checking whether a context has been shared

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
This commit is contained in:
Matthew Waters 2016-01-07 14:02:52 +11:00 committed by Tim-Philipp Müller
parent a0a0e51249
commit 472970324c
3 changed files with 93 additions and 24 deletions

View file

@ -138,35 +138,52 @@ load_self_module (gpointer user_data)
#error "Add module loading support for GLES3" #error "Add module loading support for GLES3"
#endif #endif
/* Context sharedness es tracked by a unique id stored in each context object /* Context sharedness is tracked by a refcounted pointer stored in each context
* in order track complex creation/deletion scenarios. As a result, sharedness * object to track complex creation/deletion scenarios. As a result,
* can only be successfully validated between two GstGLContext's where one is * sharedness can only be successfully validated between two GstGLContext's
* not a wrapped context. * where one is not a wrapped context.
* *
* As there is no API at the winsys level to tell whether two OpenGL contexts * 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. * 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
static guint
_new_sharegroup_id (void)
{ {
guint current, ret; volatile int refcount;
};
do { static struct ContextShareGroup *
current = g_atomic_int_get (&sharegroup_idx); _context_share_group_new (void)
ret = current + 1; {
struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1);
/* 0 is special */ ret->refcount = 1;
if (ret == 0)
ret++;
} while (!g_atomic_int_compare_and_exchange (&sharegroup_idx, current, ret));
GST_TRACE ("generated new share group id %u", ret);
return ret; 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 #define GST_CAT_DEFAULT gst_gl_context_debug
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
@ -194,7 +211,7 @@ struct _GstGLContextPrivate
gboolean alive; gboolean alive;
GWeakRef other_context_ref; GWeakRef other_context_ref;
guint sharegroup_id; struct ContextShareGroup *sharegroup;
GError **error; GError **error;
gint gl_major; gint gl_major;
@ -389,7 +406,7 @@ gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
context = (GstGLContext *) context_wrap; context = (GstGLContext *) context_wrap;
context->display = gst_object_ref (display); 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->handle = handle;
context_wrap->platform = context_type; context_wrap->platform = context_type;
context_wrap->available_apis = available_apis; context_wrap->available_apis = available_apis;
@ -638,6 +655,9 @@ gst_gl_context_finalize (GObject * object)
gst_object_unref (context->window); gst_object_unref (context->window);
} }
if (context->priv->sharegroup)
_context_share_group_unref (context->priv->sharegroup);
gst_object_unref (context->display); gst_object_unref (context->display);
if (context->gl_vtable) { 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); 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 */ /* check if the contexts are descendants or the root nodes are the same */
return context->priv->sharegroup_id != 0 return context->priv->sharegroup != NULL
&& context->priv->sharegroup_id == other_context->priv->sharegroup_id; && 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); g_weak_ref_set (&context->priv->other_context_ref, other_context);
context->priv->error = error; context->priv->error = error;
if (other_context == NULL) if (other_context == NULL)
context->priv->sharegroup_id = _new_sharegroup_id (); context->priv->sharegroup = _context_share_group_new ();
else 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", context->priv->gl_thread = g_thread_new ("gstglcontext",
(GThreadFunc) gst_gl_context_create_thread, context); (GThreadFunc) gst_gl_context_create_thread, context);
@ -1590,6 +1611,23 @@ gst_gl_context_get_current (void)
return g_private_get (&current_context_key); 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 static GstGLAPI
gst_gl_wrapped_context_get_gl_api (GstGLContext * context) gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
{ {

View 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); guintptr gst_gl_context_get_current_gl_context (GstGLPlatform platform);
GstGLAPI gst_gl_context_get_current_gl_api (GstGLPlatform platform, guint *major, guint *minor); 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); gboolean gst_gl_context_fill_info (GstGLContext * context, GError ** error);
/* FIXME: remove */ /* FIXME: remove */

View file

@ -489,6 +489,34 @@ GST_START_TEST (test_context_can_share)
GST_END_TEST; 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 * static Suite *
gst_gl_context_suite (void) 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_wrapped_context);
tcase_add_test (tc_chain, test_current_context); tcase_add_test (tc_chain, test_current_context);
tcase_add_test (tc_chain, test_context_can_share); tcase_add_test (tc_chain, test_context_can_share);
tcase_add_test (tc_chain, test_is_shared);
return s; return s;
} }