xwayland: add support for wp_linux_drm_syncobj_v1

This protocol allows for explicit synchronization of GPU operations by
Wayland clients and the compositor. Xwayland can make use of this to
ensure any rendering it initiates has completed before the target image
is accessed by the compositor, without having to rely on kernel-level
implicit synchronization.

Furthermore, for X11 clients that also support explicit synchronization
using the mechanisms exposed in the DRI3 and Present extensions, this
Wayland protocol allows us to simply forward the timeline, acquire, and
release points directly to the compositor, ideally avoiding any
premature stalls in the presentation pipeline.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/967>
This commit is contained in:
Erik Kurzinger 2023-08-15 15:32:47 -07:00 committed by Olivier Fourdan
parent 6f85ce4d4e
commit 87bf2cafcc
11 changed files with 323 additions and 12 deletions

View File

@ -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') 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') 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') 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, client_header = generator(scanner,
output : '@BASENAME@-client-protocol.h', 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(xwayland_shell_xml)
srcs += client_header.process(tearing_xml) srcs += client_header.process(tearing_xml)
srcs += client_header.process(fractional_scale_xml) srcs += client_header.process(fractional_scale_xml)
srcs += client_header.process(syncobj_xml)
srcs += code.process(relative_xml) srcs += code.process(relative_xml)
srcs += code.process(pointer_xml) srcs += code.process(pointer_xml)
srcs += code.process(gestures_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(xwayland_shell_xml)
srcs += code.process(tearing_xml) srcs += code.process(tearing_xml)
srcs += code.process(fractional_scale_xml) srcs += code.process(fractional_scale_xml)
srcs += code.process(syncobj_xml)
if build_ei if build_ei
xwayland_dep += libei_dep xwayland_dep += libei_dep

View File

@ -55,6 +55,7 @@
#include "xwayland-screen.h" #include "xwayland-screen.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
struct xwl_gbm_private { struct xwl_gbm_private {
drmDevice *device; drmDevice *device;
@ -620,6 +621,8 @@ xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
wl_drm_destroy(xwl_gbm->drm); wl_drm_destroy(xwl_gbm->drm);
if (xwl_gbm->gbm) if (xwl_gbm->gbm)
gbm_device_destroy(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); free(xwl_gbm);
} }
@ -965,8 +968,38 @@ struct xwl_dri3_syncobj
{ {
struct dri3_syncobj base; struct dri3_syncobj base;
uint32_t handle; 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 static Bool
xwl_dri3_check_syncobj(struct dri3_syncobj *syncobj, uint64_t point, Bool check_avail) 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_screen *xwl_screen = xwl_screen_get(syncobj->screen);
struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_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) if (xwl_syncobj->handle)
drmSyncobjDestroy(xwl_gbm->drm_fd, 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) xwl_dri3_create_syncobj(struct xwl_screen *xwl_screen, uint32_t handle)
{ {
struct xwl_dri3_syncobj *syncobj = calloc(1, sizeof (*syncobj)); 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) if (!syncobj)
return NULL; 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->handle = handle;
syncobj->base.screen = xwl_screen->screen; syncobj->base.screen = xwl_screen->screen;
syncobj->base.refcount = 1; 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.signaled_eventfd = xwl_dri3_syncobj_signaled_eventfd;
syncobj->base.submitted_eventfd = xwl_dri3_syncobj_submitted_eventfd; syncobj->base.submitted_eventfd = xwl_dri3_syncobj_submitted_eventfd;
return &syncobj->base; 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 * static struct dri3_syncobj *
@ -1301,6 +1367,17 @@ xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
return TRUE; 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 static Bool
xwl_glamor_gbm_has_egl_extension(void) 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")) "ANDROID_native_fence_sync"))
xwl_gbm->supports_syncobjs = TRUE; 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; return TRUE;
error: error:
if (xwl_screen->egl_display != EGL_NO_DISPLAY) { if (xwl_screen->egl_display != EGL_NO_DISPLAY) {

View File

@ -41,6 +41,7 @@
#include "drm-client-protocol.h" #include "drm-client-protocol.h"
#include "linux-dmabuf-unstable-v1-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-dmabuf.h"
#include "xwayland-glamor.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); xwl_screen_set_drm_interface(xwl_screen, id, version);
else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0)
xwl_screen_set_dmabuf_interface(xwl_screen, id, version); 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 static Bool
@ -293,6 +296,27 @@ xwl_glamor_get_fence(struct xwl_screen *xwl_screen)
return fence_fd; 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 Bool
xwl_glamor_init(struct xwl_screen *xwl_screen) xwl_glamor_init(struct xwl_screen *xwl_screen)
{ {

View File

@ -35,6 +35,7 @@
#include "xwayland-types.h" #include "xwayland-types.h"
#include "xwayland-glamor-gbm.h" #include "xwayland-glamor-gbm.h"
#include "dri3.h"
typedef enum _xwl_glamor_mode_flags{ typedef enum _xwl_glamor_mode_flags{
XWL_GLAMOR_NONE = 0, 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, Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version); 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); struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);
void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen,
struct wl_registry *registry, 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); int xwl_glamor_dmabuf_export_sync_file(PixmapPtr pixmap);
Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen); Bool xwl_glamor_supports_syncobjs(struct xwl_screen *xwl_screen);
int xwl_glamor_get_fence(struct xwl_screen *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 #ifdef XV
/* glamor Xv Adaptor */ /* glamor Xv Adaptor */

View File

@ -40,6 +40,7 @@
#include "xwayland-pixmap.h" #include "xwayland-pixmap.h"
#include "tearing-control-v1-client-protocol.h" #include "tearing-control-v1-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
#define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear #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) xwl_present_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
{ {
WindowPtr window = vblank->window; 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); struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
uint8_t mode = PresentCompleteModeFlip; 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 = struct xwl_present_event *event =
xwl_present_event_from_vblank(xwl_present_window->flip_active); 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); xwl_present_free_event(event);
else } else
/* Put the previous flip in the idle_queue and wait for further notice from /* Put the previous flip in the idle_queue and wait for further notice from
* the Wayland compositor * the Wayland compositor
*/ */
@ -767,7 +774,8 @@ xwl_present_check_flip(RRCrtcPtr crtc,
!xwl_glamor_check_flip(present_window, pixmap)) !xwl_glamor_check_flip(present_window, pixmap))
return FALSE; 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; return FALSE;
#endif /* XWL_HAS_GLAMOR */ #endif /* XWL_HAS_GLAMOR */
@ -852,6 +860,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
BoxPtr damage_box; BoxPtr damage_box;
struct wl_buffer *buffer; struct wl_buffer *buffer;
struct xwl_present_event *event = xwl_present_event_from_vblank(vblank); struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
Bool implicit_sync = TRUE;
if (!xwl_window) if (!xwl_window)
return FALSE; return FALSE;
@ -868,8 +877,34 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
event->pixmap = pixmap; event->pixmap = pixmap;
#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); 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) */ /* We can flip directly to the main surface (full screen window without clips) */
wl_surface_attach(xwl_window->surface, buffer, 0, 0); wl_surface_attach(xwl_window->surface, buffer, 0, 0);
@ -911,6 +946,42 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
return TRUE; 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. * 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); 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); 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_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); xorg_list_del(&vblank->event_queue);
retry: 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; return;
if (flip_pending && vblank->flip && vblank->pixmap && vblank->window) { if (flip_pending && vblank->flip && vblank->pixmap && vblank->window) {
@ -967,7 +1040,6 @@ retry:
if (xwl_present_flip(vblank, damage)) { if (xwl_present_flip(vblank, damage)) {
WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(vblank->window); WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(vblank->window);
struct xwl_window *xwl_window = xwl_window_from_window(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); PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
/* Replace window pixmap with flip pixmap */ /* Replace window pixmap with flip pixmap */

View File

@ -112,6 +112,7 @@ struct xwl_screen {
struct xwayland_shell_v1 *xwayland_shell; struct xwayland_shell_v1 *xwayland_shell;
struct wp_tearing_control_manager_v1 *tearing_control_manager; struct wp_tearing_control_manager_v1 *tearing_control_manager;
struct wp_fractional_scale_manager_v1 *fractional_scale_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 drm_lease_devices;
struct xorg_list queued_drm_lease_devices; struct xorg_list queued_drm_lease_devices;
struct xorg_list drm_leases; struct xorg_list drm_leases;

View File

@ -35,6 +35,11 @@
#ifdef XWL_HAS_GLAMOR #ifdef XWL_HAS_GLAMOR
#include "glamor.h" #include "glamor.h"
#endif #endif
#include "dri3.h"
#include <poll.h>
#include <sys/eventfd.h>
#include "linux-drm-syncobj-v1-client-protocol.h"
#define BUFFER_TIMEOUT 1 * 1000 /* ms */ #define BUFFER_TIMEOUT 1 * 1000 /* ms */
@ -42,6 +47,11 @@ struct xwl_window_buffer {
struct xwl_window *xwl_window; struct xwl_window *xwl_window;
PixmapPtr pixmap; PixmapPtr pixmap;
RegionPtr damage_region; RegionPtr damage_region;
#ifdef XWL_HAS_GLAMOR
struct dri3_syncobj *syncobj;
uint64_t timeline_point;
int efd;
#endif /* XWL_HAS_GLAMOR */
int refcnt; int refcnt;
uint32_t time; uint32_t time;
struct xorg_list link_buffer; 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->damage_region = RegionCreate(NullBox, 1);
xwl_window_buffer->pixmap = NullPixmap; xwl_window_buffer->pixmap = NullPixmap;
xwl_window_buffer->refcnt = 1; 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); 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) if (xwl_window_buffer->pixmap)
xwl_window_buffer_destroy_pixmap (xwl_window_buffer); 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); xorg_list_del(&xwl_window_buffer->link_buffer);
free(xwl_window_buffer); free(xwl_window_buffer);
@ -215,6 +238,20 @@ xwl_window_buffer_release_callback(void *data)
xwl_window); 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 void
xwl_window_buffers_init(struct xwl_window *xwl_window) 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); 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 PixmapPtr
xwl_window_swap_pixmap(struct xwl_window *xwl_window) xwl_window_swap_pixmap(struct xwl_window *xwl_window)
{ {
struct xwl_screen *xwl_screen = xwl_window->xwl_screen; struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
struct xwl_window_buffer *xwl_window_buffer; struct xwl_window_buffer *xwl_window_buffer;
PixmapPtr window_pixmap; PixmapPtr window_pixmap;
Bool implicit_sync = TRUE;
window_pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window); 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); BoxPtr pBox = RegionRects(full_damage);
int nBox = RegionNumRects(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--) { while (nBox--) {
copy_pixmap_area(window_pixmap, copy_pixmap_area(window_pixmap,
xwl_window_buffer->pixmap, xwl_window_buffer->pixmap,
@ -390,13 +478,35 @@ xwl_window_swap_pixmap(struct xwl_window *xwl_window)
#ifdef XWL_HAS_GLAMOR #ifdef XWL_HAS_GLAMOR
if (!xwl_glamor_supports_implicit_sync(xwl_screen)) { if (!xwl_glamor_supports_implicit_sync(xwl_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); glamor_finish(xwl_screen->screen);
} }
#endif /* XWL_HAS_GLAMOR */ #endif /* XWL_HAS_GLAMOR */
if (implicit_sync) {
xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap, xwl_pixmap_set_buffer_release_cb(xwl_window_buffer->pixmap,
xwl_window_buffer_release_callback, xwl_window_buffer_release_callback,
xwl_window_buffer); 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, xorg_list_append(&xwl_window_buffer->link_buffer,
&xwl_window->window_buffers_unavailable); &xwl_window->window_buffers_unavailable);

View File

@ -55,6 +55,7 @@
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "xwayland-shell-v1-client-protocol.h" #include "xwayland-shell-v1-client-protocol.h"
#include "fractional-scale-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 */ #define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
@ -1496,6 +1497,9 @@ xwl_unrealize_window(WindowPtr window)
if (xwl_window->fractional_scale) if (xwl_window->fractional_scale)
wp_fractional_scale_v1_destroy(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); release_wl_surface_for_window(xwl_window);
xorg_list_del(&xwl_window->link_damage); xorg_list_del(&xwl_window->link_damage);
xorg_list_del(&xwl_window->link_window); xorg_list_del(&xwl_window->link_window);

View File

@ -84,6 +84,7 @@ struct xwl_window {
struct wp_tearing_control_v1 *tearing_control; struct wp_tearing_control_v1 *tearing_control;
struct wp_fractional_scale_v1 *fractional_scale; struct wp_fractional_scale_v1 *fractional_scale;
int fractional_scale_numerator; int fractional_scale_numerator;
struct wp_linux_drm_syncobj_surface_v1 *surface_sync;
}; };
struct xwl_window *xwl_window_get(WindowPtr window); struct xwl_window *xwl_window_get(WindowPtr window);

View File

@ -64,7 +64,7 @@ libdrm_req = '>= 2.4.116'
libselinux_req = '>= 2.0.86' libselinux_req = '>= 2.0.86'
xext_req = '>= 1.0.99.4' xext_req = '>= 1.0.99.4'
wayland_req = '>= 1.21.0' wayland_req = '>= 1.21.0'
wayland_protocols_req = '>= 1.31' wayland_protocols_req = '>= 1.34'
gbm_req = '>= 10.2' gbm_req = '>= 10.2'
xf86dgaproto_req = '>= 2.0.99.1' xf86dgaproto_req = '>= 2.0.99.1'
xshmfence_req = '>= 1.1' xshmfence_req = '>= 1.1'

View File

@ -79,7 +79,10 @@ present_execute_wait(present_vblank_ptr vblank, uint64_t crtc_msc)
} }
#ifdef DRI3 #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_syncobj->is_signaled(vblank->acquire_syncobj,
vblank->acquire_point)) { vblank->acquire_point)) {
vblank->efd = eventfd(0, EFD_CLOEXEC); vblank->efd = eventfd(0, EFD_CLOEXEC);