opt: Reconstruct the output commit logic

This commit is contained in:
DreamMaoMao 2026-06-25 10:37:52 +08:00
parent fde0eee0a5
commit 09e241121e
6 changed files with 112 additions and 103 deletions

61
src/action/monitor.h Normal file
View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -1,3 +1,4 @@
#include <stdbool.h>
#include <wlr/types/wlr_tearing_control_v1.h>
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);
}
}

View file

@ -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);
}
}