From ee01712847c97317b176c19f42aa5497e5f14b84 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 15:25:51 +0100 Subject: [PATCH] backend/drm: unify connector test and commit codepaths There is some duplicated logic between these two functions. The commit codepath was calling the test function before doing the real commit, so this also saves an unnecessary test-only commit when performing a real commit. --- backend/drm/drm.c | 157 +++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 101 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 971f11cf..2c1e3b48 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -723,11 +723,38 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn, static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn); -static bool drm_connector_test(struct wlr_output *output, - const struct wlr_output_state *state) { - struct wlr_drm_connector *conn = get_drm_connector_from_output(output); +bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { + struct wlr_drm_backend *drm = conn->backend; + + struct wlr_drm_crtc *crtc = conn->crtc; + if (!crtc) { + return false; + } + + uint64_t vrr_capable; + if (conn->props.vrr_capable == 0 || + !get_drm_prop(drm->fd, conn->id, conn->props.vrr_capable, + &vrr_capable) || !vrr_capable) { + wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " + "connector doesn't support VRR"); + return false; + } + + if (crtc->props.vrr_enabled == 0) { + wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " + "CRTC %"PRIu32" doesn't support VRR", crtc->id); + return false; + } + + return true; +} + +static bool drm_connector_commit_state(struct wlr_drm_connector *conn, + const struct wlr_output_state *state, bool test_only) { + struct wlr_drm_backend *drm = conn->backend; + struct wlr_output *output = &conn->output; - if (!conn->backend->session->active) { + if (!drm->session->active) { return false; } @@ -738,7 +765,7 @@ static bool drm_connector_test(struct wlr_output *output, return false; } - if ((state->committed & COMMIT_OUTPUT_STATE) == 0) { + if (test_only && (state->committed & COMMIT_OUTPUT_STATE) == 0) { // This commit doesn't change the KMS state return true; } @@ -752,34 +779,33 @@ static bool drm_connector_test(struct wlr_output *output, } } - if (output_pending_enabled(output, state) && !drm_connector_alloc_crtc(conn)) { - wlr_drm_conn_log(conn, WLR_DEBUG, - "No CRTC available for this connector"); - return false; - } - bool ok = false; struct wlr_drm_connector_state pending = {0}; drm_connector_state_init(&pending, conn, state); struct wlr_drm_device_state pending_dev = {0}; drm_device_state_init_single(&pending_dev, &pending); + if (output_pending_enabled(output, state) && !drm_connector_alloc_crtc(conn)) { + wlr_drm_conn_log(conn, WLR_DEBUG, + "No CRTC available for this connector"); + return false; + } + if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && state->adaptive_sync_enabled && !drm_connector_supports_vrr(conn)) { goto out; } - if (conn->backend->parent) { + if (test_only && conn->backend->parent) { // If we're running as a secondary GPU, we can't perform an atomic // commit without blitting a buffer. ok = true; goto out; } - if (!conn->crtc) { - // If the output is disabled, we don't have a crtc even after - // reallocation + if (!pending.active && conn->crtc == NULL) { + // Disabling an already-disabled connector ok = true; goto out; } @@ -796,7 +822,7 @@ static bool drm_connector_test(struct wlr_output *output, } if (state->committed & WLR_OUTPUT_STATE_LAYERS) { if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) { - return false; + goto out; } } @@ -806,79 +832,7 @@ static bool drm_connector_test(struct wlr_output *output, goto out; } - ok = drm_commit(conn->backend, &pending_dev, 0, true); - -out: - drm_connector_state_finish(&pending); - return ok; -} - -bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) { - struct wlr_drm_backend *drm = conn->backend; - - struct wlr_drm_crtc *crtc = conn->crtc; - if (!crtc) { - return false; - } - - uint64_t vrr_capable; - if (conn->props.vrr_capable == 0 || - !get_drm_prop(drm->fd, conn->id, conn->props.vrr_capable, - &vrr_capable) || !vrr_capable) { - wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " - "connector doesn't support VRR"); - return false; - } - - if (crtc->props.vrr_enabled == 0) { - wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to enable adaptive sync: " - "CRTC %"PRIu32" doesn't support VRR", crtc->id); - return false; - } - - return true; -} - -static bool drm_connector_commit_state(struct wlr_drm_connector *conn, - const struct wlr_output_state *base) { - struct wlr_drm_backend *drm = conn->backend; - - if (!drm->session->active) { - return false; - } - - bool ok = false; - struct wlr_drm_connector_state pending = {0}; - drm_connector_state_init(&pending, conn, base); - struct wlr_drm_device_state pending_dev = {0}; - drm_device_state_init_single(&pending_dev, &pending); - - if (!pending.active && conn->crtc == NULL) { - // Disabling an already-disabled connector - ok = true; - goto out; - } - - if (pending.active) { - if (!drm_connector_alloc_crtc(conn)) { - wlr_drm_conn_log(conn, WLR_ERROR, - "No CRTC available for this connector"); - goto out; - } - } - - if (pending.base->committed & WLR_OUTPUT_STATE_BUFFER) { - if (!drm_connector_state_update_primary_fb(conn, &pending)) { - goto out; - } - } - if (pending.base->committed & WLR_OUTPUT_STATE_LAYERS) { - if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) { - return false; - } - } - - if (pending_dev.modeset) { + if (!test_only && pending_dev.modeset) { if (pending.active) { wlr_drm_conn_log(conn, WLR_INFO, "Modesetting with %dx%d @ %.3f Hz", pending.mode.hdisplay, pending.mode.vdisplay, @@ -892,26 +846,26 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn, // page-flip, either a blocking modeset. When performing a blocking modeset // we'll wait for all queued page-flips to complete, so we don't need this // safeguard. - if (pending_dev.nonblock && conn->pending_page_flip != NULL) { + if (!test_only && pending_dev.nonblock && conn->pending_page_flip != NULL) { wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: " "a page-flip is already pending"); goto out; } uint32_t flags = 0; - if (pending.active) { + if (!test_only && pending.active) { flags |= DRM_MODE_PAGE_FLIP_EVENT; } if (pending.base->tearing_page_flip) { flags |= DRM_MODE_PAGE_FLIP_ASYNC; } - ok = drm_commit(drm, &pending_dev, flags, false); + ok = drm_commit(drm, &pending_dev, flags, test_only); if (!ok) { goto out; } - if (!pending.active) { + if (!test_only && !pending.active) { drm_plane_finish_surface(conn->crtc->primary); drm_plane_finish_surface(conn->crtc->cursor); drm_fb_clear(&conn->cursor_pending_fb); @@ -925,15 +879,16 @@ out: return ok; } -static bool drm_connector_commit(struct wlr_output *output, +static bool drm_connector_test(struct wlr_output *output, const struct wlr_output_state *state) { struct wlr_drm_connector *conn = get_drm_connector_from_output(output); + return drm_connector_commit_state(conn, state, true); +} - if (!drm_connector_test(output, state)) { - return false; - } - - return drm_connector_commit_state(conn, state); +static bool drm_connector_commit(struct wlr_output *output, + const struct wlr_output_state *state) { + struct wlr_drm_connector *conn = get_drm_connector_from_output(output); + return drm_connector_commit_state(conn, state, false); } size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, @@ -1280,7 +1235,7 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) { struct wlr_output_state state; wlr_output_state_init(&state); wlr_output_state_set_enabled(&state, false); - if (!drm_connector_commit_state(conn, &state)) { + if (!drm_connector_commit_state(conn, &state, false)) { // On GPU unplug, disabling the CRTC can fail with EPERM wlr_drm_conn_log(conn, WLR_ERROR, "Failed to disable CRTC %"PRIu32, conn->crtc->id); @@ -1900,7 +1855,7 @@ void restore_drm_device(struct wlr_drm_backend *drm) { wl_list_for_each(conn, &drm->connectors, link) { struct wlr_output_state state; build_current_connector_state(&state, conn); - if (!drm_connector_commit_state(conn, &state)) { + if (!drm_connector_commit_state(conn, &state, false)) { wlr_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch"); } wlr_output_state_finish(&state);