display/egl: implement getting the EGLDisplay of a specific platform
authorMatthew Waters <matthew@centricular.com>
Thu, 27 Nov 2014 04:50:04 +0000 (15:50 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:24 +0000 (19:32 +0000)
https://bugzilla.gnome.org/show_bug.cgi?id=774518

gst-libs/gst/gl/egl/gstglcontext_egl.c
gst-libs/gst/gl/egl/gstglcontext_egl.h
gst-libs/gst/gl/egl/gstgldisplay_egl.c
gst-libs/gst/gl/egl/gstgldisplay_egl.h

index 305a3d4..d348ac0 100644 (file)
@@ -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
index 728689a..e851261 100644 (file)
@@ -25,6 +25,8 @@
 #include <gst/gl/gl.h>
 #include <gst/gl/egl/gstegl.h>
 
+#include <gst/gl/egl/gstgldisplay_egl.h>
+
 G_BEGIN_DECLS
 
 typedef struct _GstGLContextEGL GstGLContextEGL;
@@ -52,6 +54,8 @@ struct _GstGLContextEGL
   /* <private> */
   GstGLContext context;
 
+  GstGLDisplayEGL *display_egl;
+
   EGLContext egl_context;
   EGLDisplay egl_display;
   EGLSurface egl_surface;
index a208808..06ddc9b 100644 (file)
 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);
@@ -68,6 +81,87 @@ gst_gl_display_egl_finalize (GObject * 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:
  *
  * Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY.
@@ -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)
 {
index 6ec7ccc..f81aeb2 100644 (file)
@@ -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