Skip to content
Commits on Source (9)
  • Pekka Paalanen's avatar
    libweston: introduce weston_eotf_mode · 5f9b68d6
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This is the switch to turn HDR mode on.
    
    The values in the enumeration come straight from CTA-861-G standard.
    Monitors advertise support for some of the HDR modes in their EDID, and
    I am not aware of any other way to detect if a HDR mode actually works
    or not. Different monitors may support different and multiple modes.
    Different modes may look different. Therefore the high-level choice of
    how to drive a HDR video sink is left for the Weston frontend to decide.
    
    All the details like what HDR metadata to use are left for the color
    manager.
    
    This commit adds the libweston API for backends to advertise support and
    for frontends to choose a mode. Backend and frontend implementations
    follow in other commits.
    
    The frontend API does not limit the EOTF mode to the supported ones to
    allow experimentation and overriding EDID.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    5f9b68d6
  • Pekka Paalanen's avatar
    backend-headless: support all EOTF modes · 1e9b1a10
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    The headless backend does not display to anything, so it doesn't care
    what the EOTF mode is. To allow testing compositor internal behavior,
    claim to support all EOTF modes.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    1e9b1a10
  • Pekka Paalanen's avatar
    color-noop: supports only SDR EOTF mode · 46c0383c
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    The no-op color manager will not support any other EOTF mode than SDR.
    Other modes would require it to set up color transformations.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    46c0383c
  • Pekka Paalanen's avatar
    color-lcms: todo for eotf_mode · 271c11e9
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    A reminder that this variable needs to be taken into account when
    crafting color transformations.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    271c11e9
  • Pekka Paalanen's avatar
    backend-drm: add HDR_OUTPUT_METADATA definitions · 69140640
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    These are fallback definitions in case libdrm is not new enough.
    They are copied from libdrm 2.4.107.
    
    struct hdr_output_metadata defines the contents of the blob to be used
    with the connector property "HDR_OUTPUT_METADATA".
    
    This is needed for programming a HDR mode in KMS.
    
    This headers need to be excluded from Doxygen, because Doxygen chokes on
    the kerneldoc markup.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    69140640
  • Pekka Paalanen's avatar
    backend-drm: check for HDR_OUTPUT_METADATA · 1d17e499
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Check whether HDR_OUTPUT_METADATA property exists on a KMS connector. If
    yes, pretend that EDID claims support for all EOTF modes and update the
    head supported EOTFs mask accordingly. If not, then only SDR is
    possible.
    
    Parsing EDID to take monitor capabilities into account is left for
    later.
    
    HDR mode cannot be set without HDR_OUTPUT_METADATA.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    1d17e499
  • Pekka Paalanen's avatar
    backend-drm: program HDR_OUTPUT_METADATA · 5151f9fe
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Program the connector property HDR_OUTPUT_METADATA based on the EOTF
    mode of the output.
    
    For now, this changes only the EOTF. The colorimetry and luminance are
    left undefined, to be filled in by later patches. This should still be
    enough to put a video sink into HDR mode, albeit the response is
    probably unknown.
    
    drm_output keeps track of the currently existing blob id. If the blob
    contents need to be re-created, this blob would be destroyed and the
    field set to zero. In this patch, there is no provision for runtime
    changing of HDR metadata, so there is no code doing that.
    
    Destroying the blob at arbitrary times is not a problem, because the
    kernel keeps a reference to the data as long as the blob id remains with
    KMS.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    5151f9fe
  • Pekka Paalanen's avatar
    compositor: add eotf-mode weston.ini option · 33d553f8
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This per-output option allows to choose one of the HDR video modes.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    33d553f8
  • Pekka Paalanen's avatar
    backend-drm: default to XRGB2101010 for HDR · e6a9e3c4
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Trying to do HDR with XRGB8888 is a bit like using RGB565 on SDR: you
    get visible color quantization and banding in gradients (without dithering
    which Weston does not implement yet, and might not work too well for HDR
    anyway).
    
    Therefore, on any HDR mode, default output framebuffer format to 10 bpc
    instead of 8 bpc.
    
    Ideally we'd also optionally try 16F or 16 bpc formats, but automatic
    fallbacks for those are more complicated to arrange. You can still
    configure 16F or 16 bpc manually.
    
    This patch also moves the default format setting from
    drm_output_set_gbm_format() to drm_output_enable(), because setting the
    default now requires eotf_mode. Frontends may call set_gbm_format()
    first and set eotf_mode next. This does create an awkward situation for
    outputs that a frontend disables and re-enables. This patch here makes
    sure that the old output configuration remains, but changing eotf_mode
    may not change the default format. One needs to call
    set_gbm_format(NULL) to re-evaluate the default format. Resetting the
    format on drm_output_deinit() would lose the current setting.
    
    DRM_FORMAT_INVALID was introduced in libdrm 2.4.95 which we already
    hard-depend on.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    e6a9e3c4
