diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c index efb44d978..e7cff9475 100644 --- a/libweston/color-lcms/color-lcms.c +++ b/libweston/color-lcms/color-lcms.c @@ -1,5 +1,6 @@ /* * Copyright 2021 Collabora, Ltd. + * Copyright 2021 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,8 +26,7 @@ #include "config.h" -#include - +#include #include #include "color.h" @@ -36,6 +36,9 @@ static void cmlcms_destroy_color_transform(struct weston_color_transform *xform_base) { + struct cmlcms_color_transform *xform = get_xform(xform_base); + + cmlcms_color_transform_destroy(xform); } static bool @@ -44,8 +47,21 @@ cmlcms_get_surface_color_transform(struct weston_color_manager *cm_base, struct weston_output *output, struct weston_surface_color_transform *surf_xform) { - /* Identity transform */ - surf_xform->transform = NULL; + struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); + struct cmlcms_color_transform_search_param param = { + /* + * Assumes both content and output color spaces are sRGB SDR. + * This defines the blending space as optical sRGB SDR. + */ + .type = CMLCMS_TYPE_EOTF_sRGB, + }; + struct cmlcms_color_transform *xform; + + xform = cmlcms_color_transform_get(cm, ¶m); + if (!xform) + return false; + + surf_xform->transform = &xform->base; surf_xform->identity_pipeline = true; return true; @@ -56,9 +72,21 @@ cmlcms_get_output_color_transform(struct weston_color_manager *cm_base, struct weston_output *output, struct weston_color_transform **xform_out) { - /* Identity transform */ - *xform_out = NULL; + struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); + struct cmlcms_color_transform_search_param param = { + /* + * Assumes blending space is optical sRGB SDR and + * output color space is sRGB SDR. + */ + .type = CMLCMS_TYPE_EOTF_sRGB_INV, + }; + struct cmlcms_color_transform *xform; + xform = cmlcms_color_transform_get(cm, ¶m); + if (!xform) + return false; + + *xform_out = &xform->base; return true; } @@ -67,6 +95,7 @@ cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base, struct weston_output *output, struct weston_color_transform **xform_out) { + /* Assumes output color space is sRGB SDR */ /* Identity transform */ *xform_out = NULL; @@ -78,29 +107,61 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base, struct weston_output *output, struct weston_color_transform **xform_out) { - /* Identity transform */ - *xform_out = NULL; + struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); + struct cmlcms_color_transform_search_param param = { + /* Assumes blending space is optical sRGB SDR */ + .type = CMLCMS_TYPE_EOTF_sRGB, + }; + struct cmlcms_color_transform *xform; + xform = cmlcms_color_transform_get(cm, ¶m); + if (!xform) + return false; + + *xform_out = &xform->base; return true; } +static void +lcms_error_logger(cmsContext context_id, + cmsUInt32Number error_code, + const char *text) +{ + weston_log("LittleCMS error: %s\n", text); +} + static bool cmlcms_init(struct weston_color_manager *cm_base) { - if (!(cm_base->compositor->capabilities & WESTON_CAP_COLOR_OPS)) { + struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); + + if (!(cm->base.compositor->capabilities & WESTON_CAP_COLOR_OPS)) { weston_log("color-lcms: error: color operations capability missing. Is GL-renderer not in use?\n"); return false; } + cm->lcms_ctx = cmsCreateContext(NULL, cm); + if (!cm->lcms_ctx) { + weston_log("color-lcms error: creating LittCMS context failed.\n"); + return false; + } + + cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger); + + weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion()); + return true; } static void cmlcms_destroy(struct weston_color_manager *cm_base) { - struct weston_color_manager_lcms *cmlcms = get_cmlcms(cm_base); + struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); - free(cmlcms); + assert(wl_list_empty(&cm->color_transform_list)); + + cmsDeleteContext(cm->lcms_ctx); + free(cm); } WL_EXPORT struct weston_color_manager * @@ -126,5 +187,7 @@ weston_color_manager_create(struct weston_compositor *compositor) cm->base.get_sRGB_to_blend_color_transform = cmlcms_get_sRGB_to_blend_color_transform; + wl_list_init(&cm->color_transform_list); + return &cm->base; } diff --git a/libweston/color-lcms/color-lcms.h b/libweston/color-lcms/color-lcms.h index 584557c02..0458d31a2 100644 --- a/libweston/color-lcms/color-lcms.h +++ b/libweston/color-lcms/color-lcms.h @@ -1,5 +1,6 @@ /* * Copyright 2021 Collabora, Ltd. + * Copyright 2021 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -26,6 +27,7 @@ #ifndef WESTON_COLOR_LCMS_H #define WESTON_COLOR_LCMS_H +#include #include #include "color.h" @@ -33,6 +35,9 @@ struct weston_color_manager_lcms { struct weston_color_manager base; + cmsContext lcms_ctx; + + struct wl_list color_transform_list; /* cmlcms_color_transform::link */ }; static inline struct weston_color_manager_lcms * @@ -41,4 +46,43 @@ get_cmlcms(struct weston_color_manager *cm_base) return container_of(cm_base, struct weston_color_manager_lcms, base); } +/* + * Perhaps a placeholder, until we get actual color spaces involved and + * see how this would work better. + */ +enum cmlcms_color_transform_type { + CMLCMS_TYPE_EOTF_sRGB = 0, + CMLCMS_TYPE_EOTF_sRGB_INV, + CMLCMS_TYPE__END, +}; + +struct cmlcms_color_transform_search_param { + enum cmlcms_color_transform_type type; +}; + +struct cmlcms_color_transform { + struct weston_color_transform base; + + /* weston_color_manager_lcms::color_transform_list */ + struct wl_list link; + + struct cmlcms_color_transform_search_param search_key; + + /* for EOTF types */ + cmsToneCurve *curve; +}; + +static inline struct cmlcms_color_transform * +get_xform(struct weston_color_transform *xform_base) +{ + return container_of(xform_base, struct cmlcms_color_transform, base); +} + +struct cmlcms_color_transform * +cmlcms_color_transform_get(struct weston_color_manager_lcms *cm, + const struct cmlcms_color_transform_search_param *param); + +void +cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform); + #endif /* WESTON_COLOR_LCMS_H */ diff --git a/libweston/color-lcms/color-transform.c b/libweston/color-lcms/color-transform.c new file mode 100644 index 000000000..713be1899 --- /dev/null +++ b/libweston/color-lcms/color-transform.c @@ -0,0 +1,157 @@ +/* + * Copyright 2021 Collabora, Ltd. + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#include +#include + +#include "color.h" +#include "color-lcms.h" +#include "shared/helpers.h" + +/* Arguments to cmsBuildParametricToneCurve() */ +struct tone_curve_def { + cmsInt32Number cmstype; + cmsFloat64Number params[5]; +}; + +/* + * LCMS uses the required number of 'params' based on 'cmstype', the parametric + * tone curve number. LCMS honors negative 'cmstype' as inverse function. + * These are LCMS built-in parametric tone curves. + */ +static const struct tone_curve_def predefined_eotf_curves[] = { + [CMLCMS_TYPE_EOTF_sRGB] = { + .cmstype = 4, + .params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 }, + }, + [CMLCMS_TYPE_EOTF_sRGB_INV] = { + .cmstype = -4, + .params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 }, + }, +}; + +static void +cmlcms_fill_in_tone_curve(struct weston_color_transform *xform_base, + float *values, unsigned len) +{ + struct cmlcms_color_transform *xform = get_xform(xform_base); + float *R_lut = values; + float *G_lut = R_lut + len; + float *B_lut = G_lut + len; + unsigned i; + cmsFloat32Number x, y; + + assert(xform->curve != NULL); + assert(len > 1); + + for (i = 0; i < len; i++) { + x = (double)i / (len - 1); + y = cmsEvalToneCurveFloat(xform->curve, x); + R_lut[i] = y; + G_lut[i] = y; + B_lut[i] = y; + } +} + +void +cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform) +{ + wl_list_remove(&xform->link); + if (xform->curve) + cmsFreeToneCurve(xform->curve); + free(xform); +} + +static struct cmlcms_color_transform * +cmlcms_color_transform_create(struct weston_color_manager_lcms *cm, + const struct cmlcms_color_transform_search_param *param) +{ + struct cmlcms_color_transform *xform; + const struct tone_curve_def *tonedef; + + if (param->type < 0 || param->type >= CMLCMS_TYPE__END) { + weston_log("color-lcms error: bad color transform type in %s.\n", + __func__); + return NULL; + } + tonedef = &predefined_eotf_curves[param->type]; + + xform = zalloc(sizeof *xform); + if (!xform) + return NULL; + + xform->curve = cmsBuildParametricToneCurve(cm->lcms_ctx, + tonedef->cmstype, + tonedef->params); + if (xform->curve == NULL) { + weston_log("color-lcms error: failed to build parametric tone curve.\n"); + free(xform); + return NULL; + } + + weston_color_transform_init(&xform->base, &cm->base); + xform->search_key = *param; + + xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D; + xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_tone_curve; + xform->base.pre_curve.u.lut_3x1d.optimal_len = 256; + + wl_list_insert(&cm->color_transform_list, &xform->link); + + return xform; +} + +static bool +transform_matches_params(const struct cmlcms_color_transform *xform, + const struct cmlcms_color_transform_search_param *param) +{ + if (xform->search_key.type != param->type) + return false; + + return true; +} + +struct cmlcms_color_transform * +cmlcms_color_transform_get(struct weston_color_manager_lcms *cm, + const struct cmlcms_color_transform_search_param *param) +{ + struct cmlcms_color_transform *xform; + + wl_list_for_each(xform, &cm->color_transform_list, link) { + if (transform_matches_params(xform, param)) { + weston_color_transform_ref(&xform->base); + return xform; + } + } + + xform = cmlcms_color_transform_create(cm, param); + if (!xform) + weston_log("color-lcms error: failed to create a color transformation.\n"); + + return xform; +} diff --git a/libweston/color-lcms/meson.build b/libweston/color-lcms/meson.build index c1b8ae91b..1f11013f8 100644 --- a/libweston/color-lcms/meson.build +++ b/libweston/color-lcms/meson.build @@ -9,6 +9,7 @@ endif srcs_color_lcms = [ 'color-lcms.c', + 'color-transform.c', ] deps_color_lcms = [