mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-25 22:25:58 +01:00
output: compare state before commit
Before calling wlr_output_impl.{test,commit}, perform a cheap comparison between the current and candidate state. Unset any fields which didn't change.
This commit is contained in:
parent
6688a3d9ea
commit
43a9b0fbb9
1 changed files with 75 additions and 12 deletions
|
@ -579,6 +579,63 @@ void output_pending_resolution(struct wlr_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare a struct wlr_output_state with the current state of a struct
|
||||||
|
* wlr_output.
|
||||||
|
*
|
||||||
|
* Returns a bitfield of the unchanged fields.
|
||||||
|
*
|
||||||
|
* Some fields are not checked: damage always changes in-between frames, the
|
||||||
|
* gamma LUT is too expensive to check, the contents of the buffer might have
|
||||||
|
* changed, etc.
|
||||||
|
*/
|
||||||
|
static uint32_t output_compare_state(struct wlr_output *output,
|
||||||
|
const struct wlr_output_state *state) {
|
||||||
|
uint32_t fields = 0;
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||||
|
bool unchanged = false;
|
||||||
|
switch (state->mode_type) {
|
||||||
|
case WLR_OUTPUT_STATE_MODE_FIXED:
|
||||||
|
unchanged = output->current_mode == state->mode;
|
||||||
|
break;
|
||||||
|
case WLR_OUTPUT_STATE_MODE_CUSTOM:
|
||||||
|
unchanged = output->width == state->custom_mode.width &&
|
||||||
|
output->height == state->custom_mode.height &&
|
||||||
|
output->refresh == state->custom_mode.refresh;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unchanged) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_MODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && output->enabled == state->enabled) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_ENABLED;
|
||||||
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_SCALE) && output->scale == state->scale) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_SCALE;
|
||||||
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_TRANSFORM) &&
|
||||||
|
output->transform == state->transform) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_TRANSFORM;
|
||||||
|
}
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
|
||||||
|
bool enabled =
|
||||||
|
output->adaptive_sync_status != WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
||||||
|
if (enabled == state->adaptive_sync_enabled) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) &&
|
||||||
|
output->render_format == state->render_format) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_RENDER_FORMAT;
|
||||||
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_SUBPIXEL) &&
|
||||||
|
output->subpixel == state->subpixel) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
static bool output_basic_test(struct wlr_output *output,
|
static bool output_basic_test(struct wlr_output *output,
|
||||||
const struct wlr_output_state *state) {
|
const struct wlr_output_state *state) {
|
||||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
|
@ -680,7 +737,14 @@ static bool output_basic_test(struct wlr_output *output,
|
||||||
|
|
||||||
bool wlr_output_test_state(struct wlr_output *output,
|
bool wlr_output_test_state(struct wlr_output *output,
|
||||||
const struct wlr_output_state *state) {
|
const struct wlr_output_state *state) {
|
||||||
if (!output_basic_test(output, state)) {
|
uint32_t unchanged = output_compare_state(output, state);
|
||||||
|
|
||||||
|
// Create a shallow copy of the state with only the fields which have been
|
||||||
|
// changed and potentially a new buffer.
|
||||||
|
struct wlr_output_state copy = *state;
|
||||||
|
copy.committed &= ~unchanged;
|
||||||
|
|
||||||
|
if (!output_basic_test(output, ©)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!output->impl->test) {
|
if (!output->impl->test) {
|
||||||
|
@ -688,13 +752,9 @@ bool wlr_output_test_state(struct wlr_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool new_back_buffer = false;
|
bool new_back_buffer = false;
|
||||||
if (!output_ensure_buffer(output, state, &new_back_buffer)) {
|
if (!output_ensure_buffer(output, ©, &new_back_buffer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a shallow copy of the state with the new buffer
|
|
||||||
// potentially included to pass to the backend.
|
|
||||||
struct wlr_output_state copy = *state;
|
|
||||||
if (new_back_buffer) {
|
if (new_back_buffer) {
|
||||||
assert((copy.committed & WLR_OUTPUT_STATE_BUFFER) == 0);
|
assert((copy.committed & WLR_OUTPUT_STATE_BUFFER) == 0);
|
||||||
copy.committed |= WLR_OUTPUT_STATE_BUFFER;
|
copy.committed |= WLR_OUTPUT_STATE_BUFFER;
|
||||||
|
@ -714,21 +774,24 @@ bool wlr_output_test(struct wlr_output *output) {
|
||||||
|
|
||||||
bool wlr_output_commit_state(struct wlr_output *output,
|
bool wlr_output_commit_state(struct wlr_output *output,
|
||||||
const struct wlr_output_state *state) {
|
const struct wlr_output_state *state) {
|
||||||
if (!output_basic_test(output, state)) {
|
uint32_t unchanged = output_compare_state(output, state);
|
||||||
|
|
||||||
|
// Create a shallow copy of the state with only the fields which have been
|
||||||
|
// changed and potentially a new buffer.
|
||||||
|
struct wlr_output_state pending = *state;
|
||||||
|
pending.committed &= ~unchanged;
|
||||||
|
|
||||||
|
if (!output_basic_test(output, &pending)) {
|
||||||
wlr_log(WLR_ERROR, "Basic output test failed for %s", output->name);
|
wlr_log(WLR_ERROR, "Basic output test failed for %s", output->name);
|
||||||
output_clear_back_buffer(output);
|
output_clear_back_buffer(output);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool new_back_buffer = false;
|
bool new_back_buffer = false;
|
||||||
if (!output_ensure_buffer(output, state, &new_back_buffer)) {
|
if (!output_ensure_buffer(output, &pending, &new_back_buffer)) {
|
||||||
output_clear_back_buffer(output);
|
output_clear_back_buffer(output);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a shallow copy of the state with the new back buffer
|
|
||||||
// potentially included to pass to the backend.
|
|
||||||
struct wlr_output_state pending = *state;
|
|
||||||
if (new_back_buffer) {
|
if (new_back_buffer) {
|
||||||
assert((pending.committed & WLR_OUTPUT_STATE_BUFFER) == 0);
|
assert((pending.committed & WLR_OUTPUT_STATE_BUFFER) == 0);
|
||||||
pending.committed |= WLR_OUTPUT_STATE_BUFFER;
|
pending.committed |= WLR_OUTPUT_STATE_BUFFER;
|
||||||
|
|
Loading…
Reference in a new issue