From fbb7b8307dc1e110cc8104b03c04cb9ed5d21d14 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 17 Jun 2025 11:17:23 +0300 Subject: [PATCH 01/10] color-lcms: move code into cmlcms_send_icc_info() Pure refactoring to clean up cmlcms_send_image_desc_info() ahead of implementing generic parametric information sending. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-profile.c | 45 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/libweston/color-lcms/color-profile.c b/libweston/color-lcms/color-profile.c index c5751ba85..7e01621d9 100644 --- a/libweston/color-lcms/color-profile.c +++ b/libweston/color-lcms/color-profile.c @@ -719,6 +719,32 @@ cmlcms_get_color_profile_from_params(struct weston_color_manager *cm_base, return true; } +static bool +cmlcms_send_icc_info(struct cm_image_desc_info *cm_image_desc_info, + const struct cmlcms_color_profile *cprof) +{ + int32_t fd; + uint32_t len; + + /* ICC-based color profile, so just send the ICC file fd. If we + * get an error (negative fd), the helper will send the proper + * error to the client. */ + fd = os_ro_anonymous_file_get_fd(cprof->icc.prof_rofile, + RO_ANONYMOUS_FILE_MAPMODE_PRIVATE); + if (fd < 0) { + weston_cm_send_icc_file(cm_image_desc_info, -1, 0); + return false; + } + + len = os_ro_anonymous_file_size(cprof->icc.prof_rofile); + weston_assert_u32_gt(cprof->base.cm->compositor, len, 0); + + weston_cm_send_icc_file(cm_image_desc_info, fd, len); + + os_ro_anonymous_file_put_fd(fd); + return true; +} + bool cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, struct weston_color_profile *cprof_base) @@ -728,8 +754,6 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, struct cmlcms_color_profile *cprof = to_cmlcms_cprof(cprof_base); const struct weston_color_primaries_info *primaries_info; const struct weston_color_tf_info *tf_info; - int32_t fd; - uint32_t len; /** * TODO: when we convert the stock sRGB profile to a parametric profile @@ -738,22 +762,7 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, */ if (cprof->type == CMLCMS_PROFILE_TYPE_ICC && cprof != cm->sRGB_profile) { - /* ICC-based color profile, so just send the ICC file fd. If we - * get an error (negative fd), the helper will send the proper - * error to the client. */ - fd = os_ro_anonymous_file_get_fd(cprof->icc.prof_rofile, - RO_ANONYMOUS_FILE_MAPMODE_PRIVATE); - if (fd < 0) { - weston_cm_send_icc_file(cm_image_desc_info, -1, 0); - return false; - } - - len = os_ro_anonymous_file_size(cprof->icc.prof_rofile); - weston_assert_u32_gt(compositor, len, 0); - - weston_cm_send_icc_file(cm_image_desc_info, fd, len); - - os_ro_anonymous_file_put_fd(fd); + return cmlcms_send_icc_info(cm_image_desc_info, cprof); } else { /* TODO: we still don't support parametric color profiles that * are not the stock one. This should change when we start From 7c4df878ebc6a07eb988a764c2bc791f11b119fc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 17 Jun 2025 14:22:45 +0300 Subject: [PATCH 02/10] color: weston_cm_send_tf() handles power-law The power-law TF uses a different protocol event than others. Adding support for it requires passing in the parameters. Now we have a single send function that handles all protocol TFs, not just those without parameters. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-profile.c | 8 ++++--- libweston/color-management.c | 31 ++++++++++++++++++++++------ libweston/color-management.h | 4 ++-- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/libweston/color-lcms/color-profile.c b/libweston/color-lcms/color-profile.c index 7e01621d9..e742ebcdb 100644 --- a/libweston/color-lcms/color-profile.c +++ b/libweston/color-lcms/color-profile.c @@ -753,7 +753,6 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, struct weston_compositor *compositor = cm->base.compositor; struct cmlcms_color_profile *cprof = to_cmlcms_cprof(cprof_base); const struct weston_color_primaries_info *primaries_info; - const struct weston_color_tf_info *tf_info; /** * TODO: when we convert the stock sRGB profile to a parametric profile @@ -795,8 +794,11 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, &primaries_info->color_gamut); /* sRGB transfer function. */ - tf_info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22); - weston_cm_send_tf_named(cm_image_desc_info, tf_info); + struct weston_color_tf tf = { + .info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22), + .params = {}, + }; + weston_cm_send_tf(cm_image_desc_info, &tf); /* Primary luminance, default values from the protocol. */ weston_cm_send_luminances(cm_image_desc_info, 0.2, 80.0, 80.0); diff --git a/libweston/color-management.c b/libweston/color-management.c index 10cf7a305..79572cc1d 100644 --- a/libweston/color-management.c +++ b/libweston/color-management.c @@ -209,15 +209,34 @@ weston_cm_send_target_primaries(struct cm_image_desc_info *cm_image_desc_info, * This is a helper function that should be used by the color plugin * that owns the color profile and has information about it. * - * \param cm_image_desc_info The image description info object - * \param tf_info The tf_info object + * \param cm_image_desc_info The image description info object. + * \param tf The color transfer function to send. */ WL_EXPORT void -weston_cm_send_tf_named(struct cm_image_desc_info *cm_image_desc_info, - const struct weston_color_tf_info *tf_info) +weston_cm_send_tf(struct cm_image_desc_info *cm_image_desc_info, + const struct weston_color_tf *tf) { - wp_image_description_info_v1_send_tf_named(cm_image_desc_info->owner, - tf_info->protocol_tf); + switch (tf->info->tf) { + case WESTON_TF_BT1886: + case WESTON_TF_GAMMA22: + case WESTON_TF_GAMMA28: + case WESTON_TF_SRGB: + case WESTON_TF_EXT_SRGB: + case WESTON_TF_ST240: + case WESTON_TF_ST428: + case WESTON_TF_ST2084_PQ: + case WESTON_TF_EXT_LINEAR: + case WESTON_TF_LOG_100: + case WESTON_TF_LOG_316: + case WESTON_TF_XVYCC: + case WESTON_TF_HLG: + wp_image_description_info_v1_send_tf_named(cm_image_desc_info->owner, + tf->info->protocol_tf); + break; + case WESTON_TF_POWER: + wp_image_description_info_v1_send_tf_power(cm_image_desc_info->owner, + tf->params[0]); + } } /** diff --git a/libweston/color-management.h b/libweston/color-management.h index 5ae38198e..0086e1207 100644 --- a/libweston/color-management.h +++ b/libweston/color-management.h @@ -56,8 +56,8 @@ weston_cm_send_target_primaries(struct cm_image_desc_info *cm_image_desc_info, const struct weston_color_gamut *color_gamut); void -weston_cm_send_tf_named(struct cm_image_desc_info *cm_image_desc_info, - const struct weston_color_tf_info *tf_info); +weston_cm_send_tf(struct cm_image_desc_info *cm_image_desc_info, + const struct weston_color_tf *tf); void weston_cm_send_luminances(struct cm_image_desc_info *cm_image_desc_info, From 720f69c44d230a915d6674226cadd5c10aa953bc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 17 Jun 2025 14:43:04 +0300 Subject: [PATCH 03/10] color: add weston_cm_send_parametric_info() Implementation of sending the protocol info events for an arbitrary parametric image description. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-profile.c | 11 ++++------ libweston/color-management.c | 31 ++++++++++++++++++++++++++++ libweston/color-management.h | 4 ++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/libweston/color-lcms/color-profile.c b/libweston/color-lcms/color-profile.c index e742ebcdb..01c0d032e 100644 --- a/libweston/color-lcms/color-profile.c +++ b/libweston/color-lcms/color-profile.c @@ -763,13 +763,10 @@ cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, if (cprof->type == CMLCMS_PROFILE_TYPE_ICC && cprof != cm->sRGB_profile) { return cmlcms_send_icc_info(cm_image_desc_info, cprof); } else { - /* TODO: we still don't support parametric color profiles that - * are not the stock one. This should change when we start - * advertising parametric image description support in our - * color-management protocol implementation. */ - if (cprof != cm->sRGB_profile) - weston_assert_not_reached(compositor, "we don't support parametric " \ - "cprof's that are not the stock sRGB one"); + if (cprof != cm->sRGB_profile) { + weston_cm_send_parametric_info(cm_image_desc_info, cprof->params); + return true; + } /* Stock sRGB color profile. TODO: when we add support for * parametric color profiles, the stock sRGB will be crafted diff --git a/libweston/color-management.c b/libweston/color-management.c index 79572cc1d..fbf59caee 100644 --- a/libweston/color-management.c +++ b/libweston/color-management.c @@ -280,6 +280,37 @@ weston_cm_send_target_luminances(struct cm_image_desc_info *cm_image_desc_info, max_lum); } +/** + * Send complete parametric image description information to the client. + */ +WL_EXPORT void +weston_cm_send_parametric_info(struct cm_image_desc_info *cm_image_desc_info, + const struct weston_color_profile_params *par) +{ + if (par->primaries_info) + weston_cm_send_primaries_named(cm_image_desc_info, par->primaries_info); + weston_cm_send_primaries(cm_image_desc_info, &par->primaries); + weston_cm_send_target_primaries(cm_image_desc_info, &par->target_primaries); + + weston_cm_send_tf(cm_image_desc_info, &par->tf); + + weston_cm_send_luminances(cm_image_desc_info, par->min_luminance, + par->max_luminance, par->reference_white_luminance); + weston_cm_send_target_luminances(cm_image_desc_info, + par->target_min_luminance, + par->target_max_luminance); + + if (par->maxCLL > 0.0f) { + wp_image_description_info_v1_send_target_max_cll(cm_image_desc_info->owner, + par->maxCLL); + } + + if (par->maxFALL > 0.0f) { + wp_image_description_info_v1_send_target_max_fall(cm_image_desc_info->owner, + par->maxFALL); + } +} + /** * Destroy an image description info object. */ diff --git a/libweston/color-management.h b/libweston/color-management.h index 0086e1207..d83ed39c4 100644 --- a/libweston/color-management.h +++ b/libweston/color-management.h @@ -67,4 +67,8 @@ void weston_cm_send_target_luminances(struct cm_image_desc_info *cm_image_desc_info, float min_lum, float max_lum); +void +weston_cm_send_parametric_info(struct cm_image_desc_info *cm_image_desc_info, + const struct weston_color_profile_params *par); + #endif /* WESTON_COLOR_MANAGEMENT_H */ From cca907c1d4b37673aa5f70a0fe6efa0bca1b7c9d Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 19 Jun 2025 13:28:46 +0300 Subject: [PATCH 04/10] color-lcms: refactor into get_defining_curve_segment() I need the new function for another purpose later, and this makes get_parametric_curveset_params() easier to read. Pure refactoring: no change in behavior. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-curve-segments.c | 91 ++++++++++++--------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/libweston/color-lcms/color-curve-segments.c b/libweston/color-lcms/color-curve-segments.c index 14f61dcd3..c879eebbf 100644 --- a/libweston/color-lcms/color-curve-segments.c +++ b/libweston/color-lcms/color-curve-segments.c @@ -531,7 +531,7 @@ join_powerlaw_curvesets(cmsContext context_id, ret = cmsStageAllocToneCurves(context_id, ARRAY_LENGTH(arr), arr); abort_oom_if_null(ret); cmsFreeToneCurveTriple(arr); - return ret; + return ret; } void @@ -573,6 +573,47 @@ curveset_print(cmsStage *stage, struct weston_log_scope *scope) } } +static const cmsCurveSegment * +get_defining_curve_segment(cmsToneCurve *from, bool *clamped_input) +{ + const cmsCurveSegment *seg0, *seg1, *seg2; + + /* We handle curves with 1 or 3 segments. No more, no less. */ + seg0 = cmsGetToneCurveSegment(0, from); + seg1 = cmsGetToneCurveSegment(1, from); + seg2 = cmsGetToneCurveSegment(2, from); + if (seg0 && !seg1) { + /* Case 1: we have a single segment (seg0). + * + * Ensure that the domain is (-inf, inf). + */ + if (!are_segment_breaks_equal(seg0->x0, -INFINITY) || + !are_segment_breaks_equal(seg0->x1, INFINITY)) + return NULL; + *clamped_input = false; + return seg0; + } else if (seg0 && seg1 && seg2) { + /* Case 2: we have three segments. Clamped input. + * + * Ensure that the domain breaks are (-inf, 0.0], + * (0.0, 1.0] and (1.0, inf]. + */ + if (!are_segment_breaks_equal(seg0->x0, -INFINITY) || + !are_segment_breaks_equal(seg0->x1, 0.0) || + !are_segment_breaks_equal(seg1->x0, 0.0) || + !are_segment_breaks_equal(seg1->x1, 1.0) || + !are_segment_breaks_equal(seg2->x0, 1.0) || + !are_segment_breaks_equal(seg2->x1, INFINITY)) + return NULL; + *clamped_input = true; + return seg1; + } else { + /* Neither 1 or 3 segments. So we don't define the + * curveset as parametric. */ + return NULL; + } +} + bool get_parametric_curveset_params(struct weston_compositor *compositor, _cmsStageToneCurvesData *trc_data, @@ -580,7 +621,7 @@ get_parametric_curveset_params(struct weston_compositor *compositor, float curveset_params[3][MAX_PARAMS_LCMS_PARAM_CURVE], bool *clamped_input) { - const cmsCurveSegment *seg, *seg0, *seg1, *seg2; + const cmsCurveSegment *seg; cmsInt32Number curve_types[3]; unsigned int i, j; @@ -596,44 +637,18 @@ get_parametric_curveset_params(struct weston_compositor *compositor, *clamped_input = false; for (i = 0; i < 3; i++) { - /* We handle curves with 1 or 3 segments. No more, no less. */ - seg0 = cmsGetToneCurveSegment(0, trc_data->TheCurves[i]); - seg1 = cmsGetToneCurveSegment(1, trc_data->TheCurves[i]); - seg2 = cmsGetToneCurveSegment(2, trc_data->TheCurves[i]); + bool clamp_this; - if (seg0 && !seg1) { - /* Case 1: we have a single segment (seg0). - * - * Ensure that the domain is (-inf, inf) and that the - * seg type is not 0 (the type of sampled segments). - */ - if (!are_segment_breaks_equal(seg0->x0, -INFINITY) || - !are_segment_breaks_equal(seg0->x1, INFINITY) || - seg0->Type == 0) - return false; - seg = seg0; - } else if (seg0 && seg1 && seg2) { - /* Case 2: we have three segments. Clamped input. - * - * Ensure that the domain breaks are (-inf, 0.0], - * (0.0, 1.0] and (1.0, inf] and that the 2nd segment - * type is not 0 (the type of sampled segments). - */ - if (!are_segment_breaks_equal(seg0->x0, -INFINITY) || - !are_segment_breaks_equal(seg0->x1, 0.0) || - !are_segment_breaks_equal(seg1->x0, 0.0) || - !are_segment_breaks_equal(seg1->x1, 1.0) || - !are_segment_breaks_equal(seg2->x0, 1.0) || - !are_segment_breaks_equal(seg2->x1, INFINITY) || - seg1->Type == 0) - return false; - seg = seg1; - *clamped_input = true; - } else { - /* Neither 1 or 3 segments. So we don't define the - * curveset as parametric. */ + seg = get_defining_curve_segment(trc_data->TheCurves[i], &clamp_this); + if (!seg) return false; - } + + /* Reject tabulated (LUT) segments. */ + if (seg->Type == 0) + return false; + + if (clamp_this) + *clamped_input = true; /* Copy the type and params from the segment that matters. We * don't use memcpy because we need to cast each cmsFloat64Number From 35631907242d0c0a4a270c7cff20d6d5c10d9df1 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 19 Jun 2025 13:35:50 +0300 Subject: [PATCH 05/10] color-lcms: recognize single bounded curve segment I don't have a specific use case in my mind for this, but it is something we can easily handle. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-curve-segments.c | 27 ++++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/libweston/color-lcms/color-curve-segments.c b/libweston/color-lcms/color-curve-segments.c index c879eebbf..51aae583e 100644 --- a/libweston/color-lcms/color-curve-segments.c +++ b/libweston/color-lcms/color-curve-segments.c @@ -583,15 +583,24 @@ get_defining_curve_segment(cmsToneCurve *from, bool *clamped_input) seg1 = cmsGetToneCurveSegment(1, from); seg2 = cmsGetToneCurveSegment(2, from); if (seg0 && !seg1) { - /* Case 1: we have a single segment (seg0). - * - * Ensure that the domain is (-inf, inf). - */ - if (!are_segment_breaks_equal(seg0->x0, -INFINITY) || - !are_segment_breaks_equal(seg0->x1, INFINITY)) - return NULL; - *clamped_input = false; - return seg0; + /* Case 1: we have a single segment (seg0). */ + + /* If the domain is (-inf, inf), the curve is unbounded. */ + if (are_segment_breaks_equal(seg0->x0, -INFINITY) && + are_segment_breaks_equal(seg0->x1, INFINITY)) { + *clamped_input = false; + return seg0; + } + + /* If the domain is [0.0, 1.0], the curve is bounded. */ + if (are_segment_breaks_equal(seg0->x0, 0.0) && + are_segment_breaks_equal(seg0->x1, 1.0)) { + *clamped_input = true; + return seg0; + } + + /* We don't handle anything else. */ + return NULL; } else if (seg0 && seg1 && seg2) { /* Case 2: we have three segments. Clamped input. * From 55b0d471abde6ebcea6d2dbd68062037b0918f06 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 19 Jun 2025 14:15:41 +0300 Subject: [PATCH 06/10] color-lcms: optimize linear TRCs The icc<->parametric color transformation code uses "optical ICC profiles" as part of the ICC pipeline. These profiles use a linear TRC to encode the black point. When such TRC survives all optimizations, it will cause the 3D LUT fallback path to be taken. Detect such curve sets on the ICC pipeline optimizer, and convert them to matrix stages. The matrix stages will then be optimized as usual, often eliminating the stage completely. The results can be seen in color-icc-output test after the stock sRGB profile has been changed into a parametric one, causing all cases in the test to hit the parametric-to-icc path. Some tests fail when they suddenly start using the 3D LUT path which causes the errors to rise. This patch fixes those (future) cases, and the errors remain the same as before changing the stock profile. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-curve-segments.c | 55 +++++++++++++++++++++ libweston/color-lcms/color-curve-segments.h | 9 ++++ libweston/color-lcms/color-transform.c | 26 ++++++++++ 3 files changed, 90 insertions(+) diff --git a/libweston/color-lcms/color-curve-segments.c b/libweston/color-lcms/color-curve-segments.c index 51aae583e..95e30f6ed 100644 --- a/libweston/color-lcms/color-curve-segments.c +++ b/libweston/color-lcms/color-curve-segments.c @@ -676,3 +676,58 @@ get_parametric_curveset_params(struct weston_compositor *compositor, return true; } + +/** Create a matrix stage equivalent to the CurveSet stage. + * + * A tabulated curve segment with 2 samples is equivalent to a matrix + * (scaling and offset), ignoring possible input clamping and allowing + * extrapolation. + * + * \param context_id The matrix stage is created in this context. + * \param stage An arbitrary stage, can be NULL. + * \return A new matrix stage equivalent to the given (CurveSet) stage, or + * NULL otherwise. + */ +cmsStage * +lcms_matrix_stage_from_curve(cmsContext context_id, cmsStage *stage) +{ + const _cmsStageToneCurvesData *data; + cmsFloat64Number Matrix[3 * 3] = {}; /* row-major */ + cmsFloat64Number Offset[3]; + unsigned i; + + if (!stage || cmsStageType(stage) != cmsSigCurveSetElemType) + return NULL; + + data = cmsStageData(stage); + if (data->nCurves != 3) + return NULL; + + for (i = 0; i < 3; i++) { + const cmsCurveSegment *seg; + bool clamped_input; + double y0, y1, k; + + seg = get_defining_curve_segment(data->TheCurves[i], &clamped_input); + if (!seg) + return NULL; + + /* Type 0 is tabulated. */ + if (seg->Type != 0) + return NULL; + + if (seg->nGridPoints != 2) + return NULL; + + y0 = seg->SampledPoints[0]; + y1 = seg->SampledPoints[1]; + + /* y = k * x + Offset */ + + k = (y1 - y0) / (seg->x1 - seg->x0); + Offset[i] = y0 - k * seg->x0; + Matrix[3 * i + i] = k; + } + + return cmsStageAllocMatrix(context_id, 3, 3, Matrix, Offset); +} diff --git a/libweston/color-lcms/color-curve-segments.h b/libweston/color-lcms/color-curve-segments.h index adb20dab4..b761a3264 100644 --- a/libweston/color-lcms/color-curve-segments.h +++ b/libweston/color-lcms/color-curve-segments.h @@ -39,6 +39,9 @@ get_parametric_curveset_params(struct weston_compositor *compositor, float curveset_params[3][MAX_PARAMS_LCMS_PARAM_CURVE], bool *clamped_input); +cmsStage * +lcms_matrix_stage_from_curve(cmsContext context_id, cmsStage *stage); + void curveset_print(cmsStage *stage, struct weston_log_scope *scope); @@ -64,6 +67,12 @@ get_parametric_curveset_params(struct weston_compositor *compositor, return false; } +cmsStage * +lcms_matrix_stage_from_curve(cmsContext ContextID, cmsStage *stage) +{ + return NULL; +} + static inline void curveset_print(cmsStage *stage, struct weston_log_scope *scope) { diff --git a/libweston/color-lcms/color-transform.c b/libweston/color-lcms/color-transform.c index 6f4ba3b8c..d3c20c048 100644 --- a/libweston/color-lcms/color-transform.c +++ b/libweston/color-lcms/color-transform.c @@ -387,6 +387,30 @@ merge_curvesets(cmsPipeline **lut, cmsContext context_id) return modified; } +static void +linear_curvesets_to_matrices(cmsPipeline **lut, cmsContext context_id) +{ + cmsPipeline *pipe; + cmsStage *elem; + cmsStage *matrix; + + pipe = cmsPipelineAlloc(context_id, 3, 3); + abort_oom_if_null(pipe); + + elem = cmsPipelineGetPtrToFirstStage(*lut); + for (; elem; elem = cmsStageNext(elem)) { + matrix = lcms_matrix_stage_from_curve(context_id, elem); + if (matrix) { + cmsPipelineInsertStage(pipe, cmsAT_END, matrix); + } else { + cmsPipelineInsertStage(pipe, cmsAT_END, cmsStageDup(elem)); + } + } + + cmsPipelineFree(*lut); + *lut = pipe; +} + static const struct weston_color_tf_info * lcms_curve_matches_any_tf(struct weston_compositor *compositor, uint32_t lcms_curve_type, bool clamped_input, @@ -1013,6 +1037,8 @@ lcms_optimize_pipeline(cmsPipeline **lut, cmsContext context_id) { bool cont_opt; + linear_curvesets_to_matrices(lut, context_id); + /** * This optimization loop will delete identity stages. Deleting * identity matrix stages is harmless, but deleting identity From 8e7f8125709bd91db40950ea9ceda702299652be Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 16 Jun 2025 15:49:56 +0300 Subject: [PATCH 07/10] color-lcms: switch default sRGB profile to parametric This avoids ICC paths when no ICC profiles are explicitly used. We can simplify the profile information sending and use the generic path for the stock profile as well, no longer hard-coding the stock profile in two places. Since the stock profile creation cannot fail, we can streamline cmlcms_init() a little, too. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-lcms.c | 10 +-- libweston/color-lcms/color-lcms.h | 2 +- libweston/color-lcms/color-profile.c | 124 +++++++-------------------- 3 files changed, 32 insertions(+), 104 deletions(-) diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c index 8317febfd..3229ba08d 100644 --- a/libweston/color-lcms/color-lcms.c +++ b/libweston/color-lcms/color-lcms.c @@ -429,19 +429,13 @@ cmlcms_init(struct weston_color_manager *cm_base) cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger); - if (!cmlcms_create_stock_profile(cm)) { - weston_log("color-lcms: error: cmlcms_create_stock_profile failed\n"); - goto out_err; - } + cm->sRGB_profile = cmlcms_create_stock_profile(cm); + weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion()); return true; out_err: - if (cm->lcms_ctx) - cmsDeleteContext(cm->lcms_ctx); - cm->lcms_ctx = NULL; - weston_log_scope_destroy(cm->transforms_scope); cm->transforms_scope = NULL; weston_log_scope_destroy(cm->optimizer_scope); diff --git a/libweston/color-lcms/color-lcms.h b/libweston/color-lcms/color-lcms.h index 0c64c5f10..56fb4ad07 100644 --- a/libweston/color-lcms/color-lcms.h +++ b/libweston/color-lcms/color-lcms.h @@ -292,7 +292,7 @@ ref_cprof(struct cmlcms_color_profile *cprof); void unref_cprof(struct cmlcms_color_profile *cprof); -bool +struct cmlcms_color_profile * cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm); void diff --git a/libweston/color-lcms/color-profile.c b/libweston/color-lcms/color-profile.c index 01c0d032e..295b20bfa 100644 --- a/libweston/color-lcms/color-profile.c +++ b/libweston/color-lcms/color-profile.c @@ -558,57 +558,36 @@ make_icc_file_description(struct lcmsProfilePtr profile, * BT.709 primaries with gamma-2.2 transfer characteristic. This is the * expected sRGB display response. */ -bool +struct cmlcms_color_profile * cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm) { - static const cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; - static const cmsCIExyYTRIPLE bt709 = { - { 0.6400, 0.3300, 1.0 }, - { 0.3000, 0.6000, 1.0 }, - { 0.1500, 0.0600, 1.0 } - }; - cmsToneCurve *gamma22[3]; - struct lcmsProfilePtr profile = { NULL }; - struct cmlcms_md5_sum md5sum; + struct weston_compositor *compositor = cm->base.compositor; + struct weston_color_profile_params p = {}; + struct cmlcms_color_profile *stock; char *desc = NULL; - const char *err_msg = NULL; - gamma22[0] = gamma22[1] = gamma22[2] = cmsBuildGamma(cm->lcms_ctx, 2.2); - if (gamma22[0]) - profile.p = cmsCreateRGBProfileTHR(cm->lcms_ctx, &D65, &bt709, gamma22); - cmsFreeToneCurve(gamma22[0]); - if (!profile.p) { - weston_log("color-lcms: error: failed to create stock sRGB profile.\n"); - return false; - } - if (!cmsMD5computeID(profile.p)) { - weston_log("Failed to compute MD5 for stock sRGB profile.\n"); - goto err_close; - } + p.primaries_info = weston_color_primaries_info_from(compositor, + WESTON_PRIMARIES_CICP_SRGB); + p.primaries = p.primaries_info->color_gamut; + p.tf.info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22); + p.reference_white_luminance = 80.0; + p.min_luminance = 0.2; + p.max_luminance = 80.0; + p.target_primaries = p.primaries; + p.target_min_luminance = p.min_luminance; + p.target_max_luminance = p.max_luminance; + p.maxCLL = -1.0f; + p.maxFALL = -1.0f; - cmsGetHeaderProfileID(profile.p, md5sum.bytes); - desc = make_icc_file_description(profile, &md5sum, "sRGB stock"); - if (!desc) - goto err_close; + str_printf(&desc, "default sRGB: %s primaries, %s transfer function", + p.primaries_info->desc, p.tf.info->desc); + abort_oom_if_null(desc); - cm->sRGB_profile = cmlcms_color_profile_alloc(cm, CMLCMS_PROFILE_TYPE_ICC, desc); - cm->sRGB_profile->icc.profile = profile; - cm->sRGB_profile->icc.md5sum = md5sum; + stock = cmlcms_color_profile_alloc(cm, CMLCMS_PROFILE_TYPE_PARAMS, desc); + *stock->params = p; + cmlcms_color_profile_register(stock); - if (!ensure_output_profile_extract(cm->sRGB_profile, cm->lcms_ctx, - cmlcms_reasonable_1D_points(), &err_msg)) - goto err_close; - - cmlcms_color_profile_register(cm->sRGB_profile); - - return true; - -err_close: - if (err_msg) - weston_log("%s\n", err_msg); - - cmlcms_color_profile_destroy(cm->sRGB_profile); - return false; + return stock; } struct weston_color_profile * @@ -749,62 +728,17 @@ bool cmlcms_send_image_desc_info(struct cm_image_desc_info *cm_image_desc_info, struct weston_color_profile *cprof_base) { - struct weston_color_manager_lcms *cm = to_cmlcms(cprof_base->cm); - struct weston_compositor *compositor = cm->base.compositor; struct cmlcms_color_profile *cprof = to_cmlcms_cprof(cprof_base); - const struct weston_color_primaries_info *primaries_info; - /** - * TODO: when we convert the stock sRGB profile to a parametric profile - * instead of an ICC one, we'll be able to change the if/else below to - * a switch/case. - */ - - if (cprof->type == CMLCMS_PROFILE_TYPE_ICC && cprof != cm->sRGB_profile) { + switch (cprof->type) { + case CMLCMS_PROFILE_TYPE_ICC: return cmlcms_send_icc_info(cm_image_desc_info, cprof); - } else { - if (cprof != cm->sRGB_profile) { - weston_cm_send_parametric_info(cm_image_desc_info, cprof->params); - return true; - } - - /* Stock sRGB color profile. TODO: when we add support for - * parametric color profiles, the stock sRGB will be crafted - * using parameters, instead of cmsCreate_sRGBProfileTHR() - * (which we currently use). So we'll get the parameters - * directly from it, instead of hardcoding as we are doing here. - * We don't get the parameters from the stock sRGB color profile - * because it is not trivial to retrieve that from LittleCMS. */ - - /* Send the H.273 ColourPrimaries code point that matches the - * Rec709 primaries and the D65 white point. */ - primaries_info = weston_color_primaries_info_from(compositor, - WESTON_PRIMARIES_CICP_SRGB); - weston_cm_send_primaries_named(cm_image_desc_info, primaries_info); - - /* These are the Rec709 primaries and D65 white point. */ - weston_cm_send_primaries(cm_image_desc_info, - &primaries_info->color_gamut); - - /* Target primaries, equal to the primary primaries. */ - weston_cm_send_target_primaries(cm_image_desc_info, - &primaries_info->color_gamut); - - /* sRGB transfer function. */ - struct weston_color_tf tf = { - .info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22), - .params = {}, - }; - weston_cm_send_tf(cm_image_desc_info, &tf); - - /* Primary luminance, default values from the protocol. */ - weston_cm_send_luminances(cm_image_desc_info, 0.2, 80.0, 80.0); - - /* Target luminance, min/max equals primary luminance min/max. */ - weston_cm_send_target_luminances(cm_image_desc_info, 0.2, 80.0); + case CMLCMS_PROFILE_TYPE_PARAMS: + weston_cm_send_parametric_info(cm_image_desc_info, cprof->params); + return true; } - return true; + return false; } struct weston_color_profile * From 318005c9bcb90954e5ad6ec55b6c83ba4a6ef368 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 9 Dec 2025 14:24:59 +0200 Subject: [PATCH 08/10] color-lcms: do not advertise saturation intent Weston does not support the saturation rendering intent for parametric image descriptions yet. Not really, Weston would just do the same as media-relative with BPC does. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-lcms.c | 3 +-- tests/color-management-parametric-test.c | 2 +- tests/color-management-test.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c index 3229ba08d..0effb74f3 100644 --- a/libweston/color-lcms/color-lcms.c +++ b/libweston/color-lcms/color-lcms.c @@ -523,9 +523,8 @@ weston_color_manager_create(struct weston_compositor *compositor) (1 << WESTON_COLOR_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES) | (1 << WESTON_COLOR_FEATURE_EXTENDED_TARGET_VOLUME); - /* We support all rendering intents. */ cm->base.supported_rendering_intents = (1 << WESTON_RENDER_INTENT_PERCEPTUAL) | - (1 << WESTON_RENDER_INTENT_SATURATION) | + /* (1 << WESTON_RENDER_INTENT_SATURATION) | */ (1 << WESTON_RENDER_INTENT_ABSOLUTE) | (1 << WESTON_RENDER_INTENT_RELATIVE) | (1 << WESTON_RENDER_INTENT_RELATIVE_BPC); diff --git a/tests/color-management-parametric-test.c b/tests/color-management-parametric-test.c index 9ad7f2384..f001bd60d 100644 --- a/tests/color-management-parametric-test.c +++ b/tests/color-management-parametric-test.c @@ -433,7 +433,7 @@ color_manager_get(struct client *client) test_assert_u32_eq(cm->supported_rendering_intents, (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL) | (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE) | - (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | + /* (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | */ (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE) | (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC)); diff --git a/tests/color-management-test.c b/tests/color-management-test.c index f4bf46f09..fd18b32e3 100644 --- a/tests/color-management-test.c +++ b/tests/color-management-test.c @@ -73,7 +73,7 @@ color_manager_get(struct client *client) test_assert_u32_eq(cm->supported_rendering_intents, (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL) | (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE) | - (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | + /* (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION) | */ (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE) | (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC)); From 5c87fe21b151db8255680f74ff3d877371e1f43f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 9 Dec 2025 14:30:03 +0200 Subject: [PATCH 09/10] color-lcms: adjust supported TF mask TF_SRGB will be deprecated, best to never advertise it. The test can simply use gamma22 instead. TF_EXT_LINEAR has an implementation and should be usable nowadays. TF_ST2084_PQ, GAMMA22 and GAMMA28 likewise. Signed-off-by: Pekka Paalanen --- libweston/color-lcms/color-lcms.c | 14 ++-------- tests/color-management-parametric-test.c | 34 ++++++++++++------------ 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c index 0effb74f3..aae6a2722 100644 --- a/libweston/color-lcms/color-lcms.c +++ b/libweston/color-lcms/color-lcms.c @@ -514,7 +514,6 @@ weston_color_manager_create(struct weston_compositor *compositor) cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform; cm->base.create_output_color_outcome = cmlcms_create_output_color_outcome; - /* We support all color features. */ cm->base.supported_color_features = (1 << WESTON_COLOR_FEATURE_ICC) | (1 << WESTON_COLOR_FEATURE_PARAMETRIC) | (1 << WESTON_COLOR_FEATURE_SET_PRIMARIES) | @@ -529,7 +528,6 @@ weston_color_manager_create(struct weston_compositor *compositor) (1 << WESTON_RENDER_INTENT_RELATIVE) | (1 << WESTON_RENDER_INTENT_RELATIVE_BPC); - /* We support all primaries named. */ cm->base.supported_primaries_named = (1 << WESTON_PRIMARIES_CICP_SRGB) | (1 << WESTON_PRIMARIES_CICP_PAL_M) | (1 << WESTON_PRIMARIES_CICP_PAL) | @@ -541,18 +539,10 @@ weston_color_manager_create(struct weston_compositor *compositor) (1 << WESTON_PRIMARIES_CICP_DISPLAY_P3) | (1 << WESTON_PRIMARIES_ADOBE_RGB); - /** - * TODO: this is a lie just to make the color-management-parametric - * tests to work. Without this the tests would be much more limited. We - * actually need to implement such TF's. There's no problem doing that, - * as parametric color profiles themselves are still unsupported. - */ - - /* We need to implement each tf, and we support only a few of them. */ cm->base.supported_tf_named = (1 << WESTON_TF_GAMMA22) | (1 << WESTON_TF_GAMMA28) | - (1 << WESTON_TF_SRGB) | - (1 << WESTON_TF_ST2084_PQ); + (1 << WESTON_TF_ST2084_PQ) | + (1 << WESTON_TF_EXT_LINEAR); wl_list_init(&cm->color_transform_list); wl_list_init(&cm->color_profile_list); diff --git a/tests/color-management-parametric-test.c b/tests/color-management-parametric-test.c index f001bd60d..4e2317044 100644 --- a/tests/color-management-parametric-test.c +++ b/tests/color-management-parametric-test.c @@ -95,10 +95,10 @@ static const struct test_case test_cases[] = { /******** Successful cases *******/ { - /* sRGB primaries with sRGB TF; succeeds. */ + /* sRGB primaries with gamma22; succeeds. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -112,10 +112,10 @@ static const struct test_case test_cases[] = { .error_point = ERROR_POINT_NONE, }, { - /* Custom primaries with sRGB TF; succeeds. */ + /* Custom primaries with gamma22; succeeds. */ .primaries_named = NOT_SET, .primaries = &color_gamut_sRGB, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -129,10 +129,10 @@ static const struct test_case test_cases[] = { .error_point = ERROR_POINT_NONE, }, { - /* sRGB primaries, sRGB TF and valid luminance values; succeeds. */ + /* sRGB primaries, gamma22 and valid luminance values; succeeds. */ .primaries_named = NOT_SET, .primaries = &color_gamut_sRGB, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = 0.5, .primaries_max_lum = 2000, @@ -163,10 +163,10 @@ static const struct test_case test_cases[] = { .error_point = ERROR_POINT_NONE, }, { - /* sRGB primaries, sRGB TF and valid target primaries; succeeds. */ + /* sRGB primaries, gamma22 and valid target primaries; succeeds. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -309,7 +309,7 @@ static const struct test_case test_cases[] = { * protocol error. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -327,7 +327,7 @@ static const struct test_case test_cases[] = { * protocol error. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -381,7 +381,7 @@ static const struct test_case test_cases[] = { * defined range); graceful failure. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -399,7 +399,7 @@ static const struct test_case test_cases[] = { * graceful failure. */ .primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, .primaries = NULL, - .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + .tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22, .tf_power = NOT_SET, .primaries_min_lum = NOT_SET, .primaries_max_lum = NOT_SET, @@ -455,7 +455,7 @@ color_manager_get(struct client *client) test_assert_u32_eq(cm->supported_tf, (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22) | (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28) | - (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB) | + (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR) | (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ)); test_assert_true(cm->init_done); @@ -736,10 +736,10 @@ TEST(set_tf_named_twice) image_desc_creator_param = color_manager_create_param(cm); wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param, - WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); client_roundtrip(client); /* make sure connection is still valid */ wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param, - WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); expect_protocol_error(client, &wp_image_description_creator_params_v1_interface, WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET); wp_image_description_creator_params_v1_destroy(image_desc_creator_param); @@ -763,7 +763,7 @@ TEST(set_tf_power_then_tf_named) 2.4 * 10000); client_roundtrip(client); /* make sure connection is still valid */ wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param, - WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); expect_protocol_error(client, &wp_image_description_creator_params_v1_interface, WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET); wp_image_description_creator_params_v1_destroy(image_desc_creator_param); @@ -784,7 +784,7 @@ TEST(set_tf_named_then_tf_power) image_desc_creator_param = color_manager_create_param(cm); wp_image_description_creator_params_v1_set_tf_named(image_desc_creator_param, - WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22); client_roundtrip(client); /* make sure connection is still valid */ wp_image_description_creator_params_v1_set_tf_power(image_desc_creator_param, 2.4 * 10000); From 275df28f2af031a37e23f297074887c4c8424a16 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 26 Jan 2026 16:54:29 +0200 Subject: [PATCH 10/10] frontend: default color-profile to auto: Now that ICC<->parametric image description interoperability is implemented, and the stock sRGB profile is parametric, we can change the default to what it should be. Signed-off-by: Pekka Paalanen --- frontend/main.c | 8 +------- man/weston.ini.man | 7 +------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/frontend/main.c b/frontend/main.c index e8c215cd5..a4047c2a4 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -2110,13 +2110,7 @@ wet_output_set_color_profile(struct weston_output *output, } else if (parent_winsys_profile) { cprof = weston_color_profile_ref(parent_winsys_profile); } else { - /* - * TODO: Once parametric color profiles are fully supported - * and interoperable with ICC profiles, the default profile - * would be created like this: - * cprof = wet_create_output_color_profile(output, wc, "auto:"); - */ - return 0; + cprof = wet_create_output_color_profile(output, wc, "auto:"); } if (!cprof) diff --git a/man/weston.ini.man b/man/weston.ini.man index 2938b563b..f52e566dc 100644 --- a/man/weston.ini.man +++ b/man/weston.ini.man @@ -597,11 +597,6 @@ on DRM, headless, wayland, and x11 backends, and for remoting and pipewire outputs. .TP 7 .BI "color-profile=" name - -.B NOTE: -This feature is not fully implemented yet, and therefore it is not expected to -work. - Color profiles describe how the display is assumed to behave. Knowing the display color behavior, Weston can adapt window contents to produce the presumed appearance. The option @@ -619,7 +614,7 @@ section by referring to it by its value. Alternatively this key can use one of the special profile names that contain a colon (:). -The default, once implemented, will be +The default is .BR "color-profile=auto:" . The following special names are accepted: