From 415ce6c96a1b9cde22ef8fd19340670b8c27994f Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 27 Nov 2014 15:50:04 +1100 Subject: [PATCH] display/egl: implement getting the EGLDisplay of a specific platform https://bugzilla.gnome.org/show_bug.cgi?id=774518 --- gst-libs/gst/gl/egl/gstglcontext_egl.c | 42 +++--- gst-libs/gst/gl/egl/gstglcontext_egl.h | 4 + gst-libs/gst/gl/egl/gstgldisplay_egl.c | 171 ++++++++++++++++++++++++- gst-libs/gst/gl/egl/gstgldisplay_egl.h | 4 + 4 files changed, 198 insertions(+), 23 deletions(-) diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index 305a3d46b1..d348ac0aa0 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -313,7 +313,7 @@ gst_gl_context_egl_create_context (GstGLContext * context, EGLint egl_minor; gboolean need_surface = TRUE; guintptr external_gl_context = 0; - GstGLDisplay *display; + guintptr egl_display; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); @@ -337,31 +337,22 @@ gst_gl_context_egl_create_context (GstGLContext * context, goto failure; } - display = gst_gl_context_get_display (context); + if (!egl->display_egl) { + GstGLDisplay *display = gst_gl_context_get_display (context); - if (display->type == GST_GL_DISPLAY_TYPE_EGL) { - egl->egl_display = (EGLDisplay) gst_gl_display_get_handle (display); - } else { - guintptr native_display = gst_gl_display_get_handle (display); - - if (!native_display) { - GstGLWindow *window = NULL; - GST_WARNING ("Failed to get a global display handle, falling back to " - "per-window display handles. Context sharing may not work"); - - if (other_context) - window = gst_gl_context_get_window (other_context); - if (!window) - window = gst_gl_context_get_window (context); - if (window) { - native_display = gst_gl_window_get_display (window); - gst_object_unref (window); - } + egl->display_egl = gst_gl_display_egl_from_gl_display (display); + if (!egl->display_egl) { + g_set_error (error, GST_GL_CONTEXT_ERROR, + GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, + "Failed to create EGLDisplay from native display"); + goto failure; } - egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) native_display); + gst_object_unref (display); } - gst_object_unref (display); + + egl_display = gst_gl_display_get_handle (GST_GL_DISPLAY (egl->display_egl)); + egl->egl_display = (EGLDisplay) egl_display; if (eglInitialize (egl->egl_display, &egl_major, &egl_minor)) { GST_INFO ("egl initialized, version: %d.%d", egl_major, egl_minor); @@ -531,6 +522,8 @@ gst_gl_context_egl_create_context (GstGLContext * context, #endif if (other_context == NULL) { + /* FIXME: fails to show two outputs at all. We need a property/option for + * glimagesink to say its a visible context */ #if GST_GL_HAVE_WINDOW_WAYLAND if (GST_IS_GL_WINDOW_WAYLAND_EGL (context->window)) { gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *) @@ -654,6 +647,11 @@ gst_gl_context_egl_destroy_context (GstGLContext * context) egl->window_handle = 0; eglReleaseThread (); + + if (egl->display_egl) { + gst_object_unref (egl->display_egl); + egl->display_egl = NULL; + } } static gboolean diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.h b/gst-libs/gst/gl/egl/gstglcontext_egl.h index 728689a0f1..e851261809 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.h +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.h @@ -25,6 +25,8 @@ #include #include +#include + G_BEGIN_DECLS typedef struct _GstGLContextEGL GstGLContextEGL; @@ -52,6 +54,8 @@ struct _GstGLContextEGL /* */ GstGLContext context; + GstGLDisplayEGL *display_egl; + EGLContext egl_context; EGLDisplay egl_display; EGLSurface egl_surface; diff --git a/gst-libs/gst/gl/egl/gstgldisplay_egl.c b/gst-libs/gst/gl/egl/gstgldisplay_egl.c index a208808295..06ddc9bdb8 100644 --- a/gst-libs/gst/gl/egl/gstgldisplay_egl.c +++ b/gst-libs/gst/gl/egl/gstgldisplay_egl.c @@ -29,6 +29,19 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); #define GST_CAT_DEFAULT gst_gl_display_debug +#ifndef EGL_PLATFORM_X11 +#define EGL_PLATFORM_X11 0x31D5 +#endif +#ifndef EGL_PLATFORM_WAYLAND +#define EGL_PLATFORM_WAYLAND 0x31D8 +#endif +#ifndef EGL_PLATFORM_ANDROID +#define EGL_PLATFORM_ANDROID 0x3141 +#endif + +typedef EGLDisplay (*_gst_eglGetPlatformDisplay_type) (EGLenum platform, + void *native_display, const EGLint * attrib_list); + G_DEFINE_TYPE (GstGLDisplayEGL, gst_gl_display_egl, GST_TYPE_GL_DISPLAY); static void gst_gl_display_egl_finalize (GObject * object); @@ -67,6 +80,87 @@ gst_gl_display_egl_finalize (GObject * object) G_OBJECT_CLASS (gst_gl_display_egl_parent_class)->finalize (object); } +/** + * gst_gl_display_egl_get_from_native: + * @type: a #GstGLDisplayType + * @display: pointer to a display (or 0) + * + * Attempts to create a new #EGLDisplay from @display. If @type is + * %GST_GL_DISPLAY_TYPE_ANY, then @display must be 0. + * + * Returns: A #EGLDisplay or %EGL_NO_DISPLAY + * + * Since: 1.12 + */ +EGLDisplay +gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display) +{ + const gchar *egl_exts; + EGLDisplay ret = EGL_NO_DISPLAY; + _gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay; + + g_return_val_if_fail ((type != GST_GL_DISPLAY_TYPE_ANY && display != 0) + || (type == GST_GL_DISPLAY_TYPE_ANY && display == 0), EGL_NO_DISPLAY); + g_return_val_if_fail ((type != GST_GL_DISPLAY_TYPE_NONE + || (type == GST_GL_DISPLAY_TYPE_NONE + && display == 0)), EGL_NO_DISPLAY); + + /* given an EGLDisplay already */ + if (type == GST_GL_DISPLAY_TYPE_EGL) + return (EGLDisplay) display; + + if (type == GST_GL_DISPLAY_TYPE_NONE) + type = GST_GL_DISPLAY_TYPE_ANY; + + egl_exts = eglQueryString (EGL_NO_DISPLAY, EGL_EXTENSIONS); + GST_DEBUG ("egl no display extensions: %s", egl_exts); + + if (eglGetError () != EGL_SUCCESS || !egl_exts) + goto default_display; + + /* check if we can actually choose the egl display type */ + if (!gst_gl_check_extension ("EGL_KHR_client_get_all_proc_addresses", + egl_exts)) + goto default_display; + if (!gst_gl_check_extension ("EGL_EXT_platform_base", egl_exts)) + goto default_display; + + _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type) + eglGetProcAddress ("eglGetPlatformDisplay"); + if (!_gst_eglGetPlatformDisplay) + _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type) + eglGetProcAddress ("eglGetPlatformDisplayEXT"); + if (!_gst_eglGetPlatformDisplay) + goto default_display; + + /* try each platform in turn */ +#if GST_GL_HAVE_WINDOW_X11 + if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_X11) && + (gst_gl_check_extension ("EGL_KHR_platform_x11", egl_exts) || + gst_gl_check_extension ("EGL_EXT_platform_x11", egl_exts))) { + ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_X11, (gpointer) display, + NULL); + } +#endif +#if GST_GL_HAVE_WINDOW_WAYLAND + if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_WAYLAND) && + (gst_gl_check_extension ("EGL_KHR_platform_wayland", egl_exts) || + gst_gl_check_extension ("EGL_EXT_platform_wayland", egl_exts))) { + ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_WAYLAND, (gpointer) display, + NULL); + } +#endif + /* android only has one winsys/display connection */ + + if (ret != EGL_NO_DISPLAY) + return ret; + + /* otherwise rely on the implementation to choose the correct display + * based on the pointer */ +default_display: + return eglGetDisplay ((EGLNativeDisplayType) display); +} + /** * gst_gl_display_egl_new: * @@ -82,7 +176,8 @@ gst_gl_display_egl_new (void) GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL); - ret->display = eglGetDisplay ((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY); + ret->display = + gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0); if (!ret->display) { GST_ERROR ("Failed to open EGL display connection"); @@ -98,6 +193,8 @@ gst_gl_display_egl_new (void) * Creates a new display connection from a EGLDisplay. * * Returns: (transfer full): a new #GstGLDisplayEGL + * + * Since: 1.12 */ GstGLDisplayEGL * gst_gl_display_egl_new_with_egl_display (EGLDisplay display) @@ -116,6 +213,78 @@ gst_gl_display_egl_new_with_egl_display (EGLDisplay display) return ret; } +static gpointer +_ref_if_set (gpointer data, gpointer user_data) +{ + if (data) + gst_object_ref (data); + return data; +} + +/** + * gst_gl_display_egl_from_gl_display: + * @display: an existing #GstGLDisplay + * + * Creates a EGL display connection from a native Display. + * + * This function will return the same value for multiple calls with the same + * @display. + * + * Returns: (transfer full): a new #GstGLDisplayEGL + * + * Since: 1.12 + */ +GstGLDisplayEGL * +gst_gl_display_egl_from_gl_display (GstGLDisplay * display) +{ + GstGLDisplayEGL *ret; + GstGLDisplayType display_type; + guintptr native_display; + + g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL); + + GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); + + if (GST_IS_GL_DISPLAY_EGL (display)) { + GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "is already a " + "GstGLDisplayEGL", display); + return gst_object_ref (display); + } + + /* try to get a previously set GstGLDisplayEGL */ + ret = g_object_dup_data (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME, + (GDuplicateFunc) _ref_if_set, NULL); + if (ret && GST_IS_GL_DISPLAY_EGL (ret)) { + GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "already has a " + "GstGLDisplayEGL %" GST_PTR_FORMAT, display, ret); + return ret; + } + + if (ret) + gst_object_unref (ret); + + display_type = gst_gl_display_get_handle_type (display); + native_display = gst_gl_display_get_handle (display); + + g_return_val_if_fail (native_display != 0, NULL); + g_return_val_if_fail (display_type != GST_GL_DISPLAY_TYPE_NONE, NULL); + + ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL); + + ret->display = + gst_gl_display_egl_get_from_native (display_type, native_display); + + if (!ret->display) { + GST_WARNING_OBJECT (ret, "failed to get EGLDisplay from native display"); + gst_object_unref (ret); + return NULL; + } + g_object_set_data_full (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME, + gst_object_ref (ret), (GDestroyNotify) gst_object_unref); + + return ret; +} + static guintptr gst_gl_display_egl_get_handle (GstGLDisplay * display) { diff --git a/gst-libs/gst/gl/egl/gstgldisplay_egl.h b/gst-libs/gst/gl/egl/gstgldisplay_egl.h index 6ec7cccb81..f81aeb26e7 100644 --- a/gst-libs/gst/gl/egl/gstgldisplay_egl.h +++ b/gst-libs/gst/gl/egl/gstgldisplay_egl.h @@ -66,6 +66,10 @@ struct _GstGLDisplayEGLClass GstGLDisplayEGL *gst_gl_display_egl_new (void); GstGLDisplayEGL *gst_gl_display_egl_new_with_egl_display (EGLDisplay display); +GstGLDisplayEGL *gst_gl_display_egl_from_gl_display (GstGLDisplay * display); +EGLDisplay gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display); + +#define GST_GL_DISPLAY_EGL_NAME "gst.gl.display.egl" G_END_DECLS