diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 8307f74b1..ebc990b57 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include #include @@ -55,6 +57,7 @@ #include "xwayland-glamor-gbm.h" #include "xwayland-pixmap.h" #include "xwayland-screen.h" +#include "xwayland-window-buffers.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-drm-syncobj-v1-client-protocol.h" @@ -82,6 +85,12 @@ struct xwl_pixmap { unsigned int texture; struct gbm_bo *bo; Bool implicit_modifier; +#ifdef DRI3 + struct dri3_syncobj *syncobj; + uint64_t timeline_point; + int efd; + struct xwl_window_buffer *xwl_window_buffer; +#endif /* DRI3 */ }; static DevPrivateKeyRec xwl_gbm_private_key; @@ -225,6 +234,9 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, xwl_pixmap->bo = bo; xwl_pixmap->buffer = NULL; xwl_pixmap->implicit_modifier = implicit_modifier; +#ifdef XWL_HAS_GLAMOR + xwl_pixmap->efd = -1; +#endif /* XWL_HAS_GLAMOR */ #ifdef GBM_BO_FD_FOR_PLANE if (xwl_gbm->dmabuf_capable) { @@ -445,6 +457,7 @@ xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); if (xwl_pixmap->bo) gbm_bo_destroy(xwl_pixmap->bo); + xwl_glamor_gbm_dispose_syncpts(pixmap); free(xwl_pixmap); } @@ -1388,6 +1401,21 @@ xwl_glamor_gbm_has_egl_extension(void) epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm")); } +#ifdef DRI3 +static void +xwl_glamor_gbm_release_fence_avail(int fd, int xevents, void *data) +{ + struct xwl_pixmap *xwl_pixmap = data; + struct xwl_window_buffer *xwl_window_buffer = xwl_pixmap->xwl_window_buffer; + + SetNotifyFd(fd, NULL, 0, NULL); + close(fd); + xwl_pixmap->efd = -1; + + xwl_window_buffer_release(xwl_window_buffer); +} +#endif /* DRI3 */ + Bool xwl_glamor_supports_implicit_sync(struct xwl_screen *xwl_screen) { @@ -1403,6 +1431,122 @@ xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen) xwl_gbm_get(xwl_screen)->supports_syncobjs; } +Bool +xwl_glamor_gbm_set_syncpts(struct xwl_window *xwl_window, PixmapPtr pixmap) +{ +#ifdef DRI3 + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + uint64_t acquire_point; + uint64_t release_point; + int fence_fd; + + if (!xwl_screen->glamor) + return FALSE; + + if (!xwl_pixmap) { + ErrorF("XWAYLAND: Failed to set synchronization point, no backing xwl_pixmap!\n"); + return FALSE; + } + + acquire_point = ++xwl_pixmap->timeline_point; + release_point = ++xwl_pixmap->timeline_point; + + if (!xwl_pixmap->syncobj) { + struct dri3_syncobj *syncobj = xwl_glamor_dri3_syncobj_create(xwl_screen); + if (!syncobj) + goto fail; + xwl_pixmap->syncobj = syncobj; + } + + fence_fd = xwl_glamor_get_fence(xwl_screen); + if (fence_fd >= 0) + xwl_pixmap->syncobj->import_fence(xwl_pixmap->syncobj, acquire_point, fence_fd); + else + goto fail; + + xwl_glamor_dri3_syncobj_passthrough(xwl_window, + xwl_pixmap->syncobj, + xwl_pixmap->syncobj, + acquire_point, + release_point); + return TRUE; + +fail: + /* can't use explicit sync, we will do a glFinish() before presenting */ + if (xwl_pixmap->syncobj) { + xwl_pixmap->syncobj->free(xwl_pixmap->syncobj); + xwl_pixmap->syncobj = NULL; + } +#endif /* DRI3 */ + return FALSE; +} + +void +xwl_glamor_gbm_dispose_syncpts(PixmapPtr pixmap) +{ +#ifdef DRI3 + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); + + if (!xwl_screen->glamor || !xwl_pixmap) + return; + + if (xwl_pixmap->syncobj) { + xwl_pixmap->syncobj->free(xwl_pixmap->syncobj); + xwl_pixmap->syncobj = NULL; + } + + if (xwl_pixmap->efd >= 0) { + SetNotifyFd(xwl_pixmap->efd, NULL, 0, NULL); + close(xwl_pixmap->efd); + } +#endif /* DRI3 */ +} + +void +xwl_glamor_gbm_wait_syncpts(PixmapPtr pixmap) +{ +#ifdef DRI3 + struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + int fence_fd; + + if (!xwl_screen->glamor || !xwl_pixmap) + return; + + if (xwl_pixmap->syncobj) { + fence_fd = xwl_pixmap->syncobj->export_fence(xwl_pixmap->syncobj, + xwl_pixmap->timeline_point); + xwl_glamor_wait_fence(xwl_screen, fence_fd); + close(fence_fd); + } +#endif /* DRI3 */ +} + +void +xwl_glamor_gbm_wait_release_fence(struct xwl_window *xwl_window, + PixmapPtr pixmap, + struct xwl_window_buffer *xwl_window_buffer) +{ +#ifdef DRI3 + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); + + if (!xwl_screen->glamor || !xwl_pixmap || !xwl_window_buffer) + return; + + xwl_pixmap->xwl_window_buffer = xwl_window_buffer; + /* wait until the release fence is available before re-using this buffer */ + xwl_pixmap->efd = eventfd(0, EFD_CLOEXEC); + SetNotifyFd(xwl_pixmap->efd, xwl_glamor_gbm_release_fence_avail, X_NOTIFY_READ, + xwl_pixmap); + xwl_pixmap->syncobj->submitted_eventfd(xwl_pixmap->syncobj, + xwl_pixmap->timeline_point, + xwl_pixmap->efd); +#endif /* DRI3 */ +} + static Bool xwl_glamor_try_to_make_context_current(struct xwl_screen *xwl_screen) { diff --git a/hw/xwayland/xwayland-glamor-gbm.h b/hw/xwayland/xwayland-glamor-gbm.h index 9083f2578..b346a0ba6 100644 --- a/hw/xwayland/xwayland-glamor-gbm.h +++ b/hw/xwayland/xwayland-glamor-gbm.h @@ -42,4 +42,12 @@ Bool xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen); Bool xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen); drmDevice *xwl_gbm_get_main_device(struct xwl_screen *xwl_screen); +/* Explicit buffer synchronization points */ +Bool xwl_glamor_gbm_set_syncpts(struct xwl_window *xwl_window, PixmapPtr pixmap); +void xwl_glamor_gbm_dispose_syncpts(PixmapPtr pixmap); +void xwl_glamor_gbm_wait_syncpts(PixmapPtr pixmap); +void xwl_glamor_gbm_wait_release_fence(struct xwl_window *xwl_window, + PixmapPtr pixmap, + struct xwl_window_buffer *xwl_window_buffer); + #endif /* XWAYLAND_GLAMOR_GBM_H */