From 68da656c6290ac8ecb4cd0c330b507cfd868dd99 Mon Sep 17 00:00:00 2001 From: "Ward Nakchbandi (Cosmic Fusion)" <83735213+CosmicFusion@users.noreply.github.com> Date: Sat, 11 Nov 2023 17:18:49 +0300 Subject: [PATCH] 23.2.2 + explict sync for nvidia patch --- debian/changelog | 2 +- debian/patches/967.patch | 2478 ++++++++++++++++++++++++++++++++++++++ debian/patches/series | 1 + main.sh | 4 +- 4 files changed, 2482 insertions(+), 3 deletions(-) create mode 100644 debian/patches/967.patch diff --git a/debian/changelog b/debian/changelog index 38d5db0..dc3c882 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -xwayland (2:23.2.1-100pika1) pikauwu; urgency=medium +xwayland (2:23.2.2-100pika1) pikauwu; urgency=medium * Update to pikauwu diff --git a/debian/patches/967.patch b/debian/patches/967.patch new file mode 100644 index 0000000..ec764be --- /dev/null +++ b/debian/patches/967.patch @@ -0,0 +1,2478 @@ +From f1fc5cfab4bffd8a96df6fbe560946274024b904 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 24 Oct 2023 16:14:17 -0700 +Subject: [PATCH 1/5] DRI3: provide stub implementation of + DRI3SetDRMDeviceInUse + +DRI3 version 1.3 introduced a new request which allows clients to +provide a hint to the server about which DRM device they are using, so +that the server might return DRM format modifiers specific to that +device. However, implementing such functionality, for Xwayland in +particular, will require fairly significant architectural changes. + +To avoid blocking future versions of the DRI3 extension, we provide here +a stub implementation for the request in question. The spec explicitly +states that it is only a hint that the server is free to ignore, so +strictly speaking this implementation is still correct. + +Signed-off-by: Erik Kurzinger +--- + dri3/dri3_request.c | 34 ++++++++++++++++++++++++++++++++++ + include/protocol-versions.h | 2 +- + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c +index 6871689308..f7170518f4 100644 +--- a/dri3/dri3_request.c ++++ b/dri3/dri3_request.c +@@ -554,6 +554,27 @@ proc_dri3_buffers_from_pixmap(ClientPtr client) + return Success; + } + ++static int ++proc_dri3_set_drm_device_in_use(ClientPtr client) ++{ ++ REQUEST(xDRI3SetDRMDeviceInUseReq); ++ WindowPtr window; ++ int status; ++ ++ REQUEST_SIZE_MATCH(xDRI3SetDRMDeviceInUseReq); ++ status = dixLookupWindow(&window, stuff->window, client, ++ DixGetAttrAccess); ++ if (status != Success) ++ return status; ++ ++ /* TODO Eventually we should use this information to have ++ * DRI3GetSupportedModifiers return device-specific modifiers, but for now ++ * we will ignore it until multi-device support is more complete. ++ * Otherwise we can't advertise support for DRI3 1.4. ++ */ ++ return Success; ++} ++ + int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + proc_dri3_query_version, /* 0 */ + proc_dri3_open, /* 1 */ +@@ -564,6 +585,7 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + proc_dri3_get_supported_modifiers, /* 6 */ + proc_dri3_pixmap_from_buffers, /* 7 */ + proc_dri3_buffers_from_pixmap, /* 8 */ ++ proc_dri3_set_drm_device_in_use, /* 9 */ + }; + + int +@@ -697,6 +719,17 @@ sproc_dri3_buffers_from_pixmap(ClientPtr client) + return (*proc_dri3_vector[stuff->dri3ReqType]) (client); + } + ++static int _X_COLD ++sproc_dri3_set_drm_device_in_use(ClientPtr client) ++{ ++ REQUEST(xDRI3SetDRMDeviceInUseReq); ++ REQUEST_SIZE_MATCH(xDRI3SetDRMDeviceInUseReq); ++ swapl(&stuff->window); ++ swapl(&stuff->drmMajor); ++ swapl(&stuff->drmMinor); ++ return (*proc_dri3_vector[stuff->dri3ReqType]) (client); ++} ++ + int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + sproc_dri3_query_version, /* 0 */ + sproc_dri3_open, /* 1 */ +@@ -707,6 +740,7 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + sproc_dri3_get_supported_modifiers, /* 6 */ + sproc_dri3_pixmap_from_buffers, /* 7 */ + sproc_dri3_buffers_from_pixmap, /* 8 */ ++ sproc_dri3_set_drm_device_in_use, /* 9 */ + }; + + int _X_COLD +diff --git a/include/protocol-versions.h b/include/protocol-versions.h +index d7bfc6dca2..2c38a15ae0 100644 +--- a/include/protocol-versions.h ++++ b/include/protocol-versions.h +@@ -48,7 +48,7 @@ + + /* DRI3 */ + #define SERVER_DRI3_MAJOR_VERSION 1 +-#define SERVER_DRI3_MINOR_VERSION 2 ++#define SERVER_DRI3_MINOR_VERSION 3 + + /* DMX */ + #define SERVER_DMX_MAJOR_VERSION 2 +-- +GitLab + + +From 85da52868b21b8998ab1826df40534297c6df280 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 16 Aug 2022 11:57:40 -0700 +Subject: [PATCH 2/5] DRI3: add DRI3ImportSyncobj and DRI3FreeSyncobj + +Adds the required infrastructure in the core DRI3 code to support +importing DRM synchronization objects from clients. This includes +support for the two new protocol requests from DRI3 version 1.4, an +internal representation of these objects in the form of the dri3_syncobj +structure, and an import_syncobj screen info callback. + +The following operations are defined for dri3_syncobj objects +* free - release any server-side resources associated with the object +* check - poll a timeline point and return whether it is signaled +* export_fence - return a sync fd corresponding to a timeline point +* import_fence - submit a sync fd as the fence for a timeline point +* signal - immediately signal a timeline point +* eventfd - register an eventfd to be signaled when the given timeline + point is either submitted or signaled, depending on wait_avail + +Implementations will be responsible for populating these function +pointers when importing a syncobj. + +Signed-off-by: Erik Kurzinger +--- + dri3/dri3.c | 15 ++++++ + dri3/dri3.h | 36 ++++++++++++++- + dri3/dri3_priv.h | 3 ++ + dri3/dri3_request.c | 91 +++++++++++++++++++++++++++++++++++++ + dri3/dri3_screen.c | 20 ++++++++ + include/protocol-versions.h | 2 +- + 6 files changed, 165 insertions(+), 2 deletions(-) + +diff --git a/dri3/dri3.c b/dri3/dri3.c +index 1912529695..f9c5172774 100644 +--- a/dri3/dri3.c ++++ b/dri3/dri3.c +@@ -63,6 +63,16 @@ dri3_screen_init(ScreenPtr screen, const dri3_screen_info_rec *info) + return TRUE; + } + ++RESTYPE dri3_syncobj_type; ++ ++static int dri3_syncobj_free(void *data, XID id) ++{ ++ struct dri3_syncobj *syncobj = data; ++ if (--syncobj->refcount == 0) ++ syncobj->free(syncobj); ++ return 0; ++} ++ + void + dri3_extension_init(void) + { +@@ -92,6 +102,11 @@ dri3_extension_init(void) + if (!dri3_screen_init(screenInfo.screens[i], NULL)) + goto bail; + } ++ ++ dri3_syncobj_type = CreateNewResourceType(dri3_syncobj_free, "DRI3Syncobj"); ++ if (!dri3_syncobj_type) ++ goto bail; ++ + return; + + bail: +diff --git a/dri3/dri3.h b/dri3/dri3.h +index 02d3b03eec..f7f4bb1c1b 100644 +--- a/dri3/dri3.h ++++ b/dri3/dri3.h +@@ -28,7 +28,33 @@ + #include + #include + +-#define DRI3_SCREEN_INFO_VERSION 2 ++#define DRI3_SCREEN_INFO_VERSION 4 ++ ++extern RESTYPE dri3_syncobj_type; ++ ++struct dri3_syncobj ++{ ++ XID id; ++ ScreenPtr screen; ++ uint32_t refcount; ++ ++ void (*free)(struct dri3_syncobj *syncobj); ++ Bool (*check)(struct dri3_syncobj *syncobj, uint64_t point); ++ int (*export_fence)(struct dri3_syncobj *syncobj, uint64_t point); ++ void (*import_fence)(struct dri3_syncobj *syncobj, uint64_t point, int fd); ++ void (*signal)(struct dri3_syncobj *syncobj, uint64_t point); ++ void (*eventfd)(struct dri3_syncobj *syncobj, uint64_t point, int efd, Bool wait_avail); ++}; ++ ++#define VERIFY_DRI3_SYNCOBJ(id, ptr, a)\ ++ do {\ ++ int rc = dixLookupResourceByType((void **)&(ptr), id,\ ++ dri3_syncobj_type, client, a);\ ++ if (rc != Success) {\ ++ client->errorValue = id;\ ++ return rc;\ ++ }\ ++ } while (0); + + typedef int (*dri3_open_proc)(ScreenPtr screen, + RRProviderPtr provider, +@@ -84,6 +110,11 @@ typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw, + uint32_t *num_modifiers, + uint64_t **modifiers); + ++typedef struct dri3_syncobj *(*dri3_import_syncobj_proc) (ClientPtr client, ++ ScreenPtr screen, ++ XID id, ++ int fd); ++ + typedef struct dri3_screen_info { + uint32_t version; + +@@ -101,6 +132,9 @@ typedef struct dri3_screen_info { + dri3_get_modifiers_proc get_modifiers; + dri3_get_drawable_modifiers_proc get_drawable_modifiers; + ++ /* Version 4 */ ++ dri3_import_syncobj_proc import_syncobj; ++ + } dri3_screen_info_rec, *dri3_screen_info_ptr; + + extern _X_EXPORT Bool +diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h +index f319d17702..71d2da9571 100644 +--- a/dri3/dri3_priv.h ++++ b/dri3/dri3_priv.h +@@ -102,4 +102,7 @@ dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, + CARD32 *num_screen_modifiers, + CARD64 **screen_modifiers); + ++int ++dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd); ++ + #endif /* _DRI3PRIV_H_ */ +diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c +index f7170518f4..520cd60c20 100644 +--- a/dri3/dri3_request.c ++++ b/dri3/dri3_request.c +@@ -28,6 +28,17 @@ + #include + #include + ++static Bool ++dri3_screen_can_one_point_four(ScreenPtr screen) ++{ ++ dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen); ++ ++ return dri3 && ++ dri3->info && ++ dri3->info->version >= 4 && ++ dri3->info->import_syncobj; ++} ++ + static Bool + dri3_screen_can_one_point_two(ScreenPtr screen) + { +@@ -61,6 +72,10 @@ proc_dri3_query_version(ClientPtr client) + rep.minorVersion = 0; + break; + } ++ if (!dri3_screen_can_one_point_four(screenInfo.screens[i])) { ++ rep.minorVersion = 2; ++ break; ++ } + } + + for (int i = 0; i < screenInfo.numGPUScreens; i++) { +@@ -68,6 +83,10 @@ proc_dri3_query_version(ClientPtr client) + rep.minorVersion = 0; + break; + } ++ if (!dri3_screen_can_one_point_four(screenInfo.gpuscreens[i])) { ++ rep.minorVersion = 2; ++ break; ++ } + } + + /* From DRI3 proto: +@@ -575,6 +594,51 @@ proc_dri3_set_drm_device_in_use(ClientPtr client) + return Success; + } + ++static int ++proc_dri3_import_syncobj(ClientPtr client) ++{ ++ REQUEST(xDRI3ImportSyncobjReq); ++ DrawablePtr drawable; ++ ScreenPtr screen; ++ int fd; ++ int status; ++ ++ SetReqFds(client, 1); ++ REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq); ++ LEGAL_NEW_RESOURCE(stuff->syncobj, client); ++ ++ status = dixLookupDrawable(&drawable, stuff->drawable, client, ++ M_ANY, DixGetAttrAccess); ++ if (status != Success) ++ return status; ++ ++ screen = drawable->pScreen; ++ ++ fd = ReadFdFromClient(client); ++ if (fd < 0) ++ return BadValue; ++ ++ return dri3_import_syncobj(client, screen, stuff->syncobj, fd); ++} ++ ++static int ++proc_dri3_free_syncobj(ClientPtr client) ++{ ++ REQUEST(xDRI3FreeSyncobjReq); ++ struct dri3_syncobj *syncobj; ++ int status; ++ ++ REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq); ++ ++ status = dixLookupResourceByType((void **) &syncobj, stuff->syncobj, ++ dri3_syncobj_type, client, DixWriteAccess); ++ if (status != Success) ++ return status; ++ ++ FreeResource(stuff->syncobj, dri3_syncobj_type); ++ return Success; ++} ++ + int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + proc_dri3_query_version, /* 0 */ + proc_dri3_open, /* 1 */ +@@ -586,6 +650,8 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + proc_dri3_pixmap_from_buffers, /* 7 */ + proc_dri3_buffers_from_pixmap, /* 8 */ + proc_dri3_set_drm_device_in_use, /* 9 */ ++ proc_dri3_import_syncobj, /* 10 */ ++ proc_dri3_free_syncobj, /* 11 */ + }; + + int +@@ -730,6 +796,29 @@ sproc_dri3_set_drm_device_in_use(ClientPtr client) + return (*proc_dri3_vector[stuff->dri3ReqType]) (client); + } + ++static int _X_COLD ++sproc_dri3_import_syncobj(ClientPtr client) ++{ ++ REQUEST(xDRI3ImportSyncobjReq); ++ REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq); ++ ++ swaps(&stuff->length); ++ swapl(&stuff->syncobj); ++ swapl(&stuff->drawable); ++ return (*proc_dri3_vector[stuff->dri3ReqType]) (client); ++} ++ ++static int _X_COLD ++sproc_dri3_free_syncobj(ClientPtr client) ++{ ++ REQUEST(xDRI3FreeSyncobjReq); ++ REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq); ++ ++ swaps(&stuff->length); ++ swapl(&stuff->syncobj); ++ return (*proc_dri3_vector[stuff->dri3ReqType]) (client); ++} ++ + int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + sproc_dri3_query_version, /* 0 */ + sproc_dri3_open, /* 1 */ +@@ -741,6 +830,8 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { + sproc_dri3_pixmap_from_buffers, /* 7 */ + sproc_dri3_buffers_from_pixmap, /* 8 */ + sproc_dri3_set_drm_device_in_use, /* 9 */ ++ sproc_dri3_import_syncobj, /* 10 */ ++ sproc_dri3_free_syncobj, /* 11 */ + }; + + int _X_COLD +diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c +index bc96e5339c..5614a22b35 100644 +--- a/dri3/dri3_screen.c ++++ b/dri3/dri3_screen.c +@@ -272,3 +272,23 @@ dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable, + + return Success; + } ++ ++int dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd) ++{ ++ const dri3_screen_info_rec *info = dri3_screen_priv(screen)->info; ++ struct dri3_syncobj *syncobj = NULL; ++ ++ if (info->version < 4 || !info->import_syncobj) ++ return BadImplementation; ++ ++ syncobj = info->import_syncobj(client, screen, id, fd); ++ close(fd); ++ ++ if (!syncobj) ++ return BadAlloc; ++ ++ if (!AddResource(id, dri3_syncobj_type, syncobj)) ++ return BadAlloc; ++ ++ return Success; ++} +diff --git a/include/protocol-versions.h b/include/protocol-versions.h +index 2c38a15ae0..ffd7d0e239 100644 +--- a/include/protocol-versions.h ++++ b/include/protocol-versions.h +@@ -48,7 +48,7 @@ + + /* DRI3 */ + #define SERVER_DRI3_MAJOR_VERSION 1 +-#define SERVER_DRI3_MINOR_VERSION 3 ++#define SERVER_DRI3_MINOR_VERSION 4 + + /* DMX */ + #define SERVER_DMX_MAJOR_VERSION 2 +-- +GitLab + + +From 45e18cad319a849b08d45d4ed78f7816d48ab286 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 16 Aug 2022 11:59:14 -0700 +Subject: [PATCH 3/5] xwayland: implement support for DRI3 syncobjs + +Adds an implementation of the import_syncobj DRI3 screen info callback +for Xwayland along with the various operations defined for dri3_syncobj +objects. + +Signed-off-by: Erik Kurzinger +--- + hw/xwayland/xwayland-glamor-gbm.c | 178 +++++++++++++++++++++++++++++- + 1 file changed, 177 insertions(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index b177b77e08..547a0999df 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -811,7 +811,177 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, + return -1; + } + +-static const dri3_screen_info_rec xwl_dri3_info = { ++struct xwl_dri3_syncobj ++{ ++ struct dri3_syncobj base; ++ uint32_t handle; ++}; ++ ++static Bool ++xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, uint64_t point) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ return !drmSyncobjTimelineWait(xwl_gbm->drm_fd, ++ &xwl_syncobj->handle, &point, 1, ++ 0 /* timeout */, ++ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, ++ NULL /* first_signaled */); ++} ++ ++#pragma weak drmSyncobjImportSyncFileTimeline ++#pragma weak drmSyncobjExportSyncFileTimeline ++ ++static int ++xwl_dri3_syncobj_export_fence(struct dri3_syncobj *syncobj, uint64_t point) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ int fd = -1; ++ ++ if (!drmSyncobjExportSyncFileTimeline || ++ drmSyncobjExportSyncFileTimeline(xwl_gbm->drm_fd, ++ xwl_syncobj->handle, ++ point, &fd)) { ++ /* try legacy export procedure */ ++ uint32_t temp_syncobj; ++ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &temp_syncobj); ++ drmSyncobjTransfer(xwl_gbm->drm_fd, temp_syncobj, 0, ++ xwl_syncobj->handle, point, 0); ++ drmSyncobjExportSyncFile(xwl_gbm->drm_fd, temp_syncobj, &fd); ++ drmSyncobjDestroy(xwl_gbm->drm_fd, temp_syncobj); ++ } ++ return fd; ++} ++ ++static void ++xwl_dri3_syncobj_import_fence(struct dri3_syncobj *syncobj, ++ uint64_t point, int fd) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ if (!drmSyncobjImportSyncFileTimeline || ++ drmSyncobjImportSyncFileTimeline(xwl_gbm->drm_fd, ++ xwl_syncobj->handle, ++ point, fd)) { ++ /* try legacy import procedure */ ++ uint32_t temp_syncobj; ++ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &temp_syncobj); ++ drmSyncobjImportSyncFile(xwl_gbm->drm_fd, temp_syncobj, fd); ++ drmSyncobjTransfer(xwl_gbm->drm_fd, xwl_syncobj->handle, point, ++ temp_syncobj, 0, 0); ++ drmSyncobjDestroy(xwl_gbm->drm_fd, temp_syncobj); ++ } ++ close(fd); ++} ++ ++static void ++xwl_dri3_signal_syncobj(struct dri3_syncobj *syncobj, uint64_t point) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ drmSyncobjTimelineSignal(xwl_gbm->drm_fd, &xwl_syncobj->handle, &point, 1); ++} ++ ++static void ++xwl_dri3_free_syncobj(struct dri3_syncobj *syncobj) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ if (xwl_syncobj->handle) ++ drmSyncobjDestroy(xwl_gbm->drm_fd, xwl_syncobj->handle); ++ ++ free(xwl_syncobj); ++} ++ ++static void ++xwl_dri3_syncobj_eventfd(struct dri3_syncobj *syncobj, uint64_t point, ++ int efd, Bool wait_avail) ++{ ++ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj; ++ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ drmSyncobjEventfd(xwl_gbm->drm_fd, xwl_syncobj->handle, point, efd, ++ wait_avail ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0); ++} ++ ++static struct dri3_syncobj * ++xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle) ++{ ++ struct xwl_dri3_syncobj *syncobj = calloc(1, sizeof (*syncobj)); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ ++ if (!syncobj) ++ return NULL; ++ ++ syncobj->handle = handle; ++ syncobj->base.screen = xwl_screen->screen; ++ syncobj->base.refcount = 1; ++ ++ syncobj->base.free = xwl_dri3_free_syncobj; ++ syncobj->base.check = xwl_dri3_check_syncobj; ++ syncobj->base.export_fence = xwl_dri3_syncobj_export_fence; ++ syncobj->base.import_fence = xwl_dri3_syncobj_import_fence; ++ syncobj->base.signal = xwl_dri3_signal_syncobj; ++ syncobj->base.eventfd = xwl_dri3_syncobj_eventfd; ++ return &syncobj->base; ++ ++fail: ++ free(syncobj); ++ return NULL; ++} ++ ++static struct dri3_syncobj * ++xwl_dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd) ++{ ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ struct xwl_dri3_syncobj *syncobj = NULL; ++ uint32_t handle; ++ ++ if (drmSyncobjFDToHandle(xwl_gbm->drm_fd, fd, &handle)) ++ return NULL; ++ ++ syncobj = (struct xwl_dri3_syncobj *)xwl_dri3_create_syncobj(xwl_screen, handle); ++ if (!syncobj) { ++ drmSyncobjDestroy(xwl_gbm->drm_fd, handle); ++ return NULL; ++ } ++ ++ syncobj->base.id = id; ++ ++ return &syncobj->base; ++} ++ ++static Bool ++xwl_gbm_supports_syncobjs(struct xwl_screen *xwl_screen) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ uint64_t syncobj_cap = 0; ++ ++ if (drmGetCap(xwl_gbm->drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, ++ &syncobj_cap) || !syncobj_cap) ++ return FALSE; ++ ++ /* Check if syncobj eventfd is supported. */ ++ drmSyncobjEventfd(xwl_gbm->drm_fd, 0, 0, -1, 0); ++ if (errno != ENOENT) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static dri3_screen_info_rec xwl_dri3_info = { + .version = 2, + .open = NULL, + .pixmap_from_fds = glamor_pixmap_from_fds, +@@ -820,6 +990,7 @@ static const dri3_screen_info_rec xwl_dri3_info = { + .get_formats = xwl_glamor_get_formats, + .get_modifiers = xwl_glamor_get_modifiers, + .get_drawable_modifiers = xwl_glamor_get_drawable_modifiers, ++ .import_syncobj = NULL, /* need to check for kernel support */ + }; + + static const char * +@@ -1182,6 +1353,11 @@ xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + ++ if (xwl_gbm_supports_syncobjs(xwl_screen)) { ++ xwl_dri3_info.version = 4; ++ xwl_dri3_info.import_syncobj = xwl_dri3_import_syncobj; ++ } ++ + if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) { + ErrorF("Failed to initialize dri3\n"); + goto error; +-- +GitLab + + +From f9025e551212cdda3571e3db53932e06fc9e22e0 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 16 Aug 2022 12:03:59 -0700 +Subject: [PATCH 4/5] Present: implement PresentPixmapSynced + +Adds support for an augmented version of PresentPixmap supporting +explicit synchronization with the GPU by way of a DRM synchronization +object. The new request will accept a previously imported timeline +syncobj along with acquire and release points on that timeline. + +If the backend reports support for PresentCapabilitySyncobj, the +syncobj, acquire, and release points will be attached to the vblank +structure for the present request, taking an extra reference to the +syncobj to ensure it is not freed before the request has completed. + +Initially, only the Xwayland backend will advertise +PresentCapabilitySyncobj, provided that the EGL driver supports the +ANDROID_native_fence_sync extension. + +Before executing a present request, if the given vblank has an attached +syncobj, we will first poll the acquire point. If it has not yet been +signaled, we will export the fence as a sync fd and add that to the +server's event loop. When the fence eventually is signaled, the request +will be re-executed. + +After executing a request, the release point must be signaled after any +GPU operations on the pixmap have completed. For flips, this can be done +as soon as the buffer has been released by the Wayland compositor (in +the case of Xwayland). For copies, we must insert a fence release into +the GPU command stream after the copy and transfer it to the syncobj. +This requires a new flush_fenced callback, which must be implemented by +any backends advertising PresentCapabilitySyncobj. This will perform the +same function as the current flush callback, but also return a sync fd +corresponding to the aforementioned fence. + +Signed-off-by: Erik Kurzinger +--- + hw/xfree86/common/xf86Module.h | 2 +- + hw/xwayland/xwayland-glamor.c | 24 +++++ + hw/xwayland/xwayland-glamor.h | 1 + + hw/xwayland/xwayland-present.c | 101 +++++++++++++++++--- + hw/xwayland/xwayland-present.h | 5 +- + hw/xwayland/xwayland-screen.h | 2 + + include/protocol-versions.h | 2 +- + present/present.c | 9 ++ + present/present_execute.c | 34 ++++++- + present/present_priv.h | 25 +++++ + present/present_request.c | 169 ++++++++++++++++++++++++++------- + present/present_scmd.c | 8 ++ + present/present_screen.c | 1 + + present/present_vblank.c | 36 +++++++ + 14 files changed, 368 insertions(+), 51 deletions(-) + +diff --git a/hw/xfree86/common/xf86Module.h b/hw/xfree86/common/xf86Module.h +index 6166e85590..b6eb806228 100644 +--- a/hw/xfree86/common/xf86Module.h ++++ b/hw/xfree86/common/xf86Module.h +@@ -74,7 +74,7 @@ + * mask is 0xFFFF0000. + */ + #define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4) +-#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(26, 1) ++#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(27, 0) + #define ABI_XINPUT_VERSION SET_ABI_VERSION(24, 4) + #define ABI_EXTENSION_VERSION SET_ABI_VERSION(10, 0) + +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index c6aa8eb172..f9a4ef0b49 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -1074,6 +1074,30 @@ xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window) + return NullPixmap; + } + ++int ++xwl_glamor_get_fence(struct xwl_screen *xwl_screen) ++{ ++ EGLint attribs[3]; ++ EGLSyncKHR sync; ++ int fence_fd = -1; ++ ++ if (!xwl_screen->glamor) ++ return -1; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ ++ attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; ++ attribs[1] = EGL_NO_NATIVE_FENCE_FD_ANDROID; ++ attribs[2] = EGL_NONE; ++ sync = eglCreateSyncKHR(xwl_screen->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); ++ if (sync != EGL_NO_SYNC_KHR) { ++ fence_fd = eglDupNativeFenceFDANDROID(xwl_screen->egl_display, sync); ++ eglDestroySyncKHR(xwl_screen->egl_display, sync); ++ } ++ ++ return fence_fd; ++} ++ + void + xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream) + { +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index 183fe755ae..6f46043642 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -151,6 +151,7 @@ Bool xwl_glamor_get_drawable_modifiers(DrawablePtr drawable, uint32_t format, + uint32_t *num_modifiers, uint64_t **modifiers); + Bool xwl_glamor_check_flip(WindowPtr present_window, PixmapPtr pixmap); + PixmapPtr xwl_glamor_create_pixmap_for_window (struct xwl_window *xwl_window); ++int xwl_glamor_get_fence(struct xwl_screen *screen); + + #ifdef XV + /* glamor Xv Adaptor */ +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +index 5ede33e4cf..3a0c1d40f4 100644 +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -27,6 +27,7 @@ + + #include + #include ++#include + + #include "xwayland-present.h" + #include "xwayland-screen.h" +@@ -211,10 +212,18 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window) + static void + xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc); + ++static int ++xwl_present_queue_vblank(ScreenPtr screen, ++ WindowPtr present_window, ++ RRCrtcPtr crtc, ++ uint64_t event_id, ++ uint64_t msc); ++ + static uint32_t + xwl_present_query_capabilities(present_screen_priv_ptr screen_priv) + { +- return XWL_PRESENT_CAPS; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen_priv->pScreen); ++ return xwl_screen->present_capabilities; + } + + static int +@@ -233,6 +242,16 @@ xwl_present_get_ust_msc(ScreenPtr screen, + return Success; + } + ++static uint64_t ++xwl_present_get_exec_msc(uint32_t options, uint64_t target_msc) ++{ ++ /* Synchronous Xwayland presentations always complete (at least) one frame after they ++ * are executed ++ */ ++ return (options & PresentOptionAsyncMayTear) ? ++ target_msc : target_msc - 1; ++} ++ + /* + * When the wait fence or previous flip is completed, it's time + * to re-try the request +@@ -240,9 +259,27 @@ xwl_present_get_ust_msc(ScreenPtr screen, + static void + xwl_present_re_execute(present_vblank_ptr vblank) + { ++ struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); + uint64_t ust = 0, crtc_msc = 0; + + (void) xwl_present_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc); ++ /* re-compute target / exec msc */ ++ vblank->target_msc = present_get_target_msc(0, crtc_msc, ++ event->divisor, ++ event->remainder, ++ event->options); ++ vblank->exec_msc = xwl_present_get_exec_msc(event->options, ++ vblank->target_msc); ++ ++ vblank->queued = TRUE; ++ if (msc_is_after(vblank->exec_msc, crtc_msc) && ++ xwl_present_queue_vblank(vblank->screen, vblank->window, ++ vblank->crtc, ++ vblank->event_id, ++ vblank->exec_msc) == Success) { ++ return; ++ } ++ + xwl_present_execute(vblank, ust, crtc_msc); + } + +@@ -281,6 +318,10 @@ xwl_present_free_event(struct xwl_present_event *event) + static void + xwl_present_free_idle_vblank(present_vblank_ptr vblank) + { ++ if (vblank->release_syncobj) ++ vblank->release_syncobj->signal(vblank->release_syncobj, ++ vblank->release_point); ++ + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + xwl_present_free_event(xwl_present_event_from_vblank(vblank)); + } +@@ -440,6 +481,11 @@ xwl_present_buffer_release(void *data) + return; + + vblank = &event->vblank; ++ ++ if (vblank->release_syncobj) ++ vblank->release_syncobj->signal(vblank->release_syncobj, ++ vblank->release_point); ++ + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + + xwl_present_window = xwl_present_window_priv(vblank->window); +@@ -630,6 +676,15 @@ xwl_present_maybe_set_reason(struct xwl_window *xwl_window, PresentFlipReason *r + } + } + ++static int ++xwl_present_flush_fenced(WindowPtr window) ++{ ++ struct xwl_window *xwl_window = xwl_window_from_window(window); ++ int fence = xwl_glamor_get_fence(xwl_window->xwl_screen); ++ xwl_present_flush(window); ++ return fence; ++} ++ + static Bool + xwl_present_check_flip(RRCrtcPtr crtc, + WindowPtr present_window, +@@ -797,7 +852,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) + + if (xwl_window->tearing_control) { + uint32_t hint; +- if (event->async_may_tear) ++ if (event->options & PresentOptionAsyncMayTear) + hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; + else + hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC; +@@ -838,6 +893,7 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) + + xorg_list_del(&vblank->event_queue); + ++retry: + if (present_execute_wait(vblank, crtc_msc)) + return; + +@@ -898,6 +954,8 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) + } + + vblank->flip = FALSE; ++ /* re-execute, falling through to copy */ ++ goto retry; + } + DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", + vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id)); +@@ -934,6 +992,10 @@ xwl_present_pixmap(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + uint64_t target_window_msc, + uint64_t divisor, +@@ -950,11 +1012,17 @@ xwl_present_pixmap(WindowPtr window, + ScreenPtr screen = window->drawable.pScreen; + present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); + present_screen_priv_ptr screen_priv = present_screen_priv(screen); ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen_priv->pScreen); ++ uint32_t caps = xwl_screen->present_capabilities; + struct xwl_present_event *event; + + if (!window_priv) + return BadAlloc; + ++ if (!(caps & PresentCapabilitySyncobj) && ++ (acquire_syncobj || release_syncobj)) ++ return BadValue; ++ + target_crtc = xwl_present_get_crtc(screen_priv, window); + + ret = xwl_present_get_ust_msc(screen, window, &ust, &crtc_msc); +@@ -989,6 +1057,10 @@ xwl_present_pixmap(WindowPtr window, + if (vblank->target_msc != target_msc) + continue; + ++ if (vblank->release_syncobj) ++ vblank->release_syncobj->signal(vblank->release_syncobj, ++ vblank->release_point); ++ + present_vblank_scrap(vblank); + if (vblank->flip_ready) + xwl_present_re_execute(vblank); +@@ -1001,22 +1073,18 @@ xwl_present_pixmap(WindowPtr window, + + vblank = &event->vblank; + if (!present_vblank_init(vblank, window, pixmap, serial, valid, update, x_off, y_off, +- target_crtc, wait_fence, idle_fence, options, XWL_PRESENT_CAPS, +- notifies, num_notifies, target_msc, crtc_msc)) { ++ target_crtc, wait_fence, idle_fence, ++ acquire_syncobj, release_syncobj, acquire_point, release_point, ++ options, caps, notifies, num_notifies, target_msc, crtc_msc)) { + present_vblank_destroy(vblank); + return BadAlloc; + } + + vblank->event_id = ++xwl_present_event_id; +- event->async_may_tear = options & PresentOptionAsyncMayTear; +- +- /* Synchronous Xwayland presentations always complete (at least) one frame after they +- * are executed +- */ +- if (event->async_may_tear) +- vblank->exec_msc = vblank->target_msc; +- else +- vblank->exec_msc = vblank->target_msc - 1; ++ event->options = options; ++ event->divisor = divisor; ++ event->remainder = remainder; ++ vblank->exec_msc = xwl_present_get_exec_msc(options, vblank->target_msc); + + vblank->queued = TRUE; + if (crtc_msc < vblank->exec_msc) { +@@ -1065,6 +1133,12 @@ xwl_present_init(ScreenPtr screen) + if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0)) + return FALSE; + ++ xwl_screen->present_capabilities = XWL_PRESENT_CAPS; ++ if (epoxy_has_egl_extension(xwl_screen->egl_display, ++ "ANDROID_native_fence_sync")) ++ xwl_screen->present_capabilities |= ++ PresentCapabilitySyncobj; ++ + screen_priv->query_capabilities = xwl_present_query_capabilities; + screen_priv->get_crtc = xwl_present_get_crtc; + +@@ -1075,6 +1149,7 @@ xwl_present_init(ScreenPtr screen) + screen_priv->present_pixmap = xwl_present_pixmap; + screen_priv->queue_vblank = xwl_present_queue_vblank; + screen_priv->flush = xwl_present_flush; ++ screen_priv->flush_fenced = xwl_present_flush_fenced; + screen_priv->re_execute = xwl_present_re_execute; + + screen_priv->abort_vblank = xwl_present_abort_vblank; +diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h +index 4fd1e579ff..8a6f11ec4e 100644 +--- a/hw/xwayland/xwayland-present.h ++++ b/hw/xwayland/xwayland-present.h +@@ -59,7 +59,10 @@ struct xwl_present_event { + present_vblank_rec vblank; + + PixmapPtr pixmap; +- Bool async_may_tear; ++ Bool released; ++ uint32_t options; ++ uint64_t divisor; ++ uint64_t remainder; + }; + + Bool xwl_present_entered_for_each_frame_callback(void); +diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h +index 94033aabf9..97af13baeb 100644 +--- a/hw/xwayland/xwayland-screen.h ++++ b/hw/xwayland/xwayland-screen.h +@@ -144,6 +144,8 @@ struct xwl_screen { + int libdecor_fd; + struct libdecor *libdecor_context; + #endif ++ ++ uint32_t present_capabilities; + }; + + /* Apps which use randr/vidmode to change the mode when going fullscreen, +diff --git a/include/protocol-versions.h b/include/protocol-versions.h +index ffd7d0e239..e28e2384d8 100644 +--- a/include/protocol-versions.h ++++ b/include/protocol-versions.h +@@ -69,7 +69,7 @@ + + /* Present */ + #define SERVER_PRESENT_MAJOR_VERSION 1 +-#define SERVER_PRESENT_MINOR_VERSION 2 ++#define SERVER_PRESENT_MINOR_VERSION 4 + + /* RandR */ + #define SERVER_RANDR_MAJOR_VERSION 1 +diff --git a/present/present.c b/present/present.c +index 211868341d..e0764fab1f 100644 +--- a/present/present.c ++++ b/present/present.c +@@ -230,6 +230,10 @@ present_pixmap(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + uint64_t window_msc, + uint64_t divisor, +@@ -250,6 +254,10 @@ present_pixmap(WindowPtr window, + target_crtc, + wait_fence, + idle_fence, ++ acquire_syncobj, ++ release_syncobj, ++ acquire_point, ++ release_point, + options, + window_msc, + divisor, +@@ -272,6 +280,7 @@ present_notify_msc(WindowPtr window, + 0, 0, + NULL, + NULL, NULL, ++ NULL, NULL, 0, 0, + divisor == 0 ? PresentOptionAsync : 0, + target_msc, divisor, remainder, NULL, 0); + } +diff --git a/present/present_execute.c b/present/present_execute.c +index 68a5878be9..795c70c88c 100644 +--- a/present/present_execute.c ++++ b/present/present_execute.c +@@ -21,6 +21,7 @@ + */ + + #include "present_priv.h" ++#include + + /* + * Called when the wait fence is triggered; just gets the current msc/ust and +@@ -37,6 +38,21 @@ present_wait_fence_triggered(void *param) + screen_priv->re_execute(vblank); + } + ++static void present_syncobj_triggered(int fd, int xevents, void *data) ++{ ++ present_vblank_ptr vblank = data; ++ ScreenPtr screen = vblank->screen; ++ present_screen_priv_ptr screen_priv = present_screen_priv(screen); ++ uint64_t efd_value; ++ ++ read(fd, &efd_value, sizeof (efd_value)); ++ SetNotifyFd(fd, NULL, 0, NULL); ++ close(fd); ++ vblank->efd = -1; ++ ++ screen_priv->re_execute(vblank); ++} ++ + Bool + present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) + { +@@ -58,6 +74,16 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) + return TRUE; + } + } ++ ++ if (vblank->acquire_syncobj && !vblank->acquire_syncobj->check(vblank->acquire_syncobj, ++ vblank->acquire_point)) { ++ vblank->efd = eventfd(0, EFD_CLOEXEC); ++ SetNotifyFd(vblank->efd, present_syncobj_triggered, X_NOTIFY_READ, vblank); ++ vblank->acquire_syncobj->eventfd(vblank->acquire_syncobj, vblank->acquire_point, ++ vblank->efd, FALSE /* wait_avail */); ++ return TRUE; ++ } ++ + return FALSE; + } + +@@ -85,7 +111,13 @@ present_execute_copy(present_vblank_ptr vblank, uint64_t crtc_msc) + * which is then freed, freeing the region + */ + vblank->update = NULL; +- screen_priv->flush(window); ++ if (vblank->release_syncobj) { ++ int fence_fd = screen_priv->flush_fenced(window); ++ vblank->release_syncobj->import_fence(vblank->release_syncobj, ++ vblank->release_point, fence_fd); ++ } else { ++ screen_priv->flush(window); ++ } + + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + } +diff --git a/present/present_priv.h b/present/present_priv.h +index 4ad7298647..727d523109 100644 +--- a/present/present_priv.h ++++ b/present/present_priv.h +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include "dri3.h" + + #if 0 + #define DebugPresent(x) ErrorF x +@@ -90,6 +91,11 @@ struct present_vblank { + Bool abort_flip; /* aborting this flip */ + PresentFlipReason reason; /* reason for which flip is not possible */ + Bool has_suboptimal; /* whether client can support SuboptimalCopy mode */ ++ struct dri3_syncobj *acquire_syncobj; ++ struct dri3_syncobj *release_syncobj; ++ uint64_t acquire_point; ++ uint64_t release_point; ++ int efd; + }; + + typedef struct present_screen_priv present_screen_priv_rec, *present_screen_priv_ptr; +@@ -124,6 +130,10 @@ typedef int (*present_priv_pixmap_ptr)(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + uint64_t window_msc, + uint64_t divisor, +@@ -137,6 +147,7 @@ typedef int (*present_priv_queue_vblank_ptr)(ScreenPtr screen, + uint64_t event_id, + uint64_t msc); + typedef void (*present_priv_flush_ptr)(WindowPtr window); ++typedef int (*present_priv_flush_fenced_ptr)(WindowPtr window); + typedef void (*present_priv_re_execute_ptr)(present_vblank_ptr vblank); + + typedef void (*present_priv_abort_vblank_ptr)(ScreenPtr screen, +@@ -147,6 +158,7 @@ typedef void (*present_priv_abort_vblank_ptr)(ScreenPtr screen, + typedef void (*present_priv_flip_destroy_ptr)(ScreenPtr screen); + + struct present_screen_priv { ++ ScreenPtr pScreen; + CloseScreenProcPtr CloseScreen; + ConfigNotifyProcPtr ConfigNotify; + DestroyWindowProcPtr DestroyWindow; +@@ -180,6 +192,7 @@ struct present_screen_priv { + + present_priv_queue_vblank_ptr queue_vblank; + present_priv_flush_ptr flush; ++ present_priv_flush_fenced_ptr flush_fenced; + present_priv_re_execute_ptr re_execute; + + present_priv_abort_vblank_ptr abort_vblank; +@@ -290,6 +303,10 @@ present_pixmap(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + uint64_t target_msc, + uint64_t divisor, +@@ -464,6 +481,10 @@ present_vblank_init(present_vblank_ptr vblank, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + const uint32_t capabilities, + present_notify_ptr notifies, +@@ -482,6 +503,10 @@ present_vblank_create(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + const uint32_t capabilities, + present_notify_ptr notifies, +diff --git a/present/present_request.c b/present/present_request.c +index f3e5679b5d..1f4f8a4dc3 100644 +--- a/present/present_request.c ++++ b/present/present_request.c +@@ -79,79 +79,121 @@ proc_present_query_version(ClientPtr client) + } while (0) + + static int +-proc_present_pixmap(ClientPtr client) ++proc_present_pixmap_common(ClientPtr client, ++ Window req_window, ++ Pixmap req_pixmap, ++ CARD32 req_serial, ++ CARD32 req_valid, ++ CARD32 req_update, ++ INT16 req_x_off, ++ INT16 req_y_off, ++ CARD32 req_target_crtc, ++ XSyncFence req_wait_fence, ++ XSyncFence req_idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ CARD64 req_acquire_point, ++ CARD64 req_release_point, ++ CARD32 req_options, ++ CARD64 req_target_msc, ++ CARD64 req_divisor, ++ CARD64 req_remainder, ++ size_t base_req_size, ++ xPresentNotify *req_notifies) + { +- REQUEST(xPresentPixmapReq); +- WindowPtr window; +- PixmapPtr pixmap; +- RegionPtr valid = NULL; +- RegionPtr update = NULL; +- SyncFence *wait_fence; +- SyncFence *idle_fence; +- RRCrtcPtr target_crtc; +- int ret; +- int nnotifies; +- present_notify_ptr notifies = NULL; +- +- REQUEST_AT_LEAST_SIZE(xPresentPixmapReq); +- ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess); ++ WindowPtr window; ++ PixmapPtr pixmap; ++ RegionPtr valid = NULL; ++ RegionPtr update = NULL; ++ RRCrtcPtr target_crtc; ++ SyncFence *wait_fence; ++ SyncFence *idle_fence; ++ int nnotifies; ++ present_notify_ptr notifies = NULL; ++ int ret; ++ ++ ret = dixLookupWindow(&window, req_window, client, DixWriteAccess); + if (ret != Success) + return ret; +- ret = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess); ++ ret = dixLookupResourceByType((void **) &pixmap, req_pixmap, RT_PIXMAP, client, DixReadAccess); + if (ret != Success) + return ret; + + if (window->drawable.depth != pixmap->drawable.depth) + return BadMatch; + +- VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess); +- VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess); ++ VERIFY_REGION_OR_NONE(valid, req_valid, client, DixReadAccess); ++ VERIFY_REGION_OR_NONE(update, req_update, client, DixReadAccess); ++ ++ VERIFY_CRTC_OR_NONE(target_crtc, req_target_crtc, client, DixReadAccess); + +- VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess); ++ VERIFY_FENCE_OR_NONE(wait_fence, req_wait_fence, client, DixReadAccess); ++ VERIFY_FENCE_OR_NONE(idle_fence, req_idle_fence, client, DixWriteAccess); + +- VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess); +- VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess); ++ if ((acquire_syncobj && req_acquire_point == 0) || ++ (release_syncobj && req_release_point == 0)) ++ return BadValue; + +- if (stuff->options & ~(PresentAllOptions)) { +- client->errorValue = stuff->options; ++ if (req_options & ~(PresentAllOptions)) { ++ client->errorValue = req_options; + return BadValue; + } + + /* + * Check to see if remainder is sane + */ +- if (stuff->divisor == 0) { +- if (stuff->remainder != 0) { +- client->errorValue = (CARD32) stuff->remainder; ++ if (req_divisor == 0) { ++ if (req_remainder != 0) { ++ client->errorValue = (CARD32)req_remainder; + return BadValue; + } + } else { +- if (stuff->remainder >= stuff->divisor) { +- client->errorValue = (CARD32) stuff->remainder; ++ if (req_remainder >= req_divisor) { ++ client->errorValue = (CARD32)req_remainder; + return BadValue; + } + } + +- nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq); ++ nnotifies = (client->req_len << 2) - base_req_size; + if (nnotifies % sizeof (xPresentNotify)) + return BadLength; + + nnotifies /= sizeof (xPresentNotify); + if (nnotifies) { +- ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), ¬ifies); ++ ret = present_create_notifies(client, nnotifies, req_notifies, ¬ifies); + if (ret != Success) + return ret; + } + +- ret = present_pixmap(window, pixmap, stuff->serial, valid, update, +- stuff->x_off, stuff->y_off, target_crtc, +- wait_fence, idle_fence, stuff->options, +- stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies); ++ ret = present_pixmap(window, pixmap, req_serial, ++ valid, update, req_x_off, req_y_off, target_crtc, ++ wait_fence, idle_fence, ++ acquire_syncobj, release_syncobj, ++ req_acquire_point, req_release_point, ++ req_options, req_target_msc, req_divisor, req_remainder, ++ notifies, nnotifies); ++ + if (ret != Success) + present_destroy_notifies(notifies, nnotifies); + return ret; + } + ++static int ++proc_present_pixmap(ClientPtr client) ++{ ++ REQUEST(xPresentPixmapReq); ++ REQUEST_AT_LEAST_SIZE(xPresentPixmapReq); ++ return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial, ++ stuff->valid, stuff->update, stuff->x_off, stuff->y_off, ++ stuff->target_crtc, ++ stuff->wait_fence, stuff->idle_fence, ++ None, None, 0, 0, ++ stuff->options, stuff->target_msc, ++ stuff->divisor, stuff->remainder, ++ sizeof (xPresentPixmapReq), ++ (xPresentNotify *)(stuff + 1)); ++} ++ + static int + proc_present_notify_msc(ClientPtr client) + { +@@ -240,12 +282,36 @@ proc_present_query_capabilities (ClientPtr client) + return Success; + } + ++static int ++proc_present_pixmap_synced (ClientPtr client) ++{ ++ REQUEST(xPresentPixmapSyncedReq); ++ struct dri3_syncobj *acquire_syncobj; ++ struct dri3_syncobj *release_syncobj; ++ ++ REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq); ++ VERIFY_DRI3_SYNCOBJ(stuff->acquire_syncobj, acquire_syncobj, DixWriteAccess); ++ VERIFY_DRI3_SYNCOBJ(stuff->release_syncobj, release_syncobj, DixWriteAccess); ++ ++ return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial, ++ stuff->valid, stuff->update, stuff->x_off, stuff->y_off, ++ stuff->target_crtc, ++ None, None, ++ acquire_syncobj, release_syncobj, ++ stuff->acquire_point, stuff->release_point, ++ stuff->options, stuff->target_msc, ++ stuff->divisor, stuff->remainder, ++ sizeof (xPresentPixmapSyncedReq), ++ (xPresentNotify *)(stuff + 1)); ++} ++ + static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = { + proc_present_query_version, /* 0 */ + proc_present_pixmap, /* 1 */ + proc_present_notify_msc, /* 2 */ + proc_present_select_input, /* 3 */ + proc_present_query_capabilities, /* 4 */ ++ proc_present_pixmap_synced, /* 5 */ + }; + + int +@@ -325,12 +391,47 @@ sproc_present_query_capabilities (ClientPtr client) + return (*proc_present_vector[stuff->presentReqType]) (client); + } + ++ ++static int _X_COLD ++sproc_present_pixmap_synced(ClientPtr client) ++{ ++ REQUEST(xPresentPixmapSyncedReq); ++ REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq); ++ ++ swaps(&stuff->length); ++ ++ swapl(&stuff->window); ++ ++ swapl(&stuff->pixmap); ++ swapl(&stuff->serial); ++ ++ swapl(&stuff->valid); ++ swapl(&stuff->update); ++ ++ swaps(&stuff->x_off); ++ swaps(&stuff->y_off); ++ swapl(&stuff->target_crtc); ++ ++ swapl(&stuff->acquire_syncobj); ++ swapl(&stuff->release_syncobj); ++ swapll(&stuff->acquire_point); ++ swapll(&stuff->release_point); ++ ++ swapl(&stuff->options); ++ ++ swapll(&stuff->target_msc); ++ swapll(&stuff->divisor); ++ swapll(&stuff->remainder); ++ return (*proc_present_vector[stuff->presentReqType]) (client); ++} ++ + static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = { + sproc_present_query_version, /* 0 */ + sproc_present_pixmap, /* 1 */ + sproc_present_notify_msc, /* 2 */ + sproc_present_select_input, /* 3 */ + sproc_present_query_capabilities, /* 4 */ ++ sproc_present_pixmap_synced, /* 5 */ + }; + + int _X_COLD +diff --git a/present/present_scmd.c b/present/present_scmd.c +index d378f00167..07dd41cd69 100644 +--- a/present/present_scmd.c ++++ b/present/present_scmd.c +@@ -738,6 +738,10 @@ present_scmd_pixmap(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + uint64_t target_window_msc, + uint64_t divisor, +@@ -824,6 +828,10 @@ present_scmd_pixmap(WindowPtr window, + target_crtc, + wait_fence, + idle_fence, ++ acquire_syncobj, ++ release_syncobj, ++ acquire_point, ++ release_point, + options, + screen_priv->info ? screen_priv->info->capabilities : 0, + notifies, +diff --git a/present/present_screen.c b/present/present_screen.c +index 2c29aafd23..df6a6a215e 100644 +--- a/present/present_screen.c ++++ b/present/present_screen.c +@@ -187,6 +187,7 @@ present_screen_priv_init(ScreenPtr screen) + wrap(screen_priv, screen, ClipNotify, present_clip_notify); + + dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv); ++ screen_priv->pScreen = screen; + + return screen_priv; + } +diff --git a/present/present_vblank.c b/present/present_vblank.c +index 4f94f16e44..2eb57abfff 100644 +--- a/present/present_vblank.c ++++ b/present/present_vblank.c +@@ -55,6 +55,10 @@ present_vblank_init(present_vblank_ptr vblank, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + const uint32_t capabilities, + present_notify_ptr notifies, +@@ -106,6 +110,7 @@ present_vblank_init(present_vblank_ptr vblank, + vblank->notifies = notifies; + vblank->num_notifies = num_notifies; + vblank->has_suboptimal = (options & PresentOptionSuboptimal); ++ vblank->efd = -1; + + if (pixmap != NULL && + !(options & PresentOptionCopy) && +@@ -135,6 +140,18 @@ present_vblank_init(present_vblank_ptr vblank, + goto no_mem; + } + ++ if (acquire_syncobj) { ++ vblank->acquire_syncobj = acquire_syncobj; ++ ++acquire_syncobj->refcount; ++ vblank->acquire_point = acquire_point; ++ } ++ ++ if (release_syncobj) { ++ vblank->release_syncobj = release_syncobj; ++ ++release_syncobj->refcount; ++ vblank->release_point = release_point; ++ } ++ + if (pixmap) + DebugPresent(("q %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p) flip %d vsync %d serial %d\n", + vblank->event_id, vblank, target_msc, +@@ -158,6 +175,10 @@ present_vblank_create(WindowPtr window, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point, + uint32_t options, + const uint32_t capabilities, + present_notify_ptr notifies, +@@ -172,6 +193,8 @@ present_vblank_create(WindowPtr window, + + if (present_vblank_init(vblank, window, pixmap, serial, valid, update, + x_off, y_off, target_crtc, wait_fence, idle_fence, ++ acquire_syncobj, release_syncobj, ++ acquire_point, release_point, + options, capabilities, notifies, num_notifies, + target_msc, crtc_msc)) + return vblank; +@@ -229,5 +252,18 @@ present_vblank_destroy(present_vblank_ptr vblank) + if (vblank->notifies) + present_destroy_notifies(vblank->notifies, vblank->num_notifies); + ++ if (vblank->efd >= 0) { ++ SetNotifyFd(vblank->efd, NULL, 0, NULL); ++ close(vblank->efd); ++ } ++ ++ if (vblank->acquire_syncobj && ++ --vblank->acquire_syncobj->refcount == 0) ++ vblank->acquire_syncobj->free(vblank->acquire_syncobj); ++ ++ if (vblank->release_syncobj && ++ --vblank->release_syncobj->refcount == 0) ++ vblank->release_syncobj->free(vblank->release_syncobj); ++ + free(vblank); + } +-- +GitLab + + +From d7efe16f0b2a7989881dfd47773dd9fc09f6cd21 Mon Sep 17 00:00:00 2001 +From: Erik Kurzinger +Date: Tue, 15 Aug 2023 15:32:47 -0700 +Subject: [PATCH 5/5] xwayland: add support for wp_linux_drm_syncobj_v1 + +This protocol allows for explicit synchronization of GPU operations by +Wayland clients and the compositor. Xwayland can make use of this to +ensure any rendering it initiates has completed before the target image +is accessed by the compositor, without having to rely on kernel-level +implicit synchronization. + +Furthermore, for X11 clients that also support explicit synchronization +using the mechanisms exposed in the DRI3 and Present extensions, this +Wayland protocol allows us to simply forward the timeline, acquire, and +release points directly to the compositor, ideally avoiding any +premature stalls in the presentation pipeline. + +Signed-off-by: Erik Kurzinger +--- + hw/xwayland/meson.build | 3 + + hw/xwayland/xwayland-glamor-gbm.c | 174 +++++++++++++++++++++++++- + hw/xwayland/xwayland-glamor.c | 84 +++++++++++++ + hw/xwayland/xwayland-glamor.h | 26 ++++ + hw/xwayland/xwayland-present.c | 51 ++++++-- + hw/xwayland/xwayland-present.h | 1 - + hw/xwayland/xwayland-screen.c | 1 + + hw/xwayland/xwayland-screen.h | 7 ++ + hw/xwayland/xwayland-window-buffers.c | 68 ++++++++++ + hw/xwayland/xwayland-window.c | 11 ++ + hw/xwayland/xwayland-window.h | 1 + + present/present_execute.c | 7 +- + 12 files changed, 420 insertions(+), 14 deletions(-) + +diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build +index f2038ab7c3..434b0ceade 100644 +--- a/hw/xwayland/meson.build ++++ b/hw/xwayland/meson.build +@@ -49,6 +49,7 @@ drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml') + shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inhibit', 'keyboard-shortcuts-inhibit-unstable-v1.xml') + xwayland_shell_xml = join_paths(protodir, 'staging', 'xwayland-shell', 'xwayland-shell-v1.xml') + tearing_xml = join_paths(protodir, 'staging', 'tearing-control', 'tearing-control-v1.xml') ++syncobj_xml = join_paths(protodir, 'staging', 'linux-drm-syncobj', 'linux-drm-syncobj-v1.xml') + + client_header = generator(scanner, + output : '@BASENAME@-client-protocol.h', +@@ -78,6 +79,7 @@ srcs += client_header.process(drm_lease_xml) + srcs += client_header.process(shortcuts_inhibit_xml) + srcs += client_header.process(xwayland_shell_xml) + srcs += client_header.process(tearing_xml) ++srcs += client_header.process(syncobj_xml) + srcs += code.process(relative_xml) + srcs += code.process(pointer_xml) + srcs += code.process(gestures_xml) +@@ -91,6 +93,7 @@ srcs += code.process(drm_lease_xml) + srcs += code.process(shortcuts_inhibit_xml) + srcs += code.process(xwayland_shell_xml) + srcs += code.process(tearing_xml) ++srcs += code.process(syncobj_xml) + + if build_ei + xwayland_dep += libei_dep +diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c +index 547a0999df..379de83629 100644 +--- a/hw/xwayland/xwayland-glamor-gbm.c ++++ b/hw/xwayland/xwayland-glamor-gbm.c +@@ -35,6 +35,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #define MESA_EGL_NO_X11_HEADERS + #define EGL_NO_X11 +@@ -51,6 +54,7 @@ + #include "xwayland-screen.h" + + #include "linux-dmabuf-unstable-v1-client-protocol.h" ++#include "linux-drm-syncobj-v1-client-protocol.h" + + struct xwl_gbm_private { + drmDevice *device; +@@ -553,6 +557,28 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap) + return xwl_pixmap->buffer; + } + ++static void ++xwl_screen_destroy_explicit_sync(struct xwl_screen *xwl_screen) ++{ ++ if (xwl_screen->glamor_syncobj) { ++ xwl_screen->glamor_syncobj->free(xwl_screen->glamor_syncobj); ++ xwl_screen->glamor_syncobj = NULL; ++ } ++ ++ if (xwl_screen->server_syncobj) { ++ xwl_screen->server_syncobj->free(xwl_screen->server_syncobj); ++ xwl_screen->server_syncobj = NULL; ++ } ++ ++ if (xwl_screen->explicit_sync) { ++ wp_linux_drm_syncobj_v1_destroy(xwl_screen->explicit_sync); ++ xwl_screen->explicit_sync = NULL; ++ } ++ ++ xwl_screen->glamor_timeline_point = 0; ++ xwl_screen->server_timeline_point = 0; ++} ++ + static void + xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) + { +@@ -567,6 +593,7 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) + wl_drm_destroy(xwl_gbm->drm); + if (xwl_gbm->gbm) + gbm_device_destroy(xwl_gbm->gbm); ++ xwl_screen_destroy_explicit_sync(xwl_screen); + + free(xwl_gbm); + } +@@ -811,12 +838,88 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, + return -1; + } + ++static int xwl_glamor_gbm_dmabuf_export_sync_file(PixmapPtr pixmap) ++{ ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ int num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); ++ int sync_file = -1; ++ int p; ++ ++ for (p = 0; p < num_planes; ++p) { ++ int plane_fd = gbm_bo_get_fd_for_plane(xwl_pixmap->bo, p); ++ struct dma_buf_export_sync_file export_args = { 0 }; ++ export_args.fd = -1; ++ export_args.flags = DMA_BUF_SYNC_READ; ++ drmIoctl(plane_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &export_args); ++ close(plane_fd); ++ if (sync_file == -1) { ++ sync_file = export_args.fd; ++ } else { ++ struct sync_merge_data merge_args = { 0 }; ++ merge_args.fd2 = export_args.fd; ++ ioctl(sync_file, SYNC_IOC_MERGE, &merge_args); ++ close(export_args.fd); ++ close(sync_file); ++ sync_file = merge_args.fence; ++ } ++ } ++ ++ return sync_file; ++} ++ ++static void xwl_glamor_gbm_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file) ++{ ++ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); ++ int num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); ++ int p; ++ ++ for (p = 0; p < num_planes; ++p) { ++ int plane_fd = gbm_bo_get_fd_for_plane(xwl_pixmap->bo, p); ++ struct dma_buf_import_sync_file import_args = { 0 }; ++ import_args.fd = sync_file; ++ import_args.flags = DMA_BUF_SYNC_READ; ++ drmIoctl(plane_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_args); ++ close(plane_fd); ++ } ++ close(sync_file); ++} ++ + struct xwl_dri3_syncobj + { + struct dri3_syncobj base; + uint32_t handle; ++ struct wp_linux_drm_syncobj_timeline_v1 *timeline; + }; + ++static void ++xwl_glamor_gbm_dri3_syncobj_passthrough(WindowPtr window, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point) ++{ ++ struct xwl_window *xwl_window = xwl_window_get(window); ++ struct xwl_screen *xwl_screen = xwl_window->xwl_screen; ++ struct xwl_dri3_syncobj *xwl_acquire_syncobj = (struct xwl_dri3_syncobj *)acquire_syncobj; ++ struct xwl_dri3_syncobj *xwl_release_syncobj = (struct xwl_dri3_syncobj *)release_syncobj; ++ uint32_t acquire_hi = acquire_point >> 32; ++ uint32_t acquire_lo = acquire_point & 0xffffffff; ++ uint32_t release_hi = release_point >> 32; ++ uint32_t release_lo = release_point & 0xffffffff; ++ ++ if (!xwl_window->surface_sync) ++ xwl_window->surface_sync = ++ wp_linux_drm_syncobj_v1_get_surface(xwl_screen->explicit_sync, ++ xwl_window->surface); ++ ++ wp_linux_drm_syncobj_surface_v1_set_acquire_point(xwl_window->surface_sync, ++ xwl_acquire_syncobj->timeline, ++ acquire_hi, acquire_lo); ++ wp_linux_drm_syncobj_surface_v1_set_release_point(xwl_window->surface_sync, ++ xwl_release_syncobj->timeline, ++ release_hi, release_lo); ++} ++ + static Bool + xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, uint64_t point) + { +@@ -897,6 +1000,9 @@ xwl_dri3_free_syncobj(struct dri3_syncobj *syncobj) + struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + ++ if (xwl_syncobj->timeline) ++ wp_linux_drm_syncobj_timeline_v1_destroy(xwl_syncobj->timeline); ++ + if (xwl_syncobj->handle) + drmSyncobjDestroy(xwl_gbm->drm_fd, xwl_syncobj->handle); + +@@ -920,10 +1026,23 @@ xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle) + { + struct xwl_dri3_syncobj *syncobj = calloc(1, sizeof (*syncobj)); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ int syncobj_fd = -1; + + if (!syncobj) + return NULL; + ++ if (xwl_screen->explicit_sync) { ++ if (drmSyncobjHandleToFD(xwl_gbm->drm_fd, handle, &syncobj_fd)) ++ goto fail; ++ ++ syncobj->timeline = ++ wp_linux_drm_syncobj_v1_import_timeline(xwl_screen->explicit_sync, ++ syncobj_fd); ++ close(syncobj_fd); ++ if (!syncobj->timeline) ++ goto fail; ++ } ++ + syncobj->handle = handle; + syncobj->base.screen = xwl_screen->screen; + syncobj->base.refcount = 1; +@@ -981,6 +1100,29 @@ xwl_gbm_supports_syncobjs(struct xwl_screen *xwl_screen) + return TRUE; + } + ++static Bool ++xwl_screen_init_explicit_sync(struct xwl_screen *xwl_screen) ++{ ++ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); ++ uint32_t glamor_syncobj_handle, server_syncobj_handle; ++ ++ if (!xwl_screen->explicit_sync) ++ return FALSE; ++ ++ if (drmSyncobjCreate(xwl_gbm->drm_fd, 0, &glamor_syncobj_handle) || ++ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &server_syncobj_handle)) ++ return FALSE; ++ ++ xwl_screen->glamor_syncobj = xwl_dri3_create_syncobj(xwl_screen, glamor_syncobj_handle); ++ xwl_screen->server_syncobj = xwl_dri3_create_syncobj(xwl_screen, server_syncobj_handle); ++ if (!xwl_screen->glamor_syncobj || !xwl_screen->server_syncobj) ++ return FALSE; ++ ++ xwl_screen->glamor_timeline_point = 1; ++ xwl_screen->server_timeline_point = 1; ++ return TRUE; ++} ++ + static dri3_screen_info_rec xwl_dri3_info = { + .version = 2, + .open = NULL, +@@ -1152,6 +1294,11 @@ xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen, + } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) { + xwl_screen_set_dmabuf_interface(xwl_screen, id, version); + return TRUE; ++ } else if (strcmp(name, "wp_linux_drm_syncobj_v1") == 0) { ++ xwl_screen->explicit_sync = ++ wl_registry_bind(xwl_screen->registry, id, ++ &wp_linux_drm_syncobj_v1_interface, ++ version); + } + + /* no match */ +@@ -1275,7 +1422,7 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + EGLint major, minor; + const GLubyte *renderer; +- const char *gbm_backend_name; ++ const char *gbm_backend_name, *egl_vendor; + + if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) { + ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n"); +@@ -1336,6 +1483,22 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) + if (gbm_backend_name && strcmp(gbm_backend_name, "drm") != 0) + xwl_screen->glvnd_vendor = gbm_backend_name; + ++ egl_vendor = eglQueryString(xwl_screen->egl_display, EGL_VENDOR); ++ /* NVIDIA driver does not support implicit sync */ ++ if (egl_vendor && strstr(egl_vendor, "NVIDIA")) ++ xwl_screen->gbm_backend.backend_flags &= ++ ~XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC; ++ ++ if (xwl_gbm_supports_syncobjs(xwl_screen) && ++ epoxy_has_egl_extension(xwl_screen->egl_display, ++ "ANDROID_native_fence_sync")) ++ xwl_screen->gbm_backend.backend_flags |= ++ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS; ++ ++ if (!xwl_glamor_supports_syncobjs(xwl_screen) || ++ !xwl_screen_init_explicit_sync(xwl_screen)) ++ xwl_screen_destroy_explicit_sync(xwl_screen); ++ + return TRUE; + error: + if (xwl_screen->egl_display != EGL_NO_DISPLAY) { +@@ -1353,7 +1516,7 @@ xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) + { + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + +- if (xwl_gbm_supports_syncobjs(xwl_screen)) { ++ if (xwl_glamor_supports_syncobjs(xwl_screen)) { + xwl_dri3_info.version = 4; + xwl_dri3_info.import_syncobj = xwl_dri3_import_syncobj; + } +@@ -1426,6 +1589,11 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) + xwl_screen->gbm_backend.get_main_device = xwl_gbm_get_main_device; + xwl_screen->gbm_backend.is_available = TRUE; + xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH | +- XWL_EGL_BACKEND_NEEDS_N_BUFFERING; ++ XWL_EGL_BACKEND_NEEDS_N_BUFFERING | ++ /* may be overriden during EGL initialization */ ++ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC; + xwl_screen->gbm_backend.create_pixmap_for_window = xwl_glamor_gbm_create_pixmap_for_window; ++ xwl_screen->gbm_backend.dmabuf_export_sync_file = xwl_glamor_gbm_dmabuf_export_sync_file; ++ xwl_screen->gbm_backend.dmabuf_import_sync_file = xwl_glamor_gbm_dmabuf_import_sync_file; ++ xwl_screen->gbm_backend.dri3_syncobj_passthrough = xwl_glamor_gbm_dri3_syncobj_passthrough; + } +diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c +index f9a4ef0b49..b4e912cb56 100644 +--- a/hw/xwayland/xwayland-glamor.c ++++ b/hw/xwayland/xwayland-glamor.c +@@ -1060,6 +1060,26 @@ xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen) + XWL_EGL_BACKEND_NEEDS_N_BUFFERING); + } + ++Bool ++xwl_glamor_supports_implicit_sync(struct xwl_screen *xwl_screen) ++{ ++ if (!xwl_screen->glamor || !xwl_screen->egl_backend) ++ return FALSE; ++ ++ return xwl_screen->egl_backend->backend_flags & ++ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC; ++} ++ ++Bool ++xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen) ++{ ++ if (!xwl_screen->glamor || !xwl_screen->egl_backend) ++ return FALSE; ++ ++ return xwl_screen->egl_backend->backend_flags & ++ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS; ++} ++ + PixmapPtr + xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window) + { +@@ -1098,6 +1118,70 @@ xwl_glamor_get_fence(struct xwl_screen *xwl_screen) + return fence_fd; + } + ++void ++xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence_fd) ++{ ++ EGLint attribs[3]; ++ EGLSyncKHR sync; ++ ++ if (!xwl_screen->glamor) ++ return; ++ ++ xwl_glamor_egl_make_current(xwl_screen); ++ ++ attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; ++ attribs[1] = fence_fd; ++ attribs[2] = EGL_NONE; ++ sync = eglCreateSyncKHR(xwl_screen->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); ++ if (sync != EGL_NO_SYNC_KHR) { ++ eglWaitSyncKHR(xwl_screen->egl_display, sync, 0); ++ eglDestroySyncKHR(xwl_screen->egl_display, sync); ++ } ++} ++ ++int ++xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap) ++{ ++ ScreenPtr screen = pixmap->drawable.pScreen; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ ++ if (xwl_screen->glamor && xwl_screen->egl_backend && ++ xwl_screen->egl_backend->dmabuf_export_sync_file) ++ return xwl_screen->egl_backend->dmabuf_export_sync_file(pixmap); ++ ++ return -1; ++} ++ ++void ++xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file) ++{ ++ ScreenPtr screen = pixmap->drawable.pScreen; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ ++ if (xwl_screen->glamor && xwl_screen->egl_backend && ++ xwl_screen->egl_backend->dmabuf_import_sync_file) ++ xwl_screen->egl_backend->dmabuf_import_sync_file(pixmap, sync_file); ++} ++ ++void ++xwl_glamor_dri3_syncobj_passthrough(WindowPtr window, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point) ++{ ++ ScreenPtr screen = window->drawable.pScreen; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); ++ ++ if (xwl_screen->glamor && xwl_screen->egl_backend && ++ xwl_screen->egl_backend->dri3_syncobj_passthrough) ++ xwl_screen->egl_backend->dri3_syncobj_passthrough(window, ++ acquire_syncobj, ++ release_syncobj, ++ acquire_point, ++ release_point); ++} ++ + void + xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream) + { +diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h +index 6f46043642..d1a8982b88 100644 +--- a/hw/xwayland/xwayland-glamor.h ++++ b/hw/xwayland/xwayland-glamor.h +@@ -34,11 +34,14 @@ + #include + + #include "xwayland-types.h" ++#include "dri3.h" + + typedef enum _xwl_egl_backend_flags { + XWL_EGL_BACKEND_NO_FLAG = 0, + XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 0), + XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 1), ++ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC = (1 << 2), ++ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS = (1 << 3), + } xwl_egl_backend_flags; + + struct xwl_egl_backend { +@@ -107,6 +110,19 @@ struct xwl_egl_backend { + + /* Direct hook to create the backing pixmap for a window */ + PixmapPtr (*create_pixmap_for_window)(struct xwl_window *xwl_window); ++ ++ /* Merge the implicit read fences of each plane into a sync file */ ++ int (*dmabuf_export_sync_file)(PixmapPtr pixmap); ++ ++ /* Sets the implicit read fence of each plane to the given sync file */ ++ void (*dmabuf_import_sync_file)(PixmapPtr pixmap, int sync_file); ++ ++ /* Sets the explicit sync acquire and release points for the given Window */ ++ void (*dri3_syncobj_passthrough)(WindowPtr window, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point); + }; + + #ifdef XWL_HAS_GLAMOR +@@ -135,6 +151,8 @@ Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window); + void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen); + Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen); ++Bool xwl_glamor_supports_implicit_sync(struct xwl_screen *xwl_screen); ++Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen); + Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen, + uint32_t format, uint64_t modifier); + uint32_t wl_drm_format_for_depth(int depth); +@@ -152,6 +170,14 @@ Bool xwl_glamor_get_drawable_modifiers(DrawablePtr drawable, uint32_t format, + Bool xwl_glamor_check_flip(WindowPtr present_window, PixmapPtr pixmap); + PixmapPtr xwl_glamor_create_pixmap_for_window (struct xwl_window *xwl_window); + int xwl_glamor_get_fence(struct xwl_screen *screen); ++void xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence); ++int xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap); ++void xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file); ++void xwl_glamor_dri3_syncobj_passthrough(WindowPtr window, ++ struct dri3_syncobj *acquire_syncobj, ++ struct dri3_syncobj *release_syncobj, ++ uint64_t acquire_point, ++ uint64_t release_point); + + #ifdef XV + /* glamor Xv Adaptor */ +diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c +index 3a0c1d40f4..fb1df379f7 100644 +--- a/hw/xwayland/xwayland-present.c ++++ b/hw/xwayland/xwayland-present.c +@@ -27,7 +27,6 @@ + + #include + #include +-#include + + #include "xwayland-present.h" + #include "xwayland-screen.h" +@@ -36,6 +35,7 @@ + #include "glamor.h" + + #include "tearing-control-v1-client-protocol.h" ++#include "linux-drm-syncobj-v1-client-protocol.h" + + #define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear + +@@ -474,6 +474,7 @@ static void + xwl_present_buffer_release(void *data) + { + struct xwl_present_window *xwl_present_window; ++ struct xwl_screen *xwl_screen; + struct xwl_present_event *event = data; + present_vblank_ptr vblank; + +@@ -482,9 +483,14 @@ xwl_present_buffer_release(void *data) + + vblank = &event->vblank; + +- if (vblank->release_syncobj) +- vblank->release_syncobj->signal(vblank->release_syncobj, +- vblank->release_point); ++ xwl_screen = xwl_screen_get(vblank->screen); ++ if (vblank->release_syncobj && !xwl_screen->explicit_sync) { ++ /* transfer implicit fence to release syncobj */ ++ int fence_fd = xwl_glamor_dmabuf_export_sync_file(vblank->pixmap); ++ vblank->release_syncobj->import_fence(vblank->release_syncobj, ++ vblank->release_point, ++ fence_fd); ++ } + + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + +@@ -698,6 +704,7 @@ xwl_present_check_flip(RRCrtcPtr crtc, + WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(present_window); + struct xwl_window *xwl_window = xwl_window_from_window(present_window); + ScreenPtr screen = pixmap->drawable.pScreen; ++ struct xwl_screen *xwl_screen = xwl_screen_get(screen); + + if (reason) + *reason = PRESENT_FLIP_REASON_UNKNOWN; +@@ -734,6 +741,13 @@ xwl_present_check_flip(RRCrtcPtr crtc, + if (!xwl_glamor_check_flip(present_window, pixmap)) + return FALSE; + ++ /* If glamor doesn't support implicit sync and the compositor doesn't ++ * support explicit sync, we cannot flip ++ */ ++ if (!xwl_glamor_supports_implicit_sync(xwl_screen) && ++ !xwl_screen->explicit_sync) ++ return FALSE; ++ + /* Can't flip if the window pixmap doesn't match the xwl_window parent + * window's, e.g. because a client redirected this window or one of its + * parents. +@@ -812,6 +826,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) + PixmapPtr pixmap = vblank->pixmap; + struct xwl_window *xwl_window = xwl_window_from_window(present_window); + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window); ++ struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + BoxPtr damage_box; + struct wl_buffer *buffer; + struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); +@@ -831,6 +846,28 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) + + event->pixmap = pixmap; + ++ assert(xwl_glamor_supports_implicit_sync(xwl_screen) || ++ xwl_screen->explicit_sync); ++ ++ if (vblank->acquire_syncobj && vblank->release_syncobj) { ++ if (xwl_screen->explicit_sync) ++ xwl_glamor_dri3_syncobj_passthrough(present_window, ++ vblank->acquire_syncobj, ++ vblank->release_syncobj, ++ vblank->acquire_point, ++ vblank->release_point); ++ else { ++ /* transfer from acquire syncobj to implicit fence */ ++ int fence_fd = ++ vblank->acquire_syncobj->export_fence(vblank->acquire_syncobj, ++ vblank->acquire_point); ++ xwl_glamor_dmabuf_import_sync_file(vblank->pixmap, fence_fd); ++ } ++ } else if (xwl_window->surface_sync) { ++ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync); ++ xwl_window->surface_sync = NULL; ++ } ++ + xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event); + + /* We can flip directly to the main surface (full screen window without clips) */ +@@ -1134,10 +1171,8 @@ xwl_present_init(ScreenPtr screen) + return FALSE; + + xwl_screen->present_capabilities = XWL_PRESENT_CAPS; +- if (epoxy_has_egl_extension(xwl_screen->egl_display, +- "ANDROID_native_fence_sync")) +- xwl_screen->present_capabilities |= +- PresentCapabilitySyncobj; ++ if (xwl_glamor_supports_syncobjs(xwl_screen)) ++ xwl_screen->present_capabilities |= PresentCapabilitySyncobj; + + screen_priv->query_capabilities = xwl_present_query_capabilities; + screen_priv->get_crtc = xwl_present_get_crtc; +diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h +index 8a6f11ec4e..ffc16f52e6 100644 +--- a/hw/xwayland/xwayland-present.h ++++ b/hw/xwayland/xwayland-present.h +@@ -59,7 +59,6 @@ struct xwl_present_event { + present_vblank_rec vblank; + + PixmapPtr pixmap; +- Bool released; + uint32_t options; + uint64_t divisor; + uint64_t remainder; +diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c +index 6b57fbe9d7..5845c6f757 100644 +--- a/hw/xwayland/xwayland-screen.c ++++ b/hw/xwayland/xwayland-screen.c +@@ -64,6 +64,7 @@ + #include "xdg-shell-client-protocol.h" + #include "xwayland-shell-v1-client-protocol.h" + #include "tearing-control-v1-client-protocol.h" ++#include "linux-drm-syncobj-v1-client-protocol.h" + + static DevPrivateKeyRec xwl_screen_private_key; + static DevPrivateKeyRec xwl_client_private_key; +diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h +index 97af13baeb..a593f01d35 100644 +--- a/hw/xwayland/xwayland-screen.h ++++ b/hw/xwayland/xwayland-screen.h +@@ -110,6 +110,7 @@ struct xwl_screen { + struct wp_viewporter *viewporter; + struct xwayland_shell_v1 *xwayland_shell; + struct wp_tearing_control_manager_v1 *tearing_control_manager; ++ struct wp_linux_drm_syncobj_v1 *explicit_sync; + struct xorg_list drm_lease_devices; + struct xorg_list queued_drm_lease_devices; + struct xorg_list drm_leases; +@@ -146,6 +147,12 @@ struct xwl_screen { + #endif + + uint32_t present_capabilities; ++ ++ /* For use with explicit sync */ ++ struct dri3_syncobj *glamor_syncobj; ++ struct dri3_syncobj *server_syncobj; ++ uint64_t glamor_timeline_point; ++ uint64_t server_timeline_point; + }; + + /* Apps which use randr/vidmode to change the mode when going fullscreen, +diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c +index f7bb571bbf..0b7cb5d160 100644 +--- a/hw/xwayland/xwayland-window-buffers.c ++++ b/hw/xwayland/xwayland-window-buffers.c +@@ -32,6 +32,13 @@ + #include "xwayland-pixmap.h" + #include "xwayland-screen.h" + #include "xwayland-window-buffers.h" ++#include "dri3.h" ++#ifdef XWL_HAS_GLAMOR ++#include "glamor.h" ++#endif ++ ++#include ++#include + + #define BUFFER_TIMEOUT 1 * 1000 /* ms */ + +@@ -40,6 +47,8 @@ struct xwl_window_buffer { + PixmapPtr pixmap; + RegionPtr damage_region; + Bool recycle_on_release; ++ uint64_t release_point; ++ int sync_fd; + int refcnt; + uint32_t time; + struct xorg_list link_buffer; +@@ -80,6 +89,7 @@ xwl_window_buffer_new(struct xwl_window *xwl_window) + xwl_window_buffer->xwl_window = xwl_window; + xwl_window_buffer->damage_region = RegionCreate(NullBox, 1); + xwl_window_buffer->pixmap = NullPixmap; ++ xwl_window_buffer->sync_fd = -1; + xwl_window_buffer->refcnt = 1; + + xorg_list_append(&xwl_window_buffer->link_buffer, +@@ -111,6 +121,9 @@ xwl_window_buffer_dispose(struct xwl_window_buffer *xwl_window_buffer) + if (xwl_window_buffer->pixmap) + xwl_window_buffer_destroy_pixmap (xwl_window_buffer); + ++ if (xwl_window_buffer->sync_fd >= 0) ++ close(xwl_window_buffer->sync_fd); ++ + xorg_list_del(&xwl_window_buffer->link_buffer); + free(xwl_window_buffer); + +@@ -194,6 +207,7 @@ xwl_window_buffer_release_callback(void *data) + { + struct xwl_window_buffer *xwl_window_buffer = data; + struct xwl_window *xwl_window = xwl_window_buffer->xwl_window; ++ struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_window_buffer *oldest_available_buffer; + + /* Drop the reference on the buffer we took in get_pixmap. If that +@@ -221,6 +235,14 @@ xwl_window_buffer_release_callback(void *data) + struct xwl_window_buffer, + link_buffer); + ++ if (xwl_window_buffer->release_point) { ++ /* We will wait for this fence before re-using the buffer */ ++ xwl_window_buffer->sync_fd = ++ xwl_screen->server_syncobj->export_fence(xwl_screen->server_syncobj, ++ xwl_window_buffer->release_point); ++ xwl_window_buffer->release_point = 0; ++ } ++ + /* Schedule next timer based on time of the oldest buffer */ + xwl_window->window_buffers_timer = + TimerSet(xwl_window->window_buffers_timer, +@@ -289,6 +311,34 @@ xwl_window_buffers_dispose(struct xwl_window *xwl_window) + } + } + ++static void ++xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer) ++{ ++ struct xwl_window *xwl_window = xwl_window_buffer->xwl_window; ++ struct xwl_screen *xwl_screen = xwl_window->xwl_screen; ++ uint64_t acquire_point = xwl_screen->glamor_timeline_point++; ++ uint64_t release_point = xwl_screen->server_timeline_point++; ++ ++ int fence_fd = xwl_glamor_get_fence(xwl_screen); ++ if (fence_fd >= 0) { ++ xwl_screen->glamor_syncobj->import_fence(xwl_screen->glamor_syncobj, ++ acquire_point, fence_fd); ++ } else { ++#ifdef XWL_HAS_GLAMOR ++ glamor_finish(xwl_screen->screen); ++#endif /* XWL_HAS_GLAMOR */ ++ xwl_screen->glamor_syncobj->signal(xwl_screen->glamor_syncobj, ++ acquire_point); ++ } ++ ++ xwl_window_buffer->release_point = release_point; ++ xwl_glamor_dri3_syncobj_passthrough(xwl_window->window, ++ xwl_screen->glamor_syncobj, ++ xwl_screen->server_syncobj, ++ acquire_point, ++ release_point); ++} ++ + PixmapPtr + xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, + RegionPtr damage_region) +@@ -313,6 +363,14 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, + + full_damage = xwl_window_buffer->damage_region; + ++#ifdef XWL_HAS_GLAMOR ++ if (xwl_window_buffer->sync_fd >= 0) { ++ xwl_glamor_wait_fence(xwl_screen, xwl_window_buffer->sync_fd); ++ close(xwl_window_buffer->sync_fd); ++ xwl_window_buffer->sync_fd = -1; ++ } ++#endif /* XWL_HAS_GLAMOR */ ++ + if (xwl_window_buffer->pixmap) { + BoxPtr pBox = RegionRects(full_damage); + int nBox = RegionNumRects(full_damage); +@@ -359,6 +417,16 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, + + /* Hold a reference on the buffer until it's released by the compositor */ + xwl_window_buffer->refcnt++; ++ ++#ifdef XWL_HAS_GLAMOR ++ if (!xwl_glamor_supports_implicit_sync(xwl_screen)) { ++ if (xwl_screen->explicit_sync) ++ xwl_window_buffers_set_syncpts(xwl_window_buffer); ++ else ++ glamor_finish(xwl_screen->screen); ++ } ++#endif /* XWL_HAS_GLAMOR */ ++ + xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap, + xwl_window_buffer_release_callback, + xwl_window_buffer); +diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c +index f1d6580e67..a75faa2ec5 100644 +--- a/hw/xwayland/xwayland-window.c ++++ b/hw/xwayland/xwayland-window.c +@@ -50,6 +50,7 @@ + #include "viewporter-client-protocol.h" + #include "xdg-shell-client-protocol.h" + #include "xwayland-shell-v1-client-protocol.h" ++#include "linux-drm-syncobj-v1-client-protocol.h" + + #define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */ + +@@ -1149,6 +1150,9 @@ xwl_unrealize_window(WindowPtr window) + if (xwl_window->tearing_control) + wp_tearing_control_v1_destroy(xwl_window->tearing_control); + ++ if (xwl_window->surface_sync) ++ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync); ++ + release_wl_surface_for_window(xwl_window); + xorg_list_del(&xwl_window->link_damage); + xorg_list_del(&xwl_window->link_window); +@@ -1354,6 +1358,13 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window) + pixmap = xwl_window_buffers_get_pixmap(xwl_window, region); + + #ifdef XWL_HAS_GLAMOR ++ if (xwl_glamor_supports_implicit_sync(xwl_screen) && ++ xwl_window->surface_sync) { ++ /* prefer implicit sync when possible */ ++ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync); ++ xwl_window->surface_sync = NULL; ++ } ++ + if (xwl_screen->glamor) + buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap); + else +diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h +index 45ae16da0f..51ce91b577 100644 +--- a/hw/xwayland/xwayland-window.h ++++ b/hw/xwayland/xwayland-window.h +@@ -122,6 +122,7 @@ struct xwl_window { + /* If TRUE, the window buffer format supports scanout with implicit modifier */ + Bool has_implicit_scanout_support; + struct wp_tearing_control_v1 *tearing_control; ++ struct wp_linux_drm_syncobj_surface_v1 *surface_sync; + }; + + struct xwl_window *xwl_window_get(WindowPtr window); +diff --git a/present/present_execute.c b/present/present_execute.c +index 795c70c88c..6d8ac2929c 100644 +--- a/present/present_execute.c ++++ b/present/present_execute.c +@@ -75,8 +75,11 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) + } + } + +- if (vblank->acquire_syncobj && !vblank->acquire_syncobj->check(vblank->acquire_syncobj, +- vblank->acquire_point)) { ++ /* Defer execution of explicitly synchronized copies. ++ * Flip synchronization is managed by the driver. ++ */ ++ if (!vblank->flip && vblank->acquire_syncobj && ++ !vblank->acquire_syncobj->check(vblank->acquire_syncobj, vblank->acquire_point)) { + vblank->efd = eventfd(0, EFD_CLOEXEC); + SetNotifyFd(vblank->efd, present_syncobj_triggered, X_NOTIFY_READ, vblank); + vblank->acquire_syncobj->eventfd(vblank->acquire_syncobj, vblank->acquire_point, +-- +GitLab + diff --git a/debian/patches/series b/debian/patches/series index 6ac7a3c..9c048c3 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ +967.patch 0001-xwayland-patch-fix-vsync.patch \ No newline at end of file diff --git a/main.sh b/main.sh index 81f066a..c1300fd 100755 --- a/main.sh +++ b/main.sh @@ -1,5 +1,5 @@ # Clone Upstream -git clone https://gitlab.freedesktop.org/xorg/xserver.git ./xwayland -b xwayland-23.2.1 +git clone https://gitlab.freedesktop.org/xorg/xserver.git ./xwayland -b xwayland-23.2.2 cp -rvf ./debian ./xwayland/ cd ./xwayland @@ -8,7 +8,7 @@ apt upgrade -y apt-get build-dep ./ -y # Build package -LOGNAME=root dh_make --createorig -y -l -p xwayland_23.2.1 +LOGNAME=root dh_make --createorig -y -l -p xwayland_23.2.2 dpkg-buildpackage --no-sign # Move the debs to output