Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libnvidia-egl-wayland for 
openSUSE:Factory checked in at 2024-07-24 15:32:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libnvidia-egl-wayland (Old)
 and      /work/SRC/openSUSE:Factory/.libnvidia-egl-wayland.new.1869 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libnvidia-egl-wayland"

Wed Jul 24 15:32:43 2024 rev:10 rq:1188743 version:1.1.14

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/libnvidia-egl-wayland/libnvidia-egl-wayland.changes  
    2023-11-14 21:41:40.869618413 +0100
+++ 
/work/SRC/openSUSE:Factory/.libnvidia-egl-wayland.new.1869/libnvidia-egl-wayland.changes
    2024-07-25 11:55:57.630505311 +0200
@@ -1,0 +2,11 @@
+Fri Jul 19 23:00:40 UTC 2024 - RN <r_ni...@proton.me>
+
+- update to version 1.1.14:
+  * Implement Explicit Sync (linux-drm-syncobj-v1)
+  * Fix freezing on KDE when explicit sync is enabled under certain 
+    conditions
+  * Read compositor device from zwp_linux_dmabuf_v1 when available
+  * Properly validate and use the passed value of 
+    EGL_EXT_present_opaque
+
+-------------------------------------------------------------------

Old:
----
  egl-wayland-1.1.13.tar.gz

New:
----
  egl-wayland-1.1.14.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libnvidia-egl-wayland.spec ++++++
--- /var/tmp/diff_new_pack.yUvQFv/_old  2024-07-25 11:55:58.946558420 +0200
+++ /var/tmp/diff_new_pack.yUvQFv/_new  2024-07-25 11:55:58.962559066 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package libnvidia-egl-wayland
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %define lname libnvidia-egl-wayland%{so_ver}
 %define rname egl-wayland
 Name:           libnvidia-egl-wayland
-Version:        1.1.13
+Version:        1.1.14
 Release:        0
 Summary:        The EGLStream-based Wayland external platform
 License:        MIT

++++++ egl-wayland-1.1.13.tar.gz -> egl-wayland-1.1.14.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/Makefile.am 
new/egl-wayland-1.1.14/Makefile.am
--- old/egl-wayland-1.1.13/Makefile.am  2023-10-18 20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/Makefile.am  2024-07-17 20:13:07.000000000 +0200
@@ -24,6 +24,7 @@
 libnvidia_egl_wayland_la_LDFLAGS =                                             
                                           \
     -shared                                                                    
                                           \
     -Wl,-Bsymbolic                                                             
                                           \
+    -ldl                                                                       
                                           \
     $(WAYLAND_LIBS)                                                            
                                           \
     $(LIBDRM_LIBS)                                                             
                                           \
     -version-number 
$(WAYLAND_EXTERNAL_MAJOR_VERSION):$(WAYLAND_EXTERNAL_MINOR_VERSION):$(WAYLAND_EXTERNAL_MICRO_VERSION)
 \
@@ -79,6 +80,12 @@
 libnvidia_egl_wayland_la_dmabuf_built_private_protocols =     \
     linux-dmabuf-unstable-v1-protocol.c
 
+libnvidia_egl_wayland_la_drm_syncobj_built_client_headers =       \
+    linux-drm-syncobj-v1-client-protocol.h
+
+libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols =    \
+    linux-drm-syncobj-v1-protocol.c
+
 libnvidia_egl_wayland_la_presentation_time_built_client_headers = \
     presentation-time-client-protocol.h
 
@@ -92,6 +99,8 @@
     $(libnvidia_egl_wayland_la_built_server_headers)                   \
     $(libnvidia_egl_wayland_la_dmabuf_built_client_headers)            \
     $(libnvidia_egl_wayland_la_dmabuf_built_private_protocols)         \
+    $(libnvidia_egl_wayland_la_drm_syncobj_built_client_headers)       \
+    $(libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols)    \
     $(libnvidia_egl_wayland_la_presentation_time_built_client_headers) \
     $(libnvidia_egl_wayland_la_presentation_time_private_protocols)
 
@@ -128,6 +137,12 @@
 $(libnvidia_egl_wayland_la_dmabuf_built_client_headers):%-client-protocol.h : 
