diff --git a/libweston/color-lcms/color-lcms.c b/libweston/color-lcms/color-lcms.c index f8d44530..97e6d6ab 100644 --- a/libweston/color-lcms/color-lcms.c +++ b/libweston/color-lcms/color-lcms.c @@ -27,6 +27,7 @@ #include "config.h" #include +#include #include #include "color.h" @@ -185,6 +186,102 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager_lcms *cm, return true; } +static float +meta_clamp(float value, const char *valname, float min, float max, + struct weston_output *output) +{ + float ret = value; + + /* Paranoia against NaN */ + if (!(ret >= min)) + ret = min; + + if (!(ret <= max)) + ret = max; + + if (ret != value) { + weston_log("output '%s' clamping %s value from %f to %f.\n", + output->name, valname, value, ret); + } + + return ret; +} + +static bool +cmlcms_get_hdr_meta(struct weston_output *output, + struct weston_hdr_metadata_type1 *hdr_meta) +{ + const struct weston_color_characteristics *cc; + + hdr_meta->group_mask = 0; + + /* Only SMPTE ST 2084 mode uses HDR Static Metadata Type 1 */ + if (weston_output_get_eotf_mode(output) != WESTON_EOTF_MODE_ST2084) + return true; + + /* ICC profile overrides color characteristics */ + if (output->color_profile) { + /* + * TODO: extract characteristics from profile? + * Get dynamic range from weston_color_characteristics? + */ + + return true; + } + + cc = weston_output_get_color_characteristics(output); + + /* Target content chromaticity */ + if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES) { + unsigned i; + + for (i = 0; i < 3; i++) { + hdr_meta->primary[i].x = meta_clamp(cc->primary[i].x, + "primary", 0.0, 1.0, + output); + hdr_meta->primary[i].y = meta_clamp(cc->primary[i].y, + "primary", 0.0, 1.0, + output); + } + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES; + } + + /* Target content white point */ + if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE) { + hdr_meta->white.x = meta_clamp(cc->white.x, "white", + 0.0, 1.0, output); + hdr_meta->white.y = meta_clamp(cc->white.y, "white", + 0.0, 1.0, output); + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE; + } + + /* Target content peak and max mastering luminance */ + if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL) { + hdr_meta->maxDML = meta_clamp(cc->max_luminance, "maxDML", + 1.0, 65535.0, output); + hdr_meta->maxCLL = meta_clamp(cc->max_luminance, "maxCLL", + 1.0, 65535.0, output); + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML; + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL; + } + + /* Target content min mastering luminance */ + if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MINL) { + hdr_meta->minDML = meta_clamp(cc->min_luminance, "minDML", + 0.0001, 6.5535, output); + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MINDML; + } + + /* Target content max frame-average luminance */ + if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL) { + hdr_meta->maxFALL = meta_clamp(cc->maxFALL, "maxFALL", + 1.0, 65535.0, output); + hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL; + } + + return true; +} + static struct weston_output_color_outcome * cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base, struct weston_output *output) @@ -196,6 +293,19 @@ cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base, if (!co) return NULL; + if (!cmlcms_get_hdr_meta(output, &co->hdr_meta)) + goto out_fail; + + /* + * TODO: if output->color_profile is NULL, maybe manufacture a + * profile from weston_color_characteristics if it has enough + * information? + * Or let the frontend decide to call a "create a profile from + * characteristics" API? + */ + + /* TODO: take container color space into account */ + if (!cmlcms_get_blend_to_output_color_transform(cm, output, &co->from_blend_to_output)) goto out_fail; @@ -208,8 +318,6 @@ cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base, &co->from_sRGB_to_output)) goto out_fail; - co->hdr_meta.group_mask = 0; - return co; out_fail: