From d024ee4303f680d2e25c0a44ec6b8e8d529d1ca7 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 7 Feb 2023 17:07:55 +0800 Subject: [PATCH] GTK plugin: Support OpenGL/WGL on Windows This attempts to implement the gtkglsink element on Windows using WGL, as there were some more gotchas that are along the way, since we need to juggle with libepoxy along the way, meaning that we need a recent GTK+-3.24.x for this to work properly, i.e. the upcoming GTK+-3.24.43. Since we are essentially using an overlay compositor only during rendering, move its initialization and destruction into the gtk_gst_gl_widget_render() function, so that things are safer as we are doing things across threads between gstreamer (gst-gl) and GTK, as GL operations, as above, have more gotchas on Windows. Part-of: --- .../gst-plugins-good/ext/gtk/gtkgstglwidget.c | 68 ++++++++++++++++--- .../gst-plugins-good/ext/gtk/meson.build | 9 +++ 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c index bb74ce09ce..75fca27c1b 100644 --- a/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c +++ b/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c @@ -39,6 +39,10 @@ #include #endif +#if GST_GL_HAVE_WINDOW_WIN32 && defined (GDK_WINDOWING_WIN32) +#include +#endif + /** * SECTION:gtkgstglwidget * @title: GtkGstGlWidget @@ -65,10 +69,10 @@ struct _GtkGstGLWidgetPrivate GLint attr_position; GLint attr_texture; GLuint current_tex; - GstGLOverlayCompositor *overlay_compositor; GstVideoOrientationMethod rotate_method; GstVideoOrientationMethod current_rotate_method; const gfloat *transform_matrix; + gboolean is_wgl; }; static const GLfloat vertices[] = { @@ -160,9 +164,6 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget) gl->BindBuffer (GL_ARRAY_BUFFER, 0); - priv->overlay_compositor = - gst_gl_overlay_compositor_new (priv->other_context); - priv->initted = TRUE; } @@ -325,6 +326,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) { GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (widget)->priv; GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget); + GstGLOverlayCompositor *overlay_compositor = NULL; GTK_GST_BASE_WIDGET_LOCK (widget); @@ -341,6 +343,8 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) goto done; } + overlay_compositor = gst_gl_overlay_compositor_new (priv->other_context); + /* Upload latest buffer */ if (base_widget->pending_buffer) { GstBuffer *buffer = base_widget->pending_buffer; @@ -357,8 +361,7 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) gst_gl_insert_debug_marker (priv->other_context, "redrawing texture %u", priv->current_tex); - gst_gl_overlay_compositor_upload_overlays (priv->overlay_compositor, - buffer); + gst_gl_overlay_compositor_upload_overlays (overlay_compositor, buffer); sync_meta = gst_buffer_get_gl_sync_meta (buffer); if (sync_meta) { @@ -381,12 +384,15 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context) base_widget->buffer, context); _redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex); - gst_gl_overlay_compositor_draw_overlays (priv->overlay_compositor); + gst_gl_overlay_compositor_draw_overlays (overlay_compositor); gst_gl_insert_debug_marker (priv->other_context, "texture %u redrawn", priv->current_tex); done: + if (overlay_compositor) + gst_object_unref (overlay_compositor); + if (priv->other_context) gst_gl_context_activate (priv->other_context, FALSE); @@ -429,9 +435,6 @@ _reset_gl (GtkGstGLWidget * gst_widget) priv->shader = NULL; } - if (priv->overlay_compositor) - gst_object_unref (priv->overlay_compositor); - gst_gl_context_activate (priv->other_context, FALSE); gst_object_unref (priv->other_context); @@ -502,6 +505,12 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget) gst_gl_display_wayland_new_with_display (wayland_display); } #endif +#if GST_GL_HAVE_WINDOW_WIN32 && defined (GDK_WINDOWING_WIN32) + if (GDK_IS_WIN32_DISPLAY (display)) { + priv->display = (GstGLDisplay *) + gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32); + } +#endif (void) display; @@ -579,6 +588,26 @@ _get_gl_context (GtkGstGLWidget * gst_widget) platform, gl_api); } #endif +#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 (gdk_gl_context_get_display (priv->gdk_context))) { + gboolean is_gles = gdk_gl_context_get_use_es (priv->gdk_context); + + /* for WGL, we need the updates in GdkWin32GLContext for this to work safely */ + if (is_gles || GTK_CHECK_VERSION (3, 24, 43)) { + platform = is_gles ? GST_GL_PLATFORM_EGL : GST_GL_PLATFORM_WGL; + 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) + priv->other_context = + gst_gl_context_new_wrapped (priv->display, gl_handle, + platform, gl_api); + + if (priv->other_context && !is_gles) + priv->is_wgl = TRUE; + } + } +#endif (void) platform; (void) gl_api; @@ -639,6 +668,21 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) } GST_OBJECT_LOCK (priv->display); + + /* If there's no wglCreateContextAttribsARB() support, then we would fallback to + * wglShareLists() which will fail with ERROR_BUSY (0xaa) if either of the GL + * contexts are current in any other thread. + * + * The workaround here is to temporarily disable GDK's GL context while we + * set up our own, and then make the GDK GL Context current again after we are done + * + * Sometimes wglCreateContextAttribsARB() + * exists, but isn't functional (some Intel drivers), so it's easiest to do this + * unconditionally. + */ + if (priv->gdk_context && priv->is_wgl) + gdk_gl_context_clear_current (); + if (!gst_gl_display_create_context (priv->display, priv->other_context, &priv->context, &error)) { GST_WARNING ("Could not create OpenGL context: %s", @@ -648,6 +692,10 @@ gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget) GTK_GST_BASE_WIDGET_UNLOCK (gst_widget); return FALSE; } + + if (priv->gdk_context && priv->is_wgl) + gdk_gl_context_make_current (priv->gdk_context); + gst_gl_display_add_context (priv->display, priv->context); GST_OBJECT_UNLOCK (priv->display); diff --git a/subprojects/gst-plugins-good/ext/gtk/meson.build b/subprojects/gst-plugins-good/ext/gtk/meson.build index ec65c5c130..04b161c165 100644 --- a/subprojects/gst-plugins-good/ext/gtk/meson.build +++ b/subprojects/gst-plugins-good/ext/gtk/meson.build @@ -34,6 +34,15 @@ if gtk_dep.found() endif endif + if gst_gl_have_window_win32 and gst_gl_have_platform_wgl + # FIXME: automagic + gtk_win32_dep = dependency('gtk+-win32-3.0', required : false) + if gtk_win32_dep.found() and gtk_win32_dep.version().version_compare('>=3.24.43') + optional_deps += [gtk_win32_dep] + have_gtk3_gl_windowing = true + endif + endif + if have_gtk3_gl_windowing gtk_sources += [ 'gstgtkglsink.c',