From 14ac40f106d5e742267f4a1ee6ce3af587a15b2e Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Mon, 23 Mar 2015 16:43:01 +0100 Subject: [PATCH] gl/dispmanx: surfaceless EGL context support Show the DispmanX window only if there's no shared external GL context set up. When a window is required by the context a transparent DispmanX element is created and later on made visible by the ::show method. https://bugzilla.gnome.org/show_bug.cgi?id=746632 --- .../gl/dispmanx/gstglwindow_dispmanx_egl.c | 97 ++++++++++++++----- .../gl/dispmanx/gstglwindow_dispmanx_egl.h | 3 + gst-libs/gst/gl/egl/gstglcontext_egl.c | 9 ++ 3 files changed, 85 insertions(+), 24 deletions(-) diff --git a/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.c b/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.c index ca5411a2d3..0adbfb6935 100644 --- a/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.c +++ b/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.c @@ -29,18 +29,31 @@ #include "gstglwindow_dispmanx_egl.h" + +#ifndef ELEMENT_CHANGE_LAYER +/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */ +#define ELEMENT_CHANGE_LAYER (1<<0) +#define ELEMENT_CHANGE_OPACITY (1<<1) +#define ELEMENT_CHANGE_DEST_RECT (1<<2) +#define ELEMENT_CHANGE_SRC_RECT (1<<3) +#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4) +#define ELEMENT_CHANGE_TRANSFORM (1<<5) +#endif + #define GST_CAT_DEFAULT gst_gl_window_debug #define gst_gl_window_dispmanx_egl_parent_class parent_class G_DEFINE_TYPE (GstGLWindowDispmanxEGL, gst_gl_window_dispmanx_egl, GST_GL_TYPE_WINDOW); +static void gst_gl_window_dispmanx_egl_finalize (GObject * object); static guintptr gst_gl_window_dispmanx_egl_get_window_handle (GstGLWindow * window); static void gst_gl_window_dispmanx_egl_set_window_handle (GstGLWindow * window, guintptr handle); static void gst_gl_window_dispmanx_egl_set_preferred_size (GstGLWindow * window, gint width, gint height); +static void gst_gl_window_dispmanx_egl_show (GstGLWindow * window); static void gst_gl_window_dispmanx_egl_draw (GstGLWindow * window); static void gst_gl_window_dispmanx_egl_run (GstGLWindow * window); static void gst_gl_window_dispmanx_egl_quit (GstGLWindow * window); @@ -53,17 +66,19 @@ static guintptr gst_gl_window_dispmanx_egl_get_display (GstGLWindow * window); static void window_resize (GstGLWindowDispmanxEGL * window_egl, guint width, - guint height); + guint height, gboolean visible); static void gst_gl_window_dispmanx_egl_class_init (GstGLWindowDispmanxEGLClass * klass) { GstGLWindowClass *window_class = (GstGLWindowClass *) klass; + GObjectClass *gobject_class = (GObjectClass *) klass; window_class->get_window_handle = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_get_window_handle); window_class->set_window_handle = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_set_window_handle); + window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_show); window_class->draw_unlocked = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_draw); window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_draw); @@ -77,11 +92,26 @@ gst_gl_window_dispmanx_egl_class_init (GstGLWindowDispmanxEGLClass * klass) GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_get_display); window_class->set_preferred_size = GST_DEBUG_FUNCPTR (gst_gl_window_dispmanx_egl_set_preferred_size); + + gobject_class->finalize = gst_gl_window_dispmanx_egl_finalize; } static void -gst_gl_window_dispmanx_egl_init (GstGLWindowDispmanxEGL * window) +gst_gl_window_dispmanx_egl_init (GstGLWindowDispmanxEGL * window_egl) { + window_egl->main_context = g_main_context_new (); + window_egl->loop = g_main_loop_new (window_egl->main_context, FALSE); +} + +static void +gst_gl_window_dispmanx_egl_finalize (GObject * object) +{ + GstGLWindowDispmanxEGL *window_egl = GST_GL_WINDOW_DISPMANX_EGL (object); + + g_main_loop_unref (window_egl->loop); + g_main_context_unref (window_egl->main_context); + + G_OBJECT_CLASS (parent_class)->finalize (object); } /* Must be called in the gl thread */ @@ -96,6 +126,7 @@ gst_gl_window_dispmanx_egl_new (void) window->egldisplay = EGL_DEFAULT_DISPLAY; + window->visible = FALSE; window->display = 0; window->dp_width = 0; window->dp_height = 0; @@ -140,16 +171,18 @@ gst_gl_window_dispmanx_egl_open (GstGLWindow * window, GError ** error) GST_DEBUG ("Got display size: %dx%d\n", window_egl->dp_width, window_egl->dp_height); + window_egl->native.element = 0; + + return TRUE; +} + +gboolean +gst_gl_window_dispmanx_egl_create_window (GstGLWindowDispmanxEGL * window_egl) +{ window_egl->native.width = 0; window_egl->native.height = 0; window_egl->display = vc_dispmanx_display_open (0); - window_egl->native.element = 0; - - window_egl->main_context = g_main_context_new (); - window_egl->loop = g_main_loop_new (window_egl->main_context, FALSE); - - window_resize (window_egl, 16, 16); - + window_resize (window_egl, 16, 16, FALSE); return TRUE; } @@ -221,7 +254,11 @@ gst_gl_window_dispmanx_egl_send_message_async (GstGLWindow * window, static guintptr gst_gl_window_dispmanx_egl_get_window_handle (GstGLWindow * window) { - return (guintptr) & GST_GL_WINDOW_DISPMANX_EGL (window)->native; + GstGLWindowDispmanxEGL *window_egl; + window_egl = GST_GL_WINDOW_DISPMANX_EGL (window); + if (window_egl->native.element) + return (guintptr) & window_egl->native; + return 0; } static void @@ -231,27 +268,32 @@ gst_gl_window_dispmanx_egl_set_window_handle (GstGLWindow * window, } static void -gst_gl_window_dispmanx_egl_set_preferred_size (GstGLWindow * window, gint width, gint height) +gst_gl_window_dispmanx_egl_set_preferred_size (GstGLWindow * window, gint width, + gint height) { GstGLWindowDispmanxEGL *window_egl = GST_GL_WINDOW_DISPMANX_EGL (window); + GST_DEBUG_OBJECT (window, "set preferred size to %dx%d", width, height); window_egl->preferred_width = width; window_egl->preferred_height = height; } static void -window_resize (GstGLWindowDispmanxEGL * window_egl, guint width, guint height) +window_resize (GstGLWindowDispmanxEGL * window_egl, guint width, guint height, + gboolean visible) { - GST_DEBUG ("resizing window from %ux%u to %ux%u", - window_egl->native.width, window_egl->native.height, width, height); + GST_DEBUG ("resizing %s window from %ux%u to %ux%u", + visible ? "visible" : "invisible", window_egl->native.width, + window_egl->native.height, width, height); if (window_egl->display) { VC_RECT_T dst_rect; VC_RECT_T src_rect; GstVideoRectangle src, dst, res; DISPMANX_UPDATE_HANDLE_T dispman_update; + uint32_t opacity = visible ? 255 : 0; VC_DISPMANX_ALPHA_T alpha = - { DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0 }; + { DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, opacity, 0 }; /* Center width*height frame inside dp_width*dp_height */ src.w = width; @@ -275,9 +317,12 @@ window_resize (GstGLWindowDispmanxEGL * window_egl, guint width, guint height) dispman_update = vc_dispmanx_update_start (0); if (window_egl->native.element) { + uint32_t change_flags = + ELEMENT_CHANGE_OPACITY | ELEMENT_CHANGE_DEST_RECT | + ELEMENT_CHANGE_SRC_RECT; vc_dispmanx_element_change_attributes (dispman_update, - window_egl->native.element, 0x00000110, 0, 0, &dst_rect, &src_rect, 0, - 0); + window_egl->native.element, change_flags, 0, opacity, &dst_rect, + &src_rect, 0, 0); } else { window_egl->native.element = vc_dispmanx_element_add (dispman_update, window_egl->display, 0, &dst_rect, 0, &src_rect, @@ -295,6 +340,17 @@ window_resize (GstGLWindowDispmanxEGL * window_egl, guint width, guint height) window_egl->native.height = height; } +static void +gst_gl_window_dispmanx_egl_show (GstGLWindow * window) +{ + GstGLWindowDispmanxEGL *window_egl = GST_GL_WINDOW_DISPMANX_EGL (window); + + if (!window_egl->visible) { + window_resize (window_egl, window_egl->preferred_width, window_egl->preferred_height, TRUE); + window_egl->visible = TRUE; + } +} + static void draw_cb (gpointer data) { @@ -303,13 +359,6 @@ draw_cb (gpointer data) GstGLContext *context = gst_gl_window_get_context (window); GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context); - if (window_egl->native.width != window_egl->preferred_width - || window_egl->native.height != window_egl->preferred_height) { - GST_DEBUG ("dimensions don't match, attempting resize"); - window_resize (window_egl, window_egl->preferred_width, - window_egl->preferred_height); - } - if (window->draw) window->draw (window->draw_data); diff --git a/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.h b/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.h index f8a6817bb5..1572bd5f2a 100644 --- a/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.h +++ b/gst-libs/gst/gl/dispmanx/gstglwindow_dispmanx_egl.h @@ -54,6 +54,8 @@ struct _GstGLWindowDispmanxEGL { GMainContext *main_context; GMainLoop *loop; + gboolean visible; + gpointer _reserved[GST_PADDING]; }; @@ -68,6 +70,7 @@ struct _GstGLWindowDispmanxEGLClass { GType gst_gl_window_dispmanx_egl_get_type (void); GstGLWindowDispmanxEGL * gst_gl_window_dispmanx_egl_new (void); +gboolean gst_gl_window_dispmanx_egl_create_window (GstGLWindowDispmanxEGL * window_egl); G_END_DECLS diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index 28c2359295..97fcb409b0 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -37,6 +37,9 @@ #if GST_GL_HAVE_WINDOW_WIN32 #include "../win32/gstglwindow_win32.h" #endif +#if GST_GL_HAVE_WINDOW_DISPMANX +#include "../dispmanx/gstglwindow_dispmanx_egl.h" +#endif #define GST_CAT_DEFAULT gst_gl_context_debug @@ -391,6 +394,12 @@ gst_gl_context_egl_create_context (GstGLContext * context, if (GST_GL_IS_WINDOW_WIN32 (context->window)) { gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); } +#endif +#if GST_GL_HAVE_WINDOW_DISPMANX + if (GST_GL_IS_WINDOW_DISPMANX_EGL (context->window)) { + gst_gl_window_dispmanx_egl_create_window ((GstGLWindowDispmanxEGL *) + context->window); + } #endif }