diff --git a/modules/media/gtkgstsink.c b/modules/media/gtkgstsink.c index a08e4646c7..8775ec54f4 100644 --- a/modules/media/gtkgstsink.c +++ b/modules/media/gtkgstsink.c @@ -31,9 +31,6 @@ #if GST_GL_HAVE_PLATFORM_GLX #include #endif -#if GST_GL_HAVE_PLATFORM_EGL -#include -#endif #endif #if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND) @@ -42,11 +39,15 @@ #include #endif -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32) +#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32) #include #include #endif +#if GST_GL_HAVE_PLATFORM_EGL && (GST_GL_HAVE_WINDOW_WIN32 || GST_GL_HAVE_WINDOW_X11) +#include +#endif + #include enum { @@ -353,11 +354,18 @@ gtk_gst_sink_show_frame (GstVideoSink *vsink, return GST_FLOW_OK; } -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32) -#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT epoxy_handle_external_wglMakeCurrent() +#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32) +#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT(ctx) handle_wgl_makecurrent(ctx) #define DEACTIVATE_WGL_CONTEXT(ctx) deactivate_gdk_wgl_context(ctx) #define REACTIVATE_WGL_CONTEXT(ctx) reactivate_gdk_wgl_context(ctx) +static void +handle_wgl_makecurrent (GdkGLContext *ctx) +{ + if (!gdk_gl_context_get_use_es (ctx)) + epoxy_handle_external_wglMakeCurrent(); +} + static void deactivate_gdk_wgl_context (GdkGLContext *ctx) { @@ -374,8 +382,37 @@ reactivate_gdk_wgl_context (GdkGLContext *ctx) if (!gdk_gl_context_get_use_es (ctx)) gdk_gl_context_make_current (ctx); } + +/* + * Unfortunately, libepoxy does not offer a way to allow us to safely call + * gst_gl_context_get_current_gl_api() on a WGL context that underlies a + * GdkGLContext after we notify libepoxy an external wglMakeCurrent() has + * been called (which is required for the first gdk_gl_context_make_current() + * call in gtk_gst_sink_initialize_gl(), for instance), so we can't do + * gst_gl_context_get_current_gl_api() directly on WGL contexts that underlies + * GdkGLContext's. So, we just ask GDK about our WGL context, since it already + * knows what kind of WGL context we have there... + */ +static gboolean +check_win32_gst_gl_api (GdkGLContext *ctx, + GstGLPlatform *platform, + GstGLAPI *gl_api) +{ + gboolean is_gles = gdk_gl_context_get_use_es (ctx); + + g_return_val_if_fail (*gl_api == GST_GL_API_NONE, FALSE); + + *platform = is_gles ? GST_GL_PLATFORM_EGL : GST_GL_PLATFORM_WGL; + + if (is_gles) + *gl_api = gst_gl_context_get_current_gl_api (*platform, NULL, NULL); + else + *gl_api = gdk_gl_context_is_legacy (ctx) ? GST_GL_API_OPENGL : GST_GL_API_OPENGL3; + + return is_gles; +} #else -#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT +#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT(ctx) #define DEACTIVATE_WGL_CONTEXT(ctx) #define REACTIVATE_WGL_CONTEXT(ctx) #endif @@ -391,7 +428,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self) display = gdk_gl_context_get_display (self->gdk_context); - HANDLE_EXTERNAL_WGL_MAKE_CURRENT; + HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context); gdk_gl_context_make_current (self->gdk_context); #ifdef HAVE_GST_X11_SUPPORT @@ -459,25 +496,55 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self) } else #endif -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32) - if (GDK_IS_WIN32_DISPLAY (display) && - !gdk_gl_context_get_use_es (self->gdk_context)) +#if GST_GL_HAVE_WINDOW_WIN32 && (GST_GL_HAVE_PLATFORM_WGL || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_WIN32) + if (GDK_IS_WIN32_DISPLAY (display)) { - platform = GST_GL_PLATFORM_WGL; + gboolean is_gles = check_win32_gst_gl_api (self->gdk_context, &platform, &gl_api); + const gchar *gl_type = is_gles ? "EGL" : "WGL"; - GST_DEBUG_OBJECT (self, "got WGL on Win32!"); + GST_DEBUG_OBJECT (self, "got %s on Win32!", gl_type); - gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); gl_handle = gst_gl_context_get_current_gl_context (platform); if (gl_handle) { - self->gst_display = gst_gl_display_new (); + /* + * We must force a win32 GstGL display type and if using desktop GL, the GL_Platform to be WGL + * and an appropriate GstGL API depending on the gl_api we receive. We also ensure that we use + * an EGL GstGL API if we are using EGL in GDK. Envvars are required, unless + * gst_gl_display_new_with_type() is available, unfortunately, so that gst_gl_display_new() does + * things correctly if we have GstGL built with both EGL and WGL support for the WGL case, + * otherwise gst_gl_display_new() will assume an EGL display, which won't work for us + */ + + if (gl_api & (GST_GL_API_OPENGL3 | GST_GL_API_OPENGL)) + { +#ifdef HAVE_GST_GL_DISPLAY_NEW_WITH_TYPE + self->gst_display = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32); +#else + g_message ("If media fails to play, set the envvar `GST_DEBUG=1`, and if GstGL context creation fails"); + g_message ("due to \"Couldn't create GL context: Cannot share context with non-EGL context\","); + g_message ("set in the environment `GST_GL_PLATFORM=wgl` and `GST_GL_WINDOW=win32`,"); + g_message ("and restart the GTK application"); + + self->gst_display = gst_gl_display_new (); +#endif + } + +#if GST_GL_HAVE_PLATFORM_EGL + else + { + gpointer display_ptr = gdk_win32_display_get_egl_display (display); + self->gst_display = GST_GL_DISPLAY (gst_gl_display_egl_new_with_egl_display (display_ptr)); + } +#endif + + gst_gl_display_filter_gl_api (self->gst_display, gl_api); self->gst_app_context = gst_gl_context_new_wrapped (self->gst_display, gl_handle, platform, gl_api); } else { - GST_ERROR_OBJECT (self, "Failed to get handle from GdkGLContext, not using WGL"); + GST_ERROR_OBJECT (self, "Failed to get handle from GdkGLContext, not using %s", gl_type); return; } } @@ -498,7 +565,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self) g_clear_error (&error); g_clear_object (&self->gst_app_context); g_clear_object (&self->gst_display); - HANDLE_EXTERNAL_WGL_MAKE_CURRENT; + HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context);; return; } else @@ -515,7 +582,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self) g_clear_object (&self->gst_display); } - HANDLE_EXTERNAL_WGL_MAKE_CURRENT; + HANDLE_EXTERNAL_WGL_MAKE_CURRENT (self->gdk_context); REACTIVATE_WGL_CONTEXT (self->gdk_context); } diff --git a/modules/media/meson.build b/modules/media/meson.build index 154390e7fe..1bd91821d8 100644 --- a/modules/media/meson.build +++ b/modules/media/meson.build @@ -47,6 +47,21 @@ gstgl_dep = dependency('gstreamer-gl-1.0', version: '>= 1.12.3', required: get_option('media-gstreamer')) if gstplayer_dep.found() and gstgl_dep.found() + extra_win_cflags = [] + + if host_machine.system() == 'windows' + new_gst_gl_display_code = \ + '''#include + int main (int a, char ** g) { + GstGLDisplay *d = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32); + return 0; + }''' + if cc.links(new_gst_gl_display_code, dependencies : gstgl_dep) + message('libgstgl has gst_gl_display_new_with_type()') + extra_win_cflags += '-DHAVE_GST_GL_DISPLAY_NEW_WITH_TYPE' + endif + endif + media_backends += 'gstreamer' cdata.set('HAVE_GSTREAMER', 1) shared_module('media-gstreamer', @@ -55,7 +70,7 @@ if gstplayer_dep.found() and gstgl_dep.found() 'gtkgstpaintable.c', 'gtkgstsink.c', ], - c_args: extra_c_args, + c_args: extra_c_args + extra_win_cflags, dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ], name_suffix: module_suffix, install_dir: media_install_dir,