Skip to content
Commits on Source (9)
  • Pekka Paalanen's avatar
    libweston: add basic output color characteristics API · 3696d9b6
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This adds color_chracteristics field in weston_output. This field is
    intended to be set by compositor frontends and read by color managers.
    Color managers can use this information when choosing the output color
    space and dynamic range, particularly when no ICC profile has been set.
    
    This is most useful for HDR outputs, where the HDR static metadata for
    PQ mode or the display luminance parameters for HLG mode can be based on
    color_characteristics.
    
    The fields of weston_color_characteristics mirror the information
    available in EDID. However, using EDID information as-is has several
    caveats, so the decision to use EDID for this is left for the frontend
    and ultimately to the end user.
    
    There are no defined ranges or validity checks for this data. The color
    manager will have to validate the values against whatever it is using
    them for.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    3696d9b6
  • Pekka Paalanen's avatar
    compositor: add color_characteristics weston.ini option · 518d72a3
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This adds an option to program basic display color characteristics from
    weston.ini. In the future there will be a way to set this information
    from EDID, but because EDID is unreliable that will probably not be the
    default. An ICC profile will likely override most or all of this. The
    main reason to add this option is to be able to characterise HDR
    monitors.
    
    An 'output' section can have a key 'color_characteristics' (string)
    set to a name. The name refers to any 'color_characteristics' section
    with 'name' set to the same string.
    
    The 'name' key of a 'color_characteristics' section cannot contain a
    colon ':'. Names with colon in 'output' section key
    'color_characteristics' value are reserved for future use, e.g. to
    indicate that the metadata is to be taken from EDID instead of a
    weston.ini section.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    518d72a3
  • Pekka Paalanen's avatar
    libweston: add HDR metadata to weston_output · cea53a90
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This adds hdr_meta field in weston_output_color_outcome. This field is
    intended to be set by color manager modules, and read by backends which
    will send the information to the video sink in SMPTE ST 2084 mode a.k.a
    Perceptual Quantizer HDR system.
    
    Such metadata is essential in ST 2084 mode for the video sink to produce
    a good picture.
    
    The validation of the data and the group split is based on the HDR
    Static Metata Type 1 definition in CTA-861-G specification.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    cea53a90
  • Pekka Paalanen's avatar
    color-lcms: color characteristics into HDR metadata · e108c1a2
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This is the beginnings of creating composited content HDR metadata for
    the ST2084 HDR mode. The immediate goal is to allow essentially setting
    the HDR metadata from weston.ini, so that it can be experimented with.
    
    Setting an output ICC profile will stop weston.ini metadata from taking
    effect, but using an ICC profile in HDR mode is an open question anyway.
    
    maxDML, maxCLL, and minDML are set based on the assumption that we want
    to make use of the full sink/monitor dynamic range.
    
    This also adds several TODOs about how we should handle output profiles,
    basic output color characteristics, and HDR metadata. Implementing these
    properly will take more thought and effort.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    e108c1a2
  • Pekka Paalanen's avatar
    tests: add color-metadata-parsing · e13e64c4
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Check that weston.ini settings to eotf-mode and basic color
    characteristics are correctly parsed.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    e13e64c4
  • Pekka Paalanen's avatar
    tests: add color-metadata-errors test · ccb4c383
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    'color_characteristics_config_error' test ensures that all code paths in
    parse_color_characteristics() and wet_output_set_color_characteristics()
    get exercised.  The return value and logged error messages are checked.
    
    Other cases test the weston_hdr_metadata_type1 validation.
    
    These are for the sake of test coverage, but also an example of how to
    test a function from main.c, and how to capture messages from
    weston_log().
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    ccb4c383
  • Pekka Paalanen's avatar
    backend-drm: move code to kms-color.c · c4fedd50
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    This creates a new file for KMS related color code, to avoid making
    drm.c even longer.
    
    The moved code was just added in 5151f9fe
    so the new file copyrights are written based on that.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    c4fedd50
  • Pekka Paalanen's avatar
    backend-drm: forward HDR metadata · c217453c
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Forward the HDR Static Metadata Type 1 to the video sink. This makes the
    sink aware of our video content parameters and may be able to produce a
    better picture. This type of metadata is used only with the ST 2084 HDR
    mode a.k.a PQ.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    c217453c
  • Pekka Paalanen's avatar
    drm-backend: add color_outcome / HDR metadata serial · 8ebebb20
    Pekka Paalanen authored and Pekka Paalanen's avatar Pekka Paalanen committed
    
    
    Output color profile may be changed in flight. Output basic color
    characteristics and EOTF mode cannot yet be changed in flight, but it is
    reasonable to assume they could in the future. Therefore the color
    outcome data may change in flight as well, which is the basis for HDR
    metadata, which needs to be updated as well.
    
    Track the changes to color outcome data with a serial number.
    DRM-backend checks the serial number to see if it needs to re-create the
    HDR metadata blob. This allows the changes to propagate all the way to
    KMS.
    
    The code added here is more of a reminder of what should happen than a
    tested path.
    
    Signed-off-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
    8ebebb20
