diff --git a/patches/tearing/README.md b/patches/tearing/README.md index 95c8ea0..477cda8 100644 --- a/patches/tearing/README.md +++ b/patches/tearing/README.md @@ -1,17 +1,17 @@ ### Description This patch adds support for tearing protocol. To get it working `export WLR_DRM_NO_ATOMIC=1` is probably required. -Setting `ForceTearingRule` is also probably required since surfaces always receive presentation hint 0 (VSYNC) as far as i can tell. +Some apps would send ASYNC hint and tearing will "just work", otherwise it's possible to force specified clients to tear with a rule. Set rules in the config.h (exact string match): ``` static const ForceTearingRule force_tearing[] = { - {.title = "", .appid = "oni.exe"}, {.title = "", .appid = "hl_linux"}, - {.title = "", .appid = "steam_app_210970"}, + {.title = "Warcraft III", .appid = ""}, + {.title = "", .appid = "gamescope"}, }; ``` ### Download - [git branch](https://codeberg.org/korei999/dwl/src/branch/tearing) -- [2024-08-15](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tearing/tearing.patch) +- [2024-09-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tearing/tearing.patch) ### Authors - [korei999](https://codeberg.org/korei999) diff --git a/patches/tearing/tearing.patch b/patches/tearing/tearing.patch index d3304e7..951d25c 100644 --- a/patches/tearing/tearing.patch +++ b/patches/tearing/tearing.patch @@ -1,13 +1,13 @@ -From d8856938de1e41b820c5e7b27d317a305c1b0ab8 Mon Sep 17 00:00:00 2001 +From 66b2e1646bee8502a3715403c165015bd019438c Mon Sep 17 00:00:00 2001 From: korei999 -Date: Thu, 15 Aug 2024 01:25:59 +0300 +Date: Wed, 18 Sep 2024 20:11:22 +0300 Subject: [PATCH] implement tearing protocol --- Makefile | 5 +- - config.def.h | 5 ++ - dwl.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++---- - 3 files changed, 173 insertions(+), 15 deletions(-) + config.def.h | 8 +++ + dwl.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 182 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 8db7409..6edc7d7 100644 @@ -33,23 +33,26 @@ index 8db7409..6edc7d7 100644 config.h: cp config.def.h $@ diff --git a/config.def.h b/config.def.h -index 22d2171..c928330 100644 +index 22d2171..52d38d3 100644 --- a/config.def.h +++ b/config.def.h -@@ -28,6 +28,11 @@ static const Rule rules[] = { +@@ -28,6 +28,14 @@ static const Rule rules[] = { { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ }; ++/* tearing */ ++static int tearing_allowed = 1; +static const ForceTearingRule force_tearing[] = { -+ {.title = "", .appid = "oni.exe"}, + {.title = "", .appid = "hl_linux"}, ++ {.title = "Warcraft III", .appid = ""}, ++ {.title = "", .appid = "gamescope"}, +}; + /* layout(s) */ static const Layout layouts[] = { /* symbol arrange function */ diff --git a/dwl.c b/dwl.c -index 8a587d1..5546e26 100644 +index dc0c861..44be1bf 100644 --- a/dwl.c +++ b/dwl.c @@ -51,6 +51,7 @@ @@ -72,7 +75,7 @@ index 8a587d1..5546e26 100644 typedef union { int i; uint32_t ui; -@@ -142,6 +148,7 @@ typedef struct { +@@ -143,6 +149,7 @@ typedef struct { uint32_t tags; int isfloating, isurgent, isfullscreen; uint32_t resize; /* configure serial of a pending resize */ @@ -100,15 +103,7 @@ index 8a587d1..5546e26 100644 /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); -@@ -256,6 +276,7 @@ static void chvt(const Arg *arg); - static void checkidleinhibitor(struct wlr_surface *exclude); - static void cleanup(void); - static void cleanupmon(struct wl_listener *listener, void *data); -+static bool clientcantear(Client* c); - static void closemon(Monitor *m); - static void commitlayersurfacenotify(struct wl_listener *listener, void *data); - static void commitnotify(struct wl_listener *listener, void *data); -@@ -293,6 +314,9 @@ static Client *focustop(Monitor *m); +@@ -293,6 +313,9 @@ static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); static void gpureset(struct wl_listener *listener, void *data); static void handlesig(int signo); @@ -118,15 +113,15 @@ index 8a587d1..5546e26 100644 static void incnmaster(const Arg *arg); static void inputdevice(struct wl_listener *listener, void *data); static int keybinding(uint32_t mods, xkb_keysym_t sym); -@@ -309,6 +333,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double +@@ -309,6 +332,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double double sy, double sx_unaccel, double sy_unaccel); static void motionrelative(struct wl_listener *listener, void *data); static void moveresize(const Arg *arg); -+static bool moncantear(Monitor* m); ++static int moncantear(Monitor* m); static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); static void outputmgrtest(struct wl_listener *listener, void *data); -@@ -323,6 +348,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data); +@@ -323,6 +347,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data); static void requestmonstate(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); @@ -134,7 +129,7 @@ index 8a587d1..5546e26 100644 static void setcursor(struct wl_listener *listener, void *data); static void setcursorshape(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); -@@ -400,6 +426,10 @@ static struct wlr_scene_rect *locked_bg; +@@ -400,6 +425,10 @@ static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; static struct wl_listener lock_listener = {.notify = locksession}; @@ -145,41 +140,7 @@ index 8a587d1..5546e26 100644 static struct wlr_seat *seat; static KeyboardGroup *kb_group; static unsigned int cursor_mode; -@@ -722,6 +752,33 @@ cleanupmon(struct wl_listener *listener, void *data) - free(m); - } - -+bool -+clientcantear(Client* c) -+{ -+ bool res = false; -+ const char* appid = client_get_appid(c); -+ const char* title = client_get_title(c); -+ -+ switch (c->tearing_hint) { -+ case WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC: -+ res = false; -+ break; -+ -+ case WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC: -+ return true; -+ }; -+ -+ for (unsigned i = 0; i < LENGTH(force_tearing); i++) { -+ if (strcmp(force_tearing[i].appid, appid) == 0) -+ return true; -+ -+ if (strcmp(force_tearing[i].title, title) == 0) -+ return true; -+ } -+ -+ return res; -+} -+ - void - closemon(Monitor *m) - { -@@ -1512,6 +1569,61 @@ handlesig(int signo) +@@ -1510,6 +1539,69 @@ handlesig(int signo) } } @@ -190,18 +151,27 @@ index 8a587d1..5546e26 100644 + struct TearingController *controller = wl_container_of(listener, controller, set_hint); + + struct wlr_xdg_surface *surface = wlr_xdg_surface_try_from_wlr_surface(controller->tearing_control->surface); ++#ifdef XWAYLAND ++ struct wlr_xwayland_surface *xsurface = wlr_xwayland_surface_try_from_wlr_surface(controller->tearing_control->surface); ++#endif + -+ /* FIXME: broken appearantly */ + wl_list_for_each(i, &fstack, flink) { -+ if (VISIBLEON(i, selmon)) -+ if (i->surface.xdg == surface) { -+ c = i; -+ break; -+ } ++ if (i->surface.xdg == surface ++#ifdef XWAYLAND ++ || i->surface.xwayland == xsurface ++#endif ++ ) { ++ c = i; ++ break; ++ } + } + + if (c) { -+ fprintf(stderr, "FOUND\n"); ++ enum wp_tearing_control_v1_presentation_hint hint = controller->tearing_control->current; ++ fprintf( ++ stderr, "TEARING: found surface: %p(appid: '%s', title: '%s'), hint: %d(%s)\n", ++ (void*)c, client_get_appid(c), client_get_title(c), hint, hint ? "ASYNC" : "VSYNC" ++ ); + c->tearing_hint = controller->tearing_control->current; + } +} @@ -210,6 +180,9 @@ index 8a587d1..5546e26 100644 +handletearingcontrollerdestroy(struct wl_listener *listener, void *data) +{ + struct TearingController *controller = wl_container_of(listener, controller, destroy); ++ ++ wl_list_remove(&controller->set_hint.link); ++ wl_list_remove(&controller->destroy.link); + wl_list_remove(&controller->link); + free(controller); +} @@ -218,47 +191,83 @@ index 8a587d1..5546e26 100644 +handlenewtearinghint(struct wl_listener *listener, void *data) +{ + 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(tearing_control_v1, tearing_control->surface); + struct TearingController *controller = calloc(1, sizeof(struct TearingController)); + -+ fprintf(stderr, "New presentation hint %d received for surface %p\n\n", hint, (void*)tearing_control->surface); -+ -+ if (!controller) { -+ fprintf(stderr, "!controller\n"); ++ if (!controller) + return; -+ } + + controller->tearing_control = tearing_control; + controller->set_hint.notify = handletearingcontrollersethint; + wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint); ++ + controller->destroy.notify = handletearingcontrollerdestroy; + wl_signal_add(&tearing_control->events.destroy, &controller->destroy); -+ wl_list_init(&controller->link); + ++ wl_list_init(&controller->link); + wl_list_insert(&tearing_controllers, &controller->link); +} + void incnmaster(const Arg *arg) { -@@ -1924,6 +2036,16 @@ moveresize(const Arg *arg) +@@ -1677,6 +1769,33 @@ locksession(struct wl_listener *listener, void *data) + wlr_session_lock_v1_send_locked(session_lock); + } + ++static inline void ++forcetearingrule(Client *c) ++{ ++ int success = 0; ++ const char* appid = client_get_appid(c); ++ const char* title = client_get_title(c); ++ ++ for (unsigned i = 0; i < LENGTH(force_tearing); i++) { ++ if (appid) ++ if (strcmp(force_tearing[i].appid, appid) == 0) { ++ success = 1; ++ break; ++ } ++ ++ if (title) ++ if (strcmp(force_tearing[i].title, title) == 0) { ++ success = 1; ++ break; ++ } ++ } ++ ++ if (success) { ++ c->tearing_hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; ++ fprintf(stderr, "tearing forced for: appid: '%s', title: '%s'\n", appid, title); ++ } ++} ++ + void + mapnotify(struct wl_listener *listener, void *data) + { +@@ -1686,6 +1805,8 @@ mapnotify(struct wl_listener *listener, void *data) + Monitor *m; + int i; + ++ forcetearingrule(c); ++ + /* Create scene tree for this client and its border */ + c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); + /* Enabled later by a call to arrange() */ +@@ -1924,6 +2045,13 @@ moveresize(const Arg *arg) } } -+bool ++int +moncantear(Monitor* m) +{ + Client *c = focustop(m); -+ if (c && c->isfullscreen && clientcantear(c)) -+ return true; -+ -+ return false; ++ return (c && c->isfullscreen && c->tearing_hint); /* 1 == ASYNC */ +} + void outputmgrapply(struct wl_listener *listener, void *data) { -@@ -2093,27 +2215,40 @@ quit(const Arg *arg) +@@ -2093,27 +2221,40 @@ quit(const Arg *arg) void rendermon(struct wl_listener *listener, void *data) { @@ -288,7 +297,7 @@ index 8a587d1..5546e26 100644 + goto skip; + } + -+ if (moncantear(m)) { ++ if (tearing_allowed && moncantear(m)) { + pending.tearing_page_flip = true; + + if (!wlr_output_test_state(m->wlr_output, &pending)) { @@ -313,7 +322,7 @@ index 8a587d1..5546e26 100644 } void -@@ -2237,6 +2372,16 @@ run(char *startup_cmd) +@@ -2237,6 +2378,16 @@ run(char *startup_cmd) wl_display_run(dpy); } @@ -330,7 +339,7 @@ index 8a587d1..5546e26 100644 void setcursor(struct wl_listener *listener, void *data) { -@@ -2584,6 +2729,11 @@ setup(void) +@@ -2584,6 +2735,11 @@ setup(void) LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);