diff --git a/frontend/main.c b/frontend/main.c index 0b20d573b..43915f8af 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -886,6 +886,7 @@ static const struct { { WESTON_CAP_VIEW_CLIP_MASK, "view mask clipping" }, { WESTON_CAP_EXPLICIT_SYNC, "explicit sync" }, { WESTON_CAP_COLOR_OPS, "color operations" }, + { WESTON_CAP_COLOR_REP, "color representation" } }; static void diff --git a/include/libweston/colorimetry.h b/include/libweston/colorimetry.h index edf88e4a4..caaa90420 100644 --- a/include/libweston/colorimetry.h +++ b/include/libweston/colorimetry.h @@ -187,6 +187,36 @@ enum weston_transfer_function { WESTON_TF_POWER, }; +enum weston_alpha_mode { + WESTON_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL = 0, + WESTON_ALPHA_MODE_PREMULTIPLIED_OPTICAL, + WESTON_ALPHA_MODE_STRAIGHT, +}; + +enum weston_color_matrix_coef { + WESTON_COLOR_MATRIX_COEF_UNSET = 0, + WESTON_COLOR_MATRIX_COEF_IDENTITY, + WESTON_COLOR_MATRIX_COEF_BT601, + WESTON_COLOR_MATRIX_COEF_BT709, + WESTON_COLOR_MATRIX_COEF_BT2020, +}; + +enum weston_color_quant_range { + WESTON_COLOR_QUANT_RANGE_UNSET = 0, + WESTON_COLOR_QUANT_RANGE_FULL, + WESTON_COLOR_QUANT_RANGE_LIMITED, +}; + +enum weston_ycbcr_chroma_location { + WESTON_YCBCR_CHROMA_LOCATION_UNSET = 0, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_0, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_1, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_2, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_3, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_4, + WESTON_YCBCR_CHROMA_LOCATION_TYPE_5, +}; + /** 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, diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index 904ff93d5..5713a3e01 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -921,6 +921,18 @@ struct weston_tablet { const char *path; }; +struct weston_color_representation { + enum weston_alpha_mode alpha_mode; + enum weston_color_matrix_coef matrix_coefficients; + enum weston_color_quant_range quant_range; + enum weston_ycbcr_chroma_location chroma_location; +}; + +struct weston_color_representation_matrix { + struct weston_mat3f matrix; + struct weston_vec3f offset; +}; + struct weston_coord_global weston_pointer_motion_to_abs(struct weston_pointer *pointer, struct weston_pointer_motion_event *event); @@ -1278,6 +1290,9 @@ enum weston_capability { /* renderer supports color management operations */ WESTON_CAP_COLOR_OPS = 0x0040, + + /* renderer supports color representation operations */ + WESTON_CAP_COLOR_REP = 0x0080, }; /* Configuration struct for a backend. @@ -1826,6 +1841,11 @@ struct weston_surface_state { struct weston_color_profile *color_profile; const struct weston_render_intent_info *render_intent; + /* wp_color_representation_surface_v1.set_alpha_mode */ + /* wp_color_representation_surface_v1.set_coefficients_and_range */ + /* wp_color_representation_surface_v1.set_chroma_location */ + struct weston_color_representation color_representation; + /* wp_fifo_v1 */ bool fifo_barrier; bool fifo_wait; @@ -1990,6 +2010,9 @@ struct weston_surface { struct wl_list cm_surface_feedback_resource_list; struct wl_resource *cm_surface; + struct wl_resource *color_representation_resource; + struct weston_color_representation color_representation; + uint64_t damage_track_id; uint64_t flow_id; diff --git a/libweston/color-representation.c b/libweston/color-representation.c new file mode 100644 index 000000000..5a939584d --- /dev/null +++ b/libweston/color-representation.c @@ -0,0 +1,554 @@ +/* + * Copyright 2025 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-representation.h" + +#include "libweston-internal.h" +#include "pixel-formats.h" +#include "shared/string-helpers.h" +#include "shared/weston-assert.h" +#include "shared/xalloc.h" + +#include "color-representation-v1-server-protocol.h" + +static const enum wp_color_representation_surface_v1_alpha_mode supported_alpha_modes[] = { + WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL, +}; + +struct coeffs_and_range { + enum wp_color_representation_surface_v1_coefficients coefficients; + enum wp_color_representation_surface_v1_range range; +}; + +#define CRS(x) WP_COLOR_REPRESENTATION_SURFACE_V1_ ##x +static const struct coeffs_and_range supported_coeffs_and_ranges[] = { + { CRS(COEFFICIENTS_IDENTITY), CRS(RANGE_FULL) }, + { CRS(COEFFICIENTS_BT601), CRS(RANGE_LIMITED) }, + { CRS(COEFFICIENTS_BT601), CRS(RANGE_FULL) }, + { CRS(COEFFICIENTS_BT709), CRS(RANGE_LIMITED) }, + { CRS(COEFFICIENTS_BT709), CRS(RANGE_FULL) }, + { CRS(COEFFICIENTS_BT2020), CRS(RANGE_LIMITED) }, + { CRS(COEFFICIENTS_BT2020), CRS(RANGE_FULL) }, +}; +#undef CRS + +WL_EXPORT void +weston_reset_color_representation(struct weston_color_representation *color_rep) +{ + color_rep->alpha_mode = WESTON_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL; + color_rep->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_UNSET; + color_rep->quant_range = WESTON_COLOR_QUANT_RANGE_UNSET; + color_rep->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_UNSET; +} + +WL_EXPORT struct weston_color_representation +weston_fill_color_representation(const struct weston_color_representation *color_rep_in, + const struct pixel_format_info *info) +{ + struct weston_color_representation color_rep; + + color_rep = *color_rep_in; + + if (color_rep.matrix_coefficients == WESTON_COLOR_MATRIX_COEF_UNSET) { + if (info->color_model == COLOR_MODEL_YUV) + color_rep.matrix_coefficients = + WESTON_COLOR_MATRIX_COEF_BT709; + else + color_rep.matrix_coefficients = + WESTON_COLOR_MATRIX_COEF_IDENTITY; + } + if (color_rep.quant_range == WESTON_COLOR_QUANT_RANGE_UNSET) { + if (info->color_model == COLOR_MODEL_YUV) + color_rep.quant_range = WESTON_COLOR_QUANT_RANGE_LIMITED; + else + color_rep.quant_range = WESTON_COLOR_QUANT_RANGE_FULL; + } + + return color_rep; +} + + +WL_EXPORT bool +weston_color_representation_equal(struct weston_color_representation *color_rep_A, + struct weston_color_representation *color_rep_B, + enum weston_cr_comparison_flag flags) +{ + if (!(flags & WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA) && + color_rep_A->alpha_mode != color_rep_B->alpha_mode) + return false; + + if (!(flags & WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION) && + color_rep_A->chroma_location != color_rep_B->chroma_location) + return false; + + return (color_rep_A->matrix_coefficients == color_rep_B->matrix_coefficients && + color_rep_A->quant_range == color_rep_B->quant_range); +} + +WL_EXPORT void +weston_get_color_representation_matrix(struct weston_compositor *compositor, + enum weston_color_matrix_coef coefficients, + enum weston_color_quant_range range, + struct weston_color_representation_matrix *cr_matrix) +{ + /* The values in this function are copied from Mesa and may not be + * optimal or correct in all cases. */ + + if (range == WESTON_COLOR_QUANT_RANGE_FULL) { + cr_matrix->offset = + WESTON_VEC3F(0.0, 128.0 / 255.0, 128.0 / 255.0); + + switch(coefficients) { + case WESTON_COLOR_MATRIX_COEF_BT601: + cr_matrix->matrix = + WESTON_MAT3F(1.0, 0.0, 1.402, + 1.0, -0.34413629, -0.71413629, + 1.0, 1.772, 0.0); + return; + case WESTON_COLOR_MATRIX_COEF_BT709: + cr_matrix->matrix = + WESTON_MAT3F(1.0, 0.0, 1.5748, + 1.0, -0.18732427, -0.46812427, + 1.0, 1.8556, 0.0); + return; + case WESTON_COLOR_MATRIX_COEF_BT2020: + cr_matrix->matrix = + WESTON_MAT3F(1.0, 0.0, 1.4746, + 1.0, -0.16455313, -0.57139187, + 1.0, 1.8814, 0.0); + return; + default: + break; + } + } else if (range == WESTON_COLOR_QUANT_RANGE_LIMITED) { + cr_matrix->offset = + WESTON_VEC3F(16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0); + + switch(coefficients) { + case WESTON_COLOR_MATRIX_COEF_BT601: + cr_matrix->matrix = + WESTON_MAT3F(255.0 / 219.0, 0.0, 1.59602678, + 255.0 / 219.0, -0.39176229, -0.81296764, + 255.0 / 219.0, 2.01723214, 0.0); + return; + case WESTON_COLOR_MATRIX_COEF_BT709: + cr_matrix->matrix = + WESTON_MAT3F(255.0 / 219.0, 0.0, 1.79274107, + 255.0 / 219.0, -0.21324861, -0.53290933, + 255.0 / 219.0, 2.11240179, 0.0); + return; + case WESTON_COLOR_MATRIX_COEF_BT2020: + cr_matrix->matrix = + WESTON_MAT3F(255.0 / 219.0, 0.0, 1.67878795, + 255.0 / 219.0, -0.18732610, -0.65046843, + 255.0 / 219.0, 2.14177232, 0.0); + return; + default: + break; + } + } + + weston_assert_not_reached(compositor, + "unknown coefficients or range value"); +} + +bool +weston_surface_check_pending_color_representation_valid( + const struct weston_surface *surface) +{ + const struct weston_surface_state *pend = &surface->pending; + const struct weston_color_representation *cr = + &pend->color_representation; + struct weston_buffer *buffer = NULL; + bool format_is_yuv; + + if (!surface->color_representation_resource) + return true; + + if (cr->matrix_coefficients == WESTON_COLOR_MATRIX_COEF_UNSET && + cr->quant_range == WESTON_COLOR_QUANT_RANGE_UNSET) + return true; + + assert(cr->matrix_coefficients != WESTON_COLOR_MATRIX_COEF_UNSET && + cr->quant_range != WESTON_COLOR_QUANT_RANGE_UNSET); + + if (pend->status & WESTON_SURFACE_DIRTY_BUFFER) { + buffer = pend->buffer_ref.buffer; + } else if (surface->buffer_ref.buffer) { + buffer = surface->buffer_ref.buffer; + } + + if (!buffer) + return true; + + format_is_yuv = buffer->pixel_format->color_model == COLOR_MODEL_YUV; + if ((format_is_yuv && + cr->matrix_coefficients == WESTON_COLOR_MATRIX_COEF_IDENTITY) || + (!format_is_yuv && + cr->matrix_coefficients != WESTON_COLOR_MATRIX_COEF_IDENTITY)) { + wl_resource_post_error(surface->color_representation_resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT, + "wp_color_representation_surface_v1@%"PRIu32" " + "Buffer format %s not compatible " + "with matrix coefficients %u", + wl_resource_get_id(surface->resource), + buffer->pixel_format->drm_format_name, + cr->matrix_coefficients); + return false; + } + + return true; +} + +static void +destroy_color_representation(struct wl_resource *resource) +{ + struct weston_surface *surface = + wl_resource_get_user_data(resource); + + if (!surface) + return; + + surface->color_representation_resource = NULL; + weston_reset_color_representation(&surface->pending.color_representation); +} + +static void +cr_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +cr_set_alpha_mode(struct wl_client *client, + struct wl_resource *resource, + uint32_t alpha_mode) +{ + struct weston_surface *surface = + wl_resource_get_user_data(resource); + bool supported = false; + + if (!surface) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT, + "wp_color_representation_surface_v1@%"PRIu32" " + "The object is inert.", + wl_resource_get_id(resource)); + return; + } + + weston_assert_ptr_eq(surface->compositor, + surface->color_representation_resource, resource); + + for (unsigned int i = 0; i < ARRAY_LENGTH(supported_alpha_modes); i++) { + if (supported_alpha_modes[i] == alpha_mode) { + supported = true; + break; + } + } + if (!supported) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE, + "wp_color_representation_surface_v1@%"PRIu32" " + "Invalid alpha mode (%u)", + wl_resource_get_id(resource), alpha_mode); + return; + } + + surface->pending.color_representation.alpha_mode = alpha_mode; +} + +static void +cr_set_coefficients_and_range(struct wl_client *client, + struct wl_resource *resource, + uint32_t coefficients, + uint32_t range) +{ + struct weston_surface *surface = + wl_resource_get_user_data(resource); + struct weston_color_representation *color_representation; + bool supported = false; + + if (!surface) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT, + "wp_color_representation_surface_v1@%"PRIu32" " + "The object is inert.", + wl_resource_get_id(resource)); + return; + } + + weston_assert_ptr_eq(surface->compositor, + surface->color_representation_resource, resource); + + color_representation = &surface->pending.color_representation; + + for (unsigned int i = 0; i < ARRAY_LENGTH(supported_coeffs_and_ranges); i++) { + if (supported_coeffs_and_ranges[i].coefficients == coefficients && + supported_coeffs_and_ranges[i].range == range) { + supported = true; + break; + } + } + if (!supported) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS, + "wp_color_representation_surface_v1@%"PRIu32" " + "Invalid coefficients (%u) or range (%u).", + wl_resource_get_id(resource), coefficients, range); + return; + } + + switch (coefficients) { + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY: + color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_IDENTITY; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709: + color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT709; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601: + color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT601; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020: + color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT2020; + break; + default: + weston_assert_not_reached(surface->compositor, "unsupported coefficients"); + } + + switch (range) { + case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL: + color_representation->quant_range = WESTON_COLOR_QUANT_RANGE_FULL; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED: + color_representation->quant_range = WESTON_COLOR_QUANT_RANGE_LIMITED; + break; + default: + weston_assert_not_reached(surface->compositor, "unsupported range"); + } +} + +static void +cr_set_chroma_location(struct wl_client *client, + struct wl_resource *resource, + uint32_t chroma_location) +{ + struct weston_surface *surface = + wl_resource_get_user_data(resource); + struct weston_color_representation *color_representation; + + if (!surface) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT, + "wp_color_representation_surface_v1@%"PRIu32" " + "The object is inert.", + wl_resource_get_id(resource)); + return; + } + + weston_assert_ptr_eq(surface->compositor, + surface->color_representation_resource, resource); + + color_representation = &surface->pending.color_representation; + + switch (chroma_location) { + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_0: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_0; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_1: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_1; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_2: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_2; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_3: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_3; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_4: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_4; + break; + case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_5: + color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_5; + break; + default: + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_CHROMA_LOCATION, + "wp_color_representation_surface_v1@%"PRIu32" " + "Invalid chroma location (%u).", + wl_resource_get_id(resource), + chroma_location); + return; + } +} + +static const struct wp_color_representation_surface_v1_interface cr_implementation = { + .destroy = cr_destroy, + .set_alpha_mode = cr_set_alpha_mode, + .set_coefficients_and_range = cr_set_coefficients_and_range, + .set_chroma_location = cr_set_chroma_location, +}; + +static void +cr_manager_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +cr_manager_get_surface(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + struct weston_surface *surface = + wl_resource_get_user_data(surface_resource); + struct wl_resource *color_representation_resource; + + if (surface->color_representation_resource) { + wl_resource_post_error(resource, + WP_COLOR_REPRESENTATION_MANAGER_V1_ERROR_SURFACE_EXISTS, + "a color representation surface for that surface already exists"); + return; + } + + color_representation_resource = wl_resource_create(client, + &wp_color_representation_surface_v1_interface, + wl_resource_get_version(resource), id); + if (color_representation_resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(color_representation_resource, + &cr_implementation, surface, destroy_color_representation); + + surface->color_representation_resource = color_representation_resource; +} + +static const struct wp_color_representation_manager_v1_interface +cr_manager_implementation = { + .destroy = cr_manager_destroy, + .get_surface = cr_manager_get_surface, +}; + +static void +bind_color_representation(struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + struct weston_compositor *compositor = data; + + resource = wl_resource_create(client, + &wp_color_representation_manager_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &cr_manager_implementation, + compositor, NULL); + + for (unsigned int i = 0; i < ARRAY_LENGTH(supported_alpha_modes); i++) { + wp_color_representation_manager_v1_send_supported_alpha_mode( + resource, + supported_alpha_modes[i]); + } + + for (unsigned int i = 0; i < ARRAY_LENGTH(supported_coeffs_and_ranges); i++) { + wp_color_representation_manager_v1_send_supported_coefficients_and_ranges( + resource, + supported_coeffs_and_ranges[i].coefficients, + supported_coeffs_and_ranges[i].range); + } + + wp_color_representation_manager_v1_send_done(resource); +} + +/** Advertise color-representation support + * + * Calling this initializes the color-representation protocol support, so that + * wp_color_representation_manager_v1_interface will be advertised to clients. + * Essentially it creates a global. Do not call this function multiple times in + * the compositor's lifetime. There is no way to deinit explicitly, globals will + * be reaped when the wl_display gets destroyed. + * + * \param compositor The compositor to init for. + * \return Zero on success, -1 on failure. + */ +int +weston_compositor_enable_color_representation_protocol(struct weston_compositor *compositor) +{ + uint32_t version = 1; + + if (!(compositor->capabilities & WESTON_CAP_COLOR_REP)) { + weston_log("Color representation not supported by renderer\n"); + return 0; + } + + if (!wl_global_create(compositor->wl_display, + &wp_color_representation_manager_v1_interface, + version, compositor, bind_color_representation)) + return -1; + + return 0; +} + +static const struct weston_color_matrix_coef_info color_matrix_coef_info_map[] = { + { WESTON_COLOR_MATRIX_COEF_UNSET, "unset", WDRM_PLANE_COLOR_ENCODING__COUNT }, + { WESTON_COLOR_MATRIX_COEF_IDENTITY, "default", WDRM_PLANE_COLOR_ENCODING__COUNT }, + { WESTON_COLOR_MATRIX_COEF_BT601, "BT.601", WDRM_PLANE_COLOR_ENCODING_BT601 }, + { WESTON_COLOR_MATRIX_COEF_BT709, "BT.709", WDRM_PLANE_COLOR_ENCODING_BT709 }, + { WESTON_COLOR_MATRIX_COEF_BT2020, "BT.2020", WDRM_PLANE_COLOR_ENCODING_BT2020 }, +}; + +WL_EXPORT const struct weston_color_matrix_coef_info * +weston_color_matrix_coef_info_get(enum weston_color_matrix_coef coefficients) +{ + for (unsigned i = 0; i < ARRAY_LENGTH(color_matrix_coef_info_map); i++) + if (color_matrix_coef_info_map[i].coefficients == coefficients) + return &color_matrix_coef_info_map[i]; + + return NULL; +} + +static const struct weston_color_quant_range_info color_quant_range_info_map[] = { + { WESTON_COLOR_QUANT_RANGE_UNSET, "unset", WDRM_PLANE_COLOR_RANGE__COUNT }, + { WESTON_COLOR_QUANT_RANGE_FULL, "full", WDRM_PLANE_COLOR_RANGE_FULL }, + { WESTON_COLOR_QUANT_RANGE_LIMITED, "limited", WDRM_PLANE_COLOR_RANGE_LIMITED }, +}; + +WL_EXPORT const struct weston_color_quant_range_info * +weston_color_quant_range_info_get(enum weston_color_quant_range range) +{ + for (unsigned i = 0; i < ARRAY_LENGTH(color_quant_range_info_map); i++) + if (color_quant_range_info_map[i].range == range) + return &color_quant_range_info_map[i]; + + return NULL; +} diff --git a/libweston/color-representation.h b/libweston/color-representation.h new file mode 100644 index 000000000..18cb41da5 --- /dev/null +++ b/libweston/color-representation.h @@ -0,0 +1,78 @@ +/* + * Copyright 2025 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. + */ + +#pragma once + +#include + +#include "backend-drm/drm-kms-enums.h" + +void +weston_reset_color_representation(struct weston_color_representation *color_rep); + +struct weston_color_representation +weston_fill_color_representation(const struct weston_color_representation *color_rep_in, + const struct pixel_format_info *info); + +enum weston_cr_comparison_flag { + WESTON_CR_COMPARISON_FLAG_NONE = 0, + WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA = 1, + WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION = 2, +}; + +bool +weston_color_representation_equal(struct weston_color_representation *color_rep_A, + struct weston_color_representation *color_rep_B, + enum weston_cr_comparison_flag flags); + +void +weston_get_color_representation_matrix(struct weston_compositor *compositor, + enum weston_color_matrix_coef coefficients, + enum weston_color_quant_range range, + struct weston_color_representation_matrix *cr_matrix); + +bool +weston_surface_check_pending_color_representation_valid(const struct weston_surface *surface); + +int +weston_compositor_enable_color_representation_protocol(struct weston_compositor *compositor); + +struct weston_color_quant_range_info { + enum weston_color_quant_range range; + const char *name; + enum wdrm_plane_color_range wdrm; +}; + +const struct weston_color_quant_range_info * +weston_color_quant_range_info_get(enum weston_color_quant_range range); + +struct weston_color_matrix_coef_info { + enum weston_color_matrix_coef coefficients; + const char *name; + enum wdrm_plane_color_encoding wdrm; +}; + +const struct weston_color_matrix_coef_info * +weston_color_matrix_coef_info_get(enum weston_color_matrix_coef coefficients); diff --git a/libweston/compositor.c b/libweston/compositor.c index f5f0aeaea..a72e028c8 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -84,6 +84,7 @@ #include "libweston-internal.h" #include "color.h" #include "color-management.h" +#include "color-representation.h" #include "id-number-allocator.h" #include "output-capture.h" #include "pixman-renderer.h" @@ -1014,6 +1015,8 @@ weston_surface_create(struct weston_compositor *compositor) /* Also part of the CM&HDR protocol extension implementation. */ weston_surface_update_preferred_color_profile(surface); + weston_reset_color_representation(&surface->color_representation); + wl_list_init(&surface->fifo_barrier_link); return surface; @@ -2757,6 +2760,11 @@ destroy_surface(struct wl_resource *resource) NULL); } + if (surface->color_representation_resource) { + wl_resource_set_user_data(surface->color_representation_resource, + NULL); + } + weston_surface_unref(surface); } @@ -5063,6 +5071,9 @@ surface_commit(struct wl_client *client, struct wl_resource *resource) return; } + if (!weston_surface_check_pending_color_representation_valid(surface)) + return; + weston_surface_commit(surface); } @@ -10136,6 +10147,9 @@ weston_compositor_backends_loaded(struct weston_compositor *compositor) return -1; } + if (weston_compositor_enable_color_representation_protocol(compositor) < 0) + return -1; + return 0; } diff --git a/libweston/meson.build b/libweston/meson.build index 83d39e494..7c2fc1262 100644 --- a/libweston/meson.build +++ b/libweston/meson.build @@ -18,6 +18,7 @@ srcs_libweston = [ 'color.c', 'color-properties.c', 'color-management.c', + 'color-representation.c', 'color-noop.c', 'color-operations.c', 'color-profile-param-builder.c', @@ -49,6 +50,8 @@ srcs_libweston = [ 'weston-direct-display.c', color_management_v1_protocol_c, color_management_v1_server_protocol_h, + color_representation_v1_protocol_c, + color_representation_v1_server_protocol_h, commit_timing_v1_protocol_c, commit_timing_v1_server_protocol_h, fifo_v1_protocol_c, diff --git a/libweston/surface-state.c b/libweston/surface-state.c index 01d886718..6617d69a6 100644 --- a/libweston/surface-state.c +++ b/libweston/surface-state.c @@ -34,6 +34,7 @@ #include "libweston-internal.h" #include "backend.h" +#include "color-representation.h" #include "pixel-formats.h" #include "shared/fd-util.h" #include "shared/timespec-util.h" @@ -156,6 +157,8 @@ weston_surface_state_init(struct weston_surface *surface, state->color_profile = NULL; state->render_intent = NULL; + weston_reset_color_representation(&state->color_representation); + state->fifo_barrier = false; state->fifo_wait = false; @@ -376,6 +379,11 @@ weston_surface_apply_state(struct weston_surface *surface, /* wp_presentation.feedback */ weston_presentation_feedback_discard_list(&surface->feedback_list); + /* wp_color_representation_v1.set_alpha_mode */ + /* wp_color_representation_v1.set_coefficients_and_range */ + /* wp_color_representation_v1.set_chroma_location */ + surface->color_representation = state->color_representation; + /* wl_surface.attach */ if (status & WESTON_SURFACE_DIRTY_BUFFER) { /* zwp_surface_synchronization_v1.set_acquire_fence */ @@ -650,6 +658,8 @@ weston_surface_state_merge_from(struct weston_surface_state *dst, dst->buffer_viewport.buffer = src->buffer_viewport.buffer; dst->buffer_viewport.surface = src->buffer_viewport.surface; + dst->color_representation = src->color_representation; + weston_buffer_reference(&src->buffer_ref, NULL, BUFFER_WILL_NOT_BE_ACCESSED); diff --git a/protocol/meson.build b/protocol/meson.build index 3935bac76..bf91b6970 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -1,7 +1,7 @@ dep_scanner = dependency('wayland-scanner', native: true) prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner')) -dep_wp = dependency('wayland-protocols', version: '>= 1.41', +dep_wp = dependency('wayland-protocols', version: '>= 1.46', fallback: ['wayland-protocols', 'wayland_protocols']) dir_wp_base = dep_wp.get_variable(pkgconfig: 'pkgdatadir', internal: 'pkgdatadir') @@ -17,6 +17,7 @@ install_data( generated_protocols = [ [ 'color-management', 'staging', 'v1' ], + [ 'color-representation', 'staging', 'v1' ], [ 'commit-timing', 'staging', 'v1' ], [ 'fifo', 'staging', 'v1' ], [ 'fullscreen-shell', 'unstable', 'v1' ],