From 78f590e35e91b69e5ca14e74e6f44b82fb7a401f Mon Sep 17 00:00:00 2001 From: GloriousEggroll 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 #include -#define DRI3_SCREEN_INFO_VERSION 2 +#define DRI3_SCREEN_INFO_VERSION 4 + +extern RESTYPE dri3_syncobj_type; + +struct dri3_syncobj +{ + XID id; + ScreenPtr screen; + uint32_t refcount; + + void (*free)(struct dri3_syncobj *syncobj); + Bool (*check)(struct dri3_syncobj *syncobj, uint64_t point); + int (*export_fence)(struct dri3_syncobj *syncobj, uint64_t point); + void (*import_fence)(struct dri3_syncobj *syncobj, uint64_t point, int fd); + void (*signal)(struct dri3_syncobj *syncobj, uint64_t point); + void (*eventfd)(struct dri3_syncobj *syncobj, uint64_t point, int efd, Bool wait_avail); +}; + +#define VERIFY_DRI3_SYNCOBJ(id, ptr, a)\ + do {\ + int rc = dixLookupResourceByType((void **)&(ptr), id,\ + dri3_syncobj_type, client, a);\ + if (rc != Success) {\ + client->errorValue = id;\ + return rc;\ + }\ + } while (0); typedef int (*dri3_open_proc)(ScreenPtr screen, RRProviderPtr provider, @@ -84,6 +110,11 @@ typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw, uint32_t *num_modifiers, uint64_t **modifiers); +typedef struct dri3_syncobj *(*dri3_import_syncobj_proc) (ClientPtr client, + ScreenPtr screen, + XID id, + int fd); + typedef struct dri3_screen_info { uint32_t version; @@ -101,6 +132,9 @@ typedef struct dri3_screen_info { dri3_get_modifiers_proc get_modifiers; dri3_get_drawable_modifiers_proc get_drawable_modifiers; + /* Version 4 */ + dri3_import_syncobj_proc import_syncobj; + } dri3_screen_info_rec, *dri3_screen_info_ptr; extern _X_EXPORT Bool diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h index 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 #include +static Bool +dri3_screen_can_one_point_four(ScreenPtr screen) +{ + dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen); + + return dri3 && + dri3->info && + dri3->info->version >= 4 && + dri3->info->import_syncobj; +} + static Bool dri3_screen_can_one_point_two(ScreenPtr screen) { @@ -61,6 +72,10 @@ proc_dri3_query_version(ClientPtr client) rep.minorVersion = 0; break; } + if (!dri3_screen_can_one_point_four(screenInfo.screens[i])) { + rep.minorVersion = 2; + break; + } } for (int i = 0; i < screenInfo.numGPUScreens; i++) { @@ -68,6 +83,10 @@ proc_dri3_query_version(ClientPtr client) rep.minorVersion = 0; break; } + if (!dri3_screen_can_one_point_four(screenInfo.gpuscreens[i])) { + rep.minorVersion = 2; + break; + } } /* From DRI3 proto: @@ -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 #include #include +#include +#include +#include #define MESA_EGL_NO_X11_HEADERS #define EGL_NO_X11 @@ -51,6 +54,7 @@ #include "xwayland-screen.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" +#include "linux-drm-syncobj-v1-client-protocol.h" struct xwl_gbm_private { drmDevice *device; @@ -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 #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 +#include #define BUFFER_TIMEOUT 1 * 1000 /* ms */ @@ -40,6 +47,8 @@ struct xwl_window_buffer { PixmapPtr pixmap; RegionPtr damage_region; Bool recycle_on_release; + uint64_t release_point; + int sync_fd; int refcnt; uint32_t time; struct xorg_list link_buffer; @@ -80,6 +89,7 @@ xwl_window_buffer_new(struct xwl_window *xwl_window) xwl_window_buffer->xwl_window = xwl_window; xwl_window_buffer->damage_region = RegionCreate(NullBox, 1); xwl_window_buffer->pixmap = NullPixmap; + xwl_window_buffer->sync_fd = -1; xwl_window_buffer->refcnt = 1; xorg_list_append(&xwl_window_buffer->link_buffer, @@ -111,6 +121,9 @@ xwl_window_buffer_dispose(struct xwl_window_buffer *xwl_window_buffer) if (xwl_window_buffer->pixmap) xwl_window_buffer_destroy_pixmap (xwl_window_buffer); + if (xwl_window_buffer->sync_fd >= 0) + close(xwl_window_buffer->sync_fd); + xorg_list_del(&xwl_window_buffer->link_buffer); free(xwl_window_buffer); @@ -194,6 +207,7 @@ xwl_window_buffer_release_callback(void *data) { struct xwl_window_buffer *xwl_window_buffer = data; struct xwl_window *xwl_window = xwl_window_buffer->xwl_window; + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; struct xwl_window_buffer *oldest_available_buffer; /* Drop the reference on the buffer we took in get_pixmap. If that @@ -221,6 +235,14 @@ xwl_window_buffer_release_callback(void *data) struct xwl_window_buffer, link_buffer); + if (xwl_window_buffer->release_point) { + /* We will wait for this fence before re-using the buffer */ + xwl_window_buffer->sync_fd = + xwl_screen->server_syncobj->export_fence(xwl_screen->server_syncobj, + xwl_window_buffer->release_point); + xwl_window_buffer->release_point = 0; + } + /* Schedule next timer based on time of the oldest buffer */ xwl_window->window_buffers_timer = TimerSet(xwl_window->window_buffers_timer, @@ -289,6 +311,34 @@ xwl_window_buffers_dispose(struct xwl_window *xwl_window) } } +static void +xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer) +{ + struct xwl_window *xwl_window = xwl_window_buffer->xwl_window; + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + uint64_t acquire_point = xwl_screen->glamor_timeline_point++; + uint64_t release_point = xwl_screen->server_timeline_point++; + + int fence_fd = xwl_glamor_get_fence(xwl_screen); + if (fence_fd >= 0) { + xwl_screen->glamor_syncobj->import_fence(xwl_screen->glamor_syncobj, + acquire_point, fence_fd); + } else { +#ifdef XWL_HAS_GLAMOR + glamor_finish(xwl_screen->screen); +#endif /* XWL_HAS_GLAMOR */ + xwl_screen->glamor_syncobj->signal(xwl_screen->glamor_syncobj, + acquire_point); + } + + xwl_window_buffer->release_point = release_point; + xwl_glamor_dri3_syncobj_passthrough(xwl_window->window, + xwl_screen->glamor_syncobj, + xwl_screen->server_syncobj, + acquire_point, + release_point); +} + PixmapPtr xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, RegionPtr damage_region) @@ -313,6 +363,14 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, full_damage = xwl_window_buffer->damage_region; +#ifdef XWL_HAS_GLAMOR + if (xwl_window_buffer->sync_fd >= 0) { + xwl_glamor_wait_fence(xwl_screen, xwl_window_buffer->sync_fd); + close(xwl_window_buffer->sync_fd); + xwl_window_buffer->sync_fd = -1; + } +#endif /* XWL_HAS_GLAMOR */ + if (xwl_window_buffer->pixmap) { BoxPtr pBox = RegionRects(full_damage); int nBox = RegionNumRects(full_damage); @@ -359,6 +417,16 @@ xwl_window_buffers_get_pixmap(struct xwl_window *xwl_window, /* Hold a reference on the buffer until it's released by the compositor */ xwl_window_buffer->refcnt++; + +#ifdef XWL_HAS_GLAMOR + if (!xwl_glamor_supports_implicit_sync(xwl_screen)) { + if (xwl_screen->explicit_sync) + xwl_window_buffers_set_syncpts(xwl_window_buffer); + else + glamor_finish(xwl_screen->screen); + } +#endif /* XWL_HAS_GLAMOR */ + xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap, xwl_window_buffer_release_callback, xwl_window_buffer); diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 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 /* * 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 #include #include +#include "dri3.h" #if 0 #define DebugPresent(x) ErrorF x @@ -90,6 +91,11 @@ struct present_vblank { Bool abort_flip; /* aborting this flip */ PresentFlipReason reason; /* reason for which flip is not possible */ Bool has_suboptimal; /* whether client can support SuboptimalCopy mode */ + struct dri3_syncobj *acquire_syncobj; + struct dri3_syncobj *release_syncobj; + uint64_t acquire_point; + uint64_t release_point; + int efd; }; typedef struct present_screen_priv present_screen_priv_rec, *present_screen_priv_ptr; @@ -124,6 +130,10 @@ typedef int (*present_priv_pixmap_ptr)(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *acquire_syncobj, + struct dri3_syncobj *release_syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t window_msc, uint64_t divisor, @@ -137,6 +147,7 @@ typedef int (*present_priv_queue_vblank_ptr)(ScreenPtr screen, uint64_t event_id, uint64_t msc); typedef void (*present_priv_flush_ptr)(WindowPtr window); +typedef int (*present_priv_flush_fenced_ptr)(WindowPtr window); typedef void (*present_priv_re_execute_ptr)(present_vblank_ptr vblank); typedef void (*present_priv_abort_vblank_ptr)(ScreenPtr screen, @@ -147,6 +158,7 @@ typedef void (*present_priv_abort_vblank_ptr)(ScreenPtr screen, typedef void (*present_priv_flip_destroy_ptr)(ScreenPtr screen); struct present_screen_priv { + ScreenPtr pScreen; CloseScreenProcPtr CloseScreen; ConfigNotifyProcPtr ConfigNotify; DestroyWindowProcPtr DestroyWindow; @@ -180,6 +192,7 @@ struct present_screen_priv { present_priv_queue_vblank_ptr queue_vblank; present_priv_flush_ptr flush; + present_priv_flush_fenced_ptr flush_fenced; present_priv_re_execute_ptr re_execute; present_priv_abort_vblank_ptr abort_vblank; @@ -290,6 +303,10 @@ present_pixmap(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *acquire_syncobj, + struct dri3_syncobj *release_syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t target_msc, uint64_t divisor, @@ -464,6 +481,10 @@ present_vblank_init(present_vblank_ptr vblank, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *acquire_syncobj, + struct dri3_syncobj *release_syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, const uint32_t capabilities, present_notify_ptr notifies, @@ -482,6 +503,10 @@ present_vblank_create(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *acquire_syncobj, + struct dri3_syncobj *release_syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, const uint32_t capabilities, present_notify_ptr notifies, diff --git a/present/present_request.c b/present/present_request.c index 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), ¬ifies); + ret = present_create_notifies(client, nnotifies, req_notifies, ¬ifies); if (ret != Success) return ret; } - ret = present_pixmap(window, pixmap, stuff->serial, valid, update, - stuff->x_off, stuff->y_off, target_crtc, - wait_fence, idle_fence, stuff->options, - stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies); + ret = present_pixmap(window, pixmap, req_serial, + valid, update, req_x_off, req_y_off, target_crtc, + wait_fence, idle_fence, + acquire_syncobj, release_syncobj, + req_acquire_point, req_release_point, + req_options, req_target_msc, req_divisor, req_remainder, + notifies, nnotifies); + if (ret != Success) present_destroy_notifies(notifies, nnotifies); return ret; } +static int +proc_present_pixmap(ClientPtr client) +{ + REQUEST(xPresentPixmapReq); + REQUEST_AT_LEAST_SIZE(xPresentPixmapReq); + return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial, + stuff->valid, stuff->update, stuff->x_off, stuff->y_off, + stuff->target_crtc, + stuff->wait_fence, stuff->idle_fence, + None, None, 0, 0, + stuff->options, stuff->target_msc, + stuff->divisor, stuff->remainder, + sizeof (xPresentPixmapReq), + (xPresentNotify *)(stuff + 1)); +} + static int proc_present_notify_msc(ClientPtr client) { @@ -240,12 +282,36 @@ proc_present_query_capabilities (ClientPtr client) return Success; } +static int +proc_present_pixmap_synced (ClientPtr client) +{ + REQUEST(xPresentPixmapSyncedReq); + struct dri3_syncobj *acquire_syncobj; + struct dri3_syncobj *release_syncobj; + + REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq); + VERIFY_DRI3_SYNCOBJ(stuff->acquire_syncobj, acquire_syncobj, DixWriteAccess); + VERIFY_DRI3_SYNCOBJ(stuff->release_syncobj, release_syncobj, DixWriteAccess); + + return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial, + stuff->valid, stuff->update, stuff->x_off, stuff->y_off, + stuff->target_crtc, + None, None, + acquire_syncobj, release_syncobj, + stuff->acquire_point, stuff->release_point, + stuff->options, stuff->target_msc, + stuff->divisor, stuff->remainder, + sizeof (xPresentPixmapSyncedReq), + (xPresentNotify *)(stuff + 1)); +} + static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = { proc_present_query_version, /* 0 */ proc_present_pixmap, /* 1 */ proc_present_notify_msc, /* 2 */ proc_present_select_input, /* 3 */ proc_present_query_capabilities, /* 4 */ + proc_present_pixmap_synced, /* 5 */ }; int @@ -325,12 +391,47 @@ sproc_present_query_capabilities (ClientPtr client) return (*proc_present_vector[stuff->presentReqType]) (client); } + +static int _X_COLD +sproc_present_pixmap_synced(ClientPtr client) +{ + REQUEST(xPresentPixmapSyncedReq); + REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq); + + swaps(&stuff->length); + + swapl(&stuff->window); + + swapl(&stuff->pixmap); + swapl(&stuff->serial); + + swapl(&stuff->valid); + swapl(&stuff->update); + + swaps(&stuff->x_off); + swaps(&stuff->y_off); + swapl(&stuff->target_crtc); + + swapl(&stuff->acquire_syncobj); + swapl(&stuff->release_syncobj); + swapll(&stuff->acquire_point); + swapll(&stuff->release_point); + + swapl(&stuff->options); + + swapll(&stuff->target_msc); + swapll(&stuff->divisor); + swapll(&stuff->remainder); + return (*proc_present_vector[stuff->presentReqType]) (client); +} + static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = { sproc_present_query_version, /* 0 */ sproc_present_pixmap, /* 1 */ sproc_present_notify_msc, /* 2 */ sproc_present_select_input, /* 3 */ sproc_present_query_capabilities, /* 4 */ + sproc_present_pixmap_synced, /* 5 */ }; int _X_COLD diff --git a/present/present_scmd.c b/present/present_scmd.c index 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