From b7fe653aac6c39806b41fa46f983904ceffbf789 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Jun 2025 13:12:05 +0200 Subject: [PATCH 1/5] output, backend/drm: add wlr_output.color_primaries This contains the output's color primaries, if known. --- backend/drm/util.c | 17 +++++++++++++++++ include/backend/drm/drm.h | 1 + include/wlr/types/wlr_output.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/backend/drm/util.c b/backend/drm/util.c index dd2b37351..76276849d 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -50,6 +50,14 @@ enum wlr_output_mode_aspect_ratio get_picture_aspect_ratio(const drmModeModeInfo } } +static void copy_chromaticity_cie1931(struct wlr_color_cie1931_xy *dst, + const struct di_chromaticity_cie1931 *src) { + *dst = (struct wlr_color_cie1931_xy){ + .x = src->x, + .y = src->y, + }; +} + void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) { struct wlr_output *output = &conn->output; @@ -83,6 +91,15 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) output->model = di_info_get_model(info); output->serial = di_info_get_serial(info); + const struct di_color_primaries *primaries = di_info_get_default_color_primaries(info); + if (primaries->has_primaries && primaries->has_default_white_point) { + copy_chromaticity_cie1931(&conn->color_primaries.red, &primaries->primary[0]); + copy_chromaticity_cie1931(&conn->color_primaries.green, &primaries->primary[1]); + copy_chromaticity_cie1931(&conn->color_primaries.blue, &primaries->primary[2]); + copy_chromaticity_cie1931(&conn->color_primaries.white, &primaries->default_white); + output->color_primaries = &conn->color_primaries; + } + const struct di_supported_signal_colorimetry *colorimetry = di_info_get_supported_signal_colorimetry(info); bool has_bt2020 = colorimetry->bt2020_cycc || colorimetry->bt2020_ycc || colorimetry->bt2020_rgb; if (conn->props.colorspace != 0 && has_bt2020) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index af4231f54..7aa10c76d 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -195,6 +195,7 @@ struct wlr_drm_connector { drmModeConnection status; uint32_t id; uint64_t max_bpc_bounds[2]; + struct wlr_color_primaries color_primaries; // might be zero struct wlr_drm_lease *lease; struct wlr_drm_crtc *crtc; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 6a0dd0455..634b8498b 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -197,6 +197,8 @@ struct wlr_output { uint32_t supported_primaries; // bitfield of enum wlr_color_named_primaries uint32_t supported_transfer_functions; // bitfield of enum wlr_color_transfer_function + const struct wlr_color_primaries *color_primaries; // NULL if unset + bool enabled; float scale; enum wl_output_subpixel subpixel; From 7b91939d9e2387c4b1705fc6fb0dc541810cd23c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Jun 2025 13:15:49 +0200 Subject: [PATCH 2/5] output, backend/drm: add desired luminances to wlr_output --- backend/drm/util.c | 3 +++ include/wlr/types/wlr_output.h | 1 + 2 files changed, 4 insertions(+) diff --git a/backend/drm/util.c b/backend/drm/util.c index 76276849d..e0d3c03a3 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -110,6 +110,9 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) { output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ; } + output->min_luminance = hdr_static_metadata->desired_content_min_luminance; + output->max_luminance = hdr_static_metadata->desired_content_max_luminance; + output->max_fall = hdr_static_metadata->desired_content_max_frame_avg_luminance; di_info_destroy(info); } diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 634b8498b..63903c499 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -198,6 +198,7 @@ struct wlr_output { uint32_t supported_transfer_functions; // bitfield of enum wlr_color_transfer_function const struct wlr_color_primaries *color_primaries; // NULL if unset + float min_luminance, max_luminance, max_fall; // cd/m², zero if unset bool enabled; float scale; From de52bc70b9ed6dcb51db1c06888b694d084bbba7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Jun 2025 13:39:40 +0200 Subject: [PATCH 3/5] render, render/vulkan: add wlr_buffer_pass_options.luminances Allows callers to customized the target luminances. --- include/render/vulkan.h | 3 +++ include/wlr/render/pass.h | 2 ++ render/vulkan/pass.c | 10 +++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index deff0eac3..8a1e820fa 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -407,6 +407,9 @@ struct wlr_vk_render_pass { bool has_primaries; struct wlr_color_primaries primaries; + bool has_luminances; + struct wlr_color_luminances luminances; + struct wlr_drm_syncobj_timeline *signal_timeline; uint64_t signal_point; diff --git a/include/wlr/render/pass.h b/include/wlr/render/pass.h index 8e22bdf8f..c1d92fe12 100644 --- a/include/wlr/render/pass.h +++ b/include/wlr/render/pass.h @@ -36,6 +36,8 @@ struct wlr_buffer_pass_options { struct wlr_color_transform *color_transform; /** Primaries describing the color volume of the destination buffer */ const struct wlr_color_primaries *primaries; + /** Luminances for the destination buffer */ + const struct wlr_color_luminances *luminances; /* Signal a timeline synchronization point when the render pass completes. * diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 4fd357113..ec0f46460 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -251,7 +251,11 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { struct wlr_color_luminances srgb_lum, dst_lum; wlr_color_transfer_function_get_default_luminance( WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum); - wlr_color_transfer_function_get_default_luminance(tf, &dst_lum); + if (pass->has_luminances) { + dst_lum = pass->luminances; + } else { + wlr_color_transfer_function_get_default_luminance(tf, &dst_lum); + } frag_pcr_data.luminance_multiplier = get_luminance_multiplier(&srgb_lum, &dst_lum); } bind_pipeline(pass, pipeline); @@ -1221,6 +1225,10 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend pass->has_primaries = true; pass->primaries = *options->primaries; } + if (options != NULL && options->luminances != NULL) { + pass->has_luminances = true; + pass->luminances = *options->luminances; + } rect_union_init(&pass->updated_region); From 6d86dcc56d449dbf9fcc18a46d0ebd02fea8b704 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Jun 2025 13:48:24 +0200 Subject: [PATCH 4/5] scene: adjust rendering luminances based on output image description --- types/scene/wlr_scene.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 8c58ea2b1..bb97a4dfb 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2282,12 +2282,26 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, struct wlr_color_transform *color_transform = NULL; const struct wlr_color_primaries *primaries = NULL; + const struct wlr_color_luminances *target_luminances = NULL; struct wlr_color_primaries primaries_value; + struct wlr_color_luminances target_luminances_value; const struct wlr_output_image_description *img_desc = output_pending_image_description(output, state); if (img_desc != NULL) { color_transform = wlr_color_transform_init_linear_to_inverse_eotf(img_desc->transfer_function); + wlr_color_primaries_from_named(&primaries_value, img_desc->primaries); primaries = &primaries_value; + + if (img_desc->mastering_luminance.min != 0 || img_desc->mastering_luminance.max != 0) { + struct wlr_color_luminances default_lum = {0}; + wlr_color_transfer_function_get_default_luminance(img_desc->transfer_function, &default_lum); + target_luminances_value = (struct wlr_color_luminances){ + .min = img_desc->mastering_luminance.min, + .max = img_desc->mastering_luminance.max, + .reference = default_lum.reference, // TODO: make configurable + }; + target_luminances = &target_luminances_value; + } } if (options->color_transform != NULL) { assert(color_transform == NULL); @@ -2300,6 +2314,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, .timer = timer ? timer->render_timer : NULL, .color_transform = options->color_transform, .primaries = primaries, + .luminances = target_luminances, .signal_timeline = scene_output->in_timeline, .signal_point = scene_output->in_point, }); From f07604d47b31005aa3bccfb146278d4757897682 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 26 Jun 2025 16:29:27 +0200 Subject: [PATCH 5/5] scene: adjust rendering primaries based on output image description --- types/scene/wlr_scene.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index bb97a4dfb..7972c4cc1 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2289,8 +2289,13 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, if (img_desc != NULL) { color_transform = wlr_color_transform_init_linear_to_inverse_eotf(img_desc->transfer_function); - wlr_color_primaries_from_named(&primaries_value, img_desc->primaries); - primaries = &primaries_value; + struct wlr_color_primaries zero_primaries = {0}; + if (memcmp(&img_desc->mastering_display_primaries, &zero_primaries, sizeof(zero_primaries)) != 0) { + primaries = &img_desc->mastering_display_primaries; + } else { + wlr_color_primaries_from_named(&primaries_value, img_desc->primaries); + primaries = &primaries_value; + } if (img_desc->mastering_luminance.min != 0 || img_desc->mastering_luminance.max != 0) { struct wlr_color_luminances default_lum = {0};