[gtk/wip.win32.fixes: 599/599] media/gstreamer: Attempt to use GL for video for Windows




commit c8e7894d5a1597ea65ae6cc5eb2f8afb0891506b
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Sat Feb 13 19:56:08 2021 +0800

    media/gstreamer: Attempt to use GL for video for Windows
    
    Add a stab to support sharing the WGL context in GDK with the WGL
    context in GStreamer, so that we can also use OpenGL in the gstreamer
    media backend to playback videos.
    
    Due to an issue in libepoxy, we can't just use
    gdk_gl_context_make_current() from the media backend, which will cause a
    crash as we attempt to make calls accross threads.  Instead, we need to
    pull out the HGLRC (WGL context) from the GdkGLContext using the private
    API we added in the previous commit, and call the native
    wglMakeCurrent() in the system-provided opengl32.dll implementation.  We
    also need to deactivate the GL context so that the wglShareLists() call
    in libgstgl won't fail as we are only allowed to have a WGL context
    current per thread.
    
    This is currently WIP as playback of audio files work, but playback of
    videos result in a shader compilation failure in libgstgl.

 modules/media/gtkgstpaintable.c |  13 -----
 modules/media/gtkgstsink.c      | 113 ++++++++++++++++++++++++++++++++++++----
 modules/media/meson.build       |   7 ++-
 3 files changed, 108 insertions(+), 25 deletions(-)
---
diff --git a/modules/media/gtkgstpaintable.c b/modules/media/gtkgstpaintable.c
index 5bd789c1f3..470a5f59e4 100644
--- a/modules/media/gtkgstpaintable.c
+++ b/modules/media/gtkgstpaintable.c
@@ -118,18 +118,6 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend
   GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer);
   GstElement *sink, *glsinkbin;
 
-#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32)
-  /*
-   * Unfortunately, we can't connect the GstGLContext with our GDKGLContext,
-   * since gdk_gl_context_make_current(), which calls wglMakeCurrent(), does not
-   * allow us to share WGL contexts across threads, which will cause a crash.
-   * See MR !3034, so no WGL in the gstreamer media backend :(
-   */
-  sink = g_object_new (GTK_TYPE_GST_SINK,
-                       "paintable", self,
-                       NULL);
-  return sink;
-#else
   sink = g_object_new (GTK_TYPE_GST_SINK,
                        "paintable", self,
                        "gl-context", self->context,
@@ -143,7 +131,6 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend
   g_object_set (glsinkbin, "sink", sink, NULL);
 
   return glsinkbin;
-#endif
 }
 
 static void
diff --git a/modules/media/gtkgstsink.c b/modules/media/gtkgstsink.c
index 8a0a124e3b..aa2e127ebd 100644
--- a/modules/media/gtkgstsink.c
+++ b/modules/media/gtkgstsink.c
@@ -35,6 +35,13 @@
 #include <gst/gl/wayland/gstgldisplay_wayland.h>
 #endif
 
