libweston: Implement color-representation protocol

For now limited to coefficients and ranges that are typically
supported by KMS drivers. We notably leave out alpha modes and
chroma locations for now.

The protocol initialization is guarded by the WESTON_CAP_COLOR_REP
backend capability and thus not enabled anywhere yet.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
This commit is contained in:
Robert Mader 2024-05-11 12:39:28 +02:00
parent f7aa35e9d2
commit 32f6148afd
9 changed files with 715 additions and 1 deletions

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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;
}

View file

@ -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 <libweston/libweston.h>
#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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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' ],