From f8fa7a856c3a569974cc89955d640167b2958205 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 23 Feb 2026 08:01:45 +0800 Subject: [PATCH] opt: optimize frame skip logic --- src/animation/client.h | 4 ++++ src/client/client.h | 28 ------------------------- src/mango.c | 47 ++++++++++++++++++++++++------------------ 3 files changed, 31 insertions(+), 48 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 2588fb1..b6683ec 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -990,6 +990,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); + if (c->configure_serial != 0) { + c->mon->resizing_count_pending++; + } + if (c == grabc) { c->animation.running = false; c->need_output_flush = false; diff --git a/src/client/client.h b/src/client/client.h index fd81a80..4788e44 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -243,34 +243,6 @@ static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) { return 0; } -static inline int32_t client_is_stopped(Client *c) { - int32_t pid; - siginfo_t in = {0}; -#ifdef XWAYLAND - if (client_is_x11(c)) - return 0; -#endif - - wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); - if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < - 0) { - /* This process is not our child process. We cannot determine its - * stopped state; assume it is not stopped to avoid blocking frame skip. - */ - if (errno == ECHILD) - return 0; // if not our child, assume not stopped - /* Other errors, also assume not stopped. */ - return 0; - } else if (in.si_pid) { - if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) - return 1; - if (in.si_code == CLD_CONTINUED) - return 0; - } - - return 0; -} - static inline int32_t client_is_unmanaged(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) diff --git a/src/mango.c b/src/mango.c index 2c4fc43..fc7eeeb 100644 --- a/src/mango.c +++ b/src/mango.c @@ -503,13 +503,15 @@ struct Monitor { struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wl_event_source *skip_timeout; + struct wl_event_source *skip_frame_timeout; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ uint32_t seltags; uint32_t tagset[2]; bool skiping_frame; + uint32_t resizing_count_pending; + uint32_t resizing_count_current; struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ @@ -786,7 +788,7 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); -static void monitor_stop_skip_timer(Monitor *m); +static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); #include "data/static_keymap.h" @@ -2234,10 +2236,10 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } - if (m->skip_timeout) { - monitor_stop_skip_timer(m); - wl_event_source_remove(m->skip_timeout); - m->skip_timeout = NULL; + if (m->skip_frame_timeout) { + monitor_stop_skip_frame_timer(m); + wl_event_source_remove(m->skip_frame_timeout); + m->skip_frame_timeout = NULL; } m->wlr_output->data = NULL; free(m->pertag); @@ -2790,9 +2792,11 @@ void createmon(struct wl_listener *listener, void *data) { struct wl_event_loop *loop = wl_display_get_event_loop(dpy); m = wlr_output->data = ecalloc(1, sizeof(*m)); - m->skip_timeout = + m->skip_frame_timeout = wl_event_loop_add_timer(loop, monitor_skip_frame_timeout_callback, m); m->skiping_frame = false; + m->resizing_count_pending = 0; + m->resizing_count_current = 0; m->wlr_output = wlr_output; m->wlr_output->data = m; @@ -4443,10 +4447,12 @@ void client_set_opacity(Client *c, double opacity) { scene_buffer_apply_opacity, &opacity); } -void monitor_stop_skip_timer(Monitor *m) { - if (m->skip_timeout) - wl_event_source_timer_update(m->skip_timeout, 0); +void monitor_stop_skip_frame_timer(Monitor *m) { + if (m->skip_frame_timeout) + wl_event_source_timer_update(m->skip_frame_timeout, 0); m->skiping_frame = false; + m->resizing_count_pending = 0; + m->resizing_count_current = 0; } static int monitor_skip_frame_timeout_callback(void *data) { @@ -4455,20 +4461,22 @@ static int monitor_skip_frame_timeout_callback(void *data) { wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; } - monitor_stop_skip_timer(m); + monitor_stop_skip_frame_timer(m); wlr_output_schedule_frame(m->wlr_output); return 1; } void monitor_check_skip_frame_timeout(Monitor *m) { - if (m->skiping_frame) { + if (m->skiping_frame && + m->resizing_count_pending == m->resizing_count_current) { return; } - if (m->skip_timeout) { - wl_event_source_timer_update(m->skip_timeout, 100); // 100ms + if (m->skip_frame_timeout) { + m->resizing_count_current = m->resizing_count_pending; m->skiping_frame = true; + wl_event_source_timer_update(m->skip_frame_timeout, 100); // 100ms } } @@ -4511,16 +4519,15 @@ void rendermon(struct wl_listener *listener, void *data) { // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; - if (!animations && !(allow_tearing && frame_allow_tearing) && - c->configure_serial && client_is_rendered_on_mon(c, m) && - !client_is_stopped(c) && !grabc) { + if (!animations && !grabc && c->configure_serial && + client_is_rendered_on_mon(c, m)) { monitor_check_skip_frame_timeout(m); goto skip; } } if (m->skiping_frame) { - monitor_stop_skip_timer(m); + monitor_stop_skip_frame_timer(m); } // 只有在需要帧时才构建和提交状态 @@ -5960,9 +5967,9 @@ void updatemons(struct wl_listener *listener, void *data) { c->mon = selmon; reset_foreign_tolevel(c); } - if(c->tags ==0 && !c->is_in_scratchpad) { + if (c->tags == 0 && !c->is_in_scratchpad) { c->tags = selmon->tagset[selmon->seltags]; - set_size_per(selmon,c); + set_size_per(selmon, c); } } focusclient(focustop(selmon), 1);