2677 lines
101 KiB
Diff
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), ¬ifies);
|
|
+ ret = present_create_notifies(client, nnotifies, req_notifies, ¬ifies);
|
|
if (ret != Success)
|
|
return ret;
|
|
}
|
|
|
|
- ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
|
|
- stuff->x_off, stuff->y_off, target_crtc,
|
|
- wait_fence, idle_fence, stuff->options,
|
|
- stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
|
|
+ ret = present_pixmap(window, pixmap, req_serial,
|
|
+ valid, update, req_x_off, req_y_off, target_crtc,
|
|
+ wait_fence, idle_fence,
|
|
+ acquire_syncobj, release_syncobj,
|
|
+ req_acquire_point, req_release_point,
|
|
+ req_options, req_target_msc, req_divisor, req_remainder,
|
|
+ notifies, nnotifies);
|
|
+
|
|
if (ret != Success)
|
|
present_destroy_notifies(notifies, nnotifies);
|
|
return ret;
|
|
}
|
|
|
|
+static int
|
|
+proc_present_pixmap(ClientPtr client)
|
|
+{
|
|
+ REQUEST(xPresentPixmapReq);
|
|
+ REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
|
|
+ return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial,
|
|
+ stuff->valid, stuff->update, stuff->x_off, stuff->y_off,
|
|
+ stuff->target_crtc,
|
|
+ stuff->wait_fence, stuff->idle_fence,
|
|
+ None, None, 0, 0,
|
|
+ stuff->options, stuff->target_msc,
|
|
+ stuff->divisor, stuff->remainder,
|
|
+ sizeof (xPresentPixmapReq),
|
|
+ (xPresentNotify *)(stuff + 1));
|
|
+}
|
|
+
|
|
static int
|
|
proc_present_notify_msc(ClientPtr client)
|
|
{
|
|
@@ -240,12 +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
|