summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPekka Paalanen <pekka.paalanen@collabora.com>2024-02-28 14:53:59 +0200
committerPekka Paalanen <pq@iki.fi>2024-03-07 14:50:47 +0000
commit4b9fa23ec6a3b2331fca5c88a3826ef9c8cd603a (patch)
tree1158ae1eeb84fdad2f871b69d61d08e3ce3cf61f
parent98454720be3abf03d55b6bf4f45115773f0f5630 (diff)
color-lcms: stop hard-coding blend-to-output transformation
Stop special-casing the blend-to-output category, and pass it through the same mechnisms and optimizations as all other transformations. In the future, more curve types will be added to weston_color_transform, meaning that blend-to-output does not always have to be a LUT. It could become a parametric curve, which is more efficient and more precise to compute, when VCGT does not exist. Drop the special crafting of output_inv_eotf_vcgt LUT and replace it with inv_eotf cms profile. inv_eotf will be combined with vcgt cms profile as a chain as needed instead. Blend-to-output transformations do not use a render intent, but we have to tell cmsCreateMultiprofileTransformTHR() something, so arbitrarily pick ICC-Absolute render intent for it. Now all color transformations go through xform_realize_chain(), where the documentation is improved. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
-rw-r--r--libweston/color-lcms/color-lcms.h12
-rw-r--r--libweston/color-lcms/color-profile.c31
-rw-r--r--libweston/color-lcms/color-transform.c73
3 files changed, 50 insertions, 66 deletions
diff --git a/libweston/color-lcms/color-lcms.h b/libweston/color-lcms/color-lcms.h
index fe9e87f1..1726553c 100644
--- a/libweston/color-lcms/color-lcms.h
+++ b/libweston/color-lcms/color-lcms.h
@@ -84,16 +84,8 @@ struct cmlcms_output_profile_extract {
*/
struct lcmsProfilePtr eotf;
- /**
- * This field represents a concatenation of inverse EOTF + VCGT,
- * if the tag exists and it can not be null.
- * VCGT is part of monitor calibration which means: even though we must
- * apply VCGT in the compositor, we pretend that it happens inside the
- * monitor. This is how the classic color management and ICC profiles work.
- * The ICC profile (ignoring the VCGT tag) characterizes the output which
- * is VCGT + monitor behavior.
- */
- cmsToneCurve *output_inv_eotf_vcgt[3];
+ /** The inverse of above */
+ struct lcmsProfilePtr inv_eotf;
/**
* VCGT tag cached from output profile, it could be null if not exist
diff --git a/libweston/color-lcms/color-profile.c b/libweston/color-lcms/color-profile.c
index ca4c3abb..0e36b6a3 100644
--- a/libweston/color-lcms/color-profile.c
+++ b/libweston/color-lcms/color-profile.c
@@ -192,6 +192,7 @@ ensure_output_profile_extract_icc(struct cmlcms_output_profile_extract *extract,
cmsToneCurve *curve = NULL;
cmsToneCurve **vcgt_curves;
cmsToneCurve *eotf_curves[3] = {};
+ cmsToneCurve *inv_eotf_curves[3] = {};
unsigned i;
cmsTagSignature tags[] = {
cmsSigRedTRCTag, cmsSigGreenTRCTag, cmsSigBlueTRCTag
@@ -240,8 +241,14 @@ ensure_output_profile_extract_icc(struct cmlcms_output_profile_extract *extract,
*err_msg = "inverting EOTF failed";
goto fail;
}
- extract->output_inv_eotf_vcgt[i] = curve;
+ inv_eotf_curves[i] = curve;
}
+ extract->inv_eotf.p = cmsCreateLinearizationDeviceLinkTHR(lcms_ctx, cmsSigRgbData, inv_eotf_curves);
+ if (!extract->inv_eotf.p) {
+ *err_msg = "out of memory";
+ goto fail;
+ }
+
vcgt_curves = cmsReadTag(hProfile.p, cmsSigVcgtTag);
if (vcgt_curves && vcgt_curves[0] && vcgt_curves[1] && vcgt_curves[2]) {
extract->vcgt.p = cmsCreateLinearizationDeviceLinkTHR(lcms_ctx, cmsSigRgbData, vcgt_curves);
@@ -249,20 +256,9 @@ ensure_output_profile_extract_icc(struct cmlcms_output_profile_extract *extract,
*err_msg = "out of memory";
goto fail;
}
-
- for (i = 0; i < 3; i++) {
- curve = lcmsJoinToneCurve(lcms_ctx,
- extract->output_inv_eotf_vcgt[i],
- vcgt_curves[i], num_points);
- if (!curve) {
- *err_msg = "joining curves failed";
- goto fail;
- }
- cmsFreeToneCurve(extract->output_inv_eotf_vcgt[i]);
- extract->output_inv_eotf_vcgt[i] = curve;
- }
}
+ cmsFreeToneCurveTriple(inv_eotf_curves);
cmsFreeToneCurveTriple(eotf_curves);
return true;
@@ -271,10 +267,15 @@ fail:
cmsCloseProfile(extract->vcgt.p);
extract->vcgt.p = NULL;
+ cmsCloseProfile(extract->inv_eotf.p);
+ extract->inv_eotf.p = NULL;
+
cmsCloseProfile(extract->eotf.p);
extract->eotf.p = NULL;
+
+ cmsFreeToneCurveTriple(inv_eotf_curves);
cmsFreeToneCurveTriple(eotf_curves);
- cmsFreeToneCurveTriple(extract->output_inv_eotf_vcgt);
+
return false;
}
@@ -391,8 +392,8 @@ cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
wl_list_remove(&cprof->link);
cmsCloseProfile(cprof->extract.vcgt.p);
+ cmsCloseProfile(cprof->extract.inv_eotf.p);
cmsCloseProfile(cprof->extract.eotf.p);
- cmsFreeToneCurveTriple(cprof->extract.output_inv_eotf_vcgt);
cmsCloseProfile(cprof->profile.p);
/* Only profiles created from ICC files have these. */
diff --git a/libweston/color-lcms/color-transform.c b/libweston/color-lcms/color-transform.c
index 4ade4932..8bd5ea44 100644
--- a/libweston/color-lcms/color-transform.c
+++ b/libweston/color-lcms/color-transform.c
@@ -89,17 +89,6 @@ fill_in_curves(cmsToneCurve *curves[3], float *values, unsigned len)
}
static void
-cmlcms_fill_in_output_inv_eotf_vcgt(struct weston_color_transform *xform_base,
- float *values, unsigned len)
-{
- struct cmlcms_color_transform *xform = to_cmlcms_xform(xform_base);
- struct cmlcms_color_profile *p = xform->search_key.output_profile;
-
- assert(p && "output_profile");
- fill_in_curves(p->extract.output_inv_eotf_vcgt, values, len);
-}
-
-static void
cmlcms_fill_in_pre_curve(struct weston_color_transform *xform_base,
float *values, unsigned len)
{
@@ -868,31 +857,50 @@ xform_realize_chain(struct cmlcms_color_transform *xform)
{
struct weston_color_manager_lcms *cm = to_cmlcms(xform->base.cm);
struct cmlcms_color_profile *output_profile = xform->search_key.output_profile;
+ const struct weston_render_intent_info *render_intent;
struct lcmsProfilePtr chain[5];
unsigned chain_len = 0;
struct lcmsProfilePtr extra = { NULL };
cmsUInt32Number dwFlags;
- chain[chain_len++] = xform->search_key.input_profile->profile;
- chain[chain_len++] = output_profile->profile;
+ render_intent = xform->search_key.render_intent;
+
+ /*
+ * Our blending space is chosen to be the optical output color space.
+ * From input space, we always go to electrical output space, then
+ * come to optical space for blending, and finally go back to
+ * electrical output space. Before the image is sent to display,
+ * we must also apply VCGT if given, since nothing else would do that.
+ *
+ * INPUT_TO_BLEND + BLEND_TO_OUTPUT = INPUT_TO_OUTPUT
+ */
switch (xform->search_key.category) {
case CMLCMS_CATEGORY_INPUT_TO_BLEND:
- /* Add linearization step to make blending well-defined. */
+ chain[chain_len++] = xform->search_key.input_profile->profile;
+ chain[chain_len++] = output_profile->profile;
chain[chain_len++] = output_profile->extract.eotf;
break;
+ case CMLCMS_CATEGORY_BLEND_TO_OUTPUT:
+ chain[chain_len++] = output_profile->extract.inv_eotf;
+ if (output_profile->extract.vcgt.p)
+ chain[chain_len++] = output_profile->extract.vcgt;
+
+ /* Render intent does not apply here, but need to set something. */
+ weston_assert_ptr_is_null(cm->base.compositor, render_intent);
+ render_intent = weston_render_intent_info_from(cm->base.compositor,
+ WESTON_RENDER_INTENT_ABSOLUTE);
+ break;
case CMLCMS_CATEGORY_INPUT_TO_OUTPUT:
- /* Just add VCGT if it is provided. */
+ chain[chain_len++] = xform->search_key.input_profile->profile;
+ chain[chain_len++] = output_profile->profile;
if (output_profile->extract.vcgt.p)
chain[chain_len++] = output_profile->extract.vcgt;
break;
- case CMLCMS_CATEGORY_BLEND_TO_OUTPUT:
- assert(0 && "category handled in the caller");
- return false;
}
assert(chain_len <= ARRAY_LENGTH(chain));
- weston_assert_ptr(cm->base.compositor, xform->search_key.render_intent);
+ weston_assert_ptr(cm->base.compositor, render_intent);
/**
* Binding to our LittleCMS plug-in occurs here.
@@ -905,13 +913,13 @@ xform_realize_chain(struct cmlcms_color_transform *xform)
assert(xform->status == CMLCMS_TRANSFORM_FAILED);
/* transform_factory() is invoked by this call. */
- dwFlags = xform->search_key.render_intent->bps ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0;
+ dwFlags = render_intent->bps ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0;
xform->cmap_3dlut = cmsCreateMultiprofileTransformTHR(xform->lcms_ctx,
from_lcmsProfilePtr_array(chain),
chain_len,
TYPE_RGB_FLT,
TYPE_RGB_FLT,
- xform->search_key.render_intent->lcms_intent,
+ render_intent->lcms_intent,
dwFlags);
cmsCloseProfile(extra.p);
@@ -996,26 +1004,9 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
cmlcms_reasonable_1D_points(), &err_msg))
goto error;
- /*
- * The blending space is chosen to be the output device space but
- * linearized. This means that BLEND_TO_OUTPUT only needs to
- * undo the linearization and add VCGT.
- */
- switch (search_param->category) {
- case CMLCMS_CATEGORY_INPUT_TO_BLEND:
- case CMLCMS_CATEGORY_INPUT_TO_OUTPUT:
- if (!xform_realize_chain(xform)) {
- err_msg = "xform_realize_chain failed";
- goto error;
- }
- break;
- case CMLCMS_CATEGORY_BLEND_TO_OUTPUT:
- xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D;
- xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_output_inv_eotf_vcgt;
- xform->base.pre_curve.u.lut_3x1d.optimal_len =
- cmlcms_reasonable_1D_points();
- xform->status = CMLCMS_TRANSFORM_OPTIMIZED;
- break;
+ if (!xform_realize_chain(xform)) {
+ err_msg = "xform_realize_chain failed";
+ goto error;
}
wl_list_insert(&cm->color_transform_list, &xform->link);