gtkgstsink.c: Support EGL on Windows as well

Add support to look for and use the EGL context in Windows if it was activated
instead of desktop OpenGL.

GstGL may have been built with or without EGL/libANGLE support, so if it were,
check in GstGL whether we have gst_gl_display_new_with_type() to create a
GstGLDisplay that is of the GST_GL_WINDOW_WIN32 type when we are using
Desktop OpenGL (WGL), otherwise we show messages indicating that envvars
need to be set to initialize GstGL properly.

Due to a bug in GstGL, the GstGLContext can only be set up successfully
if one of the following is true:

*  An OpenGL 3.x or later emulator, such as Mesa is used (for WGL)
*  The latest GstGL master is being used, at the time of writing (for
   WGL)
*  GTK, libepoxy and GstGL are all built only with WGL support (for WGL)
*  EGL is being used in GTK at runtime

Special thanks to Matthew Waters for the help during the process.
This commit is contained in:
Chun-wei Fan 2021-05-17 16:04:53 +08:00
parent 52d1c0c271
commit ccdec5da77
2 changed files with 101 additions and 19 deletions

View File

@ -31,9 +31,6 @@
#if GST_GL_HAVE_PLATFORM_GLX
#include <gst/gl/x11/gstgldisplay_x11.h>
#endif
#if GST_GL_HAVE_PLATFORM_EGL
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND)
@ -42,11 +39,15 @@
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#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 <gdk/win32/gdkwin32.h>
#include <epoxy/wgl.h>
#endif
#if GST_GL_HAVE_PLATFORM_EGL && (GST_GL_HAVE_WINDOW_WIN32 || GST_GL_HAVE_WINDOW_X11)
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#include <gst/gl/gstglfuncs.h>
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)
{
/*
* 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);
}

View File

@ -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 <gst/gl/gstgldisplay.h>
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,