color-lcms: extract HDR static metadata from profile

Extract the HDR static metadata type 1 from the output color profile
directly, instead of relying on a separate weston.ini section to provide
the metadata separately.

Weston should tell the monitor what target color volume it is rendering
for. I don't see a reason to be able to control the metadata separately,
and it would add complexity.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2026-01-30 15:17:59 +02:00 committed by Leandro Ribeiro
parent 8872d5ee14
commit dbdb5f92f2
2 changed files with 46 additions and 71 deletions

View file

@ -195,7 +195,7 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager_lcms *cm,
static float
meta_clamp(float value, const char *valname, float min, float max,
struct weston_output *output)
const struct cmlcms_color_profile *cprof)
{
float ret = value;
@ -207,78 +207,71 @@ meta_clamp(float value, const char *valname, float min, float max,
ret = max;
if (ret != value) {
weston_log("output '%s' clamping %s value from %f to %f.\n",
output->name, valname, value, ret);
weston_log("Output profile p%u '%s': clamping %s value from %f to %f.\n",
cprof->base.id, cprof->base.description, valname, value, ret);
}
return ret;
}
static bool
cmlcms_get_hdr_meta(struct weston_output *output,
struct weston_hdr_metadata_type1 *hdr_meta)
static void
cmlcms_get_hdr_meta(struct weston_hdr_metadata_type1 *hdr_meta,
const struct cmlcms_color_profile *cprof)
{
const struct weston_color_characteristics *cc;
/* TODO: get color characteristics from color profiles instead. */
const struct weston_color_profile_params *cpp = NULL;
unsigned i;
hdr_meta->group_mask = 0;
/* Only SMPTE ST 2084 mode uses HDR Static Metadata Type 1 */
if (weston_output_get_eotf_mode(output) != WESTON_EOTF_MODE_ST2084)
return true;
switch (cprof->type) {
case CMLCMS_PROFILE_TYPE_ICC:
/* No HDR metadata */
return;
cc = weston_output_get_color_characteristics(output);
/* Target content chromaticity */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
hdr_meta->primary[i].x = meta_clamp(cc->primary[i].x,
"primary", 0.0, 1.0,
output);
hdr_meta->primary[i].y = meta_clamp(cc->primary[i].y,
"primary", 0.0, 1.0,
output);
}
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES;
case CMLCMS_PROFILE_TYPE_PARAMS:
cpp = cprof->params;
break;
}
weston_assert_ptr_not_null(cprof->base.cm->compositor, cpp);
/* Target content white point */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE) {
hdr_meta->white.x = meta_clamp(cc->white.x, "white",
0.0, 1.0, output);
hdr_meta->white.y = meta_clamp(cc->white.y, "white",
0.0, 1.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE;
for (i = 0; i < 3; i++) {
hdr_meta->primary[i].x = meta_clamp(cpp->target_primaries.primary[i].x,
"primary", 0.0, 1.0, cprof);
hdr_meta->primary[i].y = meta_clamp(cpp->target_primaries.primary[i].y,
"primary", 0.0, 1.0, cprof);
}
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES;
/* Target content peak and max mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL) {
hdr_meta->maxDML = meta_clamp(cc->max_luminance, "maxDML",
1.0, 65535.0, output);
hdr_meta->maxCLL = meta_clamp(cc->max_luminance, "maxCLL",
1.0, 65535.0, output);
hdr_meta->white.x = meta_clamp(cpp->target_primaries.white_point.x,
"white", 0.0, 1.0, cprof);
hdr_meta->white.y = meta_clamp(cpp->target_primaries.white_point.y,
"white", 0.0, 1.0, cprof);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE;
if (cpp->target_max_luminance > 0.0f) {
hdr_meta->maxDML = meta_clamp(cpp->target_max_luminance,
"maxDML", 1.0, 65535.0, cprof);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML;
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL;
}
/* Target content min mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MINL) {
hdr_meta->minDML = meta_clamp(cc->min_luminance, "minDML",
0.0001, 6.5535, output);
if (cpp->target_min_luminance > 0.0f) {
hdr_meta->minDML = meta_clamp(cpp->target_min_luminance,
"minDML", 0.0001, 6.5535, cprof);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MINDML;
}
/* Target content max frame-average luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL) {
hdr_meta->maxFALL = meta_clamp(cc->maxFALL, "maxFALL",
1.0, 65535.0, output);
if (cpp->maxFALL > 0.0f) {
hdr_meta->maxFALL = meta_clamp(cpp->maxFALL,
"maxFALL", 1.0, 65535.0, cprof);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL;
}
return true;
if (cpp->maxCLL > 0.0f) {
hdr_meta->maxCLL = meta_clamp(cpp->maxCLL,
"maxCLL", 1.0, 65535.0, cprof);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL;
}
}
static struct weston_output_color_outcome *
@ -288,14 +281,13 @@ cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_color_manager_lcms *cm = to_cmlcms(cm_base);
struct weston_output_color_outcome *co;
weston_assert_ptr_not_null(cm->base.compositor, output->color_profile);
co = zalloc(sizeof *co);
if (!co)
return NULL;
if (!cmlcms_get_hdr_meta(output, &co->hdr_meta))
goto out_fail;
assert(output->color_profile);
cmlcms_get_hdr_meta(&co->hdr_meta, to_cmlcms_cprof(output->color_profile));
/* TODO: take container color space into account */

View file

@ -77,7 +77,6 @@ PLUGIN_TEST(color_characteristics_from_weston_ini)
enum weston_eotf_mode mode;
enum weston_colorimetry_mode colorimetry_mode;
const struct weston_color_characteristics *cc;
const struct weston_hdr_metadata_type1 *hdr_meta;
wl_list_for_each(it, &compositor->output_list, link) {
if (strcmp(it->name, "headless") == 0) {
@ -108,21 +107,5 @@ PLUGIN_TEST(color_characteristics_from_weston_ini)
test_assert_f32_eq(cc->max_luminance, 65535.0f);
test_assert_f32_eq(cc->maxFALL, 1000.0f);
/* The below is color manager policy. */
hdr_meta = weston_output_get_hdr_metadata_type1(output);
test_assert_enum(hdr_meta->group_mask, WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK);
test_assert_f32_eq(hdr_meta->primary[0].x, 0.9999f);
test_assert_f32_eq(hdr_meta->primary[0].y, 0.3f);
test_assert_f32_eq(hdr_meta->primary[1].x, 0.1771f);
test_assert_f32_eq(hdr_meta->primary[1].y, 0.80001f);
test_assert_f32_eq(hdr_meta->primary[2].x, 0.1f);
test_assert_f32_eq(hdr_meta->primary[2].y, 0.11f);
test_assert_f32_eq(hdr_meta->white.x, 0.313f);
test_assert_f32_eq(hdr_meta->white.y, 0.323f);
test_assert_f32_eq(hdr_meta->minDML, 0.0001f);
test_assert_f32_eq(hdr_meta->maxDML, 65535.0f);
test_assert_f32_eq(hdr_meta->maxCLL, 65535.0f);
test_assert_f32_eq(hdr_meta->maxFALL, 1000.0f);
return RESULT_OK;
}