output: allow tearing with atomic mode setting

Additionally, track errors and abandon the tearing allowance when it
cannot be set for two-seconds' worth of consecutive frames.
This commit is contained in:
Christopher Snowhill 2024-07-17 17:10:04 -07:00 committed by Andrew J. Hesford
parent 14d9bbab90
commit d033a2fbf6
4 changed files with 42 additions and 15 deletions

View file

@ -186,10 +186,13 @@ this is for compatibility with Openbox.
mode.
*<core><allowTearing>* [yes|no]
Allow tearing to reduce input lag. Default is no.
This option requires setting the environment variable
WLR_DRM_NO_ATOMIC=1.
*yes* allow tearing if requested by the active window.
Allow tearing, if requested by the active window, to reduce input lag.
Default is no.
Note: Enabling this option with atomic mode setting is experimental. If
you experience undesirable side effects when tearing is allowed,
consider setting the environment variable WLR_DRM_NO_ATOMIC=1 when
launching labwc.
*<core><reuseOutputMode>* [yes|no]
Try to re-use the existing output mode (resolution / refresh rate).

View file

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

View file

@ -885,13 +885,6 @@ entry(xmlNode *node, char *nodename, char *content)
set_adaptive_sync_mode(content, &rc.adaptive_sync);
} else if (!strcasecmp(nodename, "allowTearing.core")) {
set_bool(content, &rc.allow_tearing);
if (rc.allow_tearing) {
char *no_atomic_env = getenv("WLR_DRM_NO_ATOMIC");
if (!no_atomic_env || strcmp(no_atomic_env, "1") != 0) {
rc.allow_tearing = false;
wlr_log(WLR_ERROR, "tearing requires WLR_DRM_NO_ATOMIC=1");
}
}
} else if (!strcasecmp(nodename, "reuseOutputMode.core")) {
set_bool(content, &rc.reuse_output_mode);
} else if (!strcmp(nodename, "policy.placement")) {

View file

@ -30,6 +30,14 @@
#include "view.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;
}
static bool
get_tearing_preference(struct output *output)
{
@ -45,6 +53,11 @@ get_tearing_preference(struct output *output)
return false;
}
/* Tearing should not have failed too many times */
if (output->nr_tearing_failures >= get_tearing_retry_count(output)) {
return false;
}
/* If the active view requests tearing, or it is toggled on with action, allow it */
return server->active_view->tearing_hint;
}
@ -112,11 +125,27 @@ output_frame_notify(struct wl_listener *listener, void *data)
*/
output_apply_gamma(output);
} else {
output->pending.tearing_page_flip =
get_tearing_preference(output);
struct wlr_scene_output *scene_output = output->scene_output;
struct wlr_output_state *pending = &output->pending;
lab_wlr_scene_output_commit(output->scene_output,
&output->pending);
pending->tearing_page_flip = get_tearing_preference(output);
bool committed =
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 };