diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index f00165d61..bedff8a96 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -73,6 +73,7 @@ struct weston_point2d_device_normalized { double y; }; +struct weston_compositor; struct weston_surface; struct weston_buffer; struct shell_surface; @@ -84,6 +85,7 @@ struct linux_dmabuf_buffer; struct weston_recorder; struct weston_pointer_constraint; struct ro_anonymous_file; +struct weston_color_profile_param_builder; struct weston_color_profile; struct weston_color_transform; struct pixel_format_info; @@ -350,6 +352,69 @@ enum weston_transfer_function { WESTON_TF_POWER, }; +/** Error codes that the color profile parameters functions may return. */ +enum weston_color_profile_param_builder_error { + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF = 0, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_PRIMARIES, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TARGET_PRIMARIES, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_CIE_XY_OUT_OF_RANGE, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_LUMINANCE, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_LUMINANCES, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_SET, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCOMPLETE_SET, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_UNSUPPORTED, +}; + +struct weston_color_profile_param_builder * +weston_color_profile_param_builder_create(struct weston_compositor *compositor); + +void +weston_color_profile_param_builder_destroy(struct weston_color_profile_param_builder *builder); + +bool +weston_color_profile_param_builder_get_error(struct weston_color_profile_param_builder *builder, + enum weston_color_profile_param_builder_error *err, + char **err_msg); + +bool +weston_color_profile_param_builder_set_primaries(struct weston_color_profile_param_builder *builder, + const struct weston_color_gamut *primaries); + +bool +weston_color_profile_param_builder_set_primaries_named(struct weston_color_profile_param_builder *builder, + enum weston_color_primaries primaries); + +bool +weston_color_profile_param_builder_set_tf_named(struct weston_color_profile_param_builder *builder, + enum weston_transfer_function tf); + +bool +weston_color_profile_param_builder_set_tf_power_exponent(struct weston_color_profile_param_builder *builder, + float power_exponent); + +bool +weston_color_profile_param_builder_set_target_primaries(struct weston_color_profile_param_builder *builder, + const struct weston_color_gamut *target_primaries); + +bool +weston_color_profile_param_builder_set_target_luminance(struct weston_color_profile_param_builder *builder, + float min_luminance, float max_luminance); + +bool +weston_color_profile_param_builder_set_maxFALL(struct weston_color_profile_param_builder *builder, + float maxFALL); + +bool +weston_color_profile_param_builder_set_maxCLL(struct weston_color_profile_param_builder *builder, + float maxCLL); + +struct weston_color_profile * +weston_color_profile_param_builder_create_color_profile(struct weston_color_profile_param_builder *builder, + const char *name_part, + enum weston_color_profile_param_builder_error *err, + char **err_msg); + enum weston_color_characteristics_groups { /** weston_color_characteristics::primary is set */ WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES = 0x01, diff --git a/libweston/color-profile-param-builder.c b/libweston/color-profile-param-builder.c new file mode 100644 index 000000000..b1d7f5f34 --- /dev/null +++ b/libweston/color-profile-param-builder.c @@ -0,0 +1,756 @@ +/* + * Copyright 2024 Collabora, Ltd. + * + * 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 "color.h" +#include "color-properties.h" +#include "shared/helpers.h" +#include "shared/string-helpers.h" +#include "shared/xalloc.h" +#include "shared/weston-assert.h" + +/** Enum that helps keep track of what params have been set. */ +enum weston_color_profile_params_set { + WESTON_COLOR_PROFILE_PARAMS_PRIMARIES = 0x01, + WESTON_COLOR_PROFILE_PARAMS_TF = 0x02, + WESTON_COLOR_PROFILE_PARAMS_TARGET_PRIMARIES = 0x04, + WESTON_COLOR_PROFILE_PARAMS_LUMINANCE = 0x08, + WESTON_COLOR_PROFILE_PARAMS_MAXCLL = 0x10, + WESTON_COLOR_PROFILE_PARAMS_MAXFALL = 0x20, +}; + +/** Builder object to create color profiles with parameters. */ +struct weston_color_profile_param_builder { + struct weston_compositor *compositor; + struct weston_color_profile_params params; + + /* + * Keeps track of what params have already been set. + * + * A bitmask of values from enum weston_color_profile_params_set. + */ + uint32_t group_mask; + + /* + * Keeps track of errors. + * + * This API may produce errors, and we store all the error messages in + * the string below to help users to debug. Regarding error codes, we + * store only the first that occurs. + * + * Such errors can be queried with + * weston_color_profile_param_builder_get_error(). They are also + * return'ed when users of the API set all the params and call + * weston_color_profile_param_builder_create_color_profile(). + */ + enum weston_color_profile_param_builder_error err; + bool has_errors; + FILE *err_fp; + char *err_msg; + size_t err_msg_size; +}; + +/** + * Creates struct weston_color_profile_param_builder object. It should be used + * to create color profiles from parameters. + * + * We expect it to be used by our frontend (to allow creating color profiles + * from .ini files or similar) and by the color-management protocol + * implementation (so that clients can create color profiles from parameters). + * + * It is invalid to set the same parameter twice using this object. + * + * After creating the color profile from this object, it will be automatically + * destroyed. + * + * \param compositor The weston compositor. + * \return The struct weston_color_profile_param_builder object created. +*/ +struct weston_color_profile_param_builder * +weston_color_profile_param_builder_create(struct weston_compositor *compositor) +{ + struct weston_color_profile_param_builder *builder; + + builder = xzalloc(sizeof(*builder)); + + builder->compositor = compositor; + + builder->err_fp = open_memstream(&builder->err_msg, + &builder->err_msg_size); + weston_assert_ptr(compositor, builder->err_fp); + + return builder; +} + +/** + * Destroys a struct weston_color_profile_param_builder object. + * + * \param builder The object that should be destroyed. + */ +void +weston_color_profile_param_builder_destroy(struct weston_color_profile_param_builder *builder) +{ + fclose(builder->err_fp); + free(builder->err_msg); + free(builder); +} + +static void __attribute__ ((format (printf, 3, 4))) +store_error(struct weston_color_profile_param_builder *builder, + enum weston_color_profile_param_builder_error err, + const char *fmt, ...) +{ + va_list ap; + + /* First error that we log. We also log the err code in such case. */ + if (!builder->has_errors) { + builder->has_errors = true; + builder->err = err; + goto log_msg; + } + + /* There are errors already, so add new line first. */ + fprintf(builder->err_fp, "\n"); + +log_msg: + va_start(ap, fmt); + vfprintf(builder->err_fp, fmt, ap); + va_end(ap); +} + +/** + * Returns the code for the first error generated and a string with all error + * messages that we caught. + * + * Function weston_color_profile_param_builder_create_color_profile() will also + * fail with the first error code (if there's any), but we still need this + * function because some users of the API may want to know about the error + * immediately after calling a setter. + * + * \param builder The builder object whose parameters will be set. + * \param err Set if there's an error, untouched otherwise. The first error code caught. + * \param err_msg Set if there's an error, untouched otherwise. Must be free()'d + * by the caller. Combination of all error messages caught. Not terminated with + * a new line character. + * \return true if there's an error, false otherwise. + */ +bool +weston_color_profile_param_builder_get_error(struct weston_color_profile_param_builder *builder, + enum weston_color_profile_param_builder_error *err, + char **err_msg) +{ + if (!builder->has_errors) + return false; + + *err = builder->err; + + fflush(builder->err_fp); + *err_msg = strdup(builder->err_msg); + + return true; +} + +/** + * Sets primaries for struct weston_color_profile_param_builder object. + * + * See also weston_color_profile_param_builder_set_primaries_named(), which is + * another way of setting the primaries. + * + * If the primaries are already set (with this function or the one + * mentioned above), this should fail. Setting a parameter twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param primaries The object containing the primaries. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_primaries(struct weston_color_profile_param_builder *builder, + const struct weston_color_gamut *primaries) +{ + struct weston_color_manager *cm = builder->compositor->color_manager; + bool success = true; + + if (!((cm->supported_color_features >> WESTON_COLOR_FEATURE_SET_PRIMARIES) & 1)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_PRIMARIES, + "set_primaries not supported by the color manager"); + success = false; + } + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_PRIMARIES) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "primaries were already set"); + success = false; + } + + if (!success) + return false; + + builder->params.primaries = *primaries; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_PRIMARIES; + + return true; +} + +/** + * Sets primaries for struct weston_color_profile_param_builder object using a + * enum weston_color_primaries. + * + * See also weston_color_profile_param_builder_set_primaries(), which is another + * way of setting the primaries. + * + * If the primaries are already set (with this function or the one mentioned + * above), this should fail. Setting a parameter twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param primaries The enum representing the primaries. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_primaries_named(struct weston_color_profile_param_builder *builder, + enum weston_color_primaries primaries) +{ + struct weston_compositor *compositor = builder->compositor; + struct weston_color_manager *cm = compositor->color_manager; + bool success = true; + + if (!((cm->supported_primaries_named >> primaries) & 1)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_PRIMARIES, + "named primaries %u not supported by the color manager", + primaries); + success = false; + } + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_PRIMARIES) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "primaries were already set"); + success = false; + } + + if (!success) + return false; + + builder->params.primaries_info = + weston_color_primaries_info_from(compositor, primaries); + + builder->params.primaries = builder->params.primaries_info->color_gamut; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_PRIMARIES; + + return true; +} + +/** + * Sets transfer function for struct weston_color_profile_param_builder object + * using a enum weston_transfer_function. + * + * See also weston_color_profile_param_builder_set_tf_power_exponent(), which is + * another way of setting the transfer function. + * + * If the transfer function is already set (with this function or the one + * mentioned above), this should fail. Setting a parameter twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param tf The enum representing the transfer function. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_tf_named(struct weston_color_profile_param_builder *builder, + enum weston_transfer_function tf) +{ + struct weston_compositor *compositor = builder->compositor; + struct weston_color_manager *cm = compositor->color_manager; + bool success = true; + + if (!((cm->supported_tf_named >> tf) & 1)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF, + "named tf %u not supported by the color manager", tf); + success = false; + } + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TF) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "tf was already set"); + success = false; + } + + if (!success) + return false; + + builder->params.tf_info = weston_color_tf_info_from(compositor, tf); + weston_assert_false(builder->compositor, + builder->params.tf_info->has_parameters); + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_TF; + + return true; +} + +/** + * Sets transfer function for struct weston_color_profile_param_builder object + * using a power law function exponent g. In such case, the transfer function is + * y = x ^ g. The valid range for the given exponent is [1.0, 10.0]. + * + * See also weston_color_profile_param_builder_set_tf_named(), which is another + * way of setting the transfer function. + * + * If the transfer function is already set (with this function or the one + * mentioned above), this should fail. Setting a parameter twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param power_exponent The power law function exponent. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_tf_power_exponent(struct weston_color_profile_param_builder *builder, + float power_exponent) +{ + struct weston_compositor *compositor = builder->compositor; + struct weston_color_manager *cm = compositor->color_manager; + bool success = true; + + if (!((cm->supported_color_features >> WESTON_COLOR_FEATURE_SET_TF_POWER) & 1)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF, + "set_tf_power not supported by the color manager"); + success = false; + } + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TF) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "tf was already set"); + success = false; + } + + /* The exponent should be at least 1.0 and at most 10.0. */ + if (!(power_exponent >= 1.0 && power_exponent <= 10.0)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF, + "tf power exponent %f is not in the range [1.0, 10.0]", + power_exponent); + success = false; + } + + if (!success) + return false; + + builder->params.tf_info = weston_color_tf_info_from(compositor, WESTON_TF_POWER); + builder->params.tf_params[0] = power_exponent; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_TF; + + return true; +} + +/** + * Sets target primaries for struct weston_color_profile_param_builder object + * using raw values. + * + * If the target primaries are already set, this should fail. Setting a + * parameter twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param target_primaries The object containing the target primaries. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_target_primaries(struct weston_color_profile_param_builder *builder, + const struct weston_color_gamut *target_primaries) +{ + struct weston_color_manager *cm = builder->compositor->color_manager; + bool success = true; + + if (!((cm->supported_color_features >> WESTON_COLOR_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES) & 1)) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TARGET_PRIMARIES, + "set_mastering_display_primaries not supported by " \ + "the color manager"); + success = false; + } + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TARGET_PRIMARIES) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "target primaries were already set"); + success = false; + } + + if (!success) + return false; + + builder->params.target_primaries = *target_primaries; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_TARGET_PRIMARIES; + + return true; +} + +/** + * Sets target luminance for struct weston_color_profile_param_builder object. + * + * If the target luminance is already set, this should fail. Setting a parameter + * twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param min_luminance The minimum luminance. + * \param max_luminance The maximum luminance. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_target_luminance(struct weston_color_profile_param_builder *builder, + float min_luminance, float max_luminance) +{ + bool success = true; + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_LUMINANCE) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "target luminance was already set"); + success = false; + } + + if (min_luminance >= max_luminance) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_LUMINANCE, + "min luminance %f shouldn't be greater than or equal to max %f", + min_luminance, max_luminance); + success = false; + } + + if (!success) + return false; + + builder->params.min_luminance = min_luminance; + builder->params.max_luminance = max_luminance; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_LUMINANCE; + + return true; +} + +/** + * Sets target maxFALL for struct weston_color_profile_param_builder object. + * + * If the target maxFALL is already set, this should fail. Setting a parameter + * twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param maxFALL The maxFALL. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_maxFALL(struct weston_color_profile_param_builder *builder, + float maxFALL) +{ + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXFALL) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "max fall was already set"); + return false; + } + + builder->params.maxFALL = maxFALL; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_MAXFALL; + + return true; +} + +/** + * Sets target maxCLL for struct weston_color_profile_param_builder object. + * + * If the target maxCLL is already set, this should fail. Setting a parameter + * twice is forbidden. + * + * If this fails, users can call weston_color_profile_param_builder_get_error() + * to get the error details. + * + * \param builder The builder object whose parameters will be set. + * \param maxCLL The maxCLL. + * \return true on success, false otherwise. + */ +bool +weston_color_profile_param_builder_set_maxCLL(struct weston_color_profile_param_builder *builder, + float maxCLL) +{ + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXCLL) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET, + "max cll was already set"); + return false; + } + + builder->params.maxCLL = maxCLL; + + builder->group_mask |= WESTON_COLOR_PROFILE_PARAMS_MAXCLL; + + return true; +} + +static void +builder_validate_params_set(struct weston_color_profile_param_builder *builder) +{ + /* Primaries are mandatory. */ + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_PRIMARIES)) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCOMPLETE_SET, + "primaries not set"); + + /* TF is mandatory. */ + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TF)) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCOMPLETE_SET, + "transfer function not set"); + + /* If luminance values were given, tf must be PQ. */ + if (builder->params.tf_info->tf != WESTON_TF_ST2084_PQ && + (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_LUMINANCE || + builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXCLL || + builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXFALL)) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_SET, + "luminance values were given but transfer function " \ + "is not Rec. ITU-R BT.2100-2 (PQ)"); +} + +static float +triangle_area(float x1, float y1, float x2, float y2, float x3, float y3) +{ + /* Based on the shoelace formula, also known as Gauss's area formula. */ + return fabs((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1)) / 2.0f; +} + +static bool +is_point_inside_triangle(float point_x, float point_y, + float x1, float y1, float x2, float y2, float x3, float y3) +{ + float A1, A2, A3; + float A; + const float PRECISION = 1e-5; + + A = triangle_area(x1, y1, x2, y2, x3, y3); + + /* Bail out if something that is not a triangle was given. */ + if (A <= PRECISION) + return false; + + A1 = triangle_area(point_x, point_y, x1, y1, x2, y2); + A2 = triangle_area(point_x, point_y, x1, y1, x3, y3); + A3 = triangle_area(point_x, point_y, x2, y2, x3, y3); + + if (fabs(A - (A1 + A2 + A3)) <= PRECISION) + return true; + + return false; +} + +static void +validate_color_gamut(struct weston_color_profile_param_builder *builder, + const struct weston_color_gamut *gamut, + const char *gamut_name) +{ + /* + * We choose the legal range [-1.0, 2.0] for CIE xy values. It is + * probably more than we'd ever need, but tight enough to not cause + * mathematical issues. If wasn't for the ACES AP0 color space, we'd + * probably choose the range [0.0, 1.0]. + */ + if (gamut->white_point.x < -1.0f || gamut->white_point.x > 2.0f || + gamut->white_point.y < -1.0f || gamut->white_point.y > 2.0f || + gamut->primary[0].x < -1.0f || gamut->primary[0].x > 2.0f || + gamut->primary[0].y < -1.0f || gamut->primary[0].y > 2.0f || + gamut->primary[1].x < -1.0f || gamut->primary[1].x > 2.0f || + gamut->primary[1].y < -1.0f || gamut->primary[1].y > 2.0f || + gamut->primary[2].x < -1.0f || gamut->primary[2].x > 2.0f || + gamut->primary[2].y < -1.0f || gamut->primary[2].y > 2.0f) { + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_CIE_XY_OUT_OF_RANGE, + "invalid %s", gamut_name); + return; + } + + /* + * That is not sufficient. There are points inside the triangle that + * would not be valid white points. But for now that's good enough. + */ + if (!is_point_inside_triangle(gamut->white_point.x, + gamut->white_point.y, + gamut->primary[0].x, + gamut->primary[0].y, + gamut->primary[1].x, + gamut->primary[1].y, + gamut->primary[2].x, + gamut->primary[2].y)) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_CIE_XY_OUT_OF_RANGE, + "white point out of %s volume", gamut_name); +} + +static void +validate_maxcll(struct weston_color_profile_param_builder *builder) +{ + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_LUMINANCE)) + return; + + if (builder->params.min_luminance >= builder->params.maxCLL) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_LUMINANCES, + "maxCLL (%f) should be greater or equal to min luminance (%f)", + builder->params.maxCLL, builder->params.min_luminance); + + if (builder->params.max_luminance < builder->params.maxCLL) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_LUMINANCES, + "maxCLL (%f) should not be greater than max luminance (%f)", + builder->params.maxCLL, builder->params.max_luminance); +} + +static void +validate_maxfall(struct weston_color_profile_param_builder *builder) +{ + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_LUMINANCE)) + return; + + if (builder->params.min_luminance >= builder->params.maxFALL) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_LUMINANCES, + "maxFALL (%f) should be greater or equal to min luminance (%f)", + builder->params.maxFALL, builder->params.min_luminance); + + if (builder->params.max_luminance < builder->params.maxFALL) + store_error(builder, WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCONSISTENT_LUMINANCES, + "maxFALL (%f) should not be greater than max luminance (%f)", + builder->params.maxFALL, builder->params.max_luminance); +} + +static void +builder_validate_params(struct weston_color_profile_param_builder *builder) +{ + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_PRIMARIES) + validate_color_gamut(builder, &builder->params.primaries, + "primaries"); + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TARGET_PRIMARIES) + validate_color_gamut(builder, &builder->params.target_primaries, + "target primaries"); + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXCLL) + validate_maxcll(builder); + + if (builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXFALL) + validate_maxfall(builder); +} + +static void +builder_complete_params(struct weston_color_profile_param_builder *builder) +{ + /* If no target primaries were set, it matches the primaries. */ + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_TARGET_PRIMARIES)) + builder->params.target_primaries = builder->params.primaries; + + /* + * If luminance is not set, set it to negative. Same applies to maxCLL + * and maxFALL. + */ + + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_LUMINANCE)) { + builder->params.min_luminance = -1.0f; + builder->params.max_luminance = -1.0f; + } + + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXCLL)) + builder->params.maxCLL = -1.0f; + + if (!(builder->group_mask & WESTON_COLOR_PROFILE_PARAMS_MAXFALL)) + builder->params.maxFALL = -1.0f; +} + +/** + * Creates a color profile from a struct weston_color_profile_param_builder + * object. + * + * After creating the weston_color_profile_param_builder and setting the + * appropriate parameters, this function should be called to finally create the + * color profile. It checks if the parameters are consistent and, if so, call + * the color manager to create the color profile. + * + * Also, this is a destructor function. It destroys the builder object. + * + * \param builder The object that has the parameters set. + * \param name_part A string to be used in describing the profile. + * \param err Set if there's an error, untouched otherwise. The first error code caught. + * \param err_msg Set if there's an error, untouched otherwise. Must be free()'d + * by the caller. Combination of all error messages caught. Not terminated with + * a new line character. + * \return The color profile created, or NULL on failure. + */ +struct weston_color_profile * +weston_color_profile_param_builder_create_color_profile(struct weston_color_profile_param_builder *builder, + const char *name_part, + enum weston_color_profile_param_builder_error *err, + char **err_msg) +{ + struct weston_color_manager *cm = builder->compositor->color_manager; + struct weston_color_profile_params *params = &builder->params; + struct weston_color_profile *cprof = NULL; + bool ret; + + /* + * See struct weston_color_profile_params description. That struct has + * some rules that we need to fullfil (e.g. target primaries must be + * set, even if client does not pass anything). In this function we + * complete the param set in order to fullfil such rules. + */ + builder_complete_params(builder); + + /* Ensure that params make sense together. */ + builder_validate_params_set(builder); + + /* Ensure that each param set is reasonable. */ + builder_validate_params(builder); + + /* Something went wrong, so error out. */ + if (builder->has_errors) { + fflush(builder->err_fp); + *err_msg = strdup(builder->err_msg); + *err = builder->err; + goto out; + } + + ret = cm->get_color_profile_from_params(cm, params, name_part, + &cprof, err_msg); + if (!ret) + *err = WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_UNSUPPORTED; + +out: + weston_color_profile_param_builder_destroy(builder); + return cprof; +} diff --git a/libweston/meson.build b/libweston/meson.build index 1675d5e1b..29d3e2ea2 100644 --- a/libweston/meson.build +++ b/libweston/meson.build @@ -18,6 +18,7 @@ srcs_libweston = [ 'color-properties.c', 'color-management.c', 'color-noop.c', + 'color-profile-param-builder.c', 'compositor.c', 'content-protection.c', 'data-device.c',