/*
* Copyright © 2010-2011 Intel Corporation
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2012-2018 Collabora, Ltd.
* Copyright © 2012-2018,2022 Collabora, Ltd.
* Copyright © 2010-2011 Benjamin Franzke
* Copyright © 2013 Jason Ekstrand
* Copyright © 2017, 2018 General Electric Company
......@@ -36,6 +36,7 @@
#include <dlfcn.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <sys/wait.h>
......@@ -54,6 +55,7 @@
#include "git-version.h"
#include <libweston/version.h>
#include "weston.h"
#include "weston-private.h"
#include <libweston/backend-drm.h>
#include <libweston/backend-headless.h>
......@@ -1383,6 +1385,156 @@ wet_output_set_eotf_mode(struct weston_output *output,
return 0;
}
struct wet_color_characteristics_keys {
const char *name;
enum weston_color_characteristics_groups group;
float minval;
float maxval;
};
#define COLOR_CHARAC_NAME "color_characteristics"
static int
parse_color_characteristics(struct weston_color_characteristics *cc_out,
struct weston_config_section *section)
{
static const struct wet_color_characteristics_keys keys[] = {
{ "red_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "red_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "green_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "green_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "blue_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "blue_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "white_x", WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE, 0.0f, 1.0f },
{ "white_y", WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE, 0.0f, 1.0f },
{ "max_L", WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL, 0.0f, 1e5f },
{ "min_L", WESTON_COLOR_CHARACTERISTICS_GROUP_MINL, 0.0f, 1e5f },
{ "maxFALL", WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL, 0.0f, 1e5f },
};
static const char *msgpfx = "Config error in weston.ini [" COLOR_CHARAC_NAME "]";
struct weston_color_characteristics cc = {};
float *const keyvalp[ARRAY_LENGTH(keys)] = {
/* These must be in the same order as keys[]. */
&cc.primary[0].x, &cc.primary[0].y,
&cc.primary[1].x, &cc.primary[1].y,
&cc.primary[2].x, &cc.primary[2].y,
&cc.white.x, &cc.white.y,
&cc.max_luminance,
&cc.min_luminance,
&cc.maxFALL,
};
bool found[ARRAY_LENGTH(keys)] = {};
uint32_t missing_group_mask = 0;
unsigned i;
char *section_name;
int ret = 0;
weston_config_section_get_string(section, "name",
&section_name, "<unnamed>");
if (strchr(section_name, ':') != NULL) {
ret = -1;
weston_log("%s name=%s: reserved name. Do not use ':' character in the name.\n",
msgpfx, section_name);
}
/* Parse keys if they exist */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
double value;
if (weston_config_section_get_double(section, keys[i].name,
&value, NAN) == 0) {
float f = value;
found[i] = true;
/* Range check, NaN shall not pass. */
if (f >= keys[i].minval && f <= keys[i].maxval) {
/* Key found, parsed, and good value. */
*keyvalp[i] = f;
continue;
}
ret = -1;
weston_log("%s name=%s: %s value %f is outside of the range %f - %f.\n",
msgpfx, section_name, keys[i].name, value,
keys[i].minval, keys[i].maxval);
continue;
}
if (errno == EINVAL) {
found[i] = true;
ret = -1;
weston_log("%s name=%s: failed to parse the value of key %s.\n",
msgpfx, section_name, keys[i].name);
}
}
/* Collect set and unset groups */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
uint32_t group = keys[i].group;
if (found[i])
cc.group_mask |= group;
else
missing_group_mask |= group;
}
/* Ensure groups are given fully or not at all. */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
uint32_t group = keys[i].group;
if ((cc.group_mask & group) && (missing_group_mask & group)) {
ret = -1;
weston_log("%s name=%s: group %d key %s is %s. "
"You must set either none or all keys of a group.\n",
msgpfx, section_name, ffs(group), keys[i].name,
found[i] ? "set" : "missing");
}
}
free(section_name);
if (ret == 0)
*cc_out = cc;
return ret;
}
WESTON_EXPORT_FOR_TESTS int
wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc,
struct weston_config_section *section)
{
char *cc_name = NULL;
struct weston_config_section *cc_section;
struct weston_color_characteristics cc;
weston_config_section_get_string(section, COLOR_CHARAC_NAME,
&cc_name, NULL);
if (!cc_name)
return 0;
cc_section = weston_config_get_section(wc, COLOR_CHARAC_NAME,
"name", cc_name);
if (!cc_section) {
weston_log("Config error in weston.ini, output %s: "
"no [" COLOR_CHARAC_NAME "] section with 'name=%s' found.\n",
output->name, cc_name);
goto out_error;
}
if (parse_color_characteristics(&cc, cc_section) < 0)
goto out_error;
weston_output_set_color_characteristics(output, &cc);
free(cc_name);
return 0;
out_error:
free(cc_name);
return -1;
}
static void
allow_content_protection(struct weston_output *output,
struct weston_config_section *section)
......@@ -1909,6 +2061,10 @@ drm_backend_output_configure(struct weston_output *output,
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
if (wet_output_set_color_characteristics(output,
wet->config, section) < 0)
return -1;
return 0;
}
......@@ -2732,6 +2888,9 @@ headless_backend_output_configure(struct weston_output *output)
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
if (wet_output_set_color_characteristics(output, wc, section) < 0)
return -1;
return wet_configure_windowed_output_from_config(output, &defaults);
}
......
/*
* Copyright 2022 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <libweston/libweston.h>
#include <libweston/config-parser.h>
int
wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc,
struct weston_config_section *section);
......@@ -241,6 +241,120 @@ enum weston_eotf_mode {
((uint32_t)(WESTON_EOTF_MODE_SDR | WESTON_EOTF_MODE_TRADITIONAL_HDR | \
WESTON_EOTF_MODE_ST2084 | WESTON_EOTF_MODE_HLG))
/** CIE 1931 xy chromaticity coordinates */
struct weston_CIExy {
float x;
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,
/** weston_color_characteristics::white is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE = 0x02,
/** weston_color_characteristics::max_luminance is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL = 0x04,
/** weston_color_characteristics::min_luminance is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MINL = 0x08,
/** weston_color_characteristics::maxFALL is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL = 0x10,
/** all valid bits */
WESTON_COLOR_CHARACTERISTICS_GROUP_ALL_MASK = 0x1f
};
/** Basic display color characteristics
*
* This is a simple description of a display or output (monitor) color
* characteristics. The parameters can be found in EDID, with caveats. They
* are particularly useful with HDR monitors.
*/
struct weston_color_characteristics {
/** Which fields are valid
*
* A bitmask of values from enum weston_color_characteristics_groups.
*/
uint32_t group_mask;
/* EOTF is tracked externally with enum weston_eotf_mode */
/** Chromaticities of the primaries */
struct weston_CIExy primary[3];
/** White point chromaticity */
struct weston_CIExy white;
/** Display's desired maximum content peak luminance, cd/m² */
float max_luminance;
/** Display's desired minimum content luminance, cd/m² */
float min_luminance;
/** Display's desired maximum frame-average light level, cd/m² */
float maxFALL;
};
/** Represents a head, usually a display connector
*
* \rst
......@@ -301,6 +415,9 @@ struct weston_output_color_outcome {
/** 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;
};
/** Content producer for heads
......@@ -414,8 +531,10 @@ struct weston_output {
struct weston_color_profile *color_profile;
bool from_blend_to_output_by_backend;
enum weston_eotf_mode eotf_mode;
struct weston_color_characteristics color_characteristics;
struct weston_output_color_outcome *color_outcome;
uint64_t color_outcome_serial;
int (*enable)(struct weston_output *output);
int (*disable)(struct weston_output *output);
......@@ -2142,6 +2261,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_color_characteristics(struct weston_output *output,
const struct weston_color_characteristics *cc);
const struct weston_color_characteristics *
weston_output_get_color_characteristics(struct weston_output *output);
void
weston_output_init(struct weston_output *output,
struct weston_compositor *compositor,
......
......@@ -551,6 +551,7 @@ struct drm_output {
uint32_t gbm_bo_flags;
uint32_t hdr_output_metadata_blob_id;
uint64_t ackd_color_outcome_serial;
/* Plane being displayed directly on the CRTC */
struct drm_plane *scanout_plane;
......@@ -726,6 +727,9 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
void
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);
#ifdef BUILD_DRM_GBM
extern struct drm_fb *
drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
......
......@@ -51,7 +51,6 @@
#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"
......@@ -441,71 +440,6 @@ 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)
{
......
/*
* Copyright 2021-2022 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <stdint.h>
#include <libweston/libweston.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "drm-internal.h"
#include "libdrm-updates.h"
static inline uint16_t
color_xy_to_u16(float v)
{
assert(v >= 0.0f);
assert(v <= 1.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* chromaticity coordinate encoding
*/
return (uint16_t)round(v * 50000.0);
}
static inline uint16_t
nits_to_u16(float nits)
{
assert(nits >= 1.0f);
assert(nits <= 65535.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* max display mastering luminance, max content light level,
* max frame-average light level
*/
return (uint16_t)round(nits);
}
static inline uint16_t
nits_to_u16_dark(float nits)
{
assert(nits >= 0.0001f);
assert(nits <= 6.5535f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* min display mastering luminance
*/
return (uint16_t)round(nits * 10000.0);
}
static void
weston_hdr_metadata_type1_to_kms(struct hdr_metadata_infoframe *dst,
const struct weston_hdr_metadata_type1 *src)
{
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
dst->display_primaries[i].x = color_xy_to_u16(src->primary[i].x);
dst->display_primaries[i].y = color_xy_to_u16(src->primary[i].y);
}
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_WHITE) {
dst->white_point.x = color_xy_to_u16(src->white.x);
dst->white_point.y = color_xy_to_u16(src->white.y);
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML)
dst->max_display_mastering_luminance = nits_to_u16(src->maxDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MINDML)
dst->min_display_mastering_luminance = nits_to_u16_dark(src->minDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL)
dst->max_cll = nits_to_u16(src->maxCLL);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL)
dst->max_fall = nits_to_u16(src->maxFALL);
}
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
{
const struct weston_hdr_metadata_type1 *src;
struct hdr_output_metadata meta;
uint32_t blob_id = 0;
int ret;
if (output->hdr_output_metadata_blob_id &&
output->ackd_color_outcome_serial == output->base.color_outcome_serial)
return 0;
src = weston_output_get_hdr_metadata_type1(&output->base);
/*
* 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 */
weston_hdr_metadata_type1_to_kms(&meta.hdmi_metadata_type1, src);
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;
}
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;
}
drmModeDestroyPropertyBlob(output->backend->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = blob_id;
output->ackd_color_outcome_serial = output->base.color_outcome_serial;
return 0;
}
......@@ -29,6 +29,7 @@ srcs_drm = [
'fb.c',
'modes.c',
'kms.c',
'kms-color.c',
'state-helpers.c',
'state-propose.c',
linux_dmabuf_unstable_v1_protocol_c,
......@@ -37,6 +38,7 @@ srcs_drm = [
]
deps_drm = [
dep_libm,
dep_libdl,
dep_libweston_private,
dep_session_helper,
......
......@@ -32,6 +32,8 @@
#ifndef LIBWESTON_BACKEND_INTERNAL_H
#define LIBWESTON_BACKEND_INTERNAL_H
struct weston_hdr_metadata_type1;
struct weston_backend {
void (*destroy)(struct weston_compositor *compositor);
......@@ -173,6 +175,9 @@ void
weston_output_region_from_global(struct weston_output *output,
pixman_region32_t *region);
const struct weston_hdr_metadata_type1 *
weston_output_get_hdr_metadata_type1(const struct weston_output *output);
/* weston_seat */
void
......
......@@ -27,6 +27,7 @@
#include "config.h"
#include <assert.h>
#include <string.h>
#include <libweston/libweston.h>
#include "color.h"
......@@ -185,6 +186,102 @@ cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager_lcms *cm,
return true;
}
static float
meta_clamp(float value, const char *valname, float min, float max,
struct weston_output *output)
{
float ret = value;
/* Paranoia against NaN */
if (!(ret >= min))
ret = min;
if (!(ret <= max))
ret = max;
if (ret != value) {
weston_log("output '%s' clamping %s value from %f to %f.\n",
output->name, valname, value, ret);
}
return ret;
}
static bool
cmlcms_get_hdr_meta(struct weston_output *output,
struct weston_hdr_metadata_type1 *hdr_meta)
{
const struct weston_color_characteristics *cc;
hdr_meta->group_mask = 0;
/* Only SMPTE ST 2084 mode uses HDR Static Metadata Type 1 */
if (weston_output_get_eotf_mode(output) != WESTON_EOTF_MODE_ST2084)
return true;
/* ICC profile overrides color characteristics */
if (output->color_profile) {
/*
* TODO: extract characteristics from profile?
* Get dynamic range from weston_color_characteristics?
*/
return true;
}
cc = weston_output_get_color_characteristics(output);
/* Target content chromaticity */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
hdr_meta->primary[i].x = meta_clamp(cc->primary[i].x,
"primary", 0.0, 1.0,
output);
hdr_meta->primary[i].y = meta_clamp(cc->primary[i].y,
"primary", 0.0, 1.0,
output);
}
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES;
}
/* Target content white point */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE) {
hdr_meta->white.x = meta_clamp(cc->white.x, "white",
0.0, 1.0, output);
hdr_meta->white.y = meta_clamp(cc->white.y, "white",
0.0, 1.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE;
}
/* Target content peak and max mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL) {
hdr_meta->maxDML = meta_clamp(cc->max_luminance, "maxDML",
1.0, 65535.0, output);
hdr_meta->maxCLL = meta_clamp(cc->max_luminance, "maxCLL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML;
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL;
}
/* Target content min mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MINL) {
hdr_meta->minDML = meta_clamp(cc->min_luminance, "minDML",
0.0001, 6.5535, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MINDML;
}
/* Target content max frame-average luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL) {
hdr_meta->maxFALL = meta_clamp(cc->maxFALL, "maxFALL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL;
}
return true;
}
static struct weston_output_color_outcome *
cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output)
......@@ -196,6 +293,19 @@ cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base,
if (!co)
return NULL;
if (!cmlcms_get_hdr_meta(output, &co->hdr_meta))
goto out_fail;
/*
* TODO: if output->color_profile is NULL, maybe manufacture a
* profile from weston_color_characteristics if it has enough
* information?
* Or let the frontend decide to call a "create a profile from
* characteristics" API?
*/
/* TODO: take container color space into account */
if (!cmlcms_get_blend_to_output_color_transform(cm, output,
&co->from_blend_to_output))
goto out_fail;
......
......@@ -116,6 +116,8 @@ cmnoop_create_output_color_outcome(struct weston_color_manager *cm_base,
co->from_sRGB_to_blend = NULL;
co->from_sRGB_to_output = NULL;
co->hdr_meta.group_mask = 0;
return co;
}
......
......@@ -6449,6 +6449,57 @@ weston_output_transform_coordinate(struct weston_output *output,
*y = p.f[1] / p.f[3];
}
static bool
validate_float_range(float val, float min, float max)
{
return val >= min && val <= max;
}
/* Based on CTA-861-G, HDR static metadata type 1 */
static bool
weston_hdr_metadata_type1_validate(const struct weston_hdr_metadata_type1 *md)
{
unsigned i;
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES) {
for (i = 0; i < ARRAY_LENGTH(md->primary); i++) {
if (!validate_float_range(md->primary[i].x, 0.0, 1.0))
return false;
if (!validate_float_range(md->primary[i].y, 0.0, 1.0))
return false;
}
}
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_WHITE) {
if (!validate_float_range(md->white.x, 0.0, 1.0))
return false;
if (!validate_float_range(md->white.y, 0.0, 1.0))
return false;
}
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML) {
if (!validate_float_range(md->maxDML, 1.0, 65535.0))
return false;
}
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MINDML) {
if (!validate_float_range(md->minDML, 0.0001, 6.5535))
return false;
}
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL) {
if (!validate_float_range(md->maxCLL, 1.0, 65535.0))
return false;
}
if (md->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL) {
if (!validate_float_range(md->maxFALL, 1.0, 65535.0))
return false;
}
return true;
}
WL_EXPORT void
weston_output_color_outcome_destroy(struct weston_output_color_outcome **pco)
{
......@@ -6465,7 +6516,7 @@ weston_output_color_outcome_destroy(struct weston_output_color_outcome **pco)
*pco = NULL;
}
static bool
WESTON_EXPORT_FOR_TESTS bool
weston_output_set_color_outcome(struct weston_output *output)
{
struct weston_color_manager *cm = output->compositor->color_manager;
......@@ -6475,12 +6526,18 @@ weston_output_set_color_outcome(struct weston_output *output)
if (!colorout) {
weston_log("Creating color transformation for output \"%s\" failed.\n",
output->name);
return false;
}
if (!weston_hdr_metadata_type1_validate(&colorout->hdr_meta)) {
weston_log("Internal color manager error creating Metadata Type 1 for output \"%s\".\n",
output->name);
goto out_error;
}
weston_output_color_outcome_destroy(&output->color_outcome);
output->color_outcome = colorout;
output->color_outcome_serial++;
output->from_blend_to_output_by_backend = false;
......@@ -6488,6 +6545,11 @@ weston_output_set_color_outcome(struct weston_output *output)
weston_color_profile_get_description(output->color_profile));
return true;
out_error:
weston_output_color_outcome_destroy(&colorout);
return false;
}
/** Removes output from compositor's list of enabled outputs
......@@ -6764,6 +6826,67 @@ weston_output_get_eotf_mode(const struct weston_output *output)
return output->eotf_mode;
}
/** Get HDR static metadata type 1
*
* \param output The output to query.
* \return Pointer to the metadata stored in weston_output.
*
* This function is meant to be used by libweston backends.
*
* \ingroup output
* \internal
*/
WL_EXPORT const struct weston_hdr_metadata_type1 *
weston_output_get_hdr_metadata_type1(const struct weston_output *output)
{
assert(output->color_outcome);
return &output->color_outcome->hdr_meta;
}
/** Set display or monitor basic color characteristics
*
* \param output The output to modify, must be in disabled state.
* \param cc The new characteristics to set, or NULL to unset everything.
*
* This sets the metadata that describes the color characteristics of the
* output in a very simple manner. If a non-NULL color profile is set for the
* output, that will always take precedence.
*
* The initial value has everything unset.
*
* This function is meant to be used by compositor frontends.
*
* \ingroup output
* \sa weston_output_set_color_profile
*/
WL_EXPORT void
weston_output_set_color_characteristics(struct weston_output *output,
const struct weston_color_characteristics *cc)
{
assert(!output->enabled);
if (cc)
output->color_characteristics = *cc;
else
output->color_characteristics.group_mask = 0;
}
/** Get display or monitor basic color characteristics
*
* \param output The output to query.
* \return Pointer to the metadata stored in weston_output.
*
* This function is meant to be used by color manager modules.
*
* \ingroup output
* \sa weston_output_set_color_characteristics
*/
WL_EXPORT const struct weston_color_characteristics *
weston_output_get_color_characteristics(struct weston_output *output)
{
return &output->color_characteristics;
}
/** Initializes a weston_output object with enough data so
** an output can be configured.
*
......
......@@ -462,4 +462,9 @@ weston_view_find_paint_node(struct weston_view *view,
int
wl_data_device_manager_init(struct wl_display *display);
/* Exclusively for unit tests */
bool
weston_output_set_color_outcome(struct weston_output *output);
#endif
......@@ -567,6 +567,13 @@ The mode can be one of the following strings:
.IP
Defaults to
.BR sdr ". Non-SDR modes require " "color-management=true" .
.TP 7
.BI "color_characteristics=" name
Sets the basic output color characteristics by loading the parameters from the
.B color_characteristics
section with the key
.BI "name=" name
\&. If an ICC profile is also set, the ICC profile takes precedence.
.\"---------------------------------------------------------------------
.SH "INPUT-METHOD SECTION"
.TP 7
......@@ -663,6 +670,69 @@ parallel to Weston, so it does not have to immediately exit. Defaults to empty.
If set to true, quit Weston after the auto-launched executable exits. Set to false
by default.
.\"---------------------------------------------------------------------
.SH "COLOR_CHARACTERISTICS SECTION"
Each
.B color_characteristics
section records one set of basic display or monitor color characterisation
parameters. The parameters are defined in CTA-861-H specification as Static
Metadata Type 1, and they can also be found in EDID. The parameters are
divided into groups. Each group must be given either fully or not at all.
.PP
Each section should be named with
.B name
key by which it can be referenced from other sections. A metadata section is
just a collection of parameter values and does nothing on its own. It has an
effect only when referenced from elsewhere.
.PP
See
.BR output " section key " color_characteristics .
.TP 7
.BI "name=" name
An arbitrary name for this section. You can choose any name you want as long as
it does not contain the colon
.RB ( : )
character. Names with at least one colon are reserved.
.SS Primaries group
.TP 7
.BI "red_x=" x
.TQ
.BI "red_y=" y
.TQ
.BI "green_x=" x
.TQ
.BI "green_y=" y
.TQ
.BI "blue_x=" x
.TQ
.BI "blue_y=" y
The CIE 1931 xy chromaticity coordinates of the display primaries.
These floating point values must reside between 0.0 and 1.0, inclusive.
.SS White point group
.TP 7
.BI "white_x=" x
.TQ
.BI "white_y=" y
The CIE 1931 xy chromaticity coordinates of the display white point.
These floating point values must reside between 0.0 and 1.0, inclusive.
.SS Independent parameters
Each parameter listed here has its own group and therefore can be given
alone.
.TP 7
.BI "max_L=" L
Display's desired maximum content luminance (peak)
.IR L \~cd/m²,
a floating point value in the range 0.0\(en100000.0.
.TP 7
.BI "min_L=" L
Display's desired minimum content luminance
.IR L \~cd/m²,
a floating point value in the range 0.0\(en100000.0.
.TP 7
.BI "maxFALL=" L
Display's desired maximum frame-average light level
.IR L \~cd/m²,
a floating point value in the range 0.0\(en100000.0.
.\"---------------------------------------------------------------------
.SH "SEE ALSO"
.BR weston (1),
.BR weston-bindings (7),
......
/*
* Copyright 2022 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <string.h>
#include <assert.h>
#include <math.h>
#include "weston-test-client-helper.h"
#include "weston-test-fixture-compositor.h"
#include "weston-private.h"
#include "libweston-internal.h"
#include "backend.h"
#include "color.h"
struct config_testcase {
bool has_characteristics_key;
const char *output_characteristics_name;
const char *characteristics_name;
const char *red_x;
const char *green_y;
const char *white_y;
const char *min_L;
int expected_retval;
const char *expected_error;
};
static const struct config_testcase config_cases[] = {
{
false, "fred", "fred", "red_x=0.9", "green_y=0.8", "white_y=0.323", "min_L=1e-4", 0,
""
},
{
true, "fred", "fred", "red_x=0.9", "green_y= 0.8 ", "white_y=0.323", "min_L=1e-4", 0,
""
},
{
true, "fred", "fred", "red_x=0.9", "green_y= 0.8 ", "white_y=0.323", "", 0,
""
},
{
true, "notexisting", "fred", "red_x=0.9", "green_y=0.8", "white_y=0.323", "min_L=1e-4", -1,
"Config error in weston.ini, output mockoutput: no [color_characteristics] section with 'name=notexisting' found.\n"
},
{
true, "fr:ed", "fr:ed", "red_x=0.9", "green_y=0.8", "white_y=0.323", "min_L=1e-4", -1,
"Config error in weston.ini [color_characteristics] name=fr:ed: reserved name. Do not use ':' character in the name.\n"
},
{
true, "fred", "fred", "red_x=-5", "green_y=1.01", "white_y=0.323", "min_L=1e-4", -1,
"Config error in weston.ini [color_characteristics] name=fred: red_x value -5.000000 is outside of the range 0.000000 - 1.000000.\n"
"Config error in weston.ini [color_characteristics] name=fred: green_y value 1.010000 is outside of the range 0.000000 - 1.000000.\n"
},
{
true, "fred", "fred", "red_x=haahaa", "green_y=-", "white_y=0.323", "min_L=1e-4", -1,
"Config error in weston.ini [color_characteristics] name=fred: failed to parse the value of key red_x.\n"
"Config error in weston.ini [color_characteristics] name=fred: failed to parse the value of key green_y.\n"
},
{
true, "fred", "fred", "", "", "white_y=0.323", "min_L=1e-4", -1,
"Config error in weston.ini [color_characteristics] name=fred: group 1 key red_x is missing. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 1 key red_y is set. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 1 key green_x is set. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 1 key green_y is missing. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 1 key blue_x is set. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 1 key blue_y is set. You must set either none or all keys of a group.\n"
},
{
true, "fred", "fred", "red_x=0.9", "green_y=0.8", "", "min_L=1e-4", -1,
"Config error in weston.ini [color_characteristics] name=fred: group 2 key white_x is set. You must set either none or all keys of a group.\n"
"Config error in weston.ini [color_characteristics] name=fred: group 2 key white_y is missing. You must set either none or all keys of a group.\n"
},
};
static FILE *logfile;
static int
logger(const char *fmt, va_list arg)
{
return vfprintf(logfile, fmt, arg);
}
static int
no_logger(const char *fmt, va_list arg)
{
return 0;
}
static struct weston_config *
create_config(const struct config_testcase *t)
{
struct compositor_setup setup;
struct weston_config *wc;
compositor_setup_defaults(&setup);
weston_ini_setup(&setup,
cfgln("[output]"),
cfgln("name=mockoutput"),
t->has_characteristics_key ?
cfgln("color_characteristics=%s", t->output_characteristics_name) :
cfgln(""),
cfgln("eotf-mode=st2084"),
cfgln("[color_characteristics]"),
cfgln("name=%s", t->characteristics_name),
cfgln("maxFALL=1000"),
cfgln("%s", t->red_x),
cfgln("red_y=0.3"),
cfgln("blue_x=0.1"),
cfgln("blue_y=0.11"),
cfgln("green_x=0.1771"),
cfgln("%s", t->green_y),
cfgln("white_x=0.313"),
cfgln("%s", t->white_y),
cfgln("%s", t->min_L),
cfgln("max_L=65535.0"),
cfgln("[core]"),
cfgln("color-management=true"));
wc = weston_config_parse(setup.config_file);
free(setup.config_file);
return wc;
}
/*
* Manufacture various weston.ini and check what
* wet_output_set_color_characteristics() says. Tests for the return value and
* the error messages logged.
*/
TEST_P(color_characteristics_config_error, config_cases)
{
const struct config_testcase *t = data;
struct weston_config *wc;
struct weston_config_section *section;
int retval;
char *logbuf;
size_t logsize;
struct weston_output mock_output = {};
weston_output_init(&mock_output, NULL, "mockoutput");
logfile = open_memstream(&logbuf, &logsize);
weston_log_set_handler(logger, logger);
wc = create_config(t);
section = weston_config_get_section(wc, "output", "name", "mockoutput");
assert(section);
retval = wet_output_set_color_characteristics(&mock_output, wc, section);
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);
weston_config_destroy(wc);
free(logbuf);
weston_output_release(&mock_output);
}
/* Setting NULL resets group_mask */
TEST(weston_output_set_color_characteristics_null)
{
struct weston_output mock_output = {};
weston_output_init(&mock_output, NULL, "mockoutput");
mock_output.color_characteristics.group_mask = 1;
weston_output_set_color_characteristics(&mock_output, NULL);
assert(mock_output.color_characteristics.group_mask == 0);
weston_output_release(&mock_output);
}
struct value_testcase {
unsigned field_index;
float value;
bool retval;
};
static const struct value_testcase value_cases[] = {
{ 0, 0.0, true },
{ 0, 1.0, true },
{ 0, -0.001, false },
{ 0, 1.01, false },
{ 0, NAN, false },
{ 0, HUGE_VALF, false },
{ 0, -HUGE_VALF, false },
{ 1, -1.0, false },
{ 2, 2.0, false },
{ 3, 2.0, false },
{ 4, 2.0, false },
{ 5, 2.0, false },
{ 6, 2.0, false },
{ 7, 2.0, false },
{ 8, 0.99, false },
{ 8, 65535.1, false },
{ 9, 0.000099, false },
{ 9, 6.55351, false },
{ 10, 0.99, false },
{ 10, 65535.1, false },
{ 11, 0.99, false },
{ 11, 65535.1, false },
};
struct mock_color_manager {
struct weston_color_manager base;
struct weston_hdr_metadata_type1 *test_hdr_meta;
};
static struct weston_output_color_outcome *
mock_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output)
{
struct mock_color_manager *cm = container_of(cm_base, typeof(*cm), base);
struct weston_output_color_outcome *co;
co = zalloc(sizeof *co);
assert(co);
co->hdr_meta = *cm->test_hdr_meta;
return co;
}
/*
* Modify one value in a known good metadata structure, and see how
* validation reacts to it.
*/
TEST_P(hdr_metadata_type1_errors, value_cases)
{
struct value_testcase *t = data;
struct weston_hdr_metadata_type1 meta = {
.group_mask = WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK,
.primary[0] = { 0.6650, 0.3261 },
.primary[1] = { 0.2890, 0.6435 },
.primary[2] = { 0.1491, 0.0507 },
.white = { 0.3134, 0.3291 },
.maxDML = 600.0,
.minDML = 0.0001,
.maxCLL = 600.0,
.maxFALL = 400.0,
};
float *fields[] = {
&meta.primary[0].x, &meta.primary[0].y,
&meta.primary[1].x, &meta.primary[1].y,
&meta.primary[2].x, &meta.primary[2].y,
&meta.white.x, &meta.white.y,
&meta.maxDML, &meta.minDML,
&meta.maxCLL, &meta.maxFALL,
};
struct mock_color_manager mock_cm = {
.base.create_output_color_outcome = mock_create_output_color_outcome,
.test_hdr_meta = &meta,
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
};
struct weston_output mock_output = {};
bool ret;
weston_log_set_handler(no_logger, no_logger);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
assert(t->field_index < ARRAY_LENGTH(fields));
*fields[t->field_index] = t->value;
ret = weston_output_set_color_outcome(&mock_output);
assert(ret == t->retval);
weston_output_color_outcome_destroy(&mock_output.color_outcome);
weston_output_release(&mock_output);
}
/* Unflagged members are ignored in validity check */
TEST(hdr_metadata_type1_ignore_unflagged)
{
/* All values invalid, but also empty mask so none actually used. */
struct weston_hdr_metadata_type1 meta = {
.group_mask = 0,
.primary[0] = { -1.0, -1.0 },
.primary[1] = { -1.0, -1.0 },
.primary[2] = { -1.0, -1.0 },
.white = { -1.0, -1.0 },
.maxDML = -1.0,
.minDML = -1.0,
.maxCLL = -1.0,
.maxFALL = -1.0,
};
struct mock_color_manager mock_cm = {
.base.create_output_color_outcome = mock_create_output_color_outcome,
.test_hdr_meta = &meta,
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
};
struct weston_output mock_output = {};
bool ret;
weston_log_set_handler(no_logger, no_logger);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
ret = weston_output_set_color_outcome(&mock_output);
assert(ret);
weston_output_color_outcome_destroy(&mock_output.color_outcome);
weston_output_release(&mock_output);
}
/*
* Copyright 2022 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <string.h>
#include <assert.h>
#include "weston-test-client-helper.h"
#include "weston-test-fixture-compositor.h"
#include "backend.h"
static enum test_result_code
fixture_setup(struct weston_test_harness *harness)
{
struct compositor_setup setup;
compositor_setup_defaults(&setup);
setup.renderer = RENDERER_GL;
setup.shell = SHELL_TEST_DESKTOP;
weston_ini_setup(&setup,
cfgln("[output]"),
cfgln("name=headless"),
cfgln("color_characteristics=my-awesome-color"),
cfgln("eotf-mode=st2084"),
cfgln("[color_characteristics]"),
cfgln("name=my-awesome-color"),
cfgln("maxFALL=1000"),
cfgln("red_x=0.9999"),
cfgln("red_y=0.3"),
cfgln("blue_x=0.1"),
cfgln("blue_y=0.11"),
cfgln("green_x=0.1771"),
cfgln("green_y=0.80001"),
cfgln("white_x=0.313"),
cfgln("white_y=0.323"),
cfgln("min_L=0.0001"),
cfgln("max_L=65535.0"),
cfgln("[core]"),
cfgln("color-management=true"));
return weston_test_harness_execute_as_plugin(harness, &setup);
}
DECLARE_FIXTURE_SETUP(fixture_setup);
PLUGIN_TEST(color_characteristics_from_weston_ini)
{
struct weston_output *output = NULL;
struct weston_output *it;
enum weston_eotf_mode mode;
const struct weston_color_characteristics *cc;
const struct weston_hdr_metadata_type1 *hdr_meta;
wl_list_for_each(it, &compositor->output_list, link) {
if (strcmp(it->name, "headless") == 0) {
output = it;
break;
}
}
assert(output);
mode = weston_output_get_eotf_mode(output);
assert(mode == WESTON_EOTF_MODE_ST2084);
cc = weston_output_get_color_characteristics(output);
assert(cc->group_mask == WESTON_COLOR_CHARACTERISTICS_GROUP_ALL_MASK);
assert(cc->primary[0].x == 0.9999f);
assert(cc->primary[0].y == 0.3f);
assert(cc->primary[1].x == 0.1771f);
assert(cc->primary[1].y == 0.80001f);
assert(cc->primary[2].x == 0.1f);
assert(cc->primary[2].y == 0.11f);
assert(cc->white.x == 0.313f);
assert(cc->white.y == 0.323f);
assert(cc->min_luminance == 0.0001f);
assert(cc->max_luminance == 65535.0f);
assert(cc->maxFALL == 1000.0f);
/* The below is color manager policy. */
hdr_meta = weston_output_get_hdr_metadata_type1(output);
assert(hdr_meta->group_mask == WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK);
assert(hdr_meta->primary[0].x == 0.9999f);
assert(hdr_meta->primary[0].y == 0.3f);
assert(hdr_meta->primary[1].x == 0.1771f);
assert(hdr_meta->primary[1].y == 0.80001f);
assert(hdr_meta->primary[2].x == 0.1f);
assert(hdr_meta->primary[2].y == 0.11f);
assert(hdr_meta->white.x == 0.313f);
assert(hdr_meta->white.y == 0.323f);
assert(hdr_meta->minDML == 0.0001f);
assert(hdr_meta->maxDML == 65535.0f);
assert(hdr_meta->maxCLL == 65535.0f);
assert(hdr_meta->maxFALL == 1000.0f);
}
......@@ -127,6 +127,10 @@ tests = [
},
{ 'name': 'bad-buffer', },
{ 'name': 'buffer-transforms', },
{
'name': 'color-metadata-errors',
'dep_objs': dep_libexec_weston,
},
{ 'name': 'color-manager', },
{ 'name': 'devices', },
{
......@@ -235,10 +239,13 @@ if get_option('color-management-lcms')
if not dep_lcms2.found()
error('color-management-lcms tests require lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.')
endif
tests += {
'name': 'color-shaper-matrix',
'dep_objs': [ dep_libm, dep_lcms2 ]
}
tests += [
{
'name': 'color-shaper-matrix',
'dep_objs': [ dep_libm, dep_lcms2 ]
},
{ 'name': 'color-metadata-parsing' },
]
endif
......