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 <[email protected]>
+
+- 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 : '@[email protected]',
@@ -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;
}