color-lcms: add debug scope for pipeline optimizer

Whenever a color transformation is being created, this debug scope
prints its pipeline before and after being optimized. It should be used
with the color-lcms-transformations scope.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
Leandro Ribeiro 2023-03-09 18:16:55 -03:00 committed by Pekka Paalanen
parent a28e0c26e1
commit 84eb3158b4
3 changed files with 139 additions and 2 deletions

View file

@ -389,6 +389,7 @@ cmlcms_destroy(struct weston_color_manager *cm_base)
cmsDeleteContext(cm->lcms_ctx);
weston_log_scope_destroy(cm->transforms_scope);
weston_log_scope_destroy(cm->optimizer_scope);
weston_log_scope_destroy(cm->profiles_scope);
free(cm);
@ -465,18 +466,24 @@ weston_color_manager_create(struct weston_compositor *compositor)
weston_compositor_add_log_scope(compositor, "color-lcms-transformations",
"Color transformation creation and destruction.\n",
transforms_scope_new_sub, NULL, cm);
cm->optimizer_scope =
weston_compositor_add_log_scope(compositor, "color-lcms-optimizer",
"Color transformation pipeline optimizer. It's best " \
"used together with the color-lcms-transformations " \
"log scope.\n", NULL, NULL, NULL);
cm->profiles_scope =
weston_compositor_add_log_scope(compositor, "color-lcms-profiles",
"Color profile creation and destruction.\n",
profiles_scope_new_sub, NULL, cm);
if (!cm->profiles_scope || !cm->transforms_scope)
if (!cm->profiles_scope || !cm->transforms_scope || !cm->optimizer_scope)
goto err;
return &cm->base;
err:
weston_log_scope_destroy(cm->transforms_scope);
weston_log_scope_destroy(cm->optimizer_scope);
weston_log_scope_destroy(cm->profiles_scope);
free(cm);
return NULL;

View file

@ -38,6 +38,7 @@ struct weston_color_manager_lcms {
struct weston_color_manager base;
struct weston_log_scope *profiles_scope;
struct weston_log_scope *transforms_scope;
struct weston_log_scope *optimizer_scope;
cmsContext lcms_ctx;
struct wl_list color_transform_list; /* cmlcms_color_transform::link */

View file

@ -598,6 +598,118 @@ optimize_float_pipeline(cmsPipeline **lut, cmsContext context_id,
return FALSE;
}
static const char *
cmlcms_stage_type_to_str(cmsStage *stage)
{
/* This table is based on cmsStageSignature enum type from the
* LittleCMS API. */
switch (cmsStageType(stage))
{
case cmsSigCurveSetElemType:
return "CurveSet";
case cmsSigMatrixElemType:
return "Matrix";
case cmsSigCLutElemType:
return "CLut";
case cmsSigBAcsElemType:
return "BAcs";
case cmsSigEAcsElemType:
return "EAcs";
case cmsSigXYZ2LabElemType:
return "XYZ2Lab";
case cmsSigLab2XYZElemType:
return "Lab2XYz";
case cmsSigNamedColorElemType:
return "NamedColor";
case cmsSigLabV2toV4:
return "LabV2toV4";
case cmsSigLabV4toV2:
return "LabV4toV2";
case cmsSigIdentityElemType:
return "Identity";
case cmsSigLab2FloatPCS:
return "Lab2FloatPCS";
case cmsSigFloatPCS2Lab:
return "FloatPCS2Lab";
case cmsSigXYZ2FloatPCS:
return "XYZ2FloatPCS";
case cmsSigFloatPCS2XYZ:
return "FloatPCS2XYZ";
case cmsSigClipNegativesElemType:
return "ClipNegatives";
}
return NULL;
}
static void
matrix_print(cmsStage *stage, struct weston_log_scope *scope)
{
const _cmsStageMatrixData *data;
const unsigned int SIZE = 3;
unsigned int row, col;
double elem;
const char *sep;
if (!weston_log_scope_is_enabled(scope))
return;
assert(cmsStageType(stage) == cmsSigMatrixElemType);
data = cmsStageData(stage);
for (row = 0; row < SIZE; row++) {
weston_log_scope_printf(scope, " ");
for (col = 0, sep = ""; col < SIZE; col++) {
elem = data->Double[row * SIZE + col];
weston_log_scope_printf(scope, "%s% .4f", sep, elem);
sep = " ";
}
/* We print offset after the last column of the matrix. */
if (data->Offset)
weston_log_scope_printf(scope, "% .4f", data->Offset[row]);
weston_log_scope_printf(scope, "\n");
}
}
static void
pipeline_print(cmsPipeline **lut, cmsContext context_id,
struct weston_log_scope *scope)
{
cmsStage *stage = cmsPipelineGetPtrToFirstStage(*lut);
const char *type_str;
if (!weston_log_scope_is_enabled(scope))
return;
if (!stage) {
weston_log_scope_printf(scope, "no elements\n");
return;
}
while (stage != NULL) {
type_str = cmlcms_stage_type_to_str(stage);
/* Unknown type, just print the hex */
if (!type_str)
weston_log_scope_printf(scope, " unknown type 0x%x\n",
cmsStageType(stage));
else
weston_log_scope_printf(scope, " %s\n", type_str);
switch(cmsStageType(stage)) {
case cmsSigMatrixElemType:
matrix_print(stage, scope);
break;
default:
break;
}
stage = cmsStageNext(stage);
}
}
/** LittleCMS transform plugin entry point
*
* This function is called by LittleCMS when it is creating a new
@ -647,8 +759,10 @@ transform_factory(_cmsTransform2Fn *xform_fn,
cmsUInt32Number *output_format,
cmsUInt32Number *flags)
{
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.");
@ -671,7 +785,22 @@ transform_factory(_cmsTransform2Fn *xform_fn,
xform = cmsGetContextUserData(context_id);
assert(xform);
return optimize_float_pipeline(lut, context_id, xform);
cm = get_cmlcms(xform->base.cm);
/* Print pipeline before optimization */
weston_log_scope_printf(cm->optimizer_scope,
" transform pipeline before optimization:\n");
pipeline_print(lut, context_id, cm->optimizer_scope);
/* Optimize pipeline */
ret = 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;
}
static cmsPluginTransform transform_plugin = {