$(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/%.xml
        $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
 
+$(libnvidia_egl_wayland_la_drm_syncobj_built_private_protocols):%-protocol.c : 
$(WAYLAND_PROTOCOLS_DATADIR)/staging/linux-drm-syncobj/%.xml
+       $(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@
+
+$(libnvidia_egl_wayland_la_drm_syncobj_built_client_headers):%-client-protocol.h
 : $(WAYLAND_PROTOCOLS_DATADIR)/staging/linux-drm-syncobj/%.xml
+       $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
 $(libnvidia_egl_wayland_la_presentation_time_private_protocols):%-protocol.c : 
$(WAYLAND_PROTOCOLS_DATADIR)/stable/presentation-time/%.xml
        $(AM_V_GEN)$(WAYLAND_SCANNER) $(WAYLAND_PRIVATE_CODEGEN) < $< > $@
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/configure.ac 
new/egl-wayland-1.1.14/configure.ac
--- old/egl-wayland-1.1.13/configure.ac 2023-10-18 20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/configure.ac 2024-07-17 20:13:07.000000000 +0200
@@ -2,7 +2,7 @@
 
 m4_define([wayland_eglstream_major_version], [1])
 m4_define([wayland_eglstream_minor_version], [1])
-m4_define([wayland_eglstream_micro_version], [13])
+m4_define([wayland_eglstream_micro_version], [14])
 m4_define([wayland_eglstream_version],
           
[wayland_eglstream_major_version.wayland_eglstream_minor_version.wayland_eglstream_micro_version])
 
@@ -15,6 +15,8 @@
 AC_CONFIG_SRCDIR([config.h.in])
 AC_CONFIG_HEADERS([config.h])
 
+AC_GNU_SOURCE
+
 AC_SUBST([WAYLAND_EXTERNAL_MAJOR_VERSION], [wayland_eglstream_major_version])
 AC_SUBST([WAYLAND_EXTERNAL_MINOR_VERSION], [wayland_eglstream_minor_version])
 AC_SUBST([WAYLAND_EXTERNAL_MICRO_VERSION], [wayland_eglstream_micro_version])
@@ -61,6 +63,9 @@
 
 # Checks for libraries.
 AX_PTHREAD()
+AC_CHECK_LIB([dl], [dlsym],
+             [],
+             [AC_MSG_ERROR("dlsym is needed to compile wayland-egldisplay")])
 PKG_CHECK_MODULES([EGL_EXTERNAL_PLATFORM], [eglexternalplatform >= 
${EGL_EXTERNAL_PLATFORM_MIN_VERSION} eglexternalplatform < 
${EGL_EXTERNAL_PLATFORM_MAX_VERSION}])
 PKG_CHECK_MODULES([WAYLAND], [wayland-server wayland-client 
wayland-egl-backend >= 3])
 PKG_CHECK_MODULES([LIBDRM], [libdrm])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/include/wayland-egldisplay.h 
new/egl-wayland-1.1.14/include/wayland-egldisplay.h
--- old/egl-wayland-1.1.13/include/wayland-egldisplay.h 2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/include/wayland-egldisplay.h 2024-07-17 
20:13:07.000000000 +0200
@@ -121,6 +121,9 @@
 typedef struct WlEglDisplayRec {
     WlEglDeviceDpy *devDpy;
 
+    /* Supports EGL_ANDROID_native_fence_sync */
+    int supports_native_fence_sync;
+
     EGLBoolean         ownNativeDpy;
     struct wl_display *nativeDpy;
 
@@ -128,6 +131,7 @@
     struct wl_eglstream_display    *wlStreamDpy;
     struct wl_eglstream_controller *wlStreamCtl;
     struct zwp_linux_dmabuf_v1     *wlDmaBuf;
+    struct wp_linux_drm_syncobj_manager_v1 *wlDrmSyncobj;
     unsigned int                    wlStreamCtlVer;
     struct wp_presentation         *wpPresentation;
     struct wl_event_queue          *wlEventQueue;
@@ -139,6 +143,9 @@
 
     WlEglPlatformData *data;
 
+    /* DRM device in use */
+    int drmFd;
+
     EGLBoolean useInitRefCount;
     EGLDeviceEXT requestedDevice;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/include/wayland-eglhandle.h 
new/egl-wayland-1.1.14/include/wayland-eglhandle.h
--- old/egl-wayland-1.1.13/include/wayland-eglhandle.h  2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/include/wayland-eglhandle.h  2024-07-17 
20:13:07.000000000 +0200
@@ -108,7 +108,9 @@
         PFNEGLCLIENTWAITSYNCKHRPROC                 clientWaitSync;
         PFNEGLSIGNALSYNCKHRPROC                     signalSync;
         PFNEGLDESTROYSYNCKHRPROC                    destroySync;
+        PFNEGLCREATESYNCKHRPROC                     createSync;
         PFNEGLSTREAMFLUSHNVPROC                     streamFlush;
+        PFNEGLDUPNATIVEFENCEFDANDROIDPROC           dupNativeFenceFD;
 
         /* Used for dma-buf surfaces */
         PFNEGLSTREAMIMAGECONSUMERCONNECTNVPROC      streamImageConsumerConnect;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/egl-wayland-1.1.13/include/wayland-eglsurface-internal.h 
new/egl-wayland-1.1.14/include/wayland-eglsurface-internal.h
--- old/egl-wayland-1.1.13/include/wayland-eglsurface-internal.h        
2023-10-18 20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/include/wayland-eglsurface-internal.h        
2024-07-17 20:13:07.000000000 +0200
@@ -51,6 +51,14 @@
     struct wl_buffer       *buffer;
     EGLBoolean              attached;
     struct wl_list          acquiredLink;
+
+    struct wp_linux_drm_syncobj_timeline_v1 *wlReleaseTimeline;
+    uint32_t                drmSyncobjHandle;
+    int                     releasePending;
+    /* Latest release point the compositor will signal with explicit sync */
+    uint64_t                releasePoint;
+    /* Cached acquire EGLSync from acquireImage */
+    EGLSyncKHR              acquireSync;
 } WlEglStreamImage;
 
 typedef struct WlEglSurfaceCtxRec {
@@ -151,6 +159,13 @@
     EGLBoolean isResized;
 
     WlEglDmaBufFeedback feedback;
+
+    /* per-surface Explicit Sync objects */
+    struct wp_linux_drm_syncobj_surface_v1 *wlSyncobjSurf;
+    struct wp_linux_drm_syncobj_timeline_v1 *wlAcquireTimeline;
+    uint32_t drmSyncobjHandle;
+    /* Last acquire point used. This starts at 1, zero means invalid.  */
+    uint64_t syncPoint;
 };
 
 void wlEglReallocSurface(WlEglDisplay *display,
@@ -185,6 +200,9 @@
                                         EGLint attribute,
                                         int *value);
 
+EGLBoolean
+wlEglSurfaceCheckReleasePoints(WlEglDisplay *display, WlEglSurface *surface);
+
 EGLBoolean wlEglSendDamageEvent(WlEglSurface *surface,
                                 struct wl_event_queue *queue);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/egl-wayland-1.1.13/include/wayland-external-exports.h 
new/egl-wayland-1.1.14/include/wayland-external-exports.h
--- old/egl-wayland-1.1.13/include/wayland-external-exports.h   2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/include/wayland-external-exports.h   2024-07-17 
20:13:07.000000000 +0200
@@ -53,7 +53,7 @@
  #define WAYLAND_EXTERNAL_VERSION_MINOR                      0
 #endif
 
-#define WAYLAND_EXTERNAL_VERSION_MICRO                       13
+#define WAYLAND_EXTERNAL_VERSION_MICRO                       14
 
 
 #define EGL_EXTERNAL_PLATFORM_VERSION_MAJOR WAYLAND_EXTERNAL_VERSION_MAJOR
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/meson.build 
new/egl-wayland-1.1.14/meson.build
--- old/egl-wayland-1.1.13/meson.build  2023-10-18 20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/meson.build  2024-07-17 20:13:07.000000000 +0200
@@ -1,5 +1,5 @@
 project('wayland-eglstream', 'c',
-        version : '1.1.13',
+        version : '1.1.14',
         default_options : [
           'buildtype=debugoptimized',
           'c_std=gnu99',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/meson.build 
new/egl-wayland-1.1.14/src/meson.build
--- old/egl-wayland-1.1.13/src/meson.build      2023-10-18 20:00:18.000000000 
+0200
+++ new/egl-wayland-1.1.14/src/meson.build      2024-07-17 20:13:07.000000000 
+0200
@@ -1,7 +1,14 @@
+if not cc.has_function('dlsym')
+    libdl = cc.find_library('dl')
+else
+    libdl = []
+endif
+
 add_project_arguments('-Wall', language : 'c')
 add_project_arguments('-Werror', language : 'c')
 add_project_arguments('-fvisibility=hidden', language : 'c')
 add_project_arguments('-DWL_HIDE_DEPRECATED', language : 'c')
+add_project_arguments('-D_GNU_SOURCE', language : 'c')
 add_project_link_arguments('-Wl,-Bsymbolic', language : 'c')
 
 if cc.has_argument('-Wpedantic')
@@ -13,6 +20,7 @@
 wl_protos_dir = wl_protos.get_pkgconfig_variable('pkgdatadir')
 wl_dmabuf_xml = join_paths(wl_protos_dir, 'unstable', 'linux-dmabuf', 
'linux-dmabuf-unstable-v1.xml')
 wp_presentation_time_xml = join_paths(wl_protos_dir, 'stable', 
'presentation-time', 'presentation-time.xml')
+wl_drm_syncobj_xml = join_paths(wl_protos_dir, 'staging', 'linux-drm-syncobj', 
'linux-drm-syncobj-v1.xml')
 
 client_header = generator(prog_scanner,
     output : '@BASENAME@-client-protocol.h',
@@ -59,6 +67,9 @@
 src += client_header.process(wp_presentation_time_xml)
 src += code.process(wp_presentation_time_xml)
 
+src += client_header.process(wl_drm_syncobj_xml)
+src += code.process(wl_drm_syncobj_xml)
+
 egl_wayland = library('nvidia-egl-wayland',
     src,
     dependencies : [
@@ -68,6 +79,7 @@
         wayland_egl_backend,
         threads,
         libdrm,
+        libdl,
     ],
     include_directories : inc,
     version : meson.project_version(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/wayland-egldisplay.c 
new/egl-wayland-1.1.14/src/wayland-egldisplay.c
--- old/egl-wayland-1.1.13/src/wayland-egldisplay.c     2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/src/wayland-egldisplay.c     2024-07-17 
20:13:07.000000000 +0200
@@ -32,6 +32,7 @@
 #include "wayland-drm-client-protocol.h"
 #include "wayland-drm.h"
 #include "presentation-time-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
 #include <string.h>
 #include <stdlib.h>
 #include <assert.h>
@@ -39,18 +40,24 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <xf86drm.h>
+#include <dlfcn.h>
 
 typedef struct WlServerProtocolsRec {
     EGLBoolean hasEglStream;
     EGLBoolean hasDmaBuf;
-    EGLBoolean hasDrm;
-    struct wl_drm *wldrm;
+    struct zwp_linux_dmabuf_v1 *wlDmaBuf;
+    dev_t devId;
+
+    struct wl_drm *wlDrm;
     char *drm_name;
 } WlServerProtocols;
 
 /* TODO: Make global display lists hang off platform data */
 static struct wl_list wlEglDisplayList = 
WL_LIST_INITIALIZER(&wlEglDisplayList);
 
+static bool getDeviceFromDevIdInitialised = false;
+static int (*getDeviceFromDevId)(dev_t dev_id, uint32_t flags, drmDevice 
**device) = NULL;
+
 EGLBoolean wlEglIsWaylandDisplay(void *nativeDpy)
 {
     if (!wlEglMemoryIsReadable(nativeDpy, sizeof (void *))) {
@@ -424,12 +431,12 @@
         display->wlStreamDpy = wl_registry_bind(registry,
                                                 name,
                                                 
&wl_eglstream_display_interface,
-                                                version);
+                                                1);
     } else if (strcmp(interface, "wl_eglstream_controller") == 0) {
         display->wlStreamCtl = wl_registry_bind(registry,
                                                 name,
                                                 
&wl_eglstream_controller_interface,
-                                                version);
+                                                version > 1 ? 2 : 1);
         display->wlStreamCtlVer = version;
     } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
         /*
@@ -448,6 +455,12 @@
                                                    name,
                                                    &wp_presentation_interface,
                                                    version);
+    } else if (strcmp(interface, "wp_linux_drm_syncobj_manager_v1") == 0 &&
+               display->supports_native_fence_sync) {
+        display->wlDrmSyncobj = wl_registry_bind(registry,
+                                                 name,
+                                                 
&wp_linux_drm_syncobj_manager_v1_interface,
+                                                 1);
     }
 }
 
@@ -501,6 +514,95 @@
 
 
 static void
+dmabuf_feedback_check_main_device(void *data,
+                            struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback,
+                            struct wl_array *dev)
+{
+    WlServerProtocols *protocols = (WlServerProtocols *)data;
+    (void) dmabuf_feedback;
+
+    assert(dev->size == sizeof(dev_t));
+    memcpy(&protocols->devId, dev->data, sizeof(dev_t));
+}
+
+static void
+dmabuf_feedback_check_tranche_target_device(void *data,
+                                      struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback,
+                                      struct wl_array *dev)
+{
+    (void) data;
+    (void) dmabuf_feedback;
+    (void) dev;
+}
+
+static void
+dmabuf_feedback_check_tranche_flags(void *data,
+                              struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback,
+                              uint32_t flags)
+{
+    (void) data;
+    (void) dmabuf_feedback;
+    (void) flags;
+}
+
+static void
+dmabuf_feedback_check_tranche_formats(void *data,
+                                struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback,
+                                struct wl_array *indices)
+{
+    (void) data;
+    (void) dmabuf_feedback;
+    (void) indices;
+}
+
+static void
+dmabuf_feedback_check_tranche_done(void *data,
+                             struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback)
+{
+    (void) data;
+    (void) dmabuf_feedback;
+}
+
+static void
+dmabuf_feedback_check_done(void *data, struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback)
+{
+    WlServerProtocols *protocols = (WlServerProtocols *)data;
+    (void) dmabuf_feedback;
+
+    drmDevice *drm_device;
+    assert(getDeviceFromDevId);
+    if (getDeviceFromDevId(protocols->devId, 0, &drm_device) == 0) {
+        if (drm_device->available_nodes & (1 << DRM_NODE_RENDER)) {
+            protocols->drm_name = strdup(drm_device->nodes[DRM_NODE_RENDER]);
+        }
+
+        drmFreeDevice(&drm_device);
+    }
+}
+
+static void
+dmabuf_feedback_check_format_table(void *data,
+                             struct zwp_linux_dmabuf_feedback_v1 
*dmabuf_feedback,
+                             int32_t fd, uint32_t size)
+{
+    (void) data;
+    (void) dmabuf_feedback;
+    (void) fd;
+    (void) size;
+}
+
+static const struct zwp_linux_dmabuf_feedback_v1_listener 
dmabuf_feedback_check_listener = {
+        .done = dmabuf_feedback_check_done,
+        .format_table = dmabuf_feedback_check_format_table,
+        .main_device = dmabuf_feedback_check_main_device,
+        .tranche_done = dmabuf_feedback_check_tranche_done,
+        .tranche_target_device = dmabuf_feedback_check_tranche_target_device,
+        .tranche_formats = dmabuf_feedback_check_tranche_formats,
+        .tranche_flags = dmabuf_feedback_check_tranche_flags,
+};
+
+
+static void
 registry_handle_global_check_protocols(
                        void *data,
                        struct wl_registry *registry,
@@ -520,12 +622,14 @@
     if ((strcmp(interface, "zwp_linux_dmabuf_v1") == 0) &&
         (version >= 3)) {
         protocols->hasDmaBuf = EGL_TRUE;
+        /* Version 4 introduced default_feedback which allows us to determine 
the device used by the compositor */
+        if (version >= 4) {
+            protocols->wlDmaBuf = wl_registry_bind(registry, name, 
&zwp_linux_dmabuf_v1_interface, 4);
+        }
     }
 
     if ((strcmp(interface, "wl_drm") == 0) && (version >= 2)) {
-        protocols->hasDrm = EGL_TRUE;
-        protocols->wldrm = wl_registry_bind(registry, name, &wl_drm_interface, 
2);
-        wl_drm_add_listener(protocols->wldrm, &drmListener, protocols);
+        protocols->wlDrm = wl_registry_bind(registry, name, &wl_drm_interface, 
2);
     }
 }
 
@@ -640,6 +744,10 @@
             wp_presentation_destroy(display->wpPresentation);
             display->wpPresentation = NULL;
         }
+        if (display->wlDrmSyncobj) {
+            wp_linux_drm_syncobj_manager_v1_destroy(display->wlDrmSyncobj);
+            display->wlDrmSyncobj = NULL;
+        }
         if (display->wlDmaBuf) {
             zwp_linux_dmabuf_v1_destroy(display->wlDmaBuf);
             display->wlDmaBuf = NULL;
@@ -670,48 +778,79 @@
     return res;
 }
 
-static void getServerProtocolsInfo(struct wl_display *nativeDpy,
+static bool getServerProtocolsInfo(struct wl_display *nativeDpy,
                                    WlServerProtocols *protocols)
 {
     struct wl_display     *wrapper      = NULL;
     struct wl_registry    *wlRegistry   = NULL;
     struct wl_event_queue *queue        = wl_display_create_queue(nativeDpy);
     int                    ret          = 0;
+    bool                   result       = false;
     const struct wl_registry_listener registryListener = {
         registry_handle_global_check_protocols,
         registry_handle_global_remove
     };
 
     if (queue == NULL) {
-        return;
+        goto done;
     }
 
     wrapper = wl_proxy_create_wrapper(nativeDpy);
+    if (wrapper == NULL) {
+        goto done;
+    }
     wl_proxy_set_queue((struct wl_proxy *)wrapper, queue);
 
     /* Listen to wl_registry events and make a roundtrip in order to find the
      * wl_eglstream_display global object.
      */
     wlRegistry = wl_display_get_registry(wrapper);
-    wl_proxy_wrapper_destroy(wrapper); /* Done with wrapper */
+    if (wlRegistry == NULL) {
+        goto done;
+    }
     ret = wl_registry_add_listener(wlRegistry,
                                    &registryListener,
                                    protocols);
     if (ret == 0) {
         wl_display_roundtrip_queue(nativeDpy, queue);
-        if (protocols->hasDrm) {
+        if (!getDeviceFromDevIdInitialised) {
+            getDeviceFromDevId = dlsym(RTLD_DEFAULT, "drmGetDeviceFromDevId");
+            getDeviceFromDevIdInitialised = true;
+        }
+
+        if (protocols->wlDmaBuf && getDeviceFromDevId) {
+            struct zwp_linux_dmabuf_feedback_v1 *default_feedback
+                    = 
zwp_linux_dmabuf_v1_get_default_feedback(protocols->wlDmaBuf);
+            if (default_feedback) {
+                zwp_linux_dmabuf_feedback_v1_add_listener(default_feedback, 
&dmabuf_feedback_check_listener, protocols);
+                wl_display_roundtrip_queue(nativeDpy, queue);
+                zwp_linux_dmabuf_feedback_v1_destroy(default_feedback);
+            }
+        } else if (protocols->wlDrm) {
+            wl_drm_add_listener(protocols->wlDrm, &drmListener, protocols);
             wl_display_roundtrip_queue(nativeDpy, queue);
-            /* destroy our wl_drm object */
-            wl_drm_destroy(protocols->wldrm);
+        }
+        result = protocols->drm_name != NULL;
+
+        if (protocols->wlDmaBuf) {
+            zwp_linux_dmabuf_v1_destroy(protocols->wlDmaBuf);
+        }
+        if (protocols->wlDrm) {
+            wl_drm_destroy(protocols->wlDrm);
         }
     }
 
+done:
+    if (wrapper) {
+        wl_proxy_wrapper_destroy(wrapper);
+    }
     if (wlRegistry) {
         wl_registry_destroy(wlRegistry);
     }
     if (queue) {
         wl_event_queue_destroy(queue);
     }
+    return result;
 }
 
 static EGLBoolean checkNvidiaDrmDevice(WlServerProtocols *protocols)
@@ -797,6 +936,7 @@
     EGLDeviceEXT requestedDevice = EGL_NO_DEVICE_EXT;
     EGLBoolean usePrimeRenderOffload = EGL_FALSE;
     EGLBoolean isServerNV;
+    const char *drmName = NULL;
 
     if (platform != EGL_PLATFORM_WAYLAND_EXT) {
         wlEglSetError(data, EGL_BAD_PARAMETER);
@@ -879,7 +1019,10 @@
      * and bind to wl_drm to get the device name.
      * protocols.drm_name will be allocated here if using wl_drm
      */
-    getServerProtocolsInfo(display->nativeDpy, &protocols);
+    if (!getServerProtocolsInfo(display->nativeDpy, &protocols)) {
+        err = EGL_BAD_ALLOC;
+        goto fail;
+    }
 
     // Check if the server is running on an NVIDIA device. This will also make
     // sure that the device node that we're looking at is a render node,
@@ -898,7 +1041,7 @@
         }
     }
 
-    if (!protocols.hasDrm || (!protocols.hasEglStream && 
!protocols.hasDmaBuf)) {
+    if (!protocols.hasEglStream && !protocols.hasDmaBuf) {
         goto fail;
     }
 
@@ -1024,7 +1167,6 @@
         display->primeRenderOffload = EGL_TRUE;
     }
 
-
     display->devDpy = wlGetInternalDisplay(pData, eglDevice);
     if (display->devDpy == NULL) {
         goto fail;
@@ -1036,6 +1178,17 @@
     display->refCount = 1;
     WL_LIST_INIT(&display->wlEglSurfaceList);
 
+    /* Get the DRM device in use */
+    drmName = display->data->egl.queryDeviceString(display->devDpy->eglDevice,
+                                                   EGL_DRM_DEVICE_FILE_EXT);
+    if (!drmName) {
+        goto fail;
+    }
+
+    display->drmFd = open(drmName, O_RDWR | O_CLOEXEC);
+    if (display->drmFd < 0) {
+        goto fail;
+    }
 
     // The newly created WlEglDisplay has been set up properly, insert it
     // in wlEglDisplayList.
@@ -1054,7 +1207,7 @@
     free(eglDeviceList);
     free(protocols.drm_name);
 
-    if (display->ownNativeDpy) {
+    if (display && display->ownNativeDpy) {
         wl_display_disconnect(display->nativeDpy);
     }
     free(display);
@@ -1073,6 +1226,7 @@
     struct wl_display *wrapper = NULL;
     EGLint             err     = EGL_SUCCESS;
     int                ret     = 0;
+    const char *dev_exts = NULL;
 
     if (!display) {
         return EGL_FALSE;
@@ -1103,6 +1257,11 @@
         return EGL_FALSE;
     }
 
+    dev_exts = display->data->egl.queryString(display->devDpy->eglDisplay, 
EGL_EXTENSIONS);
+    if (dev_exts && wlEglFindExtension("EGL_ANDROID_native_fence_sync", 
dev_exts)) {
+        display->supports_native_fence_sync = true;
+    }
+
     // Set the initCount to 1. If something goes wrong, then terminateDisplay
     // will clean up and set it back to zero.
     display->initCount = 1;
@@ -1221,6 +1380,7 @@
 static void wlEglUnrefDisplay(WlEglDisplay *display) {
     if (--display->refCount == 0) {
         wlEglMutexDestroy(&display->mutex);
+        close(display->drmFd);
         free(display);
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/wayland-eglhandle.c 
new/egl-wayland-1.1.14/src/wayland-eglhandle.c
--- old/egl-wayland-1.1.13/src/wayland-eglhandle.c      2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/src/wayland-eglhandle.c      2024-07-17 
20:13:07.000000000 +0200
@@ -111,6 +111,8 @@
     GET_PROC(clientWaitSync,              eglClientWaitSyncKHR);
     GET_PROC(signalSync,                  eglSignalSyncKHR);
     GET_PROC(destroySync,                 eglDestroySyncKHR);
+    GET_PROC(createSync,                  eglCreateSyncKHR);
+    GET_PROC(dupNativeFenceFD,            eglDupNativeFenceFDANDROID);
 
     /* Stream flush */
     GET_PROC(streamFlush,                 eglStreamFlushNV);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/wayland-eglsurface.c 
new/egl-wayland-1.1.14/src/wayland-eglsurface.c
--- old/egl-wayland-1.1.13/src/wayland-eglsurface.c     2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/src/wayland-eglsurface.c     2024-07-17 
20:13:07.000000000 +0200
@@ -24,6 +24,7 @@
 #include "wayland-eglstream-client-protocol.h"
 #include "wayland-eglstream-controller-client-protocol.h"
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
 #include "wayland-eglstream-server.h"
 #include "wayland-thread.h"
 #include "wayland-eglutils.h"
@@ -42,6 +43,8 @@
 #include <errno.h>
 #include <libdrm/drm_fourcc.h>
 #include <sys/stat.h>
+#include <xf86drm.h>
+#include <stdio.h>
 
 #define WL_EGL_WINDOW_DESTROY_CALLBACK_SINCE 3
 
@@ -154,6 +157,89 @@
     return EGL_SUCCESS;
 }
 
+static bool
+syncobj_import_fd_to_current_point(WlEglDisplay *display, WlEglSurface 
*surface,
+                                   int syncFd)
+{
+    bool                ret = false;
+    uint32_t            tmpSyncobj;
+
+    /* Import our syncfd at a new release point */
+    if (drmSyncobjCreate(display->drmFd, 0, &tmpSyncobj) != 0) {
+        return false;
+    }
+
+    if (drmSyncobjImportSyncFile(display->drmFd, tmpSyncobj, syncFd) != 0) {
+        goto end;
+    }
+
+    if (drmSyncobjTransfer(display->drmFd, surface->drmSyncobjHandle,
+                           surface->syncPoint, tmpSyncobj, 0, 0) != 0) {
+        goto end;
+    }
+
+    ret = true;
+
+end:
+    drmSyncobjDestroy(display->drmFd, tmpSyncobj);
+
+    return ret;
+}
+
+static bool
+send_explicit_sync_points (WlEglDisplay *display, WlEglSurface *surface,
+                           WlEglStreamImage *image)
+{
+    WlEglPlatformData  *data        = display->data;
+    EGLDisplay          dpy         = display->devDpy->eglDisplay;
+    int                 syncFd, err;
+    uint64_t            acquireSyncPoint;
+
+    /* Ignore this unless we are using Explicit Sync */
+    if (!surface->wlSyncobjSurf) {
+        return true;
+    }
+
+    /* --------------- Get acquire sync fd -------------- */
+    syncFd = data->egl.dupNativeFenceFD(dpy, image->acquireSync);
+    if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        return false;
+    }
+
+    /* Clean up our acquire sync object now that we are done with it */
+    data->egl.destroySync(dpy, image->acquireSync);
+    image->acquireSync = EGL_NO_SYNC_KHR;
+
+    err = syncobj_import_fd_to_current_point(display, surface, syncFd);
+    close(syncFd);
+    if (!err) {
+        return false;
+    }
+    acquireSyncPoint = surface->syncPoint++;
+
+    /* --------------- Get release EGLSyncKHR -------------- */
+
+    /* Increment to a new sync point here in the image. */
+    image->releasePoint++;
+    image->releasePending = true;
+
+    /* --------------- Send sync points -------------- */
+
+    /* Now notify the compositor of our next acquire point */
+    wp_linux_drm_syncobj_surface_v1_set_acquire_point(surface->wlSyncobjSurf,
+                                                      
surface->wlAcquireTimeline,
+                                                      acquireSyncPoint >> 32,
+                                                      acquireSyncPoint & 
0xffffffff);
+
+    /* Now notify the compositor of our next release point */
+    wp_linux_drm_syncobj_surface_v1_set_release_point(surface->wlSyncobjSurf,
+                                                      image->wlReleaseTimeline,
+                                                      image->releasePoint >> 
32,
+                                                      image->releasePoint & 
0xffffffff);
+
+    return true;
+}
+
 EGLBoolean
 wlEglSendDamageEvent(WlEglSurface *surface, struct wl_event_queue *queue)
 {
@@ -183,6 +269,15 @@
                           surface->ctx.currentBuffer,
                           surface->dx,
                           surface->dy);
+
+        /*
+         * Send our explicit sync acquire and release points. This needs to be 
done
+         * as part of the surface attach as it is a protocol error to specify 
these
+         * points without attaching a buffer in the same commit.
+         */
+        if (!send_explicit_sync_points(surface->wlEglDpy, surface, image)) {
+            return EGL_FALSE;
+        }
     }
 
     wl_surface_damage(surface->wlSurface, 0, 0,
@@ -473,6 +568,7 @@
     assert(image->eglImage != EGL_NO_IMAGE_KHR);
     data->egl.destroyImage(dpy, image->eglImage);
     image->eglImage = EGL_NO_IMAGE_KHR;
+    image->releasePoint = 0;
 
     if (surface->ctx.currentBuffer == image->buffer) {
         surface->ctx.currentBuffer = NULL;
@@ -487,6 +583,16 @@
         wl_list_remove(&image->acquiredLink);
         wl_list_init(&image->acquiredLink);
     }
+
+    if (image->wlReleaseTimeline) {
+        wp_linux_drm_syncobj_timeline_v1_destroy(image->wlReleaseTimeline);
+        drmSyncobjDestroy(display->drmFd, image->drmSyncobjHandle);
+        if (image->acquireSync != EGL_NO_SYNC_KHR) {
+            data->egl.destroySync(dpy, image->acquireSync);
+            image->acquireSync = EGL_NO_SYNC_KHR;
+        }
+        image->releasePending = false;
+    }
 }
 
 static void
@@ -938,6 +1044,14 @@
     image->attached = EGL_FALSE;
 
     if (image->eglImage != EGL_NO_IMAGE_KHR) {
+        /*
+         * Release our image back to the stream if explicit sync is not in use
+         *
+         * If explicit sync was used, then wl_buffer.release means nothing. We
+         * will instead have already marked this image for release contingent
+         * on the release sync getting signaled. This callback doesn't even 
fire
+         * in that scenario.
+         */
         data->egl.streamReleaseImage(display->devDpy->eglDisplay,
                                      surface->ctx.eglStream,
                                      image->eglImage,
@@ -958,6 +1072,178 @@
     stream_local_buffer_release_callback,
 };
 
+/*
+ * Export a syncfd from the timeline at the specified point and make an
+ * EGLSyncKHR out of it.  We can then pass this eglsync to releaseImageNV and
+ * it will wait for the release point to signal before releasing the image back
+ * to the screen.
+ */
+static EGLSyncKHR
+get_release_sync(WlEglDisplay *display, WlEglStreamImage *image)
+{
+    EGLDisplay          dpy         = display->devDpy->eglDisplay;
+    WlEglPlatformData  *data        = display->data;
+    EGLSyncKHR          eglSync     = EGL_NO_SYNC_KHR;
+    int                 syncFd      = -1;
+    uint32_t            tmpSyncobj;
+    EGLint              attribs[3];
+
+
+    /* Import our acquire syncfd at a new acquire point */
+    if (drmSyncobjCreate(display->drmFd, 0, &tmpSyncobj) != 0) {
+        return EGL_NO_SYNC_KHR;
+    }
+
+    if (drmSyncobjTransfer(display->drmFd, tmpSyncobj, 0,
+                           image->drmSyncobjHandle, image->releasePoint,
+                           0) != 0) {
+        goto destroy;
+    }
+
+    if (drmSyncobjExportSyncFile(display->drmFd, tmpSyncobj,
+                                 &syncFd) != 0) {
+        goto destroy;
+    }
+
+    attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID;
+    attribs[1] = syncFd;
+    attribs[2] = EGL_NONE;
+    eglSync = data->egl.createSync(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                   attribs);
+    close (syncFd);
+destroy:
+    drmSyncobjDestroy(display->drmFd, tmpSyncobj);
+
+    return eglSync;
+}
+
+/*
+ * We have committed a frame, and if we are using explicit sync
+ * we will have registered a release point with the compositor.
+ * The release point's fence didn't exist then, so we should check
+ * for any available fences that we should trigger releasing
+ * images back into the stream with.
+ *
+ * This will block if no available buffers have been released.
+ */
+EGLBoolean
+wlEglSurfaceCheckReleasePoints(WlEglDisplay *display, WlEglSurface *surface)
+{
+    WlEglPlatformData  *data        = display->data;
+    EGLDisplay          dpy         = display->devDpy->eglDisplay;
+    EGLSyncKHR          releaseSync = EGL_NO_SYNC_KHR;
+    WlEglStreamImage   *image = NULL;
+    uint32_t           *syncobjs;
+    uint64_t           *syncPoints;
+    uint32_t            i, firstSignaled, numSyncPoints = 0;
+    int64_t             timeout;
+    EGLBoolean          ret = EGL_FALSE;
+
+    if (!surface->wlSyncobjSurf) {
+        return EGL_TRUE;
+    }
+
+    syncobjs = calloc(surface->ctx.numStreamImages, sizeof(uint32_t));
+    syncPoints = calloc(surface->ctx.numStreamImages, sizeof(uint64_t));
+    if (!syncobjs || !syncPoints) {
+        return EGL_FALSE;
+    }
+
+    for (i = 0; i < surface->ctx.numStreamImages; i++) {
+        pthread_mutex_lock(&surface->ctx.streamImages[i]->mutex);
+    }
+
+    /* record each release point we are waiting on */
+    for (i = 0; i < surface->ctx.numStreamImages; i++) {
+        syncobjs[i] = surface->ctx.streamImages[i]->drmSyncobjHandle;
+
+        if (surface->ctx.streamImages[i]->releasePending) {
+            syncPoints[i] = surface->ctx.streamImages[i]->releasePoint;
+            numSyncPoints++;
+        } else {
+            /*
+             * Use a bogus point for acquired images so we can keep our indices
+             * the same. This won't affect anything since it will never have a 
fence
+             * appear.
+             */
+            syncPoints[i] = UINT64_MAX;
+        }
+    }
+
+    if (numSyncPoints == 0) {
+        goto end;
+    }
+
+    /*
+     * Wait for at least one release point to have a fence. We need to block 
here
+     * since the streams internal code expects to have at least one buffer 
placed
+     * back on the release (internally called returns) queue.
+     *
+     * We only wait indefinitely when all but one buffers are pending. There 
are
+     * four total buffers:
+     *   1. One owned by the driver (as per above)
+     *   2. One we just committed and sent to the compositor
+     *   3. One owned by compositor, queued for scanout
+     *   4. One owned by compositor, in process of releasing
+     *
+     * Not all compositors will hold 3 and 4 indefinitely, although Kwin does
+     * at certain times.
+     */
+    timeout = numSyncPoints >= 3 ? INT64_MAX : 0;
+
+    /*
+     * The Linux docs say that DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE should be
+     * used to wait for a fence to appear without waiting on the fence itself.
+     * Note that there are some bugs with older kernels where this may not
+     * signal correctly.
+     */
+    if (drmSyncobjTimelineWait(display->drmFd, syncobjs, syncPoints,
+                               surface->ctx.numStreamImages, timeout,
+                               DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE,
+                               &firstSignaled) != 0) {
+        goto end;
+    }
+
+    image = surface->ctx.streamImages[firstSignaled];
+
+    /* Try to get a release point for the first available buffer.  */
+    releaseSync = get_release_sync(display, image);
+    if (releaseSync == EGL_NO_SYNC_KHR) {
+        goto end;
+    }
+
+    /*
+     * Pass our newly created release EGLSyncKHR to our eglstream, it
+     * will wait for it to signal before it releases the image back to
+     * the stream. Note that wl_buffer.release means nothing with
+     * linux-drm-syncobj-v1.
+     */
+    ret = data->egl.streamReleaseImage(display->devDpy->eglDisplay,
+                                       surface->ctx.eglStream,
+                                       image->eglImage,
+                                       releaseSync);
+    /* releaseImage makes a copy, so we destroy ours here */
+    data->egl.destroySync(dpy, releaseSync);
+
+    /*
+     * If we succesfully released the image, Clear our release point so we
+     * don't repeat this.
+     */
+    if (ret == EGL_TRUE) {
+        image->releasePending = false;
+    }
+
+end:
+    for (i = 0; i < surface->ctx.numStreamImages; i++) {
+        pthread_mutex_unlock(&surface->ctx.streamImages[i]->mutex);
+    }
+
+    free(syncPoints);
+    free(syncobjs);
+
+    return ret;
+}
+
 static EGLint
 acquire_surface_image(WlEglDisplay *display, WlEglSurface *surface)
 {
@@ -974,12 +1260,33 @@
     EGLint              offset;
     uint32_t            i;
     int                 fd;
+    EGLSyncKHR          acquireSync = EGL_NO_SYNC_KHR;
+    const EGLint attribs[] = {
+        EGL_SYNC_NATIVE_FENCE_FD_ANDROID, EGL_NO_NATIVE_FENCE_FD_ANDROID,
+        EGL_SYNC_STATUS, EGL_SIGNALED,
+        EGL_NONE,
+    };
+
+    if (surface->wlSyncobjSurf) {
+        /*
+         * don't flush before acquireImage, we have to pass it in signaled.
+         *
+         * acquireImage will reset this, causing the fd to populate.
+         */
+        acquireSync = data->egl.createSync(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                           attribs);
+        if (acquireSync == EGL_NO_SYNC_KHR) {
+            return EGL_BAD_SURFACE;
+        }
+    }
 
     if (!data->egl.streamAcquireImage(dpy,
                                       surface->ctx.eglStream,
                                       &eglImage,
-                                      EGL_NO_SYNC_KHR)) {
-        return EGL_BAD_SURFACE;
+                                      acquireSync)) {
+        if (acquireSync != EGL_NO_SYNC_KHR) {
+            goto fail_destroy_sync;
+        }
     }
 
     for (i = 0; i < surface->ctx.numStreamImages; i++) {
@@ -990,11 +1297,13 @@
     }
 
     if (!image) {
-        goto fail_release;
+        goto fail_destroy_sync;
     }
 
     pthread_mutex_lock(&image->mutex);
 
+    image->acquireSync = acquireSync;
+
     if (!image->buffer) {
         if (!data->egl.exportDMABUFImageQuery(dpy,
                                               eglImage,
@@ -1058,7 +1367,8 @@
             goto fail_release;
         }
 
-        if (wl_buffer_add_listener(image->buffer,
+        if (!surface->wlSyncobjSurf &&
+            wl_buffer_add_listener(image->buffer,
                                    &stream_local_buffer_listener,
                                    image) == -1) {
             wl_buffer_destroy(image->buffer);
@@ -1081,12 +1391,23 @@
                                  eglImage,
                                  EGL_NO_SYNC_KHR);
 
+    if (image && image->acquireSync != EGL_NO_SYNC_KHR) {
+        data->egl.destroySync(dpy, image->acquireSync);
+        image->acquireSync = EGL_NO_SYNC_KHR;
+    }
+
     if (image) {
         /* Release the image lock */
         pthread_mutex_unlock(&image->mutex);
     }
 
     return EGL_BAD_SURFACE;
+
+fail_destroy_sync:
+    if (acquireSync != EGL_NO_SYNC_KHR) {
+        data->egl.destroySync(dpy, acquireSync);
+    }
+    return EGL_BAD_SURFACE;
 }
 
 static void
@@ -1125,34 +1446,94 @@
     return NULL;
 }
 
+static int
+create_syncobj_timeline(WlEglDisplay *display, uint32_t *drmSyncobjHandleOut)
+{
+    int ret;
+
+    /* Create a DRM timeline and share it with the compositor */
+    if (drmSyncobjCreate(display->drmFd, 0, drmSyncobjHandleOut)) {
+        return -1;
+    }
+
+    if (drmSyncobjHandleToFD(display->drmFd, *drmSyncobjHandleOut, &ret)) {
+        return -1;
+    }
+
+    return ret;
+}
+
 static EGLint
-add_surface_image(WlEglDisplay *display, WlEglSurface *surface)
+init_surface_image(WlEglDisplay *display, WlEglSurface *surface,
+                   WlEglStreamImage    *image)
 {
     WlEglPlatformData   *data     = display->data;
     EGLDisplay           dpy      = display->devDpy->eglDisplay;
+    int                  drmSyncobjFd = -1;
+
+    image->eglImage = data->egl.createImage(dpy, EGL_NO_CONTEXT,
+                                            EGL_STREAM_CONSUMER_IMAGE_NV,
+                                            
(EGLClientBuffer)surface->ctx.eglStream,
+                                            NULL);
+    if (image->eglImage == EGL_NO_IMAGE_KHR) {
+        return EGL_BAD_ALLOC;
+    }
+
+    /*
+     * Create a per-stream image release timeline.
+     *
+     * This is needed since we will be the ones signaling acquire points. If 
the acquire points
+     * are on the same timeline as the release points then they will 
accidentally signal all
+     * pending release points.
+     */
+    if (surface->wlSyncobjSurf) {
+        drmSyncobjFd = create_syncobj_timeline(display, 
&image->drmSyncobjHandle);
+        if (drmSyncobjFd < 0) {
+            goto fail;
+        }
+        image->acquireSync = EGL_NO_SYNC_KHR;
+
+        /* Get a DRM timeline wl object */
+        image->wlReleaseTimeline =
+            
wp_linux_drm_syncobj_manager_v1_import_timeline(display->wlDrmSyncobj, 
drmSyncobjFd);
+        if (!image->wlReleaseTimeline) {
+            goto fail;
+        }
+
+        close(drmSyncobjFd);
+    }
+
+    return EGL_SUCCESS;
+
+fail:
+    if (image->drmSyncobjHandle) {
+        drmSyncobjDestroy(display->drmFd, image->drmSyncobjHandle);
+    }
+
+    if (drmSyncobjFd > 0) {
+        close(drmSyncobjFd);
+    }
+
+    data->egl.destroyImage(dpy, image->eglImage);
+    return EGL_BAD_ALLOC;
+}
+
+static EGLint
+add_surface_image(WlEglDisplay *display, WlEglSurface *surface)
+{
     WlEglStreamImage   **newImages;
     WlEglStreamImage    *image;
-    EGLImageKHR          eglImage;
+    EGLint               ret;
     uint32_t             i;
 
     for (i = 0; i < surface->ctx.numStreamImages; i++) {
         image = surface->ctx.streamImages[i];
         pthread_mutex_lock(&image->mutex);
         if ((image->eglImage == EGL_NO_IMAGE_KHR) && !image->buffer) {
-            eglImage = image->eglImage =
-                data->egl.createImage(dpy,
-                                      EGL_NO_CONTEXT,
-                                      EGL_STREAM_CONSUMER_IMAGE_NV,
-                                      (EGLClientBuffer)surface->ctx.eglStream,
-                                      NULL);
+            ret = init_surface_image(display, surface, image);
 
             pthread_mutex_unlock(&image->mutex);
-
-            if (eglImage != EGL_NO_IMAGE_KHR) {
-                return EGL_SUCCESS;
-            } else {
-                return EGL_BAD_ALLOC;
-            }
+            return ret;
         }
         pthread_mutex_unlock(&image->mutex);
     }
@@ -1187,14 +1568,8 @@
     }
 
     wl_list_init(&newImages[i]->acquiredLink);
-    newImages[i]->eglImage =
-        data->egl.createImage(dpy,
-                              EGL_NO_CONTEXT,
-                              EGL_STREAM_CONSUMER_IMAGE_NV,
-                              (EGLClientBuffer)surface->ctx.eglStream,
-                              NULL);
 
-    if (newImages[i]->eglImage == EGL_NO_IMAGE_KHR) {
+    if (init_surface_image(display, surface, newImages[i]) != EGL_SUCCESS) {
         wlEglMutexDestroy(&newImages[i]->mutex);
         goto free_image;
     }
@@ -1218,6 +1593,7 @@
     EGLAttrib             aux;
     EGLenum               event;
     EGLint                err = EGL_SUCCESS;
+    EGLTime               timeout = surface->wlSyncobjSurf ? EGL_FOREVER : 0;
 
     if (surface->ctx.wlStreamResource) {
         /* Not a local stream */
@@ -1225,9 +1601,14 @@
     }
 
     while (1) {
+        /*
+         * With explicit sync we should block here and not return until we have
+         * acquired a new image. The stream will not release the image until
+         * the release point we handed to the compositor signals.
+         */
         err = data->egl.queryStreamConsumerEvent(dpy,
                                                  surface->ctx.eglStream,
-                                                 0,
+                                                 timeout,
                                                  &event,
                                                  &aux);
 
@@ -1247,6 +1628,8 @@
         switch (event) {
         case EGL_STREAM_IMAGE_AVAILABLE_NV:
             err = acquire_surface_image(display, surface);
+            /* Clear our timeout so we exit after all events are handled */
+            timeout = 0;
             break;
         case EGL_STREAM_IMAGE_ADD_NV:
             err = add_surface_image(display, surface);
@@ -1457,7 +1840,12 @@
 
     wl_list_init(&surface->ctx.acquiredImages);
 
-    if (!surface->wlBufferEventQueue) {
+    /*
+     * Don't enable the buffer release thread when explicit sync is in use.
+     * In explicit sync we don't care about the delivery of release events, we
+     * only pay attention to the release points.
+     */
+    if (!surface->wlBufferEventQueue && !surface->wlSyncobjSurf) {
         /*
          * Local stream contexts need a private wayland queue used by a 
separate
          * thread that can process buffer release events even the application
@@ -1651,6 +2039,7 @@
 
     /* Check whether we should use a damage thread */
     surface->ctx.useDamageThread =
+                    !surface->wlSyncobjSurf &&
                     display->devDpy->exts.stream_fifo_synchronous &&
                     display->devDpy->exts.stream_sync &&
                     data->egl.queryStream(display->devDpy->eglDisplay,
@@ -1967,7 +2356,9 @@
         return EGL_FALSE;
 
     case EGL_PRESENT_OPAQUE_EXT:
-        return EGL_TRUE;
+        return (value == EGL_TRUE ||
+                value == EGL_FALSE) ? EGL_TRUE :
+                                      EGL_FALSE;
 
     /* If attribute is supported/unsupported for both EGL_WINDOW_BIT and
      * EGL_STREAM_BIT_KHR, then that will be handled inside the actual
@@ -2013,7 +2404,7 @@
     if (attribs) {
         for (i = 0; attribs[i] != EGL_NONE; i += 2) {
             if (attribs[i] == EGL_PRESENT_OPAQUE_EXT) {
-                surface->presentOpaque = EGL_TRUE;
+                surface->presentOpaque = attribs[i + 1];
                 continue;
             }
             if ((attribs[i] != EGL_RENDER_BUFFER) &&
@@ -2151,6 +2542,11 @@
 
     wlEglDestroyFeedback(&surface->feedback);
 
+    if (surface->wlSyncobjSurf) {
+        wp_linux_drm_syncobj_surface_v1_destroy(surface->wlSyncobjSurf);
+        wp_linux_drm_syncobj_timeline_v1_destroy(surface->wlAcquireTimeline);
+    }
+
     if (surface->presentFeedbackQueue != NULL) {
         wl_event_queue_destroy(surface->presentFeedbackQueue);
         surface->presentFeedbackQueue = NULL;
@@ -2247,6 +2643,7 @@
     EGLBoolean            res     = EGL_FALSE;
     EGLint                err     = EGL_SUCCESS;
     EGLint                surfType;
+    int                   drmSyncobjFd = -1;
 
     if (!display) {
         return EGL_NO_SURFACE;
@@ -2319,9 +2716,31 @@
     surface->isSurfaceProducer = EGL_TRUE;
     surface->refCount = 1;
     surface->isDestroyed = EGL_FALSE;
+    surface->syncPoint = 1;
     // FIFO_LENGTH == 1 to set FIFO mode, FIFO_LENGTH == 0 to set MAILBOX mode
+    // We set two here however to bump the "swapchain" count to 4 on Wayland.
+    // This is done to better match what Mesa does, as apparently 4 is the
+    // expectation on wayland.
+    // https://gitlab.freedesktop.org/mesa/mesa/-/issues/6249#note_1328923
+    //
+    // The problem users are running into is that we always have to advance to
+    // a new buffer (in PresentCore) because the driver always expects to be
+    // incremented to the next valid buffer as part of swapbuffers.  So
+    // currently it seems one of the three images will always be owned by the
+    // driver (either the buffer currently/just rendered to, or the one we just
+    // advanced to for future rendering)
+    //
+    // So the three buffers are used up by:
+    //   1. One buffer owned by the driver
+    //   2. One buffer that just got committed and shared with the compositor
+    //   3. One buffer owned by the compositor, pending a release
+    //
+    // For whatever reason Kwin is holding onto 2 and 3 indefinitely when the
+    // dock gets hidden, and we hold onto 1 and try waiting for one of the
+    // other two to become free. We need a fourth to allow us to continue 
feeding
+    // the driver .
     surface->fifoLength = (display->devDpy->exts.stream_fifo_synchronous &&
-                           display->devDpy->exts.stream_sync) ? 1 : 0;
+                           display->devDpy->exts.stream_sync) ? 2 : 0;
 
     // Create per surface wayland queue
     surface->wlEventQueue = wl_display_create_queue(display->nativeDpy);
@@ -2365,6 +2784,28 @@
         surface->feedback.unprocessedFeedback = false;
     }
 
+    if (display->wlDrmSyncobj) {
+        /* Create a DRM timeline and share it with the compositor */
+        drmSyncobjFd = create_syncobj_timeline(display, 
&surface->drmSyncobjHandle);
+        if (drmSyncobjFd < 0) {
+            goto fail;
+        }
+
+        /* Get a per-surface explicit sync object, share our DRM syncobj with 
the compositor */
+        surface->wlSyncobjSurf =
+            wp_linux_drm_syncobj_manager_v1_get_surface(display->wlDrmSyncobj, 
surface->wlSurface);
+
+        surface->wlAcquireTimeline =
+            
wp_linux_drm_syncobj_manager_v1_import_timeline(display->wlDrmSyncobj, 
drmSyncobjFd);
+        close(drmSyncobjFd);
+        drmSyncobjFd = -1;
+
+        if (!surface->wlSyncobjSurf || !surface->wlAcquireTimeline) {
+            err = EGL_BAD_ALLOC;
+            goto fail;
+        }
+    }
+
     err = create_surface_context(surface);
     if (err != EGL_SUCCESS) {
         goto fail;
@@ -2391,6 +2832,14 @@
     return surface;
 
 fail:
+    if (surface->drmSyncobjHandle) {
+        drmSyncobjDestroy(display->drmFd, surface->drmSyncobjHandle);
+    }
+
+    if (drmSyncobjFd > 0) {
+        close(drmSyncobjFd);
+    }
+
     if (surface) {
         wlEglDestroySurface(display, surface);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/wayland-eglswap.c 
new/egl-wayland-1.1.14/src/wayland-eglswap.c
--- old/egl-wayland-1.1.13/src/wayland-eglswap.c        2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/src/wayland-eglswap.c        2024-07-17 
20:13:07.000000000 +0200
@@ -148,6 +148,7 @@
         } else {
             wlEglCreateFrameSync(surface);
             res = wlEglSendDamageEvent(surface, surface->wlEventQueue);
+            wlEglSurfaceCheckReleasePoints(display, surface);
         }
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/egl-wayland-1.1.13/src/wayland-external-exports.c 
new/egl-wayland-1.1.14/src/wayland-external-exports.c
--- old/egl-wayland-1.1.13/src/wayland-external-exports.c       2023-10-18 
20:00:18.000000000 +0200
+++ new/egl-wayland-1.1.14/src/wayland-external-exports.c       2024-07-17 
20:13:07.000000000 +0200
@@ -96,7 +96,8 @@
                                    EGLExtPlatform *platform)
 {
     if (!platform ||
-        !EGL_EXTERNAL_PLATFORM_VERSION_CHECK(major, minor)) {
+        !EGL_EXTERNAL_PLATFORM_VERSION_CMP(major, minor,
+            WAYLAND_EXTERNAL_VERSION_MAJOR, WAYLAND_EXTERNAL_VERSION_MINOR)) {
         return EGL_FALSE;
     }
 

Reply via email to