diff --git a/dri3/dri3.c b/dri3/dri3.c index 191252969518a78e5b042d62177b238474ec50ff..f9c517277432537cfbbc6fc44f10773a5d1273aa 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 02d3b03eecf043156f3fca00fd38d135032f095d..f738fe8f5fe12d01eb278f43806936c920db85fb 100644 --- a/dri3/dri3.h +++ b/dri3/dri3.h @@ -30,6 +30,31 @@ #define DRI3_SCREEN_INFO_VERSION 2 +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); +}; + +#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, int *fd); @@ -84,6 +109,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 +131,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 f319d17702c6101c372491405590b25ec4350035..71d2da95713f9fcfb58addeb11cde8afb47a89ee 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 6871689308d579a041735c47342664976c27d9fd..e7218b8b9c5d33edaa35220c44f7b05314b4a0ad 100644 --- a/dri3/dri3_request.c +++ b/dri3/dri3_request.c @@ -554,6 +554,51 @@ proc_dri3_buffers_from_pixmap(ClientPtr client) return Success; } +static int +proc_dri3_import_syncobj(ClientPtr client) +{ + REQUEST(xDRI3ImportSyncobjReq); + DrawablePtr drawable; + ScreenPtr screen; + int fd; + int status; + + SetReqFds(client, 1); + REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq); + LEGAL_NEW_RESOURCE(stuff->syncobj, client); + + status = dixLookupDrawable(&drawable, stuff->drawable, client, + M_ANY, DixGetAttrAccess); + if (status != Success) + return status; + + screen = drawable->pScreen; + + fd = ReadFdFromClient(client); + if (fd < 0) + return BadValue; + + return dri3_import_syncobj(client, screen, stuff->syncobj, fd); +} + +static int +proc_dri3_free_syncobj(ClientPtr client) +{ + REQUEST(xDRI3FreeSyncobjReq); + struct dri3_syncobj *syncobj; + int status; + + REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq); + + status = dixLookupResourceByType((void **) &syncobj, stuff->syncobj, + dri3_syncobj_type, client, DixWriteAccess); + if (status != Success) + return status; + + FreeResource(stuff->syncobj, dri3_syncobj_type); + return Success; +} + int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { proc_dri3_query_version, /* 0 */ proc_dri3_open, /* 1 */ @@ -564,6 +609,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 */ + NULL, /* 9 */ + proc_dri3_import_syncobj, /* 10 */ + proc_dri3_free_syncobj, /* 11 */ }; int @@ -697,6 +745,29 @@ sproc_dri3_buffers_from_pixmap(ClientPtr client) return (*proc_dri3_vector[stuff->dri3ReqType]) (client); } +static int _X_COLD +sproc_dri3_import_syncobj(ClientPtr client) +{ + REQUEST(xDRI3ImportSyncobjReq); + REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq); + + swaps(&stuff->length); + swapl(&stuff->syncobj); + swapl(&stuff->drawable); + return (*proc_dri3_vector[stuff->dri3ReqType]) (client); +} + +static int _X_COLD +sproc_dri3_free_syncobj(ClientPtr client) +{ + REQUEST(xDRI3FreeSyncobjReq); + REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq); + + swaps(&stuff->length); + swapl(&stuff->syncobj); + return (*proc_dri3_vector[stuff->dri3ReqType]) (client); +} + int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { sproc_dri3_query_version, /* 0 */ sproc_dri3_open, /* 1 */ @@ -707,6 +778,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 */ + NULL, /* 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 3c7e5bf60f9b9911afd738caa981411971eb6d81..57df426ac54ebc7837f1e4ff1d69a40404bc7d0a 100644 --- a/dri3/dri3_screen.c +++ b/dri3/dri3_screen.c @@ -304,3 +304,21 @@ 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->import_syncobj) + return BadImplementation; + + syncobj = info->import_syncobj(client, screen, id, fd); + if (!syncobj) + return BadAlloc; + + if (!AddResource(id, dri3_syncobj_type, syncobj)) + return BadAlloc; + + return Success; +} diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 60c63ba990d90ec030a648f2fca2094d051fa94b..93610d9a8fc5ef1af49e6ed276b67ace866f8f67 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -52,6 +52,8 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" +static uint32_t scratch_syncobj = 0; + struct xwl_gbm_private { char *device_name; struct gbm_device *gbm; @@ -438,6 +440,9 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) wl_drm_destroy(xwl_gbm->drm); if (xwl_gbm->gbm) gbm_device_destroy(xwl_gbm->gbm); + if (scratch_syncobj) + drmSyncobjDestroy(xwl_gbm->drm_fd, + scratch_syncobj); free(xwl_gbm); } @@ -652,6 +657,105 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, return -1; } +struct xwl_syncobj +{ + struct dri3_syncobj base; + uint32_t handle; +}; + +static Bool xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, + uint64_t point) +{ + struct xwl_syncobj *xwl_syncobj = (struct xwl_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 */, 0 /* flags */, + NULL /* first_signaled */); +} + +static int xwl_dri3_syncobj_export_fence(struct dri3_syncobj *syncobj, + uint64_t point) +{ + struct xwl_syncobj *xwl_syncobj = (struct xwl_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 (!drmSyncobjTransfer(xwl_gbm->drm_fd, + scratch_syncobj, 0, + xwl_syncobj->handle, point, + 0 /* flags */)) + drmSyncobjExportSyncFile(xwl_gbm->drm_fd, scratch_syncobj, &fd); + + return fd; +} + +static void xwl_dri3_syncobj_import_fence(struct dri3_syncobj *syncobj, + uint64_t point, int fd) +{ + struct xwl_syncobj *xwl_syncobj = (struct xwl_syncobj *)syncobj; + struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (!drmSyncobjImportSyncFile(xwl_gbm->drm_fd, scratch_syncobj, fd)) + drmSyncobjTransfer(xwl_gbm->drm_fd, + xwl_syncobj->handle, point, + scratch_syncobj, 0, + 0 /* flags */); + close(fd); +} + +static void xwl_dri3_signal_syncobj(struct dri3_syncobj *syncobj, + uint64_t point) +{ + struct xwl_syncobj *xwl_syncobj = (struct xwl_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_syncobj *xwl_syncobj = (struct xwl_syncobj *)syncobj; + struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + drmSyncobjDestroy(xwl_gbm->drm_fd, xwl_syncobj->handle); + free(xwl_syncobj); +} + +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_syncobj *syncobj = calloc(1, sizeof (*syncobj)); + + if (!syncobj) + return NULL; + + if (drmSyncobjFDToHandle(xwl_gbm->drm_fd, fd, &syncobj->handle)) { + free(syncobj); + return NULL; + } + + syncobj->base.id = id; + syncobj->base.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; + return &syncobj->base; +} + static const dri3_screen_info_rec xwl_dri3_info = { .version = 2, .open = NULL, @@ -661,6 +765,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 = glamor_get_drawable_modifiers, + .import_syncobj = xwl_dri3_import_syncobj, }; static const char * @@ -996,6 +1101,13 @@ 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; + if (drmSyncobjCreate(xwl_gbm->drm_fd, 0 /* flags */, + &scratch_syncobj)) { + ErrorF("failed to create DRM syncobj\n"); + goto error; + } + + return TRUE; error: if (xwl_screen->egl_display != EGL_NO_DISPLAY) { diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 99e476b2fd79e253926f65121adea9990f480c2b..23bf7be5d999ee1468144e7dae92d8517a5e4a9e 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -33,9 +33,7 @@ #include "xwayland-window.h" #include "xwayland-pixmap.h" #include "glamor.h" - - -#define XWL_PRESENT_CAPS PresentCapabilityAsync +#include "glamor_egl.h" /* @@ -173,7 +171,8 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_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 @@ -240,6 +239,9 @@ xwl_present_free_event(struct xwl_present_event *event) static void xwl_present_free_idle_vblank(present_vblank_ptr vblank) { + if (vblank->syncobj) + vblank->syncobj->signal(vblank->syncobj, vblank->release_point); + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); xwl_present_free_event(xwl_present_event_from_id((uintptr_t)vblank)); } @@ -395,6 +397,10 @@ xwl_present_buffer_release(void *data) return; vblank = &event->vblank; + + if (vblank->syncobj) + vblank->syncobj->signal(vblank->syncobj, vblank->release_point); + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); xwl_present_window = xwl_present_window_priv(vblank->window); @@ -559,6 +565,31 @@ xwl_present_flush(WindowPtr window) glamor_block_handler(window->drawable.pScreen); } +static int +xwl_present_flush_fenced(WindowPtr window) +{ + struct xwl_window *xwl_window = xwl_window_from_window(window); + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + EGLint attribs[3]; + EGLSyncKHR sync; + int fence_fd = -1; + assert(xwl_screen->present_capabilities & PresentCapabilitySyncobj); + + 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); + } + + xwl_present_flush(window); + return fence_fd; +} + static Bool xwl_present_check_flip(RRCrtcPtr crtc, WindowPtr present_window, @@ -855,6 +886,9 @@ xwl_present_pixmap(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t target_window_msc, uint64_t divisor, @@ -870,6 +904,7 @@ 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); struct xwl_present_event *event; if (!window_priv) @@ -909,6 +944,9 @@ xwl_present_pixmap(WindowPtr window, if (vblank->target_msc != target_msc) continue; + if (vblank->syncobj) + vblank->syncobj->signal(vblank->syncobj, vblank->release_point); + present_vblank_scrap(vblank); if (vblank->flip_ready) xwl_present_re_execute(vblank); @@ -921,7 +959,9 @@ 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, + target_crtc, wait_fence, idle_fence, + syncobj, acquire_point, release_point, + options, xwl_screen->present_capabilities, notifies, num_notifies, target_msc, crtc_msc)) { present_vblank_destroy(vblank); return BadAlloc; @@ -981,6 +1021,12 @@ xwl_present_init(ScreenPtr screen) if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0)) return FALSE; + xwl_screen->present_capabilities = PresentCapabilityAsync; + if (epoxy_has_egl_extension(xwl_screen->egl_display, + "ANDROID_native_fence_sync")) + xwl_screen->present_capabilities |= + PresentCapabilitySyncobj; + screen_priv->query_capabilities = xwl_present_query_capabilities; screen_priv->get_crtc = xwl_present_get_crtc; @@ -991,6 +1037,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-screen.h b/hw/xwayland/xwayland-screen.h index fd201cdf5f540563a57d849cf12f69f58d9089af..b8613822394ca44a2d1bbd3b5ea02fd5c498d132 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -132,6 +132,8 @@ struct xwl_screen { int libdecor_fd; struct libdecor *libdecor_context; #endif + + uint32_t present_capabilities; }; /* Apps which use randr/vidmode to change the mode when going fullscreen, diff --git a/present/present.c b/present/present.c index 271fe32bc8b389498171dc572f17f5cd611ff167..7baba1146158d5742a5933f87fffd1d05fd44b1b 100644 --- a/present/present.c +++ b/present/present.c @@ -230,6 +230,9 @@ present_pixmap(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t window_msc, uint64_t divisor, @@ -250,6 +253,9 @@ present_pixmap(WindowPtr window, target_crtc, wait_fence, idle_fence, + syncobj, + acquire_point, + release_point, options, window_msc, divisor, @@ -272,6 +278,7 @@ present_notify_msc(WindowPtr window, 0, 0, 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 68a5878be9c3f9698e4905c36965cf1e5b6efc89..77db32fb936cf16887c390fbf8e8e2c322f30eeb 100644 --- a/present/present_execute.c +++ b/present/present_execute.c @@ -37,6 +37,18 @@ present_wait_fence_triggered(void *param) screen_priv->re_execute(vblank); } +static void present_syncobj_triggered(int fd, int xevents, void *data) +{ + present_vblank_ptr vblank = data; + ScreenPtr screen = vblank->screen; + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + + SetNotifyFd(fd, NULL, 0, NULL); + close(fd); + vblank->notify_fd = -1; + screen_priv->re_execute(vblank); +} + Bool present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) { @@ -58,6 +70,17 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) return TRUE; } } + + if (vblank->syncobj && !vblank->syncobj->check(vblank->syncobj, vblank->acquire_point)) { + int fence_fd = vblank->syncobj->export_fence(vblank->syncobj, vblank->acquire_point); + if (fence_fd >= 0) { + SetNotifyFd(fence_fd, present_syncobj_triggered, X_NOTIFY_READ, vblank); + assert(vblank->notify_fd == -1); + vblank->notify_fd = fence_fd; + return TRUE; + } + } + return FALSE; } @@ -85,7 +108,12 @@ 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->syncobj) { + int fence_fd = screen_priv->flush_fenced(window); + vblank->syncobj->import_fence(vblank->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 6ebd009a26e8d65101653fb36ff50df7c8eaf65d..2bf8cb6b611f0e7567e67e751ec164ce8ef5ec7a 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 @@ -85,6 +86,10 @@ 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 *syncobj; + uint64_t acquire_point; + uint64_t release_point; + int notify_fd; }; typedef struct present_screen_priv present_screen_priv_rec, *present_screen_priv_ptr; @@ -119,6 +124,9 @@ typedef int (*present_priv_pixmap_ptr)(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t window_msc, uint64_t divisor, @@ -132,6 +140,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, @@ -142,6 +151,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; @@ -175,6 +185,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; @@ -285,6 +296,9 @@ present_pixmap(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t target_msc, uint64_t divisor, @@ -459,6 +473,9 @@ present_vblank_init(present_vblank_ptr vblank, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, const uint32_t capabilities, present_notify_ptr notifies, @@ -477,6 +494,9 @@ present_vblank_create(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *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 f3e5679b5d1c182d2a0e89b2a27506a000e7fdb7..e13f0ff5875258e8859bf3dd94f06d6fc34c9f7b 100644 --- a/present/present_request.c +++ b/present/present_request.c @@ -145,7 +145,7 @@ proc_present_pixmap(ClientPtr client) ret = present_pixmap(window, pixmap, stuff->serial, valid, update, stuff->x_off, stuff->y_off, target_crtc, - wait_fence, idle_fence, stuff->options, + wait_fence, idle_fence, NULL, 0, 0, stuff->options, stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies); if (ret != Success) present_destroy_notifies(notifies, nnotifies); @@ -240,12 +240,104 @@ proc_present_query_capabilities (ClientPtr client) return Success; } +#define VERIFY_SYNCOBJ_OR_NONE(syncobj_ptr, syncobj_id, client, access)\ + do {\ + if ((syncobj_id) == None)\ + (syncobj_ptr) = NULL;\ + else \ + VERIFY_DRI3_SYNCOBJ(syncobj_id, syncobj_ptr, access);\ + } while (0); + +static int +proc_present_pixmap_synced (ClientPtr client) +{ + REQUEST(xPresentPixmapSyncedReq); + WindowPtr window; + PixmapPtr pixmap; + RegionPtr valid = NULL; + RegionPtr update = NULL; + SyncFence *wait_fence; + SyncFence *idle_fence; + struct dri3_syncobj *syncobj; + RRCrtcPtr target_crtc; + int ret; + int nnotifies; + present_notify_ptr notifies = NULL; + + REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq); + ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess); + if (ret != Success) + return ret; + ret = dixLookupResourceByType((void **) &pixmap, stuff->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_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess); + + VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess); + VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess); + + VERIFY_SYNCOBJ_OR_NONE(syncobj, stuff->syncobj, client, DixWriteAccess); + + if (stuff->options & ~(PresentAllOptions)) { + client->errorValue = stuff->options; + return BadValue; + } + + if (stuff->divisor == 0) { + if (stuff->remainder != 0) { + client->errorValue = (CARD32) stuff->remainder; + return BadValue; + } + } else { + if (stuff->remainder >= stuff->divisor) { + client->errorValue = (CARD32) stuff->remainder; + return BadValue; + } + } + + if (stuff->syncobj && + (stuff->acquire_point == 0 || + stuff->release_point == 0 || + stuff->acquire_point >= stuff->release_point)) + return BadValue; + + nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapSyncedReq); + if (nnotifies % sizeof (xPresentNotify)) + return BadLength; + + nnotifies /= sizeof (xPresentNotify); + if (nnotifies) { + ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), ¬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, + syncobj, stuff->acquire_point, stuff->release_point, + stuff->options, stuff->target_msc, stuff->divisor, stuff->remainder, + notifies, nnotifies); + if (ret != Success) + present_destroy_notifies(notifies, nnotifies); + return ret; +} + 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 +417,49 @@ 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->wait_fence); + swapl(&stuff->idle_fence); + + swapl(&stuff->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 239055bc10d8c934555356c4213cda37dbff711e..5d4b44f5904b0735f4363aef6f1bec7c19a5c9ef 100644 --- a/present/present_scmd.c +++ b/present/present_scmd.c @@ -674,6 +674,9 @@ present_scmd_pixmap(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, uint64_t target_window_msc, uint64_t divisor, @@ -755,6 +758,9 @@ present_scmd_pixmap(WindowPtr window, target_crtc, wait_fence, idle_fence, + 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 15684eda4963f52ed034390b142ad377890f2343..e9d124298e480babfd3ecf13b32cc1f30778e845 100644 --- a/present/present_screen.c +++ b/present/present_screen.c @@ -178,6 +178,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 a9f17d4b2be374257b44199959c5ae1beb2d3972..4becdbab82251ddd8dd283de5e4bb439affdc533 100644 --- a/present/present_vblank.c +++ b/present/present_vblank.c @@ -55,6 +55,9 @@ present_vblank_init(present_vblank_ptr vblank, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, const uint32_t capabilities, present_notify_ptr notifies, @@ -106,6 +109,7 @@ present_vblank_init(present_vblank_ptr vblank, vblank->notifies = notifies; vblank->num_notifies = num_notifies; vblank->has_suboptimal = (options & PresentOptionSuboptimal); + vblank->notify_fd = -1; if (pixmap != NULL && !(options & PresentOptionCopy) && @@ -135,6 +139,13 @@ present_vblank_init(present_vblank_ptr vblank, goto no_mem; } + if (capabilities & PresentCapabilitySyncobj) { + vblank->syncobj = syncobj; + vblank->acquire_point = acquire_point; + vblank->release_point = release_point; + ++syncobj->refcount; + } + 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 +169,9 @@ present_vblank_create(WindowPtr window, RRCrtcPtr target_crtc, SyncFence *wait_fence, SyncFence *idle_fence, + struct dri3_syncobj *syncobj, + uint64_t acquire_point, + uint64_t release_point, uint32_t options, const uint32_t capabilities, present_notify_ptr notifies, @@ -172,6 +186,7 @@ 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, + syncobj, acquire_point, release_point, options, capabilities, notifies, num_notifies, target_msc, crtc_msc)) return vblank; @@ -229,5 +244,13 @@ present_vblank_destroy(present_vblank_ptr vblank) if (vblank->notifies) present_destroy_notifies(vblank->notifies, vblank->num_notifies); + if (vblank->notify_fd >= 0) { + SetNotifyFd(vblank->notify_fd, NULL, 0, NULL); + close(vblank->notify_fd); + } + + if (vblank->syncobj && --vblank->syncobj->refcount == 0) + vblank->syncobj->free(vblank->syncobj); + free(vblank); }