gl/wayland: implement basic video overlay support via subsurfaces
authorMatthew Waters <matthew@centricular.com>
Wed, 27 May 2015 06:39:06 +0000 (16:39 +1000)
committerMatthew Waters <matthew@centricular.com>
Sun, 31 May 2015 06:04:13 +0000 (16:04 +1000)
Currently does not position the subsurface relative to the parent surface at all

gst-libs/gst/gl/egl/gstglcontext_egl.c
gst-libs/gst/gl/wayland/gstgldisplay_wayland.c
gst-libs/gst/gl/wayland/gstgldisplay_wayland.h
gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c
gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h

index f1fb70f..14be7c6 100644 (file)
@@ -34,6 +34,9 @@
 #include "../x11/gstglwindow_x11.h"
 #include <gst/gl/x11/gstgldisplay_x11.h>
 #endif
+#if GST_GL_HAVE_WINDOW_WAYLAND
+#include "../wayland/gstglwindow_wayland_egl.h"
+#endif
 #if GST_GL_HAVE_WINDOW_WIN32
 #include "../win32/gstglwindow_win32.h"
 #endif
@@ -393,6 +396,12 @@ gst_gl_context_egl_create_context (GstGLContext * context,
       gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window);
     }
 #endif
+#if GST_GL_HAVE_WINDOW_WAYLAND
+    if (GST_GL_IS_WINDOW_WAYLAND_EGL (context->window)) {
+      gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *)
+          context->window);
+    }
+#endif
 #if GST_GL_HAVE_WINDOW_WIN32
     if (GST_GL_IS_WINDOW_WIN32 (context->window)) {
       gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window);
index 90cf1ea..c5c5094 100644 (file)
@@ -45,6 +45,9 @@ registry_handle_global (void *data, struct wl_registry *registry,
   if (g_strcmp0 (interface, "wl_compositor") == 0) {
     display->compositor =
         wl_registry_bind (registry, name, &wl_compositor_interface, 1);
+  } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) {
+    display->subcompositor =
+        wl_registry_bind (registry, name, &wl_subcompositor_interface, 1);
   } else if (g_strcmp0 (interface, "wl_shell") == 0) {
     display->shell = wl_registry_bind (registry, name, &wl_shell_interface, 1);
   }
index 67b3883..3612c78 100644 (file)
@@ -55,6 +55,7 @@ struct _GstGLDisplayWayland
   struct wl_display       *display;
   struct wl_registry      *registry;
   struct wl_compositor    *compositor;
+  struct wl_subcompositor *subcompositor;
   struct wl_shell         *shell;
 
   /* <private> */
index 6679abc..519f9af 100644 (file)
@@ -48,6 +48,7 @@ static guintptr gst_gl_window_wayland_egl_get_window_handle (GstGLWindow *
     window);
 static void gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window,
     guintptr handle);
+static void gst_gl_window_wayland_egl_show (GstGLWindow * window);
 static void gst_gl_window_wayland_egl_draw (GstGLWindow * window);
 static void gst_gl_window_wayland_egl_run (GstGLWindow * window);
 static void gst_gl_window_wayland_egl_quit (GstGLWindow * window);
@@ -228,56 +229,124 @@ static const struct wl_shell_surface_listener shell_surface_listener = {
   handle_popup_done
 };
 
-static gboolean
-create_surface (GstGLWindowWaylandEGL * window_egl)
+static void
+surface_handle_enter (void *data, struct wl_surface *wl_surface,
+    struct wl_output *output)
 {
-  GstGLDisplayWayland *display =
-      GST_GL_DISPLAY_WAYLAND (GST_GL_WINDOW (window_egl)->display);
-
-  window_egl->window.surface =
-      wl_compositor_create_surface (display->compositor);
-  wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.surface,
-      window_egl->window.queue);
-
-  window_egl->window.shell_surface =
-      wl_shell_get_shell_surface (display->shell, window_egl->window.surface);
-  wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.shell_surface,
-      window_egl->window.queue);
-
-  wl_shell_surface_add_listener (window_egl->window.shell_surface,
-      &shell_surface_listener, window_egl);
-
-  if (window_egl->window.window_width <= 0)
-    window_egl->window.window_width = 320;
-  if (window_egl->window.window_height <= 0)
-    window_egl->window.window_height = 240;
-
-  window_egl->window.native =
-      wl_egl_window_create (window_egl->window.surface,
-      window_egl->window.window_width, window_egl->window.window_height);
+}
 
