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_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);

Loading…
Cancel
Save