diff --git a/frontend/main.c b/frontend/main.c index adeededc6..f306e5541 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/libweston/color-lcms/color-curve-segments.c b/libweston/color-lcms/color-curve-segments.c index 14f61dcd3..95e30f6ed 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,56 @@ 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). */ + + /* 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. + * + * 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 +630,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 +646,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 @@ -652,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-lcms.c b/libweston/color-lcms/color-lcms.c index 8317febfd..aae6a2722 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); @@ -520,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,14 +522,12 @@ 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); - /* 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) | @@ -548,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/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 c5751ba85..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 * @@ -719,84 +698,47 @@ 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) { - 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; - 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 - * 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) { - /* 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); - } 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"); - - /* 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. */ - tf_info = weston_color_tf_info_from(compositor, WESTON_TF_GAMMA22); - weston_cm_send_tf_named(cm_image_desc_info, tf_info); - - /* 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); + switch (cprof->type) { + case CMLCMS_PROFILE_TYPE_ICC: + return cmlcms_send_icc_info(cm_image_desc_info, cprof); + 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 * 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 diff --git a/libweston/color-management.c b/libweston/color-management.c index 10cf7a305..fbf59caee 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]); + } } /** @@ -261,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 5ae38198e..d83ed39c4 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, @@ -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 */ diff --git a/man/weston.ini.man b/man/weston.ini.man index c7bd161e0..52d1c9528 100644 --- a/man/weston.ini.man +++ b/man/weston.ini.man @@ -583,11 +583,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 @@ -605,7 +600,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: diff --git a/tests/color-management-parametric-test.c b/tests/color-management-parametric-test.c index 9ad7f2384..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, @@ -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)); @@ -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); 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));