diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 7a9645c00..0097ca8b2 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -50,6 +50,7 @@ shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inh 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') fractional_scale_xml = join_paths(protodir, 'staging', 'fractional-scale', 'fractional-scale-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', @@ -80,6 +81,7 @@ srcs += client_header.process(shortcuts_inhibit_xml) srcs += client_header.process(xwayland_shell_xml) srcs += client_header.process(tearing_xml) srcs += client_header.process(fractional_scale_xml) +srcs += client_header.process(syncobj_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) srcs += code.process(gestures_xml) @@ -94,6 +96,7 @@ srcs += code.process(shortcuts_inhibit_xml) srcs += code.process(xwayland_shell_xml) srcs += code.process(tearing_xml) srcs += code.process(fractional_scale_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 bb37d1556..5bfbb3262 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -55,6 +55,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; @@ -620,6 +621,8 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) wl_drm_destroy(xwl_gbm->drm); if (xwl_gbm->gbm) gbm_device_destroy(xwl_gbm->gbm); + if (xwl_screen->explicit_sync) + wp_linux_drm_syncobj_manager_v1_destroy(xwl_screen->explicit_sync); free(xwl_gbm); } @@ -965,8 +968,38 @@ struct xwl_dri3_syncobj { struct dri3_syncobj base; uint32_t handle; + struct wp_linux_drm_syncobj_timeline_v1 *timeline; }; +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) +{ + struct xwl_window *xwl_window = xwl_window_from_window(window); + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_dri3_syncobj *xwl_acquire_syncobj = (struct xwl_dri3_syncobj *)acquire_syncobj; + struct xwl_dri3_syncobj *xwl_release_syncobj = (struct xwl_dri3_syncobj *)release_syncobj; + uint32_t acquire_hi = acquire_point >> 32; + uint32_t acquire_lo = acquire_point & 0xffffffff; + uint32_t release_hi = release_point >> 32; + uint32_t release_lo = release_point & 0xffffffff; + + if (!xwl_window->surface_sync) + xwl_window->surface_sync = + wp_linux_drm_syncobj_manager_v1_get_surface(xwl_screen->explicit_sync, + xwl_window->surface); + + wp_linux_drm_syncobj_surface_v1_set_acquire_point(xwl_window->surface_sync, + xwl_acquire_syncobj->timeline, + acquire_hi, acquire_lo); + wp_linux_drm_syncobj_surface_v1_set_release_point(xwl_window->surface_sync, + xwl_release_syncobj->timeline, + release_hi, release_lo); +} + static Bool xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, uint64_t point, Bool check_avail) { @@ -1046,6 +1079,9 @@ xwl_dri3_free_syncobj(struct dri3_syncobj *syncobj) struct xwl_screen *xwl_screen = xwl_screen_get(syncobj->screen); struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + if (xwl_syncobj->timeline) + wp_linux_drm_syncobj_timeline_v1_destroy(xwl_syncobj->timeline); + if (xwl_syncobj->handle) drmSyncobjDestroy(xwl_gbm->drm_fd, xwl_syncobj->handle); @@ -1082,10 +1118,28 @@ 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); + Bool create = !handle; if (!syncobj) return NULL; + if (create && drmSyncobjCreate(xwl_gbm->drm_fd, 0, &handle)) + goto fail; + + if (xwl_screen->explicit_sync) { + int syncobj_fd = -1; + if (drmSyncobjHandleToFD(xwl_gbm->drm_fd, handle, &syncobj_fd)) + goto fail; + + syncobj->timeline = + wp_linux_drm_syncobj_manager_v1_import_timeline(xwl_screen->explicit_sync, + syncobj_fd); + close(syncobj_fd); + if (!syncobj->timeline) + goto fail; + } + syncobj->handle = handle; syncobj->base.screen = xwl_screen->screen; syncobj->base.refcount = 1; @@ -1099,6 +1153,18 @@ xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle) syncobj->base.signaled_eventfd = xwl_dri3_syncobj_signaled_eventfd; syncobj->base.submitted_eventfd = xwl_dri3_syncobj_submitted_eventfd; return &syncobj->base; + +fail: + if (create && handle) + drmSyncobjDestroy(xwl_gbm->drm_fd, handle); + free(syncobj); + return NULL; +} + +struct dri3_syncobj * +xwl_glamor_dri3_syncobj_create(struct xwl_screen *xwl_screen) +{ + return xwl_dri3_create_syncobj(xwl_screen, 0 /* allocate new handle */); } static struct dri3_syncobj * @@ -1301,6 +1367,17 @@ xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, return TRUE; } +Bool +xwl_screen_set_syncobj_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + xwl_screen->explicit_sync = + wl_registry_bind(xwl_screen->registry, id, + &wp_linux_drm_syncobj_manager_v1_interface, + version); + return TRUE; +} + static Bool xwl_glamor_gbm_has_egl_extension(void) { @@ -1545,6 +1622,12 @@ xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) "ANDROID_native_fence_sync")) xwl_gbm->supports_syncobjs = TRUE; + if (!xwl_gbm->supports_syncobjs && xwl_screen->explicit_sync) { + /* explicit sync requires syncobj support */ + wp_linux_drm_syncobj_manager_v1_destroy(xwl_screen->explicit_sync); + xwl_screen->explicit_sync = NULL; + } + return TRUE; error: if (xwl_screen->egl_display != EGL_NO_DISPLAY) { diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index eb15eea2d..f03366437 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -41,6 +41,7 @@ #include "drm-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" +#include "linux-drm-syncobj-v1-client-protocol.h" #include "xwayland-dmabuf.h" #include "xwayland-glamor.h" @@ -111,6 +112,8 @@ xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, xwl_screen_set_drm_interface(xwl_screen, id, version); else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) xwl_screen_set_dmabuf_interface(xwl_screen, id, version); + else if (strcmp(interface, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) + xwl_screen_set_syncobj_interface(xwl_screen, id, version); } static Bool @@ -293,6 +296,27 @@ xwl_glamor_get_fence(struct xwl_screen *xwl_screen) return fence_fd; } +void +xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence_fd) +{ + EGLint attribs[3]; + EGLSyncKHR sync; + + if (!xwl_screen->glamor) + return; + + xwl_glamor_egl_make_current(xwl_screen); + + attribs[0] = EGL_SYNC_NATIVE_FENCE_FD_ANDROID; + attribs[1] = fence_fd; + attribs[2] = EGL_NONE; + sync = eglCreateSyncKHR(xwl_screen->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync != EGL_NO_SYNC_KHR) { + eglWaitSyncKHR(xwl_screen->egl_display, sync, 0); + eglDestroySyncKHR(xwl_screen->egl_display, sync); + } +} + Bool xwl_glamor_init(struct xwl_screen *xwl_screen) { diff --git a/hw/xwayland/xwayland-glamor.h b/hw/xwayland/xwayland-glamor.h index b3fa8bfc3..bbf930437 100644 --- a/hw/xwayland/xwayland-glamor.h +++ b/hw/xwayland/xwayland-glamor.h @@ -35,6 +35,7 @@ #include "xwayland-types.h" #include "xwayland-glamor-gbm.h" +#include "dri3.h" typedef enum _xwl_glamor_mode_flags{ XWL_GLAMOR_NONE = 0, @@ -49,6 +50,8 @@ Bool xwl_glamor_init(struct xwl_screen *xwl_screen); Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version); +Bool xwl_screen_set_syncobj_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version); struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap); void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, struct wl_registry *registry, @@ -62,6 +65,13 @@ void xwl_glamor_dmabuf_import_sync_file(PixmapPtr pixmap, int sync_file); int xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap); Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen); int xwl_glamor_get_fence(struct xwl_screen *screen); +void xwl_glamor_wait_fence(struct xwl_screen *xwl_screen, int fence); +struct dri3_syncobj *xwl_glamor_dri3_syncobj_create(struct xwl_screen *xwl_screen); +void xwl_glamor_dri3_syncobj_passthrough(WindowPtr window, + struct dri3_syncobj *acquire_syncobj, + struct dri3_syncobj *release_syncobj, + uint64_t acquire_point, + uint64_t release_point); #ifdef XV /* glamor Xv Adaptor */ diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 2edfa22c1..959528a3f 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -40,6 +40,7 @@ #include "xwayland-pixmap.h" #include "tearing-control-v1-client-protocol.h" +#include "linux-drm-syncobj-v1-client-protocol.h" #define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear @@ -389,6 +390,7 @@ static void xwl_present_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) { WindowPtr window = vblank->window; + struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); uint8_t mode = PresentCompleteModeFlip; @@ -405,9 +407,14 @@ xwl_present_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t struct xwl_present_event *event = xwl_present_event_from_vblank(xwl_present_window->flip_active); - if (!event->pixmap) + if (!event->pixmap +#ifdef DRI3 + /* If this flip used explicit sync, we won't get a release event */ + || (xwl_screen->explicit_sync && vblank->release_syncobj) +#endif /* DRI3 */ + ) { xwl_present_free_event(event); - else + } else /* Put the previous flip in the idle_queue and wait for further notice from * the Wayland compositor */ @@ -767,7 +774,8 @@ xwl_present_check_flip(RRCrtcPtr crtc, !xwl_glamor_check_flip(present_window, pixmap)) return FALSE; - if (!xwl_glamor_supports_implicit_sync(xwl_window->xwl_screen)) + if (!xwl_glamor_supports_implicit_sync(xwl_window->xwl_screen) && + !xwl_window->xwl_screen->explicit_sync) return FALSE; #endif /* XWL_HAS_GLAMOR */ @@ -852,6 +860,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) BoxPtr damage_box; struct wl_buffer *buffer; struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); + Bool implicit_sync = TRUE; if (!xwl_window) return FALSE; @@ -868,7 +877,33 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) event->pixmap = pixmap; - xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event); +#ifdef XWL_HAS_GLAMOR + if (vblank->acquire_syncobj && vblank->release_syncobj) { + if (xwl_window->xwl_screen->explicit_sync) { + xwl_glamor_dri3_syncobj_passthrough(present_window, + vblank->acquire_syncobj, + vblank->release_syncobj, + vblank->acquire_point, + vblank->release_point); + implicit_sync = FALSE; + } else { + /* transfer from acquire syncobj to implicit fence */ + int fence_fd = + vblank->acquire_syncobj->export_fence(vblank->acquire_syncobj, + vblank->acquire_point); + xwl_glamor_dmabuf_import_sync_file(vblank->pixmap, fence_fd); + } + } +#endif /* XWL_HAS_GLAMOR */ + + if (implicit_sync) { + xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event); + + if (xwl_window->surface_sync) { + wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync); + xwl_window->surface_sync = NULL; + } + } /* We can flip directly to the main surface (full screen window without clips) */ wl_surface_attach(xwl_window->surface, buffer, 0, 0); @@ -911,6 +946,42 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) return TRUE; } +#ifdef XWL_HAS_GLAMOR +static void +xwl_present_acquire_fence_avail(int fd, int xevents, void *data) +{ + present_vblank_ptr vblank = data; + + SetNotifyFd(fd, NULL, 0, NULL); + close(fd); + vblank->efd = -1; + + xwl_present_re_execute(vblank); +} +#endif /* XWL_HAS_GLAMOR */ + +static Bool +xwl_present_wait_acquire_fence_avail(struct xwl_screen *xwl_screen, + present_vblank_ptr vblank) +{ +#ifdef XWL_HAS_GLAMOR + /* If the compositor does not support explicit sync we need to wait for the + * acquire fence to be submitted before flipping. */ + if (vblank->flip && !xwl_screen->explicit_sync && + vblank->pixmap && vblank->acquire_syncobj && + !vblank->acquire_syncobj->has_fence(vblank->acquire_syncobj, + vblank->acquire_point)) { + vblank->efd = eventfd(0, EFD_CLOEXEC); + SetNotifyFd(vblank->efd, xwl_present_acquire_fence_avail, X_NOTIFY_READ, vblank); + vblank->acquire_syncobj->submitted_eventfd(vblank->acquire_syncobj, + vblank->acquire_point, + vblank->efd); + return TRUE; + } +#endif /* XWL_HAS_GLAMOR */ + return FALSE; +} + /* * Once the required MSC has been reached, execute the pending request. * @@ -927,11 +998,13 @@ xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window); struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); + struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); xorg_list_del(&vblank->event_queue); retry: - if (present_execute_wait(vblank, crtc_msc)) + if (present_execute_wait(vblank, crtc_msc) || + xwl_present_wait_acquire_fence_avail(xwl_screen, vblank)) return; if (flip_pending && vblank->flip && vblank->pixmap && vblank->window) { @@ -967,7 +1040,6 @@ retry: if (xwl_present_flip(vblank, damage)) { WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(vblank->window); struct xwl_window *xwl_window = xwl_window_from_window(window); - struct xwl_screen *xwl_screen = xwl_window->xwl_screen; PixmapPtr old_pixmap = screen->GetWindowPixmap(window); /* Replace window pixmap with flip pixmap */ diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index d0b510d1b..2b3bdb29e 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -112,6 +112,7 @@ struct xwl_screen { struct xwayland_shell_v1 *xwayland_shell; struct wp_tearing_control_manager_v1 *tearing_control_manager; struct wp_fractional_scale_manager_v1 *fractional_scale_manager; + struct wp_linux_drm_syncobj_manager_v1 *explicit_sync; struct xorg_list drm_lease_devices; struct xorg_list queued_drm_lease_devices; struct xorg_list drm_leases; diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c index 85c987de7..042a55fc0 100644 --- a/hw/xwayland/xwayland-window-buffers.c +++ b/hw/xwayland/xwayland-window-buffers.c @@ -35,6 +35,11 @@ #ifdef XWL_HAS_GLAMOR #include "glamor.h" #endif +#include "dri3.h" + +#include +#include +#include "linux-drm-syncobj-v1-client-protocol.h" #define BUFFER_TIMEOUT 1 * 1000 /* ms */ @@ -42,6 +47,11 @@ struct xwl_window_buffer { struct xwl_window *xwl_window; PixmapPtr pixmap; RegionPtr damage_region; +#ifdef XWL_HAS_GLAMOR + struct dri3_syncobj *syncobj; + uint64_t timeline_point; + int efd; +#endif /* XWL_HAS_GLAMOR */ int refcnt; uint32_t time; struct xorg_list link_buffer; @@ -80,6 +90,9 @@ xwl_window_buffer_new(struct xwl_window *xwl_window) xwl_window_buffer->damage_region = RegionCreate(NullBox, 1); xwl_window_buffer->pixmap = NullPixmap; xwl_window_buffer->refcnt = 1; +#ifdef XWL_HAS_GLAMOR + xwl_window_buffer->efd = -1; +#endif /* XWL_HAS_GLAMOR */ xorg_list_init(&xwl_window_buffer->link_buffer); @@ -109,6 +122,16 @@ xwl_window_buffer_maybe_dispose(struct xwl_window_buffer *xwl_window_buffer) if (xwl_window_buffer->pixmap) xwl_window_buffer_destroy_pixmap (xwl_window_buffer); +#ifdef XWL_HAS_GLAMOR + if (xwl_window_buffer->syncobj) + xwl_window_buffer->syncobj->free(xwl_window_buffer->syncobj); + + if (xwl_window_buffer->efd >= 0) { + SetNotifyFd(xwl_window_buffer->efd, NULL, 0, NULL); + close(xwl_window_buffer->efd); + } +#endif /* XWL_HAS_GLAMOR */ + xorg_list_del(&xwl_window_buffer->link_buffer); free(xwl_window_buffer); @@ -215,6 +238,20 @@ xwl_window_buffer_release_callback(void *data) xwl_window); } +#ifdef XWL_HAS_GLAMOR +static void +xwl_window_buffers_release_fence_avail(int fd, int xevents, void *data) +{ + struct xwl_window_buffer *xwl_window_buffer = data; + + SetNotifyFd(fd, NULL, 0, NULL); + close(fd); + xwl_window_buffer->efd = -1; + + xwl_window_buffer_release_callback(data); +} +#endif /* XWL_HAS_GLAMOR */ + void xwl_window_buffers_init(struct xwl_window *xwl_window) { @@ -333,12 +370,53 @@ xwl_window_realloc_pixmap(struct xwl_window *xwl_window) screen->DestroyPixmap(window_pixmap); } +#ifdef XWL_HAS_GLAMOR +static Bool +xwl_window_buffers_set_syncpts(struct xwl_window_buffer *xwl_window_buffer) +{ + struct xwl_window *xwl_window = xwl_window_buffer->xwl_window; + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + uint64_t acquire_point = ++xwl_window_buffer->timeline_point; + uint64_t release_point = ++xwl_window_buffer->timeline_point; + + if (!xwl_window_buffer->syncobj) { + struct dri3_syncobj *syncobj = xwl_glamor_dri3_syncobj_create(xwl_screen); + if (!syncobj) + goto fail; + xwl_window_buffer->syncobj = syncobj; + } + + int fence_fd = xwl_glamor_get_fence(xwl_screen); + if (fence_fd >= 0) + xwl_window_buffer->syncobj->import_fence(xwl_window_buffer->syncobj, + acquire_point, fence_fd); + else + goto fail; + + xwl_glamor_dri3_syncobj_passthrough(xwl_window->window, + xwl_window_buffer->syncobj, + xwl_window_buffer->syncobj, + acquire_point, + release_point); + return TRUE; + +fail: + /* can't use explicit sync, we will do a glFinish() before presenting */ + if (xwl_window_buffer->syncobj) { + xwl_window_buffer->syncobj->free(xwl_window_buffer->syncobj); + xwl_window_buffer->syncobj = NULL; + } + return FALSE; +} +#endif /* XWL_HAS_GLAMOR */ + PixmapPtr xwl_window_swap_pixmap(struct xwl_window *xwl_window) { struct xwl_screen *xwl_screen = xwl_window->xwl_screen; struct xwl_window_buffer *xwl_window_buffer; PixmapPtr window_pixmap; + Bool implicit_sync = TRUE; window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window); @@ -350,6 +428,16 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window) BoxPtr pBox = RegionRects(full_damage); int nBox = RegionNumRects(full_damage); +#ifdef XWL_HAS_GLAMOR + if (xwl_window_buffer->syncobj) { + int fence_fd = + xwl_window_buffer->syncobj->export_fence(xwl_window_buffer->syncobj, + xwl_window_buffer->timeline_point); + xwl_glamor_wait_fence(xwl_screen, fence_fd); + close(fence_fd); + } +#endif /* XWL_HAS_GLAMOR */ + while (nBox--) { copy_pixmap_area(window_pixmap, xwl_window_buffer->pixmap, @@ -390,12 +478,34 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window) #ifdef XWL_HAS_GLAMOR if (!xwl_glamor_supports_implicit_sync(xwl_screen)) { - glamor_finish(xwl_screen->screen); + if (xwl_screen->explicit_sync && xwl_window_buffers_set_syncpts(xwl_window_buffer)) { + implicit_sync = FALSE; + /* wait until the release fence is available before re-using this buffer */ + xwl_window_buffer->efd = eventfd(0, EFD_CLOEXEC); + SetNotifyFd(xwl_window_buffer->efd, xwl_window_buffers_release_fence_avail, + X_NOTIFY_READ, xwl_window_buffer); + xwl_window_buffer->syncobj->submitted_eventfd(xwl_window_buffer->syncobj, + xwl_window_buffer->timeline_point, + xwl_window_buffer->efd); + } else + /* If glamor does not support implicit sync and we can't use + * explicit sync, wait for the GPU to be idle before presenting. + * Note that buffer re-use will still be unsynchronized :( + */ + glamor_finish(xwl_screen->screen); } #endif /* XWL_HAS_GLAMOR */ - xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap, - xwl_window_buffer_release_callback, - xwl_window_buffer); + + if (implicit_sync) { + xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap, + xwl_window_buffer_release_callback, + xwl_window_buffer); + + if (xwl_window->surface_sync) { + wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync); + xwl_window->surface_sync = NULL; + } + } xorg_list_append(&xwl_window_buffer->link_buffer, &xwl_window->window_buffers_unavailable); diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index f4d8a0227..a8731f4dd 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -55,6 +55,7 @@ #include "xdg-shell-client-protocol.h" #include "xwayland-shell-v1-client-protocol.h" #include "fractional-scale-v1-client-protocol.h" +#include "linux-drm-syncobj-v1-client-protocol.h" #define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */ @@ -1496,6 +1497,9 @@ xwl_unrealize_window(WindowPtr window) if (xwl_window->fractional_scale) wp_fractional_scale_v1_destroy(xwl_window->fractional_scale); + 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); diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 108c19e09..a00284fde 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -84,6 +84,7 @@ struct xwl_window { struct wp_tearing_control_v1 *tearing_control; struct wp_fractional_scale_v1 *fractional_scale; int fractional_scale_numerator; + struct wp_linux_drm_syncobj_surface_v1 *surface_sync; }; struct xwl_window *xwl_window_get(WindowPtr window); diff --git a/meson.build b/meson.build index 02ef1ad49..94dea6970 100644 --- a/meson.build +++ b/meson.build @@ -64,7 +64,7 @@ libdrm_req = '>= 2.4.116' libselinux_req = '>= 2.0.86' xext_req = '>= 1.0.99.4' wayland_req = '>= 1.21.0' -wayland_protocols_req = '>= 1.31' +wayland_protocols_req = '>= 1.34' gbm_req = '>= 10.2' xf86dgaproto_req = '>= 2.0.99.1' xshmfence_req = '>= 1.1' diff --git a/present/present_execute.c b/present/present_execute.c index e0396c52e..5253344a1 100644 --- a/present/present_execute.c +++ b/present/present_execute.c @@ -79,7 +79,10 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc) } #ifdef DRI3 - if (vblank->acquire_syncobj && + /* Defer execution of explicitly synchronized copies. + * Flip synchronization is managed by the driver. + */ + if (!vblank->flip && vblank->acquire_syncobj && !vblank->acquire_syncobj->is_signaled(vblank->acquire_syncobj, vblank->acquire_point)) { vblank->efd = eventfd(0, EFD_CLOEXEC);