From 2c9f573600513b4273098539844d09a41edae6cb Mon Sep 17 00:00:00 2001 From: korei999 Date: Sat, 24 Aug 2024 23:42:01 +0300 Subject: [PATCH] tearing updates --- patches/tearing/README.md | 3 +- patches/tearing/tearing-0.1.patch | 395 ------------------ .../{tearing-0.2.patch => tearing.patch} | 0 3 files changed, 1 insertion(+), 397 deletions(-) delete mode 100644 patches/tearing/tearing-0.1.patch rename patches/tearing/{tearing-0.2.patch => tearing.patch} (100%) diff --git a/patches/tearing/README.md b/patches/tearing/README.md index 393a422..95c8ea0 100644 --- a/patches/tearing/README.md +++ b/patches/tearing/README.md @@ -12,7 +12,6 @@ static const ForceTearingRule force_tearing[] = { ``` ### 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-0.2.patch) -- [2024-08-07](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tearing/tearing-0.1.patch) +- [2024-08-15](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-0.1.patch b/patches/tearing/tearing-0.1.patch deleted file mode 100644 index bcf329f..0000000 --- a/patches/tearing/tearing-0.1.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 490b66b2301c3eab6e9178500998f0b9ead97a5a Mon Sep 17 00:00:00 2001 -From: korei999 -Date: Wed, 7 Aug 2024 17:35:57 +0300 -Subject: [PATCH] implement tearing protocol - ---- - Makefile | 7 +- - config.def.h | 5 ++ - dwl.c | 211 +++++++++++++++++++++++++++++++++++++++++++-------- - 3 files changed, 190 insertions(+), 33 deletions(-) - -diff --git a/Makefile b/Makefile -index f3e1f10..0d1b41a 100644 ---- a/Makefile -+++ b/Makefile -@@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \ - -Wfloat-conversion - - # CFLAGS / LDFLAGS --PKGS = wlroots-0.19 wayland-server xkbcommon libinput $(XLIBS) -+PKGS = wlroots-0.19 wayland-server xkbcommon libinput pixman-1 $(XLIBS) - DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) - LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) - -@@ -21,7 +21,7 @@ dwl: dwl.o util.o - $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ - dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ - pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ -- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h -+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h tearing-control-v1-protocol.h - util.o: util.c util.h - - # wayland-scanner is a tool which generates C headers and rigging for Wayland -@@ -45,6 +45,9 @@ wlr-output-power-management-unstable-v1-protocol.h: - xdg-shell-protocol.h: - $(WAYLAND_SCANNER) server-header \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ -+tearing-control-v1-protocol.h: -+ $(WAYLAND_SCANNER) server-header \ -+ $(WAYLAND_PROTOCOLS)/staging/tearing-control/tearing-control-v1.xml $@ - - config.h: - cp config.def.h $@ -diff --git a/config.def.h b/config.def.h -index 22d2171..c928330 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -28,6 +28,11 @@ static const Rule rules[] = { - { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ - }; - -+static const ForceTearingRule force_tearing[] = { -+ {.title = "", .appid = "oni.exe"}, -+ {.title = "", .appid = "hl_linux"}, -+}; -+ - /* layout(s) */ - static const Layout layouts[] = { - /* symbol arrange function */ -diff --git a/dwl.c b/dwl.c -index 72892d9..91b2708 100644 ---- a/dwl.c -+++ b/dwl.c -@@ -51,6 +51,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -90,6 +91,11 @@ enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, - NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ - #endif - -+typedef struct ForceTearingRule { -+ const char* title; -+ const char* appid; -+} ForceTearingRule; -+ - typedef union { - int i; - uint32_t ui; -@@ -142,6 +148,7 @@ typedef struct { - uint32_t tags; - int isfloating, isurgent, isfullscreen; - uint32_t resize; /* configure serial of a pending resize */ -+ enum wp_tearing_control_v1_presentation_hint tearing_hint; - } Client; - - typedef struct { -@@ -243,6 +250,19 @@ typedef struct { - struct wl_listener destroy; - } SessionLock; - -+typedef struct TearingController { -+ struct wlr_tearing_control_v1 *tearing_control; -+ struct wl_listener set_hint; -+ struct wl_listener destroy; -+ -+ struct wl_list link; /* tearing_controllers */ -+} TearingController; -+ -+typedef struct SendFrameDoneData { -+ struct timespec when; -+ struct Monitor *mon; -+} SendFrameDoneData; -+ - /* 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); - static void fullscreennotify(struct wl_listener *listener, void *data); - static void gpureset(struct wl_listener *listener, void *data); - static void handlesig(int signo); -+static void handletearingcontrollersethint(struct wl_listener *listener, void *data); -+static void handletearingcontrollerdestroy(struct wl_listener *listener, void *data); -+static void handlenewtearinghint(struct wl_listener *listener, void *data); - 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 - 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 outputcantear(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); - 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); -+static void sendframedoneiterator(struct wlr_scene_buffer *buffer, int x, int y, void *user_data); - 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); -@@ -403,6 +429,10 @@ static struct wlr_scene_rect *locked_bg; - static struct wlr_session_lock_v1 *cur_lock; - static struct wl_listener lock_listener = {.notify = locksession}; - -+struct wlr_tearing_control_manager_v1 *tearing_control_v1; -+struct wl_listener tearing_control_new_object; -+struct wl_list tearing_controllers; -+ - static struct wlr_seat *seat; - static KeyboardGroup *kb_group; - static unsigned int cursor_mode; -@@ -726,6 +756,35 @@ 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 (appid) -+ if (strcmp(force_tearing[i].appid, appid) == 0) -+ return true; -+ -+ if (title) -+ if (strcmp(force_tearing[i].title, title) == 0) -+ return true; -+ } -+ -+ return res; -+} -+ - void - closemon(Monitor *m) - { -@@ -1517,6 +1576,61 @@ handlesig(int signo) - } - } - -+void -+handletearingcontrollersethint(struct wl_listener *listener, void *data) -+{ -+ Client *c = NULL, *i = NULL; -+ 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); -+ -+ /* FIXME: broken appearantly */ -+ wl_list_for_each(i, &fstack, flink) { -+ if (VISIBLEON(i, selmon)) -+ if (i->surface.xdg == surface) { -+ c = i; -+ break; -+ } -+ } -+ -+ if (c) { -+ fprintf(stderr, "FOUND\n"); -+ c->tearing_hint = controller->tearing_control->current; -+ } -+} -+ -+void -+handletearingcontrollerdestroy(struct wl_listener *listener, void *data) -+{ -+ struct TearingController *controller = wl_container_of(listener, controller, destroy); -+ wl_list_remove(&controller->link); -+ free(controller); -+} -+ -+void -+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"); -+ 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_insert(&tearing_controllers, &controller->link); -+} -+ - void - incnmaster(const Arg *arg) - { -@@ -1929,6 +2043,16 @@ moveresize(const Arg *arg) - } - } - -+bool -+outputcantear(Monitor* m) -+{ -+ Client *c = focustop(m); -+ if (c && c->isfullscreen && clientcantear(c)) -+ return true; -+ -+ return false; -+} -+ - void - outputmgrapply(struct wl_listener *listener, void *data) - { -@@ -2104,50 +2228,60 @@ rendermon(struct wl_listener *listener, void *data) - /* This function is called every time an output is ready to display a frame, - * generally at the output's refresh rate (e.g. 60Hz). */ - Monitor *m = wl_container_of(listener, m, frame); -- Client *c; -+ struct wlr_scene_output *scene_output = m->scene_output; -+ struct wlr_output *wlr_output = m->wlr_output; -+ struct wlr_gamma_control_v1 *gamma_control = NULL; - struct wlr_output_state pending = {0}; -- struct wlr_gamma_control_v1 *gamma_control; -- struct timespec now; -+ SendFrameDoneData frame_done_data = {0}; - -- /* Render if no XDG clients have an outstanding resize and are visible on -- * this monitor. */ -- wl_list_for_each(c, &clients, link) { -- if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) -- goto skip; -+ m->wlr_output->frame_pending = false; -+ -+ if (!wlr_output->needs_frame && !m->gamma_lut_changed && -+ !pixman_region32_not_empty(&scene_output->pending_commit_damage)) { -+ goto skip; -+ } -+ -+ wlr_output_state_init(&pending); -+ if (!wlr_scene_output_build_state(m->scene_output, &pending, NULL)) { -+ wlr_output_state_finish(&pending); -+ goto skip; - } - -- /* -- * HACK: The "correct" way to set the gamma is to commit it together with -- * the rest of the state in one go, but to do that we would need to rewrite -- * wlr_scene_output_commit() in order to add the gamma to the pending -- * state before committing, instead try to commit the gamma in one frame, -- * and commit the rest of the state in the next one (or in the same frame if -- * the gamma can not be committed). -- */ - if (m->gamma_lut_changed) { -- gamma_control -- = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output); - m->gamma_lut_changed = 0; -- -- if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) -- goto commit; -+ gamma_control = wlr_gamma_control_manager_v1_get_control( -+ gamma_control_mgr, m->wlr_output); -+ if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) { -+ wlr_output_state_finish(&pending); -+ goto skip; -+ } - - if (!wlr_output_test_state(m->wlr_output, &pending)) { - wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); -- goto commit; -+ wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL); - } -- wlr_output_commit_state(m->wlr_output, &pending); -- wlr_output_schedule_frame(m->wlr_output); -- } else { --commit: -- wlr_scene_output_commit(m->scene_output, NULL); - } - --skip: -- /* Let clients know a frame has been rendered */ -- clock_gettime(CLOCK_MONOTONIC, &now); -- wlr_scene_output_send_frame_done(m->scene_output, &now); -+ if (outputcantear(m)) { -+ pending.tearing_page_flip = true; -+ -+ if (!wlr_output_test_state(m->wlr_output, &pending)) { -+ fprintf(stderr, "Output test failed on '%s', retrying without tearing page-flip\n", m->wlr_output->name); -+ -+ pending.tearing_page_flip = false; -+ } -+ } -+ -+ if (!wlr_output_commit_state(m->wlr_output, &pending)) -+ fprintf(stderr, "Page-flip failed on output %s", m->wlr_output->name); -+ - wlr_output_state_finish(&pending); -+ -+skip: -+ /* Send frame done to all visible surfaces */ -+ clock_gettime(CLOCK_MONOTONIC, &frame_done_data.when); -+ frame_done_data.mon = m; -+ wlr_scene_output_for_each_buffer(m->scene_output, sendframedoneiterator, &frame_done_data); - } - - void -@@ -2271,6 +2405,16 @@ run(char *startup_cmd) - wl_display_run(dpy); - } - -+void -+sendframedoneiterator(struct wlr_scene_buffer *buffer, int x, int y, void *user_data) -+{ -+ SendFrameDoneData *data = user_data; -+ if (buffer->primary_output != data->mon->scene_output) -+ return; -+ -+ wlr_scene_buffer_send_frame_done(buffer, &data->when); -+} -+ - void - setcursor(struct wl_listener *listener, void *data) - { -@@ -2630,6 +2774,11 @@ setup(void) - LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); - LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); - -+ tearing_control_v1 = wlr_tearing_control_manager_v1_create(dpy, 1); -+ tearing_control_new_object.notify = handlenewtearinghint; -+ wl_signal_add(&tearing_control_v1->events.new_object, &tearing_control_new_object); -+ wl_list_init(&tearing_controllers); -+ - /* Make sure XWayland clients don't connect to the parent X server, - * e.g when running in the x11 backend or the wayland backend and the - * compositor has Xwayland support */ --- -2.45.2 - diff --git a/patches/tearing/tearing-0.2.patch b/patches/tearing/tearing.patch similarity index 100% rename from patches/tearing/tearing-0.2.patch rename to patches/tearing/tearing.patch