-  wl_shell_surface_set_title (window_egl->window.shell_surface,
-      "OpenGL Renderer");
+static void
+surface_handle_leave (void *data, struct wl_surface *wl_surface,
+    struct wl_output *output)
+{
+}
 
-  wl_shell_surface_set_toplevel (window_egl->window.shell_surface);
+static const struct wl_surface_listener surface_listener = {
+  surface_handle_enter,
+  surface_handle_leave
+};
 
-  return TRUE;
+static void
+destroy_surfaces (GstGLWindowWaylandEGL * window_egl)
+{
+  if (window_egl->window.subsurface) {
+    wl_subsurface_destroy (window_egl->window.subsurface);
+    window_egl->window.subsurface = NULL;
+  }
+  if (window_egl->window.shell_surface) {
+    wl_shell_surface_destroy (window_egl->window.shell_surface);
+    window_egl->window.shell_surface = NULL;
+  }
+  if (window_egl->window.surface) {
+    wl_surface_destroy (window_egl->window.surface);
+    window_egl->window.surface = NULL;
+  }
+  if (window_egl->window.native) {
+    wl_egl_window_destroy (window_egl->window.native);
+    window_egl->window.native = NULL;
+  }
 }
 
 static void
-destroy_surface (GstGLWindowWaylandEGL * window_egl)
+create_surfaces (GstGLWindowWaylandEGL * window_egl)
 {
-  if (window_egl->window.native)
-    wl_egl_window_destroy (window_egl->window.native);
+  GstGLDisplayWayland *display =
+      GST_GL_DISPLAY_WAYLAND (GST_GL_WINDOW (window_egl)->display);
+  gint width, height;
+
+  if (!window_egl->window.surface) {
+    window_egl->window.surface =
+        wl_compositor_create_surface (display->compositor);
+    if (window_egl->window.queue)
+      wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.surface,
+          window_egl->window.queue);
+  }
 
-  if (window_egl->window.shell_surface)
-    wl_shell_surface_destroy (window_egl->window.shell_surface);
+  if (gst_gl_wl_display_roundtrip_queue (display->display,
+          window_egl->window.queue) < 0) {
+    GST_ERROR_OBJECT (window_egl,
+        "Failed to perform a roundtrip on our wl_event_queue");
+  }
 
-  if (window_egl->window.surface)
-    wl_surface_destroy (window_egl->window.surface);
+  if (window_egl->window.foreign_surface) {
+    /* (re)parent */
+    if (!display->subcompositor) {
+      GST_ERROR_OBJECT (window_egl,
+          "Wayland server does not support subsurfaces");
+      window_egl->window.foreign_surface = NULL;
+      goto shell_window;
+    }
+
+    if (!window_egl->window.subsurface) {
+      window_egl->window.subsurface =
+          wl_subcompositor_get_subsurface (display->subcompositor,
+          window_egl->window.surface, window_egl->window.foreign_surface);
+      if (window_egl->window.queue)
+        wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.subsurface,
+            window_egl->window.queue);
+
+      wl_subsurface_set_position (window_egl->window.subsurface,
+          window_egl->window.window_x, window_egl->window.window_y);
+      wl_subsurface_set_desync (window_egl->window.subsurface);
+    }
+  } else {
+  shell_window:
+    if (!window_egl->window.shell_surface) {
+      window_egl->window.shell_surface =
+          wl_shell_get_shell_surface (display->shell,
+          window_egl->window.surface);
+      if (window_egl->window.queue)
+        wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.
+            shell_surface, window_egl->window.queue);
+
+      wl_shell_surface_add_listener (window_egl->window.shell_surface,
+          &shell_surface_listener, window_egl);
+
+      wl_shell_surface_set_title (window_egl->window.shell_surface,
+          "OpenGL Renderer");
+      wl_shell_surface_set_toplevel (window_egl->window.shell_surface);
+    }
+  }
 
