From 3067e45c2ee913a0eeb1688c9b830490331d37ea Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Oct 2021 20:09:38 +0200 Subject: [PATCH] backend/drm: add support for explicit sync APIs --- backend/drm/atomic.c | 62 ++++++++++++++++++++++++++++++-- backend/drm/drm.c | 10 +++++- backend/drm/properties.c | 2 ++ include/backend/drm/drm.h | 1 + include/backend/drm/properties.h | 2 ++ 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 2649a1a5..d3a91efb 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -272,6 +274,15 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips); } + int in_fence_fd = -1; + if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) { + in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->base->wait_timeline, + state->base->wait_point); + if (in_fence_fd < 0) { + return false; + } + } + bool prev_vrr_enabled = output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; bool vrr_enabled = prev_vrr_enabled; @@ -285,6 +296,7 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo state->mode_id = mode_id; state->gamma_lut = gamma_lut; state->fb_damage_clips = fb_damage_clips; + state->primary_in_fence_fd = in_fence_fd; state->vrr_enabled = vrr_enabled; return true; } @@ -305,6 +317,15 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) { WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; destroy_blob(drm, state->fb_damage_clips); + if (state->primary_in_fence_fd >= 0) { + close(state->primary_in_fence_fd); + } + if (state->out_fence_fd >= 0) { + // TODO: error handling + wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline, + state->base->signal_point, state->out_fence_fd); + close(state->out_fence_fd); + } } void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) { @@ -316,6 +337,12 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut); destroy_blob(drm, state->fb_damage_clips); + if (state->primary_in_fence_fd >= 0) { + close(state->primary_in_fence_fd); + } + if (state->out_fence_fd >= 0) { + close(state->out_fence_fd); + } } static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) { @@ -353,12 +380,37 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm, atomic_add(atom, id, props->crtc_y, (uint64_t)y); } -static bool supports_cursor_hotspots(const struct wlr_drm_plane* plane) { +static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) { return plane->props.hotspot_x && plane->props.hotspot_y; } +static void set_plane_in_fence_fd(struct atomic *atom, + struct wlr_drm_plane *plane, int sync_file_fd) { + if (!plane->props.in_fence_fd) { + wlr_log(WLR_ERROR, "Plane %"PRIu32 " is missing the IN_FENCE_FD property", + plane->id); + atom->failed = true; + return; + } + + atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd); +} + +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 void atomic_connector_add(struct atomic *atom, - const struct wlr_drm_connector_state *state, bool modeset) { + struct wlr_drm_connector_state *state, bool modeset) { struct wlr_drm_connector *conn = state->connector; struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; @@ -391,6 +443,12 @@ static void atomic_connector_add(struct atomic *atom, atomic_add(atom, crtc->primary->id, crtc->primary->props.fb_damage_clips, state->fb_damage_clips); } + if (state->primary_in_fence_fd >= 0) { + set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd); + } + if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) { + set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd); + } if (crtc->cursor) { if (drm_connector_is_cursor_visible(conn)) { set_plane_props(atom, drm, crtc->cursor, state->cursor_fb, diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 5756f289..4104f87c 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -42,7 +42,9 @@ static const uint32_t COMMIT_OUTPUT_STATE = WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_GAMMA_LUT | WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED | - WLR_OUTPUT_STATE_LAYERS; + WLR_OUTPUT_STATE_LAYERS | + WLR_OUTPUT_STATE_WAIT_TIMELINE | + WLR_OUTPUT_STATE_SIGNAL_TIMELINE; static const uint32_t SUPPORTED_OUTPUT_STATE = WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE; @@ -630,6 +632,8 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state, .connector = conn, .base = base, .active = output_pending_enabled(&conn->output, base), + .primary_in_fence_fd = -1, + .out_fence_fd = -1, }; struct wlr_output_mode *mode = conn->output.current_mode; @@ -1619,6 +1623,10 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn, output->non_desktop = non_desktop; } + // TODO: support sync timelines in multi-GPU mode + // TODO: support sync timelines with libliftoff + output->timeline = drm->parent == NULL && drm->iface == &atomic_iface; + memset(wlr_conn->max_bpc_bounds, 0, sizeof(wlr_conn->max_bpc_bounds)); if (wlr_conn->props.max_bpc != 0) { if (!introspect_drm_prop_range(drm->fd, wlr_conn->props.max_bpc, diff --git a/backend/drm/properties.c b/backend/drm/properties.c index d78bfaf6..05af1673 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -40,6 +40,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 }; @@ -55,6 +56,7 @@ static const struct prop_info plane_info[] = { { "FB_ID", INDEX(fb_id) }, { "HOTSPOT_X", INDEX(hotspot_x) }, { "HOTSPOT_Y", INDEX(hotspot_y) }, + { "IN_FENCE_FD", INDEX(in_fence_fd) }, { "IN_FORMATS", INDEX(in_formats) }, { "SIZE_HINTS", INDEX(size_hints) }, { "SRC_H", INDEX(src_h) }, diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 1106e9f5..18f48742 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -145,6 +145,7 @@ struct wlr_drm_connector_state { uint32_t mode_id; uint32_t gamma_lut; uint32_t fb_damage_clips; + int primary_in_fence_fd, out_fence_fd; bool vrr_enabled; }; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 57073702..421eb427 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -38,6 +38,7 @@ struct wlr_drm_crtc_props { uint32_t active; uint32_t mode_id; + uint32_t out_fence_ptr; }; struct wlr_drm_plane_props { @@ -61,6 +62,7 @@ struct wlr_drm_plane_props { uint32_t fb_damage_clips; uint32_t hotspot_x; uint32_t hotspot_y; + uint32_t in_fence_fd; }; bool get_drm_connector_props(int fd, uint32_t id,