commit libnvidia-egl-wayland for openSUSE:Factory
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_Nik_C@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, ®istryListener, 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; }
participants (1)
-
Source-Sync