-  if (window_egl->window.callback)
-    wl_callback_destroy (window_egl->window.callback);
+  if (window_egl->window.window_width > 0)
+    width = window_egl->window.window_width;
+  else
+    width = 320;
+  window_egl->window.window_width = width;
+
+  if (window_egl->window.window_height > 0)
+    height = window_egl->window.window_height;
+  else
+    height = 240;
+  window_egl->window.window_height = height;
+
+  if (!window_egl->window.native) {
+    window_egl->window.native =
+        wl_egl_window_create (window_egl->window.surface, width, height);
+    if (window_egl->window.queue)
+      wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.native,
+          window_egl->window.queue);
+  }
 }
 
 static void
@@ -292,6 +361,7 @@ gst_gl_window_wayland_egl_class_init (GstGLWindowWaylandEGLClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_set_window_handle);
   window_class->draw_unlocked =
       GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_draw);
+  window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_show);
   window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_draw);
   window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_run);
   window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_quit);
@@ -343,7 +413,7 @@ gst_gl_window_wayland_egl_close (GstGLWindow * window)
 
   window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
 
-  destroy_surface (window_egl);
+  destroy_surfaces (window_egl);
 
   g_source_destroy (window_egl->wl_source);
   g_source_unref (window_egl->wl_source);
@@ -367,7 +437,7 @@ gst_gl_window_wayland_egl_open (GstGLWindow * window, GError ** error)
 
   wl_display_roundtrip (display->display);
 
-  create_surface (window_egl);
+  create_surfaces (window_egl);
 
   window_egl->wl_source = wayland_event_source_new (display->display,
       window_egl->window.queue);
@@ -442,6 +512,12 @@ gst_gl_window_wayland_egl_send_message_async (GstGLWindow * window,
       message);
 }
 
+void
+gst_gl_window_wayland_egl_create_window (GstGLWindowWaylandEGL * window_egl)
+{
+  create_surfaces (window_egl);
+}
+
 static guintptr
 gst_gl_window_wayland_egl_get_window_handle (GstGLWindow * window)
 {
@@ -452,6 +528,31 @@ static void
 gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window,
     guintptr handle)
 {
+  GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+  struct wl_surface *surface = (struct wl_surface *) handle;
+
+  /* already set the NULL handle */
+  if (surface == NULL && window_egl->window.foreign_surface == NULL)
+    return;
+
+  /* unparent */
+  destroy_surfaces (window_egl);
+  window_egl->window.foreign_surface = surface;
+  create_surfaces (window_egl);
+}
+
+static void
+gst_gl_window_wayland_egl_show (GstGLWindow * window)
+{
+  GstGLDisplayWayland *display_wayland =
+      GST_GL_DISPLAY_WAYLAND (window->display);
+  GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+
+  create_surfaces (window_egl);
+
+  if (gst_gl_wl_display_roundtrip_queue (display_wayland->display,
+          window_egl->window.queue) < 0)
+    GST_WARNING_OBJECT (window, "failed a roundtrip");
 }
 
 static void
@@ -482,11 +583,16 @@ draw_cb (gpointer data)
   GstGLContext *context = gst_gl_window_get_context (window);
   GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
 
+  create_surfaces (window_egl);
+
   if (window->draw)
     window->draw (window->draw_data);
 
   context_class->swap_buffers (context);
 
+  if (window_egl->window.subsurface)
+    wl_subsurface_set_desync (window_egl->window.subsurface);
+
   gst_object_unref (context);
 }
 
index 845b925..3d08f6f 100644 (file)
@@ -64,9 +64,11 @@ struct window {
   struct display *display;
 
   struct wl_event_queue     *queue;
-  struct wl_egl_window      *native;
   struct wl_surface         *surface;
   struct wl_shell_surface   *shell_surface;
+  struct wl_egl_window      *native;
+  struct wl_surface         *foreign_surface;
+  struct wl_subsurface      *subsurface;
   struct wl_callback        *callback;
   int fullscreen, configured;
   int window_width, window_height;
@@ -98,6 +100,8 @@ GType gst_gl_window_wayland_egl_get_type     (void);
 
 GstGLWindowWaylandEGL * gst_gl_window_wayland_egl_new  (void);
 
+void gst_gl_window_wayland_egl_create_window (GstGLWindowWaylandEGL * window_egl);
+
 G_END_DECLS
 
 #endif /* __GST_GL_WINDOW_X11_H__ */