mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2025-12-20 05:50:10 +01:00
Based on what is configured in weston_output, check and set the colorimetry mode into KMS connector property "Colorspace". This changes how video sinks interpret the pixels, and should allow driving e.g. WCG monitors in BT.2020 mode. This does not alter the pixel values themselves. That is the color manager responsibility, and ultimately the responsibility of the frontend and the end user to match the monitor driving mode with the output color profile they chose. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
195 lines
5.6 KiB
C
195 lines
5.6 KiB
C
/*
|
|
* 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"
|
|
|
|
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)
|
|
{
|
|
struct drm_device *device = output->device;
|
|
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(device->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(device->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;
|
|
}
|
|
|
|
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;
|
|
}
|