bazzite/spec_files/xorg-x11-server-Xwayland/967.patch
2023-12-12 23:27:33 -08:00

2123 lines
79 KiB
Diff

From 78f590e35e91b69e5ca14e74e6f44b82fb7a401f Mon Sep 17 00:00:00 2001
From: GloriousEggroll <gloriouseggroll@gmail.com>
Date: Thu, 16 Nov 2023 00:32:36 -0700
Subject: [PATCH] MR-967
---
dri3/dri3.c | 15 ++
dri3/dri3.h | 36 ++-
dri3/dri3_priv.h | 3 +
dri3/dri3_request.c | 125 +++++++++
dri3/dri3_screen.c | 20 ++
hw/xwayland/meson.build | 3 +
hw/xwayland/xwayland-glamor-gbm.c | 356 +++++++++++++++++++++++++-
hw/xwayland/xwayland-glamor.c | 108 ++++++++
hw/xwayland/xwayland-glamor.h | 27 ++
hw/xwayland/xwayland-present.c | 136 +++++++++-
hw/xwayland/xwayland-present.h | 4 +-
hw/xwayland/xwayland-screen.c | 1 +
hw/xwayland/xwayland-screen.h | 9 +
hw/xwayland/xwayland-window-buffers.c | 68 +++++
hw/xwayland/xwayland-window.c | 11 +
hw/xwayland/xwayland-window.h | 1 +
include/protocol-versions.h | 4 +-
present/present.c | 9 +
present/present_execute.c | 37 ++-
present/present_priv.h | 25 ++
present/present_request.c | 169 +++++++++---
present/present_scmd.c | 8 +
present/present_screen.c | 1 +
present/present_vblank.c | 36 +++
24 files changed, 1157 insertions(+), 55 deletions(-)
diff --git a/dri3/dri3.c b/dri3/dri3.c
index 1912529..f9c5172 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 02d3b03..f7f4bb1 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,33 @@
#include <X11/extensions/dri3proto.h>
#include <randrstr.h>
-#define DRI3_SCREEN_INFO_VERSION 2
+#define DRI3_SCREEN_INFO_VERSION 4
+
+extern RESTYPE dri3_syncobj_type;
+
+struct dri3_syncobj
+{
+ XID id;
+ ScreenPtr screen;
+ uint32_t refcount;
+
+ void (*free)(struct dri3_syncobj *syncobj);
+ Bool (*check)(struct dri3_syncobj *syncobj, uint64_t point);
+ int (*export_fence)(struct dri3_syncobj *syncobj, uint64_t point);
+ void (*import_fence)(struct dri3_syncobj *syncobj, uint64_t point, int fd);
+ void (*signal)(struct dri3_syncobj *syncobj, uint64_t point);
+ void (*eventfd)(struct dri3_syncobj *syncobj, uint64_t point, int efd, Bool wait_avail);
+};
+
+#define VERIFY_DRI3_SYNCOBJ(id, ptr, a)\
+ do {\
+ int rc = dixLookupResourceByType((void **)&(ptr), id,\
+ dri3_syncobj_type, client, a);\
+ if (rc != Success) {\
+ client->errorValue = id;\
+ return rc;\
+ }\
+ } while (0);
typedef int (*dri3_open_proc)(ScreenPtr screen,
RRProviderPtr provider,
@@ -84,6 +110,11 @@ typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw,
uint32_t *num_modifiers,
uint64_t **modifiers);
+typedef struct dri3_syncobj *(*dri3_import_syncobj_proc) (ClientPtr client,
+ ScreenPtr screen,
+ XID id,
+ int fd);
+
typedef struct dri3_screen_info {
uint32_t version;
@@ -101,6 +132,9 @@ typedef struct dri3_screen_info {
dri3_get_modifiers_proc get_modifiers;
dri3_get_drawable_modifiers_proc get_drawable_modifiers;
+ /* Version 4 */
+ dri3_import_syncobj_proc import_syncobj;
+
} dri3_screen_info_rec, *dri3_screen_info_ptr;
extern _X_EXPORT Bool
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index f319d17..71d2da9 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 6871689..520cd60 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:
@@ -554,6 +573,72 @@ 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;
+}
+
+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 */
@@ -564,6 +649,9 @@ 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 */
+ proc_dri3_import_syncobj, /* 10 */
+ proc_dri3_free_syncobj, /* 11 */
};
int
@@ -697,6 +785,40 @@ 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);
+}
+
+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 */
@@ -707,6 +829,9 @@ 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 */
+ 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 bc96e53..5614a22 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/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 54529b6..57a01ce 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 cfcd39a..707b1b3 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;
@@ -569,6 +573,28 @@ xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap)
return xwl_pixmap->buffer;
}
+static void
+xwl_screen_destroy_explicit_sync(struct xwl_screen *xwl_screen)
+{
+ if (xwl_screen->glamor_syncobj) {
+ xwl_screen->glamor_syncobj->free(xwl_screen->glamor_syncobj);
+ xwl_screen->glamor_syncobj = NULL;
+ }
+
+ if (xwl_screen->server_syncobj) {
+ xwl_screen->server_syncobj->free(xwl_screen->server_syncobj);
+ xwl_screen->server_syncobj = NULL;
+ }
+
+ if (xwl_screen->explicit_sync) {
+ wp_linux_drm_syncobj_v1_destroy(xwl_screen->explicit_sync);
+ xwl_screen->explicit_sync = NULL;
+ }
+
+ xwl_screen->glamor_timeline_point = 0;
+ xwl_screen->server_timeline_point = 0;
+}
+
static void
xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
{
@@ -583,6 +609,7 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
wl_drm_destroy(xwl_gbm->drm);
if (xwl_gbm->gbm)
gbm_device_destroy(xwl_gbm->gbm);
+ xwl_screen_destroy_explicit_sync(xwl_screen);
free(xwl_gbm);
}
@@ -827,7 +854,298 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
return -1;
}
-static const dri3_screen_info_rec xwl_dri3_info = {
+static int xwl_glamor_gbm_dmabuf_export_sync_file(PixmapPtr pixmap)
+{
+ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
+ int num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
+ int sync_file = -1;
+ int p;
+
+ for (p = 0; p < num_planes; ++p) {
+ int plane_fd = gbm_bo_get_fd_for_plane(xwl_pixmap->bo, p);
+ struct dma_buf_export_sync_file export_args = { 0 };
+ export_args.fd = -1;
+ export_args.flags = DMA_BUF_SYNC_READ;
+ drmIoctl(plane_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &export_args);
+ close(plane_fd);
+ if (sync_file == -1) {
+ sync_file = export_args.fd;
+ } else {
+ struct sync_merge_data merge_args = { 0 };
+ merge_args.fd2 = export_args.fd;
+ ioctl(sync_file, SYNC_IOC_MERGE, &merge_args);
+ close(export_args.fd);
+ close(sync_file);
+ sync_file = merge_args.fence;
+ }
+ }
+
+ return sync_file;
+}
+
+static void xwl_glamor_gbm_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file)
+{
+ struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
+ int num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
+ int p;
+
+ for (p = 0; p < num_planes; ++p) {
+ int plane_fd = gbm_bo_get_fd_for_plane(xwl_pixmap->bo, p);
+ struct dma_buf_import_sync_file import_args = { 0 };
+ import_args.fd = sync_file;
+ import_args.flags = DMA_BUF_SYNC_READ;
+ drmIoctl(plane_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_args);
+ close(plane_fd);
+ }
+ close(sync_file);
+}
+
+struct xwl_dri3_syncobj
+{
+ struct dri3_syncobj base;
+ uint32_t handle;
+ struct wp_linux_drm_syncobj_timeline_v1 *timeline;
+};
+
+static void
+xwl_glamor_gbm_dri3_syncobj_passthrough(WindowPtr window,
+ struct dri3_syncobj *acquire_syncobj,
+ struct dri3_syncobj *release_syncobj,
+ uint64_t acquire_point,
+ uint64_t release_point)
+{
+ struct xwl_window *xwl_window = xwl_window_get(window);
+ struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+ struct xwl_dri3_syncobj *xwl_acquire_syncobj = (struct xwl_dri3_syncobj *)acquire_syncobj;
+ struct xwl_dri3_syncobj *xwl_release_syncobj = (struct xwl_dri3_syncobj *)release_syncobj;
+ uint32_t acquire_hi = acquire_point >> 32;
+ uint32_t acquire_lo = acquire_point & 0xffffffff;
+ uint32_t release_hi = release_point >> 32;
+ uint32_t release_lo = release_point & 0xffffffff;
+
+ if (!xwl_window->surface_sync)
+ xwl_window->surface_sync =
+ wp_linux_drm_syncobj_v1_get_surface(xwl_screen->explicit_sync,
+ xwl_window->surface);
+
+ wp_linux_drm_syncobj_surface_v1_set_acquire_point(xwl_window->surface_sync,
+ xwl_acquire_syncobj->timeline,
+ acquire_hi, acquire_lo);
+ wp_linux_drm_syncobj_surface_v1_set_release_point(xwl_window->surface_sync,
+ xwl_release_syncobj->timeline,
+ release_hi, release_lo);
+}
+
+static Bool
+xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, uint64_t point)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+ return !drmSyncobjTimelineWait(xwl_gbm->drm_fd,
+ &xwl_syncobj->handle, &point, 1,
+ 0 /* timeout */,
+ DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
+ NULL /* first_signaled */);
+}
+
+extern int
+drmSyncobjImportSyncFileTimeline(int fd, uint32_t handle,
+ uint64_t point, int sync_file_fd)
+ __attribute__((weak));
+extern int
+drmSyncobjExportSyncFileTimeline(int fd, uint32_t handle,
+ uint64_t point, int *sync_file_fd)
+ __attribute__((weak));
+
+static int
+xwl_dri3_syncobj_export_fence(struct dri3_syncobj *syncobj, uint64_t point)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ int fd = -1;
+
+ if (!drmSyncobjExportSyncFileTimeline ||
+ drmSyncobjExportSyncFileTimeline(xwl_gbm->drm_fd,
+ xwl_syncobj->handle,
+ point, &fd)) {
+ /* try legacy export procedure */
+ uint32_t temp_syncobj;
+ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &temp_syncobj);
+ drmSyncobjTransfer(xwl_gbm->drm_fd, temp_syncobj, 0,
+ xwl_syncobj->handle, point, 0);
+ drmSyncobjExportSyncFile(xwl_gbm->drm_fd, temp_syncobj, &fd);
+ drmSyncobjDestroy(xwl_gbm->drm_fd, temp_syncobj);
+ }
+ return fd;
+}
+
+static void
+xwl_dri3_syncobj_import_fence(struct dri3_syncobj *syncobj,
+ uint64_t point, int fd)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+ if (!drmSyncobjImportSyncFileTimeline ||
+ drmSyncobjImportSyncFileTimeline(xwl_gbm->drm_fd,
+ xwl_syncobj->handle,
+ point, fd)) {
+ /* try legacy import procedure */
+ uint32_t temp_syncobj;
+ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &temp_syncobj);
+ drmSyncobjImportSyncFile(xwl_gbm->drm_fd, temp_syncobj, fd);
+ drmSyncobjTransfer(xwl_gbm->drm_fd, xwl_syncobj->handle, point,
+ temp_syncobj, 0, 0);
+ drmSyncobjDestroy(xwl_gbm->drm_fd, temp_syncobj);
+ }
+ close(fd);
+}
+
+static void
+xwl_dri3_signal_syncobj(struct dri3_syncobj *syncobj, uint64_t point)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+ drmSyncobjTimelineSignal(xwl_gbm->drm_fd, &xwl_syncobj->handle, &point, 1);
+}
+
+static void
+xwl_dri3_free_syncobj(struct dri3_syncobj *syncobj)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+ if (xwl_syncobj->timeline)
+ wp_linux_drm_syncobj_timeline_v1_destroy(xwl_syncobj->timeline);
+
+ if (xwl_syncobj->handle)
+ drmSyncobjDestroy(xwl_gbm->drm_fd, xwl_syncobj->handle);
+
+ free(xwl_syncobj);
+}
+
+static void
+xwl_dri3_syncobj_eventfd(struct dri3_syncobj *syncobj, uint64_t point,
+ int efd, Bool wait_avail)
+{
+ struct xwl_dri3_syncobj *xwl_syncobj = (struct xwl_dri3_syncobj *)syncobj;
+ struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+
+ drmSyncobjEventfd(xwl_gbm->drm_fd, xwl_syncobj->handle, point, efd,
+ wait_avail ? DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE : 0);
+}
+
+static struct dri3_syncobj *
+xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle)
+{
+ struct xwl_dri3_syncobj *syncobj = calloc(1, sizeof (*syncobj));
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ int syncobj_fd = -1;
+
+ if (!syncobj)
+ return NULL;
+
+ if (xwl_screen->explicit_sync) {
+ if (drmSyncobjHandleToFD(xwl_gbm->drm_fd, handle, &syncobj_fd))
+ goto fail;
+
+ syncobj->timeline =
+ wp_linux_drm_syncobj_v1_import_timeline(xwl_screen->explicit_sync,
+ syncobj_fd);
+ close(syncobj_fd);
+ if (!syncobj->timeline)
+ goto fail;
+ }
+
+ syncobj->handle = handle;
+ syncobj->base.screen = xwl_screen->screen;
+ syncobj->base.refcount = 1;
+
+ syncobj->base.free = xwl_dri3_free_syncobj;
+ syncobj->base.check = xwl_dri3_check_syncobj;
+ syncobj->base.export_fence = xwl_dri3_syncobj_export_fence;
+ syncobj->base.import_fence = xwl_dri3_syncobj_import_fence;
+ syncobj->base.signal = xwl_dri3_signal_syncobj;
+ syncobj->base.eventfd = xwl_dri3_syncobj_eventfd;
+ return &syncobj->base;
+
+fail:
+ free(syncobj);
+ return NULL;
+}
+
+static struct dri3_syncobj *
+xwl_dri3_import_syncobj(ClientPtr client, ScreenPtr screen, XID id, int fd)
+{
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ struct xwl_dri3_syncobj *syncobj = NULL;
+ uint32_t handle;
+
+ if (drmSyncobjFDToHandle(xwl_gbm->drm_fd, fd, &handle))
+ return NULL;
+
+ syncobj = (struct xwl_dri3_syncobj *)xwl_dri3_create_syncobj(xwl_screen, handle);
+ if (!syncobj) {
+ drmSyncobjDestroy(xwl_gbm->drm_fd, handle);
+ return NULL;
+ }
+
+ syncobj->base.id = id;
+
+ return &syncobj->base;
+}
+
+static Bool
+xwl_gbm_supports_syncobjs(struct xwl_screen *xwl_screen)
+{
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ uint64_t syncobj_cap = 0;
+
+ if (drmGetCap(xwl_gbm->drm_fd, DRM_CAP_SYNCOBJ_TIMELINE,
+ &syncobj_cap) || !syncobj_cap)
+ return FALSE;
+
+ /* Check if syncobj eventfd is supported. */
+ drmSyncobjEventfd(xwl_gbm->drm_fd, 0, 0, -1, 0);
+ if (errno != ENOENT)
+ return FALSE;
+
+ return TRUE;
+}
+
+static Bool
+xwl_screen_init_explicit_sync(struct xwl_screen *xwl_screen)
+{
+ struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ uint32_t glamor_syncobj_handle, server_syncobj_handle;
+
+ if (!xwl_screen->explicit_sync)
+ return FALSE;
+
+ if (drmSyncobjCreate(xwl_gbm->drm_fd, 0, &glamor_syncobj_handle) ||
+ drmSyncobjCreate(xwl_gbm->drm_fd, 0, &server_syncobj_handle))
+ return FALSE;
+
+ xwl_screen->glamor_syncobj = xwl_dri3_create_syncobj(xwl_screen, glamor_syncobj_handle);
+ xwl_screen->server_syncobj = xwl_dri3_create_syncobj(xwl_screen, server_syncobj_handle);
+ if (!xwl_screen->glamor_syncobj || !xwl_screen->server_syncobj)
+ return FALSE;
+
+ xwl_screen->glamor_timeline_point = 1;
+ xwl_screen->server_timeline_point = 1;
+ return TRUE;
+}
+
+static dri3_screen_info_rec xwl_dri3_info = {
.version = 2,
.open = NULL,
.pixmap_from_fds = glamor_pixmap_from_fds,
@@ -836,6 +1154,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 *
@@ -997,6 +1316,11 @@ xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
} else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) {
xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
return TRUE;
+ } else if (strcmp(name, "wp_linux_drm_syncobj_v1") == 0) {
+ xwl_screen->explicit_sync =
+ wl_registry_bind(xwl_screen->registry, id,
+ &wp_linux_drm_syncobj_v1_interface,
+ version);
}
/* no match */
@@ -1120,7 +1444,7 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
EGLint major, minor;
const GLubyte *renderer;
- const char *gbm_backend_name;
+ const char *gbm_backend_name, *egl_vendor;
if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) {
ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
@@ -1181,6 +1505,22 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
if (gbm_backend_name && strcmp(gbm_backend_name, "drm") != 0)
xwl_screen->glvnd_vendor = gbm_backend_name;
+ egl_vendor = eglQueryString(xwl_screen->egl_display, EGL_VENDOR);
+ /* NVIDIA driver does not support implicit sync */
+ if (egl_vendor && strstr(egl_vendor, "NVIDIA"))
+ xwl_screen->gbm_backend.backend_flags &=
+ ~XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC;
+
+ if (xwl_gbm_supports_syncobjs(xwl_screen) &&
+ epoxy_has_egl_extension(xwl_screen->egl_display,
+ "ANDROID_native_fence_sync"))
+ xwl_screen->gbm_backend.backend_flags |=
+ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS;
+
+ if (!xwl_glamor_supports_syncobjs(xwl_screen) ||
+ !xwl_screen_init_explicit_sync(xwl_screen))
+ xwl_screen_destroy_explicit_sync(xwl_screen);
+
return TRUE;
error:
if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
@@ -1198,6 +1538,11 @@ xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen)
{
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
+ if (xwl_glamor_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;
@@ -1266,6 +1611,11 @@ xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
xwl_screen->gbm_backend.get_main_device = xwl_gbm_get_main_device;
xwl_screen->gbm_backend.is_available = TRUE;
xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH |
- XWL_EGL_BACKEND_NEEDS_N_BUFFERING;
+ XWL_EGL_BACKEND_NEEDS_N_BUFFERING |
+ /* may be overriden during EGL initialization */
+ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC;
xwl_screen->gbm_backend.create_pixmap_for_window = xwl_glamor_gbm_create_pixmap_for_window;
+ xwl_screen->gbm_backend.dmabuf_export_sync_file = xwl_glamor_gbm_dmabuf_export_sync_file;
+ xwl_screen->gbm_backend.dmabuf_import_sync_file = xwl_glamor_gbm_dmabuf_import_sync_file;
+ xwl_screen->gbm_backend.dri3_syncobj_passthrough = xwl_glamor_gbm_dri3_syncobj_passthrough;
}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index c6aa8eb..b4e912c 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -1060,6 +1060,26 @@ xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen)
XWL_EGL_BACKEND_NEEDS_N_BUFFERING);
}
+Bool
+xwl_glamor_supports_implicit_sync(struct xwl_screen *xwl_screen)
+{
+ if (!xwl_screen->glamor || !xwl_screen->egl_backend)
+ return FALSE;
+
+ return xwl_screen->egl_backend->backend_flags &
+ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC;
+}
+
+Bool
+xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen)
+{
+ if (!xwl_screen->glamor || !xwl_screen->egl_backend)
+ return FALSE;
+
+ return xwl_screen->egl_backend->backend_flags &
+ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS;
+}
+
PixmapPtr
xwl_glamor_create_pixmap_for_window(struct xwl_window *xwl_window)
{
@@ -1074,6 +1094,94 @@ 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_wait_fence(struct xwl_screen *xwl_screen, int fence_fd)
+{
+ EGLint attribs[3];
+ EGLSyncKHR sync;
+
+ if (!xwl_screen->glamor)
+ return;
+
+ xwl_glamor_egl_make_current(xwl_screen);
+
+ attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID;
+ attribs[1] = fence_fd;
+ attribs[2] = EGL_NONE;
+ sync = eglCreateSyncKHR(xwl_screen->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync != EGL_NO_SYNC_KHR) {
+ eglWaitSyncKHR(xwl_screen->egl_display, sync, 0);
+ eglDestroySyncKHR(xwl_screen->egl_display, sync);
+ }
+}
+
+int
+xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+
+ if (xwl_screen->glamor && xwl_screen->egl_backend &&
+ xwl_screen->egl_backend->dmabuf_export_sync_file)
+ return xwl_screen->egl_backend->dmabuf_export_sync_file(pixmap);
+
+ return -1;
+}
+
+void
+xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+
+ if (xwl_screen->glamor && xwl_screen->egl_backend &&
+ xwl_screen->egl_backend->dmabuf_import_sync_file)
+ xwl_screen->egl_backend->dmabuf_import_sync_file(pixmap, sync_file);
+}
+
+void
+xwl_glamor_dri3_syncobj_passthrough(WindowPtr window,
+ struct dri3_syncobj *acquire_syncobj,
+ struct dri3_syncobj *release_syncobj,
+ uint64_t acquire_point,
+ uint64_t release_point)
+{
+ ScreenPtr screen = window->drawable.pScreen;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+
+ if (xwl_screen->glamor && xwl_screen->egl_backend &&
+ xwl_screen->egl_backend->dri3_syncobj_passthrough)
+ xwl_screen->egl_backend->dri3_syncobj_passthrough(window,
+ acquire_syncobj,
+ release_syncobj,
+ acquire_point,
+ release_point);
+}
+
void
xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream)
{
diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h
index 183fe75..d1a8982 100644
--- a/hw/xwayland/xwayland-glamor.h
+++ b/hw/xwayland/xwayland-glamor.h
@@ -34,11 +34,14 @@
#include <xf86drm.h>
#include "xwayland-types.h"
+#include "dri3.h"
typedef enum _xwl_egl_backend_flags {
XWL_EGL_BACKEND_NO_FLAG = 0,
XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH = (1 << 0),
XWL_EGL_BACKEND_NEEDS_N_BUFFERING = (1 << 1),
+ XWL_EGL_BACKEND_SUPPORTS_IMPLICIT_SYNC = (1 << 2),
+ XWL_EGL_BACKEND_SUPPORTS_SYNCOBJS = (1 << 3),
} xwl_egl_backend_flags;
struct xwl_egl_backend {
@@ -107,6 +110,19 @@ struct xwl_egl_backend {
/* Direct hook to create the backing pixmap for a window */
PixmapPtr (*create_pixmap_for_window)(struct xwl_window *xwl_window);
+
+ /* Merge the implicit read fences of each plane into a sync file */
+ int (*dmabuf_export_sync_file)(PixmapPtr pixmap);
+
+ /* Sets the implicit read fence of each plane to the given sync file */
+ void (*dmabuf_import_sync_file)(PixmapPtr pixmap, int sync_file);
+
+ /* Sets the explicit sync acquire and release points for the given Window */
+ void (*dri3_syncobj_passthrough)(WindowPtr window,
+ struct dri3_syncobj *acquire_syncobj,
+ struct dri3_syncobj *release_syncobj,
+ uint64_t acquire_point,
+ uint64_t release_point);
};
#ifdef XWL_HAS_GLAMOR
@@ -135,6 +151,8 @@ Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window);
void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen);
Bool xwl_glamor_needs_buffer_flush(struct xwl_screen *xwl_screen);
Bool xwl_glamor_needs_n_buffering(struct xwl_screen *xwl_screen);
+Bool xwl_glamor_supports_implicit_sync(struct xwl_screen *xwl_screen);
+Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen);
Bool xwl_glamor_is_modifier_supported(struct xwl_screen *xwl_screen,
uint32_t format, uint64_t modifier);
uint32_t wl_drm_format_for_depth(int depth);
@@ -151,6 +169,15 @@ 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);
+void xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence);
+int xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap);
+void xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file);
+void xwl_glamor_dri3_syncobj_passthrough(WindowPtr window,
+ struct dri3_syncobj *acquire_syncobj,
+ struct dri3_syncobj *release_syncobj,
+ uint64_t acquire_point,
+ uint64_t release_point);
#ifdef XV
/* glamor Xv Adaptor */
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index 941be06..f611bb9 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -35,6 +35,7 @@
#include "glamor.h"
#include "tearing-control-v1-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
#define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear
@@ -211,10 +212,18 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
static void
xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
+static int
+xwl_present_queue_vblank(ScreenPtr screen,
+ WindowPtr present_window,
+ RRCrtcPtr crtc,
+ uint64_t event_id,
+ uint64_t msc);
+
static uint32_t
xwl_present_query_capabilities(present_screen_priv_ptr screen_priv)
{
- return XWL_PRESENT_CAPS;
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen_priv->pScreen);
+ return xwl_screen->present_capabilities;
}
static int
@@ -233,6 +242,16 @@ xwl_present_get_ust_msc(ScreenPtr screen,
return Success;
}
+static uint64_t
+xwl_present_get_exec_msc(uint32_t options, uint64_t target_msc)
+{
+ /* Synchronous Xwayland presentations always complete (at least) one frame after they
+ * are executed
+ */
+ return (options & PresentOptionAsyncMayTear) ?
+ target_msc : target_msc - 1;
+}
+
/*
* When the wait fence or previous flip is completed, it's time
* to re-try the request
@@ -240,9 +259,27 @@ xwl_present_get_ust_msc(ScreenPtr screen,
static void
xwl_present_re_execute(present_vblank_ptr vblank)
{
+ struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
uint64_t ust = 0, crtc_msc = 0;
(void) xwl_present_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc);
+ /* re-compute target / exec msc */
+ vblank->target_msc = present_get_target_msc(0, crtc_msc,
+ event->divisor,
+ event->remainder,
+ event->options);
+ vblank->exec_msc = xwl_present_get_exec_msc(event->options,
+ vblank->target_msc);
+
+ vblank->queued = TRUE;
+ if (msc_is_after(vblank->exec_msc, crtc_msc) &&
+ xwl_present_queue_vblank(vblank->screen, vblank->window,
+ vblank->crtc,
+ vblank->event_id,
+ vblank->exec_msc) == Success) {
+ return;
+ }
+
xwl_present_execute(vblank, ust, crtc_msc);
}
@@ -281,6 +318,10 @@ xwl_present_free_event(struct xwl_present_event *event)
static void
xwl_present_free_idle_vblank(present_vblank_ptr vblank)
{
+ if (vblank->release_syncobj)
+ vblank->release_syncobj->signal(vblank->release_syncobj,
+ vblank->release_point);
+
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
xwl_present_free_event(xwl_present_event_from_vblank(vblank));
}
@@ -435,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;
@@ -442,6 +484,16 @@ xwl_present_buffer_release(void *data)
return;
vblank = &event->vblank;
+
+ xwl_screen = xwl_screen_get(vblank->screen);
+ if (vblank->release_syncobj && !xwl_screen->explicit_sync) {
+ /* transfer implicit fence to release syncobj */
+ int fence_fd = xwl_glamor_dmabuf_export_sync_file(vblank->pixmap);
+ vblank->release_syncobj->import_fence(vblank->release_syncobj,
+ vblank->release_point,
+ fence_fd);
+ }
+
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
xwl_present_window = xwl_present_window_priv(vblank->window);
@@ -632,6 +684,15 @@ xwl_present_maybe_set_reason(struct xwl_window *xwl_window, PresentFlipReason *r
}
}
+static int
+xwl_present_flush_fenced(WindowPtr window)
+{
+ struct xwl_window *xwl_window = xwl_window_from_window(window);
+ int fence = xwl_glamor_get_fence(xwl_window->xwl_screen);
+ xwl_present_flush(window);
+ return fence;
+}
+
static Bool
xwl_present_check_flip(RRCrtcPtr crtc,
WindowPtr present_window,
@@ -645,6 +706,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;
@@ -681,6 +743,13 @@ xwl_present_check_flip(RRCrtcPtr crtc,
if (!xwl_glamor_check_flip(present_window, pixmap))
return FALSE;
+ /* If glamor doesn't support implicit sync and the compositor doesn't
+ * support explicit sync, we cannot flip
+ */
+ if (!xwl_glamor_supports_implicit_sync(xwl_screen) &&
+ !xwl_screen->explicit_sync)
+ return FALSE;
+
/* Can't flip if the window pixmap doesn't match the xwl_window parent
* window's, e.g. because a client redirected this window or one of its
* parents.
@@ -759,6 +828,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);
@@ -778,6 +848,28 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
event->pixmap = pixmap;
+ assert(xwl_glamor_supports_implicit_sync(xwl_screen) ||
+ xwl_screen->explicit_sync);
+
+ if (vblank->acquire_syncobj && vblank->release_syncobj) {
+ if (xwl_screen->explicit_sync)
+ xwl_glamor_dri3_syncobj_passthrough(present_window,
+ vblank->acquire_syncobj,
+ vblank->release_syncobj,
+ vblank->acquire_point,
+ vblank->release_point);
+ else {
+ /* transfer from acquire syncobj to implicit fence */
+ int fence_fd =
+ vblank->acquire_syncobj->export_fence(vblank->acquire_syncobj,
+ vblank->acquire_point);
+ xwl_glamor_dmabuf_import_sync_file(vblank->pixmap, fence_fd);
+ }
+ } else if (xwl_window->surface_sync) {
+ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
+ xwl_window->surface_sync = NULL;
+ }
+
xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event);
/* We can flip directly to the main surface (full screen window without clips) */
@@ -799,7 +891,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;
@@ -840,6 +932,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;
@@ -900,6 +993,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));
@@ -936,6 +1031,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,
@@ -952,11 +1051,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);
@@ -991,6 +1096,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);
@@ -1003,22 +1112,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) {
@@ -1067,6 +1172,10 @@ xwl_present_init(ScreenPtr screen)
if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
return FALSE;
+ xwl_screen->present_capabilities = XWL_PRESENT_CAPS;
+ if (xwl_glamor_supports_syncobjs(xwl_screen))
+ xwl_screen->present_capabilities |= PresentCapabilitySyncobj;
+
screen_priv->query_capabilities = xwl_present_query_capabilities;
screen_priv->get_crtc = xwl_present_get_crtc;
@@ -1077,6 +1186,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 4fd1e57..ffc16f5 100644
--- a/hw/xwayland/xwayland-present.h
+++ b/hw/xwayland/xwayland-present.h
@@ -59,7 +59,9 @@ struct xwl_present_event {
present_vblank_rec vblank;
PixmapPtr pixmap;
- Bool async_may_tear;
+ 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.c b/hw/xwayland/xwayland-screen.c
index cc14e07..e4c2127 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -64,6 +64,7 @@
#include "xdg-shell-client-protocol.h"
#include "xwayland-shell-v1-client-protocol.h"
#include "tearing-control-v1-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
static DevPrivateKeyRec xwl_screen_private_key;
static DevPrivateKeyRec xwl_client_private_key;
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index bd66dd6..fce3510 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -111,6 +111,7 @@ struct xwl_screen {
struct wp_viewporter *viewporter;
struct xwayland_shell_v1 *xwayland_shell;
struct wp_tearing_control_manager_v1 *tearing_control_manager;
+ struct wp_linux_drm_syncobj_v1 *explicit_sync;
struct xorg_list drm_lease_devices;
struct xorg_list queued_drm_lease_devices;
struct xorg_list drm_leases;
@@ -145,6 +146,14 @@ struct xwl_screen {
int libdecor_fd;
struct libdecor *libdecor_context;
#endif
+
+ uint32_t present_capabilities;
+
+ /* For use with explicit sync */
+ struct dri3_syncobj *glamor_syncobj;
+ struct dri3_syncobj *server_syncobj;
+ uint64_t glamor_timeline_point;
+ uint64_t server_timeline_point;
};
/* Apps which use randr/vidmode to change the mode when going fullscreen,
diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c
index f7bb571..0b7cb5d 100644
--- a/hw/xwayland/xwayland-window-buffers.c
+++ b/hw/xwayland/xwayland-window-buffers.c
@@ -32,6 +32,13 @@
#include "xwayland-pixmap.h"
#include "xwayland-screen.h"
#include "xwayland-window-buffers.h"
+#include "dri3.h"
+#ifdef XWL_HAS_GLAMOR
+#include "glamor.h"
+#endif
+
+#include <poll.h>
+#include <sys/eventfd.h>
#define BUFFER_TIMEOUT 1 * 1000 /* ms */
@@ -40,6 +47,8 @@ struct xwl_window_buffer {
PixmapPtr pixmap;
RegionPtr damage_region;
Bool recycle_on_release;
+ uint64_t release_point;
+ int sync_fd;
int refcnt;
uint32_t time;
struct xorg_list link_buffer;
@@ -80,6 +89,7 @@ xwl_window_buffer_new(struct xwl_window *xwl_window)
xwl_window_buffer->xwl_window = xwl_window;
xwl_window_buffer->damage_region = RegionCreate(NullBox, 1);
xwl_window_buffer->pixmap = NullPixmap;
+ xwl_window_buffer->sync_fd = -1;
xwl_window_buffer->refcnt = 1;
xorg_list_append(&xwl_window_buffer->link_buffer,
@@ -111,6 +121,9 @@ xwl_window_buffer_dispose(struct xwl_window_buffer *xwl_window_buffer)
if (xwl_window_buffer->pixmap)
xwl_window_buffer_destroy_pixmap (xwl_window_buffer);
+ if (xwl_window_buffer->sync_fd >= 0)
+ close(xwl_window_buffer->sync_fd);
+
xorg_list_del(&xwl_window_buffer->link_buffer);
free(xwl_window_buffer);
@@ -194,6 +207,7 @@ xwl_window_buffer_release_callback(void *data)
{
struct xwl_window_buffer *xwl_window_buffer = data;
struct xwl_window *xwl_window = xwl_window_buffer->xwl_window;
+ struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
struct xwl_window_buffer *oldest_available_buffer;
/* Drop the reference on the buffer we took in get_pixmap. If that
@@ -221,6 +235,14 @@ xwl_window_buffer_release_callback(void *data)
struct xwl_window_buffer,
link_buffer);
+ if (xwl_window_buffer->release_point) {
+ /* We will wait for this fence before re-using the buffer */
+ xwl_window_buffer->sync_fd =
+ xwl_screen->server_syncobj->export_fence(xwl_screen->server_syncobj,
+ xwl_window_buffer->release_point);
+ xwl_window_buffer->release_point = 0;
+ }
+
/* Schedule next timer based on time of the oldest buffer */
xwl_window->window_buffers_timer =
TimerSet(xwl_window->window_buffers_timer,
@@ -289,6 +311,34 @@ xwl_window_buffers_dispose(struct xwl_window *xwl_window)
}
}
+static void
+xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer)
+{
+ struct xwl_window *xwl_window = xwl_window_buffer->xwl_window;
+ struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
+ uint64_t acquire_point = xwl_screen->glamor_timeline_point++;
+ uint64_t release_point = xwl_screen->server_timeline_point++;
+
+ int fence_fd = xwl_glamor_get_fence(xwl_screen);
+ if (fence_fd >= 0) {
+ xwl_screen->glamor_syncobj->import_fence(xwl_screen->glamor_syncobj,
+ acquire_point, fence_fd);
+ } else {
+#ifdef XWL_HAS_GLAMOR
+ glamor_finish(xwl_screen->screen);
+#endif /* XWL_HAS_GLAMOR */
+ xwl_screen->glamor_syncobj->signal(xwl_screen->glamor_syncobj,
+ acquire_point);
+ }
+
+ xwl_window_buffer->release_point = release_point;
+ xwl_glamor_dri3_syncobj_passthrough(xwl_window->window,
+ xwl_screen->glamor_syncobj,
+ xwl_screen->server_syncobj,
+ acquire_point,
+ release_point);
+}
+
PixmapPtr
xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
RegionPtr damage_region)
@@ -313,6 +363,14 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
full_damage = xwl_window_buffer->damage_region;
+#ifdef XWL_HAS_GLAMOR
+ if (xwl_window_buffer->sync_fd >= 0) {
+ xwl_glamor_wait_fence(xwl_screen, xwl_window_buffer->sync_fd);
+ close(xwl_window_buffer->sync_fd);
+ xwl_window_buffer->sync_fd = -1;
+ }
+#endif /* XWL_HAS_GLAMOR */
+
if (xwl_window_buffer->pixmap) {
BoxPtr pBox = RegionRects(full_damage);
int nBox = RegionNumRects(full_damage);
@@ -359,6 +417,16 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window,
/* Hold a reference on the buffer until it's released by the compositor */
xwl_window_buffer->refcnt++;
+
+#ifdef XWL_HAS_GLAMOR
+ if (!xwl_glamor_supports_implicit_sync(xwl_screen)) {
+ if (xwl_screen->explicit_sync)
+ xwl_window_buffers_set_syncpts(xwl_window_buffer);
+ else
+ glamor_finish(xwl_screen->screen);
+ }
+#endif /* XWL_HAS_GLAMOR */
+
xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap,
xwl_window_buffer_release_callback,
xwl_window_buffer);
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index a4f02a0..070d40d 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -50,6 +50,7 @@
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "xwayland-shell-v1-client-protocol.h"
+#include "linux-drm-syncobj-v1-client-protocol.h"
#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
@@ -1159,6 +1160,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);
@@ -1364,6 +1368,13 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window)
pixmap = xwl_window_buffers_get_pixmap(xwl_window, region);
#ifdef XWL_HAS_GLAMOR
+ if (xwl_glamor_supports_implicit_sync(xwl_screen) &&
+ xwl_window->surface_sync) {
+ /* prefer implicit sync when possible */
+ wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
+ xwl_window->surface_sync = NULL;
+ }
+
if (xwl_screen->glamor)
buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap);
else
diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h
index 45ae16d..51ce91b 100644
--- a/hw/xwayland/xwayland-window.h
+++ b/hw/xwayland/xwayland-window.h
@@ -122,6 +122,7 @@ struct xwl_window {
/* If TRUE, the window buffer format supports scanout with implicit modifier */
Bool has_implicit_scanout_support;
struct wp_tearing_control_v1 *tearing_control;
+ struct wp_linux_drm_syncobj_surface_v1 *surface_sync;
};
struct xwl_window *xwl_window_get(WindowPtr window);
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index d7bfc6d..e28e238 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -48,7 +48,7 @@
/* DRI3 */
#define SERVER_DRI3_MAJOR_VERSION 1
-#define SERVER_DRI3_MINOR_VERSION 2
+#define SERVER_DRI3_MINOR_VERSION 4
/* DMX */
#define SERVER_DMX_MAJOR_VERSION 2
@@ -69,7 +69,7 @@
/* Present */
#define SERVER_PRESENT_MAJOR_VERSION 1
-#define SERVER_PRESENT_MINOR_VERSION 2
+#define SERVER_PRESENT_MINOR_VERSION 4
/* RandR */
#define SERVER_RANDR_MAJOR_VERSION 1
diff --git a/present/present.c b/present/present.c
index 2118683..e0764fa 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 68a5878..6d8ac29 100644
--- a/present/present_execute.c
+++ b/present/present_execute.c
@@ -21,6 +21,7 @@
*/
#include "present_priv.h"
+#include <sys/eventfd.h>
/*
* Called when the wait fence is triggered; just gets the current msc/ust and
@@ -37,6 +38,21 @@ present_wait_fence_triggered(void *param)
screen_priv->re_execute(vblank);
}
+static void present_syncobj_triggered(int fd, int xevents, void *data)
+{
+ present_vblank_ptr vblank = data;
+ ScreenPtr screen = vblank->screen;
+ present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+ uint64_t efd_value;
+
+ read(fd, &efd_value, sizeof (efd_value));
+ SetNotifyFd(fd, NULL, 0, NULL);
+ close(fd);
+ vblank->efd = -1;
+
+ screen_priv->re_execute(vblank);
+}
+
Bool
present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
{
@@ -58,6 +74,19 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
return TRUE;
}
}
+
+ /* Defer execution of explicitly synchronized copies.
+ * Flip synchronization is managed by the driver.
+ */
+ if (!vblank->flip && vblank->acquire_syncobj &&
+ !vblank->acquire_syncobj->check(vblank->acquire_syncobj, vblank->acquire_point)) {
+ vblank->efd = eventfd(0, EFD_CLOEXEC);
+ SetNotifyFd(vblank->efd, present_syncobj_triggered, X_NOTIFY_READ, vblank);
+ vblank->acquire_syncobj->eventfd(vblank->acquire_syncobj, vblank->acquire_point,
+ vblank->efd, FALSE /* wait_avail */);
+ return TRUE;
+ }
+
return FALSE;
}
@@ -85,7 +114,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 4ad7298..727d523 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 f3e5679..1f4f8a4 100644
--- a/present/present_request.c
+++ b/present/present_request.c
@@ -79,79 +79,121 @@ proc_present_query_version(ClientPtr client)
} while (0)
static int
-proc_present_pixmap(ClientPtr client)
+proc_present_pixmap_common(ClientPtr client,
+ Window req_window,
+ Pixmap req_pixmap,
+ CARD32 req_serial,
+ CARD32 req_valid,
+ CARD32 req_update,
+ INT16 req_x_off,
+ INT16 req_y_off,
+ CARD32 req_target_crtc,
+ XSyncFence req_wait_fence,
+ XSyncFence req_idle_fence,
+ struct dri3_syncobj *acquire_syncobj,
+ struct dri3_syncobj *release_syncobj,
+ CARD64 req_acquire_point,
+ CARD64 req_release_point,
+ CARD32 req_options,
+ CARD64 req_target_msc,
+ CARD64 req_divisor,
+ CARD64 req_remainder,
+ size_t base_req_size,
+ xPresentNotify *req_notifies)
{
- REQUEST(xPresentPixmapReq);
- WindowPtr window;
- PixmapPtr pixmap;
- RegionPtr valid = NULL;
- RegionPtr update = NULL;
- SyncFence *wait_fence;
- SyncFence *idle_fence;
- RRCrtcPtr target_crtc;
- int ret;
- int nnotifies;
- present_notify_ptr notifies = NULL;
-
- REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
- ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
+ WindowPtr window;
+ PixmapPtr pixmap;
+ RegionPtr valid = NULL;
+ RegionPtr update = NULL;
+ RRCrtcPtr target_crtc;
+ SyncFence *wait_fence;
+ SyncFence *idle_fence;
+ int nnotifies;
+ present_notify_ptr notifies = NULL;
+ int ret;
+
+ ret = dixLookupWindow(&window, req_window, client, DixWriteAccess);
if (ret != Success)
return ret;
- ret = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
+ ret = dixLookupResourceByType((void **) &pixmap, req_pixmap, RT_PIXMAP, client, DixReadAccess);
if (ret != Success)
return ret;
if (window->drawable.depth != pixmap->drawable.depth)
return BadMatch;
- VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
- VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
+ VERIFY_REGION_OR_NONE(valid, req_valid, client, DixReadAccess);
+ VERIFY_REGION_OR_NONE(update, req_update, client, DixReadAccess);
+
+ VERIFY_CRTC_OR_NONE(target_crtc, req_target_crtc, client, DixReadAccess);
- VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
+ VERIFY_FENCE_OR_NONE(wait_fence, req_wait_fence, client, DixReadAccess);
+ VERIFY_FENCE_OR_NONE(idle_fence, req_idle_fence, client, DixWriteAccess);
- VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
- VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
+ if ((acquire_syncobj && req_acquire_point == 0) ||
+ (release_syncobj && req_release_point == 0))
+ return BadValue;
- if (stuff->options & ~(PresentAllOptions)) {
- client->errorValue = stuff->options;
+ if (req_options & ~(PresentAllOptions)) {
+ client->errorValue = req_options;
return BadValue;
}
/*
* Check to see if remainder is sane
*/
- if (stuff->divisor == 0) {
- if (stuff->remainder != 0) {
- client->errorValue = (CARD32) stuff->remainder;
+ if (req_divisor == 0) {
+ if (req_remainder != 0) {
+ client->errorValue = (CARD32)req_remainder;
return BadValue;
}
} else {
- if (stuff->remainder >= stuff->divisor) {
- client->errorValue = (CARD32) stuff->remainder;
+ if (req_remainder >= req_divisor) {
+ client->errorValue = (CARD32)req_remainder;
return BadValue;
}
}
- nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
+ nnotifies = (client->req_len << 2) - base_req_size;
if (nnotifies % sizeof (xPresentNotify))
return BadLength;
nnotifies /= sizeof (xPresentNotify);
if (nnotifies) {
- ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), &notifies);
+ ret = present_create_notifies(client, nnotifies, req_notifies, &notifies);
if (ret != Success)
return ret;
}
- ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
- stuff->x_off, stuff->y_off, target_crtc,
- wait_fence, idle_fence, stuff->options,
- stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
+ ret = present_pixmap(window, pixmap, req_serial,
+ valid, update, req_x_off, req_y_off, target_crtc,
+ wait_fence, idle_fence,
+ acquire_syncobj, release_syncobj,
+ req_acquire_point, req_release_point,
+ req_options, req_target_msc, req_divisor, req_remainder,
+ notifies, nnotifies);
+
if (ret != Success)
present_destroy_notifies(notifies, nnotifies);
return ret;
}
+static int
+proc_present_pixmap(ClientPtr client)
+{
+ REQUEST(xPresentPixmapReq);
+ REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
+ return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial,
+ stuff->valid, stuff->update, stuff->x_off, stuff->y_off,
+ stuff->target_crtc,
+ stuff->wait_fence, stuff->idle_fence,
+ None, None, 0, 0,
+ stuff->options, stuff->target_msc,
+ stuff->divisor, stuff->remainder,
+ sizeof (xPresentPixmapReq),
+ (xPresentNotify *)(stuff + 1));
+}
+
static int
proc_present_notify_msc(ClientPtr client)
{
@@ -240,12 +282,36 @@ proc_present_query_capabilities (ClientPtr client)
return Success;
}
+static int
+proc_present_pixmap_synced (ClientPtr client)
+{
+ REQUEST(xPresentPixmapSyncedReq);
+ struct dri3_syncobj *acquire_syncobj;
+ struct dri3_syncobj *release_syncobj;
+
+ REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq);
+ VERIFY_DRI3_SYNCOBJ(stuff->acquire_syncobj, acquire_syncobj, DixWriteAccess);
+ VERIFY_DRI3_SYNCOBJ(stuff->release_syncobj, release_syncobj, DixWriteAccess);
+
+ return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial,
+ stuff->valid, stuff->update, stuff->x_off, stuff->y_off,
+ stuff->target_crtc,
+ None, None,
+ acquire_syncobj, release_syncobj,
+ stuff->acquire_point, stuff->release_point,
+ stuff->options, stuff->target_msc,
+ stuff->divisor, stuff->remainder,
+ sizeof (xPresentPixmapSyncedReq),
+ (xPresentNotify *)(stuff + 1));
+}
+
static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
proc_present_query_version, /* 0 */
proc_present_pixmap, /* 1 */
proc_present_notify_msc, /* 2 */
proc_present_select_input, /* 3 */
proc_present_query_capabilities, /* 4 */
+ proc_present_pixmap_synced, /* 5 */
};
int
@@ -325,12 +391,47 @@ sproc_present_query_capabilities (ClientPtr client)
return (*proc_present_vector[stuff->presentReqType]) (client);
}
+
+static int _X_COLD
+sproc_present_pixmap_synced(ClientPtr client)
+{
+ REQUEST(xPresentPixmapSyncedReq);
+ REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq);
+
+ swaps(&stuff->length);
+
+ swapl(&stuff->window);
+
+ swapl(&stuff->pixmap);
+ swapl(&stuff->serial);
+
+ swapl(&stuff->valid);
+ swapl(&stuff->update);
+
+ swaps(&stuff->x_off);
+ swaps(&stuff->y_off);
+ swapl(&stuff->target_crtc);
+
+ swapl(&stuff->acquire_syncobj);
+ swapl(&stuff->release_syncobj);
+ swapll(&stuff->acquire_point);
+ swapll(&stuff->release_point);
+
+ swapl(&stuff->options);
+
+ swapll(&stuff->target_msc);
+ swapll(&stuff->divisor);
+ swapll(&stuff->remainder);
+ return (*proc_present_vector[stuff->presentReqType]) (client);
+}
+
static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
sproc_present_query_version, /* 0 */
sproc_present_pixmap, /* 1 */
sproc_present_notify_msc, /* 2 */
sproc_present_select_input, /* 3 */
sproc_present_query_capabilities, /* 4 */
+ sproc_present_pixmap_synced, /* 5 */
};
int _X_COLD
diff --git a/present/present_scmd.c b/present/present_scmd.c
index d378f00..07dd41c 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 2c29aaf..df6a6a2 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 4f94f16..2eb57ab 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);
}
--
2.41.0