diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 70f55afff..c1a2d35cf 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -163,6 +165,41 @@ error: atom->failed = true; } +static int set_plane_in_fence_fd(struct atomic *atom, struct wlr_drm_plane *plane, + struct wlr_render_timeline *timeline, uint64_t src_point) { + if (!plane->props.in_fence_fd) { + wlr_log(WLR_ERROR, "Missing IN_FENCE_FD property"); + goto error; + } + + int sync_file_fd = wlr_render_timeline_export_sync_file(timeline, src_point); + if (sync_file_fd < 0) { + goto error; + } + + atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd); + + return sync_file_fd; + +error: + wlr_log(WLR_ERROR, "Failed to set plane %"PRIu32" IN_FENCE_FD", plane->id); + atom->failed = true; + return -1; +} + +static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc, + int *fd_ptr) { + if (!crtc->props.out_fence_ptr) { + wlr_log(WLR_ERROR, + "CRTC %"PRIu32" is missing the OUT_FENCE_PTR property", + crtc->id); + atom->failed = true; + return; + } + + atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr); +} + static bool atomic_crtc_commit(struct wlr_drm_connector *conn, const struct wlr_drm_connector_state *state, uint32_t flags, bool test_only) { @@ -228,6 +265,8 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, flags |= DRM_MODE_ATOMIC_NONBLOCK; } + int in_fence_fd = -1, out_fence_fd = -1; + struct atomic atom; atomic_begin(&atom); atomic_add(&atom, conn->id, conn->props.crtc_id, active ? crtc->id : 0); @@ -249,6 +288,13 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, atomic_add(&atom, crtc->primary->id, crtc->primary->props.fb_damage_clips, fb_damage_clips); } + if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) { + in_fence_fd = set_plane_in_fence_fd(&atom, crtc->primary, + state->base->wait_timeline, state->base->wait_point); + } + if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) { + set_crtc_out_fence_ptr(&atom, crtc, &out_fence_fd); + } if (crtc->cursor) { if (drm_connector_is_cursor_visible(conn)) { set_plane_props(&atom, drm, crtc->cursor, crtc->id, @@ -288,6 +334,14 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, wlr_log_errno(WLR_ERROR, "Failed to destroy FB_DAMAGE_CLIPS property blob"); } + close(in_fence_fd); + + if (out_fence_fd > 0) { + ok = wlr_render_timeline_import_sync_file(state->base->signal_timeline, + state->base->signal_point, out_fence_fd); + close(out_fence_fd); + } + return ok; } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 191ad064d..d65f3d0ed 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -36,7 +36,9 @@ static const uint32_t SUPPORTED_OUTPUT_STATE = WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED | - WLR_OUTPUT_STATE_GAMMA_LUT; + WLR_OUTPUT_STATE_GAMMA_LUT | + WLR_OUTPUT_STATE_WAIT_TIMELINE | + WLR_OUTPUT_STATE_SIGNAL_TIMELINE; bool check_drm_features(struct wlr_drm_backend *drm) { if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) { @@ -491,6 +493,13 @@ static bool drm_connector_test(struct wlr_output *output) { } } + if ((output->pending.committed & (WLR_OUTPUT_STATE_WAIT_TIMELINE | + WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) && conn->backend->parent) { + wlr_drm_conn_log(conn, WLR_DEBUG, + "Sync timelines are unsupported in multi-GPU mode"); + return false; + } + struct wlr_drm_connector_state pending = {0}; drm_connector_state_init(&pending, conn, &output->pending); diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 37d8147af..880dab9b9 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -54,6 +54,13 @@ static bool legacy_crtc_test(struct wlr_drm_connector *conn, } } + if (state->base->committed & (WLR_OUTPUT_STATE_WAIT_TIMELINE | + WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) { + wlr_drm_conn_log(conn, WLR_DEBUG, + "Sync timelines are unsupported with legacy KMS interface"); + return false; + } + return true; } diff --git a/backend/drm/properties.c b/backend/drm/properties.c index f26965933..db819828d 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -38,6 +38,7 @@ static const struct prop_info crtc_info[] = { { "GAMMA_LUT", INDEX(gamma_lut) }, { "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) }, { "MODE_ID", INDEX(mode_id) }, + { "OUT_FENCE_PTR", INDEX(out_fence_ptr) }, { "VRR_ENABLED", INDEX(vrr_enabled) }, #undef INDEX }; @@ -51,6 +52,7 @@ static const struct prop_info plane_info[] = { { "CRTC_Y", INDEX(crtc_y) }, { "FB_DAMAGE_CLIPS", INDEX(fb_damage_clips) }, { "FB_ID", INDEX(fb_id) }, + { "IN_FENCE_FD", INDEX(in_fence_fd) }, { "IN_FORMATS", INDEX(in_formats) }, { "SRC_H", INDEX(src_h) }, { "SRC_W", INDEX(src_w) }, diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 10c1ccd09..eadbdece8 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -39,6 +39,7 @@ union wlr_drm_crtc_props { uint32_t active; uint32_t mode_id; + uint32_t out_fence_ptr; }; uint32_t props[6]; }; @@ -62,6 +63,7 @@ union wlr_drm_plane_props { uint32_t fb_id; uint32_t crtc_id; uint32_t fb_damage_clips; + uint32_t in_fence_fd; }; uint32_t props[14]; };