tearing: add fullscreen options (#1941)

Co-authored-by: Consolatis <35009135+Consolatis@users.noreply.github.com>
This commit is contained in:
Jens Peters 2024-08-06 22:23:10 +02:00 committed by GitHub
parent 19f0b769de
commit 433a4509af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 105 additions and 20 deletions

View file

@ -187,7 +187,12 @@ Actions are used in menus and keyboard/mouse bindings.
original window. There can be multiple windows with this mode set.
*<action name="ToggleTearing" />*
Toggles tearing for the focused window.
Toggles tearing for the focused window between enabled and disabled.
This overrides the preference (tearing hint) from the focused window.
Requires the config option 'allowTearing'. When 'allowTearing' is set
to 'fullscreen' or 'fullscreenForced', tearing will still only be
enabled if the active window is in fullscreen mode.
*<action name="FocusOutput" output="HDMI-A-1" />*
Give focus to topmost window on given output and warp the cursor

View file

@ -185,9 +185,18 @@ this is for compatibility with Openbox.
*fullscreen* enables adaptive sync whenever a window is in fullscreen
mode.
*<core><allowTearing>* [yes|no]
Allow tearing, if requested by the active window, to reduce input lag.
Default is no.
*<core><allowTearing>* [yes|no|fullscreen|fullscreenForced]
Allow tearing to reduce input lag. Default is no.
*yes* allows tearing if requested by the active window.
*fullscreen* allows tearing if requested by the active window, but
only when the window is in fullscreen mode.
*fullscreenForced* enables tearing whenever the active window is in
fullscreen mode, whether or not the application has requested tearing.
Use the *ToggleTearing* action for forcefully enable tearing.
Note: Enabling this option with atomic mode setting is experimental. If
you experience undesirable side effects when tearing is allowed,

View file

@ -30,6 +30,13 @@ enum adaptive_sync_mode {
LAB_ADAPTIVE_SYNC_FULLSCREEN,
};
enum tearing_mode {
LAB_TEARING_DISABLED = 0,
LAB_TEARING_ENABLED,
LAB_TEARING_FULLSCREEN,
LAB_TEARING_FULLSCREEN_FORCED,
};
enum tiling_events_mode {
LAB_TILING_EVENTS_NEVER = 0,
LAB_TILING_EVENTS_REGION = 1 << 0,
@ -54,7 +61,7 @@ struct rcxml {
bool xdg_shell_server_side_deco;
int gap;
enum adaptive_sync_mode adaptive_sync;
bool allow_tearing;
enum tearing_mode allow_tearing;
bool reuse_output_mode;
enum view_placement_policy placement_policy;
bool xwayland_persistence;

View file

@ -535,6 +535,7 @@ struct output *output_nearest_to_cursor(struct server *server);
bool output_is_usable(struct output *output);
void output_update_usable_area(struct output *output);
void output_update_all_usable_areas(struct server *server, bool layout_changed);
bool output_get_tearing_allowance(struct output *output);
struct wlr_box output_usable_area_in_layout_coords(struct output *output);
struct wlr_box output_usable_area_scaled(struct output *output);
void handle_output_power_manager_set_mode(struct wl_listener *listener,

View file

@ -30,6 +30,12 @@ enum ssd_preference {
LAB_SSD_PREF_SERVER,
};
enum three_state {
LAB_STATE_UNSPECIFIED = 0,
LAB_STATE_ENABLED,
LAB_STATE_DISABLED
};
/**
* Directions in which a view can be maximized. "None" is used
* internally to mean "not maximized" but is not valid in rc.xml.
@ -187,6 +193,7 @@ struct view {
enum view_axis maximized;
bool fullscreen;
bool tearing_hint;
enum three_state force_tearing;
bool visible_on_all_workspaces;
enum view_edge tiled;
uint32_t edges_visible; /* enum wlr_edges bitset */

View file

@ -1109,9 +1109,22 @@ actions_run(struct view *activator, struct server *server,
break;
case ACTION_TYPE_TOGGLE_TEARING:
if (view) {
view->tearing_hint = !view->tearing_hint;
wlr_log(WLR_DEBUG, "tearing %sabled",
view->tearing_hint ? "en" : "dis");
switch (view->force_tearing) {
case LAB_STATE_UNSPECIFIED:
view->force_tearing =
output_get_tearing_allowance(view->output)
? LAB_STATE_DISABLED : LAB_STATE_ENABLED;
break;
case LAB_STATE_DISABLED:
view->force_tearing = LAB_STATE_ENABLED;
break;
case LAB_STATE_ENABLED:
view->force_tearing = LAB_STATE_DISABLED;
break;
}
wlr_log(WLR_ERROR, "force tearing %sabled",
view->force_tearing == LAB_STATE_ENABLED
? "en" : "dis");
}
break;
case ACTION_TYPE_TOGGLE_SHADE:

View file

@ -772,6 +772,20 @@ set_adaptive_sync_mode(const char *str, enum adaptive_sync_mode *variable)
}
}
static void
set_tearing_mode(const char *str, enum tearing_mode *variable)
{
if (!strcasecmp(str, "fullscreen")) {
*variable = LAB_TEARING_FULLSCREEN;
} else if (!strcasecmp(str, "fullscreenForced")) {
*variable = LAB_TEARING_FULLSCREEN_FORCED;
} else if (parse_bool(str, -1) == 1) {
*variable = LAB_TEARING_ENABLED;
} else {
*variable = LAB_TEARING_DISABLED;
}
}
static void
entry(xmlNode *node, char *nodename, char *content)
{
@ -886,7 +900,7 @@ entry(xmlNode *node, char *nodename, char *content)
} else if (!strcasecmp(nodename, "adaptiveSync.core")) {
set_adaptive_sync_mode(content, &rc.adaptive_sync);
} else if (!strcasecmp(nodename, "allowTearing.core")) {
set_bool(content, &rc.allow_tearing);
set_tearing_mode(content, &rc.allow_tearing);
} else if (!strcasecmp(nodename, "reuseOutputMode.core")) {
set_bool(content, &rc.reuse_output_mode);
} else if (!strcmp(nodename, "policy.placement")) {

View file

@ -38,28 +38,50 @@ get_tearing_retry_count(struct output *output)
return refresh > 0 ? refresh / 500 : 120;
}
static bool
get_tearing_preference(struct output *output)
bool
output_get_tearing_allowance(struct output *output)
{
struct server *server = output->server;
/* Never allow tearing when disabled */
/* never allow tearing when disabled */
if (!rc.allow_tearing) {
return false;
}
/* Tearing is only allowed for the output with the active view */
if (!server->active_view || server->active_view->output != output) {
struct view *view = server->active_view;
/* tearing is only allowed for the output with the active view */
if (!view || view->output != output) {
return false;
}
/* Tearing should not have failed too many times */
/* 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;
/* allow tearing for any window when requested or forced */
if (rc.allow_tearing == LAB_TEARING_ENABLED) {
if (view->force_tearing == LAB_STATE_UNSPECIFIED) {
return view->tearing_hint;
} else {
return view->force_tearing == LAB_STATE_ENABLED;
}
}
/* remaining tearing options apply only to full-screen windows */
if (!view->fullscreen) {
return false;
}
if (view->force_tearing == LAB_STATE_UNSPECIFIED) {
/* honor the tearing hint or the fullscreen-force preference */
return view->tearing_hint ||
rc.allow_tearing == LAB_TEARING_FULLSCREEN_FORCED;
}
/* honor tearing as requested by action */
return view->force_tearing == LAB_STATE_ENABLED;
}
static void
@ -128,7 +150,7 @@ output_frame_notify(struct wl_listener *listener, void *data)
struct wlr_scene_output *scene_output = output->scene_output;
struct wlr_output_state *pending = &output->pending;
pending->tearing_page_flip = get_tearing_preference(output);
pending->tearing_page_flip = output_get_tearing_allowance(output);
bool committed =
lab_wlr_scene_output_commit(scene_output, pending);

View file

@ -15,8 +15,15 @@ set_tearing_hint(struct wl_listener *listener, void *data)
{
struct tearing_controller *controller = wl_container_of(listener, controller, set_hint);
struct view *view = view_from_wlr_surface(controller->tearing_control->surface);
if (view && controller->tearing_control->current) {
view->tearing_hint = true;
if (view) {
/*
* tearing_control->current is actually an enum:
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC = 0
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC = 1
*
* Using it as a bool here allows us to not ship the XML.
*/
view->tearing_hint = controller->tearing_control->current;
}
}