Add tearing support (#1390)

Co-authored-by: Andrew J. Hesford <ajh@sideband.org>
This commit is contained in:
Ph42oN 2024-01-08 22:58:58 +02:00 committed by GitHub
parent 72f3ce6b41
commit bce0c6ce56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 111 additions and 1 deletions

View file

@ -154,6 +154,9 @@ Actions are used in menus and keyboard/mouse bindings.
the usual keybinds will function again until switching back to the the usual keybinds will function again until switching back to the
original window. There can be multiple windows with this mode set. original window. There can be multiple windows with this mode set.
*<action name="ToggleTearing" />*
Toggles tearing for the focused window.
*<action name="FocusOutput" output="HDMI-A-1" />* *<action name="FocusOutput" output="HDMI-A-1" />*
Give focus to topmost window on given output and warp the cursor Give focus to topmost window on given output and warp the cursor
to the center of the window. If the given output does not contain to the center of the window. If the given output does not contain

View file

@ -109,6 +109,7 @@ this is for compatibility with Openbox.
<decoration>server</decoration> <decoration>server</decoration>
<gap>0</gap> <gap>0</gap>
<adaptiveSync>no</adaptiveSync> <adaptiveSync>no</adaptiveSync>
<allowTearing>no</allowTearing>
<reuseOutputMode>no</reuseOutputMode> <reuseOutputMode>no</reuseOutputMode>
</core> </core>
``` ```
@ -128,6 +129,12 @@ this is for compatibility with Openbox.
*fullscreen* enables adaptive sync whenever a window is in fullscreen *fullscreen* enables adaptive sync whenever a window is in fullscreen
mode. 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.
*<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).
This may prevent unnecessary screenblank delays when starting labwc This may prevent unnecessary screenblank delays when starting labwc

View file

@ -11,6 +11,7 @@
<decoration>server</decoration> <decoration>server</decoration>
<gap>0</gap> <gap>0</gap>
<adaptiveSync>no</adaptiveSync> <adaptiveSync>no</adaptiveSync>
<allowTearing>no</allowTearing>
<reuseOutputMode>no</reuseOutputMode> <reuseOutputMode>no</reuseOutputMode>
</core> </core>

View file

