From 81ceca1aea35cfebf2d4b9b994a6c1ec20adf5b4 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 28 Oct 2014 17:31:37 +1100 Subject: [PATCH] glcontext: add api for retreiving the current context and api that is current in the calling thread. --- docs/libs/gst-plugins-bad-libs-sections.txt | 2 + gst-libs/gst/gl/cocoa/gstglcontext_cocoa.h | 1 + gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m | 6 + gst-libs/gst/gl/eagl/gstglcontext_eagl.h | 1 + gst-libs/gst/gl/eagl/gstglcontext_eagl.m | 5 + gst-libs/gst/gl/egl/gstglcontext_egl.c | 11 +- gst-libs/gst/gl/egl/gstglcontext_egl.h | 1 + gst-libs/gst/gl/gstglcontext.c | 169 +++++++++++++++++++- gst-libs/gst/gl/gstglcontext.h | 6 +- gst-libs/gst/gl/win32/gstglcontext_wgl.c | 9 +- gst-libs/gst/gl/win32/gstglcontext_wgl.h | 1 + gst-libs/gst/gl/x11/gstglcontext_glx.c | 13 +- gst-libs/gst/gl/x11/gstglcontext_glx.h | 1 + tests/check/libs/gstglcontext.c | 55 +++++++ 14 files changed, 268 insertions(+), 13 deletions(-) diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt index f9051fa574..939004e00a 100644 --- a/docs/libs/gst-plugins-bad-libs-sections.txt +++ b/docs/libs/gst-plugins-bad-libs-sections.txt @@ -804,6 +804,8 @@ gst_gl_context_get_display gst_gl_context_get_gl_api gst_gl_context_get_gl_context gst_gl_context_get_gl_platform +gst_gl_context_get_current_gl_context +gst_gl_context_get_current_gl_api gst_gl_context_get_thread gst_gl_context_can_share gst_gl_context_check_feature diff --git a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.h b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.h index d7f0e044c1..1c5d66debe 100644 --- a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.h +++ b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.h @@ -61,6 +61,7 @@ struct _GstGLContextCocoaClass { GType gst_gl_context_cocoa_get_type (void); GstGLContextCocoa * gst_gl_context_cocoa_new (void); +guintptr gst_gl_context_cocoa_get_current_context (void); G_END_DECLS diff --git a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m index 7a12650cc0..94da0bca97 100644 --- a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m +++ b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m @@ -363,3 +363,9 @@ gst_gl_context_cocoa_get_gl_platform (GstGLContext * context) { return GST_GL_PLATFORM_CGL; } + +guintptr +gst_gl_context_cocoa_get_current_context (void) +{ + return (guintptr) [NSOpenGLContext currentContext]; +} diff --git a/gst-libs/gst/gl/eagl/gstglcontext_eagl.h b/gst-libs/gst/gl/eagl/gstglcontext_eagl.h index bc4618cf20..fca51772a2 100644 --- a/gst-libs/gst/gl/eagl/gstglcontext_eagl.h +++ b/gst-libs/gst/gl/eagl/gstglcontext_eagl.h @@ -61,6 +61,7 @@ GstGLContextEagl * gst_gl_context_eagl_new (void); 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); G_END_DECLS diff --git a/gst-libs/gst/gl/eagl/gstglcontext_eagl.m b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m index e3b71f355f..ab86912773 100644 --- a/gst-libs/gst/gl/eagl/gstglcontext_eagl.m +++ b/gst-libs/gst/gl/eagl/gstglcontext_eagl.m @@ -341,3 +341,8 @@ gst_gl_context_eagl_get_gl_platform (GstGLContext * context) return GST_GL_PLATFORM_EAGL; } +guintptr +gst_gl_context_eagl_get_current_context (void) +{ + return (guintptr) [EAGLContext currentContext]; +} diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index 16adff9281..aebbdd57d6 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -82,6 +82,8 @@ gst_gl_context_egl_class_init (GstGLContextEGLClass * klass) GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_proc_address); context_class->check_feature = GST_DEBUG_FUNCPTR (gst_gl_context_egl_check_feature); + context_class->get_current_context = + GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_current_context); } static void @@ -550,8 +552,9 @@ gst_gl_context_egl_get_proc_address (GstGLContext * context, const gchar * name) { gpointer result = NULL; static GOnce g_once = G_ONCE_INIT; + GstGLAPI gl_api = gst_gl_context_get_gl_api (context); - result = gst_gl_context_default_get_proc_address (context, name); + result = gst_gl_context_default_get_proc_address (gl_api, name); g_once (&g_once, load_egl_module, NULL); @@ -583,3 +586,9 @@ gst_gl_context_egl_check_feature (GstGLContext * context, const gchar * feature) return FALSE; } + +guintptr +gst_gl_context_egl_get_current_context (void) +{ + return (guintptr) eglGetCurrentContext (); +} diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.h b/gst-libs/gst/gl/egl/gstglcontext_egl.h index 96018655ac..2f950f8b03 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.h +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.h @@ -57,6 +57,7 @@ struct _GstGLContextEGLClass { GType gst_gl_context_egl_get_type (void); GstGLContextEGL * gst_gl_context_egl_new (void); +guintptr gst_gl_context_egl_get_current_context (void); /* TODO: * add support for EGL_NO_CONTEXT diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c index 783fb04509..2393a532e2 100644 --- a/gst-libs/gst/gl/gstglcontext.c +++ b/gst-libs/gst/gl/gstglcontext.c @@ -67,6 +67,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_performance); static GModule *module_self; +static GOnce module_self_gonce = G_ONCE_INIT; #if GST_GL_HAVE_OPENGL static GOnce module_opengl_gonce = G_ONCE_INIT; @@ -118,6 +119,14 @@ load_gles2_module (gpointer user_data) } #endif +static gpointer +load_self_module (gpointer user_data) +{ + module_self = g_module_open (NULL, G_MODULE_BIND_LAZY); + + return NULL; +} + #if GST_GL_HAVE_GLES3 #error "Add module loading support for GLES3" #endif @@ -132,6 +141,8 @@ G_DEFINE_ABSTRACT_TYPE (GstGLContext, gst_gl_context, GST_TYPE_OBJECT); (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT, GstGLContextPrivate)) static gpointer gst_gl_context_create_thread (GstGLContext * context); +static gpointer _default_get_proc_address (GstGLContext * context, + const gchar * name); static void gst_gl_context_finalize (GObject * object); struct _GstGLContextPrivate @@ -226,10 +237,7 @@ gst_gl_context_class_init (GstGLContextClass * klass) { g_type_class_add_private (klass, sizeof (GstGLContextPrivate)); - module_self = g_module_open (NULL, G_MODULE_BIND_LAZY); - - klass->get_proc_address = - GST_DEBUG_FUNCPTR (gst_gl_context_default_get_proc_address); + klass->get_proc_address = GST_DEBUG_FUNCPTR (_default_get_proc_address); G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize; } @@ -339,6 +347,144 @@ gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle, return context; } +/** + * gst_gl_context_get_current_gl_context: + * @context_type: a #GstGLPlatform specifying the type of context to retreive + * + * Returns: The OpenGL context handle current in the calling thread or %NULL + */ +guintptr +gst_gl_context_get_current_gl_context (GstGLPlatform context_type) +{ + guintptr handle = 0; + + _init_debug (); + +#if GST_GL_HAVE_PLATFORM_GLX + if (!handle && (context_type & GST_GL_PLATFORM_GLX) != 0) + handle = gst_gl_context_glx_get_current_context (); +#endif +#if GST_GL_HAVE_PLATFORM_EGL + if (!handle && (context_type & GST_GL_PLATFORM_EGL) != 0) + handle = gst_gl_context_egl_get_current_context (); +#endif +#if GST_GL_HAVE_PLATFORM_CGL + if (!handle && (context_type & GST_GL_PLATFORM_CGL) != 0) + handle = gst_gl_context_cocoa_get_current_context (); +#endif +#if GST_GL_HAVE_PLATFORM_WGL + if (!handle && (context_type & GST_GL_PLATFORM_WGL) != 0) + handle = gst_gl_context_wgl_get_current_context (); +#endif +#if GST_GL_HAVE_PLATFORM_EAGL + if (!handle && (context_type & GST_GL_PLATFORM_EAGL) != 0) + handle = gst_gl_context_eagl_get_current_context (); +#endif + + if (!handle) + GST_WARNING ("Could not retreive current context"); + + return handle; +} + +/** + * gst_gl_context_get_current_gl_api: + * @context_type: a #GstGLPlatform specifying the type of context to retreive + * @major: (out): (allow-none): the major version + * @minor: (out): (allow-none): the minor version + * + * If an error occurs, @major and @minor aren't modified and %GST_GL_API_NONE is + * returned. + * + * Returns: The version supported by the OpenGL context current in the calling + * thread or %GST_GL_API_NONE + */ +GstGLAPI +gst_gl_context_get_current_gl_api (guint * major, guint * minor) +{ + const GLubyte *(*GetString) (GLenum name); + void (*GetIntegerv) (GLenum name, GLuint * n); + const gchar *version; + gint maj, min, n; + GstGLAPI ret = (1 << 31); + + _init_debug (); + + while (ret != GST_GL_API_NONE) { + /* FIXME: attempt to delve into the platform specific GetProcAddress */ + GetString = gst_gl_context_default_get_proc_address (ret, "glGetString"); + GetIntegerv = + gst_gl_context_default_get_proc_address (ret, "glGetIntegerv"); + if (!GetString) { + goto next; + } + + version = (const gchar *) GetString (GL_VERSION); + if (!version) + goto next; + + /* strlen (x.x) == 3 */ + n = strlen (version); + if (n < 3) + goto next; + + if (g_strstr_len (version, 9, "OpenGL ES")) { + /* strlen (OpenGL ES x.x) == 13 */ + if (n < 13) + goto next; + + sscanf (&version[10], "%d.%d", &maj, &min); + + if (maj <= 0 || min < 0) + goto next; + + if (maj == 1) { + ret = GST_GL_API_GLES1; + break; + } else if (maj == 2 || maj == 3) { + ret = GST_GL_API_GLES2; + break; + } + + goto next; + } else { + GLuint context_flags = 0; + sscanf (version, "%d.%d", &maj, &min); + + if (maj <= 0 || min < 0) + goto next; + +#if GST_GL_HAVE_OPENGL + if (GetIntegerv && (maj > 3 || (maj == 3 && min > 1))) { + ret = GST_GL_API_NONE; + GetIntegerv (GL_CONTEXT_PROFILE_MASK, &context_flags); + if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT) + ret |= GST_GL_API_OPENGL3; + if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + ret |= GST_GL_API_OPENGL; + break; + } +#endif + ret = GST_GL_API_OPENGL; + break; + } + + next: + /* iterate through the apis */ + ret >>= 1; + } + + if (ret == GST_GL_API_NONE) + return GST_GL_API_NONE; + + if (major) + *major = maj; + if (minor) + *minor = min; + + return ret; +} + static void gst_gl_context_finalize (GObject * object) { @@ -466,6 +612,14 @@ gst_gl_context_get_gl_api (GstGLContext * context) return context_class->get_gl_api (context); } +static gpointer +_default_get_proc_address (GstGLContext * context, const gchar * name) +{ + GstGLAPI gl_api = gst_gl_context_get_gl_api (context); + + return gst_gl_context_default_get_proc_address (gl_api, name); +} + /** * gst_gl_context_get_proc_address: * @context: a #GstGLContext @@ -496,11 +650,9 @@ gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name) } gpointer -gst_gl_context_default_get_proc_address (GstGLContext * context, - const gchar * name) +gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar * name) { gpointer ret = NULL; - GstGLAPI gl_api = gst_gl_context_get_gl_api (context); /* First try to load symbol from the selected GL API for this context */ #if GST_GL_HAVE_GLES2 @@ -520,6 +672,7 @@ gst_gl_context_default_get_proc_address (GstGLContext * context, #endif /* Otherwise fall back to the current module */ + g_once (&module_self_gonce, load_self_module, NULL); if (!ret) g_module_symbol (module_self, name, &ret); @@ -1281,7 +1434,7 @@ void gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min) { g_return_if_fail (GST_GL_IS_CONTEXT (context)); - g_return_if_fail (maj == NULL && min == NULL); + g_return_if_fail (maj != NULL && min != NULL); if (maj) *maj = context->priv->gl_major; diff --git a/gst-libs/gst/gl/gstglcontext.h b/gst-libs/gst/gl/gstglcontext.h index d2acc0deee..9d243d1c69 100644 --- a/gst-libs/gst/gl/gstglcontext.h +++ b/gst-libs/gst/gl/gstglcontext.h @@ -95,6 +95,7 @@ struct _GstGLContext { struct _GstGLContextClass { GstObjectClass parent_class; + guintptr (*get_current_context) (void); guintptr (*get_gl_context) (GstGLContext *context); GstGLAPI (*get_gl_api) (GstGLContext *context); GstGLPlatform (*get_gl_platform) (GstGLContext *context); @@ -132,7 +133,7 @@ gboolean gst_gl_context_can_share (GstGLContext * context, GstGLCont gboolean gst_gl_context_create (GstGLContext *context, GstGLContext *other_context, GError ** error); void gst_gl_context_destroy (GstGLContext *context); -gpointer gst_gl_context_default_get_proc_address (GstGLContext *context, const gchar *name); +gpointer gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar *name); gboolean gst_gl_context_set_window (GstGLContext *context, GstGLWindow *window); GstGLWindow * gst_gl_context_get_window (GstGLContext *context); @@ -141,6 +142,9 @@ void gst_gl_context_get_gl_version (GstGLContext *context, gint *maj, g gboolean gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api, gint maj, gint min); gboolean gst_gl_context_check_feature (GstGLContext *context, const gchar *feature); +guintptr gst_gl_context_get_current_gl_context (GstGLPlatform platform); +GstGLAPI gst_gl_context_get_current_gl_api (guint *major, guint *minor); + /* FIXME: remove */ void gst_gl_context_thread_add (GstGLContext * context, GstGLContextThreadFunc func, gpointer data); diff --git a/gst-libs/gst/gl/win32/gstglcontext_wgl.c b/gst-libs/gst/gl/win32/gstglcontext_wgl.c index 4886e9af52..7547b47272 100644 --- a/gst-libs/gst/gl/win32/gstglcontext_wgl.c +++ b/gst-libs/gst/gl/win32/gstglcontext_wgl.c @@ -289,10 +289,17 @@ static gpointer gst_gl_context_wgl_get_proc_address (GstGLContext * context, const gchar * name) { gpointer result; + GstGLAPI gl_api = gst_gl_context_get_gl_api (context); - if (!(result = gst_gl_context_default_get_proc_address (context, name))) { + if (!(result = gst_gl_context_default_get_proc_address (gl_api, name))) { result = wglGetProcAddress ((LPCSTR) name); } return result; } + +guintptr +gst_gl_context_wgl_get_current_context (void) +{ + return (guintptr) wglGetCurrentContext (); +} diff --git a/gst-libs/gst/gl/win32/gstglcontext_wgl.h b/gst-libs/gst/gl/win32/gstglcontext_wgl.h index b996dc7cbc..d840175e13 100644 --- a/gst-libs/gst/gl/win32/gstglcontext_wgl.h +++ b/gst-libs/gst/gl/win32/gstglcontext_wgl.h @@ -56,6 +56,7 @@ struct _GstGLContextWGLClass { GType gst_gl_context_wgl_get_type (void); GstGLContextWGL * gst_gl_context_wgl_new (void); +guintptr gst_gl_context_wgl_get_current_context (void); G_END_DECLS diff --git a/gst-libs/gst/gl/x11/gstglcontext_glx.c b/gst-libs/gst/gl/x11/gstglcontext_glx.c index 00aa546cef..6614dddf73 100644 --- a/gst-libs/gst/gl/x11/gstglcontext_glx.c +++ b/gst-libs/gst/gl/x11/gstglcontext_glx.c @@ -96,6 +96,8 @@ gst_gl_context_glx_class_init (GstGLContextGLXClass * klass) GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform); context_class->get_proc_address = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_proc_address); + context_class->get_current_context = + GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_current_context); } static void @@ -197,7 +199,7 @@ gst_gl_context_glx_create_context (GstGLContext * context, context_attribs_3); x_error = gst_gl_window_x11_untrap_x_errors (); - context_glx->priv->context_api = GST_GL_API_OPENGL3 | GST_GL_API_OPENGL; + context_glx->priv->context_api = GST_GL_API_OPENGL; if (!context_glx->glx_context || x_error != 0) { GST_DEBUG ("Failed to create an Opengl 3 context. trying a legacy one"); @@ -423,10 +425,17 @@ static gpointer gst_gl_context_glx_get_proc_address (GstGLContext * context, const gchar * name) { gpointer result; + GstGLAPI gl_api = gst_gl_context_get_gl_api (context); - if (!(result = gst_gl_context_default_get_proc_address (context, name))) { + if (!(result = gst_gl_context_default_get_proc_address (gl_api, name))) { result = glXGetProcAddressARB ((const GLubyte *) name); } return result; } + +guintptr +gst_gl_context_glx_get_current_context (void) +{ + return (guintptr) glXGetCurrentContext (); +} diff --git a/gst-libs/gst/gl/x11/gstglcontext_glx.h b/gst-libs/gst/gl/x11/gstglcontext_glx.h index eca8d7f5d6..0c08f24b84 100644 --- a/gst-libs/gst/gl/x11/gstglcontext_glx.h +++ b/gst-libs/gst/gl/x11/gstglcontext_glx.h @@ -60,6 +60,7 @@ struct _GstGLContextGLXClass { GType gst_gl_context_glx_get_type (void); GstGLContextGLX * gst_gl_context_glx_new (void); +guintptr gst_gl_context_glx_get_current_context (void); G_END_DECLS diff --git a/tests/check/libs/gstglcontext.c b/tests/check/libs/gstglcontext.c index bb7e295b08..d9249e921b 100644 --- a/tests/check/libs/gstglcontext.c +++ b/tests/check/libs/gstglcontext.c @@ -341,6 +341,60 @@ GST_START_TEST (test_wrapped_context) GST_END_TEST; +struct context_info +{ + GstGLAPI api; + guint major; + guint minor; + GstGLPlatform platform; + guintptr handle; +}; + +static void +_fill_context_info (GstGLContext * context, struct context_info *info) +{ + info->handle = gst_gl_context_get_current_gl_context (info->platform); + info->api = gst_gl_context_get_current_gl_api (&info->major, &info->minor); +} + +GST_START_TEST (test_current_context) +{ + GstGLContext *context; + GError *error = NULL; + guintptr handle; + GstGLPlatform platform; + GstGLAPI api; + gint major, minor; + struct context_info info; + + context = gst_gl_context_new (display); + + gst_gl_context_create (context, 0, &error); + + fail_if (error != NULL, "Error creating master context %s\n", + error ? error->message : "Unknown Error"); + + handle = gst_gl_context_get_gl_context (context); + platform = gst_gl_context_get_gl_platform (context); + api = gst_gl_context_get_gl_api (context); + gst_gl_context_get_gl_version (context, &major, &minor); + + info.platform = platform; + + gst_gl_context_thread_add (context, + (GstGLContextThreadFunc) _fill_context_info, &info); + + fail_if (info.platform != platform); + fail_if (info.api != api); + fail_if (info.major != major); + fail_if (info.minor != minor); + fail_if (info.handle != handle); + + gst_object_unref (context); +} + +GST_END_TEST; + static Suite * gst_gl_context_suite (void) @@ -352,6 +406,7 @@ gst_gl_context_suite (void) tcase_add_checked_fixture (tc_chain, setup, teardown); tcase_add_test (tc_chain, test_share); tcase_add_test (tc_chain, test_wrapped_context); + tcase_add_test (tc_chain, test_current_context); return s; }