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.
master
Simon Ser 9 months ago committed by Kenny Levinsen
parent 2ff3479558
commit ee01712847

@ -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_alloc_crtc(struct wlr_drm_connector *conn);
static bool drm_connector_test(struct wlr_output *output, bool drm_connector_supports_vrr(struct wlr_drm_connector *conn) {
const struct wlr_output_state *state) { struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
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; return false;
} }
@ -738,7 +765,7 @@ static bool drm_connector_test(struct wlr_output *output,
return false; 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 // This commit doesn't change the KMS state
return true; 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; bool ok = false;
struct wlr_drm_connector_state pending = {0}; struct wlr_drm_connector_state pending = {0};
drm_connector_state_init(&pending, conn, state); drm_connector_state_init(&pending, conn, state);
struct wlr_drm_device_state pending_dev = {0}; struct wlr_drm_device_state pending_dev = {0};
drm_device_state_init_single(&pending_dev, &pending); 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) && if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
state->adaptive_sync_enabled && state->adaptive_sync_enabled &&
!drm_connector_supports_vrr(conn)) { !drm_connector_supports_vrr(conn)) {
goto out; 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 // If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer. // commit without blitting a buffer.
ok = true; ok = true;
goto out; goto out;
} }
if (!conn->crtc) { if (!pending.active && conn->crtc == NULL) {
// If the output is disabled, we don't have a crtc even after // Disabling an already-disabled connector
// reallocation
ok = true; ok = true;
goto out; goto out;
} }
@ -796,7 +822,7 @@ static bool drm_connector_test(struct wlr_output *output,
} }
if (state->committed & WLR_OUTPUT_STATE_LAYERS) { if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) { 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; goto out;
} }
ok = drm_commit(conn->backend, &pending_dev, 0, true); if (!test_only && pending_dev.modeset) {
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 (pending.active) { if (pending.active) {
wlr_drm_conn_log(conn, WLR_INFO, "Modesetting with %dx%d @ %.3f Hz", wlr_drm_conn_log(conn, WLR_INFO, "Modesetting with %dx%d @ %.3f Hz",
pending.mode.hdisplay, pending.mode.vdisplay, 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 // 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 // we'll wait for all queued page-flips to complete, so we don't need this
// safeguard. // 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: " wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: "
"a page-flip is already pending"); "a page-flip is already pending");
goto out; goto out;
} }
uint32_t flags = 0; uint32_t flags = 0;
if (pending.active) { if (!test_only && pending.active) {
flags |= DRM_MODE_PAGE_FLIP_EVENT; flags |= DRM_MODE_PAGE_FLIP_EVENT;
} }
if (pending.base->tearing_page_flip) { if (pending.base->tearing_page_flip) {
flags |= DRM_MODE_PAGE_FLIP_ASYNC; 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) { if (!ok) {
goto out; goto out;
} }
if (!pending.active) { if (!test_only && !pending.active) {
drm_plane_finish_surface(conn->crtc->primary); drm_plane_finish_surface(conn->crtc->primary);
drm_plane_finish_surface(conn->crtc->cursor); drm_plane_finish_surface(conn->crtc->cursor);
drm_fb_clear(&conn->cursor_pending_fb); drm_fb_clear(&conn->cursor_pending_fb);
@ -925,15 +879,16 @@ out:
return ok; 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) { const struct wlr_output_state *state) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output); 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)) { static bool drm_connector_commit(struct wlr_output *output,
return false; 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);
return drm_connector_commit_state(conn, state);
} }
size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm, 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; struct wlr_output_state state;
wlr_output_state_init(&state); wlr_output_state_init(&state);
wlr_output_state_set_enabled(&state, false); 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 // On GPU unplug, disabling the CRTC can fail with EPERM
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to disable CRTC %"PRIu32, wlr_drm_conn_log(conn, WLR_ERROR, "Failed to disable CRTC %"PRIu32,
conn->crtc->id); conn->crtc->id);
@ -1900,7 +1855,7 @@ void restore_drm_device(struct wlr_drm_backend *drm) {
wl_list_for_each(conn, &drm->connectors, link) { wl_list_for_each(conn, &drm->connectors, link) {
struct wlr_output_state state; struct wlr_output_state state;
build_current_connector_state(&state, conn); 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_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch");
} }
wlr_output_state_finish(&state); wlr_output_state_finish(&state);

Loading…
Cancel
Save