diff --git a/backend/drm/util.c b/backend/drm/util.c index dd2b37351..e0d3c03a3 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) { @@ -93,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/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/render/vulkan.h b/include/render/vulkan.h index 5358b01c1..1ed53aa91 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -426,6 +426,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 1785ee562..a2014e0c1 100644 --- a/include/wlr/render/pass.h +++ b/include/wlr/render/pass.h @@ -37,6 +37,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/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 2ae11a4d3..87457415b 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -197,6 +197,9 @@ 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 + float min_luminance, max_luminance, max_fall; // cd/m², zero if unset + bool enabled; float scale; enum wl_output_subpixel subpixel; diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 398ee2104..ee0b78339 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -254,7 +254,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); @@ -1243,6 +1247,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); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index c5cbcd29f..020af3c1e 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2359,12 +2359,31 @@ 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; + + 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}; + 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); @@ -2388,6 +2407,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output, .timer = timer ? timer->render_timer : NULL, .color_transform = color_transform, .primaries = primaries, + .luminances = target_luminances, .signal_timeline = scene_output->in_timeline, .signal_point = scene_output->in_point, });