gl/wayland: implement basic video overlay support via subsurfaces

Currently does not position the subsurface relative to the parent surface at all
This commit is contained in:
Matthew Waters 2015-05-27 16:39:06 +10:00
parent 1dc0f40a35
commit de389e07dc
5 changed files with 167 additions and 44 deletions

View 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);

View 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);
}

View 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> */

View 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");
wl_shell_surface_set_toplevel (window_egl->window.shell_surface);
return TRUE;
}
static void
destroy_surface (GstGLWindowWaylandEGL * window_egl)
surface_handle_leave (void *data, struct wl_surface *wl_surface,
struct wl_output *output)
{
if (window_egl->window.native)
wl_egl_window_destroy (window_egl->window.native);
}
if (window_egl->window.shell_surface)
static const struct wl_surface_listener surface_listener = {
surface_handle_enter,
surface_handle_leave
};
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);
if (window_egl->window.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;
}
}
if (window_egl->window.callback)
wl_callback_destroy (window_egl->window.callback);
static void
create_surfaces (GstGLWindowWaylandEGL * window_egl)
{
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 (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.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.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);
}

View 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__ */