@ -53,6 +53,7 @@ struct rcxml {
bool xdg_shell_server_side_deco; bool xdg_shell_server_side_deco;
int gap; int gap;
enum adaptive_sync_mode adaptive_sync; enum adaptive_sync_mode adaptive_sync;
bool allow_tearing;
bool reuse_output_mode; bool reuse_output_mode;
enum view_placement_policy placement_policy; enum view_placement_policy placement_policy;

View file

@ -39,6 +39,7 @@
#include <wlr/types/wlr_drm_lease_v1.h> #include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h> #include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h> #include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "config/keybind.h" #include "config/keybind.h"
#include "config/rcxml.h" #include "config/rcxml.h"
@ -318,6 +319,9 @@ struct server {
struct wlr_pointer_constraints_v1 *constraints; struct wlr_pointer_constraints_v1 *constraints;
struct wl_listener new_constraint; struct wl_listener new_constraint;
struct wlr_tearing_control_manager_v1 *tearing_control;
struct wl_listener tearing_new_object;
/* Set when in cycle (alt-tab) mode */ /* Set when in cycle (alt-tab) mode */
struct osd_state { struct osd_state {
struct view *cycle_view; struct view *cycle_view;
@ -478,6 +482,7 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
void output_add_virtual(struct server *server, const char *output_name); void output_add_virtual(struct server *server, const char *output_name);
void output_remove_virtual(struct server *server, const char *output_name); void output_remove_virtual(struct server *server, const char *output_name);
void output_enable_adaptive_sync(struct wlr_output *output, bool enabled); void output_enable_adaptive_sync(struct wlr_output *output, bool enabled);
void new_tearing_hint(struct wl_listener *listener, void *data);
void server_init(struct server *server); void server_init(struct server *server);
void server_start(struct server *server); void server_start(struct server *server);

View file

@ -151,6 +151,7 @@ struct view {
bool minimized; bool minimized;
enum view_axis maximized; enum view_axis maximized;
bool fullscreen; bool fullscreen;
bool tearing_hint;
bool visible_on_all_workspaces; bool visible_on_all_workspaces;
enum view_edge tiled; enum view_edge tiled;
bool inhibits_keybinds; bool inhibits_keybinds;

View file

@ -18,6 +18,7 @@ server_protocols = [
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
'wlr-layer-shell-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml',
'wlr-input-inhibitor-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml',
'wlr-output-power-management-unstable-v1.xml', 'wlr-output-power-management-unstable-v1.xml',

View file

@ -102,6 +102,7 @@ enum action_type {
ACTION_TYPE_VIRTUAL_OUTPUT_ADD, ACTION_TYPE_VIRTUAL_OUTPUT_ADD,
ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE, ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE,
ACTION_TYPE_AUTO_PLACE, ACTION_TYPE_AUTO_PLACE,
ACTION_TYPE_TOGGLE_TEARING,
}; };
const char *action_names[] = { const char *action_names[] = {
@ -149,6 +150,7 @@ const char *action_names[] = {
"VirtualOutputAdd", "VirtualOutputAdd",
"VirtualOutputRemove", "VirtualOutputRemove",
"AutoPlace", "AutoPlace",
"ToggleTearing",
NULL NULL
}; };
@ -951,6 +953,13 @@ actions_run(struct view *activator, struct server *server,
} }
} }
break; 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");
}
break;
case ACTION_TYPE_INVALID: case ACTION_TYPE_INVALID:
wlr_log(WLR_ERROR, "Not executing unknown action"); wlr_log(WLR_ERROR, "Not executing unknown action");
break; break;

View file

@ -740,6 +740,12 @@ entry(xmlNode *node, char *nodename, char *content)
rc.gap = atoi(content); rc.gap = atoi(content);
} else if (!strcasecmp(nodename, "adaptiveSync.core")) { } else if (!strcasecmp(nodename, "adaptiveSync.core")) {
set_adaptive_sync_mode(content, &rc.adaptive_sync); set_adaptive_sync_mode(content, &rc.adaptive_sync);
} else if (!strcasecmp(nodename, "allowTearing.core")) {
set_bool(content, &rc.allow_tearing);
if (rc.allow_tearing && strcmp(getenv("WLR_DRM_NO_ATOMIC"), "1")) {
rc.allow_tearing = false;
wlr_log(WLR_INFO, "WLR_DRM_NO_ATOMIC is not 1, tearing disabled");
}
} 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

@ -19,6 +19,7 @@ labwc_sources = files(
'server.c', 'server.c',
'session-lock.c', 'session-lock.c',
'snap.c', 'snap.c',
'tearing.c',
'theme.c', 'theme.c',
'view.c', 'view.c',
'view-impl-common.c', 'view-impl-common.c',

View file

@ -27,6 +27,25 @@
#include "view.h" #include "view.h"
#include "xwayland.h" #include "xwayland.h"
static bool
get_tearing_preference(struct output *output)
{
struct server *server = output->server;
/* 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) {
return false;
}
/* If the active view requests tearing, or it is toggled on with action, allow it */
return server->active_view->tearing_hint;
}
static void static void
output_frame_notify(struct wl_listener *listener, void *data) output_frame_notify(struct wl_listener *listener, void *data)
{ {
@ -68,7 +87,9 @@ output_frame_notify(struct wl_listener *listener, void *data)
return; return;
} }
wlr_scene_output_commit(output->scene_output, NULL); output->wlr_output->pending.tearing_page_flip =
get_tearing_preference(output);
lab_wlr_scene_output_commit(output->scene_output);
struct timespec now = { 0 }; struct timespec now = { 0 };
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);

View file

@ -449,6 +449,10 @@ server_init(struct server *server)
wl_signal_add(&server->output_power_manager_v1->events.set_mode, wl_signal_add(&server->output_power_manager_v1->events.set_mode,
&server->output_power_manager_set_mode); &server->output_power_manager_set_mode);
server->tearing_control = wlr_tearing_control_manager_v1_create(server->wl_display, 1);
server->tearing_new_object.notify = new_tearing_hint;
wl_signal_add(&server->tearing_control->events.new_object, &server->tearing_new_object);
layers_init(server); layers_init(server);
#if HAVE_XWAYLAND #if HAVE_XWAYLAND

50
src/tearing.c Normal file
View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "labwc.h"
#include "view.h"
struct tearing_controller {
struct wlr_tearing_control_v1 *tearing_control;
struct wl_listener set_hint;
struct wl_listener destroy;
};
static void
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->hint) {
view->tearing_hint = true;
}
}
static void
tearing_controller_destroy(struct wl_listener *listener, void *data)
{
struct tearing_controller *controller = wl_container_of(listener, controller, destroy);
free(controller);
}
void
new_tearing_hint(struct wl_listener *listener, void *data)
{
struct server *server = wl_container_of(listener, server, tearing_new_object);
struct wlr_tearing_control_v1 *tearing_control = data;
enum wp_tearing_control_v1_presentation_hint hint =
wlr_tearing_control_manager_v1_surface_hint_from_surface
(server->tearing_control, tearing_control->surface);
wlr_log(WLR_DEBUG, "New presentation hint %d received for surface %p",
hint, tearing_control->surface);
struct tearing_controller *controller = calloc(1, sizeof(struct tearing_controller));
if (!controller) {
return;
}
controller->tearing_control = tearing_control;
controller->set_hint.notify = set_tearing_hint;
wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
controller->destroy.notify = tearing_controller_destroy;
wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
}