From d033a2fbf68064a56652a9277bc0ecfc9ec7bba5 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Wed, 17 Jul 2024 17:10:04 -0700 Subject: [PATCH] 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. --- docs/labwc-config.5.scd | 11 +++++++---- include/labwc.h | 2 ++ src/config/rcxml.c | 7 ------- src/output.c | 37 +++++++++++++++++++++++++++++++++---- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 25e1f0cf..746904d4 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -186,10 +186,13 @@ this is for compatibility with Openbox. mode. ** [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. ** [yes|no] Try to re-use the existing output mode (resolution / refresh rate). diff --git a/include/labwc.h b/include/labwc.h index 21cab83b..468da5b5 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -389,6 +389,8 @@ struct output { bool leased; bool gamma_lut_changed; + + uint32_t nr_tearing_failures; }; #undef LAB_NR_LAYERS diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 28eff198..da4bb637 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -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")) { diff --git a/src/output.c b/src/output.c index 8ca93c47..8ba8225a 100644 --- a/src/output.c +++ b/src/output.c @@ -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 }; -- 2.52.0