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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8504>
This commit is contained in:
Matthew Waters 2025-02-18 16:36:28 +11:00 committed by GStreamer Marge Bot
parent bb4d21001f
commit ddf7c1ec63
3 changed files with 90 additions and 3 deletions

View File

@ -328,7 +328,11 @@ the associated `EGLImage` if necessary</doc>
through the provided API</doc>
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h"/>
<constructor name="new" c:identifier="gst_gl_display_egl_new">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY.</doc>
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">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.</doc>
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h"/>
<return-value transfer-ownership="full" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">a new #GstGLDisplayEGL or %NULL</doc>
@ -359,7 +363,12 @@ EGL_PLATFORM_SURFACELESS_MESA extension.</doc>
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">Creates a EGL display connection from a native Display.
This function will return the same value for multiple calls with the same
@display.</doc>
@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().</doc>
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h"/>
<return-value transfer-ownership="full" nullable="1">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">a new #GstGLDisplayEGL</doc>
@ -392,6 +401,37 @@ This function will return the same value for multiple calls with the same
</parameter>
</parameters>
</function>
<method name="set_foreign" c:identifier="gst_gl_display_egl_set_foreign" version="1.26">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">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().</doc>
<source-position filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.h"/>
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<instance-parameter name="display_egl" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">a #GstGLDisplayEGL</doc>
<type name="GLDisplayEGL" c:type="GstGLDisplayEGL*"/>
</instance-parameter>
<parameter name="foreign" transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/gl/egl/gstgldisplay_egl.c">whether @display_egl should be marked as containing a foreign
`EGLDisplay`</doc>
<type name="gboolean" c:type="gboolean"/>
</parameter>
</parameters>
</method>
<field name="parent">
<type name="GstGL.GLDisplay" c:type="GstGLDisplay"/>
</field>

View File

@ -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)
{

View File

@ -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