color-lcms: override sRGB two-piece TF on input profile

https://gitlab.freedesktop.org/pq/color-and-hdr/-/blob/main/doc/wayland_qa.md#q-should-srgb-content-be-decoded-with-the-piecewise-srgb-transfer-function

When anything claims to target a display with the sRGB two-piece
transfer function, override it with the power-2.2. That is how sRGB
displays actually work.

This patch includes a small refactoring in
cmlcms_color_transform_create().

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2025-06-10 13:51:50 +03:00
parent 3999d685bc
commit 37bee3050e

View file

@ -1560,6 +1560,16 @@ xform_to_shaper_plus_3dlut(struct weston_color_transform *xform_base,
return true;
}
static void
cmlcms_color_transform_recipe_copy(struct cmlcms_color_transform_recipe *dst,
const struct cmlcms_color_transform_recipe *src)
{
dst->category = src->category;
dst->input_profile = ref_cprof(src->input_profile);
dst->output_profile = ref_cprof(src->output_profile);
dst->render_intent = src->render_intent;
}
static struct cmlcms_color_transform *
cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
const struct cmlcms_color_transform_recipe *recipe)
@ -1572,9 +1582,7 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
weston_color_transform_init(&xform->base, &cm->base);
wl_list_init(&xform->link);
xform->base.to_shaper_plus_3dlut = xform_to_shaper_plus_3dlut;
xform->search_key = *recipe;
xform->search_key.input_profile = ref_cprof(recipe->input_profile);
xform->search_key.output_profile = ref_cprof(recipe->output_profile);
cmlcms_color_transform_recipe_copy(&xform->search_key, recipe);
weston_log_scope_printf(cm->transforms_scope,
"New color transformation: t%u\n", xform->base.id);
@ -1612,6 +1620,49 @@ error:
return NULL;
}
static void
cmclms_adjust_recipe(struct cmlcms_color_transform_recipe *adjusted,
const struct cmlcms_color_transform_recipe *recipe,
struct weston_color_manager_lcms *cm)
{
const struct cmlcms_color_profile *in_prof = recipe->input_profile;
struct weston_color_profile_params tmp;
struct weston_color_profile *replacement;
char *errmsg;
bool ret;
cmlcms_color_transform_recipe_copy(adjusted, recipe);
if (!in_prof)
return;
/*
* The standard sRGB display uses a power-2.2 EOTF. Anything that claims
* to be targeting a display with the sRGB two-piece TF is likely mistaken.
*/
if (in_prof->type == CMLCMS_PROFILE_TYPE_PARAMS &&
in_prof->params->tf_info->tf == WESTON_TF_SRGB) {
tmp = *in_prof->params;
tmp.tf_info = weston_color_tf_info_from(cm->base.compositor, WESTON_TF_GAMMA22);
ret = cmlcms_get_color_profile_from_params(&cm->base,
&tmp, "override sRGB EOTF",
&replacement, &errmsg);
if (ret) {
weston_log_scope_printf(cm->transforms_scope,
"Replacing profile p%u (%s) with profile p%u (%s)"
"for color transformation.\n",
in_prof->base.id,
in_prof->params->tf_info->desc,
replacement->id, tmp.tf_info->desc);
unref_cprof(adjusted->input_profile);
adjusted->input_profile = to_cmlcms_cprof(replacement);
} else {
weston_log("Warning: overriding sRGB two-piece TF with power-2.2 failed: %s\n", errmsg);
free(errmsg);
}
}
}
static bool
transform_matches_recipe(const struct cmlcms_color_transform *xform,
const struct cmlcms_color_transform_recipe *recipe)
@ -1631,7 +1682,9 @@ struct cmlcms_color_transform *
cmlcms_color_transform_get(struct weston_color_manager_lcms *cm,
const struct cmlcms_color_transform_recipe *recipe)
{
struct cmlcms_color_transform *xform;
struct cmlcms_color_transform_recipe adjusted;
struct cmlcms_color_transform *xform = NULL;
struct cmlcms_color_transform *it;
weston_assert_ptr_not_null(cm->base.compositor, recipe->output_profile);
switch (recipe->category) {
@ -1646,16 +1699,23 @@ cmlcms_color_transform_get(struct weston_color_manager_lcms *cm,
break;
}
wl_list_for_each(xform, &cm->color_transform_list, link) {
if (transform_matches_recipe(xform, recipe)) {
weston_color_transform_ref(&xform->base);
return xform;
cmclms_adjust_recipe(&adjusted, recipe, cm);
wl_list_for_each(it, &cm->color_transform_list, link) {
if (transform_matches_recipe(it, &adjusted)) {
weston_color_transform_ref(&it->base);
xform = it;
}
}
xform = cmlcms_color_transform_create(cm, recipe);
if (!xform)
xform = cmlcms_color_transform_create(cm, &adjusted);
if (!xform)
weston_log("color-lcms error: failed to create a color transformation.\n");
unref_cprof(adjusted.input_profile);
unref_cprof(adjusted.output_profile);
return xform;
}