Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package libnvidia-egl-x11 for
openSUSE:Factory checked in at 2026-09-02 16:59:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libnvidia-egl-x11 (Old)
and /work/SRC/openSUSE:Factory/.libnvidia-egl-x11.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libnvidia-egl-x11"
Wed Sep 2 16:59:28 2026 rev:9 rq:1375226 version:1.0.6
Changes:
--------
--- /work/SRC/openSUSE:Factory/libnvidia-egl-x11/libnvidia-egl-x11.changes
2026-02-04 21:10:28.503600208 +0100
+++
/work/SRC/openSUSE:Factory/.libnvidia-egl-x11.new.1265/libnvidia-egl-x11.changes
2026-09-02 16:59:37.196838141 +0200
@@ -1,0 +2,37 @@
+Tue Sep 1 12:28:04 UTC 2026 - Stefan Dirsch <[email protected]>
+
+- upated to 1.0.5 release tarball
+ * Fix building on FreeBSD
+ * Some fixes for handling the attribute list in
+ eglCreateWindow/PixmapSurface
+ * Add a setting to tell egl-x11 to run on the normal NVIDIA Xorg
+ driver. Requires DRI3 1.2 support, which was added in 595 and
+ later drivers.
+- supersedes the following patches
+ 0001-Fix-attribute-handling-for-eglCreateWindow-PixmapSur.patch
+ 0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
+ 0003-Bump-version-number-to-1.0.5.patch
+ 0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
+ 0005-Fix-building-on-FreeBSD.patch
+- added latest patches from git
+ * 0001-base-Use-an-rwlock-for-the-surface-list.patch
+ * 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
+ * 0003-base-Add-an-explicit-egl-dependency.patch
+ * 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
+ * 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
+ * 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
+ * 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
+ * 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
+ * 0009-egl-wayland2-add-FP16-DRM-format.patch
+ * 0010-Bump-the-version-number-to-1.0.6.patch
+ * 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
+ * 0012-Update-the-X11-code-to-match-the-base-library-change.patch
+ * 0013-x11-Remove-some-unused-function-pointers.patch
+ * 0014-poll-for-resize-events-in-x11-SwapBuffers.patch
+ * 0015-fix-parameter-validation.patch
+ * 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
+ * 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
+ * 0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch
+- bumped version to 1.0.6
+
+-------------------------------------------------------------------
Old:
----
0001-Fix-attribute-handling-for-eglCreateWindow-PixmapSur.patch
0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
0003-Bump-version-number-to-1.0.5.patch
0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
0005-Fix-building-on-FreeBSD.patch
egl-x11-1.0.4.tar.gz
New:
----
0001-base-Use-an-rwlock-for-the-surface-list.patch
0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
0003-base-Add-an-explicit-egl-dependency.patch
0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
0009-egl-wayland2-add-FP16-DRM-format.patch
0010-Bump-the-version-number-to-1.0.6.patch
0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
0012-Update-the-X11-code-to-match-the-base-library-change.patch
0013-x11-Remove-some-unused-function-pointers.patch
0014-poll-for-resize-events-in-x11-SwapBuffers.patch
0015-fix-parameter-validation.patch
0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch
egl-x11-1.0.5.tar.gz
----------(Old B)----------
Old:- supersedes the following patches
0001-Fix-attribute-handling-for-eglCreateWindow-PixmapSur.patch
0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
Old: 0001-Fix-attribute-handling-for-eglCreateWindow-PixmapSur.patch
0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
0003-Bump-version-number-to-1.0.5.patch
Old: 0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
0003-Bump-version-number-to-1.0.5.patch
0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
Old: 0003-Bump-version-number-to-1.0.5.patch
0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
0005-Fix-building-on-FreeBSD.patch
Old: 0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
0005-Fix-building-on-FreeBSD.patch
- added latest patches from git
----------(Old E)----------
----------(New B)----------
New:- added latest patches from git
* 0001-base-Use-an-rwlock-for-the-surface-list.patch
* 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
New: * 0001-base-Use-an-rwlock-for-the-surface-list.patch
* 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
* 0003-base-Add-an-explicit-egl-dependency.patch
New: * 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
* 0003-base-Add-an-explicit-egl-dependency.patch
* 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
New: * 0003-base-Add-an-explicit-egl-dependency.patch
* 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
* 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
New: * 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
* 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
* 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
New: * 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
* 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
* 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
New: * 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
* 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
* 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
New: * 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
* 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
* 0009-egl-wayland2-add-FP16-DRM-format.patch
New: * 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
* 0009-egl-wayland2-add-FP16-DRM-format.patch
* 0010-Bump-the-version-number-to-1.0.6.patch
New: * 0009-egl-wayland2-add-FP16-DRM-format.patch
* 0010-Bump-the-version-number-to-1.0.6.patch
* 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
New: * 0010-Bump-the-version-number-to-1.0.6.patch
* 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
* 0012-Update-the-X11-code-to-match-the-base-library-change.patch
New: * 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
* 0012-Update-the-X11-code-to-match-the-base-library-change.patch
* 0013-x11-Remove-some-unused-function-pointers.patch
New: * 0012-Update-the-X11-code-to-match-the-base-library-change.patch
* 0013-x11-Remove-some-unused-function-pointers.patch
* 0014-poll-for-resize-events-in-x11-SwapBuffers.patch
New: * 0013-x11-Remove-some-unused-function-pointers.patch
* 0014-poll-for-resize-events-in-x11-SwapBuffers.patch
* 0015-fix-parameter-validation.patch
New: * 0014-poll-for-resize-events-in-x11-SwapBuffers.patch
* 0015-fix-parameter-validation.patch
* 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
New: * 0015-fix-parameter-validation.patch
* 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
* 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
New: * 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
* 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
* 0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch
New: * 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
* 0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch
- bumped version to 1.0.6
----------(New E)----------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ libnvidia-egl-x11.spec ++++++
--- /var/tmp/diff_new_pack.mpqjBL/_old 2026-09-02 16:59:38.409880311 +0200
+++ /var/tmp/diff_new_pack.mpqjBL/_new 2026-09-02 16:59:38.411880380 +0200
@@ -20,20 +20,33 @@
%define lname libnvidia-egl-x11%{so_ver}
%define rname egl-x11
Name: libnvidia-egl-x11
-Version: 1.0.5
+Version: 1.0.6
Release: 0
Summary: NVIDIA XLib and XCB EGL Platform Library
# src/x11/dma-buf.h:/* SPDX-License-Identifier: GPL-2.0 WITH
Linux-syscall-note */
License: Apache-2.0
Group: Development/Libraries/C and C++
URL: https://github.com/NVIDIA/egl-x11
-Source0: %{rname}-1.0.4.tar.gz
+Source0: %{rname}-1.0.5.tar.gz
Source1: baselibs.conf
-Patch1: 0001-Fix-attribute-handling-for-eglCreateWindow-PixmapSur.patch
-Patch2: 0002-Handle-eglQuerySurface-EGL_RENDER_BUFFER.patch
-Patch3: 0003-Bump-version-number-to-1.0.5.patch
-Patch4: 0004-Enable-implicit-sync-if-we-re-talking-to-the-NVIDIA-.patch
-Patch5: 0005-Fix-building-on-FreeBSD.patch
+Patch1: 0001-base-Use-an-rwlock-for-the-surface-list.patch
+Patch2: 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch
+Patch3: 0003-base-Add-an-explicit-egl-dependency.patch
+Patch4: 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch
+Patch5: 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch
+Patch6: 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch
+Patch7: 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch
+Patch8: 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch
+Patch9: 0009-egl-wayland2-add-FP16-DRM-format.patch
+Patch10: 0010-Bump-the-version-number-to-1.0.6.patch
+Patch11: 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch
+Patch12: 0012-Update-the-X11-code-to-match-the-base-library-change.patch
+Patch13: 0013-x11-Remove-some-unused-function-pointers.patch
+Patch14: 0014-poll-for-resize-events-in-x11-SwapBuffers.patch
+Patch15: 0015-fix-parameter-validation.patch
+Patch16: 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch
+Patch17: 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch
+Patch18: 0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch
BuildRequires: gcc-c++
BuildRequires: meson
BuildRequires: ninja
@@ -97,7 +110,7 @@
using %{name}.
%prep
-%autosetup -n %{rname}-1.0.4 -p1
+%autosetup -n %{rname}-1.0.5 -p1
%build
export LDFLAGS="-Wl,-z,noexecstack -Wl,-z,now -Wl,-z,relro %{?_lto_cflags}"
++++++ 0001-base-Use-an-rwlock-for-the-surface-list.patch ++++++
>From 4aa5e626958f76bd6c2433292d11b41e8d065311 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Fri, 24 Jan 2025 15:06:48 -0700
Subject: [PATCH 01/18] base: Use an rwlock for the surface list.
Use an rwlock to protect the display's surface list.
eglCreate*Surface, eglDestroySurface, and eglTerminate all take the
write lock. All other functions that operate on an EGLSurface take the
read lock.
This will allow most EGL functions that take an EGLSurface to run
concurrently, without worrying about another thread calling
eglDestroySurface or eglTerminate.
That works because, outside of creation and destruction, almost
everything in EplSurface is effectively read-only. The only thing that
might change is the internal EGLSurface handle, and with the new
platform surface interface, that won't need need to change either.
This also changes and simplifies surface destruction. Since
eglSwapBuffers et. al. don't need to worry about another thread
destroying an EplSurface, EplSurface no longer needs to be refcounted.
Now, the EplSurface is always fully destroyed during the
eglDestroySurface hook, and so we can remove EplImplFuncs::FreeSurface.
Also remove eplSurfaceAcquire and eplSurfaceRelease. Instead, there's a
new eplDisplayLockSurfaceList function, which takes the read lock for
the surface list and returns a pointer to the list head, and
eplSurfaceListLookup, which scans the surface list for an external
EGLSurface handle.
As a convenience, eplHookDisplaySurface and eplHookDisplaySurfaceEnd
are wrappers to the functions above to handle looking up an EGLDisplay
and an EGLSurface, with the appropriate locking and unlocking.
---
src/base/platform-base.c | 159 +++++++++++++++++++++++++--------------
src/base/platform-base.h | 78 +++++++++++++++----
src/base/platform-impl.h | 37 +++++----
3 files changed, 183 insertions(+), 91 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 8710d10..0a487cb 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -85,7 +85,6 @@ EplPlatformData *eplPlatformBaseAllocate(int major, int minor,
assert(impl->InitializeDisplay != NULL);
assert(impl->TerminateDisplay != NULL);
assert(impl->DestroySurface != NULL);
- assert(impl->FreeSurface != NULL);
// SwapBuffers is only required if the platform supports windows.
assert(impl->CreateWindowSurface == NULL || impl->SwapBuffers != NULL);
@@ -356,17 +355,16 @@ EGLDisplay eplGetCurrentDisplay(void)
static void DestroyAllSurfaces(EplDisplay *pdpy)
{
+ pthread_rwlock_wrlock(&pdpy->surface_list_lock);
+
while (!glvnd_list_is_empty(&pdpy->surface_list))
{
EplSurface *psurf = glvnd_list_first_entry(&pdpy->surface_list,
EplSurface, entry);
- // Bump the refcount, as if we'd called eglSurfaceAcquire, so that
- // eplSurfaceRelease works below.
- eplRefCountRef(&psurf->refcount);
-
DeleteSurfaceCommon(pdpy, psurf);
- eplSurfaceRelease(pdpy, psurf);
}
+
+ pthread_rwlock_unlock(&pdpy->surface_list_lock);
}
static void DestroyDisplay(EplDisplay *pdpy)
@@ -518,47 +516,78 @@ EGLBoolean eplTerminateInternalDisplay(EplPlatformData
*platform, EplInternalDis
return EGL_TRUE;
}
-EplSurface *eplSurfaceAcquire(EplDisplay *pdpy, EGLSurface esurf)
+const struct glvnd_list *eplDisplayLockSurfaceList(EplDisplay *pdpy)
+{
+ pthread_rwlock_rdlock(&pdpy->surface_list_lock);
+
+ return &pdpy->surface_list;
+}
+
+void eplDisplayUnlockSurfaceList(EplDisplay *pdpy)
+{
+ pthread_rwlock_unlock(&pdpy->surface_list_lock);
+}
+
+EplSurface *eplSurfaceListLookup(const struct glvnd_list *surface_list,
EGLSurface esurf)
{
EplSurface *psurf;
- EplSurface *found = NULL;
- if (pdpy == NULL || esurf == EGL_NO_SURFACE)
+ if (esurf == EGL_NO_SURFACE)
{
return NULL;
}
- glvnd_list_for_each_entry(psurf, &pdpy->surface_list, entry)
+ glvnd_list_for_each_entry(psurf, surface_list, entry)
{
if (psurf->external_surface == esurf)
{
- found = psurf;
- break;
+ return psurf;
}
}
- if (found != NULL)
+ return NULL;
+}
+
+EGLBoolean eplHookDisplaySurface(EGLDisplay edpy, EGLSurface esurf,
+ EplDisplay **ret_pdpy, EplSurface **ret_psurf)
+{
+ EplDisplay *pdpy = eplDisplayAcquire(edpy);
+ const struct glvnd_list *surface_list = NULL;
+ EplSurface *psurf = NULL;
+
+ *ret_pdpy = NULL;
+ *ret_psurf = NULL;
+
+ if (pdpy == NULL)
{
- eplRefCountRef(&found->refcount);
+ return EGL_FALSE;
}
- return found;
+ if (esurf == EGL_NO_SURFACE)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLSurface handle is
EGL_NO_SURFACE");
+ eplDisplayRelease(pdpy);
+ return EGL_FALSE;
+ }
+
+ surface_list = eplDisplayLockSurfaceList(pdpy);
+ psurf = eplSurfaceListLookup(surface_list, esurf);
+ if (psurf == NULL)
+ {
+ eplDisplayUnlockSurfaceList(pdpy);
+ }
+ *ret_pdpy = pdpy;
+ *ret_psurf = psurf;
+ return EGL_TRUE;
}
-void eplSurfaceRelease(EplDisplay *pdpy, EplSurface *psurf)
+void eplHookDisplaySurfaceEnd(EplDisplay *pdpy, const EplSurface *psurf)
{
if (psurf != NULL)
{
- if (eplRefCountUnref(&psurf->refcount))
- {
- // If the refcount is zero, then that means eglDestroySurface or
- // eglTerminate has already run, so the platform-specific code has
- // already cleaned up the surface.
- assert(psurf->deleted);
- pdpy->platform->impl->FreeSurface(pdpy, psurf);
- FreeBaseSurface(psurf);
- }
+ eplDisplayUnlockSurfaceList(pdpy);
}
+ eplDisplayRelease(pdpy);
}
static EGLDisplay eplGetPlatformDisplayExport(void *platformData,
@@ -662,6 +691,14 @@ static EGLDisplay eplGetPlatformDisplayExport(void
*platformData,
goto done;
}
+ if (pthread_rwlock_init(&pdpy->surface_list_lock, NULL) != 0)
+ {
+ eplSetError(plat, EGL_BAD_ALLOC, "Failed to create internal locks");
+ pthread_mutex_destroy(&pdpy->mutex);
+ free(pdpy);
+ goto done;
+ }
+
pdpy->platform = eplPlatformDataRef(plat);
pdpy->platform_enum = platform;
pdpy->external_display = (EGLDisplay) pdpy;
@@ -836,18 +873,20 @@ static EGLSurface CommonCreateSurface(EplDisplay *pdpy,
psurf = AllocBaseSurface(pdpy->platform);
if (psurf == NULL)
{
- eplDisplayRelease(pdpy);
return EGL_NO_SURFACE;
}
psurf->type = type;
+ pthread_rwlock_wrlock(&pdpy->surface_list_lock);
+
if (type == EPL_SURFACE_TYPE_WINDOW)
{
if (pdpy->platform->impl->CreateWindowSurface != NULL)
{
psurf->internal_surface =
pdpy->platform->impl->CreateWindowSurface(pdpy->platform,
- pdpy, psurf, config, native_handle, attrib_list,
create_platform);
+ pdpy, psurf, config, native_handle, attrib_list,
create_platform,
+ &pdpy->surface_list);
}
else
{
@@ -859,7 +898,8 @@ static EGLSurface CommonCreateSurface(EplDisplay *pdpy,
if (pdpy->platform->impl->CreatePixmapSurface != NULL)
{
psurf->internal_surface =
pdpy->platform->impl->CreatePixmapSurface(pdpy->platform,
- pdpy, psurf, config, native_handle, attrib_list,
create_platform);
+ pdpy, psurf, config, native_handle, attrib_list,
create_platform,
+ &pdpy->surface_list);
}
else
{
@@ -876,7 +916,6 @@ static EGLSurface CommonCreateSurface(EplDisplay *pdpy,
{
psurf->external_surface = (EGLSurface) psurf;
ret = psurf->external_surface;
- eplRefCountRef(&psurf->refcount);
glvnd_list_add(&psurf->entry, &pdpy->surface_list);
}
else
@@ -884,6 +923,7 @@ static EGLSurface CommonCreateSurface(EplDisplay *pdpy,
FreeBaseSurface(psurf);
}
+ pthread_rwlock_unlock(&pdpy->surface_list_lock);
return ret;
}
@@ -989,22 +1029,18 @@ static EGLSurface HookCreatePbufferSurface(EGLDisplay
edpy, EGLConfig config, co
static void DeleteSurfaceCommon(EplDisplay *pdpy, EplSurface *psurf)
{
- assert(!psurf->deleted);
+ glvnd_list_del(&psurf->entry);
- if (!psurf->deleted)
- {
- psurf->deleted = EGL_TRUE;
- glvnd_list_del(&psurf->entry);
- pdpy->platform->impl->DestroySurface(pdpy, psurf);
+ pdpy->platform->impl->DestroySurface(pdpy, psurf, &pdpy->surface_list);
- eplRefCountUnref(&psurf->refcount);
- }
+ FreeBaseSurface(psurf);
}
static EGLBoolean HookDestroySurface(EGLDisplay edpy, EGLSurface esurf)
{
EplDisplay *pdpy;
- EplSurface *psurf;
+ EplSurface *elem;
+ EplSurface *psurf = NULL;
EGLBoolean ret = EGL_FALSE;
pdpy = eplDisplayAcquire(edpy);
@@ -1013,11 +1049,20 @@ static EGLBoolean HookDestroySurface(EGLDisplay edpy,
EGLSurface esurf)
return EGL_FALSE;
}
- psurf = eplSurfaceAcquire(pdpy, esurf);
+ pthread_rwlock_wrlock(&pdpy->surface_list_lock);
+
+ glvnd_list_for_each_entry(elem, &pdpy->surface_list, entry)
+ {
+ if (elem->external_surface == esurf)
+ {
+ psurf = elem;
+ break;
+ }
+ }
+
if (psurf != NULL)
{
DeleteSurfaceCommon(pdpy, psurf);
- eplSurfaceRelease(pdpy, psurf);
ret = EGL_TRUE;
}
else
@@ -1027,6 +1072,7 @@ static EGLBoolean HookDestroySurface(EGLDisplay edpy,
EGLSurface esurf)
ret = pdpy->platform->egl.DestroySurface(pdpy->internal_display,
esurf);
}
+ pthread_rwlock_unlock(&pdpy->surface_list_lock);
eplDisplayRelease(pdpy);
return ret;
}
@@ -1037,8 +1083,7 @@ static EGLBoolean HookSwapBuffersWithDamage(EGLDisplay
edpy, EGLSurface esurf, c
EplSurface *psurf;
EGLBoolean ret = EGL_FALSE;
- pdpy = eplDisplayAcquire(edpy);
- if (pdpy == NULL)
+ if (!eplHookDisplaySurface(edpy, esurf, &pdpy, &psurf))
{
return EGL_FALSE;
}
@@ -1046,11 +1091,10 @@ static EGLBoolean HookSwapBuffersWithDamage(EGLDisplay
edpy, EGLSurface esurf, c
if (pdpy->platform->egl.GetCurrentDisplay() != edpy)
{
eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLDisplay %p is not
current", edpy);
- eplDisplayRelease(pdpy);
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
return EGL_FALSE;
}
- psurf = eplSurfaceAcquire(pdpy, esurf);
if (psurf != NULL)
{
if (psurf->type != EPL_SURFACE_TYPE_WINDOW)
@@ -1068,8 +1112,7 @@ static EGLBoolean HookSwapBuffersWithDamage(EGLDisplay
edpy, EGLSurface esurf, c
ret = pdpy->platform->impl->SwapBuffers(pdpy->platform, pdpy,
psurf, rects, n_rects);
}
- eplSurfaceRelease(pdpy, psurf);
- eplDisplayRelease(pdpy);
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
}
else
{
@@ -1081,7 +1124,7 @@ static EGLBoolean HookSwapBuffersWithDamage(EGLDisplay
edpy, EGLSurface esurf, c
// Release the display before calling into the driver, so that we don't
// sit on the lock for a (potentially long) SwapBuffers operation.
- eplDisplayRelease(pdpy);
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
if (SwapBuffersWithDamage != NULL && rects != NULL && n_rects > 0)
{
@@ -1113,12 +1156,15 @@ static EGLBoolean HookWaitGL(void)
return EGL_FALSE;
}
+
assert(pdpy->platform->impl->WaitGL != NULL);
if (pdpy->platform->impl->WaitGL != NULL)
{
- EplSurface *psurf = eplSurfaceAcquire(pdpy,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
+ const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
+ EplSurface *psurf = eplSurfaceListLookup(surface_list,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
+
ret = pdpy->platform->impl->WaitGL(pdpy, psurf);
- eplSurfaceRelease(pdpy, psurf);
+ eplDisplayUnlockSurfaceList(pdpy);
}
else
{
@@ -1126,8 +1172,6 @@ static EGLBoolean HookWaitGL(void)
// we have an implementation. But, if we wanted to handle this case,
// then we could just forward the call through to the driver.
eplSetError(pdpy->platform, EGL_BAD_ALLOC, "Internal error: eglWaitGL
hook should not be called");
- eplDisplayRelease(pdpy);
- return EGL_FALSE;
}
eplDisplayRelease(pdpy);
@@ -1148,15 +1192,15 @@ static EGLBoolean HookWaitNative(void)
assert(pdpy->platform->impl->WaitNative != NULL);
if (pdpy->platform->impl->WaitNative != NULL)
{
- EplSurface *psurf = eplSurfaceAcquire(pdpy,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
+ const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
+ EplSurface *psurf = eplSurfaceListLookup(surface_list,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
+
ret = pdpy->platform->impl->WaitNative(pdpy, psurf);
- eplSurfaceRelease(pdpy, psurf);
+ eplDisplayUnlockSurfaceList(pdpy);
}
else
{
eplSetError(pdpy->platform, EGL_BAD_ALLOC, "Internal error:
eglWaitNative hook should not be called");
- eplDisplayRelease(pdpy);
- return EGL_FALSE;
}
eplDisplayRelease(pdpy);
@@ -1303,11 +1347,11 @@ static void *eplGetInternalHandleExport(EGLDisplay
edpy, EGLenum type, void *han
{
if (type == EGL_OBJECT_SURFACE_KHR)
{
- EplSurface *psurf = eplSurfaceAcquire(pdpy, (EGLSurface)
handle);
+ const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
+ EplSurface *psurf = eplSurfaceListLookup(surface_list,
(EGLSurface) handle);
if (psurf != NULL)
{
ret = psurf->internal_surface;
- eplSurfaceRelease(pdpy, psurf);
}
else
{
@@ -1320,6 +1364,7 @@ static void *eplGetInternalHandleExport(EGLDisplay edpy,
EGLenum type, void *han
*/
ret = handle;
}
+ eplDisplayUnlockSurfaceList(pdpy);
}
eplDisplayRelease(pdpy);
}
diff --git a/src/base/platform-base.h b/src/base/platform-base.h
index 63e36f8..297def3 100644
--- a/src/base/platform-base.h
+++ b/src/base/platform-base.h
@@ -79,8 +79,6 @@ typedef struct
*/
typedef struct
{
- EplRefCount refcount;
-
EGLSurface external_surface;
EGLSurface internal_surface;
EplSurfaceType type;
@@ -139,11 +137,6 @@ typedef struct
*/
struct _EplPlatformData *platform;
- /**
- * All of the existing EplSurface structs.
- */
- struct glvnd_list surface_list;
-
/**
* Private data for the implementation.
*/
@@ -152,6 +145,24 @@ typedef struct
// Everything after this in EplDisplay should be treated as internal to
// platform-base.c.
+ /**
+ * All of the existing EplSurface structs.
+ */
+ struct glvnd_list surface_list;
+
+ /**
+ * A read/write lock to protect the surface list.
+ *
+ * The eglCreate*Surface and eglDestroySurface hooks will hold the write
+ * lock, and any other functions that operate on an EGLSurface a will hold
+ * the read lock.
+ *
+ * This allows most functions (especially eglSwapBuffers, which may have to
+ * block for extended periods of time) to run concurrently, without needing
+ * to worry about the EGLSurface getting destroyed out from under it.
+ */
+ pthread_rwlock_t surface_list_lock;
+
/**
* A mutex to control access to the display. This is a recursive mutex.
*/
@@ -367,20 +378,59 @@ EGLBoolean eplTerminateInternalDisplay(EplPlatformData
*platform, EplInternalDis
void eplSetError(EplPlatformData *platform, EGLint error, const char *fmt,
...);
/**
- * Looks up the EplSurface struct for a surface.
+ * Returns the display's surface list.
+ *
+ * This will take the read lock for the surface list, and then return the list
+ * head.
+ *
+ * The caller must call eplDisplayUnlockSurfaceList to unlock the surface list
+ * afterward.
+ */
+const struct glvnd_list *eplDisplayLockSurfaceList(EplDisplay *pdpy);
+
+/**
+ * Unlocks the display's surface list.
+ */
+void eplDisplayUnlockSurfaceList(EplDisplay *pdpy);
+
+/**
+ * A convenience function for hooks that operate on an EGLSurface.
+ *
+ * This function just calls eglDisplayAcquire to look up the EplDisplay, and
+ * then eplDisplayLockSurfaceList and eplSurfaceListLookup to look up an
+ * EplSurface.
*
- * This will lock the surface and increment its refcount.
+ * The caller must then call \c eplHookDisplaySurfaceEnd afterward.
*
- * The caller must release the surface with \c eplSurfaceRelease.
+ * \note If \p esurf is not NULL, but doesn't match any EplSurface struct, then
+ * this function will still succeed. In most cases, that just means that the
+ * hook function should pass it through to the driver.
*
- * Note that this might return NULL if the surface is a pbuffer or stream.
+ * \note If \p ret_psurf returns NULL, then the surface list will be left
+ * unlocked.
+ *
+ * \param edpy The external EGLDisplay handle.
+ * \param esurf The external EGLSurface handle.
+ * \param[out] ret_pdpy Returns the EplDisplay pointer.
+ * \param[out] ret_psurf Returns the EplSurface pointer, or NULL if \p esurf
+ * doesn't match any EplDisplay.
+ * \return EGL_TRUE on success. EGL_FALSE if \p edpy is invalid, or if
+ * \p esurf is EGL_NO_SURFACE.
*/
-EplSurface *eplSurfaceAcquire(EplDisplay *pdpy, EGLSurface esurf);
+EGLBoolean eplHookDisplaySurface(EGLDisplay edpy, EGLSurface esurf,
+ EplDisplay **ret_pdpy, EplSurface **ret_surface);
+
+void eplHookDisplaySurfaceEnd(EplDisplay *pdpy, const EplSurface *psurf);
/**
- * Decrements the refcount for an EplSurface and unlocks it.
+ * Looks up an EplSurface from its external EGLSurface handle.
+ *
+ * \param surface_list The surface list, as returned by \c
eplDisplayLockSurfaceList.
+ * \param esurf The external EGLSurface handle.
+ * \return The corresponding EplSurface, or NULL if \p esurf doesn't match any
+ * surface.
*/
-void eplSurfaceRelease(EplDisplay *pdpy, EplSurface *psurf);
+EplSurface *eplSurfaceListLookup(const struct glvnd_list *surface_list,
EGLSurface esurf);
/**
* Replaces the current surface.
diff --git a/src/base/platform-impl.h b/src/base/platform-impl.h
index abd74be..a44ac60 100644
--- a/src/base/platform-impl.h
+++ b/src/base/platform-impl.h
@@ -183,10 +183,13 @@ typedef struct _EplImplFuncs
* \param create_platform If this is true, then the call is from
* eglCreatePlatformWindowSurface. If false, it's from
* eglCreateWindowSurface.
+ * \param existing_surfaces A linked list of existing surfaces. The new
+ * surface will not be in this list.
* \return The internal EGLSurface handle, or EGL_NO_SURFACE on failure.
*/
EGLSurface (* CreateWindowSurface) (EplPlatformData *plat, EplDisplay
*pdpy, EplSurface *psurf,
- EGLConfig config, void *native_surface, const EGLAttrib *attribs,
EGLBoolean create_platform);
+ EGLConfig config, void *native_surface, const EGLAttrib *attribs,
EGLBoolean create_platform,
+ const struct glvnd_list *existing_surfaces);
/**
* Creates an EGLSurface for a pixmap.
@@ -202,35 +205,29 @@ typedef struct _EplImplFuncs
* \param create_platform If this is true, then the call is from
* eglCreatePlatformPixmapSurface. If false, it's from
* eglCreatePixmapSurface.
+ * \param existing_surfaces A linked list of existing surfaces. The new
+ * surface will not be in this list.
* \return The internal EGLSurface handle, or EGL_NO_SURFACE on failure.
*/
EGLSurface (* CreatePixmapSurface) (EplPlatformData *plat, EplDisplay
*pdpy, EplSurface *psurf,
- EGLConfig config, void *native_surface, const EGLAttrib *attribs,
EGLBoolean create_platform);
+ EGLConfig config, void *native_surface, const EGLAttrib *attribs,
EGLBoolean create_platform,
+ const struct glvnd_list *existing_surfaces);
/**
- * Called to handle eglDestroySurface and eglTerminate.
+ * Called from eglDestroySurface and eglTerminate to destroy a surface.
*
- * Note that it's possible that the EplSurface struct itself might stick
around
- * if another thread is holding a reference to it.
+ * After this, the \c EplSurface struct itself is freed.
*
- * \c FreeSurface is called when the refcount actually drops to zero.
+ * Note that this function is called with the surface list already locked,
+ * so it must not try to call \c eplDisplayLockSurfaceList.
*
- * \param plat The EplPlatformData struct
- * \param pdpy The EplDisplay struct
- */
- void (* DestroySurface) (EplDisplay *pdpy, EplSurface *psurf);
-
- /**
- * Called when an EplSurface is about to be freed.
- *
- * At this point, it's safe to assume that no other thread is going to
touch
- * the surface, so the platform must free anything that it hasn't already
freed
- * in \c DestroySurface.
- *
- * \param plat The EplPlatformData struct
* \param pdpy The EplDisplay struct
+ * \param psurf The EplSurface that's being destroyed.
+ * \param existing_surfaces A linked list of existing surfaces. \p psurf
+ * will not be in this list.
*/
- void (* FreeSurface) (EplDisplay *pdpy, EplSurface *psurf);
+ void (* DestroySurface) (EplDisplay *pdpy, EplSurface *psurf,
+ const struct glvnd_list *existing_surfaces);
/**
* Implements eglSwapBuffers and eglSwapBuffersWithDamageEXT.
--
2.51.0
++++++ 0002-base-Use-an-rwlock-for-eglInitialize-eglTerminate.patch ++++++
>From dcc787efd2cf407652d6bdbafc8f4a4195c9ad30 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Fri, 24 Jan 2025 15:39:09 -0700
Subject: [PATCH 02/18] base: Use an rwlock for eglInitialize/eglTerminate
Use an rwlock to protect against concurrent calls to eglTerminate,
instead of using a secondary refcount.
Removed EplDisplay::use_count, and instead added EplDisplay::init_lock,
which is a read/write lock that protects the eglInitialize count.
eglInitialize, eglTermiante, and teardown will all take the write lock.
Any function which needs an initialized EGLDisplay will take the read
lock. That's enough to prevent any other threads from terminating the
EGLDisplay out from under it, without otherwise blocking concurrent
functions.
As with surfaces, a read lock is fine. The surface list has its own
lock, and outside of eglInitialize/eglTerminate, everything else in
EplDisplay has its own lock.
In particular, eglSwapBuffers implementations no longer need to
temporarily unlock the display before perfoming long waits or reads.
Unlocking like that makes it much harder to reason about, because you
have to deal with the case where another thread calls eglDestroySurface
or eglTerminate.
In addition, the use_count field would give the wrong behavior in one
(admittedly contrived) case: If another thread calls eglTerminate and
then eglInitilize during that temporary unlock, then they get
effectively ignored, and none of the cleanup stuff in eglTerminate
happens.
---
src/base/platform-base.c | 150 ++++++++++++++++++++-------------------
src/base/platform-base.h | 43 +++--------
2 files changed, 87 insertions(+), 106 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 0a487cb..ad0dc8c 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -26,8 +26,6 @@
#include "platform-utils.h"
#include "platform-impl.h"
-#define USE_ERRORCHECK_MUTEX 1
-
static void *eplGetHookAddressExport(void *platformData, const char *name);
static EGLBoolean eplIsValidNativeDisplayExport(void *platformData, void
*nativeDisplay);
static EGLDisplay eplGetPlatformDisplayExport(void *platformData, EGLenum
platform, void *nativeDisplay, const EGLAttrib* attribs);
@@ -69,6 +67,7 @@ static __attribute__((destructor)) void LibraryFini(void)
EPL_REFCOUNT_DEFINE_TYPE_FUNCS(EplPlatformData, eplPlatformData, refcount,
free);
EPL_REFCOUNT_DEFINE_TYPE_FUNCS(EplInternalDisplay, eplInternalDisplay,
refcount, free);
+EPL_REFCOUNT_DEFINE_TYPE_FUNCS(EplDisplay, eplDisplay, refcount,
DestroyDisplay);
EplPlatformData *eplPlatformBaseAllocate(int major, int minor,
const EGLExtDriver *driver, EGLExtPlatform *extplatform,
@@ -231,21 +230,19 @@ static EGLBoolean eplUnloadExternalPlatformExport(void
*platformData)
continue;
}
- pthread_mutex_lock(&pdpy->mutex);
-
// Remove the display from the list and decrement its refcount.
glvnd_list_del(&pdpy->entry);
- pthread_mutex_unlock(&pdpy->mutex);
+
+ pthread_rwlock_wrlock(&pdpy->init_lock);
+ TerminateDisplay(pdpy);
+ pthread_rwlock_unlock(&pdpy->init_lock);
// Note that if some other thread is still holding a reference to this
// display, then it might get leaked.
// TODO: Should we just unconditionally free the display here? If
// another thread is in the middle of a function call, then it's going
// to crash anyway.
- if (eplRefCountUnref(&pdpy->refcount))
- {
- DestroyDisplay(pdpy);
- }
+ eplDisplayUnref(pdpy);
}
pthread_mutex_unlock(&display_list_mutex);
@@ -271,7 +268,7 @@ static EGLBoolean eplUnloadExternalPlatformExport(void
*platformData)
* This looks up and locks an EGLDisplay, but it does not check whether the
* display is initialized.
*/
-static EplDisplay *eplLockDisplayInternal(EGLDisplay edpy)
+static EplDisplay *eplLookupDisplay(EGLDisplay edpy)
{
EplDisplay *pdpy = NULL;
EplDisplay *node = NULL;
@@ -297,9 +294,7 @@ static EplDisplay *eplLockDisplayInternal(EGLDisplay edpy)
return NULL;
}
- pthread_mutex_lock(&pdpy->mutex);
- eplRefCountRef(&pdpy->refcount);
- pdpy->use_count++;
+ eplDisplayRef(pdpy);
pthread_mutex_unlock(&display_list_mutex);
@@ -308,17 +303,20 @@ static EplDisplay *eplLockDisplayInternal(EGLDisplay edpy)
EplDisplay *eplDisplayAcquire(EGLDisplay edpy)
{
- EplDisplay *pdpy = eplLockDisplayInternal(edpy);
+ EplDisplay *pdpy = eplLookupDisplay(edpy);
if (pdpy == NULL)
{
return NULL;
}
+ pthread_rwlock_rdlock(&pdpy->init_lock);
+
if (!pdpy->initialized)
{
eplSetError(pdpy->platform, EGL_NOT_INITIALIZED, "EGLDisplay %p is not
initialized", edpy);
- eplDisplayRelease(pdpy);
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
return NULL;
}
@@ -375,7 +373,8 @@ static void DestroyDisplay(EplDisplay *pdpy)
DestroyAllSurfaces(pdpy);
pdpy->platform->impl->CleanupDisplay(pdpy);
- pthread_mutex_destroy(&pdpy->mutex);
+ pthread_rwlock_destroy(&pdpy->init_lock);
+ pthread_rwlock_destroy(&pdpy->surface_list_lock);
eplPlatformDataUnref(pdpy->platform);
free(pdpy);
@@ -388,24 +387,9 @@ void eplDisplayRelease(EplDisplay *pdpy)
return;
}
- pdpy->use_count--;
- CheckTerminateDisplay(pdpy);
- pthread_mutex_unlock(&pdpy->mutex);
+ pthread_rwlock_unlock(&pdpy->init_lock);
- if (eplRefCountUnref(&pdpy->refcount))
- {
- DestroyDisplay(pdpy);
- }
-}
-
-void eplDisplayUnlock(EplDisplay *pdpy)
-{
- pthread_mutex_unlock(&pdpy->mutex);
-}
-
-void eplDisplayLock(EplDisplay *pdpy)
-{
- pthread_mutex_lock(&pdpy->mutex);
+ eplDisplayUnref(pdpy);
}
EplInternalDisplay *eplLookupInternalDisplay(EplPlatformData *platform,
EGLDisplay handle)
@@ -684,9 +668,9 @@ static EGLDisplay eplGetPlatformDisplayExport(void
*platformData,
goto done;
}
- if (!eplInitRecursiveMutex(&pdpy->mutex))
+ if (pthread_rwlock_init(&pdpy->init_lock, NULL) != 0)
{
- eplSetError(plat, EGL_BAD_ALLOC, "Failed to create internal mutex");
+ eplSetError(plat, EGL_BAD_ALLOC, "Failed to create internal locks");
free(pdpy);
goto done;
}
@@ -694,7 +678,7 @@ static EGLDisplay eplGetPlatformDisplayExport(void
*platformData,
if (pthread_rwlock_init(&pdpy->surface_list_lock, NULL) != 0)
{
eplSetError(plat, EGL_BAD_ALLOC, "Failed to create internal locks");
- pthread_mutex_destroy(&pdpy->mutex);
+ pthread_rwlock_destroy(&pdpy->init_lock);
free(pdpy);
goto done;
}
@@ -709,7 +693,8 @@ static EGLDisplay eplGetPlatformDisplayExport(void
*platformData,
if (!plat->impl->GetPlatformDisplay(plat, pdpy, nativeDisplay,
remainingAttribs, &display_list))
{
- pthread_mutex_destroy(&pdpy->mutex);
+ pthread_rwlock_destroy(&pdpy->init_lock);
+ pthread_rwlock_destroy(&pdpy->surface_list_lock);
eplPlatformDataUnref(pdpy->platform);
free(pdpy);
ret = EGL_NO_DISPLAY;
@@ -727,20 +712,23 @@ done:
static EGLBoolean HookInitialize(EGLDisplay edpy, EGLint *major, EGLint *minor)
{
- EplDisplay *pdpy = eplLockDisplayInternal(edpy);
+ EplDisplay *pdpy = eplLookupDisplay(edpy);
if (pdpy == NULL)
{
return EGL_FALSE;
}
+ pthread_rwlock_wrlock(&pdpy->init_lock);
+
if (!pdpy->initialized)
{
pdpy->major = 1;
pdpy->minor = 5;
if (!pdpy->platform->impl->InitializeDisplay(pdpy->platform, pdpy,
&pdpy->major, &pdpy->minor))
{
- eplDisplayRelease(pdpy);
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
return EGL_FALSE;
}
pdpy->initialized = EGL_TRUE;
@@ -767,31 +755,28 @@ static EGLBoolean HookInitialize(EGLDisplay edpy, EGLint
*major, EGLint *minor)
*minor = pdpy->minor;
}
- eplDisplayRelease(pdpy);
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
return EGL_TRUE;
}
static void TerminateDisplay(EplDisplay *pdpy)
{
pdpy->init_count = 0;
- pdpy->initialized = EGL_FALSE;
-
- if (pdpy->platform == NULL)
+ if (pdpy->initialized)
{
- // We've already gone through teardown, so don't try to do anything
- // else. All remaining cleanup will happen in DestroyDisplay.
- return;
- }
+ pdpy->initialized = EGL_FALSE;
- DestroyAllSurfaces(pdpy);
- pdpy->platform->impl->TerminateDisplay(pdpy->platform, pdpy);
+ DestroyAllSurfaces(pdpy);
+ pdpy->platform->impl->TerminateDisplay(pdpy->platform, pdpy);
+ }
}
static void CheckTerminateDisplay(EplDisplay *pdpy)
{
if (pdpy->initialized)
{
- if (pdpy->init_count == 0 && pdpy->use_count == 0)
+ if (pdpy->init_count == 0)
{
TerminateDisplay(pdpy);
}
@@ -800,18 +785,23 @@ static void CheckTerminateDisplay(EplDisplay *pdpy)
static EGLBoolean HookTerminate(EGLDisplay edpy)
{
- EplDisplay *pdpy = eplLockDisplayInternal(edpy);
+ EplDisplay *pdpy = eplLookupDisplay(edpy);
if (pdpy == NULL)
{
return EGL_FALSE;
}
+ pthread_rwlock_wrlock(&pdpy->init_lock);
+
if (pdpy->init_count > 0)
{
pdpy->init_count--;
+ CheckTerminateDisplay(pdpy);
}
- eplDisplayRelease(pdpy);
+
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
return EGL_TRUE;
}
@@ -1333,40 +1323,52 @@ static void *eplGetInternalHandleExport(EGLDisplay
edpy, EGLenum type, void *han
if (type == EGL_OBJECT_DISPLAY_KHR)
{
- EplDisplay *pdpy = eplLockDisplayInternal(handle);
+ EplDisplay *pdpy = eplLookupDisplay(handle);
+
if (pdpy != NULL)
{
- ret = pdpy->internal_display;
- eplDisplayRelease(pdpy);
+ pthread_rwlock_rdlock(&pdpy->init_lock);
+ if (pdpy->initialized)
+ {
+ ret = pdpy->internal_display;
+ }
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
}
}
else
{
- EplDisplay *pdpy = eplLockDisplayInternal(edpy);
+ EplDisplay *pdpy = eplLookupDisplay(edpy);
if (pdpy != NULL)
{
- if (type == EGL_OBJECT_SURFACE_KHR)
+ pthread_rwlock_rdlock(&pdpy->init_lock);
+
+ if (pdpy->initialized)
{
- const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
- EplSurface *psurf = eplSurfaceListLookup(surface_list,
(EGLSurface) handle);
- if (psurf != NULL)
- {
- ret = psurf->internal_surface;
- }
- else
+ if (type == EGL_OBJECT_SURFACE_KHR)
{
- /*
- * Assume that if we don't recognize the handle, then it's
- * a pbuffer or stream surface, and so the driver should
- * just pass it through. If the handle is invalid, then the
- * driver should then set the appropriate error code on its
- * own.
- */
- ret = handle;
+ const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
+ EplSurface *psurf = eplSurfaceListLookup(surface_list,
(EGLSurface) handle);
+ if (psurf != NULL)
+ {
+ ret = psurf->internal_surface;
+ }
+ else
+ {
+ /*
+ * Assume that if we don't recognize the handle, then
it's
+ * a pbuffer or stream surface, and so the driver
should
+ * just pass it through. If the handle is invalid,
then the
+ * driver should then set the appropriate error code
on its
+ * own.
+ */
+ ret = handle;
+ }
+ eplDisplayUnlockSurfaceList(pdpy);
}
- eplDisplayUnlockSurfaceList(pdpy);
}
- eplDisplayRelease(pdpy);
+ pthread_rwlock_unlock(&pdpy->init_lock);
+ eplDisplayUnref(pdpy);
}
}
diff --git a/src/base/platform-base.h b/src/base/platform-base.h
index 297def3..8ec845e 100644
--- a/src/base/platform-base.h
+++ b/src/base/platform-base.h
@@ -83,8 +83,6 @@ typedef struct
EGLSurface internal_surface;
EplSurfaceType type;
- EGLBoolean deleted;
-
/**
* Private data used by the implementation.
*/
@@ -145,6 +143,17 @@ typedef struct
// Everything after this in EplDisplay should be treated as internal to
// platform-base.c.
+ /**
+ * A read/write lock to protect against concurrent calls to
eglTerminate.
+ *
+ * eglInitialize, eglTerminate, and library teardown will all take the
read
+ * lock.
+ *
+ * All other functions will take the read lock, so that they don't have
to
+ * worry about another thread coming along and terminating the display.
+ */
+ pthread_rwlock_t init_lock;
+
/**
* All of the existing EplSurface structs.
*/
@@ -163,11 +172,6 @@ typedef struct
*/
pthread_rwlock_t surface_list_lock;
- /**
- * A mutex to control access to the display. This is a recursive mutex.
- */
- pthread_mutex_t mutex;
-
/**
* True if this display was created with EGL_TRACK_REFERENCES set.
*/
@@ -180,14 +184,6 @@ typedef struct
*/
unsigned int init_count;
- /**
- * This is a counter to keep track of whether the display is in use or not.
- *
- * If the app calls eglTerminate, then we defer the termination until the
- * display is no longer in use.
- */
- unsigned int use_count;
-
/// The major version number for eglInitialize in this context.
EGLint major;
/// The minor version number for eglInitialize in this context.
@@ -330,23 +326,6 @@ EGLDisplay eplGetCurrentDisplay(void);
*/
void eplDisplayRelease(EplDisplay *pdpy);
-/**
- * Unlocks the mutex for an EplDisplay, but does not decrement the reference
- * count.
- *
- * This allows a platform library to temporarily release the mutex for an
- * EplDisplay, but ensures that the EplDisplay itself sticks around.
- *
- * The caller must call eplDisplayLock to lock the mutex again before calling
- * eplDisplayRelease.
- */
-void eplDisplayUnlock(EplDisplay *pdpy);
-
-/**
- * Re-locks the mutex for an EplDisplay.
- */
-void eplDisplayLock(EplDisplay *pdpy);
-
/**
* Looks up an internal EGLDisplay. If an EplInternalDisplay struct doesn't
* already exist, then it will be created and returned.
--
2.51.0
++++++ 0003-base-Add-an-explicit-egl-dependency.patch ++++++
>From 6c93d5120feca384a75856a172f86f0351184350 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Wed, 26 Mar 2025 10:16:55 -0600
Subject: [PATCH 03/18] base: Add an explicit egl dependency
Add an explicit dependency on 'egl' to the meson.build files.
---
meson.build | 1 +
src/base/meson.build | 1 +
2 files changed, 2 insertions(+)
diff --git a/meson.build b/meson.build
index 449baf2..5314d06 100644
--- a/meson.build
+++ b/meson.build
@@ -21,6 +21,7 @@ project('nvidia-egl-platform-base', 'c',
dep_libdrm = dependency('libdrm')
dep_threads = dependency('threads')
dep_eglexternal = dependency('eglexternalplatform', version : ['>=1.2', '<2'])
+dep_egl = dependency('egl', version : ['>=1.5',
'<2']).partial_dependency(includes : true, compile_args : true)
inc_base = include_directories('src/base')
cc = meson.get_compiler('c')
diff --git a/src/base/meson.build b/src/base/meson.build
index a909998..0c863e1 100644
--- a/src/base/meson.build
+++ b/src/base/meson.build
@@ -24,6 +24,7 @@ platform_base = static_library('platform-base',
dep_libdrm.partial_dependency(compile_args : true, includes : true),
dep_threads,
dep_eglexternal,
+ dep_egl,
],
gnu_symbol_visibility: 'hidden',
install: false)
--
2.51.0
++++++ 0004-Replace-eplGetCurrentDisplay-with-eplGetCurrentSurfa.patch ++++++
>From 0e4e129ff2315f0cd8d3cd2327e7809b7e93e1ac Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Wed, 29 Jan 2025 10:48:10 -0700
Subject: [PATCH 04/18] Replace eplGetCurrentDisplay with eplGetCurrentSurface.
Remove eplGetCurrentDisplay, and replace it with a eplGetCurrentSurface
function that returns both the current EGLDisplay and the current
EGLSurface.
That makes it possible to use eplHookDisplaySurface and
eplHookDisplaySurfaceEnd with functions that operate on the current
EGLSurface.
---
src/base/platform-base.c | 45 +++++++++++++++++++++++-----------------
src/base/platform-base.h | 8 +++++--
2 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index ad0dc8c..687e323 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -323,10 +323,11 @@ EplDisplay *eplDisplayAcquire(EGLDisplay edpy)
return pdpy;
}
-EGLDisplay eplGetCurrentDisplay(void)
+void eplGetCurrentSurface(EGLDisplay *ret_edpy, EGLSurface *ret_esurf)
{
EplPlatformData *plat;
EGLDisplay edpy = EGL_NO_DISPLAY;
+ EGLSurface esurf = EGL_NO_SURFACE;
/*
* In practice, loadEGLExternalPlatform is only ever going to get called
@@ -343,12 +344,20 @@ EGLDisplay eplGetCurrentDisplay(void)
edpy = plat->egl.GetCurrentDisplay();
if (edpy != EGL_NO_DISPLAY)
{
+ esurf = plat->egl.GetCurrentSurface(EGL_DRAW);
break;
}
}
pthread_mutex_unlock(&platform_data_list_mutex);
- return edpy;
+ if (ret_edpy != NULL)
+ {
+ *ret_edpy = edpy;
+ }
+ if (ret_esurf != NULL)
+ {
+ *ret_esurf = esurf;
+ }
}
static void DestroyAllSurfaces(EplDisplay *pdpy)
@@ -1137,24 +1146,23 @@ static EGLBoolean HookSwapBuffers(EGLDisplay edpy,
EGLSurface esurf)
static EGLBoolean HookWaitGL(void)
{
- EGLDisplay edpy = eplGetCurrentDisplay();
- EplDisplay *pdpy = eplDisplayAcquire(edpy);
+ EGLDisplay edpy = EGL_NO_DISPLAY;
+ EGLDisplay esurf = EGL_NO_SURFACE;
+ EplDisplay *pdpy = NULL;
+ EplSurface *psurf = NULL;
EGLBoolean ret = EGL_FALSE;
- if (pdpy == NULL)
+ eplGetCurrentSurface(&edpy, &esurf);
+
+ if (!eplHookDisplaySurface(edpy, esurf, &pdpy, &psurf))
{
return EGL_FALSE;
}
-
assert(pdpy->platform->impl->WaitGL != NULL);
if (pdpy->platform->impl->WaitGL != NULL)
{
- const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
- EplSurface *psurf = eplSurfaceListLookup(surface_list,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
-
ret = pdpy->platform->impl->WaitGL(pdpy, psurf);
- eplDisplayUnlockSurfaceList(pdpy);
}
else
{
@@ -1164,17 +1172,20 @@ static EGLBoolean HookWaitGL(void)
eplSetError(pdpy->platform, EGL_BAD_ALLOC, "Internal error: eglWaitGL
hook should not be called");
}
- eplDisplayRelease(pdpy);
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
return ret;
}
static EGLBoolean HookWaitNative(void)
{
- EGLDisplay edpy = eplGetCurrentDisplay();
- EplDisplay *pdpy = eplDisplayAcquire(edpy);
+ EGLDisplay edpy = EGL_NO_DISPLAY;
+ EGLDisplay esurf = EGL_NO_SURFACE;
+ EplDisplay *pdpy = NULL;
+ EplSurface *psurf = NULL;
EGLBoolean ret = EGL_FALSE;
- if (pdpy == NULL)
+ eplGetCurrentSurface(&edpy, &esurf);
+ if (!eplHookDisplaySurface(edpy, esurf, &pdpy, &psurf))
{
return EGL_FALSE;
}
@@ -1182,18 +1193,14 @@ static EGLBoolean HookWaitNative(void)
assert(pdpy->platform->impl->WaitNative != NULL);
if (pdpy->platform->impl->WaitNative != NULL)
{
- const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
- EplSurface *psurf = eplSurfaceListLookup(surface_list,
pdpy->platform->egl.GetCurrentSurface(EGL_DRAW));
-
ret = pdpy->platform->impl->WaitNative(pdpy, psurf);
- eplDisplayUnlockSurfaceList(pdpy);
}
else
{
eplSetError(pdpy->platform, EGL_BAD_ALLOC, "Internal error:
eglWaitNative hook should not be called");
}
- eplDisplayRelease(pdpy);
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
return ret;
}
diff --git a/src/base/platform-base.h b/src/base/platform-base.h
index 8ec845e..f31834d 100644
--- a/src/base/platform-base.h
+++ b/src/base/platform-base.h
@@ -317,9 +317,13 @@ void eplPlatformBaseInitFail(EplPlatformData *plat);
EplDisplay *eplDisplayAcquire(EGLDisplay edpy);
/**
- * Returns the current EGLDisplay for the current thread.
+ * Returns the current external EGLDisplay and EGLSurface handles for the
+ * calling thread.
+ *
+ * \param[out] ret_edpy Returns the current external EGLDisplay
+ * \param[out] ret_esurf Returns the current external EGLSurface
*/
-EGLDisplay eplGetCurrentDisplay(void);
+void eplGetCurrentSurface(EGLDisplay *ret_edpy, EGLSurface *ret_esurf);
/**
* Releases a display acquired with eplDisplayAcquire.
--
2.51.0
++++++ 0005-base-Add-an-optional-hook-for-eglSwapInterval.patch ++++++
>From 61356b495fd3dd6476cdfb77bf839d43d08f36c1 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Wed, 12 Mar 2025 14:15:21 -0600
Subject: [PATCH 05/18] base: Add an optional hook for eglSwapInterval
Add an optional EplImplFuncs::SwapInterval function to handle
eglSwapInterval calls.
If it's not NULL, then the base library will provide a hook function for
eglSwapInterval.
HookSwapInterval will handle looking up the current EGLDisplay and
EGLSurface and making sure that they're valid, including all the
necessary locking.
---
src/base/platform-base.c | 61 ++++++++++++++++++++++++++++++++++++++++
src/base/platform-base.h | 1 +
src/base/platform-impl.h | 19 +++++++++++++
3 files changed, 81 insertions(+)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 687e323..2560f14 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -130,6 +130,7 @@ EplPlatformData *eplPlatformBaseAllocate(int major, int
minor,
platform->egl.MakeCurrent = driver->getProcAddress("eglMakeCurrent");
platform->egl.WaitGL = driver->getProcAddress("eglWaitGL");
platform->egl.WaitNative = driver->getProcAddress("eglWaitNative");
+ platform->egl.SwapInterval = driver->getProcAddress("eglSwapInterval");
platform->egl.WaitClient = driver->getProcAddress("eglWaitClient");
platform->egl.ChooseConfig = driver->getProcAddress("eglChooseConfig");
platform->egl.GetConfigAttrib =
driver->getProcAddress("eglGetConfigAttrib");
@@ -1238,6 +1239,62 @@ static EGLBoolean HookQueryDisplayAttrib(EGLDisplay
edpy, EGLint attribute, EGLA
return ret;
}
+static EGLBoolean HookSwapInterval(EGLDisplay edpy, EGLint interval)
+{
+ EplDisplay *pdpy = NULL;
+ EGLBoolean ret = EGL_FALSE;
+ EGLDisplay internal_edpy = EGL_NO_DISPLAY;
+ PFNEGLSWAPINTERVALPROC SwapInterval = NULL;
+
+ pdpy = eplDisplayAcquire(edpy);
+ if (pdpy == NULL)
+ {
+ return EGL_FALSE;
+ }
+
+ if (pdpy->platform->egl.GetCurrentDisplay() == edpy)
+ {
+ EGLSurface esurf = pdpy->platform->egl.GetCurrentSurface(EGL_DRAW);
+ const struct glvnd_list *surface_list =
eplDisplayLockSurfaceList(pdpy);
+ EplSurface *psurf = eplSurfaceListLookup(surface_list, esurf);
+ if (psurf != NULL)
+ {
+ if (pdpy->platform->impl->SwapInterval != NULL)
+ {
+ ret = pdpy->platform->impl->SwapInterval(pdpy, psurf,
interval);
+ }
+ else
+ {
+ // This should never happen: If we don't have a SwapInterval
+ // implementation, then we shouldn't have provided an
+ // eglSwapInterval hook to the driver.
+ assert(!"Can't happen -- no SwapInterval implementation");
+ ret = EGL_TRUE;
+ }
+ }
+ else
+ {
+ // If we don't recognize he current EGLSurface, then we'll just
+ // pass the call through to the driver after we unlock everything.
+ internal_edpy = pdpy->internal_display;
+ SwapInterval = pdpy->platform->egl.SwapInterval;
+ }
+ eplDisplayUnlockSurfaceList(pdpy);
+ }
+ else
+ {
+ eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLDisplay %p is not
current", edpy);
+ }
+
+ if (SwapInterval != NULL)
+ {
+ ret = SwapInterval(internal_edpy, interval);
+ }
+
+ eplDisplayRelease(pdpy);
+ return ret;
+}
+
static const EplHookFunc BASE_HOOK_FUNCTIONS[] =
{
{ "eglCreatePbufferSurface", HookCreatePbufferSurface },
@@ -1285,6 +1342,10 @@ void *eplGetHookAddressExport(void *platformData, const
char *name)
{
return HookWaitNative;
}
+ if (plat->impl->SwapInterval != NULL && strcmp(name, "eglSwapInterval") ==
0)
+ {
+ return HookSwapInterval;
+ }
return NULL;
}
diff --git a/src/base/platform-base.h b/src/base/platform-base.h
index f31834d..5616321 100644
--- a/src/base/platform-base.h
+++ b/src/base/platform-base.h
@@ -217,6 +217,7 @@ typedef struct _EplPlatformData
PFNEGLWAITGLPROC WaitGL;
PFNEGLWAITCLIENTPROC WaitClient;
PFNEGLWAITNATIVEPROC WaitNative;
+ PFNEGLSWAPINTERVALPROC SwapInterval;
PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC QueryDeviceStringEXT;
diff --git a/src/base/platform-impl.h b/src/base/platform-impl.h
index a44ac60..e3a865d 100644
--- a/src/base/platform-impl.h
+++ b/src/base/platform-impl.h
@@ -290,6 +290,25 @@ typedef struct _EplImplFuncs
* \return EGL_TRUE on success, EGL_FALSE on failure.
*/
EGLBoolean (*QueryDisplayAttrib) (EplDisplay *pdpy, EGLint attrib,
EGLAttrib *ret_value);
+
+ /**
+ * Implements eglSwapInterval.
+ *
+ * This is only called if the current EGLSurface belongs to the platform
+ * library. If the current EGLSurface does not belong to the platform
+ * library (e.g., a pbuffer or stream), then the base library will pass the
+ * call through to the driver.
+ *
+ * This function is optional. If it's NULL, then the base library will not
+ * provide a hook function eglSwapInterval, and so the driver will follow
its
+ * default behavior.
+ *
+ * \param pdpy The current display.
+ * \param psurf The current draw surface. This will never be NULL.
+ * \param interval The new swap interval.
+ * \return EGL_TRUE on success, or EGL_FALSE on failure.
+ */
+ EGLBoolean (* SwapInterval) (EplDisplay *pdpy, EplSurface *psurf, EGLint
interval);
} EplImplFuncs;
#ifdef __cplusplus
--
2.51.0
++++++ 0006-base-Add-basic-support-for-EGL_KHR_partial_update.patch ++++++
>From dcbb123f1804572889d2dc45af00e89ee9e5ff4f Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Tue, 14 Oct 2025 16:33:47 -0600
Subject: [PATCH 06/18] base: Add basic support for EGL_KHR_partial_update.
Add the necessary bookkeeping to handle EGL_KHR_partial_update and
EGL_EXT_buffer_age.
Added hook functions for eglQuerySurface and eglSetDamageRegionKHR.
Added flags to EplSurface to keep track of whether EGL_BUFFER_AGE has
been queried, and whether eglSetDamageRegionKHR has been called, since
that affects the error behavior of eglSetDamageRegionKHR.
Currently, it'll just return zero for EGL_BUFFER_AGE and ignore the
rectangles for eglSetDamageRegionKHR, which is valid if not very useful.
Later change will add functions to EplImplFuncs to plumb those through
to platform-specific handlers.
---
src/base/platform-base.c | 127 +++++++++++++++++++++++++++++++++++++++
src/base/platform-base.h | 14 +++++
2 files changed, 141 insertions(+)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 2560f14..94aa4b7 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -135,6 +135,7 @@ EplPlatformData *eplPlatformBaseAllocate(int major, int
minor,
platform->egl.ChooseConfig = driver->getProcAddress("eglChooseConfig");
platform->egl.GetConfigAttrib =
driver->getProcAddress("eglGetConfigAttrib");
platform->egl.GetConfigs = driver->getProcAddress("eglGetConfigs");
+ platform->egl.QuerySurface = driver->getProcAddress("eglQuerySurface");
platform->egl.QueryDeviceAttribEXT =
driver->getProcAddress("eglQueryDeviceAttribEXT");
platform->egl.QueryDeviceStringEXT =
driver->getProcAddress("eglQueryDeviceStringEXT");
platform->egl.QueryDevicesEXT =
driver->getProcAddress("eglQueryDevicesEXT");
@@ -164,6 +165,7 @@ EplPlatformData *eplPlatformBaseAllocate(int major, int
minor,
|| platform->egl.ChooseConfig == NULL
|| platform->egl.GetConfigAttrib == NULL
|| platform->egl.GetConfigs == NULL
+ || platform->egl.QuerySurface == NULL
|| platform->egl.QueryDeviceAttribEXT == NULL
|| platform->egl.QueryDeviceStringEXT == NULL
|| platform->egl.QueryDevicesEXT == NULL
@@ -1110,6 +1112,11 @@ static EGLBoolean HookSwapBuffersWithDamage(EGLDisplay
edpy, EGLSurface esurf, c
else
{
ret = pdpy->platform->impl->SwapBuffers(pdpy->platform, pdpy,
psurf, rects, n_rects);
+ if (ret)
+ {
+ psurf->setDamageRegionCalled = EGL_FALSE;
+ psurf->bufferAgeCalled = EGL_FALSE;
+ }
}
eplHookDisplaySurfaceEnd(pdpy, psurf);
@@ -1295,6 +1302,124 @@ static EGLBoolean HookSwapInterval(EGLDisplay edpy,
EGLint interval)
return ret;
}
+static EGLBoolean HookQuerySurface(EGLDisplay edpy, EGLSurface esurf, EGLint
attribute, EGLint *value)
+{
+ EplDisplay *pdpy;
+ EplSurface *psurf;
+ EGLBoolean ret = EGL_FALSE;
+
+ if (!eplHookDisplaySurface(edpy, esurf, &pdpy, &psurf))
+ {
+ return EGL_FALSE;
+ }
+
+ if (value == NULL)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_PARAMETER, "value pointer must not
be NULL");
+ goto done;
+ }
+
+ if (psurf != NULL)
+ {
+ if (attribute == EGL_BUFFER_AGE_KHR)
+ {
+ if (pdpy->platform->egl.GetCurrentSurface(EGL_DRAW) != esurf)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLSurface %p is
not current", esurf);
+ goto done;
+ }
+
+ // Note: This is where we'll call into the platform-specific code
+ // once we add a query function to EplImplFuncs. Until then,
+ // returning zero is valid (if not very useful).
+ *value = 0;
+
+ psurf->bufferAgeCalled = EGL_TRUE;
+ ret = EGL_TRUE;
+ }
+ else
+ {
+ // If it's not an attribute that we recognize, then pass the query
+ // through to the driver.
+ ret = pdpy->platform->egl.QuerySurface(pdpy->internal_display,
+ psurf->internal_surface, attribute, value);
+ }
+ }
+ else
+ {
+ // If it's not an EGLSurface that we recognize, then pass the query
+ // through to the driver.
+ ret = pdpy->platform->egl.QuerySurface(pdpy->internal_display,
+ esurf, attribute, value);
+ }
+
+done:
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
+ return ret;
+}
+
+static EGLBoolean HookSetDamageRegion(EGLDisplay edpy, EGLSurface esurf,
EGLint *rects, EGLint n_rects)
+{
+ EplDisplay *pdpy;
+ EplSurface *psurf;
+ EGLBoolean ret = EGL_FALSE;
+
+ if (!eplHookDisplaySurface(edpy, esurf, &pdpy, &psurf))
+ {
+ return EGL_FALSE;
+ }
+
+ if (psurf != NULL)
+ {
+ if (psurf->type != EPL_SURFACE_TYPE_WINDOW)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_MATCH, "EGLSurface %p is not a
postable surface", esurf);
+ goto done;
+ }
+ if (pdpy->platform->egl.GetCurrentSurface(EGL_DRAW) != esurf)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_MATCH, "EGLSurface %p is not
current", esurf);
+ goto done;
+ }
+ if (!psurf->bufferAgeCalled)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_ACCESS,
+ "EGL_BUFFER_AGE_KHR must be queried before calling
eglSetDamageRegionKHR");
+ goto done;
+ }
+ if (psurf->setDamageRegionCalled)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_ACCESS,
+ "eglSetDamageRegionKHR has already been called this
frame");
+ goto done;
+ }
+
+ /*
+ * Here's where we'd optionally call into the platform-specific code.
+ * Since eglSetDamageRegionKHR is just a hint, it's also valid to just
+ * ignore it.
+ */
+
+ psurf->setDamageRegionCalled = EGL_TRUE;
+ ret = EGL_TRUE;
+ }
+ else if (pdpy->platform->egl.SetDamageRegionKHR != NULL)
+ {
+ // We don't recgonize this EGLSurface, so pass it through to the
driver.
+ ret = pdpy->platform->egl.SetDamageRegionKHR(pdpy->internal_display,
esurf, rects, n_rects);
+ }
+ else
+ {
+ // If the driver doesn't support eglSetDamageRegionKHR, then just
+ // ignore it and return success.
+ ret = EGL_TRUE;
+ }
+
+done:
+ eplHookDisplaySurfaceEnd(pdpy, psurf);
+ return ret;
+}
+
static const EplHookFunc BASE_HOOK_FUNCTIONS[] =
{
{ "eglCreatePbufferSurface", HookCreatePbufferSurface },
@@ -1307,6 +1432,8 @@ static const EplHookFunc BASE_HOOK_FUNCTIONS[] =
{ "eglQueryDisplayAttribEXT", HookQueryDisplayAttrib },
{ "eglQueryDisplayAttribKHR", HookQueryDisplayAttrib },
{ "eglQueryDisplayAttribNV", HookQueryDisplayAttrib },
+ { "eglQuerySurface", HookQuerySurface },
+ { "eglSetDamageRegionKHR", HookSetDamageRegion },
{ "eglSwapBuffers", HookSwapBuffers },
{ "eglSwapBuffersWithDamageEXT", HookSwapBuffersWithDamage },
{ "eglSwapBuffersWithDamageKHR", HookSwapBuffersWithDamage },
diff --git a/src/base/platform-base.h b/src/base/platform-base.h
index 5616321..d615e46 100644
--- a/src/base/platform-base.h
+++ b/src/base/platform-base.h
@@ -88,6 +88,17 @@ typedef struct
*/
EplImplSurface *priv;
+ /**
+ * True if eglSetDamageRegionKHR has been called since the last
+ * eglSwapBuffers.
+ */
+ EGLBoolean setDamageRegionCalled;
+
+ /**
+ * True EGL_BUFFER_AGE has been queried since the last eglSwapBuffers.
+ */
+ EGLBoolean bufferAgeCalled;
+
struct glvnd_list entry;
} EplSurface;
@@ -218,6 +229,7 @@ typedef struct _EplPlatformData
PFNEGLWAITCLIENTPROC WaitClient;
PFNEGLWAITNATIVEPROC WaitNative;
PFNEGLSWAPINTERVALPROC SwapInterval;
+ PFNEGLQUERYSURFACEPROC QuerySurface;
PFNEGLQUERYDEVICEATTRIBEXTPROC QueryDeviceAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC QueryDeviceStringEXT;
@@ -226,6 +238,8 @@ typedef struct _EplPlatformData
PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC SwapBuffersWithDamage;
PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC
CreateStreamProducerSurfaceKHR;
+
+ PFNEGLSETDAMAGEREGIONKHRPROC SetDamageRegionKHR;
} egl;
struct
--
2.51.0
++++++ 0007-base-Add-an-EplImplFuncs-function-for-EGL_BUFFER_AGE.patch ++++++
>From 94f578e48cbcde2468385b7187b71d22b2bb9ba2 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Tue, 14 Oct 2025 16:42:08 -0600
Subject: [PATCH 07/18] base: Add an EplImplFuncs function for EGL_BUFFER_AGE.
Add a new function, EplImplFuncs::QueryBufferAge, which is used to check
the value of EGL_BUFFER_AGE for a surface.
---
src/base/platform-base.c | 23 +++++++++++++++++++----
src/base/platform-impl.h | 12 ++++++++++++
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 94aa4b7..f746fe3 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -1329,10 +1329,25 @@ static EGLBoolean HookQuerySurface(EGLDisplay edpy,
EGLSurface esurf, EGLint att
goto done;
}
- // Note: This is where we'll call into the platform-specific code
- // once we add a query function to EplImplFuncs. Until then,
- // returning zero is valid (if not very useful).
- *value = 0;
+ if (pdpy->platform->impl->QueryBufferAge != NULL)
+ {
+ EGLint age = pdpy->platform->impl->QueryBufferAge(pdpy, psurf);
+ if (age < 0)
+ {
+ goto done;
+ }
+
+ *value = age;
+ }
+ else
+ {
+ /*
+ * If the platform code doesn't implement this, then just
return
+ * zero. That's always valid, and means that the application
can't
+ * make any assumptions about the buffer's contents.
+ */
+ *value = 0;
+ }
psurf->bufferAgeCalled = EGL_TRUE;
ret = EGL_TRUE;
diff --git a/src/base/platform-impl.h b/src/base/platform-impl.h
index e3a865d..d767f3b 100644
--- a/src/base/platform-impl.h
+++ b/src/base/platform-impl.h
@@ -309,6 +309,18 @@ typedef struct _EplImplFuncs
* \return EGL_TRUE on success, or EGL_FALSE on failure.
*/
EGLBoolean (* SwapInterval) (EplDisplay *pdpy, EplSurface *psurf, EGLint
interval);
+
+ /**
+ * Returns the value of EGL_BUFFER_AGE_KHR.
+ *
+ * This function is optional. If it's NULL, then the base library will just
+ * return zero.
+ *
+ * \param pdpy The current display.
+ * \param psurf The current draw surface. This will never be NULL.
+ * \return The buffer age, or -1 on error.
+ */
+ EGLint (* QueryBufferAge) (EplDisplay *pdpy, EplSurface *psurf);
} EplImplFuncs;
#ifdef __cplusplus
--
2.51.0
++++++ 0008-base-Add-an-EplImplFuncs-function-for-eglSetDamageRe.patch ++++++
>From 83c95316e8758ae46232d78d7425fdefcedb603c Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Tue, 14 Oct 2025 16:49:33 -0600
Subject: [PATCH 08/18] base: Add an EplImplFuncs function for
eglSetDamageRegionKHR
Add an optional EplImplFuncs::SetDamageRegion function to implement
eglSetDamageRegionKHR.
---
src/base/platform-base.c | 23 ++++++++++++++++-------
src/base/platform-impl.h | 14 ++++++++++++++
2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index f746fe3..18196bd 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -1409,14 +1409,23 @@ static EGLBoolean HookSetDamageRegion(EGLDisplay edpy,
EGLSurface esurf, EGLint
goto done;
}
- /*
- * Here's where we'd optionally call into the platform-specific code.
- * Since eglSetDamageRegionKHR is just a hint, it's also valid to just
- * ignore it.
- */
+ if (pdpy->platform->impl->SetDamageRegion != NULL)
+ {
+ ret = pdpy->platform->impl->SetDamageRegion(pdpy, psurf, rects,
n_rects);
+ }
+ else
+ {
+ /*
+ * eglSetDamageRegionKHR is just a hint, so if the platform doesn't
+ * do anything with it, we can still return success.
+ */
+ ret = EGL_TRUE;
+ }
- psurf->setDamageRegionCalled = EGL_TRUE;
- ret = EGL_TRUE;
+ if (ret)
+ {
+ psurf->setDamageRegionCalled = EGL_TRUE;
+ }
}
else if (pdpy->platform->egl.SetDamageRegionKHR != NULL)
{
diff --git a/src/base/platform-impl.h b/src/base/platform-impl.h
index d767f3b..b6f5dad 100644
--- a/src/base/platform-impl.h
+++ b/src/base/platform-impl.h
@@ -321,6 +321,20 @@ typedef struct _EplImplFuncs
* \return The buffer age, or -1 on error.
*/
EGLint (* QueryBufferAge) (EplDisplay *pdpy, EplSurface *psurf);
+
+ /**
+ * Implements eglSetDamageRegionKHR.
+ *
+ * This function is optional. If it's NULL, then the base library will
+ * ignore the damage areas and return success.
+ *
+ * \param pdpy The current display.
+ * \param psurf The current draw surface. This will never be NULL.
+ * \param rects The damage rectangles.
+ * \param n_rects The number of elements in the \p rects array.
+ * \return EGL_TRUE on success, or EGL_FALSE on failure.
+ */
+ EGLBoolean (* SetDamageRegion) (EplDisplay *pdpy, EplSurface *psurf, const
EGLint *rects, EGLint n_rects);
} EplImplFuncs;
#ifdef __cplusplus
--
2.51.0
++++++ 0009-egl-wayland2-add-FP16-DRM-format.patch ++++++
>From 4f027414b95d358c8f088b7631a5755f1639e10e Mon Sep 17 00:00:00 2001
From: Austin Shafer <[email protected]>
Date: Mon, 27 Oct 2025 14:03:55 -0400
Subject: [PATCH 09/18] egl-wayland2: add FP16 DRM format
---
src/base/config-list.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/base/config-list.c b/src/base/config-list.c
index 08c27af..ce4095c 100644
--- a/src/base/config-list.c
+++ b/src/base/config-list.c
@@ -41,6 +41,7 @@ const EplFormatInfo FORMAT_INFO_LIST[] =
{ DRM_FORMAT_RG1616, 32, { 16, 16, 0, 0 }, { 16, 0, 0, 0 } },
{ DRM_FORMAT_ARGB2101010, 32, { 10, 10, 10, 2 }, { 20, 10, 0, 30 } },
{ DRM_FORMAT_ABGR2101010, 32, { 10, 10, 10, 2 }, { 0, 10, 20, 30 } },
+ { DRM_FORMAT_ABGR16161616F, 64, { 16, 16, 16, 16 }, { 0, 16, 32, 48 } },
/* 8 bpp RGB */
{ DRM_FORMAT_RGB332, 8, { 3, 3, 2, 0 }, { 5, 2, 0, 0 } },
--
2.51.0
++++++ 0010-Bump-the-version-number-to-1.0.6.patch ++++++
>From 6b088ea403126005cfeeab0229b0f6d53cc74780 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Fri, 6 Mar 2026 12:20:56 -0700
Subject: [PATCH 10/18] Bump the version number to 1.0.6.
---
meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index 560c489..b48d29b 100644
--- a/meson.build
+++ b/meson.build
@@ -14,7 +14,7 @@
# limitations under the License.
project('egl-x11', 'c',
- version : '1.0.5',
+ version : '1.0.6',
default_options : ['c_std=gnu99'],
)
--
2.51.0
++++++ 0011-base-Replace-EplImplFuncs-QueryBufferAge-with-QueryS.patch ++++++
>From 7429b9f95fe81a20a4ae9617f461634b0fbc3ca5 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Tue, 10 Mar 2026 11:03:47 -0600
Subject: [PATCH 11/18] base: Replace EplImplFuncs::QueryBufferAge with
QuerySurface
Remove EplImplFuncs::QueryBufferAge and replace it with a more general
QuerySurface function.
This allows adding platform-specific attributes, but keeps the
bookkeeping for EGL_BUFFER_AGE_KHR.
Since having the platform code pass the call through to the driver won't
work for EGL_BUFFER_AGE_KHR, this change also adds a new EplQueryResult
enum to distinguish between success, failure, and an attribute that the
platform simply doesn't recognize.
For consistency, also change QueryDisplayAttrib to return an
EplQueryResult.
---
src/base/platform-base.c | 62 ++++++++++++++++++++++++++--------------
src/base/platform-impl.h | 44 ++++++++++++++++++++++++----
2 files changed, 78 insertions(+), 28 deletions(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 18196bd..1f86ffc 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -1233,13 +1233,22 @@ static EGLBoolean HookQueryDisplayAttrib(EGLDisplay
edpy, EGLint attribute, EGLA
*value = (EGLAttrib) pdpy->track_references;
ret = EGL_TRUE;
}
- else if (pdpy->platform->impl->QueryDisplayAttrib != NULL)
- {
- ret = pdpy->platform->impl->QueryDisplayAttrib(pdpy, attribute, value);
- }
else
{
- ret =
pdpy->platform->egl.QueryDisplayAttribEXT(pdpy->internal_display, attribute,
value);
+ EplQueryResult result = EPL_QUERY_RESULT_UNKNOWN;
+ if (pdpy->platform->impl->QueryDisplayAttrib != NULL)
+ {
+ result = pdpy->platform->impl->QueryDisplayAttrib(pdpy, attribute,
value);
+ }
+
+ if (result == EPL_QUERY_RESULT_UNKNOWN)
+ {
+ ret =
pdpy->platform->egl.QueryDisplayAttribEXT(pdpy->internal_display, attribute,
value);
+ }
+ else
+ {
+ ret = (result == EPL_QUERY_RESULT_SUCCESS);
+ }
}
eplDisplayRelease(pdpy);
@@ -1321,25 +1330,27 @@ static EGLBoolean HookQuerySurface(EGLDisplay edpy,
EGLSurface esurf, EGLint att
if (psurf != NULL)
{
+ EplQueryResult result = EPL_QUERY_RESULT_UNKNOWN;
+
if (attribute == EGL_BUFFER_AGE_KHR)
{
+ // Querying EGL_BUFFER_AGE_KHR is only valid for the current
+ // EGLSurface.
if (pdpy->platform->egl.GetCurrentSurface(EGL_DRAW) != esurf)
{
eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLSurface %p is
not current", esurf);
goto done;
}
+ }
- if (pdpy->platform->impl->QueryBufferAge != NULL)
- {
- EGLint age = pdpy->platform->impl->QueryBufferAge(pdpy, psurf);
- if (age < 0)
- {
- goto done;
- }
+ if (pdpy->platform->impl->QuerySurface != NULL)
+ {
+ result = pdpy->platform->impl->QuerySurface(pdpy, psurf,
attribute, value);
+ }
- *value = age;
- }
- else
+ if (result == EPL_QUERY_RESULT_UNKNOWN)
+ {
+ if (attribute == EGL_BUFFER_AGE_KHR)
{
/*
* If the platform code doesn't implement this, then just
return
@@ -1347,17 +1358,24 @@ static EGLBoolean HookQuerySurface(EGLDisplay edpy,
EGLSurface esurf, EGLint att
* make any assumptions about the buffer's contents.
*/
*value = 0;
+ ret = EGL_TRUE;
+ }
+ else
+ {
+ // If it's not an attribute that we recognize, then pass the
query
+ // through to the driver.
+ ret = pdpy->platform->egl.QuerySurface(pdpy->internal_display,
+ psurf->internal_surface, attribute, value);
}
-
- psurf->bufferAgeCalled = EGL_TRUE;
- ret = EGL_TRUE;
}
else
{
- // If it's not an attribute that we recognize, then pass the query
- // through to the driver.
- ret = pdpy->platform->egl.QuerySurface(pdpy->internal_display,
- psurf->internal_surface, attribute, value);
+ ret = (result == EPL_QUERY_RESULT_SUCCESS);
+ }
+
+ if (ret && attribute == EGL_BUFFER_AGE_KHR)
+ {
+ psurf->bufferAgeCalled = EGL_TRUE;
}
}
else
diff --git a/src/base/platform-impl.h b/src/base/platform-impl.h
index b6f5dad..527dded 100644
--- a/src/base/platform-impl.h
+++ b/src/base/platform-impl.h
@@ -35,6 +35,31 @@
extern "C" {
#endif
+/**
+ * This is the return value used for EplImplFuncs::QuerySurface.
+ */
+typedef enum
+{
+ /**
+ * The platform library doesn't recognize the attribute. In this case, the
+ * base library will pass the query through to the driver.
+ */
+ EPL_QUERY_RESULT_UNKNOWN,
+
+ /**
+ * The platform library recognized and returned the attribute.
+ */
+ EPL_QUERY_RESULT_SUCCESS,
+
+ /**
+ * The platform library recognized the attribute, but there was some error
+ * returning the value.
+ *
+ * The platform library should set the EGL error code before returning.
+ */
+ EPL_QUERY_RESULT_ERROR,
+} EplQueryResult;
+
/**
* A table of functions for the platform-specific implementation.
*/
@@ -287,9 +312,9 @@ typedef struct _EplImplFuncs
* \param pdpy The EplDisplay struct
* \param attrib The attribute to look up.
* \param[out] value Returns the value of the attribute.
- * \return EGL_TRUE on success, EGL_FALSE on failure.
+ * \return An \c EplQueryResult value.
*/
- EGLBoolean (*QueryDisplayAttrib) (EplDisplay *pdpy, EGLint attrib,
EGLAttrib *ret_value);
+ EplQueryResult (*QueryDisplayAttrib) (EplDisplay *pdpy, EGLint attrib,
EGLAttrib *ret_value);
/**
* Implements eglSwapInterval.
@@ -311,16 +336,23 @@ typedef struct _EplImplFuncs
EGLBoolean (* SwapInterval) (EplDisplay *pdpy, EplSurface *psurf, EGLint
interval);
/**
- * Returns the value of EGL_BUFFER_AGE_KHR.
+ * Implements eglQuerySurface for any platform-specific attributes.
*
* This function is optional. If it's NULL, then the base library will just
- * return zero.
+ * act as if the platform returned EPL_QUERY_RESULT_UNKNOWN.
+ *
+ * Note that the base library handles the error checking for
+ * EGL_EXT_buffer_age and EGL_KHR_partial_update internally. If \p attrib
+ * is \c EGL_BUFFER_AGE_KHR, then the platform can assume that the surface
+ * is current.
*
* \param pdpy The current display.
* \param psurf The current draw surface. This will never be NULL.
- * \return The buffer age, or -1 on error.
+ * \param attrib The attribute to look up.
+ * \param[out] value Returns the value of the attribute.
+ * \return An \c EplQueryResult value.
*/
- EGLint (* QueryBufferAge) (EplDisplay *pdpy, EplSurface *psurf);
+ EplQueryResult (* QuerySurface) (EplDisplay *pdpy, EplSurface *psurf,
EGLint attrib, EGLint *ret_value);
/**
* Implements eglSetDamageRegionKHR.
--
2.51.0
++++++ 0012-Update-the-X11-code-to-match-the-base-library-change.patch ++++++
++++ 639 lines (skipped)
++++++ 0013-x11-Remove-some-unused-function-pointers.patch ++++++
>From 361c1bae90cbfbbc2e7bba19ef45f7607b7dfa75 Mon Sep 17 00:00:00 2001
From: Kyle Brenneman <[email protected]>
Date: Tue, 10 Mar 2026 11:34:26 -0600
Subject: [PATCH 13/18] x11: Remove some unused function pointers.
Remove the QueryDisplayAttribKHR, SwapInterval, and QuerySurface
function pointers from EplImplPlatform::egl, since nothing uses them.
---
src/x11/x11-platform.c | 8 +-------
src/x11/x11-platform.h | 3 ---
2 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/src/x11/x11-platform.c b/src/x11/x11-platform.c
index 0b85eb5..96f39fe 100644
--- a/src/x11/x11-platform.c
+++ b/src/x11/x11-platform.c
@@ -182,9 +182,6 @@ EGLBoolean eplX11LoadEGLExternalPlatformCommon(int major,
int minor,
return EGL_FALSE;
}
- plat->priv->egl.QueryDisplayAttribKHR =
driver->getProcAddress("eglQueryDisplayAttribKHR");
- plat->priv->egl.SwapInterval = driver->getProcAddress("eglSwapInterval");
- plat->priv->egl.QuerySurface = driver->getProcAddress("eglQuerySurface");
plat->priv->egl.QueryDmaBufFormatsEXT =
driver->getProcAddress("eglQueryDmaBufFormatsEXT");
plat->priv->egl.QueryDmaBufModifiersEXT =
driver->getProcAddress("eglQueryDmaBufModifiersEXT");
plat->priv->egl.CreateSync = driver->getProcAddress("eglCreateSync");
@@ -202,10 +199,7 @@ EGLBoolean eplX11LoadEGLExternalPlatformCommon(int major,
int minor,
plat->priv->egl.PlatformAllocColorBufferNVX =
driver->getProcAddress("eglPlatformAllocColorBufferNVX");
plat->priv->egl.PlatformExportColorBufferNVX =
driver->getProcAddress("eglPlatformExportColorBufferNVX");
- if (plat->priv->egl.QueryDisplayAttribKHR == NULL
- || plat->priv->egl.SwapInterval == NULL
- || plat->priv->egl.QuerySurface == NULL
- || plat->priv->egl.QueryDmaBufFormatsEXT == NULL
+ if (plat->priv->egl.QueryDmaBufFormatsEXT == NULL
|| plat->priv->egl.QueryDmaBufModifiersEXT == NULL
|| plat->priv->egl.CreateSync == NULL
|| plat->priv->egl.DestroySync == NULL
diff --git a/src/x11/x11-platform.h b/src/x11/x11-platform.h
index 3b6e791..1e510bc 100644
--- a/src/x11/x11-platform.h
+++ b/src/x11/x11-platform.h
@@ -76,9 +76,6 @@ struct _EplImplPlatform
{
struct
{
- PFNEGLQUERYDISPLAYATTRIBKHRPROC QueryDisplayAttribKHR;
- PFNEGLSWAPINTERVALPROC SwapInterval;
- PFNEGLQUERYSURFACEPROC QuerySurface;
PFNEGLQUERYDMABUFFORMATSEXTPROC QueryDmaBufFormatsEXT;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC QueryDmaBufModifiersEXT;
PFNEGLCREATESYNCPROC CreateSync;
--
2.51.0
++++++ 0014-poll-for-resize-events-in-x11-SwapBuffers.patch ++++++
>From 587334ac2b07d824743fe746beb7cf2dcddc394b Mon Sep 17 00:00:00 2001
From: Riku Salminen <[email protected]>
Date: Tue, 14 Apr 2026 06:48:04 +0000
Subject: [PATCH 14/18] poll for resize events in x11 SwapBuffers
In x11 SwapBuffers call PollForWindowEvents to ensure that resize events
are handled before CheckReallocWindow.
Without it the event might not get handled if there are no pending frames
and WaitForWindowEvents would not get called.
Fixes dEQP-EGL.functional.resize.*
---
src/x11/x11-window.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/x11/x11-window.c b/src/x11/x11-window.c
index c7816fa..ff6ea62 100644
--- a/src/x11/x11-window.c
+++ b/src/x11/x11-window.c
@@ -2183,6 +2183,22 @@ EGLBoolean eplX11SwapBuffers(EplPlatformData *plat,
EplDisplay *pdpy, EplSurface
options |= XCB_PRESENT_OPTION_SUBOPTIMAL;
}
+ /*
+ * Poll for any pending Present events before entering the throttle loop.
+ *
+ * The throttle loop calls WaitForWindowEvents only when the number of
+ * in-flight frames exceeds MAX_PENDING_FRAMES. With MAX_PENDING_FRAMES=1
+ * the common case is exactly one frame in flight, so the loop exits
+ * immediately without ever calling WaitForWindowEvents.
+ *
+ * This means events queued between two eglSwapBuffers calls, in
+ * particular a PresentConfigureNotify generated by a window resize, would
+ * otherwise never be read before CheckReallocWindow inspects
+ * pending_width/height, causing the resize to go undetected until the
+ * following swap.
+ */
+ PollForWindowEvents(surf);
+
// Wait for pending frames to complete before we continue.
while (1)
{
--
2.51.0
++++++ 0015-fix-parameter-validation.patch ++++++
>From ce455738b9887fb518efe217dfda5615f9bdd45f Mon Sep 17 00:00:00 2001
From: Riku Salminen <[email protected]>
Date: Tue, 14 Apr 2026 14:43:35 +0000
Subject: [PATCH 15/18] fix parameter validation
Add missing validation for EGL_NATIVE_RENDERABLE to eglChooseConfig.
Fixes dEQP-EGL.functional.negative_api.*
---
src/base/config-list.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/base/config-list.c b/src/base/config-list.c
index ce4095c..19299e7 100644
--- a/src/base/config-list.c
+++ b/src/base/config-list.c
@@ -258,6 +258,14 @@ EplConfig **eplConfigListChooseConfigs(EplPlatformData
*platform, EGLDisplay edp
}
else if (attribs[i] == EGL_NATIVE_RENDERABLE)
{
+ if (attribs[i + 1] != EGL_TRUE && attribs[i + 1] != EGL_FALSE
+ && attribs[i + 1] != EGL_DONT_CARE)
+ {
+ eplSetError(platform, EGL_BAD_ATTRIBUTE,
+ "Invalid value 0x%04x for EGL_NATIVE_RENDERABLE",
attribs[i + 1]);
+ goto done;
+ }
+
nativeRenderable = attribs[i + 1];
}
else if (attribs[i] == EGL_NATIVE_VISUAL_TYPE)
--
2.51.0
++++++ 0016-x11-implement-EGL_BUFFER_AGE_KHR-tracking-for-window.patch ++++++
>From 5da0d37a6171bcd3cffd17874c31f44feadf657c Mon Sep 17 00:00:00 2001
From: Riku Salminen <[email protected]>
Date: Thu, 30 Jul 2026 12:11:25 +0000
Subject: [PATCH 16/18] x11: implement EGL_BUFFER_AGE_KHR tracking for window
surfaces
Add buffer age tracking to the X11 window backend, following the same
pattern as the wayland2 backend.
Each X11ColorBuffer gains a buffer_age field (0 = undefined). After a
successful PresentPixmap and buffer swap, the just-presented buffer's
age is set to 1 and all other non-zero ages are incremented. PRIME
surfaces always return age 0 (no multi-buffer tracking for PRIME).
eplX11QuerySurface now handles EGL_BUFFER_AGE_KHR by returning the
current back buffer's age via the new eplX11GetWindowBufferAge helper.
Fixes dEQP-EGL.functional.partial_update.* (27 tests, all pass)
---
src/x11/x11-platform.c | 12 ++++++++++++
src/x11/x11-platform.h | 8 ++++++++
src/x11/x11-window.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 50 insertions(+)
diff --git a/src/x11/x11-platform.c b/src/x11/x11-platform.c
index 96f39fe..3dab885 100644
--- a/src/x11/x11-platform.c
+++ b/src/x11/x11-platform.c
@@ -1551,6 +1551,18 @@ EplQueryResult eplX11QuerySurface(EplDisplay *pdpy,
EplSurface *psurf, EGLint at
}
return EPL_QUERY_RESULT_SUCCESS;
}
+ else if (attrib == EGL_BUFFER_AGE_KHR)
+ {
+ if (psurf->type == EPL_SURFACE_TYPE_WINDOW)
+ {
+ *ret_value = eplX11GetWindowBufferAge(psurf);
+ }
+ else
+ {
+ *ret_value = 0;
+ }
+ return EPL_QUERY_RESULT_SUCCESS;
+ }
else
{
return EPL_QUERY_RESULT_UNKNOWN;
diff --git a/src/x11/x11-platform.h b/src/x11/x11-platform.h
index 1e510bc..db84c32 100644
--- a/src/x11/x11-platform.h
+++ b/src/x11/x11-platform.h
@@ -453,6 +453,14 @@ void eplX11DestroyPixmap(EplSurface *surf);
EGLBoolean eplX11SwapInterval(EplDisplay *pdpy, EplSurface *psurf, EGLint
interval);
+/**
+ * Returns the EGL_BUFFER_AGE_KHR value for a window surface.
+ *
+ * Returns 0 for PRIME surfaces or if no swap has occurred yet.
+ * Must only be called when the surface is current (enforced by
platform-base.c).
+ */
+EGLint eplX11GetWindowBufferAge(EplSurface *surf);
+
void eplX11DestroyWindow(EplSurface *surf);
EGLBoolean eplX11WaitGLWindow(EplDisplay *pdpy, EplSurface *psurf);
diff --git a/src/x11/x11-window.c b/src/x11/x11-window.c
index ff6ea62..1c490fa 100644
--- a/src/x11/x11-window.c
+++ b/src/x11/x11-window.c
@@ -148,6 +148,14 @@ typedef struct
*/
X11Timeline timeline;
+ /**
+ * The EGL_BUFFER_AGE_KHR value for this buffer.
+ *
+ * 0 means the contents are undefined (buffer was never presented, or
+ * this is a PRIME surface). Updated after each successful PresentPixmap.
+ */
+ EGLint buffer_age;
+
struct glvnd_list entry;
} X11ColorBuffer;
@@ -2280,6 +2288,18 @@ EGLBoolean eplX11SwapBuffers(EplPlatformData *plat,
EplDisplay *pdpy, EplSurface
eplSetError(plat, EGL_BAD_ALLOC, "Driver error: Can't assign new
color buffers");
goto done;
}
+
+ if (!pwin->prime)
+ {
+ X11ColorBuffer *buf;
+ glvnd_list_for_each_entry(buf, &pwin->color_buffers, entry)
+ {
+ if (buf == pwin->current_front)
+ buf->buffer_age = 1;
+ else if (buf->buffer_age != 0)
+ buf->buffer_age++;
+ }
+ }
}
ret = EGL_TRUE;
@@ -2291,6 +2311,16 @@ done:
return ret;
}
+EGLint eplX11GetWindowBufferAge(EplSurface *surf)
+{
+ X11Window *pwin = (X11Window *) surf->priv;
+
+ if (pwin->prime || pwin->current_back == NULL)
+ return 0;
+
+ return pwin->current_back->buffer_age;
+}
+
EGLBoolean eplX11SwapInterval(EplDisplay *pdpy, EplSurface *psurf, EGLint
interval)
{
if (psurf->type == EPL_SURFACE_TYPE_WINDOW)
--
2.51.0
++++++ 0017-base-fix-eglSetDamageRegionKHR-for-non-postable-surf.patch ++++++
>From ec2d477c65d5fe45976aa37a8573fd22656da7f6 Mon Sep 17 00:00:00 2001
From: Riku Salminen <[email protected]>
Date: Fri, 7 Aug 2026 12:05:40 +0000
Subject: [PATCH 17/18] base: fix eglSetDamageRegionKHR for non-postable
surfaces
When eglSetDamageRegionKHR is called on a surface not in the EPL surface
list (e.g. a pbuffer), the previous code either forwarded the call to the
driver (if the driver function pointer was set) or silently returned
EGL_TRUE. The EGL_KHR_partial_update spec requires EGL_BAD_MATCH for
non-postable surfaces.
Initialize egl.SetDamageRegionKHR in eplPlatformBaseAllocate so the
driver function pointer is available. This enables the pass-through path
for postable surfaces not tracked by the EPL, such as EGL stream producer
surfaces created with eglCreateStreamProducerSurfaceKHR.
Fixes dEQP-EGL.functional.negative_partial_update.not_postable_surface
---
src/base/platform-base.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index 1f86ffc..eac69fe 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -148,6 +148,7 @@ EplPlatformData *eplPlatformBaseAllocate(int major, int
minor,
platform->egl.SwapBuffersWithDamage =
driver->getProcAddress("eglSwapBuffersWithDamageEXT");
}
platform->egl.CreateStreamProducerSurfaceKHR =
driver->getProcAddress("CreateStreamProducerSurfaceKHR");
+ platform->egl.SetDamageRegionKHR =
driver->getProcAddress("eglSetDamageRegionKHR");
if (platform->egl.QueryString == NULL
|| platform->egl.QueryString == NULL
--
2.51.0
++++++ 0018-base-fix-eglSwapInterval-to-return-correct-error-wit.patch ++++++
>From c83c2e8829e6eda418a7c876aae70084bfaf42e7 Mon Sep 17 00:00:00 2001
From: Riku Salminen <[email protected]>
Date: Fri, 7 Aug 2026 11:44:47 +0000
Subject: [PATCH 18/18] base: fix eglSwapInterval to return correct error
without current context
When eglSwapInterval is called with no current context, the EPL's
HookSwapInterval returned EGL_BAD_SURFACE because the current display
check fails. Pass through to the driver instead, which now returns
EGL_BAD_CONTEXT via NvEglIntSwapInterval.
Fixes dEQP-EGL.functional.negative_api.swap_interval
---
src/base/platform-base.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/base/platform-base.c b/src/base/platform-base.c
index eac69fe..e4aa714 100644
--- a/src/base/platform-base.c
+++ b/src/base/platform-base.c
@@ -1300,7 +1300,10 @@ static EGLBoolean HookSwapInterval(EGLDisplay edpy,
EGLint interval)
}
else
{
- eplSetError(pdpy->platform, EGL_BAD_SURFACE, "EGLDisplay %p is not
current", edpy);
+ // Current display is not this display (or there is no current
context).
+ // Pass through to the driver, which will return the appropriate error.
+ internal_edpy = pdpy->internal_display;
+ SwapInterval = pdpy->platform->egl.SwapInterval;
}
if (SwapInterval != NULL)
--
2.51.0
++++++ egl-x11-1.0.4.tar.gz -> egl-x11-1.0.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/egl-x11-1.0.4/meson.build
new/egl-x11-1.0.5/meson.build
--- old/egl-x11-1.0.4/meson.build 2025-11-12 17:32:54.000000000 +0100
+++ new/egl-x11-1.0.5/meson.build 2025-12-31 05:59:43.000000000 +0100
@@ -14,7 +14,7 @@
# limitations under the License.
project('egl-x11', 'c',
- version : '1.0.4',
+ version : '1.0.5',
default_options : ['c_std=gnu99'],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/egl-x11-1.0.4/src/x11/x11-pixmap.c
new/egl-x11-1.0.5/src/x11/x11-pixmap.c
--- old/egl-x11-1.0.4/src/x11/x11-pixmap.c 2025-11-12 17:32:54.000000000
+0100
+++ new/egl-x11-1.0.5/src/x11/x11-pixmap.c 2025-12-31 05:59:43.000000000
+0100
@@ -370,6 +370,7 @@
void eplX11DestroyPixmap(EplSurface *surf)
{
X11Pixmap *ppix = (X11Pixmap *) surf->priv;
+
surf->priv = NULL;
if (ppix != NULL)
{
@@ -468,10 +469,10 @@
fmt = eplFormatInfoLookup(configInfo->fourcc);
assert(fmt != NULL);
- internalAttribs = eplX11GetInternalSurfaceAttribs(plat, pdpy,
internalAttribs);
+ internalAttribs = eplX11GetInternalSurfaceAttribs(plat, pdpy,
EPL_SURFACE_TYPE_PIXMAP, attribs);
if (internalAttribs == NULL)
{
- goto done;
+ return EGL_NO_SURFACE;
}
geomCookie = xcb_get_geometry(inst->conn, xpix);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/egl-x11-1.0.4/src/x11/x11-platform.c
new/egl-x11-1.0.5/src/x11/x11-platform.c
--- old/egl-x11-1.0.4/src/x11/x11-platform.c 2025-11-12 17:32:54.000000000
+0100
+++ new/egl-x11-1.0.5/src/x11/x11-platform.c 2025-12-31 05:59:43.000000000
+0100
@@ -79,11 +79,13 @@
static void eplX11DestroySurface(EplDisplay *pdpy, EplSurface *surf);
static void eplX11FreeSurface(EplDisplay *pdpy, EplSurface *surf);
static EGLBoolean eplX11WaitGL(EplDisplay *pdpy, EplSurface *psurf);
+static EGLBoolean eplX11HookQuerySurface(EGLDisplay edpy, EGLSurface esurf,
EGLint attribute, EGLint *value);
static const EplHookFunc X11_HOOK_FUNCTIONS[] =
{
{ "eglChooseConfig", eplX11HookChooseConfig },
{ "eglGetConfigAttrib", eplX11HookGetConfigAttrib },
+ { "eglQuerySurface", eplX11HookQuerySurface },
{ "eglSwapInterval", eplX11SwapInterval },
};
static const int NUM_X11_HOOK_FUNCTIONS = sizeof(X11_HOOK_FUNCTIONS) /
sizeof(X11_HOOK_FUNCTIONS[0]);
@@ -183,6 +185,7 @@
plat->priv->egl.QueryDisplayAttribKHR =
driver->getProcAddress("eglQueryDisplayAttribKHR");
plat->priv->egl.SwapInterval = driver->getProcAddress("eglSwapInterval");
+ plat->priv->egl.QuerySurface = driver->getProcAddress("eglQuerySurface");
plat->priv->egl.QueryDmaBufFormatsEXT =
driver->getProcAddress("eglQueryDmaBufFormatsEXT");
plat->priv->egl.QueryDmaBufModifiersEXT =
driver->getProcAddress("eglQueryDmaBufModifiersEXT");
plat->priv->egl.CreateSync = driver->getProcAddress("eglCreateSync");
@@ -202,6 +205,7 @@
if (plat->priv->egl.QueryDisplayAttribKHR == NULL
|| plat->priv->egl.SwapInterval == NULL
+ || plat->priv->egl.QuerySurface == NULL
|| plat->priv->egl.QueryDmaBufFormatsEXT == NULL
|| plat->priv->egl.QueryDmaBufModifiersEXT == NULL
|| plat->priv->egl.CreateSync == NULL
@@ -705,6 +709,21 @@
}
}
+static EGLBoolean CheckX11Extension(xcb_connection_t *conn, const char *name)
+{
+ xcb_generic_error_t *error = NULL;
+ xcb_query_extension_reply_t *reply = xcb_query_extension_reply(conn,
+ xcb_query_extension(conn, strlen(name), name), &error);
+ EGLBoolean ret = EGL_FALSE;
+ if (reply != NULL)
+ {
+ ret = (reply->present != 0);
+ free(reply);
+ }
+ free(error);
+ return ret;
+}
+
/**
* Checks whether the server has the necessary support that we need.
*
@@ -723,7 +742,6 @@
xcb_dri3_query_version_reply_t *dri3Reply = NULL;
xcb_present_query_version_cookie_t presentCookie;
xcb_present_query_version_reply_t *presentReply = NULL;
- xcb_query_extension_reply_t *nvglxReply = NULL;
EGLBoolean success = EGL_FALSE;
// Check to make sure that we're using a domain socket, since we need to be
@@ -761,17 +779,7 @@
* we could add some requests to NV-GLX to support older (pre DRI3 1.2)
* servers or non-Linux systems.
*/
- const char NVGLX_EXTENSION_NAME[] = "NV-GLX";
- xcb_query_extension_cookie_t extCookie =
xcb_query_extension(inst->conn,
- sizeof(NVGLX_EXTENSION_NAME) - 1, NVGLX_EXTENSION_NAME);
- nvglxReply = xcb_query_extension_reply(inst->conn, extCookie, &error);
- if (nvglxReply == NULL)
- {
- // XQueryExtension isn't supposed to generate any errors.
- goto done;
- }
-
- if (nvglxReply->present)
+ if (CheckX11Extension(inst->conn, "NV-GLX"))
{
goto done;
}
@@ -817,7 +825,6 @@
success = EGL_TRUE;
done:
- free(nvglxReply);
free(presentReply);
free(dri3Reply);
free(error);
@@ -889,6 +896,7 @@
EplInternalDisplay *internalDpy = NULL;
EGLBoolean supportsDirect = EGL_FALSE;
EGLBoolean supportsLinear = EGL_FALSE;
+ const char *env;
inst = calloc(1, sizeof(X11DisplayInstance));
if (inst == NULL)
@@ -1009,7 +1017,15 @@
return NULL;
}
- inst->supports_implicit_sync = EGL_FALSE;
+ /*
+ * The NVIDIA driver does not support implicit sync semantics in OpenGL
+ * and similar. However, if the NVIDIA server-side driver module for
+ * Xorg supports DRI3 1.2, then it will will extract and attach fences
+ * from the dma-buf when it processes a PresentPixmap or CopyArea
+ * request, which is all we actually need in order to use our implicit
+ * sync path.
+ */
+ inst->supports_implicit_sync = CheckX11Extension(inst->conn, "NV-GLX");
}
else
{
@@ -1043,6 +1059,19 @@
inst->supports_implicit_sync = EGL_TRUE;
}
+ env = getenv("__NV_X11_FORCE_IMPLICIT_SYNC");
+ if (env != NULL)
+ {
+ if (strcmp(env, "1") == 0)
+ {
+ inst->supports_implicit_sync = EGL_TRUE;
+ }
+ else if (strcmp(env, "0") == 0)
+ {
+ inst->supports_implicit_sync = EGL_FALSE;
+ }
+ }
+
if (inst->device == EGL_NO_DEVICE_EXT)
{
if (from_init)
@@ -1188,6 +1217,15 @@
}
}
+ if (inst->supports_explicit_sync)
+ {
+ env = getenv("__NV_X11_DISABLE_EXPLICIT_SYNC");
+ if (env != NULL && atoi(env) != 0)
+ {
+ inst->supports_explicit_sync = EGL_FALSE;
+ }
+ }
+
if (inst->force_prime && !inst->supports_prime)
{
if (from_init)
@@ -1311,34 +1349,85 @@
return ret;
}
-EGLAttrib *eplX11GetInternalSurfaceAttribs(EplPlatformData *plat, EplDisplay
*pdpy, const EGLAttrib *attribs)
+EGLAttrib *eplX11GetInternalSurfaceAttribs(EplPlatformData *plat,
+ EplDisplay *pdpy, EplSurfaceType surface_type, const EGLAttrib
*attribs)
{
EGLAttrib *internalAttribs = NULL;
- int count = 0;
+ int count = eplCountAttribs(attribs);
+
+ // Allocate extra space so that we can add EGL_SURFACE_Y_INVERTED_NVX
below.
+ internalAttribs = malloc((count + 3) * sizeof(EGLAttrib));
+ if (internalAttribs == NULL)
+ {
+ eplSetError(plat, EGL_BAD_ALLOC, "Out of memory\n");
+ return NULL;
+ }
+
+ count = 0;
+ internalAttribs[count++] = EGL_SURFACE_Y_INVERTED_NVX;
+ internalAttribs[count++] = EGL_TRUE;
if (attribs != NULL)
{
- for (count = 0; attribs[count] != EGL_NONE; count += 2)
+ int i;
+ for (i=0; attribs[i] != EGL_NONE; i += 2)
{
- if (attribs[count] == EGL_SURFACE_Y_INVERTED_NVX)
+ if (attribs[i] == EGL_SURFACE_Y_INVERTED_NVX)
{
- eplSetError(plat, EGL_BAD_ATTRIBUTE, "Invalid attribute
0x%04x\n", attribs[count]);
+ eplSetError(plat, EGL_BAD_ATTRIBUTE, "Invalid attribute
0x%04x\n", attribs[i]);
+ free(internalAttribs);
return NULL;
}
+ else if (attribs[i] == EGL_RENDER_BUFFER)
+ {
+ /*
+ * eglPlatformCreateSurfaceNVX doesn't accept the
+ * EGL_RENDER_BUFFER attribute, since it's the platform library
+ * that allocates and specifies the front and back buffers, not
+ * the driver.
+ */
+ if (surface_type != EPL_SURFACE_TYPE_WINDOW)
+ {
+ /*
+ * The EGL_RENDER_BUFFER is not valid for pixmaps, since
+ * they're always single-buffered.
+ */
+ eplSetError(plat, EGL_BAD_ATTRIBUTE, "EGL_RENDER_BUFFER is
not valid for pixmaps");
+ free(internalAttribs);
+ return NULL;
+ }
+ else if (attribs[i + 1] == EGL_SINGLE_BUFFER)
+ {
+ /*
+ * We don't currently support single-buffered rendering for
+ * a window, but this attribute is only a hint, so it's not
+ * an error to request it.
+ *
+ * If we do implement EGL_SINGLE_BUFFER for windows in the
+ * future, then we'd do that by passing only a GL_FRONT
+ * buffer to eglPlatformCreateSurfaceNVX, like we do for
+ * pixmaps.
+ */
+ plat->callbacks.debugMessage(EGL_DEBUG_MSG_WARN_KHR,
+ "EGL_SINGLE_BUFFER requested, but single-buffered
rendering is not supported");
+ }
+ else if (attribs[i + 1] != EGL_BACK_BUFFER)
+ {
+ eplSetError(plat, EGL_BAD_ATTRIBUTE,
+ "Invalid EGL_RENDER_BUFFER value 0x%04x",
attribs[i + 1]);
+ free(internalAttribs);
+ return NULL;
+ }
+ }
+ else
+ {
+ internalAttribs[count++] = attribs[i];
+ internalAttribs[count++] = attribs[i + 1];
+ }
}
}
- internalAttribs = malloc((count + 3) * sizeof(EGLAttrib));
- if (internalAttribs == NULL)
- {
- eplSetError(plat, EGL_BAD_ALLOC, "Out of memory\n");
- return NULL;
- }
-
- memcpy(internalAttribs, attribs, count * sizeof(EGLAttrib));
- internalAttribs[count] = EGL_SURFACE_Y_INVERTED_NVX;
- internalAttribs[count + 1] = EGL_TRUE;
- internalAttribs[count + 2] = EGL_NONE;
+ internalAttribs[count] = EGL_NONE;
return internalAttribs;
}
@@ -1461,3 +1550,55 @@
return xid;
}
+
+EGLBoolean eplX11HookQuerySurface(EGLDisplay edpy, EGLSurface esurf, EGLint
attribute, EGLint *value)
+{
+ EplDisplay *pdpy = NULL;
+ EplSurface *psurf = NULL;
+ EGLBoolean ret = EGL_FALSE;
+
+ pdpy = eplDisplayAcquire(edpy);
+ if (pdpy == NULL)
+ {
+ return EGL_FALSE;
+ }
+
+ if (value == NULL)
+ {
+ eplSetError(pdpy->platform, EGL_BAD_ATTRIBUTE, "value pointer must not
be NULL");
+ eplDisplayRelease(pdpy);
+ return EGL_FALSE;
+ }
+
+ psurf = eplSurfaceAcquire(pdpy, esurf);
+ if (psurf != NULL)
+ {
+ if (attribute == EGL_RENDER_BUFFER)
+ {
+ if (psurf->type == EPL_SURFACE_TYPE_WINDOW)
+ {
+ *value = EGL_BACK_BUFFER;
+ }
+ else
+ {
+ *value = EGL_SINGLE_BUFFER;
+ }
+ ret = EGL_TRUE;
+ }
+ else
+ {
+ ret =
pdpy->platform->priv->egl.QuerySurface(pdpy->internal_display,
+ psurf->internal_surface, attribute, value);
+ }
+ eplSurfaceRelease(pdpy, psurf);
+ }
+ else
+ {
+ // If we don't recognize the EGLSurface, then just pass the call
+ // through to the driver.
+ ret = pdpy->platform->priv->egl.QuerySurface(pdpy->internal_display,
esurf, attribute, value);
+ }
+
+ eplDisplayRelease(pdpy);
+ return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/egl-x11-1.0.4/src/x11/x11-platform.h
new/egl-x11-1.0.5/src/x11/x11-platform.h
--- old/egl-x11-1.0.4/src/x11/x11-platform.h 2025-11-12 17:32:54.000000000
+0100
+++ new/egl-x11-1.0.5/src/x11/x11-platform.h 2025-12-31 05:59:43.000000000
+0100
@@ -43,6 +43,11 @@
#include "config-list.h"
#include "refcountobj.h"
+// FreeBSD doesn't have ETIME, so the DRM calls return ETIMEDOUT instead.
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
#ifndef EGL_EXT_platform_xcb
#define EGL_EXT_platform_xcb 1
#define EGL_PLATFORM_XCB_EXT 0x31DC
@@ -73,6 +78,7 @@
{
PFNEGLQUERYDISPLAYATTRIBKHRPROC QueryDisplayAttribKHR;
PFNEGLSWAPINTERVALPROC SwapInterval;
+ PFNEGLQUERYSURFACEPROC QuerySurface;
PFNEGLQUERYDMABUFFORMATSEXTPROC QueryDmaBufFormatsEXT;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC QueryDmaBufModifiersEXT;
PFNEGLCREATESYNCPROC CreateSync;
@@ -429,13 +435,14 @@
*
* \param plat The platform data
* \param pdpy The display data
+ * \param surface_type The type of surface that the attributes are for.
* \param attribs The attribute list that was passed to eglCreateWindowSurface
* or eglCreatePixmapSurface.
* \return The EGLAttrib array to pass to the driver, or NULL on error. The
* caller must free the array using free().
*/
-
-EGLAttrib *eplX11GetInternalSurfaceAttribs(EplPlatformData *plat, EplDisplay
*pdpy, const EGLAttrib *attribs);
+EGLAttrib *eplX11GetInternalSurfaceAttribs(EplPlatformData *plat,
+ EplDisplay *pdpy, EplSurfaceType surface_type, const EGLAttrib
*attribs);
EGLBoolean eplX11HookChooseConfig(EGLDisplay edpy, EGLint const *attribs,
EGLConfig *configs, EGLint configSize, EGLint *numConfig);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/egl-x11-1.0.4/src/x11/x11-window.c
new/egl-x11-1.0.5/src/x11/x11-window.c
--- old/egl-x11-1.0.4/src/x11/x11-window.c 2025-11-12 17:32:54.000000000
+0100
+++ new/egl-x11-1.0.5/src/x11/x11-window.c 2025-12-31 05:59:43.000000000
+0100
@@ -340,15 +340,14 @@
static X11ColorBuffer *AllocOneColorBuffer(X11DisplayInstance *inst,
const EplFormatInfo *fmt, uint32_t width, uint32_t height,
const uint64_t *modifiers, int num_modifiers,
- EGLBoolean scanout)
+ EGLBoolean prime)
{
- int fd = -1;
uint32_t flags = 0;
X11ColorBuffer *buffer = NULL;
assert(num_modifiers > 0);
- if (scanout)
+ if (!prime)
{
flags |= GBM_BO_USE_SCANOUT;
}
@@ -370,14 +369,14 @@
goto done;
}
- fd = gbm_bo_get_fd(buffer->gbo);
- if (fd < 0)
+ buffer->fd = gbm_bo_get_fd(buffer->gbo);
+ if (buffer->fd < 0)
{
goto done;
}
buffer->buffer =
inst->platform->priv->egl.PlatformImportColorBufferNVX(inst->internal_display->edpy,
- fd, width, height, gbm_bo_get_format(buffer->gbo),
+ buffer->fd, width, height, gbm_bo_get_format(buffer->gbo),
gbm_bo_get_stride(buffer->gbo),
gbm_bo_get_offset(buffer->gbo, 0),
gbm_bo_get_modifier(buffer->gbo));
@@ -386,11 +385,15 @@
goto done;
}
-done:
- if (fd >= 0)
+ if (prime || !inst->supports_implicit_sync)
{
- close(fd);
+ // We only need to hold on to a file descriptor for a shared dma-buf,
+ // and only if we're using implicit sync.
+ close(buffer->fd);
+ buffer->fd = -1;
}
+
+done:
if (buffer->buffer == NULL)
{
FreeColorBuffer(inst, buffer);
@@ -497,7 +500,7 @@
EGLBoolean success = EGL_TRUE;
front = AllocOneColorBuffer(pwin->inst, pwin->format->fmt,
pwin->pending_width, pwin->pending_height,
- modifiers, num_modifiers, !prime);
+ modifiers, num_modifiers, prime);
if (front == NULL)
{
goto done;
@@ -508,7 +511,7 @@
modifier = gbm_bo_get_modifier(front->gbo);
back = AllocOneColorBuffer(pwin->inst, pwin->format->fmt,
pwin->pending_width, pwin->pending_height,
- &modifier, 1, !prime);
+ &modifier, 1, prime);
if (back == NULL)
{
goto done;
@@ -732,6 +735,11 @@
{
X11Window *pwin = (X11Window *) surf->priv;
+ if (pwin == NULL)
+ {
+ return;
+ }
+
FreeWindowBuffers(surf);
if (pwin->inst->conn != NULL && pwin->present_event != NULL)
@@ -1308,10 +1316,10 @@
return EGL_NO_SURFACE;
}
- internalAttribs = eplX11GetInternalSurfaceAttribs(plat, pdpy,
internalAttribs);
+ internalAttribs = eplX11GetInternalSurfaceAttribs(plat, pdpy,
EPL_SURFACE_TYPE_WINDOW, attribs);
if (internalAttribs == NULL)
{
- goto done;
+ return EGL_NO_SURFACE;
}
fmt = eplX11FindDriverFormat(inst, configInfo->fourcc);
@@ -1780,6 +1788,7 @@
{
if (buffer != skip && buffer->status == BUFFER_STATUS_IDLE_NOTIFIED)
{
+ assert(buffer->fd >= 0);
buffers[count] = buffer;
fds[count].fd = buffer->fd;
fds[count].events = POLLOUT;
@@ -1818,7 +1827,7 @@
}
return count;
}
- else if (ret == 0 || err == ETIME || err == EINTR)
+ else if (ret == 0 || err == EINTR)
{
// Nothing freed up before the timeout, but that's not a fatal error
// here.
@@ -2102,7 +2111,7 @@
else
{
buffer = AllocOneColorBuffer(pwin->inst, pwin->format->fmt,
pwin->width, pwin->height,
- &pwin->modifier, 1, !pwin->prime);
+ &pwin->modifier, 1, pwin->prime);
}
if (buffer == NULL)
{