From 54199ea20364f8ee031ca598d0e54319bd0c04d8 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 27 May 2015 16:39:06 +1000 Subject: [PATCH] gl/wayland: implement basic video overlay support via subsurfaces Currently does not position the subsurface relative to the parent surface at all --- gst-libs/gst/gl/egl/gstglcontext_egl.c | 9 ++ gst-libs/gst/gl/wayland/gstgldisplay_wayland.c | 3 + gst-libs/gst/gl/wayland/gstgldisplay_wayland.h | 1 + gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c | 188 +++++++++++++++++----- gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h | 6 +- 5 files changed, 165 insertions(+), 42 deletions(-) diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index f1fb70f..14be7c6 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -34,6 +34,9 @@ #include "../x11/gstglwindow_x11.h" #include #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); diff --git a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c index 90cf1ea..c5c5094 100644 --- a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c +++ b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c @@ -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); } diff --git a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h index 67b3883..3612c78 100644 --- a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h +++ b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h @@ -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; /* */ diff --git a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c index 6679abc..519f9af 100644 --- a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +++ b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c @@ -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); } diff --git a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h index 845b925..3d08f6f 100644 --- a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h +++ b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.h @@ -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__ */ -- 2.7.4