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. mode.
*<core><allowTearing>* [yes|no] *<core><allowTearing>* [yes|no]
Allow tearing to reduce input lag. Default is no. Allow tearing, if requested by the active window, to reduce input lag.
This option requires setting the environment variable Default is no.
WLR_DRM_NO_ATOMIC=1.
*yes* allow tearing if requested by the active window. 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] *<core><reuseOutputMode>* [yes|no]
Try to re-use the existing output mode (resolution / refresh rate). Try to re-use the existing output mode (resolution / refresh rate).

View file

@ -389,6 +389,8 @@ 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

@ -885,13 +885,6 @@ entry(xmlNode *node, char *nodename, char *content)
set_adaptive_sync_mode(content, &rc.adaptive_sync); set_adaptive_sync_mode(content, &rc.adaptive_sync);
} else if (!strcasecmp(nodename, "allowTearing.core")) { } else if (!strcasecmp(nodename, "allowTearing.core")) {
set_bool(content, &rc.allow_tearing); 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")) { } else if (!strcasecmp(nodename, "reuseOutputMode.core")) {
set_bool(content, &rc.reuse_output_mode); set_bool(content, &rc.reuse_output_mode);
} else if (!strcmp(nodename, "policy.placement")) { } else if (!strcmp(nodename, "policy.placement")) {

View file

@ -30,6 +30,14 @@
#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;
}
static bool static bool
get_tearing_preference(struct output *output) get_tearing_preference(struct output *output)
{ {
@ -45,6 +53,11 @@ get_tearing_preference(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;
}
/* If the active view requests tearing, or it is toggled on with action, allow it */ /* If the active view requests tearing, or it is toggled on with action, allow it */
return server->active_view->tearing_hint; return server->active_view->tearing_hint;
} }
@ -112,11 +125,27 @@ output_frame_notify(struct wl_listener *listener, void *data)
*/ */
output_apply_gamma(output); output_apply_gamma(output);
} else { } else {
output->pending.tearing_page_flip = struct wlr_scene_output *scene_output = output->scene_output;
get_tearing_preference(output); struct wlr_output_state *pending = &output->pending;
lab_wlr_scene_output_commit(output->scene_output, pending->tearing_page_flip = get_tearing_preference(output);
&output->pending);
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 }; struct timespec now = { 0 };