mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-06-25 13:14:13 -04:00
feat: hdr support
This commit is contained in:
parent
085d65c219
commit
5fb6b230a0
8 changed files with 211 additions and 63 deletions
|
|
@ -1,6 +1,7 @@
|
|||
#include "dwl-ipc.h"
|
||||
#include "ext-workspace.h"
|
||||
#include "foreign-toplevel.h"
|
||||
#include "hdr.h"
|
||||
#include "tablet.h"
|
||||
#include "tearing.h"
|
||||
#include "text-input.h"
|
||||
|
|
|
|||
128
src/ext-protocol/hdr.h
Normal file
128
src/ext-protocol/hdr.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include <drm_fourcc.h>
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
static uint32_t output_formats_8bit[] = {
|
||||
DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBX8888,
|
||||
DRM_FORMAT_BGRX8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_BGR888,
|
||||
};
|
||||
|
||||
static uint32_t output_formats_10bit[] = {
|
||||
DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_RGBX1010102,
|
||||
DRM_FORMAT_BGRX1010102, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010,
|
||||
DRM_FORMAT_RGBA1010102, DRM_FORMAT_BGRA1010102,
|
||||
};
|
||||
|
||||
static bool output_set_render_format(Monitor *m, uint32_t candidates[],
|
||||
size_t count) {
|
||||
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))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool output_format_in_candidates(uint32_t format, uint32_t candidates[],
|
||||
size_t count) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
if (candidates[i] == format)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum render_bit_depth bit_depth_from_format(uint32_t render_format) {
|
||||
if (output_format_in_candidates(render_format, output_formats_10bit,
|
||||
ARRAY_SIZE(output_formats_10bit)))
|
||||
return MANGO_RENDER_BIT_DEPTH_10;
|
||||
if (output_format_in_candidates(render_format, output_formats_8bit,
|
||||
ARRAY_SIZE(output_formats_8bit)))
|
||||
return MANGO_RENDER_BIT_DEPTH_8;
|
||||
return MANGO_RENDER_BIT_DEPTH_DEFAULT;
|
||||
}
|
||||
|
||||
static bool output_supports_hdr(const struct wlr_output *output,
|
||||
const char **reason) {
|
||||
const char *r = NULL;
|
||||
if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020))
|
||||
r = "BT2020 primaries not supported";
|
||||
else if (!(output->supported_transfer_functions &
|
||||
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ))
|
||||
r = "PQ transfer function not supported";
|
||||
else if (!drw->features.output_color_transform)
|
||||
r = "renderer doesn't support output color transforms";
|
||||
if (reason)
|
||||
*reason = r;
|
||||
return !r;
|
||||
}
|
||||
|
||||
void output_enable_hdr(Monitor *m, struct wlr_output_state *os, bool enabled,
|
||||
bool silent) {
|
||||
if (enabled && !output_supports_hdr(m->wlr_output, NULL))
|
||||
enabled = false;
|
||||
|
||||
if (!enabled) {
|
||||
if (m->wlr_output->supported_primaries ||
|
||||
m->wlr_output->supported_transfer_functions) {
|
||||
if (!silent)
|
||||
wlr_log(WLR_DEBUG, "Disabling HDR on output %s",
|
||||
m->wlr_output->name);
|
||||
wlr_output_state_set_image_description(os, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!silent)
|
||||
wlr_log(WLR_DEBUG, "Enabling HDR on output %s", m->wlr_output->name);
|
||||
struct wlr_output_image_description desc = {
|
||||
.primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020,
|
||||
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
};
|
||||
wlr_output_state_set_image_description(os, &desc);
|
||||
}
|
||||
|
||||
void output_state_setup_hdr(Monitor *m, bool silent) {
|
||||
uint32_t render_format = m->wlr_output->render_format;
|
||||
const char *unsupported_reason = NULL;
|
||||
bool hdr_supported =
|
||||
output_supports_hdr(m->wlr_output, &unsupported_reason);
|
||||
bool hdr_succeeded = false;
|
||||
|
||||
enum render_bit_depth depth = config.hdr_depth;
|
||||
if (depth == MANGO_RENDER_BIT_DEPTH_DEFAULT)
|
||||
depth = bit_depth_from_format(render_format);
|
||||
|
||||
if (!hdr_supported && depth == MANGO_RENDER_BIT_DEPTH_10) {
|
||||
if (!silent)
|
||||
wlr_log(WLR_INFO, "Cannot enable HDR on output %s: %s",
|
||||
m->wlr_output->name, unsupported_reason);
|
||||
depth = MANGO_RENDER_BIT_DEPTH_8;
|
||||
}
|
||||
|
||||
if (depth == MANGO_RENDER_BIT_DEPTH_10 &&
|
||||
bit_depth_from_format(render_format) == depth) {
|
||||
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));
|
||||
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)))
|
||||
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)))
|
||||
if (!silent)
|
||||
wlr_log(WLR_ERROR, "No 8 bit color formats supported!");
|
||||
}
|
||||
|
||||
output_enable_hdr(m, &m->pending, hdr_succeeded, silent);
|
||||
}
|
||||
|
|
@ -100,73 +100,44 @@ bool custom_wlr_scene_output_commit(struct wlr_scene_output *scene_output,
|
|||
struct wlr_output *wlr_output = scene_output->output;
|
||||
Monitor *m = wlr_output->data;
|
||||
|
||||
// 检查是否需要帧
|
||||
if (!wlr_scene_output_needs_frame(scene_output)) {
|
||||
wlr_log(WLR_DEBUG, "No frame needed for output %s", wlr_output->name);
|
||||
if (!wlr_scene_output_needs_frame(scene_output))
|
||||
return true;
|
||||
}
|
||||
|
||||
// 构建输出状态
|
||||
if (!wlr_scene_output_build_state(scene_output, state, NULL)) {
|
||||
wlr_log(WLR_ERROR, "Failed to build output state for %s",
|
||||
wlr_output->name);
|
||||
// 构建状态,将场景的 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;
|
||||
}
|
||||
|
||||
// 测试撕裂翻页
|
||||
if (state->tearing_page_flip) {
|
||||
if (!wlr_output_test_state(wlr_output, state)) {
|
||||
state->tearing_page_flip = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试提交
|
||||
// 提交状态
|
||||
bool committed = wlr_output_commit_state(wlr_output, state);
|
||||
|
||||
// 如果启用撕裂翻页但提交失败,重试禁用撕裂翻页
|
||||
if (!committed && state->tearing_page_flip) {
|
||||
wlr_log(WLR_DEBUG, "Retrying commit without tearing for %s",
|
||||
wlr_output->name);
|
||||
// 重试一次
|
||||
state->tearing_page_flip = false;
|
||||
committed = wlr_output_commit_state(wlr_output, state);
|
||||
}
|
||||
|
||||
// 处理状态清理
|
||||
if (committed) {
|
||||
wlr_log(WLR_DEBUG, "Successfully committed output %s",
|
||||
wlr_output->name);
|
||||
if (state == &m->pending) {
|
||||
wlr_output_state_finish(&m->pending);
|
||||
wlr_output_state_init(&m->pending);
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Failed to commit output %s", wlr_output->name);
|
||||
// 即使提交失败,也清理状态避免积累
|
||||
if (state == &m->pending) {
|
||||
wlr_output_state_finish(&m->pending);
|
||||
wlr_output_state_init(&m->pending);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return committed;
|
||||
}
|
||||
|
||||
void apply_tear_state(Monitor *m) {
|
||||
if (wlr_scene_output_needs_frame(m->scene_output)) {
|
||||
wlr_output_state_init(&m->pending);
|
||||
if (wlr_scene_output_build_state(m->scene_output, &m->pending, NULL)) {
|
||||
struct wlr_output_state *pending = &m->pending;
|
||||
pending->tearing_page_flip = true;
|
||||
if (!wlr_scene_output_needs_frame(m->scene_output))
|
||||
return;
|
||||
|
||||
if (!custom_wlr_scene_output_commit(m->scene_output, pending)) {
|
||||
wlr_log(WLR_ERROR, "Failed to commit output %s",
|
||||
m->scene_output->output->name);
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Failed to build state for output %s",
|
||||
m->scene_output->output->name);
|
||||
wlr_output_state_finish(&m->pending);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue