From 09e241121e22740aa9237835cd4b3935665fc5e5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 25 Jun 2026 10:37:52 +0800 Subject: [PATCH] opt: Reconstruct the output commit logic --- src/action/monitor.h | 61 ++++++++++++++++++++++++++++++++++++++ src/config/parse_config.h | 16 ++++------ src/dispatch/bind_define.h | 16 +++++----- src/ext-protocol/hdr.h | 19 +++++++----- src/ext-protocol/tearing.h | 51 +++---------------------------- src/mango.c | 52 ++++++++++++++------------------ 6 files changed, 112 insertions(+), 103 deletions(-) create mode 100644 src/action/monitor.h diff --git a/src/action/monitor.h b/src/action/monitor.h new file mode 100644 index 00000000..434fb159 --- /dev/null +++ b/src/action/monitor.h @@ -0,0 +1,61 @@ +bool mango_scene_output_commit(struct wlr_scene_output *scene_output, + struct wlr_output_state *state) { + struct wlr_output *wlr_output = scene_output->output; + Monitor *m = wlr_output->data; + bool committed = false; + + bool frame_allow_tearing = check_tearing_frame_allow(m); + + if (!wlr_scene_output_needs_frame(scene_output)) + return true; + + // 构建状态,将场景的 Buffer 附着到 state 上 + if (!wlr_scene_output_build_state(scene_output, state, NULL)) + return false; + + if (frame_allow_tearing) { + state->tearing_page_flip = true; + } else { + state->tearing_page_flip = false; + } + + // 测试是否支持撕裂 + if (state->tearing_page_flip == true) { + if (!wlr_output_test_state(wlr_output, state)) { + // 如果 DRM 拒绝(例如当前输出/驱动不支持撕裂),降级关闭撕裂 + state->tearing_page_flip = false; + } + } + + // 提交状态 + committed = wlr_output_commit_state(wlr_output, state); + if (!committed && state->tearing_page_flip) { + // 重试一次 + state->tearing_page_flip = false; + committed = wlr_output_commit_state(wlr_output, state); + } + + if (committed) { + if (state == &m->pending) { + wlr_output_state_finish(&m->pending); + wlr_output_state_init(&m->pending); + } + } else { + wlr_log(WLR_INFO, "Failed to commit output %s", m->wlr_output->name); + return false; + } + + return committed; +} + +bool mango_output_commit(Monitor *m) { + + bool committed = wlr_output_commit_state(m->wlr_output, &m->pending); + if (committed) { + wlr_output_state_finish(&m->pending); + wlr_output_state_init(&m->pending); + } else { + wlr_log(WLR_ERROR, "Failed to commit frame"); + } + return committed; +} \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 306f23bf..959ff095 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -4054,8 +4054,6 @@ void reapply_monitor_rules(void) { if (!m->wlr_output->enabled) continue; - wlr_output_state_init(&m->pending); - for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; @@ -4078,16 +4076,14 @@ void reapply_monitor_rules(void) { wlr_output_state_set_enabled(&m->pending, true); if (m->hdr_enable) { - output_state_setup_hdr(m, false); - bool success = wlr_output_commit_state(m->wlr_output, &m->pending); - if (!success) { // 多尝试一次 - output_state_setup_hdr(m, true); - } - } else { - wlr_output_commit_state(m->wlr_output, &m->pending); + output_state_setup_hdr(m, false, &m->pending); } - wlr_output_state_finish(&m->pending); + if (!(mango_scene_output_commit(m->scene_output, &m->pending))) { + if (m->hdr_enable) { + output_state_setup_hdr(m, true, &m->pending); + } + } wlr_output_effective_resolution(m->wlr_output, &m->m.width, &m->m.height); } diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c70d6213..9312b12c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1944,11 +1944,11 @@ int32_t togglejump(const Arg *arg) { int32_t disable_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, false); - wlr_output_commit_state(m->wlr_output, &state); + wlr_output_state_set_enabled(&m->pending, false); + mango_output_commit(m); m->asleep = 1; updatemons(NULL, NULL); break; @@ -1959,11 +1959,10 @@ int32_t disable_monitor(const Arg *arg) { int32_t enable_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, true); - wlr_output_commit_state(m->wlr_output, &state); + wlr_output_state_set_enabled(&m->pending, true); + mango_output_commit(m); m->asleep = 0; updatemons(NULL, NULL); break; @@ -1974,11 +1973,10 @@ int32_t enable_monitor(const Arg *arg) { int32_t toggle_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, !m->wlr_output->enabled); - wlr_output_commit_state(m->wlr_output, &state); + wlr_output_state_set_enabled(&m->pending, !m->wlr_output->enabled); + mango_output_commit(m); m->asleep = !m->wlr_output->enabled; updatemons(NULL, NULL); break; diff --git a/src/ext-protocol/hdr.h b/src/ext-protocol/hdr.h index 2f2ff9a3..7b82a983 100644 --- a/src/ext-protocol/hdr.h +++ b/src/ext-protocol/hdr.h @@ -16,10 +16,11 @@ static uint32_t output_formats_10bit[] = { }; static bool output_set_render_format(Monitor *m, uint32_t candidates[], - size_t count) { + size_t count, + struct wlr_output_state *state) { for (size_t i = 0; i < count; i++) { - wlr_output_state_set_render_format(&m->pending, candidates[i]); - if (wlr_output_test_state(m->wlr_output, &m->pending)) + wlr_output_state_set_render_format(state, candidates[i]); + if (wlr_output_test_state(m->wlr_output, state)) return true; } return false; @@ -83,7 +84,8 @@ void output_enable_hdr(Monitor *m, struct wlr_output_state *os, bool enabled, wlr_output_state_set_image_description(os, &desc); } -void output_state_setup_hdr(Monitor *m, bool silent) { +void output_state_setup_hdr(Monitor *m, bool silent, + struct wlr_output_state *state) { uint32_t render_format = m->wlr_output->render_format; const char *unsupported_reason = NULL; bool hdr_supported = @@ -106,23 +108,24 @@ void output_state_setup_hdr(Monitor *m, bool silent) { hdr_succeeded = true; // 上次已经成功设置10位,直接复用 } else if (depth == MANGO_RENDER_BIT_DEPTH_10) { hdr_succeeded = output_set_render_format( - m, output_formats_10bit, ARRAY_SIZE(output_formats_10bit)); + m, output_formats_10bit, ARRAY_SIZE(output_formats_10bit), state); if (!hdr_succeeded) { if (!silent) wlr_log(WLR_INFO, "No 10 bit color formats supported, HDR disabled."); if (!output_set_render_format(m, output_formats_8bit, - ARRAY_SIZE(output_formats_8bit))) + ARRAY_SIZE(output_formats_8bit), + state)) if (!silent) wlr_log(WLR_ERROR, "No 8 bit color formats either!"); } } else { // 明确要求8位或自动降级 if (!output_set_render_format(m, output_formats_8bit, - ARRAY_SIZE(output_formats_8bit))) + ARRAY_SIZE(output_formats_8bit), state)) if (!silent) wlr_log(WLR_ERROR, "No 8 bit color formats supported!"); } - output_enable_hdr(m, &m->pending, hdr_succeeded, silent); + output_enable_hdr(m, state, hdr_succeeded, silent); } \ No newline at end of file diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h index 02394eaa..90143423 100644 --- a/src/ext-protocol/tearing.h +++ b/src/ext-protocol/tearing.h @@ -1,3 +1,4 @@ +#include #include struct tearing_controller { @@ -64,6 +65,9 @@ bool check_tearing_frame_allow(Monitor *m) { return false; } + if (!selmon) + return false; + Client *c = selmon->sel; /* tearing is only allowed for the output with the active client */ @@ -94,50 +98,3 @@ bool check_tearing_frame_allow(Monitor *m) { /* honor tearing as requested by action */ return c->force_tearing == STATE_ENABLED; } - -bool custom_wlr_scene_output_commit(struct wlr_scene_output *scene_output, - struct wlr_output_state *state) { - struct wlr_output *wlr_output = scene_output->output; - Monitor *m = wlr_output->data; - - if (!wlr_scene_output_needs_frame(scene_output)) - return true; - - // 构建状态,将场景的 Buffer 附着到 state 上 - if (!wlr_scene_output_build_state(scene_output, state, NULL)) - return false; - - // 测试是否支持撕裂 - if (!wlr_output_test_state(wlr_output, state)) { - // 如果 DRM 拒绝(例如当前输出/驱动不支持撕裂),降级关闭撕裂 - state->tearing_page_flip = false; - } - - // 提交状态 - bool committed = wlr_output_commit_state(wlr_output, state); - if (!committed && state->tearing_page_flip) { - // 重试一次 - state->tearing_page_flip = false; - committed = wlr_output_commit_state(wlr_output, state); - } - - if (committed) { - if (state == &m->pending) { - wlr_output_state_finish(&m->pending); - wlr_output_state_init(&m->pending); - } - } - return committed; -} - -void apply_tear_state(Monitor *m) { - if (!wlr_scene_output_needs_frame(m->scene_output)) - return; - - wlr_output_state_init(&m->pending); - m->pending.tearing_page_flip = true; - if (!custom_wlr_scene_output_commit(m->scene_output, &m->pending)) { - wlr_log(WLR_ERROR, "Failed to commit output %s", - m->scene_output->output->name); - } -} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index aa77e910..476b4e94 100644 --- a/src/mango.c +++ b/src/mango.c @@ -953,9 +953,14 @@ static void global_draw_group_bar(Client *c, int32_t x, int32_t y, static void client_reparent_group(Client *c); static void client_change_mon(Client *c, Monitor *m); static void check_vrr_enable(Client *c); -static void output_state_setup_hdr(Monitor *m, bool silent); +static void output_state_setup_hdr(Monitor *m, bool silent, + struct wlr_output_state *state); static void output_enable_hdr(Monitor *m, struct wlr_output_state *os, bool enabled, bool silent); +static bool mango_scene_output_commit(struct wlr_scene_output *scene_output, + struct wlr_output_state *state); +static bool mango_output_commit(Monitor *m); +static bool check_tearing_frame_allow(Monitor *m); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1165,6 +1170,7 @@ static struct wl_event_source *sync_keymap; #endif #include "action/client.h" +#include "action/monitor.h" #include "animation/client.h" #include "animation/common.h" #include "animation/layer.h" @@ -3520,14 +3526,9 @@ void createmon(struct wl_listener *listener, void *data) { wlr_output_state_set_enabled(&m->pending, 1); if (m->hdr_enable) { - output_state_setup_hdr(m, false); + output_state_setup_hdr(m, false, &m->pending); } - wlr_output_commit_state(wlr_output, &m->pending); - wlr_output_state_finish(&m->pending); - - wlr_output_effective_resolution(m->wlr_output, &m->m.width, &m->m.height); - wl_list_insert(&mons, &m->link); m->pertag = calloc(1, sizeof(Pertag)); @@ -3575,6 +3576,9 @@ void createmon(struct wl_listener *listener, void *data) { else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); + mango_scene_output_commit(m->scene_output, &m->pending); + wlr_output_effective_resolution(m->wlr_output, &m->m.width, &m->m.height); + if (config.blur) { m->blur = wlr_scene_optimized_blur_create(&scene->tree, 0, 0); wlr_scene_node_set_position(&m->blur->node, m->m.x, m->m.y); @@ -4142,6 +4146,7 @@ void requestmonstate(struct wl_listener *listener, void *data) { const struct wlr_output_event_request_state *event = data; if (event->state->committed == WLR_OUTPUT_STATE_MODE) { + switch (event->state->mode_type) { case WLR_OUTPUT_STATE_MODE_FIXED: wlr_output_state_set_mode(&m->pending, event->state->mode); @@ -5298,15 +5303,13 @@ void handle_iamge_copy_capture_new_session(struct wl_listener *listener, void powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; - struct wlr_output_state state = {0}; Monitor *m = event->output->data; if (!m) return; - wlr_output_state_set_enabled(&state, event->mode); - wlr_output_commit_state(m->wlr_output, &state); - + wlr_output_state_set_enabled(&m->pending, event->mode); + mango_output_commit(m); m->asleep = !event->mode; updatemons(NULL, NULL); } @@ -5363,7 +5366,6 @@ void rendermon(struct wl_listener *listener, void *data) { LayerSurface *l = NULL, *tmpl = NULL; int32_t i; struct wl_list *layer_list; - bool frame_allow_tearing = false; struct timespec now; bool need_more_frames = false; @@ -5374,8 +5376,6 @@ void rendermon(struct wl_listener *listener, void *data) { if (!m->wlr_output->enabled || !allow_frame_scheduling) return; - frame_allow_tearing = check_tearing_frame_allow(m); - // 绘制层和淡出效果 for (i = 0; i < LENGTH(m->layers); i++) { layer_list = &m->layers[i]; @@ -5406,12 +5406,7 @@ void rendermon(struct wl_listener *listener, void *data) { monitor_stop_skip_frame_timer(m); } - // 只有在需要帧时才构建和提交状态 - if (config.allow_tearing && frame_allow_tearing) { - apply_tear_state(m); - } else { - wlr_scene_output_commit(m->scene_output, NULL); - } + mango_scene_output_commit(m->scene_output, &m->pending); skip: // 发送帧完成通知 @@ -6669,7 +6664,6 @@ void check_keep_idle_inhibit(Client *c) { void check_vrr_enable(Client *c) { - struct wlr_output_state state = {0}; Monitor *m = c && c->mon ? c->mon : selmon; if (!m) @@ -6677,8 +6671,8 @@ void check_vrr_enable(Client *c) { if (!c && m && !m->iscleanuping && m->is_vrr_opening && !m->vrr_global_enable) { - disable_adaptive_sync(m, &state); - wlr_output_commit_state(m->wlr_output, &state); + disable_adaptive_sync(m, &m->pending); + mango_output_commit(m); return; } @@ -6687,17 +6681,17 @@ void check_vrr_enable(Client *c) { if (VISIBLEON(c, c->mon) && c->vrr_only_fullscreen && c->isfullscreen && !c->mon->is_vrr_opening) { - enable_adaptive_sync(c->mon, &state); - wlr_output_commit_state(c->mon->wlr_output, &state); + enable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); return; } if (!c->mon->is_vrr_opening && c->mon->vrr_global_enable) { - enable_adaptive_sync(c->mon, &state); - wlr_output_commit_state(c->mon->wlr_output, &state); + enable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); } else if (c->mon->is_vrr_opening && !c->mon->vrr_global_enable) { - disable_adaptive_sync(c->mon, &state); - wlr_output_commit_state(c->mon->wlr_output, &state); + disable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); } }