xwayland/patches/967.patch
Ward Nakchbandi (Cosmic Fusion) b37abc917e
patcchy
2024-01-28 20:39:19 +03:00

2677 lines
101 KiB
Diff

From ed9991b1152359079b72d8193509aea0de395f1b 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/6] 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 bb2b81b8f9..951cc6357e 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -52,7 +52,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 7bdf16ff9725990ed1e54437748bed3899e9d67b 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/6] 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
* has_fence - check if the fence for a timeline point is submitted
* is_signaled - check if a timeline point 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
* submitted_eventfd and signaled_eventfd - register an eventfd to be
signaled when the given timeline point is either submitted or
signaled
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 | 38 +++++++++++++++-
dri3/dri3_priv.h | 3 ++
dri3/dri3_request.c | 91 +++++++++++++++++++++++++++++++++++++
dri3/dri3_screen.c | 20 ++++++++
include/protocol-versions.h | 2 +-
6 files changed, 167 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..14f9a1efa7 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,35 @@
#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 (*has_fence)(struct dri3_syncobj *syncobj, uint64_t point);
+ Bool (*is_signaled)(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 (*submitted_eventfd)(struct dri3_syncobj *syncobj, uint64_t point, int efd);
+ void (*signaled_eventfd)(struct dri3_syncobj *syncobj, uint64_t point, int efd);
+};
+
+#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 +112,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 +134,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 951cc6357e..2b0f85e392 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -52,7 +52,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 1faf528c3c99884a8d04031ee96a1ff44531f77f 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/6] 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 | 214 +++++++++++++++++++++++++++++-
1 file changed, 213 insertions(+), 1 deletion(-)
diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c
index 69ead78f26..35c06f5bee 100644
--- a/hw/xwayland/xwayland-glamor-gbm.c
+++ b/hw/xwayland/xwayland-glamor-gbm.c
@@ -843,7 +843,213 @@ 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, Bool check_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);
+
+ return !drmSyncobjTimelineWait(xwl_gbm->drm_fd,
+ &xwl_syncobj->handle, &point, 1,
+ 0 /* timeout */,
+ check_avail ?
+ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE :
+ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
+ NULL /* first_signaled */);
+}
+
+static Bool
+xwl_dri3_syncobj_has_fence(struct dri3_syncobj *syncobj, uint64_t point)
+{
+ return xwl_dri3_check_syncobj(syncobj, point, TRUE /* check_avail */);
+}
+
+static Bool
+xwl_dri3_syncobj_is_signaled(struct dri3_syncobj *syncobj, uint64_t point)
+{
+ return xwl_dri3_check_syncobj(syncobj, point, FALSE /* check_avail */);
+}
+
+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 void
+xwl_dri3_syncobj_submitted_eventfd(struct dri3_syncobj *syncobj,
+ uint64_t point, int efd)
+{
+ xwl_dri3_syncobj_eventfd(syncobj, point, efd, TRUE /* wait_avail */);
+}
+
+static void
+xwl_dri3_syncobj_signaled_eventfd(struct dri3_syncobj *syncobj,
+ uint64_t point, int efd)
+{
+ xwl_dri3_syncobj_eventfd(syncobj, point, efd, FALSE /* wait_avail */);
+}
+
+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.has_fence = xwl_dri3_syncobj_has_fence;
+ syncobj->base.is_signaled = xwl_dri3_syncobj_is_signaled;
+ 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.signaled_eventfd = xwl_dri3_syncobj_signaled_eventfd;
+ syncobj->base.submitted_eventfd = xwl_dri3_syncobj_submitted_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,
@@ -852,6 +1058,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 *
@@ -1265,6 +1472,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 9609ec156eb29bd66e3a5cf2001d6b222e0dada3 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/6] 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 | 108 ++++++++++++++++++---
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 | 170 ++++++++++++++++++++++++++-------
present/present_scmd.c | 8 ++
present/present_screen.c | 1 +
present/present_vblank.c | 36 +++++++
14 files changed, 376 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 074594cc7a..850e25db05 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -1073,6 +1073,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 97e8fb6642..260c60b652 100644
--- a/hw/xwayland/xwayland-glamor.h
+++ b/hw/xwayland/xwayland-glamor.h
@@ -158,6 +158,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 783b04ff43..fb5a37b907 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -30,6 +30,7 @@
#endif
#include <windowstr.h>
#include <present.h>
+#include <sys/eventfd.h>
#include "xwayland-present.h"
#include "xwayland-screen.h"
@@ -214,10 +215,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
@@ -236,6 +245,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
@@ -243,9 +262,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);
}
@@ -284,6 +321,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));
}
@@ -445,6 +486,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);
@@ -641,6 +687,19 @@ xwl_present_maybe_set_reason(struct xwl_window *xwl_window, PresentFlipReason *r
}
}
+static int
+xwl_present_flush_fenced(WindowPtr window)
+{
+ int fence = -1;
+#ifdef XWL_HAS_GLAMOR
+ struct xwl_window *xwl_window = xwl_window_from_window(window);
+ if (xwl_window)
+ fence = xwl_glamor_get_fence(xwl_window->xwl_screen);
+ xwl_present_flush(window);
+#endif /* XWL_HAS_GLAMOR */
+ return fence;
+}
+
static Bool
xwl_present_check_flip(RRCrtcPtr crtc,
WindowPtr present_window,
@@ -814,7 +873,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;
@@ -855,6 +914,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;
@@ -920,6 +980,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));
@@ -956,6 +1018,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,
@@ -972,11 +1038,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);
@@ -1011,6 +1083,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);
@@ -1023,22 +1099,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) {
@@ -1068,6 +1140,7 @@ xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
Bool
xwl_present_init(ScreenPtr screen)
{
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
present_screen_priv_ptr screen_priv;
if (!present_screen_register_priv_keys())
@@ -1083,6 +1156,14 @@ xwl_present_init(ScreenPtr screen)
if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
return FALSE;
+ xwl_screen->present_capabilities = XWL_PRESENT_CAPS;
+#ifdef XWL_HAS_GLAMOR
+ if (epoxy_has_egl_extension(xwl_screen->egl_display,
+ "ANDROID_native_fence_sync"))
+ xwl_screen->present_capabilities |=
+ PresentCapabilitySyncobj;
+#endif /* XWL_HAS_GLAMOR */
+
screen_priv->query_capabilities = xwl_present_query_capabilities;
screen_priv->get_crtc = xwl_present_get_crtc;
@@ -1093,6 +1174,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 dab636c844..b10198a40b 100644
--- a/hw/xwayland/xwayland-present.h
+++ b/hw/xwayland/xwayland-present.h
@@ -58,7 +58,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 a53d18bad8..0a41986099 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -147,6 +147,8 @@ struct xwl_screen {
struct libdecor *libdecor_context;
#endif
const char *output_name;
+
+ 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 2b0f85e392..aa3ba41fe1 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -73,7 +73,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..913a8b67ba 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,19 @@ 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);
+
+ 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 +72,18 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
return TRUE;
}
}
+
+ if (vblank->acquire_syncobj &&
+ !vblank->acquire_syncobj->is_signaled(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->signaled_eventfd(vblank->acquire_syncobj,
+ vblank->acquire_point,
+ vblank->efd);
+ 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..411798ab96 100644
--- a/present/present_request.c
+++ b/present/present_request.c
@@ -79,79 +79,117 @@ 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, stuff->target_crtc, client, DixReadAccess);
+ VERIFY_CRTC_OR_NONE(target_crtc, req_target_crtc, client, DixReadAccess);
- VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
- VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
+ VERIFY_FENCE_OR_NONE(wait_fence, req_wait_fence, client, DixReadAccess);
+ VERIFY_FENCE_OR_NONE(idle_fence, req_idle_fence, client, DixWriteAccess);
- 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 +278,41 @@ 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);
+
+ if (stuff->acquire_point == 0 || stuff->release_point == 0 ||
+ (stuff->acquire_syncobj == stuff->release_syncobj &&
+ stuff->acquire_point >= stuff->release_point))
+ return BadValue;
+
+ 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 +392,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 ef56ff779a..0589b2ee91 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 bcb2a82b5c83a25351ff806df29a2a6bad4648e6 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/6] 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 | 146 +++++++++++++++++++++++++-
hw/xwayland/xwayland-glamor.c | 94 +++++++++++++++++
hw/xwayland/xwayland-glamor.h | 30 ++++++
hw/xwayland/xwayland-present.c | 82 ++++++++++++---
hw/xwayland/xwayland-present.h | 1 -
hw/xwayland/xwayland-screen.c | 1 +
hw/xwayland/xwayland-screen.h | 1 +
hw/xwayland/xwayland-window-buffers.c | 110 ++++++++++++++++++-
hw/xwayland/xwayland-window.c | 10 ++
hw/xwayland/xwayland-window.h | 1 +
present/present_execute.c | 5 +-
12 files changed, 464 insertions(+), 20 deletions(-)
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 8898f3e6c1..df4fa19178 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 35c06f5bee..da8ae6c32f 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;
@@ -599,6 +603,8 @@ 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);
+ if (xwl_screen->explicit_sync)
+ wp_linux_drm_syncobj_manager_v1_destroy(xwl_screen->explicit_sync);
free(xwl_gbm);
}
@@ -843,12 +849,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_manager_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, Bool check_avail)
{
@@ -949,6 +1031,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);
@@ -986,10 +1071,27 @@ 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);
+ Bool create = !handle;
if (!syncobj)
return NULL;
+ if (create && drmSyncobjCreate(xwl_gbm->drm_fd, 0, &handle))
+ goto fail;
+
+ if (xwl_screen->explicit_sync) {
+ int syncobj_fd = -1;
+ if (drmSyncobjHandleToFD(xwl_gbm->drm_fd, handle, &syncobj_fd))
+ goto fail;
+
+ syncobj->timeline =
+ wp_linux_drm_syncobj_manager_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;
@@ -1005,10 +1107,18 @@ xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle)
return &syncobj->base;
fail:
+ if (create && handle)
+ drmSyncobjDestroy(xwl_gbm->drm_fd, handle);
free(syncobj);
return NULL;
}
+static struct dri3_syncobj *
+xwl_glamor_gbm_dri3_syncobj_create(struct xwl_screen *xwl_screen)
+{
+ return xwl_dri3_create_syncobj(xwl_screen, 0 /* allocate new handle */);
+}
+
static struct dri3_syncobj *
xwl_dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd)
{
@@ -1220,6 +1330,11 @@ xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
} else if (strcmp(name, zwp_linux_dmabuf_v1_interface.name) == 0) {
xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
return TRUE;
+ } else if (strcmp(name, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) {
+ xwl_screen->explicit_sync =
+ wl_registry_bind(xwl_screen->registry, id,
+ &wp_linux_drm_syncobj_manager_v1_interface,
+ version);
}
/* no match */
@@ -1390,7 +1505,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->drm && !xwl_glamor_gbm_init_main_dev(xwl_screen))
return FALSE;
@@ -1455,6 +1570,25 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
xwl_screen->glvnd_vendor = gbm_backend_name;
xwl_gbm->glamor_gles = !epoxy_is_desktop_gl();
+ 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->explicit_sync) {
+ /* explicit sync requires syncobj support */
+ wp_linux_drm_syncobj_manager_v1_destroy(xwl_screen->explicit_sync);
+ xwl_screen->explicit_sync = NULL;
+ }
+
return TRUE;
error:
if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
@@ -1472,7 +1606,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;
}
@@ -1545,6 +1679,12 @@ 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_create = xwl_glamor_gbm_dri3_syncobj_create;
+ 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 850e25db05..dcc1c2f5fe 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -1059,6 +1059,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 TRUE;
+
+ 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)
{
@@ -1097,6 +1117,80 @@ 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);
+}
+
+struct dri3_syncobj *
+xwl_glamor_dri3_syncobj_create(struct xwl_screen *xwl_screen)
+{
+ if (xwl_screen->glamor && xwl_screen->egl_backend &&
+ xwl_screen->egl_backend->dri3_syncobj_create)
+ return xwl_screen->egl_backend->dri3_syncobj_create(xwl_screen);
+
+ return NULL;
+}
+
+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 260c60b652..7e3eea014b 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;
typedef enum _xwl_glamor_mode_flags{
@@ -114,6 +117,22 @@ 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);
+
+ /* Creates a new dri3 syncobj */
+ struct dri3_syncobj *(*dri3_syncobj_create)(struct xwl_screen *xwl_screen);
+
+ /* 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
@@ -142,6 +161,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);
@@ -159,6 +180,15 @@ 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);
+struct dri3_syncobj *xwl_glamor_dri3_syncobj_create(struct xwl_screen *xwl_screen);
+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 fb5a37b907..b7afc4d8b9 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -39,6 +39,7 @@
#include "xwayland-pixmap.h"
#include "tearing-control-v1-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
#define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear
@@ -321,10 +322,6 @@ 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));
}
@@ -479,6 +476,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;
@@ -487,9 +485,16 @@ 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);
+#ifdef XWL_HAS_GLAMOR
+ 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);
+ }
+#endif /* XWL_HAS_GLAMOR */
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
@@ -713,6 +718,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;
@@ -753,7 +759,11 @@ xwl_present_check_flip(RRCrtcPtr crtc,
if (xwl_window->xwl_screen->glamor &&
!xwl_glamor_check_flip(present_window, pixmap))
return FALSE;
-#endif
+
+ if (!xwl_glamor_supports_implicit_sync(xwl_screen) &&
+ !xwl_screen->explicit_sync)
+ return FALSE;
+#endif /* XWL_HAS_GLAMOR */
/* 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
@@ -833,6 +843,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);
@@ -846,12 +857,35 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
return FALSE;
}
+ if (xwl_window->surface_sync) {
+ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
+ xwl_window->surface_sync = NULL;
+ }
+
damage_box = RegionExtents(damage);
pixmap->refcnt++;
event->pixmap = pixmap;
+#ifdef XWL_HAS_GLAMOR
+ 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);
+ }
+ }
+#endif /* XWL_HAS_GLAMOR */
+
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) */
@@ -896,6 +930,18 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
return TRUE;
}
+static void
+xwl_present_acquire_fence_avail(int fd, int xevents, void *data)
+{
+ present_vblank_ptr vblank = data;
+
+ SetNotifyFd(fd, NULL, 0, NULL);
+ close(fd);
+ vblank->efd = -1;
+
+ xwl_present_re_execute(vblank);
+}
+
/*
* Once the required MSC has been reached, execute the pending request.
*
@@ -911,6 +957,7 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
WindowPtr window = vblank->window;
struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
+ struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
xorg_list_del(&vblank->event_queue);
@@ -938,6 +985,19 @@ retry:
vblank->event_id, vblank, crtc_msc,
vblank->pixmap->drawable.id, vblank->window->drawable.id));
+ /* if the client is using explicit sync but the compositor does not
+ * support it, we must wait for the acquire fence to be available */
+ if (vblank->acquire_syncobj && !xwl_screen->explicit_sync &&
+ !vblank->acquire_syncobj->has_fence(vblank->acquire_syncobj,
+ vblank->acquire_point)) {
+ vblank->efd = eventfd(0, EFD_CLOEXEC);
+ SetNotifyFd(vblank->efd, xwl_present_acquire_fence_avail, X_NOTIFY_READ, vblank);
+ vblank->acquire_syncobj->submitted_eventfd(vblank->acquire_syncobj,
+ vblank->acquire_point,
+ vblank->efd);
+ return;
+ }
+
/* Set update region as damaged */
if (vblank->update) {
damage = RegionDuplicate(vblank->update);
@@ -1158,10 +1218,8 @@ xwl_present_init(ScreenPtr screen)
xwl_screen->present_capabilities = XWL_PRESENT_CAPS;
#ifdef XWL_HAS_GLAMOR
- 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;
#endif /* XWL_HAS_GLAMOR */
screen_priv->query_capabilities = xwl_present_query_capabilities;
diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h
index b10198a40b..f518068fbd 100644
--- a/hw/xwayland/xwayland-present.h
+++ b/hw/xwayland/xwayland-present.h
@@ -58,7 +58,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 5c71b55e29..94a047bf63 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -68,6 +68,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 0a41986099..2799be773d 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -112,6 +112,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_manager_v1 *explicit_sync;
struct xorg_list drm_lease_devices;
struct xorg_list queued_drm_lease_devices;
struct xorg_list drm_leases;
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
index 40e19e3495..fe19caaaed 100644
--- a/hw/xwayland/xwayland-window-buffers.c
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -32,6 +32,14 @@
#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>
+#include "linux-drm-syncobj-v1-client-protocol.h"
#define BUFFER_TIMEOUT 1 * 1000 /* ms */
@@ -39,6 +47,9 @@ struct xwl_window_buffer {
struct xwl_window *xwl_window;
PixmapPtr pixmap;
RegionPtr damage_region;
+ struct dri3_syncobj *syncobj;
+ uint64_t timeline_point;
+ int efd;
int refcnt;
uint32_t time;
struct xorg_list link_buffer;
@@ -76,6 +87,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->efd = -1;
xwl_window_buffer->refcnt = 1;
xorg_list_append(&xwl_window_buffer->link_buffer,
@@ -107,6 +119,14 @@ xwl_window_buffer_maybe_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->syncobj)
+ xwl_window_buffer->syncobj->free(xwl_window_buffer->syncobj);
+
+ if (xwl_window_buffer->efd >= 0) {
+ SetNotifyFd(xwl_window_buffer->efd, NULL, 0, NULL);
+ close(xwl_window_buffer->efd);
+ }
+
xorg_list_del(&xwl_window_buffer->link_buffer);
free(xwl_window_buffer);
@@ -213,6 +233,18 @@ xwl_window_buffer_release_callback(void *data)
xwl_window);
}
+static void
+xwl_window_buffers_release_fence_avail(int fd, int xevents, void *data)
+{
+ struct xwl_window_buffer *xwl_window_buffer = data;
+
+ SetNotifyFd(fd, NULL, 0, NULL);
+ close(fd);
+ xwl_window_buffer->efd = -1;
+
+ xwl_window_buffer_release_callback(data);
+}
+
void
xwl_window_buffers_init(struct xwl_window *xwl_window)
{
@@ -331,6 +363,46 @@ xwl_window_recycle_pixmap(struct xwl_window *xwl_window)
screen->DestroyPixmap(window_pixmap);
}
+#ifdef XWL_HAS_GLAMOR
+static Bool
+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_window_buffer->timeline_point;
+ uint64_t release_point = ++xwl_window_buffer->timeline_point;
+
+ if (!xwl_window_buffer->syncobj) {
+ struct dri3_syncobj *syncobj = xwl_glamor_dri3_syncobj_create(xwl_screen);
+ if (!syncobj)
+ goto fail;
+ xwl_window_buffer->syncobj = syncobj;
+ }
+
+ int fence_fd = xwl_glamor_get_fence(xwl_screen);
+ if (fence_fd >= 0)
+ xwl_window_buffer->syncobj->import_fence(xwl_window_buffer->syncobj,
+ acquire_point, fence_fd);
+ else
+ goto fail;
+
+ xwl_glamor_dri3_syncobj_passthrough(xwl_window->window,
+ xwl_window_buffer->syncobj,
+ xwl_window_buffer->syncobj,
+ acquire_point,
+ release_point);
+ return TRUE;
+
+fail:
+ /* can't use explicit sync, we will do a glFinish() before presenting */
+ if (xwl_window_buffer->syncobj) {
+ xwl_window_buffer->syncobj->free(xwl_window_buffer->syncobj);
+ xwl_window_buffer->syncobj = NULL;
+ }
+ return FALSE;
+}
+#endif /* XWL_HAS_GLAMOR */
+
PixmapPtr
xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
RegionPtr damage_region)
@@ -349,11 +421,22 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
xwl_window_buffer_add_damage_region(xwl_window, damage_region);
xwl_window_buffer = xwl_window_buffer_get_available(xwl_window);
+
if (xwl_window_buffer) {
RegionPtr full_damage = xwl_window_buffer->damage_region;
BoxPtr pBox = RegionRects(full_damage);
int nBox = RegionNumRects(full_damage);
+#ifdef XWL_HAS_GLAMOR
+ if (xwl_window_buffer->syncobj) {
+ int fence_fd =
+ xwl_window_buffer->syncobj->export_fence(xwl_window_buffer->syncobj,
+ xwl_window_buffer->timeline_point);
+ xwl_glamor_wait_fence(xwl_screen, fence_fd);
+ close(fence_fd);
+ }
+#endif /* XWL_HAS_GLAMOR */
+
new_window_pixmap = xwl_window_buffer->pixmap;
while (nBox--) {
@@ -388,9 +471,30 @@ 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++;
- xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap,
- xwl_window_buffer_release_callback,
- xwl_window_buffer);
+
+#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)) {
+ /* wait until the release fence is available before re-using this buffer */
+ xwl_window_buffer->efd = eventfd(0, EFD_CLOEXEC);
+ SetNotifyFd(xwl_window_buffer->efd, xwl_window_buffers_release_fence_avail,
+ X_NOTIFY_READ, xwl_window_buffer);
+ xwl_window_buffer->syncobj->submitted_eventfd(xwl_window_buffer->syncobj,
+ xwl_window_buffer->timeline_point,
+ xwl_window_buffer->efd);
+ } else
+ /* If glamor does not support implicit sync and we can't use
+ * explicit sync, wait for the GPU to be idle before presenting.
+ * Note that buffer re-use will still be unsynchronized :(
+ */
+ glamor_finish(xwl_screen->screen);
+ }
+#endif /* XWL_HAS_GLAMOR */
+
+ if (xwl_window_buffer->efd == -1)
+ xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap,
+ xwl_window_buffer_release_callback,
+ xwl_window_buffer);
xorg_list_del(&xwl_window_buffer->link_buffer);
xorg_list_append(&xwl_window_buffer->link_buffer,
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index d2434de8f5..023d58ba34 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -51,6 +51,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 */
@@ -1182,6 +1183,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);
@@ -1384,6 +1388,12 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window)
pixmap = xwl_window_buffers_get_pixmap(xwl_window, region);
buffer = xwl_pixmap_get_wl_buffer(pixmap);
+ if (xwl_window->surface_sync) {
+ /* default to implicit sync */
+ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
+ xwl_window->surface_sync = NULL;
+ }
+
if (!buffer) {
ErrorF("Error getting buffer\n");
return FALSE;
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 3370c45aaa..d415415f31 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -120,6 +120,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 913a8b67ba..2fb49749eb 100644
--- a/present/present_execute.c
+++ b/present/present_execute.c
@@ -73,7 +73,10 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
}
}
- if (vblank->acquire_syncobj &&
+ /* Defer execution of explicitly synchronized copies.
+ * Flip synchronization is managed by the driver.
+ */
+ if (!vblank->flip && vblank->acquire_syncobj &&
!vblank->acquire_syncobj->is_signaled(vblank->acquire_syncobj,
vblank->acquire_point)) {
vblank->efd = eventfd(0, EFD_CLOEXEC);
--
GitLab
From b28cb0a1dd8872a667843c6be297588ba5c405e9 Mon Sep 17 00:00:00 2001
From: Erik Kurzinger <ekurzinger@nvidia.com>
Date: Tue, 23 Jan 2024 14:17:57 -0800
Subject: [PATCH 6/6] xwayland: start present timer when waiting for fence
Before executing a present request, xwl_present_execute will call
present_execute_wait, which may cause execution to be deferred until
either the wait-fence (for PresentPixmap requests) or the acquire
timeline point (for PresentPixmapSynced requests) has been signaled.
If another present request is received targeting the same window and msc
before the first request is re-executed the older request will be
scrapped in favor of the newer request.
However, execution this newer request may also be deferred by
present_execute_wait for the same reason, and if yet another request
arrives quickly enough, the second request will also be scrapped. Thus,
we can get stuck in an endless loop and nothing ever ends up on the
screen.
This cycle *should* be broken when we bump the msc, causing the last
request before that to be executed for real. But, assuming all of these
requests are targeted for immediate execution, that never actually
happens because we only start the frame timer when queueing a request
for a future msc.
To fix this, we make two changes. Firstly, if present_execute_wait
causes execution to be deferred and the frame timer for the window is
not running, we will start it. Note that present_execute_wait may have
already called xwl_present_queue_vblank under certain circumstances,
which will have started the timer itself, but not if the request is
deferred due to a fence wait.
Secondly, we change xwl_present_has_pending_events to return true if the
vblank list of the present_window_priv is non-empty, instead of only
returning true if there are any queued vblanks or a pending flip. So it
will now return true if there are any vblanks waiting on their fence to
be signaled, meaning xwl_present_reset_timer will start the timer in
that case, which is what we want.
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
---
hw/xwayland/xwayland-present.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index b7afc4d8b9..1b75808654 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -168,10 +168,8 @@ xwl_present_get_pending_flip(struct xwl_present_window *xwl_present_window)
static inline Bool
xwl_present_has_pending_events(struct xwl_present_window *xwl_present_window)
{
- present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
-
- return (flip_pending && flip_pending->sync_flip) ||
- !xorg_list_is_empty(&xwl_present_window->wait_list);
+ present_window_priv_ptr window_priv = present_window_priv(xwl_present_window->window);
+ return !xorg_list_is_empty(&window_priv->vblank);
}
void
@@ -962,8 +960,11 @@ 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))
+ if (present_execute_wait(vblank, crtc_msc)) {
+ if (!xwl_present_window->frame_timer)
+ xwl_present_reset_timer(xwl_present_window);
return;
+ }
if (flip_pending && vblank->flip && vblank->pixmap && vblank->window) {
DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n",
--
GitLab