Skip to content
Commits on Source (16)
......@@ -1404,9 +1404,10 @@ wet_output_set_color_profile(struct weston_output *output,
return ok ? 0 : -1;
}
static int
WESTON_EXPORT_FOR_TESTS int
wet_output_set_eotf_mode(struct weston_output *output,
struct weston_config_section *section)
struct weston_config_section *section,
bool have_color_manager)
{
static const struct {
const char *name;
......@@ -1417,13 +1418,10 @@ wet_output_set_eotf_mode(struct weston_output *output,
{ "st2084", WESTON_EOTF_MODE_ST2084 },
{ "hlg", WESTON_EOTF_MODE_HLG },
};
struct wet_compositor *compositor;
enum weston_eotf_mode eotf_mode = WESTON_EOTF_MODE_SDR;
char *str = NULL;
unsigned i;
compositor = to_wet_compositor(output->compositor);
if (section) {
weston_config_section_get_string(section, "eotf-mode",
&str, NULL);
......@@ -1446,6 +1444,7 @@ wet_output_set_eotf_mode(struct weston_output *output,
for (i = 0; i < ARRAY_LENGTH(modes); i++)
weston_log_continue(" %s", modes[i].name);
weston_log_continue("\n");
free(str);
return -1;
}
eotf_mode = modes[i].eotf_mode;
......@@ -1461,8 +1460,7 @@ wet_output_set_eotf_mode(struct weston_output *output,
return -1;
}
if (eotf_mode != WESTON_EOTF_MODE_SDR &&
!compositor->use_color_manager) {
if (eotf_mode != WESTON_EOTF_MODE_SDR && !have_color_manager) {
weston_log("Error: EOTF mode %s on output '%s' requires color-management=true in weston.ini\n",
str, output->name);
free(str);
......@@ -1475,6 +1473,79 @@ wet_output_set_eotf_mode(struct weston_output *output,
return 0;
}
WESTON_EXPORT_FOR_TESTS int
wet_output_set_colorimetry_mode(struct weston_output *output,
struct weston_config_section *section,
bool have_color_manager)
{
static const struct {
const char *name;
enum weston_colorimetry_mode cmode;
} modes[] = {
{ "default", WESTON_COLORIMETRY_MODE_DEFAULT },
{ "bt2020cycc", WESTON_COLORIMETRY_MODE_BT2020_CYCC },
{ "bt2020ycc", WESTON_COLORIMETRY_MODE_BT2020_YCC },
{ "bt2020rgb", WESTON_COLORIMETRY_MODE_BT2020_RGB },
{ "p3d65", WESTON_COLORIMETRY_MODE_P3D65 },
{ "p3dci", WESTON_COLORIMETRY_MODE_P3DCI },
{ "ictcp", WESTON_COLORIMETRY_MODE_ICTCP },
};
enum weston_colorimetry_mode cmode = WESTON_COLORIMETRY_MODE_DEFAULT;
char *str = NULL;
unsigned i;
if (section) {
weston_config_section_get_string(section, "colorimetry-mode",
&str, NULL);
}
if (!str) {
/* The default RGB mode is always supported. */
assert(weston_output_get_supported_colorimetry_modes(output) & cmode);
weston_output_set_colorimetry_mode(output, cmode);
return 0;
}
for (i = 0; i < ARRAY_LENGTH(modes); i++)
if (strcmp(str, modes[i].name) == 0)
break;
if (i == ARRAY_LENGTH(modes)) {
weston_log("Error in config for output '%s': '%s' is not a valid colorimetry mode. Try one of:",
output->name, str);
for (i = 0; i < ARRAY_LENGTH(modes); i++)
weston_log_continue(" %s", modes[i].name);
weston_log_continue("\n");
free(str);
return -1;
}
cmode = modes[i].cmode;
if ((weston_output_get_supported_colorimetry_modes(output) & cmode) == 0) {
weston_log("Error: output '%s' does not support colorimetry mode %s.\n",
output->name, str);
#if !HAVE_LIBDISPLAY_INFO
weston_log_continue(STAMP_SPACE "Weston was built without libdisplay-info, "
"so colorimetry capabilities cannot be detected.\n");
#endif
free(str);
return -1;
}
if (cmode != WESTON_COLORIMETRY_MODE_DEFAULT &&
!have_color_manager) {
weston_log("Error: Colorimetry mode %s on output '%s' requires color-management=true in weston.ini\n",
str, output->name);
free(str);
return -1;
}
weston_output_set_colorimetry_mode(output, cmode);
free(str);
return 0;
}
struct wet_color_characteristics_keys {
const char *name;
enum weston_color_characteristics_groups group;
......@@ -2214,7 +2285,9 @@ drm_backend_output_configure(struct weston_output *output,
allow_content_protection(output, section);
if (wet_output_set_eotf_mode(output, section) < 0)
if (wet_output_set_eotf_mode(output, section, wet->use_color_manager) < 0)
return -1;
if (wet_output_set_colorimetry_mode(output, section, wet->use_color_manager) < 0)
return -1;
if (wet_output_set_color_characteristics(output,
......@@ -3123,11 +3196,14 @@ headless_backend_output_configure(struct weston_output *output)
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL
};
struct weston_config *wc = wet_get_config(output->compositor);
struct wet_compositor *wet = to_wet_compositor(output->compositor);
struct weston_config *wc = wet->config;
struct weston_config_section *section;
section = weston_config_get_section(wc, "output", "name", output->name);
if (wet_output_set_eotf_mode(output, section) < 0)
if (wet_output_set_eotf_mode(output, section, wet->use_color_manager) < 0)
return -1;
if (wet_output_set_colorimetry_mode(output, section, wet->use_color_manager) < 0)
return -1;
if (wet_output_set_color_characteristics(output, wc, section) < 0)
......
......@@ -40,3 +40,13 @@ int
wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc,
struct weston_config_section *section);
int
wet_output_set_eotf_mode(struct weston_output *output,
struct weston_config_section *section,
bool have_color_manager);
int
wet_output_set_colorimetry_mode(struct weston_output *output,
struct weston_config_section *section,
bool have_color_manager);
......@@ -88,6 +88,7 @@ struct weston_color_profile;
struct weston_color_transform;
struct pixel_format_info;
struct weston_output_capture_info;
struct weston_output_color_outcome;
struct weston_tearing_control;
enum weston_keyboard_modifier {
......@@ -221,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
......@@ -261,63 +311,6 @@ struct weston_CIExy {
float y;
};
enum weston_hdr_metadata_type1_groups {
/** weston_hdr_metadata_type1::primary is set */
WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES = 0x01,
/** weston_hdr_metadata_type1::white is set */
WESTON_HDR_METADATA_TYPE1_GROUP_WHITE = 0x02,
/** weston_hdr_metadata_type1::maxDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML = 0x04,
/** weston_hdr_metadata_type1::minDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MINDML = 0x08,
/** weston_hdr_metadata_type1::maxCLL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL = 0x10,
/** weston_hdr_metadata_type1::maxFALL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL = 0x20,
/** all valid bits */
WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK = 0x3f
};
/** HDR static metadata type 1
*
* The fields are defined by CTA-861-G except here they use float encoding.
*
* In Weston used only with HDR display modes.
*/
struct weston_hdr_metadata_type1 {
/** Which fields are valid
*
* A bitmask of values from enum weston_hdr_metadata_type1_groups.
*/
uint32_t group_mask;
/* EOTF is tracked externally with enum weston_eotf_mode */
/** Chromaticities of the primaries, in any order */
struct weston_CIExy primary[3];
/** White point chromaticity */
struct weston_CIExy white;
/** Maximum display mastering luminance, 1 - 65535 cd/m² */
float maxDML;
/** Minimum display mastering luminance, 0.0001 - 6.5535 cd/m² */
float minDML;
/** Maximum content light level, 1 - 65535 cd/m² */
float maxCLL;
/** Maximum frame-average light level, 1 - 65535 cd/m² */
float maxFALL;
};
enum weston_color_characteristics_groups {
/** weston_color_characteristics::primary is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES = 0x01,
......@@ -407,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;
......@@ -418,29 +412,6 @@ struct weston_head {
struct wl_list cm_output_resource_list;
};
/** Output properties derived from its color characteristics and profile
*
* These are constructed by a color manager.
*
* A weston_output_color_outcome owns (a reference to) everything it contains.
*
* \ingroup output
* \internal
*/
struct weston_output_color_outcome {
/** sRGB to output color space transformation */
struct weston_color_transform *from_sRGB_to_output;
/** sRGB to blending color space transformation */
struct weston_color_transform *from_sRGB_to_blend;
/** Blending to output color space transformation */
struct weston_color_transform *from_blend_to_output;
/** HDR Static Metadata Type 1 for WESTON_EOTF_MODE_ST2084 */
struct weston_hdr_metadata_type1 hdr_meta;
};
enum weston_output_power_state {
/** No rendering and dpms off */
WESTON_OUTPUT_POWER_FORCED_OFF = 0,
......@@ -580,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;
......@@ -2610,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);
......@@ -2635,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);
......
......@@ -60,6 +60,7 @@
#include "libinput-seat.h"
#include "backend.h"
#include "libweston-internal.h"
#include "drm-kms-enums.h"
#ifndef GBM_BO_USE_CURSOR
#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
......@@ -148,126 +149,6 @@ struct drm_property_info {
uint64_t range_values[2];
};
/**
* List of properties attached to DRM planes
*/
enum wdrm_plane_property {
WDRM_PLANE_TYPE = 0,
WDRM_PLANE_SRC_X,
WDRM_PLANE_SRC_Y,
WDRM_PLANE_SRC_W,
WDRM_PLANE_SRC_H,
WDRM_PLANE_CRTC_X,
WDRM_PLANE_CRTC_Y,
WDRM_PLANE_CRTC_W,
WDRM_PLANE_CRTC_H,
WDRM_PLANE_FB_ID,
WDRM_PLANE_CRTC_ID,
WDRM_PLANE_IN_FORMATS,
WDRM_PLANE_IN_FENCE_FD,
WDRM_PLANE_FB_DAMAGE_CLIPS,
WDRM_PLANE_ZPOS,
WDRM_PLANE_ROTATION,
WDRM_PLANE_ALPHA,
WDRM_PLANE__COUNT
};
/**
* Possible values for the WDRM_PLANE_TYPE property.
*/
enum wdrm_plane_type {
WDRM_PLANE_TYPE_PRIMARY = 0,
WDRM_PLANE_TYPE_CURSOR,
WDRM_PLANE_TYPE_OVERLAY,
WDRM_PLANE_TYPE__COUNT
};
/**
* Possible values for the WDRM_PLANE_ROTATION property.
*/
enum wdrm_plane_rotation {
WDRM_PLANE_ROTATION_0 = 0,
WDRM_PLANE_ROTATION_90,
WDRM_PLANE_ROTATION_180,
WDRM_PLANE_ROTATION_270,
WDRM_PLANE_ROTATION_REFLECT_X,
WDRM_PLANE_ROTATION_REFLECT_Y,
WDRM_PLANE_ROTATION__COUNT,
};
/**
* List of properties attached to a DRM connector
*/
enum wdrm_connector_property {
WDRM_CONNECTOR_EDID = 0,
WDRM_CONNECTOR_DPMS,
WDRM_CONNECTOR_CRTC_ID,
WDRM_CONNECTOR_WRITEBACK_PIXEL_FORMATS,
WDRM_CONNECTOR_WRITEBACK_FB_ID,
WDRM_CONNECTOR_WRITEBACK_OUT_FENCE_PTR,
WDRM_CONNECTOR_NON_DESKTOP,
WDRM_CONNECTOR_CONTENT_PROTECTION,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR_CONTENT_TYPE,
WDRM_CONNECTOR__COUNT
};
enum wdrm_content_protection_state {
WDRM_CONTENT_PROTECTION_UNDESIRED = 0,
WDRM_CONTENT_PROTECTION_DESIRED,
WDRM_CONTENT_PROTECTION_ENABLED,
WDRM_CONTENT_PROTECTION__COUNT
};
enum wdrm_hdcp_content_type {
WDRM_HDCP_CONTENT_TYPE0 = 0,
WDRM_HDCP_CONTENT_TYPE1,
WDRM_HDCP_CONTENT_TYPE__COUNT
};
enum wdrm_dpms_state {
WDRM_DPMS_STATE_OFF = 0,
WDRM_DPMS_STATE_ON,
WDRM_DPMS_STATE_STANDBY, /* unused */
WDRM_DPMS_STATE_SUSPEND, /* unused */
WDRM_DPMS_STATE__COUNT
};
enum wdrm_panel_orientation {
WDRM_PANEL_ORIENTATION_NORMAL = 0,
WDRM_PANEL_ORIENTATION_UPSIDE_DOWN,
WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP,
WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP,
WDRM_PANEL_ORIENTATION__COUNT
};
enum wdrm_content_type {
WDRM_CONTENT_TYPE_NO_DATA = 0,
WDRM_CONTENT_TYPE_GRAPHICS,
WDRM_CONTENT_TYPE_PHOTO,
WDRM_CONTENT_TYPE_CINEMA,
WDRM_CONTENT_TYPE_GAME,
WDRM_CONTENT_TYPE__COUNT
};
/**
* List of properties attached to DRM CRTCs
*/
enum wdrm_crtc_property {
WDRM_CRTC_MODE_ID = 0,
WDRM_CRTC_ACTIVE,
WDRM_CRTC_CTM,
WDRM_CRTC_DEGAMMA_LUT,
WDRM_CRTC_DEGAMMA_LUT_SIZE,
WDRM_CRTC_GAMMA_LUT,
WDRM_CRTC_GAMMA_LUT_SIZE,
WDRM_CRTC_VRR_ENABLED,
WDRM_CRTC__COUNT
};
/**
* Reasons why placing a view on a plane failed. Needed by the dma-buf feedback.
*/
......@@ -667,6 +548,7 @@ struct drm_output {
uint64_t ackd_color_outcome_serial;
unsigned max_bpc;
enum wdrm_colorspace connector_colorspace;
bool deprecated_gamma_is_set;
bool legacy_gamma_not_supported;
......@@ -886,6 +768,9 @@ drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev);
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output);
enum wdrm_colorspace
wdrm_colorspace_from_output(struct weston_output *output);
#ifdef BUILD_DRM_GBM
extern struct drm_fb *
drm_fb_get_from_paint_node(struct drm_output_state *state,
......
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2017, 2018 Collabora, Ltd.
* Copyright © 2017, 2018 General Electric Company
* Copyright (c) 2018 DisplayLink (UK) 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.
*/
/*
* Like libdrm fourcc.h, also this header is used by libweston core.
* This header must not depend on anything libweston core is not already
* depending on.
*/
#pragma once
/**
* List of properties attached to DRM planes
*/
enum wdrm_plane_property {
WDRM_PLANE_TYPE = 0,
WDRM_PLANE_SRC_X,
WDRM_PLANE_SRC_Y,
WDRM_PLANE_SRC_W,
WDRM_PLANE_SRC_H,
WDRM_PLANE_CRTC_X,
WDRM_PLANE_CRTC_Y,
WDRM_PLANE_CRTC_W,
WDRM_PLANE_CRTC_H,
WDRM_PLANE_FB_ID,
WDRM_PLANE_CRTC_ID,
WDRM_PLANE_IN_FORMATS,
WDRM_PLANE_IN_FENCE_FD,
WDRM_PLANE_FB_DAMAGE_CLIPS,
WDRM_PLANE_ZPOS,
WDRM_PLANE_ROTATION,
WDRM_PLANE_ALPHA,
WDRM_PLANE__COUNT
};
/**
* Possible values for the WDRM_PLANE_TYPE property.
*/
enum wdrm_plane_type {
WDRM_PLANE_TYPE_PRIMARY = 0,
WDRM_PLANE_TYPE_CURSOR,
WDRM_PLANE_TYPE_OVERLAY,
WDRM_PLANE_TYPE__COUNT
};
/**
* Possible values for the WDRM_PLANE_ROTATION property.
*/
enum wdrm_plane_rotation {
WDRM_PLANE_ROTATION_0 = 0,
WDRM_PLANE_ROTATION_90,
WDRM_PLANE_ROTATION_180,
WDRM_PLANE_ROTATION_270,
WDRM_PLANE_ROTATION_REFLECT_X,
WDRM_PLANE_ROTATION_REFLECT_Y,
WDRM_PLANE_ROTATION__COUNT,
};
/**
* List of properties attached to a DRM connector
*/
enum wdrm_connector_property {
WDRM_CONNECTOR_EDID = 0,
WDRM_CONNECTOR_DPMS,
WDRM_CONNECTOR_CRTC_ID,
WDRM_CONNECTOR_WRITEBACK_PIXEL_FORMATS,
WDRM_CONNECTOR_WRITEBACK_FB_ID,
WDRM_CONNECTOR_WRITEBACK_OUT_FENCE_PTR,
WDRM_CONNECTOR_NON_DESKTOP,
WDRM_CONNECTOR_CONTENT_PROTECTION,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR_CONTENT_TYPE,
WDRM_CONNECTOR_COLORSPACE,
WDRM_CONNECTOR__COUNT
};
enum wdrm_content_protection_state {
WDRM_CONTENT_PROTECTION_UNDESIRED = 0,
WDRM_CONTENT_PROTECTION_DESIRED,
WDRM_CONTENT_PROTECTION_ENABLED,
WDRM_CONTENT_PROTECTION__COUNT
};
enum wdrm_hdcp_content_type {
WDRM_HDCP_CONTENT_TYPE0 = 0,
WDRM_HDCP_CONTENT_TYPE1,
WDRM_HDCP_CONTENT_TYPE__COUNT
};
enum wdrm_dpms_state {
WDRM_DPMS_STATE_OFF = 0,
WDRM_DPMS_STATE_ON,
WDRM_DPMS_STATE_STANDBY, /* unused */
WDRM_DPMS_STATE_SUSPEND, /* unused */
WDRM_DPMS_STATE__COUNT
};
enum wdrm_panel_orientation {
WDRM_PANEL_ORIENTATION_NORMAL = 0,
WDRM_PANEL_ORIENTATION_UPSIDE_DOWN,
WDRM_PANEL_ORIENTATION_LEFT_SIDE_UP,
WDRM_PANEL_ORIENTATION_RIGHT_SIDE_UP,
WDRM_PANEL_ORIENTATION__COUNT
};
enum wdrm_content_type {
WDRM_CONTENT_TYPE_NO_DATA = 0,
WDRM_CONTENT_TYPE_GRAPHICS,
WDRM_CONTENT_TYPE_PHOTO,
WDRM_CONTENT_TYPE_CINEMA,
WDRM_CONTENT_TYPE_GAME,
WDRM_CONTENT_TYPE__COUNT
};
enum wdrm_colorspace {
WDRM_COLORSPACE_DEFAULT = 0,
WDRM_COLORSPACE_SMPTE_170M_YCC,
WDRM_COLORSPACE_BT709_YCC,
WDRM_COLORSPACE_XVYCC_601,
WDRM_COLORSPACE_XVYCC_709,
WDRM_COLORSPACE_SYCC_601,
WDRM_COLORSPACE_OPYCC_601,
WDRM_COLORSPACE_OPRGB,
WDRM_COLORSPACE_BT2020_CYCC,
WDRM_COLORSPACE_BT2020_RGB,
WDRM_COLORSPACE_BT2020_YCC,
WDRM_COLORSPACE_DCI_P3_RGB_D65,
WDRM_COLORSPACE_DCI_P3_RGB_THEATER,
WDRM_COLORSPACE_RGB_WIDE_FIXED,
WDRM_COLORSPACE_RGB_WIDE_FLOAT,
WDRM_COLORSPACE_BT601_YCC,
WDRM_COLORSPACE__COUNT,
};
/**
* List of properties attached to DRM CRTCs
*/
enum wdrm_crtc_property {
WDRM_CRTC_MODE_ID = 0,
WDRM_CRTC_ACTIVE,
WDRM_CRTC_CTM,
WDRM_CRTC_DEGAMMA_LUT,
WDRM_CRTC_DEGAMMA_LUT_SIZE,
WDRM_CRTC_GAMMA_LUT,
WDRM_CRTC_GAMMA_LUT_SIZE,
WDRM_CRTC_VRR_ENABLED,
WDRM_CRTC__COUNT
};
......@@ -2259,6 +2259,10 @@ drm_output_enable(struct weston_output *base)
output->format = b->format;
}
output->connector_colorspace = wdrm_colorspace_from_output(&output->base);
if (output->connector_colorspace == WDRM_COLORSPACE__COUNT)
return -1;
ret = drm_output_attach_crtc(output);
if (ret < 0)
return -1;
......@@ -2576,6 +2580,14 @@ drm_head_log_info(struct drm_head *head, const char *msg)
str);
}
free(str);
str = weston_colorimetry_mask_to_str(head->base.supported_colorimetry_mask);
if (str) {
weston_log_continue(STAMP_SPACE
"Supported colorimetry modes: %s\n",
str);
}
free(str);
} else {
weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
head->base.name, msg, head->connector.connector_id);
......
......@@ -176,3 +176,20 @@ drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
return 0;
}
enum wdrm_colorspace
wdrm_colorspace_from_output(struct weston_output *output)
{
enum weston_colorimetry_mode cmode = output->colorimetry_mode;
const struct weston_colorimetry_mode_info *cm;
cm = weston_colorimetry_mode_info_get(cmode);
if (!(weston_output_get_supported_colorimetry_modes(output) & cmode) ||
!cm || cm->wdrm == WDRM_COLORSPACE__COUNT) {
weston_log("Error: DRM output '%s' does not support colorimetry mode %s.",
output->name, weston_colorimetry_mode_to_str(cmode));
return WDRM_COLORSPACE__COUNT;
}
return cm->wdrm;
}
......@@ -154,6 +154,25 @@ struct drm_property_enum_info content_type_enums[] = {
[WDRM_CONTENT_TYPE_GAME] = { .name = "Game", },
};
struct drm_property_enum_info colorspace_enums[] = {
[WDRM_COLORSPACE_DEFAULT] = { .name = "Default", },
[WDRM_COLORSPACE_SMPTE_170M_YCC] = { .name = "SMPTE_170M_YCC", },
[WDRM_COLORSPACE_BT709_YCC] = { .name = "BT709_YCC", },
[WDRM_COLORSPACE_XVYCC_601] = { .name = "XVYCC_601", },
[WDRM_COLORSPACE_XVYCC_709] = { .name = "XVYCC_709", },
[WDRM_COLORSPACE_SYCC_601] = { .name = "SYCC_601", },
[WDRM_COLORSPACE_OPYCC_601] = { .name = "opYCC_601", },
[WDRM_COLORSPACE_OPRGB] = { .name = "opRGB", },
[WDRM_COLORSPACE_BT2020_CYCC] = { .name = "BT2020_CYCC", },
[WDRM_COLORSPACE_BT2020_RGB] = { .name = "BT2020_RGB", },
[WDRM_COLORSPACE_BT2020_YCC] = { .name = "BT2020_YCC", },
[WDRM_COLORSPACE_DCI_P3_RGB_D65] = { .name = "DCI-P3_RGB_D65", },
[WDRM_COLORSPACE_DCI_P3_RGB_THEATER] = { .name = "DCI-P3_RGB_Theater", },
[WDRM_COLORSPACE_RGB_WIDE_FIXED] = { .name = "RGB_WIDE_FIXED", },
[WDRM_COLORSPACE_RGB_WIDE_FLOAT] = { .name = "RGB_WIDE_FLOAT", },
[WDRM_COLORSPACE_BT601_YCC] = { .name = "BT601_YCC", },
};
const struct drm_property_info connector_props[] = {
[WDRM_CONNECTOR_EDID] = { .name = "EDID" },
[WDRM_CONNECTOR_DPMS] = {
......@@ -190,6 +209,11 @@ const struct drm_property_info connector_props[] = {
.enum_values = content_type_enums,
.num_enum_values = WDRM_CONTENT_TYPE__COUNT,
},
[WDRM_CONNECTOR_COLORSPACE] = {
.name = "Colorspace",
.enum_values = colorspace_enums,
.num_enum_values = WDRM_COLORSPACE__COUNT,
},
};
const struct drm_property_info crtc_props[] = {
......@@ -1143,6 +1167,32 @@ drm_connector_set_content_type(struct drm_connector *connector,
WDRM_CONNECTOR_CONTENT_TYPE, prop_val);
}
static int
drm_connector_set_colorspace(struct drm_connector *connector,
enum wdrm_colorspace colorspace,
drmModeAtomicReq *req)
{
const struct drm_property_info *info;
const struct drm_property_enum_info *enum_info;
assert(colorspace >= 0);
assert(colorspace < WDRM_COLORSPACE__COUNT);
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_COLORSPACE)) {
if (colorspace == WDRM_COLORSPACE_DEFAULT)
return 0;
return -1;
}
info = &connector->props[WDRM_CONNECTOR_COLORSPACE];
enum_info = &info->enum_values[colorspace];
assert(enum_info->valid);
return connector_add_prop(req, connector,
WDRM_CONNECTOR_COLORSPACE, enum_info->value);
}
static int
drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req,
......@@ -1252,6 +1302,8 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
}
ret |= drm_connector_set_max_bpc(&head->connector, output, req);
ret |= drm_connector_set_colorspace(&head->connector,
output->connector_colorspace, req);
}
if (ret != 0) {
......
......@@ -49,6 +49,11 @@ struct drm_head_info {
* enum weston_eotf_mode bits.
*/
uint32_t eotf_mask;
/* The monitor supported colorimetry modes, combination of
* enum weston_colorimetry_mode bits.
*/
uint32_t colorimetry_mask;
};
static void
......@@ -251,6 +256,7 @@ drm_head_info_from_edid(struct drm_head_info *dhi,
/* TODO: parse this from EDID */
dhi->eotf_mask = WESTON_EOTF_MODE_ALL_MASK;
dhi->colorimetry_mask = WESTON_COLORIMETRY_MODE_ALL_MASK;
}
#else /* HAVE_LIBDISPLAY_INFO */
......@@ -380,6 +386,7 @@ drm_head_info_from_edid(struct drm_head_info *dhi,
/* This ad hoc code will never parse HDR data. */
dhi->eotf_mask = WESTON_EOTF_MODE_SDR;
dhi->colorimetry_mask = WESTON_COLORIMETRY_MODE_DEFAULT;
}
#endif /* HAVE_LIBDISPLAY_INFO else */
......@@ -447,6 +454,35 @@ prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
*eotf_mask = WESTON_EOTF_MODE_SDR;
}
static uint32_t
drm_head_get_kms_colorimetry_modes(const struct drm_head *head)
{
const struct drm_property_info *info;
/* Cannot bother implementing without atomic */
if (!head->connector.device->atomic_modeset)
return WESTON_COLORIMETRY_MODE_DEFAULT;
info = &head->connector.props[WDRM_CONNECTOR_COLORSPACE];
if (info->prop_id == 0)
return WESTON_COLORIMETRY_MODE_DEFAULT;
uint32_t colorimetry_modes = WESTON_COLORIMETRY_MODE_NONE;
unsigned i; /* actually enum wdrm_colorspace */
for (i = 0; i < WDRM_COLORSPACE__COUNT; i++) {
if (info->enum_values[i].valid) {
const struct weston_colorimetry_mode_info *cm;
cm = weston_colorimetry_mode_info_get_by_wdrm(i);
if (cm)
colorimetry_modes |= cm->mode;
}
}
return colorimetry_modes;
}
static uint32_t
drm_refresh_rate_mHz(const drmModeModeInfo *info)
{
......@@ -643,6 +679,9 @@ update_head_from_connector(struct drm_head *head)
prune_eotf_modes_by_kms_support(head, &dhi.eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, dhi.eotf_mask);
dhi.colorimetry_mask &= drm_head_get_kms_colorimetry_modes(head);
weston_head_set_supported_colorimetry_mask(&head->base, dhi.colorimetry_mask);
drm_head_info_fini(&dhi);
}
......
......@@ -489,6 +489,8 @@ headless_head_create(struct weston_backend *base,
weston_head_set_connection_status(&head->base, true);
weston_head_set_supported_eotf_mask(&head->base,
WESTON_EOTF_MODE_ALL_MASK);
weston_head_set_supported_colorimetry_mask(&head->base,
WESTON_COLORIMETRY_MODE_ALL_MASK);
/* Ideally all attributes of the head would be set here, so that the
* user has all the information when deciding to create outputs.
......
......@@ -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
......
......@@ -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"
/**
......@@ -409,14 +410,8 @@ weston_eotf_mode_to_str(enum weston_eotf_mode e)
return "???";
}
/** A list of EOTF modes as a string
*
* \param eotf_mask Bitwise-or'd enum weston_eotf_mode values.
* \return Comma separated names of the listed EOTF modes. Must be free()'d by
* the caller.
*/
WL_EXPORT char *
weston_eotf_mask_to_str(uint32_t eotf_mask)
static char *
bits_to_str(uint32_t bits, const char *(*map)(uint32_t))
{
FILE *fp;
char *str = NULL;
......@@ -428,18 +423,98 @@ weston_eotf_mask_to_str(uint32_t eotf_mask)
if (!fp)
return NULL;
for (i = 0; eotf_mask; i++) {
for (i = 0; bits; i++) {
uint32_t bitmask = 1u << i;
if (eotf_mask & bitmask) {
fprintf(fp, "%s%s", sep,
weston_eotf_mode_to_str(bitmask));
if (bits & bitmask) {
fprintf(fp, "%s%s", sep, map(bitmask));
sep = ", ";
}
eotf_mask &= ~bitmask;
bits &= ~bitmask;
}
fclose(fp);
return str;
}
/** A list of EOTF modes as a string
*
* \param eotf_mask Bitwise-or'd enum weston_eotf_mode values.
* \return Comma separated names of the listed EOTF modes. Must be free()'d by
* the caller.
*/
WL_EXPORT char *
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 information structure of colorimetry mode from KMS "Colorspace" enum
*
* \internal
*/
WL_EXPORT const struct weston_colorimetry_mode_info *
weston_colorimetry_mode_info_get_by_wdrm(enum wdrm_colorspace cs)
{
unsigned i;
for (i = 0; i < ARRAY_LENGTH(colorimetry_mode_info_map); i++)
if (colorimetry_mode_info_map[i].wdrm == cs)
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);
}
......@@ -31,6 +31,88 @@
#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,
/** weston_hdr_metadata_type1::white is set */
WESTON_HDR_METADATA_TYPE1_GROUP_WHITE = 0x02,
/** weston_hdr_metadata_type1::maxDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML = 0x04,
/** weston_hdr_metadata_type1::minDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MINDML = 0x08,
/** weston_hdr_metadata_type1::maxCLL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL = 0x10,
/** weston_hdr_metadata_type1::maxFALL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL = 0x20,
/** all valid bits */
WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK = 0x3f
};
/** HDR static metadata type 1
*
* The fields are defined by CTA-861-G except here they use float encoding.
*
* In Weston used only with HDR display modes.
*/
struct weston_hdr_metadata_type1 {
/** Which fields are valid
*
* A bitmask of values from enum weston_hdr_metadata_type1_groups.
*/
uint32_t group_mask;
/* EOTF is tracked externally with enum weston_eotf_mode */
/** Chromaticities of the primaries, in any order */
struct weston_CIExy primary[3];
/** White point chromaticity */
struct weston_CIExy white;
/** Maximum display mastering luminance, 1 - 65535 cd/m² */
float maxDML;
/** Minimum display mastering luminance, 0.0001 - 6.5535 cd/m² */
float minDML;
/** Maximum content light level, 1 - 65535 cd/m² */
float maxCLL;
/** Maximum frame-average light level, 1 - 65535 cd/m² */
float maxFALL;
};
/** Output properties derived from its color characteristics and profile
*
* These are constructed by a color manager.
*
* A weston_output_color_outcome owns (a reference to) everything it contains.
*
* \ingroup output
* \internal
*/
struct weston_output_color_outcome {
/** sRGB to output color space transformation */
struct weston_color_transform *from_sRGB_to_output;
/** sRGB to blending color space transformation */
struct weston_color_transform *from_sRGB_to_blend;
/** Blending to output color space transformation */
struct weston_color_transform *from_blend_to_output;
/** HDR Static Metadata Type 1 for WESTON_EOTF_MODE_ST2084 */
struct weston_hdr_metadata_type1 hdr_meta;
};
/**
* Represents a color profile description (an ICC color profile)
*
......@@ -468,6 +550,29 @@ 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 struct weston_colorimetry_mode_info *
weston_colorimetry_mode_info_get_by_wdrm(enum wdrm_colorspace cs);
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);
......
......@@ -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);
......@@ -6805,7 +6806,8 @@ WL_EXPORT void
weston_head_set_supported_eotf_mask(struct weston_head *head,
uint32_t eotf_mask)
{
assert((eotf_mask & ~WESTON_EOTF_MODE_ALL_MASK) == 0);
weston_assert_legal_bits(head->compositor,
eotf_mask, WESTON_EOTF_MODE_ALL_MASK);
if (head->supported_eotf_mask == eotf_mask)
return;
......@@ -6815,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)
......@@ -7651,6 +7679,8 @@ weston_output_set_color_profile(struct weston_output *output,
* supported on the output. Enabling an output with an unsupported EOTF mode
* has undefined visual results.
*
* TODO: Enforce mode validity.
*
* The initial EOTF mode is SDR.
*
* \ingroup output
......@@ -7659,7 +7689,7 @@ WL_EXPORT void
weston_output_set_eotf_mode(struct weston_output *output,
enum weston_eotf_mode eotf_mode)
{
assert(!output->enabled);
weston_assert_false(output->compositor, output->enabled);
output->eotf_mode = eotf_mode;
}
......@@ -7678,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.
......@@ -7809,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;
......@@ -7972,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;
......@@ -8321,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.
......
......@@ -596,6 +596,36 @@ A comma separated list of the IDs of applications to place on this output.
These IDs should match the application IDs as set with the xdg_shell.set_app_id
request. Currently, this option is supported by kiosk-shell.
.TP 7
.BI "colorimetry-mode=" default
Sets the colorimetry mode on the output. The colorimetry mode together with
the EOTF mode below define the color encoding used in the video signal. The
colorimetry mode is used for choosing between the default sink defined
colorimetry (intended to be described by EDID), and standardised other
encodings that support wide color gamut (WCG).
The display driver, the graphics card, and the video sink (monitor) need to
support the chosen mode, otherwise the result is undefined or fails.
The mode can be one of the following strings:
.PP
.RS 10
.nf
.BR "default " "default (RGB) colorimetry, video sink dependant"
.BR "bt2020cycc " "Rec. ITU-R BT.2020 constant luminance YCbCr"
.BR "bt2020ycc " "Rec. ITU-R BT.2020 non-constant luminance YCbCr"
.BR "bt2020rgb " "Rec. ITU-R BT.2020 RGB"
.BR "p3d65 " "SMPTE ST 2113 DCI-P3 RGB D65"
.BR "p3dci " "SMPTE ST 2113 DCI-P3 RGB Theater"
.BR "ictcp " "Rec. ITU-R BT.2100 ICtCp"
.fi
.RE
.IP
Defaults to
.BR default ". Non-default modes require " "color-management=true" .
Note: The operating system might not honor the choice between RGB and YCbCr,
that may be picked by a Linux display driver automatically.
.TP 7
.BI "eotf-mode=" sdr
Sets the EOTF mode on the output. This is used for choosing between standard
dynamic range (SDR) mode and the various high dynamic range (HDR) modes. The
......
......@@ -85,6 +85,9 @@ do { \
#define weston_assert_true(compositor, a) \
weston_assert_(compositor, a, true, bool, "%d", ==)
#define weston_assert_false(compositor, a) \
weston_assert_(compositor, a, false, bool, "%d", ==)
#define weston_assert_ptr(compositor, a) \
weston_assert_(compositor, a, NULL, const void *, "%p", !=)
......@@ -129,3 +132,18 @@ do { \
__FILE__, __LINE__, #bit, b, #value, v); \
cond; \
})
#define weston_assert_legal_bits(compositor, value, mask) \
({ \
struct weston_compositor *ec = compositor; \
uint64_t v_ = (value); \
uint64_t m_ = (mask); \
uint64_t ill = v_ & ~m_; \
bool cond = ill == 0; \
if (!cond) \
custom_assert_fail_(ec, "%s:%u: Assertion failed! " \
"Value %s (0x%" PRIx64 ") contains illegal bits 0x%" PRIx64 ". " \
"Legal mask is %s (0x%" PRIx64 ").\n", \
__FILE__, __LINE__, #value, v_, ill, #mask, m_); \
cond; \
})
......@@ -86,6 +86,12 @@ TEST(asserts)
ret = weston_assert_true(compositor, true);
abort_if_not(ret);
ret = weston_assert_false(compositor, true);
abort_if_not(ret == false);
ret = weston_assert_false(compositor, false);
abort_if_not(ret);
ret = weston_assert_true(compositor, true && false);
abort_if_not(ret == false);
......@@ -136,4 +142,12 @@ TEST(asserts)
uint64_t max_uint64 = UINT64_MAX;
ret = weston_assert_uint64_eq(compositor, max_uint64, 0);
abort_if_not(ret == false);
uint64_t val = 0x200010001000ffff;
uint64_t msk = 0x00000000fffffff3;
ret = weston_assert_legal_bits(compositor, val, msk);
abort_if_not(ret == false);
ret = weston_assert_legal_bits(compositor, val, UINT64_MAX);
abort_if_not(ret);
}
......@@ -399,3 +399,268 @@ TEST(hdr_metadata_type1_ignore_unflagged)
weston_output_release(&mock_output);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}
struct mode_testcase {
bool color_management;
uint32_t supported_eotf_mask;
uint32_t supported_colorimetry_mask;
const char *eotf_mode;
const char *colorimetry_mode;
enum weston_eotf_mode expected_eotf_mode;
enum weston_colorimetry_mode expected_colorimetry_mode;
int expected_retval;
const char *expected_error;
};
static const struct mode_testcase mode_config_cases[] = {
/* Defaults */
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT, NULL, NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
/* Color management off, EOTF modes */
{
false, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "sdr", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
false, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "hdr-gamma", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: EOTF mode hdr-gamma on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "st2084", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: EOTF mode st2084 on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "hlg", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: EOTF mode hlg on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "nonosense", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error in config for output 'mockoutput': 'nonosense' is not a valid EOTF mode. Try one of: sdr hdr-gamma st2084 hlg\n"
},
/* Color management on, EOTF modes */
{
true, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "sdr", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
true, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "hdr-gamma", NULL,
WESTON_EOTF_MODE_TRADITIONAL_HDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
true, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "st2084", NULL,
WESTON_EOTF_MODE_ST2084, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
true, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "hlg", NULL,
WESTON_EOTF_MODE_HLG, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
true, WESTON_EOTF_MODE_ALL_MASK, WESTON_COLORIMETRY_MODE_DEFAULT, "nonosense", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error in config for output 'mockoutput': 'nonosense' is not a valid EOTF mode. Try one of: sdr hdr-gamma st2084 hlg\n"
},
/* unsupported EOTF mode */
{
true,
WESTON_EOTF_MODE_SDR | WESTON_EOTF_MODE_TRADITIONAL_HDR | WESTON_EOTF_MODE_ST2084,
WESTON_COLORIMETRY_MODE_DEFAULT, "hlg", NULL,
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: output 'mockoutput' does not support EOTF mode hlg.\n"
},
/* Color management off, colorimetry modes */
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "default",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020cycc",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode bt2020cycc on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020ycc",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode bt2020ycc on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020rgb",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode bt2020rgb on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "p3d65",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode p3d65 on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "p3dci",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode p3dci on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "ictcp",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: Colorimetry mode ictcp on output 'mockoutput' requires color-management=true in weston.ini\n"
},
{
false, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "imagine that",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error in config for output 'mockoutput': 'imagine that' is not a valid colorimetry mode. Try one of: default bt2020cycc bt2020ycc bt2020rgb p3d65 p3dci ictcp\n"
},
/* Color management on, colorimetry modes */
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "default",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020cycc",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_BT2020_CYCC,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020ycc",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_BT2020_YCC,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "bt2020rgb",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_BT2020_RGB,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "p3d65",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_P3D65,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "p3dci",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_P3DCI,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "ictcp",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ICTCP,
0, ""
},
{
true, WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_ALL_MASK, NULL, "imagine that",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error in config for output 'mockoutput': 'imagine that' is not a valid colorimetry mode. Try one of: default bt2020cycc bt2020ycc bt2020rgb p3d65 p3dci ictcp\n"
},
/* Unsupported colorimetry mode */
{
true, WESTON_EOTF_MODE_SDR,
WESTON_COLORIMETRY_MODE_DEFAULT | WESTON_COLORIMETRY_MODE_BT2020_RGB | WESTON_COLORIMETRY_MODE_BT2020_CYCC | WESTON_COLORIMETRY_MODE_P3D65,
NULL, "ictcp",
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
-1, "Error: output 'mockoutput' does not support colorimetry mode ictcp.\n"
},
};
static struct weston_config *
create_mode_config(const struct mode_testcase *t)
{
struct compositor_setup setup;
struct weston_config *wc;
compositor_setup_defaults(&setup);
weston_ini_setup(&setup,
cfgln("[output]"),
cfgln("name=mockoutput"),
t->eotf_mode ?
cfgln("eotf-mode=%s", t->eotf_mode) :
cfgln(""),
t->colorimetry_mode ?
cfgln("colorimetry-mode=%s", t->colorimetry_mode) :
cfgln("")
);
wc = weston_config_parse(setup.config_file);
free(setup.config_file);
return wc;
}
/*
* Manufacture various weston.ini and check what
* wet_output_set_eotf_mode() and wet_output_set_colorimetry_mode() says.
* Tests for the return value and the error messages logged.
*/
TEST_P(mode_config_error, mode_config_cases)
{
const struct mode_testcase *t = data;
struct mock_color_manager mock_cm = {
.base.create_output_color_outcome = mock_create_output_color_outcome,
.base.ref_stock_sRGB_color_profile = mock_cm_ref_stock_sRGB_color_profile,
.base.destroy_color_profile = mock_cm_destroy_color_profile,
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
};
struct weston_config *wc;
struct weston_config_section *section;
int retval;
int attached;
char *logbuf;
size_t logsize;
struct weston_head mock_head = {};
struct weston_output mock_output = {};
mock_cm.base.compositor = &mock_compositor;
wl_list_init(&mock_compositor.plane_list);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
weston_head_init(&mock_head, "mockhead");
weston_head_set_supported_eotf_mask(&mock_head, t->supported_eotf_mask);
weston_head_set_supported_colorimetry_mask(&mock_head, t->supported_colorimetry_mask);
attached = weston_output_attach_head(&mock_output, &mock_head);
assert(attached == 0);
logfile = open_memstream(&logbuf, &logsize);
weston_log_set_handler(logger, logger);
wc = create_mode_config(t);
section = weston_config_get_section(wc, "output", "name", "mockoutput");
assert(section);
retval = wet_output_set_eotf_mode(&mock_output, section, t->color_management);
if (retval == 0) {
retval = wet_output_set_colorimetry_mode(&mock_output, section,
t->color_management);
}
assert(fclose(logfile) == 0);
logfile = NULL;
testlog("retval %d, logs:\n%s\n", retval, logbuf);
assert(retval == t->expected_retval);
assert(strcmp(logbuf, t->expected_error) == 0);
assert(weston_output_get_eotf_mode(&mock_output) == t->expected_eotf_mode);
assert(weston_output_get_colorimetry_mode(&mock_output) == t->expected_colorimetry_mode);
weston_config_destroy(wc);
free(logbuf);
weston_output_release(&mock_output);
weston_head_release(&mock_head);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}
......@@ -31,6 +31,7 @@
#include "weston-test-client-helper.h"
#include "weston-test-fixture-compositor.h"
#include "backend.h"
#include "color.h"
static enum test_result_code
fixture_setup(struct weston_test_harness *harness)
......@@ -45,6 +46,7 @@ fixture_setup(struct weston_test_harness *harness)
cfgln("[output]"),
cfgln("name=headless"),
cfgln("color_characteristics=my-awesome-color"),
cfgln("colorimetry-mode=bt2020rgb"),
cfgln("eotf-mode=st2084"),
cfgln("[color_characteristics]"),
......@@ -73,6 +75,7 @@ PLUGIN_TEST(color_characteristics_from_weston_ini)
struct weston_output *output = NULL;
struct weston_output *it;
enum weston_eotf_mode mode;
enum weston_colorimetry_mode colorimetry_mode;
const struct weston_color_characteristics *cc;
const struct weston_hdr_metadata_type1 *hdr_meta;
......@@ -88,6 +91,9 @@ PLUGIN_TEST(color_characteristics_from_weston_ini)
mode = weston_output_get_eotf_mode(output);
assert(mode == WESTON_EOTF_MODE_ST2084);
colorimetry_mode = weston_output_get_colorimetry_mode(output);
assert(colorimetry_mode == WESTON_COLORIMETRY_MODE_BT2020_RGB);
cc = weston_output_get_color_characteristics(output);
assert(cc->group_mask == WESTON_COLOR_CHARACTERISTICS_GROUP_ALL_MASK);
assert(cc->primary[0].x == 0.9999f);
......