xwayland/patches/967.patch
Ward Nakchbandi (Cosmic Fusion) 2168723842
2023-11-13 20:20:53 +03:00

2485 lines
93 KiB
Diff

From f1fc5cfab4bffd8a96df6fbe560946274024b904 Mon Sep 17 00:00:00 2001
From: Erik Kurzinger <ekurzinger@nvidia.com>
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 <ekurzinger@nvidia.com>
---
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 <ekurzinger@nvidia.com>
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 <ekurzinger@nvidia.com>
---
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 <X11/extensions/dri3proto.h>
#include <randrstr.h>
-#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 <protocol-versions.h>
#include <drm_fourcc.h>
+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 982ad9c2f4ff6c29ce1ded6123a81dfd8422dd72 Mon Sep 17 00:00:00 2001
From: Erik Kurzinger <ekurzinger@nvidia.com>
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 <ekurzinger@nvidia.com>
---
hw/xwayland/xwayland-glamor-gbm.c | 184 +++++++++++++++++++++++++++++-
1 file changed, 183 insertions(+), 1 deletion(-)
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index b177b77e08..5bd2373500 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -811,7 +811,183 @@ 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 */);
+}
+
+extern int
+drmSyncobjImportSyncFileTimeline(int fd, uint32_t handle,
+ uint64_t point, int sync_file_fd)
+ __attribute__((weak));
+extern int
+drmSyncobjExportSyncFileTimeline(int fd, uint32_t handle,
+ uint64_t point, int *sync_file_fd)
+ __attribute__((weak));
+
+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 +996,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 +1359,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 5b3744ecbc40f45650f961dd7d8ea82987519230 Mon Sep 17 00:00:00 2001
From: Erik Kurzinger <ekurzinger@nvidia.com>
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 <ekurzinger@nvidia.com>
---
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 <windowstr.h>
#include <present.h>
+#include <sys/eventfd.h>
#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 <sys/eventfd.h>
/*
* 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 <xfixes.h>
#include <randrstr.h>
#include <inttypes.h>
+#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), &notifies);
+ ret = present_create_notifies(client, nnotifies, req_notifies, &notifies);
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 02621661f676debe73956c0a8fc0d914664711a4 Mon Sep 17 00:00:00 2001
From: Erik Kurzinger <ekurzinger@nvidia.com>
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 <ekurzinger@nvidia.com>
---
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 5bd2373500..6a06be2daa 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -35,6 +35,9 @@
#include <sys/stat.h>
#include <xf86drm.h>
#include <drm_fourcc.h>
+#include <linux/dma-buf.h>
+#include <linux/sync_file.h>
+#include <sys/ioctl.h>
#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)
{
@@ -903,6 +1006,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);
@@ -926,10 +1032,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;
@@ -987,6 +1106,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,
@@ -1158,6 +1300,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 */
@@ -1281,7 +1428,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");
@@ -1342,6 +1489,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) {
@@ -1359,7 +1522,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;
}
@@ -1432,6 +1595,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 <xf86drm.h>
#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 <windowstr.h>
#include <present.h>
-#include <sys/eventfd.h>
#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 <poll.h>
+#include <sys/eventfd.h>
#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