weston/libweston/color-properties.c

389 lines
16 KiB
C

/*
* Copyright 2023 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"
#ifdef HAVE_LCMS
#include <lcms2.h>
#define LCMS_INTENT(x) .lcms_intent = (x)
#else
/* invalid value */
#define LCMS_INTENT(x) .lcms_intent = 0xffffffff
#endif
#include <libweston/libweston.h>
#include <color-properties.h>
#include "shared/helpers.h"
#include "shared/weston-assert.h"
#include "color-management-v1-server-protocol.h"
static const struct weston_color_feature_info color_feature_info_table[] = {
{
.feature = WESTON_COLOR_FEATURE_ICC,
.desc = "Allow clients to use the new_icc_creator request " \
"from the CM&HDR protocol extension",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_ICC_V2_V4,
},
{
.feature = WESTON_COLOR_FEATURE_PARAMETRIC,
.desc = "Allow clients to use the new_parametric_creator " \
"request from the CM&HDR protocol extension",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_PARAMETRIC,
},
{
.feature = WESTON_COLOR_FEATURE_SET_PRIMARIES,
.desc = "Allow clients to use the parametric set_primaries " \
"request from the CM&HDR protocol extension",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_SET_PRIMARIES,
},
{
.feature = WESTON_COLOR_FEATURE_SET_TF_POWER,
.desc = "Allow clients to use the parametric set_tf_power " \
"request from the CM&HDR protocol extension",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_SET_TF_POWER,
},
{
.feature = WESTON_COLOR_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES,
.desc = "Allow clients to use the parametric " \
"set_mastering_display_primaries request from the " \
"CM&HDR protocol extension",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES,
},
{
.feature = WESTON_COLOR_FEATURE_EXTENDED_TARGET_VOLUME,
.desc = "Allow clients to specify (through the CM&HDR protocol " \
"extension) target color volumes that extend outside of the" \
"primary color volume. This can only be supported when feature " \
"WESTON_COLOR_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES " \
"is supported",
.protocol_feature = XX_COLOR_MANAGER_V2_FEATURE_EXTENDED_TARGET_VOLUME,
},
};
static const struct weston_render_intent_info render_intent_info_table[] = {
{
.intent = WESTON_RENDER_INTENT_PERCEPTUAL,
.desc = "Perceptual",
.protocol_intent = XX_COLOR_MANAGER_V2_RENDER_INTENT_PERCEPTUAL,
LCMS_INTENT(INTENT_PERCEPTUAL),
.bps = false,
},
{
.intent = WESTON_RENDER_INTENT_RELATIVE,
.desc = "Media-relative colorimetric",
.protocol_intent = XX_COLOR_MANAGER_V2_RENDER_INTENT_RELATIVE,
LCMS_INTENT(INTENT_RELATIVE_COLORIMETRIC),
.bps = false,
},
{
.intent = WESTON_RENDER_INTENT_SATURATION,
.desc = "Saturation",
.protocol_intent = XX_COLOR_MANAGER_V2_RENDER_INTENT_SATURATION,
LCMS_INTENT(INTENT_SATURATION),
.bps = false,
},
{
.intent = WESTON_RENDER_INTENT_ABSOLUTE,
.desc = "ICC-absolute colorimetric",
.protocol_intent = XX_COLOR_MANAGER_V2_RENDER_INTENT_ABSOLUTE,
LCMS_INTENT(INTENT_ABSOLUTE_COLORIMETRIC),
.bps = false,
},
{
.intent = WESTON_RENDER_INTENT_RELATIVE_BPC,
.desc = "Media-relative colorimetric + black point compensation",
.protocol_intent = XX_COLOR_MANAGER_V2_RENDER_INTENT_RELATIVE_BPC,
LCMS_INTENT(INTENT_RELATIVE_COLORIMETRIC),
.bps = true,
},
};
static const struct weston_color_primaries_info color_primaries_info_table[] = {
{
.primaries = WESTON_PRIMARIES_CICP_SRGB,
.desc = "Color primaries for the sRGB color space as defined by " \
"the BT.709 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_SRGB,
.color_gamut = {
.primary = { { 0.64, 0.33 }, /* RGB order */
{ 0.30, 0.60 },
{ 0.15, 0.06 },
},
.white_point = { 0.3127, 0.3290 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_PAL_M,
.desc = "Color primaries for PAL-M as defined by the BT.470 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_PAL_M,
.color_gamut = {
.primary = { { 0.67, 0.33 }, /* RGB order */
{ 0.21, 0.71 },
{ 0.14, 0.08 },
},
.white_point = { 0.3101, 0.3162 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_PAL,
.desc = "Color primaries for PAL as defined by the BT.601 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_PAL,
.color_gamut = {
.primary = { { 0.64, 0.33 }, /* RGB order */
{ 0.29, 0.60 },
{ 0.15, 0.06 },
},
.white_point = { 0.3127, 0.3290 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_NTSC,
.desc = "Color primaries for NTSC as defined by the BT.601 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_NTSC,
.color_gamut = {
.primary = { { 0.630, 0.340 }, /* RGB order */
{ 0.310, 0.595 },
{ 0.155, 0.070 },
},
.white_point = { 0.3127, 0.3290 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_GENERIC_FILM,
.desc = "Generic film with color filters using Illuminant C",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_GENERIC_FILM,
.color_gamut = {
.primary = { { 0.681, 0.319 }, /* RGB order */
{ 0.243, 0.692 },
{ 0.145, 0.049 },
},
.white_point = { 0.3101, 0.3162 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_BT2020,
.desc = "Color primaries as defined by the BT.2020 and BT.2100 " \
"standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_BT2020,
.color_gamut = {
.primary = { { 0.708, 0.292 }, /* RGB order */
{ 0.170, 0.797 },
{ 0.131, 0.046 },
},
.white_point = { 0.3127, 0.3290 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_CIE1931_XYZ,
.desc = "Color primaries of the full CIE 1931 XYZ color space",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_CIE1931_XYZ,
.color_gamut = {
.primary = { { 1.0, 0.0 }, /* RGB order */
{ 0.0, 1.0 },
{ 0.0, 0.0 },
},
.white_point = { 0.3333, 0.3333 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_DCI_P3,
.desc = "Color primaries of the DCI P3 color space as defined by " \
"the SMPTE RP 431 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_DCI_P3,
.color_gamut = {
.primary = { { 0.680, 0.320 }, /* RGB order */
{ 0.265, 0.690 },
{ 0.150, 0.060 },
},
.white_point = { 0.314, 0.351 },
},
},
{
.primaries = WESTON_PRIMARIES_CICP_DISPLAY_P3,
.desc = "Color primaries of Display P3 variant of the DCI-P3 color " \
"space as defined by the SMPTE EG 432 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_DISPLAY_P3,
.color_gamut = {
.primary = { { 0.680, 0.320 }, /* RGB order */
{ 0.265, 0.690 },
{ 0.150, 0.060 },
},
.white_point = { 0.3127, 0.3290 },
},
},
{
.primaries = WESTON_PRIMARIES_ADOBE_RGB,
.desc = "Color primaries of the Adobe RGB color space as defined " \
"by the ISO 12640 standard",
.protocol_primaries = XX_COLOR_MANAGER_V2_PRIMARIES_ADOBE_RGB,
.color_gamut = {
.primary = { { 0.64, 0.33 }, /* RGB order */
{ 0.21, 0.71 },
{ 0.15, 0.06 },
},
.white_point = { 0.3127, 0.3290 },
},
},
};
static const struct weston_color_tf_info color_tf_info_table[] = {
{
.tf = WESTON_TF_LINEAR,
.desc = "Linear transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LINEAR,
},
{
.tf = WESTON_TF_GAMMA22,
.desc = "Assumed display gamma 2.2 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA22,
},
{
.tf = WESTON_TF_GAMMA28,
.desc = "Assumed display gamma 2.8 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_GAMMA28,
},
{
.tf = WESTON_TF_SRGB,
.desc = "sRGB piece-wise transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_SRGB,
},
{
.tf = WESTON_TF_EXT_SRGB,
.desc = "Extended sRGB piece-wise transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_EXT_SRGB,
},
{
.tf = WESTON_TF_BT709,
.desc = "BT.709 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_BT709,
},
{
.tf = WESTON_TF_BT1361,
.desc = "BT.1361 extended transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_BT1361,
},
{
.tf = WESTON_TF_ST240,
.desc = "SMPTE ST 240 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST240,
},
{
.tf = WESTON_TF_ST428,
.desc = "SMPTE ST 428 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST428,
},
{
.tf = WESTON_TF_ST2084_PQ,
.desc = "Perceptual quantizer transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_ST2084_PQ,
},
{
.tf = WESTON_TF_LOG_100,
.desc = "Logarithmic 100:1 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LOG_100,
},
{
.tf = WESTON_TF_LOG_316,
.desc = "Logarithmic (100*Sqrt(10) : 1) transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_LOG_316,
},
{
.tf = WESTON_TF_XVYCC,
.desc = "IEC 61966-2-4 transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_XVYCC,
},
{
.tf = WESTON_TF_HLG,
.desc = "Hybrid log-gamma transfer function",
.protocol_tf = XX_COLOR_MANAGER_V2_TRANSFER_FUNCTION_HLG,
},
};
WL_EXPORT const struct weston_color_feature_info *
weston_color_feature_info_from(struct weston_compositor *compositor,
enum weston_color_feature feature)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(color_feature_info_table); i++)
if (color_feature_info_table[i].feature == feature)
return &color_feature_info_table[i];
weston_assert_not_reached(compositor, "unknown color feature");
}
WL_EXPORT const struct weston_render_intent_info *
weston_render_intent_info_from(struct weston_compositor *compositor,
enum weston_render_intent intent)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(render_intent_info_table); i++)
if (render_intent_info_table[i].intent == intent)
return &render_intent_info_table[i];
weston_assert_not_reached(compositor, "unknown render intent");
}
WL_EXPORT const struct weston_render_intent_info *
weston_render_intent_info_from_protocol(struct weston_compositor *compositor,
uint32_t protocol_intent)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(render_intent_info_table); i++)
if (render_intent_info_table[i].protocol_intent == protocol_intent)
return &render_intent_info_table[i];
return NULL;
}
WL_EXPORT const struct weston_color_primaries_info *
weston_color_primaries_info_from(struct weston_compositor *compositor,
enum weston_color_primaries primaries)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(color_primaries_info_table); i++)
if (color_primaries_info_table[i].primaries == primaries)
return &color_primaries_info_table[i];
weston_assert_not_reached(compositor, "unknown primaries");
}
WL_EXPORT const struct weston_color_tf_info *
weston_color_tf_info_from(struct weston_compositor *compositor,
enum weston_transfer_function tf)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(color_tf_info_table); i++)
if (color_tf_info_table[i].tf == tf)
return &color_tf_info_table[i];
weston_assert_not_reached(compositor, "unknown tf");
}