tearing: avoid permanent disable due to rejected commits (#2295)

Currently, the cursor plane does not allow async page flips which causes tearing page flips to be rejected if the cursor was moved.

However, in games where no cursor image is present, the async page flips can still work as expected.

Instead of permanently disabling tearing after too many failures, test the output state first before each frame to see if we can commit with tearing_page_flip set to true.
This commit is contained in:
Ricardo Steijn 2024-11-03 22:05:46 +01:00 committed by GitHub
parent c29d8a2174
commit 8f940358e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 38 deletions

View file

@ -406,8 +406,6 @@ struct output {
bool leased; bool leased;
bool gamma_lut_changed; bool gamma_lut_changed;
uint32_t nr_tearing_failures;
}; };
#undef LAB_NR_LAYERS #undef LAB_NR_LAYERS

View file

@ -107,19 +107,33 @@ lab_wlr_scene_output_commit(struct wlr_scene_output *scene_output,
return false; return false;
} }
if (state->tearing_page_flip) {
if (!wlr_output_test_state(wlr_output, state)) {
state->tearing_page_flip = false;
}
}
struct wlr_box additional_damage = {0}; struct wlr_box additional_damage = {0};
if (state->buffer && is_magnify_on()) { if (state->buffer && is_magnify_on()) {
magnify(output, state->buffer, &additional_damage); magnify(output, state->buffer, &additional_damage);
} }
if (state == &output->pending) { bool committed = wlr_output_commit_state(wlr_output, state);
if (!output_state_commit(output)) { /*
wlr_log(WLR_INFO, "Failed to commit output %s", * Handle case where the ouput state test for tearing succeeded,
wlr_output->name); * but actual commit failed. Retry wihout tearing.
return false; */
if (!committed && state->tearing_page_flip) {
state->tearing_page_flip = false;
committed = wlr_output_commit_state(wlr_output, state);
}
if (committed) {
if (state == &output->pending) {
wlr_output_state_finish(&output->pending);
wlr_output_state_init(&output->pending);
} }
} else if (!wlr_output_commit_state(wlr_output, state)) { } else {
wlr_log(WLR_INFO, "Failed to commit state for output %s", wlr_log(WLR_INFO, "Failed to commit output %s",
wlr_output->name); wlr_output->name);
return false; return false;
} }

View file

@ -32,14 +32,6 @@
#include "view.h" #include "view.h"
#include "xwayland.h" #include "xwayland.h"
static unsigned int
get_tearing_retry_count(struct output *output)
{
/* Two seconds worth of frames, guessing 60Hz if refresh is invalid */
int refresh = output->wlr_output->refresh;
return refresh > 0 ? refresh / 500 : 120;
}
bool bool
output_get_tearing_allowance(struct output *output) output_get_tearing_allowance(struct output *output)
{ {
@ -57,11 +49,6 @@ output_get_tearing_allowance(struct output *output)
return false; return false;
} }
/* tearing should not have failed too many times */
if (output->nr_tearing_failures >= get_tearing_retry_count(output)) {
return false;
}
/* allow tearing for any window when requested or forced */ /* allow tearing for any window when requested or forced */
if (rc.allow_tearing == LAB_TEARING_ENABLED) { if (rc.allow_tearing == LAB_TEARING_ENABLED) {
if (view->force_tearing == LAB_STATE_UNSPECIFIED) { if (view->force_tearing == LAB_STATE_UNSPECIFIED) {
@ -154,22 +141,7 @@ output_frame_notify(struct wl_listener *listener, void *data)
pending->tearing_page_flip = output_get_tearing_allowance(output); pending->tearing_page_flip = output_get_tearing_allowance(output);
bool committed = lab_wlr_scene_output_commit(scene_output, pending);
lab_wlr_scene_output_commit(scene_output, pending);
if (pending->tearing_page_flip) {
if (committed) {
output->nr_tearing_failures = 0;
} else {
if (++output->nr_tearing_failures >=
get_tearing_retry_count(output)) {
wlr_log(WLR_INFO, "setting tearing allowance failed "
"for two consecutive seconds, disabling");
}
pending->tearing_page_flip = false;
lab_wlr_scene_output_commit(scene_output, pending);
}
}
} }
struct timespec now = { 0 }; struct timespec now = { 0 };