[gtk/gst.gl.win32: 1/2] gtkgstsink.c: Support EGL on Windows as well




commit ccdec5da7788a4d84432cb2deb91ae851ca30c99
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Mon May 17 16:04:53 2021 +0800

    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.

 modules/media/gtkgstsink.c | 103 +++++++++++++++++++++++++++++++++++++--------
 modules/media/meson.build  |  17 +++++++-
 2 files changed, 101 insertions(+), 19 deletions(-)
---
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 <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)
         {
-          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 <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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]