From ddf7c1ec6358d28b33d07f52a8cb6d1f547172a1 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 18 Feb 2025 16:36:28 +1100 Subject: [PATCH] gldisplay/egl: Add API for overriding foreign-ness of the EGLDisplay Scenario is using wayland with this pipeline: videotestsrc ! glupload ! qml6glsink. First pipeline and qml construction works just fine. However if all GStreamer and QML scenegraph resources are removed, GStreamer will call eglTerminate() and sever the connection to the display server for Qt. When Qt attempts to do any further GL operations like construct a new QML scene, it can crash in any number of places as libEGL will start returning NULL or other unexpected values. What we really need is to ensure that if an external API (e.g. Qt) will eventually call eglTerminate(), there is no need for GStreamer to call eglTerminate(). This is what the foreign display flags allows setting. There is also another possible scenario where one may like to make GStreamer assume ownership of an EGLDisplay and thus eventually call `eglTerminate()`. As such, it is now also possible to mark an GstGLDisplayEGL as non-foreign. Part-of: --- girs/GstGLEGL-1.0.gir | 44 +++++++++++++++++- .../gst-libs/gst/gl/egl/gstgldisplay_egl.c | 46 ++++++++++++++++++- .../gst-libs/gst/gl/egl/gstgldisplay_egl.h | 3 ++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/girs/GstGLEGL-1.0.gir b/girs/GstGLEGL-1.0.gir index 0aa3a6ca97..9081f40cef 100644 --- a/girs/GstGLEGL-1.0.gir +++ b/girs/GstGLEGL-1.0.gir @@ -328,7 +328,11 @@ the associated `EGLImage` if necessary through the provided API - Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY. + Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY. + +The returned #GstGLDisplayEGL will by default free all EGL resources when +finalized. See gst_gl_display_egl_set_foreign() for details on if you need +the EGLDisplay to remain alive. a new #GstGLDisplayEGL or %NULL @@ -359,7 +363,12 @@ EGL_PLATFORM_SURFACELESS_MESA extension. Creates a EGL display connection from a native Display. This function will return the same value for multiple calls with the same -@display. +@display. + +The returned #GstGLDisplayEGL will *not* be marked as foreign and will free +some display global EGL resources on finalization. If an external API/user +will be also handling the lifetime of the `EGLDisplay`, you should mark the +returned #GstGLDisplayEGL as foreign by calling gst_gl_display_egl_set_foreign(). a new #GstGLDisplayEGL @@ -392,6 +401,37 @@ This function will return the same value for multiple calls with the same + + Configure whether or not this EGL display is foreign and is managed by an +external application/library. + +A display marked as foreign will not have display global resources freed when +this display is finalized. As such, any external API using the same +`EGLDisplay` must keep the `EGLDisplay` alive while GStreamer is using any +EGL or GL resources associated with that `EGLDisplay`. The reverse is also +true and a foreign #GstGLDisplayEGL must not be used after the associated +`EGLDisplay` has been destroyed externally with `eglTerminate()`. + +A non-foreign #GstGLDisplayEGL will destroy the associated `EGLDisplay` on +finalization. This can also be useful when a user would like GStreamer to +assume ownership of the `EGLDisplay` after calling e.g. +gst_gl_display_egl_new_with_egl_display(). + + + + + + + a #GstGLDisplayEGL + + + + whether @display_egl should be marked as containing a foreign + `EGLDisplay` + + + + diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c index 902416c19f..cabf8b16ae 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c @@ -256,6 +256,10 @@ default_display: * * Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY. * + * The returned #GstGLDisplayEGL will by default free all EGL resources when + * finalized. See gst_gl_display_egl_set_foreign() for details on if you need + * the EGLDisplay to remain alive. + * * Returns: (transfer full) (nullable): a new #GstGLDisplayEGL or %NULL */ GstGLDisplayEGL * @@ -318,7 +322,9 @@ gst_gl_display_egl_new_surfaceless (void) * gst_gl_display_egl_new_with_display: * @display: an existing and connected EGLDisplay * - * Creates a new display connection from a EGLDisplay. + * Creates a new display connection from a EGLDisplay. The display will be + * marked as foreign and freeing some EGL resources must be completed by the + * application. See gst_gl_display_egl_set_foreign() for more details. * * Returns: (transfer full): a new #GstGLDisplayEGL * @@ -359,6 +365,11 @@ _ref_if_set (gpointer data, gpointer user_data) * This function will return the same value for multiple calls with the same * @display. * + * The returned #GstGLDisplayEGL will *not* be marked as foreign and will free + * some display global EGL resources on finalization. If an external API/user + * will be also handling the lifetime of the `EGLDisplay`, you should mark the + * returned #GstGLDisplayEGL as foreign by calling gst_gl_display_egl_set_foreign(). + * * Returns: (transfer full) (nullable): a new #GstGLDisplayEGL * * Since: 1.12 @@ -415,6 +426,39 @@ gst_gl_display_egl_from_gl_display (GstGLDisplay * display) return ret; } +/** + * gst_gl_display_egl_set_foreign: + * @display_egl: a #GstGLDisplayEGL + * @foreign: whether @display_egl should be marked as containing a foreign + * `EGLDisplay` + * + * Configure whether or not this EGL display is foreign and is managed by an + * external application/library. + * + * A display marked as foreign will not have display global resources freed when + * this display is finalized. As such, any external API using the same + * `EGLDisplay` must keep the `EGLDisplay` alive while GStreamer is using any + * EGL or GL resources associated with that `EGLDisplay`. The reverse is also + * true and a foreign #GstGLDisplayEGL must not be used after the associated + * `EGLDisplay` has been destroyed externally with `eglTerminate()`. + * + * A non-foreign #GstGLDisplayEGL will destroy the associated `EGLDisplay` on + * finalization. This can also be useful when a user would like GStreamer to + * assume ownership of the `EGLDisplay` after calling e.g. + * gst_gl_display_egl_new_with_egl_display(). + * + * Since: 1.26 + */ +void +gst_gl_display_egl_set_foreign (GstGLDisplayEGL * display_egl, gboolean foreign) +{ + g_return_if_fail (GST_IS_GL_DISPLAY_EGL (display_egl)); + + GST_OBJECT_LOCK (display_egl); + display_egl->foreign_display = foreign; + GST_OBJECT_UNLOCK (display_egl); +} + static guintptr gst_gl_display_egl_get_handle (GstGLDisplay * display) { diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h b/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h index f7e27de5f9..f59e6c6501 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h @@ -78,6 +78,9 @@ GstGLDisplayEGL *gst_gl_display_egl_from_gl_display (GstGLDisplay * display); GST_GL_API gpointer gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display); +GST_GL_API +void gst_gl_display_egl_set_foreign (GstGLDisplayEGL * display_egl, gboolean foreign); + #define GST_GL_DISPLAY_EGL_NAME "gst.gl.display.egl" G_END_DECLS