libweston: add colorimetry_mode API

This API is mostly for use by the DRM-backend. Colorimetry mode is is
the KMS connector property "Colorspace" which defines the video signal
encoding colorimetry. A video sink indicates the supported modes in EDID
or DisplayID.

This patch adds the libweston API that allows backends to indicate the
supported modes for the frontends, and frontends to set the mode to be
used by backends. Colorimetry mode does not directly affect color
management inside Weston, it is only metadata for the video sink. It is
the frontend's responsibility to set up an output color profile that
agrees with the colorimetry mode. (That API has not been implemented
yet.) eotf_mode will be the same.

There is only one reason to make this a libweston core API instead of
a backend-drm API: when wayland-backend gains color-management protocol
support, meaning it can forward WCG and HDR content correctly to a
host compositor, the supported colorimetry modes can be determined from
the host compositor's supported color-management features, allowing the
guest Weston to pick some other output image description than the host
compositor's preferred image description. This likely allows only a few
other choices from standard colorspaces, so it's possible this isn't
sufficient for that use case.

Either way, it is easy to just copy the eotf_mode API design, and since
colorimetry_mode and eotf_mode go together, let both have the same API
design. It is possible to convert this to backend-drm API later.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2023-09-01 14:50:20 +03:00 committed by Pekka Paalanen
parent cd622900ee
commit 53493aaddc
5 changed files with 251 additions and 2 deletions

View file

