config/output: Only apply changes if needed

Instead of just setting things in the wlr_output_state and committing
whatever the result is, try to only make changes if the new config
differs from the current state and bail out if no changes were made.
This commit is contained in:
Kenny Levinsen 2023-11-16 14:18:12 +01:00
parent 4e28bce6d0
commit ee2d4a22e0

View file

@ -253,10 +253,16 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
mhz = mhz <= 0 ? INT_MAX : mhz; mhz = mhz <= 0 ? INT_MAX : mhz;
if (wl_list_empty(&output->modes) || custom) { if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name); // Check if the current mode is similar to the custom mode specified.
wlr_output_state_set_custom_mode(pending, width, height, // This is a bit ugly as we do not have a mode object to compare.
refresh_rate > 0 ? mhz : 0); if (!output->current_mode || output->current_mode->preferred ||
return; output->width != width || output->height != height ||
(refresh_rate > 0 && output->refresh != mhz)) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
wlr_output_state_set_custom_mode(pending, width, height,
refresh_rate > 0 ? mhz : 0);
return;
}
} }
struct wlr_output_mode *mode, *best = NULL; struct wlr_output_mode *mode, *best = NULL;
@ -287,7 +293,9 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
width, height, refresh_rate, width, height, refresh_rate,
best->width, best->height, best->refresh / 1000.f); best->width, best->height, best->refresh / 1000.f);
} }
wlr_output_state_set_mode(pending, best); if (best != output->current_mode) {
wlr_output_state_set_mode(pending, best);
}
} }
static void set_modeline(struct wlr_output *output, static void set_modeline(struct wlr_output *output,
@ -299,7 +307,7 @@ static void set_modeline(struct wlr_output *output,
} }
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name); sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode); struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
if (mode) { if (mode && mode != output->current_mode) {
wlr_output_state_set_mode(pending, mode); wlr_output_state_set_mode(pending, mode);
} }
#else #else
@ -396,14 +404,17 @@ static void queue_output_config(struct output_config *oc,
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
if (oc && (!oc->enabled || oc->power == 0)) { bool needs_enabled = oc == NULL || (oc->enabled || oc->power == 1);
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); if (needs_enabled != wlr_output->enabled) {
wlr_output_state_set_enabled(pending, false); if (!needs_enabled) {
return; sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
} wlr_output_state_set_enabled(pending, false);
return;
}
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
wlr_output_state_set_enabled(pending, true); wlr_output_state_set_enabled(pending, true);
}
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) { if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
sway_log(SWAY_DEBUG, "Set %s modeline", sway_log(SWAY_DEBUG, "Set %s modeline",
@ -418,26 +429,29 @@ static void queue_output_config(struct output_config *oc,
sway_log(SWAY_DEBUG, "Set preferred mode"); sway_log(SWAY_DEBUG, "Set preferred mode");
struct wlr_output_mode *preferred_mode = struct wlr_output_mode *preferred_mode =
wlr_output_preferred_mode(wlr_output); wlr_output_preferred_mode(wlr_output);
wlr_output_state_set_mode(pending, preferred_mode); if (preferred_mode != wlr_output->current_mode) {
wlr_output_state_set_mode(pending, preferred_mode);
if (!wlr_output_test_state(wlr_output, pending)) { if (!wlr_output_test_state(wlr_output, pending)) {
sway_log(SWAY_DEBUG, "Preferred mode rejected, " sway_log(SWAY_DEBUG, "Preferred mode rejected, "
"falling back to another mode"); "falling back to another mode");
struct wlr_output_mode *mode; struct wlr_output_mode *mode;
wl_list_for_each(mode, &wlr_output->modes, link) { wl_list_for_each(mode, &wlr_output->modes, link) {
if (mode == preferred_mode) { if (mode == preferred_mode) {
continue; continue;
} }
wlr_output_state_set_mode(pending, mode); wlr_output_state_set_mode(pending, mode);
if (wlr_output_test_state(wlr_output, pending)) { if (wlr_output_test_state(wlr_output, pending)) {
break; break;
}
} }
} }
} }
} }
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN &&
oc->subpixel != wlr_output->subpixel)) {
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name, sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
sway_wl_output_subpixel_to_string(oc->subpixel)); sway_wl_output_subpixel_to_string(oc->subpixel));
wlr_output_state_set_subpixel(pending, oc->subpixel); wlr_output_state_set_subpixel(pending, oc->subpixel);
@ -481,7 +495,8 @@ static void queue_output_config(struct output_config *oc,
wlr_output_state_set_scale(pending, scale); wlr_output_state_set_scale(pending, scale);
} }
if (oc && oc->adaptive_sync != -1) { bool adaptive_sync_enabled = wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
if (oc && oc->adaptive_sync != -1 && oc->adaptive_sync != adaptive_sync_enabled) {
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
oc->adaptive_sync); oc->adaptive_sync);
wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
@ -498,6 +513,10 @@ static void queue_output_config(struct output_config *oc,
for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) { for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
wlr_output_state_set_render_format(pending, fmts[i]); wlr_output_state_set_render_format(pending, fmts[i]);
if (wlr_output_test_state(wlr_output, pending)) { if (wlr_output_test_state(wlr_output, pending)) {
if (pending->render_format == wlr_output->render_format) {
// No change, undo the committed flag
pending->committed &= ~WLR_OUTPUT_STATE_RENDER_FORMAT;
}
break; break;
} }
@ -521,6 +540,11 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
struct wlr_output_state pending = {0}; struct wlr_output_state pending = {0};
queue_output_config(oc, output, &pending); queue_output_config(oc, output, &pending);
if (pending.committed == 0) {
// No change
return true;
}
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
if (!wlr_output_commit_state(wlr_output, &pending)) { if (!wlr_output_commit_state(wlr_output, &pending)) {
// Failed to commit output changes, maybe the output is missing a CRTC. // Failed to commit output changes, maybe the output is missing a CRTC.