color-lcms: keep fallback LCMS xform even when pipeline is optimized

Up to now, when we were able to optimize a color pipeline, we'd delete
xform->cmap_3dlut. In such cases, we'd have a pre curve, color mapping
and post curve that Weston recognizes and implements in the shaders. So
there was no need to use xform->cmap_3dlut.

But at some point we'll try to offload such color transformations to our
DRM-backend, and we are not in control of what color operations the
hardware/driver are capable of. In such case, we may want to use the
fallback LCMS xform (xform->cmap_3dlut) and decompose it into a shaper
(3x1D LUT) + 3D LUT, as such operations should be commonly supported
by hardwares/drivers.

This shows that using the optimized pipeline or not should be a
renderer/backend decision. So do not delete xform->cmap_3dlut even when
we optimize the pipeline.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
Leandro Ribeiro 2025-01-16 18:57:51 -03:00 committed by Pekka Paalanen
parent b3fae5ae6b
commit 9f1cf0db24
2 changed files with 25 additions and 41 deletions

View file

@ -221,7 +221,8 @@ struct cmlcms_color_transform {
* 3D LUT color mapping part of the transformation, if needed by the
* weston_color_transform. This is used as a fallback when an
* arbitrary LittleCMS pipeline cannot be translated into a more
* specific form.
* specific form or when the backend/renderer is not able to use
* such optimized form.
*/
cmsHTRANSFORM cmap_3dlut;
@ -238,14 +239,11 @@ struct cmlcms_color_transform {
/** Error producing a pipeline */
CMLCMS_TRANSFORM_FAILED = 0,
/**
* Pipeline was optimized into weston_color_transform,
* 3D LUT not used.
*/
/** Pipeline was optimized into weston_color_transform. */
CMLCMS_TRANSFORM_OPTIMIZED,
/** The transformation uses 3D LUT. */
CMLCMS_TRANSFORM_3DLUT,
/** Non-optimized pipeline, xform->cmap_3dlut must be used. */
CMLCMS_TRANSFORM_NON_OPTIMIZED,
} status;
};

View file

@ -160,8 +160,7 @@ cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform)
cmsFreeToneCurveTriple(xform->pre_curve);
if (xform->cmap_3dlut)
cmsDeleteTransform(xform->cmap_3dlut);
cmsDeleteTransform(xform->cmap_3dlut);
cmsFreeToneCurveTriple(xform->post_curve);
@ -1045,7 +1044,7 @@ lcms_optimize_pipeline(cmsPipeline **lut, cmsContext context_id)
} while (cont_opt);
}
static cmsBool
static void
optimize_float_pipeline(cmsPipeline **lut, cmsContext context_id,
struct cmlcms_color_transform *xform)
{
@ -1053,7 +1052,7 @@ optimize_float_pipeline(cmsPipeline **lut, cmsContext context_id,
if (translate_pipeline(xform, *lut)) {
xform->status = CMLCMS_TRANSFORM_OPTIMIZED;
return TRUE;
return;
}
xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_IDENTITY;
@ -1062,14 +1061,7 @@ optimize_float_pipeline(cmsPipeline **lut, cmsContext context_id,
xform->base.mapping.u.lut3d.optimal_len = cmlcms_reasonable_3D_points();
xform->base.post_curve.type = WESTON_COLOR_CURVE_TYPE_IDENTITY;
xform->status = CMLCMS_TRANSFORM_3DLUT;
/*
* We use cmsDoTransform() to realize the 3D LUT. Return false so
* that LittleCMS installs its usual float transform machinery,
* running on the pipeline we optimized here.
*/
return FALSE;
xform->status = CMLCMS_TRANSFORM_NON_OPTIMIZED;
}
static const char *
@ -1192,12 +1184,14 @@ pipeline_print(cmsPipeline **lut, cmsContext context_id,
* cmsCreateMultiprofileTransformTHR() is handed to us for inspection before
* the said function call returns.
*
* \param xform_fn If we handle the given transformation, we should assign
* our own transformation function here. We do not do that, because:
* a) Even when we optimize the pipeline, but do not handle the transformation,
* we rely on LittleCMS' own float transformation machinery.
* b) When we do handle the transformation, we will not be calling
* cmsDoTransform() anymore.
* During this call we try to optimize the pipeline and translate it into an
* optimized weston_color_transform. If the translation fails, or some renderer
* or backend cannot use the translation, we depend on LittleCMS' own float
* transformation machinery for evaluating the pipeline.
*
* \param xform_fn If we handle the given transformation, we should assign our
* own transformation function here. We do not do that, because we depend on
* LittleCMS' transformation machinery (i.e. an useful cmsHTRANSFORM).
*
* \param user_data We could store a void pointer to custom user data
* through this pointer to be carried with the cmsHTRANSFORM.
@ -1218,11 +1212,9 @@ pipeline_print(cmsPipeline **lut, cmsContext context_id,
*
* \param flags Some flags we could also override? See cmsFLAGS_* defines.
*
* \return If this returns TRUE, it implies we handle the transformation. No
* other plugin will be tried anymore and the transformation object is
* complete. If this returns FALSE, the search for a plugin to handle this
* transformation continues and falls back to the usual handling inside
* LittleCMS.
* \return We always return FALSE, because we always depend on LittleCMS being
* able to handle the transformation itself (i.e. returning an useful
* cmsHTRANSFORM).
*/
static cmsBool
transform_factory(_cmsTransform2Fn *xform_fn,
@ -1236,7 +1228,6 @@ transform_factory(_cmsTransform2Fn *xform_fn,
struct weston_color_manager_lcms *cm;
struct cmlcms_color_transform *xform;
cmsContext context_id;
bool ret;
if (T_CHANNELS(*input_format) != 3) {
weston_log("color-lcms debug: input format is not 3-channel.");
@ -1267,14 +1258,14 @@ transform_factory(_cmsTransform2Fn *xform_fn,
pipeline_print(lut, context_id, cm->optimizer_scope);
/* Optimize pipeline */
ret = optimize_float_pipeline(lut, context_id, xform);
optimize_float_pipeline(lut, context_id, xform);
/* Print pipeline after optimization */
weston_log_scope_printf(cm->optimizer_scope,
" transform pipeline after optimization:\n");
pipeline_print(lut, context_id, cm->optimizer_scope);
return ret;
return FALSE;
}
static cmsPluginTransform transform_plugin = {
@ -1390,20 +1381,15 @@ xform_realize_chain(struct cmlcms_color_transform *xform)
if (!xform->cmap_3dlut)
goto failed;
if (xform->status != CMLCMS_TRANSFORM_3DLUT) {
cmsDeleteTransform(xform->cmap_3dlut);
xform->cmap_3dlut = NULL;
}
switch (xform->status) {
case CMLCMS_TRANSFORM_FAILED:
goto failed;
case CMLCMS_TRANSFORM_OPTIMIZED:
break;
case CMLCMS_TRANSFORM_3DLUT:
case CMLCMS_TRANSFORM_NON_OPTIMIZED:
/*
* Given the chain formed above, blend-to-output should never
* fall back to 3D LUT.
* Given the chain formed above, blend-to-output should be
* optimized.
*/
weston_assert_uint32_neq(cm->base.compositor, xform->search_key.category,
CMLCMS_CATEGORY_BLEND_TO_OUTPUT);