@ -222,6 +222,55 @@ struct weston_testsuite_data {
void *test_private_data;
};
/** Colorimetry mode for outputs and heads
*
* A list of colorimetry modes for driving displays, defined by ANSI/CTA-861-H.
*
* On heads, a bitmask of one or more entries shows which modes are claimed
* supported.
*
* On outputs, the mode to be used for driving the video sink.
*
* Default (RGB) colorimetry differs from all the others in that the signal
* colorimetry is not defined here. It is defined by the video sink, and it
* may be described in e.g. EDID.
*/
enum weston_colorimetry_mode {
/** Invalid colorimetry mode, or none supported. */
WESTON_COLORIMETRY_MODE_NONE = 0,
/** Default (RGB) colorimetry, video sink dependant */
WESTON_COLORIMETRY_MODE_DEFAULT = 0x01,
/** Rec. ITU-R BT.2020 constant luminance YCbCr */
WESTON_COLORIMETRY_MODE_BT2020_CYCC = 0x02,
/** Rec. ITU-R BT.2020 non-constant luminance YCbCr */
WESTON_COLORIMETRY_MODE_BT2020_YCC = 0x04,
/** Rec. ITU-R BT.2020 RGB */
WESTON_COLORIMETRY_MODE_BT2020_RGB = 0x08,
/** SMPTE ST 2113 DCI-P3 RGB D65 */
WESTON_COLORIMETRY_MODE_P3D65 = 0x10,
/** SMPTE ST 2113 DCI-P3 RGB Theater */
WESTON_COLORIMETRY_MODE_P3DCI = 0x20,
/** Rec. ITU-R BT.2100 ICtCp HDR (with PQ and/or HLG)*/
WESTON_COLORIMETRY_MODE_ICTCP = 0x40,
};
/** Bitmask of all defined colorimetry modes */
#define WESTON_COLORIMETRY_MODE_ALL_MASK \
((uint32_t)(WESTON_COLORIMETRY_MODE_DEFAULT | \
WESTON_COLORIMETRY_MODE_BT2020_CYCC | \
WESTON_COLORIMETRY_MODE_BT2020_YCC | \
WESTON_COLORIMETRY_MODE_BT2020_RGB | \
WESTON_COLORIMETRY_MODE_P3D65 | \
WESTON_COLORIMETRY_MODE_P3DCI | \
WESTON_COLORIMETRY_MODE_ICTCP))
/** EOTF mode for outputs and heads
*
* A list of EOTF modes for driving displays, defined by CTA-861-G for
@ -351,6 +400,7 @@ struct weston_head {
bool connected; /**< is physically connected */
bool non_desktop; /**< non-desktop display, e.g. HMD */
uint32_t supported_eotf_mask; /**< supported weston_eotf_mode bits */
uint32_t supported_colorimetry_mask; /**< supported weston_colorimetry_mode bits */
/** Current content protection status */
enum weston_hdcp_protection current_protection;
@ -501,6 +551,7 @@ struct weston_output {
struct weston_color_profile *color_profile;
bool from_blend_to_output_by_backend;
enum weston_eotf_mode eotf_mode;
enum weston_colorimetry_mode colorimetry_mode;
struct weston_color_characteristics color_characteristics;
struct weston_output_color_outcome *color_outcome;
@ -2531,6 +2582,13 @@ weston_output_set_eotf_mode(struct weston_output *output,
enum weston_eotf_mode
weston_output_get_eotf_mode(const struct weston_output *output);
void
weston_output_set_colorimetry_mode(struct weston_output *output,
enum weston_colorimetry_mode colorimetry_mode);
enum weston_colorimetry_mode
weston_output_get_colorimetry_mode(const struct weston_output *output);
void
weston_output_set_color_characteristics(struct weston_output *output,
const struct weston_color_characteristics *cc);
@ -2556,6 +2614,9 @@ weston_output_disable(struct weston_output *output);
uint32_t
weston_output_get_supported_eotf_modes(struct weston_output *output);
uint32_t
weston_output_get_supported_colorimetry_modes(struct weston_output *output);
void
weston_output_power_off(struct weston_output *output);

View file

@ -159,6 +159,10 @@ void
weston_head_set_supported_eotf_mask(struct weston_head *head,
uint32_t eotf_mask);
void
weston_head_set_supported_colorimetry_mask(struct weston_head *head,
uint32_t colorimetry_mask);
/* weston_output */
void

View file

@ -40,6 +40,7 @@
#include "id-number-allocator.h"
#include "libweston-internal.h"
#include <libweston/weston-log.h>
#include "shared/helpers.h"
#include "shared/xalloc.h"
/**
@ -448,3 +449,56 @@ weston_eotf_mask_to_str(uint32_t eotf_mask)
{
return bits_to_str(eotf_mask, weston_eotf_mode_to_str);
}
static const struct weston_colorimetry_mode_info colorimetry_mode_info_map[] = {
{ WESTON_COLORIMETRY_MODE_NONE, "(none)", WDRM_COLORSPACE__COUNT },
{ WESTON_COLORIMETRY_MODE_DEFAULT, "default", WDRM_COLORSPACE_DEFAULT },
{ WESTON_COLORIMETRY_MODE_BT2020_CYCC, "BT.2020 (cYCC)", WDRM_COLORSPACE_BT2020_CYCC },
{ WESTON_COLORIMETRY_MODE_BT2020_YCC, "BT.2020 (YCC)", WDRM_COLORSPACE_BT2020_YCC },
{ WESTON_COLORIMETRY_MODE_BT2020_RGB, "BT.2020 (RGB)", WDRM_COLORSPACE_BT2020_RGB },
{ WESTON_COLORIMETRY_MODE_P3D65, "DCI-P3 RGB D65", WDRM_COLORSPACE_DCI_P3_RGB_D65 },
{ WESTON_COLORIMETRY_MODE_P3DCI, "DCI-P3 RGB Theatre", WDRM_COLORSPACE_DCI_P3_RGB_THEATER },
{ WESTON_COLORIMETRY_MODE_ICTCP, "BT.2100 ICtCp", WDRM_COLORSPACE__COUNT },
};
/** Get information structure of colorimetry mode
*
* \internal
*/
WL_EXPORT const struct weston_colorimetry_mode_info *
weston_colorimetry_mode_info_get(enum weston_colorimetry_mode c)
{
unsigned i;
for (i = 0; i < ARRAY_LENGTH(colorimetry_mode_info_map); i++)
if (colorimetry_mode_info_map[i].mode == c)
return &colorimetry_mode_info_map[i];
return NULL;
}
/** Get a string naming the colorimetry mode
*
* \internal
*/
WL_EXPORT const char *
weston_colorimetry_mode_to_str(enum weston_colorimetry_mode c)
{
const struct weston_colorimetry_mode_info *info;
info = weston_colorimetry_mode_info_get(c);
return info ? info->name : "???";
}
/** A list of colorimetry modes as a string
*
* \param colorimetry_mask Bitwise-or'd enum weston_colorimetry_mode values.
* \return Comma separated names of the listed colorimetry modes.
* Must be free()'d by the caller.
*/
WL_EXPORT char *
weston_colorimetry_mask_to_str(uint32_t colorimetry_mask)
{
return bits_to_str(colorimetry_mask, weston_colorimetry_mode_to_str);
}

View file

@ -31,6 +31,8 @@
#include <stdint.h>
#include <libweston/libweston.h>
#include "backend-drm/drm-kms-enums.h"
enum weston_hdr_metadata_type1_groups {
/** weston_hdr_metadata_type1::primary is set */
WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES = 0x01,
@ -548,6 +550,26 @@ weston_eotf_mode_to_str(enum weston_eotf_mode e);
char *
weston_eotf_mask_to_str(uint32_t eotf_mask);
struct weston_colorimetry_mode_info {
/** Primary key: the colorimetry mode */
enum weston_colorimetry_mode mode;
/** Its name as a string for logging. */
const char *name;
/** wdrm equivalent, or WDRM_COLORSPACE__COUNT if none */
enum wdrm_colorspace wdrm;
};
const struct weston_colorimetry_mode_info *
weston_colorimetry_mode_info_get(enum weston_colorimetry_mode c);
const char *
weston_colorimetry_mode_to_str(enum weston_colorimetry_mode c);
char *
weston_colorimetry_mask_to_str(uint32_t colorimetry_mask);
void
weston_output_color_outcome_destroy(struct weston_output_color_outcome **pco);

View file

@ -6213,6 +6213,7 @@ weston_head_init(struct weston_head *head, const char *name)
wl_list_init(&head->cm_output_resource_list);
head->name = xstrdup(name);
head->supported_eotf_mask = WESTON_EOTF_MODE_SDR;
head->supported_colorimetry_mask = WESTON_COLORIMETRY_MODE_DEFAULT;
head->current_protection = WESTON_HDCP_DISABLE;
weston_head_set_monitor_strings(head, NULL, NULL, NULL);
@ -6816,6 +6817,32 @@ weston_head_set_supported_eotf_mask(struct weston_head *head,
weston_head_set_device_changed(head);
}
/** Store the set of supported colorimetry modes
*
* \param head The head to modify.
* \param colorimetry_mask A bit mask with the possible bits or'ed together from
* enum weston_colorimetry_mode.
*
* This may set the device_changed flag.
*
* \ingroup head
* \internal
*/
WL_EXPORT void
weston_head_set_supported_colorimetry_mask(struct weston_head *head,
uint32_t colorimetry_mask)
{
weston_assert_legal_bits(head->compositor,
colorimetry_mask, WESTON_COLORIMETRY_MODE_ALL_MASK);
if (head->supported_colorimetry_mask == colorimetry_mask)
return;
head->supported_colorimetry_mask = colorimetry_mask;
weston_head_set_device_changed(head);
}
WL_EXPORT void
weston_head_set_content_protection_status(struct weston_head *head,
enum weston_hdcp_protection status)
@ -7681,6 +7708,56 @@ weston_output_get_eotf_mode(const struct weston_output *output)
return output->eotf_mode;
}
/** Set colorimetry mode on an output
*
* \param output The output to modify, must be in disabled state.
* \param colorimetry_mode The colorimetry mode to set.
*
* Setting the output colorimetry mode is used for choosing the video signal
* encoding colorimetry. This is purely metadata to be sent to the video sink,
* intended to allow the video sink to decode the sent pixels correctly.
* This may be used to enable wide color gamut modes. ST2084 and HLG EOTF modes
* for HDR tend to use BT.2020 colorimetry mode.
*
* Only backends that directly drive a video sink might use this information
* (DRM-backend).
*
* After attaching heads to an output, you can find out the possibly supported
* colorimetry modes with weston_output_get_supported_colorimetry_modes().
*
* This function does not check whether the given colorimetry_mode is actually
* supported on the output. Enabling an output with an unsupported colorimetry
* mode has undefined visual results.
*
* TODO: Enforce mode validity.
*
* The initial colorimetry mode is DEFAULT.
*
* \ingroup output
*/
WL_EXPORT void
weston_output_set_colorimetry_mode(struct weston_output *output,
enum weston_colorimetry_mode colorimetry_mode)
{
weston_assert_false(output->compositor, output->enabled);
output->colorimetry_mode = colorimetry_mode;
}
/** Get colorimetry mode of an output
*
* \param output The output to query.
* \return The colorimetry mode.
*
* \sa weston_output_set_colorimetry_mode
* \ingroup output
*/
WL_EXPORT enum weston_colorimetry_mode
weston_output_get_colorimetry_mode(const struct weston_output *output)
{
return output->colorimetry_mode;
}
/** Get HDR static metadata type 1
*
* \param output The output to query.
@ -7812,6 +7889,7 @@ weston_output_init(struct weston_output *output,
wl_signal_init(&output->user_destroy_signal);
output->enabled = false;
output->eotf_mode = WESTON_EOTF_MODE_SDR;
output->colorimetry_mode = WESTON_COLORIMETRY_MODE_DEFAULT;
output->desired_protection = WESTON_HDCP_DISABLE;
output->allow_protection = true;
output->power_state = WESTON_OUTPUT_POWER_NORMAL;
@ -7975,8 +8053,10 @@ weston_output_enable(struct weston_output *output)
weston_output_update_matrix(output);
weston_log("Output '%s' attempts EOTF mode: %s\n", output->name,
weston_eotf_mode_to_str(output->eotf_mode));
weston_log("Output '%s' attempts EOTF mode %s and colorimetry mode %s.\n",
output->name,
weston_eotf_mode_to_str(output->eotf_mode),
weston_colorimetry_mode_to_str(output->colorimetry_mode));
if (!weston_output_set_color_outcome(output))
return -1;
@ -8324,6 +8404,34 @@ weston_output_get_supported_eotf_modes(struct weston_output *output)
return eotf_modes;
}
/** Get supported colorimetry modes as a bit mask
*
* \param output The output to query.
* \return A bit mask with values from enum weston_colorimetry_mode or'ed together.
*
* Returns the intersection of the colorimetry modes supported by the currently
* attached heads as a bit mask. Adding or removing heads may change the result.
* An output can be queried regardless of whether it is enabled or disabled.
*
* If no heads are attached, no colorimetry modes are deemed supported.
*
* \ingroup output
*/
WL_EXPORT uint32_t
weston_output_get_supported_colorimetry_modes(struct weston_output *output)
{
uint32_t colorimetry_modes = WESTON_COLORIMETRY_MODE_ALL_MASK;
struct weston_head *head;
if (wl_list_empty(&output->head_list))
return WESTON_COLORIMETRY_MODE_NONE;
wl_list_for_each(head, &output->head_list, output_link)
colorimetry_modes = colorimetry_modes & head->supported_colorimetry_mask;
return colorimetry_modes;
}
/* Set the forced-power state of output
*
* \param output The output to set power state.