......@@ -1316,6 +1316,73 @@ wet_output_set_color_profile(struct weston_output *output,
return ok ? 0 : -1;
}
static int
wet_output_set_eotf_mode(struct weston_output *output,
struct weston_config_section *section)
{
static const struct {
const char *name;
enum weston_eotf_mode eotf_mode;
} modes[] = {
{ "sdr", WESTON_EOTF_MODE_SDR },
{ "hdr-gamma", WESTON_EOTF_MODE_TRADITIONAL_HDR },
{ "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);
}
if (!str) {
/* The default SDR mode is always supported. */
assert(weston_output_get_supported_eotf_modes(output) & eotf_mode);
weston_output_set_eotf_mode(output, eotf_mode);
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 EOTF 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");
return -1;
}
eotf_mode = modes[i].eotf_mode;
if ((weston_output_get_supported_eotf_modes(output) & eotf_mode) == 0) {
weston_log("Error: output '%s' does not support EOTF mode %s.\n",
output->name, str);
free(str);
return -1;
}
if (eotf_mode != WESTON_EOTF_MODE_SDR &&
!compositor->use_color_manager) {
weston_log("Error: EOTF mode %s on output '%s' requires color-management=true in weston.ini\n",
str, output->name);
free(str);
return -1;
}
weston_output_set_eotf_mode(output, eotf_mode);
free(str);
return 0;
}
static void
allow_content_protection(struct weston_output *output,
struct weston_config_section *section)
......@@ -1839,6 +1906,9 @@ drm_backend_output_configure(struct weston_output *output,
allow_content_protection(output, section);
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
return 0;
}
......@@ -2655,6 +2725,12 @@ 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 weston_config_section *section;
section = weston_config_get_section(wc, "output", "name", output->name);
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
return wet_configure_windowed_output_from_config(output, &defaults);
}
......
......@@ -888,7 +888,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
EXCLUDE_PATTERNS = */backend-drm/libdrm-updates.h
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
......
......@@ -207,6 +207,40 @@ struct weston_testsuite_data {
void *test_private_data;
};
/** EOTF mode for outputs and heads
*
* A list of EOTF modes for driving displays, defined by CTA-861-G for
* Dynamic Range and Mastering InfoFrame.
*
* 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.
*
* For traditional non-HDR sRGB, use WESTON_EOTF_MODE_SDR.
*/
enum weston_eotf_mode {
/** Invalid EOTF mode, or none supported. */
WESTON_EOTF_MODE_NONE = 0,
/** Traditional gamma, SDR luminance range */
WESTON_EOTF_MODE_SDR = 0x01,
/** Traditional gamma, HDR luminance range */
WESTON_EOTF_MODE_TRADITIONAL_HDR = 0x02,
/** Preceptual quantizer, SMPTE ST 2084 */
WESTON_EOTF_MODE_ST2084 = 0x04,
/** Hybrid log-gamma, ITU-R BT.2100 */
WESTON_EOTF_MODE_HLG = 0x08,
};
/** Bitmask of all defined EOTF modes */
#define WESTON_EOTF_MODE_ALL_MASK \
((uint32_t)(WESTON_EOTF_MODE_SDR | WESTON_EOTF_MODE_TRADITIONAL_HDR | \
WESTON_EOTF_MODE_ST2084 | WESTON_EOTF_MODE_HLG))
/** Represents a head, usually a display connector
*
* \rst
......@@ -243,6 +277,7 @@ struct weston_head {
char *name; /**< head name, e.g. connector name */
bool connected; /**< is physically connected */
bool non_desktop; /**< non-desktop display, e.g. HMD */
uint32_t supported_eotf_mask; /**< supported weston_eotf_mode bits */
/** Current content protection status */
enum weston_hdcp_protection current_protection;
......@@ -361,6 +396,7 @@ struct weston_output {
struct weston_color_transform *from_sRGB_to_blend;
struct weston_color_transform *from_blend_to_output;
bool from_blend_to_output_by_backend;
enum weston_eotf_mode eotf_mode;
int (*enable)(struct weston_output *output);
int (*disable)(struct weston_output *output);
......@@ -2107,6 +2143,13 @@ bool
weston_output_set_color_profile(struct weston_output *output,
struct weston_color_profile *cprof);
void
weston_output_set_eotf_mode(struct weston_output *output,
enum weston_eotf_mode eotf_mode);
enum weston_eotf_mode
weston_output_get_eotf_mode(const struct weston_output *output);
void
weston_output_init(struct weston_output *output,
struct weston_compositor *compositor,
......@@ -2121,6 +2164,9 @@ weston_output_enable(struct weston_output *output);
void
weston_output_disable(struct weston_output *output);
uint32_t
weston_output_get_supported_eotf_modes(struct weston_output *output);
void
weston_compositor_flush_heads_changed(struct weston_compositor *compositor);
......
......@@ -186,6 +186,7 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_CONTENT_PROTECTION,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR__COUNT
};
......@@ -548,6 +549,8 @@ struct drm_output {
uint32_t gbm_format;
uint32_t gbm_bo_flags;
uint32_t hdr_output_metadata_blob_id;
/* Plane being displayed directly on the CRTC */
struct drm_plane *scanout_plane;
......
......@@ -51,6 +51,7 @@
#include <libweston/backend-drm.h>
#include <libweston/weston-log.h>
#include "drm-internal.h"
#include "libdrm-updates.h"
#include "shared/helpers.h"
#include "shared/timespec-util.h"
#include "shared/string-helpers.h"
......@@ -440,6 +441,71 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
pixman_region32_fini(&scanout_damage);
}
static int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
{
struct hdr_output_metadata meta;
uint32_t blob_id = 0;
int ret;
if (output->hdr_output_metadata_blob_id)
return 0;
/*
* Set up the data for Dynamic Range and Mastering InfoFrame,
* CTA-861-G, a.k.a the static HDR metadata.
*/
memset(&meta, 0, sizeof meta);
meta.metadata_type = 0; /* Static Metadata Type 1 */
/* Duplicated field in UABI struct */
meta.hdmi_metadata_type1.metadata_type = meta.metadata_type;
switch (output->base.eotf_mode) {
case WESTON_EOTF_MODE_NONE:
assert(0 && "bad eotf_mode: none");
return -1;
case WESTON_EOTF_MODE_SDR:
/*
* Do not send any static HDR metadata. Video sinks should
* respond by switching to traditional SDR mode. If they
* do not, the kernel should fix that up.
*/
assert(output->hdr_output_metadata_blob_id == 0);
return 0;
case WESTON_EOTF_MODE_TRADITIONAL_HDR:
meta.hdmi_metadata_type1.eotf = 1; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_ST2084:
meta.hdmi_metadata_type1.eotf = 2; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_HLG:
meta.hdmi_metadata_type1.eotf = 3; /* from CTA-861-G */
break;
}
if (meta.hdmi_metadata_type1.eotf == 0) {
assert(0 && "bad eotf_mode");
return -1;
}
/* The other fields are intentionally left as zeroes. */
ret = drmModeCreatePropertyBlob(output->backend->drm.fd,
&meta, sizeof meta, &blob_id);
if (ret != 0) {
weston_log("Error: failed to create KMS blob for HDR metadata on output '%s': %s\n",
output->base.name, strerror(-ret));
return -1;
}
output->hdr_output_metadata_blob_id = blob_id;
return 0;
}
static int
drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
{
......@@ -474,6 +540,9 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
else
state->protection = WESTON_HDCP_DISABLE;
if (drm_output_ensure_hdr_output_metadata_blob(output) < 0)
goto err;
drm_output_render(state, damage);
scanout_state = drm_output_state_get_plane(state,
output->scanout_plane);
......@@ -1347,10 +1416,10 @@ drm_output_set_gbm_format(struct weston_output *base,
const char *gbm_format)
{
struct drm_output *output = to_drm_output(base);
struct drm_backend *b = to_drm_backend(base->compositor);
if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
output->gbm_format = b->gbm_format;
if (parse_gbm_format(gbm_format,
DRM_FORMAT_INVALID, &output->gbm_format) == -1)
output->gbm_format = DRM_FORMAT_INVALID;
}
static void
......@@ -1786,6 +1855,13 @@ drm_output_enable(struct weston_output *base)
assert(!output->virtual);
if (output->gbm_format == DRM_FORMAT_INVALID) {
if (output->base.eotf_mode != WESTON_EOTF_MODE_SDR)
output->gbm_format = DRM_FORMAT_XRGB2101010;
else
output->gbm_format = b->gbm_format;
}
ret = drm_output_attach_crtc(output);
if (ret < 0)
return -1;
......@@ -1845,6 +1921,12 @@ drm_output_deinit(struct weston_output *base)
drm_output_deinit_planes(output);
drm_output_detach_crtc(output);
if (output->hdr_output_metadata_blob_id) {
drmModeDestroyPropertyBlob(b->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = 0;
}
}
static void
......@@ -1879,6 +1961,8 @@ drm_output_destroy(struct weston_output *base)
assert(!output->state_last);
drm_output_state_free(output->state_cur);
assert(output->hdr_output_metadata_blob_id == 0);
free(output);
}
......@@ -2053,12 +2137,21 @@ drm_connector_fini(struct drm_connector *connector)
static void
drm_head_log_info(struct drm_head *head, const char *msg)
{
char *eotf_list;
if (head->base.connected) {
weston_log("DRM: head '%s' %s, connector %d is connected, "
"EDID make '%s', model '%s', serial '%s'\n",
head->base.name, msg, head->connector.connector_id,
head->base.make, head->base.model,
head->base.serial_number ?: "");
eotf_list = weston_eotf_mask_to_str(head->base.supported_eotf_mask);
if (eotf_list) {
weston_log_continue(STAMP_SPACE
"Supported EOTF modes: %s\n",
eotf_list);
}
free(eotf_list);
} else {
weston_log("DRM: head '%s' %s, connector %d is disconnected.\n",
head->base.name, msg, head->connector.connector_id);
......@@ -2215,6 +2308,7 @@ drm_output_create(struct weston_compositor *compositor, const char *name)
output->backend = b;
output->crtc = NULL;
output->gbm_format = DRM_FORMAT_INVALID;
#ifdef BUILD_DRM_GBM
output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
#endif
......
......@@ -143,6 +143,9 @@ const struct drm_property_info connector_props[] = {
.enum_values = panel_orientation_enums,
.num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
},
[WDRM_CONNECTOR_HDR_OUTPUT_METADATA] = {
.name = "HDR_OUTPUT_METADATA",
},
};
const struct drm_property_info crtc_props[] = {
......@@ -970,10 +973,18 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
WDRM_CONNECTOR_CRTC_ID, 0);
}
wl_list_for_each(head, &output->base.head_list, base.output_link)
wl_list_for_each(head, &output->base.head_list, base.output_link) {
drm_connector_set_hdcp_property(&head->connector,
state->protection, req);
if (drm_connector_has_prop(&head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
output->hdr_output_metadata_blob_id);
}
}
if (ret != 0) {
weston_log("couldn't set atomic CRTC/connector state\n");
return ret;
......
/*
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com>
* Copyright (c) 2008 Red Hat Inc.
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
* Copyright (c) 2007-2008 Intel Corporation
*
* 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 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 <xf86drmMode.h>
/*
* This header contains fallback definitions copied from libdrm upstream to
* avoid hard-depending on too new libdrm.
*/
#if !HAVE_LIBDRM_HDR
/**
* struct hdr_metadata_infoframe - HDR Metadata Infoframe Data.
*
* HDR Metadata Infoframe as per CTA 861.G spec. This is expected
* to match exactly with the spec.
*
* Userspace is expected to pass the metadata information as per
* the format described in this structure.
*/
struct hdr_metadata_infoframe {
/**
* @eotf: Electro-Optical Transfer Function (EOTF)
* used in the stream.
*/
__u8 eotf;
/**
* @metadata_type: Static_Metadata_Descriptor_ID.
*/
__u8 metadata_type;
/**
* @display_primaries: Color Primaries of the Data.
* These are coded as unsigned 16-bit values in units of
* 0.00002, where 0x0000 represents zero and 0xC350
* represents 1.0000.
* @display_primaries.x: X cordinate of color primary.
* @display_primaries.y: Y cordinate of color primary.
*/
struct {
__u16 x, y;
} display_primaries[3];
/**
* @white_point: White Point of Colorspace Data.
* These are coded as unsigned 16-bit values in units of
* 0.00002, where 0x0000 represents zero and 0xC350
* represents 1.0000.
* @white_point.x: X cordinate of whitepoint of color primary.
* @white_point.y: Y cordinate of whitepoint of color primary.
*/
struct {
__u16 x, y;
} white_point;
/**
* @max_display_mastering_luminance: Max Mastering Display Luminance.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_display_mastering_luminance;
/**
* @min_display_mastering_luminance: Min Mastering Display Luminance.
* This value is coded as an unsigned 16-bit value in units of
* 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
* represents 6.5535 cd/m2.
*/
__u16 min_display_mastering_luminance;
/**
* @max_cll: Max Content Light Level.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_cll;
/**
* @max_fall: Max Frame Average Light Level.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_fall;
};
/**
* struct hdr_output_metadata - HDR output metadata
*
* Metadata Information to be passed from userspace
*/
struct hdr_output_metadata {
/**
* @metadata_type: Static_Metadata_Descriptor_ID.
*/
__u32 metadata_type;
/**
* @hdmi_metadata_type1: HDR Metadata Infoframe.
*/
union {
struct hdr_metadata_infoframe hdmi_metadata_type1;
};
};
#endif /* !HAVE_LIBDRM_HDR */
......@@ -19,6 +19,11 @@ dep_backlight = declare_dependency(
config_h.set('BUILD_DRM_COMPOSITOR', '1')
config_h.set10(
'HAVE_LIBDRM_HDR',
dep_libdrm.version().version_compare('>= 2.4.104')
)
srcs_drm = [
'drm.c',
'fb.c',
......
......@@ -304,6 +304,8 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
* \param[out] make The monitor make (PNP ID).
* \param[out] model The monitor model (name).
* \param[out] serial_number The monitor serial number.
* \param[out] eotf_mask The monitor supported EOTF modes, combination of
* enum weston_eotf_mode bits.
*
* Each of \c *make, \c *model and \c *serial_number are set only if the
* information is found in the EDID. The pointers they are set to must not
......@@ -315,7 +317,8 @@ find_and_parse_output_edid(struct drm_head *head,
drmModeObjectPropertiesPtr props,
const char **make,
const char **model,
const char **serial_number)
const char **serial_number,
uint32_t *eotf_mask)
{
drmModePropertyBlobPtr edid_blob = NULL;
uint32_t blob_id;
......@@ -344,6 +347,21 @@ find_and_parse_output_edid(struct drm_head *head,
*serial_number = head->edid.serial_number;
}
drmModeFreePropertyBlob(edid_blob);
/* TODO: parse this from EDID */
*eotf_mask = WESTON_EOTF_MODE_ALL_MASK;
}
static void
prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
{
const struct drm_property_info *info;
/* Without the KMS property, cannot do anything but SDR. */
info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA];
if (!head->backend->atomic_modeset || info->prop_id == 0)
*eotf_mask = WESTON_EOTF_MODE_SDR;
}
static uint32_t
......@@ -515,9 +533,12 @@ update_head_from_connector(struct drm_head *head)
const char *make = "unknown";
const char *model = "unknown";
const char *serial_number = "unknown";
uint32_t eotf_mask = WESTON_EOTF_MODE_SDR;
find_and_parse_output_edid(head, props, &make, &model, &serial_number);
find_and_parse_output_edid(head, props, &make, &model, &serial_number, &eotf_mask);
weston_head_set_monitor_strings(&head->base, make, model, serial_number);
prune_eotf_modes_by_kms_support(head, &eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, eotf_mask);
weston_head_set_non_desktop(&head->base,
check_non_desktop(connector, props));
weston_head_set_subpixel(&head->base,
......
......@@ -361,6 +361,8 @@ headless_head_create(struct weston_compositor *compositor,
weston_head_init(&head->base, name);
weston_head_set_connection_status(&head->base, true);
weston_head_set_supported_eotf_mask(&head->base,
WESTON_EOTF_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.
......
......@@ -136,6 +136,10 @@ weston_head_set_subpixel(struct weston_head *head,
void
weston_head_set_transform(struct weston_head *head, uint32_t transform);
void
weston_head_set_supported_eotf_mask(struct weston_head *head,
uint32_t eotf_mask);
/* weston_output */
void
......
......@@ -102,6 +102,8 @@ cmlcms_get_surface_color_transform(struct weston_color_manager *cm_base,
struct cmlcms_color_transform_search_param param = {};
struct cmlcms_color_transform *xform;
/* TODO: take weston_output::eotf_mode into account */
setup_search_param(CMLCMS_CATEGORY_INPUT_TO_BLEND, surface, output,
cm->sRGB_profile, &param);
......@@ -132,6 +134,8 @@ cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
struct cmlcms_color_transform_search_param param = {};
struct cmlcms_color_transform *xform;
/* TODO: take weston_output::eotf_mode into account */
setup_search_param(CMLCMS_CATEGORY_BLEND_TO_OUTPUT, NULL, output,
cm->sRGB_profile, &param);
......@@ -152,6 +156,8 @@ cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
struct cmlcms_color_transform_search_param param = {};
struct cmlcms_color_transform *xform;
/* TODO: take weston_output::eotf_mode into account */
setup_search_param(CMLCMS_CATEGORY_INPUT_TO_OUTPUT, NULL, output,
cm->sRGB_profile, &param);
/*
......@@ -179,6 +185,8 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
struct cmlcms_color_transform_search_param param = {};
struct cmlcms_color_transform *xform;
/* TODO: take weston_output::eotf_mode into account */
setup_search_param(CMLCMS_CATEGORY_INPUT_TO_BLEND, NULL, output,
cm->sRGB_profile, &param);
......
......@@ -35,6 +35,18 @@ struct weston_color_manager_noop {
struct weston_color_manager base;
};
static bool
check_output_eotf_mode(struct weston_output *output)
{
if (output->eotf_mode == WESTON_EOTF_MODE_SDR)
return true;
weston_log("Error: color manager no-op does not support EOTF mode %s of output %s.\n",
weston_eotf_mode_to_str(output->eotf_mode),
output->name);
return false;
}
static struct weston_color_manager_noop *
get_cmnoop(struct weston_color_manager *cm_base)
{
......@@ -74,6 +86,9 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
/* TODO: Assert surface has no colorspace set */
assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */
surf_xform->transform = NULL;
surf_xform->identity_pipeline = true;
......@@ -88,6 +103,9 @@ cmnoop_get_output_color_transform(struct weston_color_manager *cm_base,
{
assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */
*xform_out = NULL;
......@@ -101,6 +119,9 @@ cmnoop_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base,
{
assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */
*xform_out = NULL;
......@@ -114,6 +135,9 @@ cmnoop_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
{
assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */
*xform_out = NULL;
......
......@@ -297,3 +297,55 @@ out_close:
close(fd);
return cprof;
}
/** Get a string naming the EOTF mode
*
* \internal
*/
WL_EXPORT const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e)
{
switch (e) {
case WESTON_EOTF_MODE_NONE: return "(none)";
case WESTON_EOTF_MODE_SDR: return "SDR";
case WESTON_EOTF_MODE_TRADITIONAL_HDR: return "traditional gamma HDR";
case WESTON_EOTF_MODE_ST2084: return "ST2084";
case WESTON_EOTF_MODE_HLG: return "HLG";
}
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)
{
FILE *fp;
char *str = NULL;
size_t size = 0;
unsigned i;
const char *sep = "";
fp = open_memstream(&str, &size);
if (!fp)
return NULL;
for (i = 0; eotf_mask; i++) {
uint32_t bitmask = 1u << i;
if (eotf_mask & bitmask) {
fprintf(fp, "%s%s", sep,
weston_eotf_mode_to_str(bitmask));
sep = ", ";
}
eotf_mask &= ~bitmask;
}
fclose(fp);
return str;
}
......@@ -379,4 +379,10 @@ weston_color_manager_noop_create(struct weston_compositor *compositor);
struct weston_color_manager *
weston_color_manager_create(struct weston_compositor *compositor);
const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e);
char *
weston_eotf_mask_to_str(uint32_t eotf_mask);
#endif /* WESTON_COLOR_H */
......@@ -5437,6 +5437,7 @@ weston_head_init(struct weston_head *head, const char *name)
wl_list_init(&head->resource_list);
wl_list_init(&head->xdg_output_resource_list);
head->name = strdup(name);
head->supported_eotf_mask = WESTON_EOTF_MODE_SDR;
head->current_protection = WESTON_HDCP_DISABLE;
}
......@@ -5962,6 +5963,31 @@ weston_head_set_connection_status(struct weston_head *head, bool connected)
weston_head_set_device_changed(head);
}
/** Store the set of supported EOTF modes
*
* \param head The head to modify.
* \param eotf_mask A bit mask with the possible bits or'ed together from
* enum weston_eotf_mode.
*
* This may set the device_changed flag.
*
* \ingroup head
* \internal
*/
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);
if (head->supported_eotf_mask == eotf_mask)
return;
head->supported_eotf_mask = eotf_mask;
weston_head_set_device_changed(head);
}
static void
weston_output_compute_protection(struct weston_output *output)
{
......@@ -6714,6 +6740,50 @@ weston_output_set_color_profile(struct weston_output *output,
return true;
}
/** Set EOTF mode on an output
*
* \param output The output to modify, must be in disabled state.
* \param eotf_mode The EOTF mode to set.
*
* Setting the output EOTF mode is used for turning HDR on/off. There are
* multiple modes for HDR on, see enum weston_eotf_mode. This is the high level
* choice on how to drive a video sink (monitor), either in the traditional
* SDR mode or in one of the HDR modes.
*
* After attaching heads to an output, you can find out the possibly supported
* EOTF modes with weston_output_get_supported_eotf_modes().
*
* This function does not check whether the given eotf_mode is actually
* supported on the output. Enabling an output with an unsupported EOTF mode
* has undefined visual results.
*
* The initial EOTF mode is SDR.
*
* \ingroup output
*/
WL_EXPORT void
weston_output_set_eotf_mode(struct weston_output *output,
enum weston_eotf_mode eotf_mode)
{
assert(!output->enabled);
output->eotf_mode = eotf_mode;
}
/** Get EOTF mode of an output
*
* \param output The output to query.
* \return The EOTF mode.
*
* \sa weston_output_set_eotf_mode
* \ingroup output
*/
WL_EXPORT enum weston_eotf_mode
weston_output_get_eotf_mode(const struct weston_output *output)
{
return output->eotf_mode;
}
/** Initializes a weston_output object with enough data so
** an output can be configured.
*
......@@ -6741,6 +6811,7 @@ weston_output_init(struct weston_output *output,
wl_list_init(&output->link);
wl_signal_init(&output->user_destroy_signal);
output->enabled = false;
output->eotf_mode = WESTON_EOTF_MODE_SDR;
output->desired_protection = WESTON_HDCP_DISABLE;
output->allow_protection = true;
......@@ -6903,6 +6974,9 @@ weston_output_enable(struct weston_output *output)
wl_list_init(&output->paint_node_list);
wl_list_init(&output->paint_node_z_order_list);
weston_log("Output '%s' attempts EOTF mode: %s\n", output->name,
weston_eotf_mode_to_str(output->eotf_mode));
if (!weston_output_set_color_transforms(output))
return -1;
......@@ -7222,6 +7296,34 @@ weston_output_allow_protection(struct weston_output *output,
output->allow_protection = allow_protection;
}
/** Get supported EOTF modes as a bit mask
*
* \param output The output to query.
* \return A bit mask with values from enum weston_eotf_mode or'ed together.
*
* Returns the bit mask of the EOTF modes that all the currently attached
* heads claim to support. Adding or removing heads may change the result.
* An output can be queried regrdless of whether it is enabled or disabled.
*
* If no heads are attached, no EOTF modes are deemed supported.
*
* \ingroup output
*/
WL_EXPORT uint32_t
weston_output_get_supported_eotf_modes(struct weston_output *output)
{
uint32_t eotf_modes = WESTON_EOTF_MODE_ALL_MASK;
struct weston_head *head;
if (wl_list_empty(&output->head_list))
return WESTON_EOTF_MODE_NONE;
wl_list_for_each(head, &output->head_list, output_link)
eotf_modes = eotf_modes & head->supported_eotf_mask;
return eotf_modes;
}
static void
xdg_output_unlist(struct wl_resource *resource)
{
......
......@@ -57,7 +57,8 @@ The actually supported pixel formats depend on the DRM driver and hardware,
and the renderer used. Using Pixman-renderer, DRM-backend supports only
.BR xrgb8888 " and " rgb565 .
The formats supported with GL-renderer depend on the EGL and OpenGL ES 2 or 3
implementations. The names are case-insensitive.
implementations. The names are case-insensitive. This setting applies only to
.RB "outputs in SDR mode, see " eotf-mode " in " weston.ini (5).
.RB "If not specified, " xrgb8888 " is used. See also " gbm-format " in"
.BR output " section."
......@@ -134,9 +135,11 @@ and possibly flipped. Possible values are
.TP
\fBgbm-format\fR=\fIformat\fR
Set the DRM KMS framebuffer format for this specific output. If not set,
.RB "the value from " gbm-format " option in " core " section is used."
.RB "the value from " gbm-format " option in " core " section is used"
.RB "for SDR mode outputs and " xrgb2101010 " for other modes."
.RI "For the possible values for " format " see "
.BR gbm-format " option in " core " section."
.RB "For SDR mode, see " eotf-mode " in " weston.ini (7).
.TP
\fBpixman-shadow\fR=\fIboolean\fR
If using the Pixman-renderer, use shadow framebuffers. Defaults to
......
......@@ -548,6 +548,25 @@ of content-protection protocol. Currently, HDCP is supported by drm-backend.
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 "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
display driver, the graphics card, and the video sink (monitor) need to support
the chosen mode, otherwise the result is undefined.
The mode can be one of the following strings:
.PP
.RS 10
.nf
.BR "sdr " "traditional gamma, SDR"
.BR "hdr-gamma " "traditional gamma, HDR"
.BR "st2084 " "SMPTE ST 2084, a.k.a Perceptual Quantizer"
.BR "hlg " "Hybrid Log-Gamma (ITU-R BT.2100)"
.fi
.RE
.IP
Defaults to
.BR sdr ". Non-SDR modes require " "color-management=true" .
.\"---------------------------------------------------------------------
.SH "INPUT-METHOD SECTION"
.TP 7
......