+#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32)
+#include <gdk/win32/gdkwin32.h>
+#include <GL/gl.h>
+
+extern HGLRC _gdk_win32_gl_context_get_hglrc (GdkGLContext *context);
+#endif
+
 #include <gst/gl/gstglfuncs.h>
 
 enum {
@@ -341,27 +348,85 @@ gtk_gst_sink_show_frame (GstVideoSink *vsink,
   return GST_FLOW_OK;
 }
 
+static guintptr
+gtk_gst_sink_gl_context_make_current (GdkGLContext  *context,
+                                      GstGLPlatform  platform)
+{
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+
+#if !GST_GL_HAVE_WINDOW_WIN32 || !GST_GL_HAVE_PLATFORM_WGL || !defined (GDK_WINDOWING_WIN32)
+  gdk_gl_context_make_current (context);
+  return gst_gl_context_get_current_gl_context (platform);
+#else
+  if (platform == GST_GL_PLATFORM_WGL)
+    {
+      HGLRC hglrc = _gdk_win32_gl_context_get_hglrc (context);
+      HWND hwnd = GDK_SURFACE_HWND (gdk_gl_context_get_surface (context));
+
+      wglMakeCurrent (GetDC (hwnd), hglrc);
+
+      return (guintptr)hglrc;
+    }
+  else
+    {
+      g_message ("EGL support not implemented for Windows yet");
+      return 0;
+    }
+#endif
+}
+
+#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (GDK_WINDOWING_WIN32)
+static void
+gtk_gst_gl_sink_win32_deactivate_gl_context (GdkGLContext *context)
+{
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+
+  if (GDK_IS_WIN32_DISPLAY (display) && !gdk_gl_context_get_use_es (context))
+    {
+      HWND hwnd = GDK_SURFACE_HWND (gdk_gl_context_get_surface (context));
+
+      wglMakeCurrent (GetDC (hwnd), NULL);
+    }
+}
+
+static void
+gtk_gst_gl_sink_win32_reactivate_gl_context (GdkGLContext *context)
+{
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+
+  if (GDK_IS_WIN32_DISPLAY (display) && !gdk_gl_context_get_use_es (context))
+    gtk_gst_sink_gl_context_make_current (context, GST_GL_PLATFORM_WGL);
+}
+
+#define GTK_GST_GL_SINK_DEACTIVATE(c) gtk_gst_gl_sink_win32_deactivate_gl_context (c)
+#define GTK_GST_GL_SINK_REACTIVATE(c) gtk_gst_gl_sink_win32_reactivate_gl_context (c)
+
+#else
+#define GTK_GST_GL_SINK_DEACTIVATE(c)
+#define GTK_GST_GL_SINK_REACTIVATE(c)
+#endif
+
 static void
 gtk_gst_sink_initialize_gl (GtkGstSink *self)
 {
   GdkDisplay *display;
   GError *error = NULL;
+  GstGLPlatform platform = GST_GL_PLATFORM_NONE;
+  GstGLAPI gl_api = GST_GL_API_NONE;
+  guintptr gl_handle = 0;
 
   display = gdk_gl_context_get_display (self->gdk_context);
 
-  gdk_gl_context_make_current (self->gdk_context);
-
 #if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (GDK_WINDOWING_X11)
   if (GDK_IS_X11_DISPLAY (display))
     {
-      GstGLPlatform platform = GST_GL_PLATFORM_GLX;
-      GstGLAPI gl_api;
-      guintptr gl_handle;
+      platform = GST_GL_PLATFORM_GLX;
 
       GST_DEBUG_OBJECT (self, "got GLX on X11!");
 
+      gl_handle = gtk_gst_sink_gl_context_make_current (self->gdk_context, platform);
       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 (gst_gl_display_x11_new_with_display 
(gdk_x11_display_get_xdisplay (display)));
@@ -378,15 +443,12 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
 #if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND)
   if (GDK_IS_WAYLAND_DISPLAY (display))
     {
-      GstGLPlatform platform = GST_GL_PLATFORM_GLX;
-      GstGLAPI gl_api;
-      guintptr gl_handle;
+      platform = GST_GL_PLATFORM_EGL;
 
       GST_DEBUG_OBJECT (self, "got EGL on Wayland!");
 
-      platform = GST_GL_PLATFORM_EGL;
+      gl_handle = gtk_gst_sink_gl_context_make_current (self->gdk_context, platform);
       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)
         {
@@ -403,6 +465,30 @@ 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))
+    {
+      platform = GST_GL_PLATFORM_WGL;
+
+      GST_DEBUG_OBJECT (self, "got WGL on Win32!");
+
+      gl_handle = gtk_gst_sink_gl_context_make_current (self->gdk_context, platform);
+      gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
+
+      if (gl_handle)
+        {
+          self->gst_display = gst_gl_display_new ();
+          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");
+             return;
+        }
+    }
+  else
 #endif
     {
       GST_INFO_OBJECT (self, "Unsupported GDK display %s for GL", G_OBJECT_TYPE_NAME (display));
@@ -412,6 +498,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
   g_assert (self->gst_app_context != NULL);
 
   gst_gl_context_activate (self->gst_app_context, TRUE);
+
   if (!gst_gl_context_fill_info (self->gst_app_context, &error))
     {
       GST_ERROR_OBJECT (self, "failed to retrieve GDK context info: %s", error->message);
@@ -422,6 +509,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
     }
   else
     {
+      GTK_GST_GL_SINK_DEACTIVATE(self->gdk_context);
       gst_gl_context_activate (self->gst_app_context, FALSE);
     }
 
@@ -431,8 +519,11 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
       g_error_free (error);
       g_clear_object (&self->gst_app_context);
       g_clear_object (&self->gst_display);
+      GTK_GST_GL_SINK_REACTIVATE (self->gdk_context);
       return;
     }
+
+  GTK_GST_GL_SINK_REACTIVATE (self->gdk_context);
 }
 
 static void
diff --git a/modules/media/meson.build b/modules/media/meson.build
index 154390e7fe..3a7b3ae697 100644
--- a/modules/media/meson.build
+++ b/modules/media/meson.build
@@ -47,6 +47,11 @@ gstgl_dep = dependency('gstreamer-gl-1.0', version: '>= 1.12.3',
                        required: get_option('media-gstreamer'))
 
 if gstplayer_dep.found() and gstgl_dep.found()
+  platform_gl_deps = []
+  if os_win32
+    platform_gl_deps = cc.find_library('opengl32')
+  endif
+
   media_backends += 'gstreamer'
   cdata.set('HAVE_GSTREAMER', 1)
   shared_module('media-gstreamer',
@@ -56,7 +61,7 @@ if gstplayer_dep.found() and gstgl_dep.found()
       'gtkgstsink.c',
     ],
     c_args: extra_c_args,
-    dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ],
+    dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep, platform_gl_deps ],
     name_suffix: module_suffix,
     install_dir: media_install_dir,
     install: true,


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