Skip to content
Commits on Source (5)
......@@ -33,6 +33,7 @@
#include "color.h"
#include "color-lcms.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
const char *
cmlcms_category_name(enum cmlcms_category cat)
......@@ -386,9 +387,58 @@ cmlcms_destroy(struct weston_color_manager *cm_base)
assert(wl_list_empty(&cm->color_profile_list));
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);
}
static void
transforms_scope_new_sub(struct weston_log_subscription *subs, void *data)
{
struct weston_color_manager_lcms *cm = data;
struct cmlcms_color_transform *xform;
char *str;
if (wl_list_empty(&cm->color_transform_list))
return;
weston_log_subscription_printf(subs, "Existent:\n");
wl_list_for_each(xform, &cm->color_transform_list, link) {
weston_log_subscription_printf(subs, "Color transformation %p:\n", xform);
str = cmlcms_color_transform_search_param_string(&xform->search_key);
weston_log_subscription_printf(subs, "%s", str);
free(str);
str = weston_color_transform_string(&xform->base);
weston_log_subscription_printf(subs, " %s", str);
free(str);
}
}
static void
profiles_scope_new_sub(struct weston_log_subscription *subs, void *data)
{
struct weston_color_manager_lcms *cm = data;
struct cmlcms_color_profile *cprof;
char *str;
if (wl_list_empty(&cm->color_profile_list))
return;
weston_log_subscription_printf(subs, "Existent:\n");
wl_list_for_each(cprof, &cm->color_profile_list, link) {
weston_log_subscription_printf(subs, "Color profile %p:\n", cprof);
str = cmlcms_color_profile_print(cprof);
weston_log_subscription_printf(subs, "%s", str);
free(str);
}
}
WL_EXPORT struct weston_color_manager *
weston_color_manager_create(struct weston_compositor *compositor)
{
......@@ -412,5 +462,29 @@ weston_color_manager_create(struct weston_compositor *compositor)
wl_list_init(&cm->color_transform_list);
wl_list_init(&cm->color_profile_list);
cm->transforms_scope =
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 || !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;
}
......@@ -29,12 +29,16 @@
#include <lcms2.h>
#include <libweston/libweston.h>
#include <libweston/weston-log.h>
#include "color.h"
#include "shared/helpers.h"
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 */
......@@ -205,6 +209,9 @@ cmlcms_color_transform_get(struct weston_color_manager_lcms *cm,
void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform);
char *
cmlcms_color_transform_search_param_string(const struct cmlcms_color_transform_search_param *search_key);
struct cmlcms_color_profile *
ref_cprof(struct cmlcms_color_profile *cprof);
......@@ -217,6 +224,9 @@ cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm);
void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof);
char *
cmlcms_color_profile_print(const struct cmlcms_color_profile *cprof);
bool
retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
cmsHPROFILE hProfile,
......
......@@ -35,6 +35,7 @@
#include "color-lcms.h"
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
struct xyz_arr_flt {
float v[3];
......@@ -298,6 +299,17 @@ cmlcms_find_color_profile_by_md5(const struct weston_color_manager_lcms *cm,
return NULL;
}
char *
cmlcms_color_profile_print(const struct cmlcms_color_profile *cprof)
{
char *str;
str_printf(&str, " description: %s\n", cprof->base.description);
abort_oom_if_null(str);
return str;
}
static struct cmlcms_color_profile *
cmlcms_color_profile_create(struct weston_color_manager_lcms *cm,
cmsHPROFILE profile,
......@@ -305,6 +317,7 @@ cmlcms_color_profile_create(struct weston_color_manager_lcms *cm,
char **errmsg)
{
struct cmlcms_color_profile *cprof;
char *str;
cprof = zalloc(sizeof *cprof);
if (!cprof)
......@@ -316,17 +329,30 @@ cmlcms_color_profile_create(struct weston_color_manager_lcms *cm,
cmsGetHeaderProfileID(profile, cprof->md5sum.bytes);
wl_list_insert(&cm->color_profile_list, &cprof->link);
weston_log_scope_printf(cm->profiles_scope,
"New color profile: %p\n", cprof);
str = cmlcms_color_profile_print(cprof);
weston_log_scope_printf(cm->profiles_scope, "%s", str);
free(str);
return cprof;
}
void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cprof->base.cm);
wl_list_remove(&cprof->link);
cmsFreeToneCurveTriple(cprof->vcgt);
cmsFreeToneCurveTriple(cprof->eotf);
cmsFreeToneCurveTriple(cprof->output_inv_eotf_vcgt);
cmsCloseProfile(cprof->profile);
weston_log_scope_printf(cm->profiles_scope, "Destroyed color profile %p. " \
"Description: %s\n", cprof, cprof->base.description);
free(cprof->base.description);
free(cprof);
}
......@@ -364,7 +390,7 @@ make_icc_file_description(cmsHPROFILE profile,
"%02x", md5sum->bytes[i]);
}
str_printf(&desc, "ICCv%f %s %s", cmsGetProfileVersion(profile),
str_printf(&desc, "ICCv%.1f %s %s", cmsGetProfileVersion(profile),
name_part, md5sum_str);
return desc;
......
......@@ -33,6 +33,7 @@
#include "color.h"
#include "color-lcms.h"
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
/**
......@@ -163,6 +164,8 @@ cmlcms_fill_in_3dlut(struct weston_color_transform *xform_base,
void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform)
{
struct weston_color_manager_lcms *cm = get_cmlcms(xform->base.cm);
wl_list_remove(&xform->link);
cmsFreeToneCurveTriple(xform->pre_curve);
......@@ -177,6 +180,10 @@ cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform)
unref_cprof(xform->search_key.input_profile);
unref_cprof(xform->search_key.output_profile);
weston_log_scope_printf(cm->transforms_scope,
"Destroyed color transformation %p.\n", xform);
free(xform);
}
......@@ -591,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
......@@ -640,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.");
......@@ -664,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 = {
......@@ -791,11 +927,39 @@ failed:
return false;
}
char *
cmlcms_color_transform_search_param_string(const struct cmlcms_color_transform_search_param *search_key)
{
const char *input_prof_desc = "none", *output_prof_desc = "none";
char *str;
if (search_key->input_profile)
input_prof_desc = search_key->input_profile->base.description;
if (search_key->output_profile)
output_prof_desc = search_key->output_profile->base.description;
str_printf(&str, " catergory: %s\n" \
" input profile: %s\n" \
" output profile: %s\n" \
" selected intent from output profile: %u\n",
cmlcms_category_name(search_key->category),
input_prof_desc,
output_prof_desc,
search_key->intent_output);
abort_oom_if_null(str);
return str;
}
static struct cmlcms_color_transform *
cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
const struct cmlcms_color_transform_search_param *search_param)
{
struct cmlcms_color_transform *xform;
const char *err_msg;
char *str;
xform = xzalloc(sizeof *xform);
weston_color_transform_init(&xform->base, &cm->base);
......@@ -804,6 +968,12 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
xform->search_key.input_profile = ref_cprof(search_param->input_profile);
xform->search_key.output_profile = ref_cprof(search_param->output_profile);
weston_log_scope_printf(cm->transforms_scope,
"New color transformation: %p\n", xform);
str = cmlcms_color_transform_search_param_string(&xform->search_key);
weston_log_scope_printf(cm->transforms_scope, "%s", str);
free(str);
/* Ensure the linearization etc. have been extracted. */
if (!search_param->output_profile->eotf[0]) {
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
......@@ -811,8 +981,10 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
search_param->output_profile->eotf,
search_param->output_profile->output_inv_eotf_vcgt,
search_param->output_profile->vcgt,
cmlcms_reasonable_1D_points()))
cmlcms_reasonable_1D_points())) {
err_msg = "retrieve_eotf_and_output_inv_eotf failed";
goto error;
}
}
/*
......@@ -823,8 +995,10 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
switch (search_param->category) {
case CMLCMS_CATEGORY_INPUT_TO_BLEND:
case CMLCMS_CATEGORY_INPUT_TO_OUTPUT:
if (!xform_realize_chain(xform))
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;
......@@ -837,11 +1011,17 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
wl_list_insert(&cm->color_transform_list, &xform->link);
assert(xform->status != CMLCMS_TRANSFORM_FAILED);
str = weston_color_transform_string(&xform->base);
weston_log_scope_printf(cm->transforms_scope, " %s", str);
free(str);
return xform;
error:
weston_log_scope_printf(cm->transforms_scope,
" %s\n", err_msg);
cmlcms_color_transform_destroy(xform);
weston_log("CM cmlcms_color_transform_create failed\n");
return NULL;
}
......
......@@ -38,6 +38,8 @@
#include "color.h"
#include "libweston-internal.h"
#include <libweston/weston-log.h>
#include "shared/xalloc.h"
/**
* Increase reference count of the color profile object
......@@ -165,6 +167,87 @@ weston_color_transform_init(struct weston_color_transform *xform,
wl_signal_init(&xform->destroy_signal);
}
static const char *
curve_type_to_str(enum weston_color_curve_type curve_type)
{
switch (curve_type) {
case WESTON_COLOR_CURVE_TYPE_IDENTITY:
return "identity";
case WESTON_COLOR_CURVE_TYPE_LUT_3x1D:
return "3x1D LUT";
}
return "???";
}
static const char *
mapping_type_to_str(enum weston_color_mapping_type mapping_type)
{
switch (mapping_type) {
case WESTON_COLOR_MAPPING_TYPE_IDENTITY:
return "identity";
case WESTON_COLOR_MAPPING_TYPE_3D_LUT:
return "3D LUT";
case WESTON_COLOR_MAPPING_TYPE_MATRIX:
return "matrix";
}
return "???";
}
/**
* Print the color transform pipeline to a string
*
* \param xform The color transform.
* \return The string in which the pipeline is printed.
*/
WL_EXPORT char *
weston_color_transform_string(const struct weston_color_transform *xform)
{
enum weston_color_mapping_type mapping_type = xform->mapping.type;
enum weston_color_curve_type pre_type = xform->pre_curve.type;
enum weston_color_curve_type post_type = xform->post_curve.type;
const char *empty = "";
const char *sep = empty;
FILE *fp;
char *str = NULL;
size_t size = 0;
fp = open_memstream(&str, &size);
abort_oom_if_null(fp);
fprintf(fp, "pipeline: ");
if (pre_type != WESTON_COLOR_CURVE_TYPE_IDENTITY) {
fprintf(fp, "%spre %s", sep, curve_type_to_str(pre_type));
if (pre_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D)
fprintf(fp, " [%u]", xform->pre_curve.u.lut_3x1d.optimal_len);
sep = ", ";
}
if (mapping_type != WESTON_COLOR_MAPPING_TYPE_IDENTITY) {
fprintf(fp, "%smapping %s", sep, mapping_type_to_str(mapping_type));
if (mapping_type == WESTON_COLOR_MAPPING_TYPE_3D_LUT)
fprintf(fp, " [%u]", xform->mapping.u.lut3d.optimal_len);
sep = ", ";
}
if (post_type != WESTON_COLOR_CURVE_TYPE_IDENTITY) {
fprintf(fp, "%spost %s", sep, curve_type_to_str(post_type));
if (post_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D)
fprintf(fp, " [%u]", xform->post_curve.u.lut_3x1d.optimal_len);
sep = ", ";
}
if (sep == empty)
fprintf(fp, "identity\n");
else
fprintf(fp, "\n");
fclose(fp);
abort_oom_if_null(str);
return str;
}
/** Deep copy */
void
weston_surface_color_transform_copy(struct weston_surface_color_transform *dst,
......
......@@ -337,6 +337,9 @@ void
weston_color_transform_init(struct weston_color_transform *xform,
struct weston_color_manager *cm);
char *
weston_color_transform_string(const struct weston_color_transform *xform);
void
weston_surface_color_transform_copy(struct weston_surface_color_transform *dst,
const struct weston_surface_color_transform *src);
......
......@@ -443,6 +443,7 @@ fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
setup.width = WINDOW_WIDTH;
setup.height = WINDOW_HEIGHT;
setup.shell = SHELL_TEST_DESKTOP;
setup.logging_scopes = "log,color-lcms-profiles,color-lcms-transformations,color-lcms-optimizer";
file_name = build_output_icc_profile(arg);
if (!file_name)
......