[gtk/gst.gl.win32: 35/44] media/gstreamer: Support using GL for video for Windows




commit 52d1c0c2719a5a729cf17c90262d6f542eab1d11
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Sat Feb 13 18:40:56 2021 +0800

    media/gstreamer: Support using GL for video for Windows
    
    Add support to share 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.  For now OpenGL/ES is not supported for this under Windows.
    
    The process of setting this up in Windows is a little bit more involved, as:
    
    *  The OpenGL support in GstGL requires a GL 4.1 Core context, but we may just
       get the GL version from wglCreateContextAttribsARB() that we pass into the
       attributes, which is 3.2 by default.  So, try to ask for a 4.1 Core context
       first if we are asking for anything less.
    
    *  There is only one GstDisplay available for Windows, so we just use
       gst_gl_display_new().
    
    *  We must explicitly tell libepoxy that we are using wglMakeCurrent() outside
       of libepoxy that is being used in GdkGL, otherwise we would end up crashing
       as the GL/WGL function pointers would become invalid.
    
    *  We must also deactivate temporarily the underlying WGL context that was made
       current by gdk_gl_context_make_current() so that when
       gst_gl_display_create_context() calls wglShareLists(), we won't get bitten
       by error 0xaa (resource busy), as some drivers don't handle this well when
       the GL context is current in another thread.
    
    For the last two points we make use of macros defined by the platforms that the
    build is done for to help us carry out the necessary tasks as needed.
    
    Thanks to Matthew Waters for the info on integrating GstGL and windowing
    toolkits on Windows.

 gdk/win32/gdkglcontext-win32.c  | 36 ++++++++++++++-----
 modules/media/gtkgstpaintable.c | 13 -------
 modules/media/gtkgstsink.c      | 76 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 96 insertions(+), 29 deletions(-)
---
diff --git a/gdk/win32/gdkglcontext-win32.c b/gdk/win32/gdkglcontext-win32.c
index bfe800516e..b3c0d8ad2b 100644
--- a/gdk/win32/gdkglcontext-win32.c
+++ b/gdk/win32/gdkglcontext-win32.c
@@ -674,7 +674,7 @@ _create_gl_context (HDC           hdc,
     }
   else
     {
-      HGLRC hglrc;
+      HGLRC hglrc = NULL;
 
       if (!wglMakeCurrent (hdc, hglrc_base))
         {
@@ -682,13 +682,33 @@ _create_gl_context (HDC           hdc,
           goto gl_fail;
         }
 
-      hglrc = _create_gl_context_with_attribs (hdc,
-                                               hglrc_base,
-                                               share,
-                                               flags,
-                                               major,
-                                               minor,
-                                               is_legacy);
+      /*
+       * We need a Core GL 4.1 context in order to use the GL support in
+       * the GStreamer media widget backend, but wglCreateContextAttribsARB()
+       * may only give us the GL context version that we ask for here, and
+       * nothing more.  So, if we are asking for a pre-GL 4.1 context,
+       * try to ask for a 4.1 context explicitly first.  If that is not supported,
+       * then we fall back to whatever version that we were asking for (or, even a
+       * legacy context if that fails), at a price of not able to have GL support
+       * for the media GStreamer backend.
+       */
+      if (major < 4 || (major == 4 && minor < 1))
+        hglrc = _create_gl_context_with_attribs (hdc,
+                                                 hglrc_base,
+                                                 share,
+                                                 flags,
+                                                 4,
+                                                 1,
+                                                 is_legacy);
+
+      if (hglrc == NULL)
+        hglrc = _create_gl_context_with_attribs (hdc,
+                                                 hglrc_base,
+                                                 share,
+                                                 flags,
+                                                 major,
+                                                 minor,
+                                                 is_legacy);
 
       /* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation 
failed */
       if (hglrc == NULL)
diff --git a/modules/media/gtkgstpaintable.c b/modules/media/gtkgstpaintable.c
index ab837382b8..ba5aefca4b 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 273df334c5..a08e4646c7 100644
--- a/modules/media/gtkgstsink.c
+++ b/modules/media/gtkgstsink.c
@@ -42,6 +42,11 @@
 #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 <epoxy/wgl.h>
+#endif
+
 #include <gst/gl/gstglfuncs.h>
 
 enum {
@@ -348,22 +353,50 @@ 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()
+#define DEACTIVATE_WGL_CONTEXT(ctx) deactivate_gdk_wgl_context(ctx)
+#define REACTIVATE_WGL_CONTEXT(ctx) reactivate_gdk_wgl_context(ctx)
+
+static void
+deactivate_gdk_wgl_context (GdkGLContext *ctx)
+{
+  if (!gdk_gl_context_get_use_es (ctx))
+    {
+      HDC hdc = GetDC (GDK_SURFACE_HWND (gdk_gl_context_get_surface (ctx)));
+      wglMakeCurrent (hdc, NULL);
+    }
+}
+
+static void
+reactivate_gdk_wgl_context (GdkGLContext *ctx)
+{
+  if (!gdk_gl_context_get_use_es (ctx))
+    gdk_gl_context_make_current (ctx);
+}
+#else
+#define HANDLE_EXTERNAL_WGL_MAKE_CURRENT
+#define DEACTIVATE_WGL_CONTEXT(ctx)
+#define REACTIVATE_WGL_CONTEXT(ctx)
+#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);
 
+  HANDLE_EXTERNAL_WGL_MAKE_CURRENT;
   gdk_gl_context_make_current (self->gdk_context);
 
 #ifdef HAVE_GST_X11_SUPPORT
   if (GDK_IS_X11_DISPLAY (display))
     {
-      GstGLPlatform platform;
-      GstGLAPI gl_api;
-      guintptr gl_handle;
       gpointer display_ptr;
 
 #if GST_GL_HAVE_PLATFORM_EGL
@@ -387,6 +420,7 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
 
       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_app_context = gst_gl_context_new_wrapped (self->gst_display, gl_handle, platform, 
gl_api);
@@ -402,13 +436,10 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
 #ifdef HAVE_GST_WAYLAND_SUPPORT
   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_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
       gl_handle = gst_gl_context_get_current_gl_context (platform);
 
@@ -427,6 +458,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_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 ();
+          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));
@@ -436,16 +491,19 @@ 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);
       g_clear_error (&error);
       g_clear_object (&self->gst_app_context);
       g_clear_object (&self->gst_display);
+      HANDLE_EXTERNAL_WGL_MAKE_CURRENT;
       return;
     }
   else
     {
+      DEACTIVATE_WGL_CONTEXT (self->gdk_context);
       gst_gl_context_activate (self->gst_app_context, FALSE);
     }
 
@@ -455,8 +513,10 @@ gtk_gst_sink_initialize_gl (GtkGstSink *self)
       g_error_free (error);
       g_clear_object (&self->gst_app_context);
       g_clear_object (&self->gst_display);
-      return;
     }
+
+  HANDLE_EXTERNAL_WGL_MAKE_CURRENT;
+  REACTIVATE_WGL_CONTEXT (self->gdk_context);
 }
 
 static void


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