color: add curve type enumerated

Not all color curves comes from parameters. For instance, with the
CM&HDR protocol users can set color curves from tf_info.

So let's add a new curve type to accommodate that.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
Leandro Ribeiro 2025-03-25 16:57:00 -03:00 committed by Pekka Paalanen
parent 0fe575b4a9
commit 209882c7d4
5 changed files with 178 additions and 0 deletions

View file

@ -255,24 +255,62 @@ static const struct weston_color_primaries_info color_primaries_info_table[] = {
},
};
#define POWER_LAW_PARAMS(g) { g, 1.0, 0.0, 1.0, 0.0 }
#define SRGB_PIECE_WISE_PARAMS { 2.4, 1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045 }
#define INVERSE_SRGB_PIECE_WISE_PARAMS { 1.0f / 2.4f, 1.055, -0.055, 12.92, 0.0031308 }
#define POWER_LAW(g, clamp) { \
.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW, \
.clamped_input = (clamp), \
.params = { POWER_LAW_PARAMS(g), POWER_LAW_PARAMS(g), \
POWER_LAW_PARAMS(g), } \
}
#define SRGB_PIECE_WISE(clamp) { \
.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW, \
.clamped_input = (clamp), \
.params = { SRGB_PIECE_WISE_PARAMS, SRGB_PIECE_WISE_PARAMS, \
SRGB_PIECE_WISE_PARAMS, } \
}
#define INVERSE_SRGB_PIECE_WISE(clamp) { \
.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_POWLIN, \
.clamped_input = (clamp), \
.params = { INVERSE_SRGB_PIECE_WISE_PARAMS, INVERSE_SRGB_PIECE_WISE_PARAMS, \
INVERSE_SRGB_PIECE_WISE_PARAMS, } \
}
static const struct weston_color_tf_info color_tf_info_table[] = {
{
.tf = WESTON_TF_BT1886,
.desc = "BT.1886 transfer function",
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886,
.count_parameters = 0,
/**
* NOTE: This is the BT.1886 special case of L_B = 0 and
* L_W = 1.
*/
.curve_params_valid = true,
.curve = POWER_LAW(2.4, true),
.inverse_curve = POWER_LAW(1.0f / 2.4f, true),
},
{
.tf = WESTON_TF_GAMMA22,
.desc = "Assumed display gamma 2.2 transfer function",
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
.count_parameters = 0,
.curve_params_valid = true,
.curve = POWER_LAW(2.2, true),
.inverse_curve = POWER_LAW(1.0f / 2.2f, true),
},
{
.tf = WESTON_TF_GAMMA28,
.desc = "Assumed display gamma 2.8 transfer function",
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28,
.count_parameters = 0,
.curve_params_valid = true,
.curve = POWER_LAW(2.8, true),
.inverse_curve = POWER_LAW(1.0f / 2.8f, true),
},
{
.tf = WESTON_TF_EXT_LINEAR,
@ -285,12 +323,18 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
.desc = "sRGB piece-wise transfer function",
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
.count_parameters = 0,
.curve_params_valid = true,
.curve = SRGB_PIECE_WISE(true),
.inverse_curve = INVERSE_SRGB_PIECE_WISE(true),
},
{
.tf = WESTON_TF_EXT_SRGB,
.desc = "Extended sRGB piece-wise transfer function",
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB,
.count_parameters = 0,
.curve_params_valid = true,
.curve = SRGB_PIECE_WISE(false),
.inverse_curve = INVERSE_SRGB_PIECE_WISE(false),
},
{
.tf = WESTON_TF_ST240,

View file

@ -29,6 +29,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "color.h"
#include <libweston/libweston.h>
struct weston_compositor;
@ -113,6 +114,13 @@ struct weston_color_tf_info {
* certain known functions that clients can define passing arbitrary
* parameters. */
bool count_parameters;
/** Are curve and inverse_curve valid? */
bool curve_params_valid;
/** Parametric curves to which we can map the tf and its inverse. */
struct weston_color_curve_parametric curve;
struct weston_color_curve_parametric inverse_curve;
};
const struct weston_color_feature_info *

View file

@ -44,6 +44,7 @@
#include "shared/string-helpers.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "shared/weston-assert.h"
/**
* Increase reference count of the color profile object
@ -188,6 +189,54 @@ weston_color_profile_params_to_str(struct weston_color_profile_params *params,
return str;
}
/**
* Given an enumerated color curve, returns an equivalent parametric curve.
*
* \param compositor The compositor instance.
* \param curve The enumerated color curve.
* \param out Where this stores the parametric curve.
* \return True on success, false otherwise.
*/
WL_EXPORT bool
weston_color_curve_enum_get_parametric(struct weston_compositor *compositor,
const struct weston_color_curve_enum *curve,
struct weston_color_curve_parametric *out)
{
unsigned int i;
memset(out, 0, sizeof(*out));
/* This one is special, the only parametric TF we currently have. */
if (curve->tf->tf == WESTON_TF_POWER) {
out->type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
out->clamped_input = false;
for (i = 0; i < 3; i++) {
float exp = curve->params[i][0];
/* LINPOW with such params matches pure power-law */
out->params[i][0] = (curve->tf_direction == WESTON_FORWARD_TF) ?
exp : 1.0f / exp; /* g */
out->params[i][1] = 1.0; /* a */
out->params[i][2] = 0.0; /* b */
out->params[i][3] = 1.0; /* c */
out->params[i][4] = 0.0; /* d */
}
return true;
}
/* No other TF's have params. */
weston_assert_uint32_eq(compositor, curve->tf->count_parameters, 0);
if (!curve->tf->curve_params_valid)
return false;
if (curve->tf_direction == WESTON_FORWARD_TF)
*out = curve->tf->curve;
else
*out = curve->tf->inverse_curve;
return true;
}
/**
* Increase reference count of the color transform object
*
@ -266,6 +315,8 @@ curve_type_to_str(enum weston_color_curve_type curve_type)
return "identity";
case WESTON_COLOR_CURVE_TYPE_LUT_3x1D:
return "3x1D LUT";
case WESTON_COLOR_CURVE_TYPE_ENUM:
return "enumerated";
case WESTON_COLOR_CURVE_TYPE_PARAMETRIC:
return "parametric";
}
@ -313,6 +364,10 @@ weston_color_transform_string(const struct weston_color_transform *xform)
fprintf(fp, "%spre %s", sep, curve_type_to_str(pre_type));
if (pre_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D)
fprintf(fp, " [%u]", xform->pre_curve.u.lut_3x1d.optimal_len);
else if (pre_type == WESTON_COLOR_CURVE_TYPE_ENUM)
fprintf(fp, " [%s%s]",
(xform->pre_curve.u.enumerated.tf_direction == WESTON_INVERSE_TF) ? "inverse " : "",
xform->pre_curve.u.enumerated.tf->desc);
else if (pre_type == WESTON_COLOR_CURVE_TYPE_PARAMETRIC)
fprintf(fp, " [%s]",
param_curve_type_to_str(xform->pre_curve.u.parametric.type));
@ -330,6 +385,10 @@ weston_color_transform_string(const struct weston_color_transform *xform)
fprintf(fp, "%spost %s", sep, curve_type_to_str(post_type));
if (post_type == WESTON_COLOR_CURVE_TYPE_LUT_3x1D)
fprintf(fp, " [%u]", xform->post_curve.u.lut_3x1d.optimal_len);
else if (post_type == WESTON_COLOR_CURVE_TYPE_ENUM)
fprintf(fp, " [%s%s]",
(xform->post_curve.u.enumerated.tf_direction == WESTON_INVERSE_TF) ? "inverse " : "",
xform->post_curve.u.enumerated.tf->desc);
else if (post_type == WESTON_COLOR_CURVE_TYPE_PARAMETRIC)
fprintf(fp, " [%s]",
param_curve_type_to_str(xform->post_curve.u.parametric.type));

View file

@ -225,6 +225,9 @@ enum weston_color_curve_type {
/** Three-channel, one-dimensional look-up table */
WESTON_COLOR_CURVE_TYPE_LUT_3x1D,
/** Enumerated color curve */
WESTON_COLOR_CURVE_TYPE_ENUM,
/** Parametric color curve */
WESTON_COLOR_CURVE_TYPE_PARAMETRIC,
};
@ -255,6 +258,24 @@ struct weston_color_curve_lut_3x1d {
unsigned optimal_len;
};
/** Direct or inverse of a tf. */
enum weston_tf_direction {
WESTON_FORWARD_TF,
WESTON_INVERSE_TF,
};
/** Enumerated color curve */
struct weston_color_curve_enum {
const struct weston_color_tf_info *tf;
/* Determines if the direct or inverse of the tf should be used. */
enum weston_tf_direction tf_direction;
/* Some tf are parametric, and we keep the params here. They may be
* different for each color channel, and channels are in RGB order. */
float params[3][MAX_PARAMS_TF];
};
/** Parametric color curve parameters */
struct weston_color_curve_parametric {
enum weston_color_curve_parametric_type type;
@ -286,6 +307,7 @@ struct weston_color_curve {
union {
/* identity: no parameters */
struct weston_color_curve_lut_3x1d lut_3x1d;
struct weston_color_curve_enum enumerated;
struct weston_color_curve_parametric parametric;
} u;
};
@ -620,6 +642,11 @@ char *
weston_color_profile_params_to_str(struct weston_color_profile_params *params,
const char *ident);
bool
weston_color_curve_enum_get_parametric(struct weston_compositor *compositor,
const struct weston_color_curve_enum *curve,
struct weston_color_curve_parametric *out);
struct weston_color_transform *
weston_color_transform_ref(struct weston_color_transform *xform);

View file

@ -167,6 +167,38 @@ gl_color_curve_parametric(struct gl_renderer *gr,
weston_assert_not_reached(gr->compositor, "unknown parametric color curve");
}
static bool
gl_color_curve_enum(struct gl_renderer *gr,
struct gl_renderer_color_curve *gl_curve,
const struct weston_color_curve *curve)
{
struct weston_color_curve_parametric parametric;
bool ret;
/* Lower TF to a parametric curve. */
ret = weston_color_curve_enum_get_parametric(gr->compositor,
&curve->u.enumerated,
&parametric);
if (!ret)
return false;
/* Handle parametric curve that we got from TF. */
ARRAY_COPY(gl_curve->u.parametric.params, parametric.params);
gl_curve->u.parametric.clamped_input = parametric.clamped_input;
switch(parametric.type) {
case WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW:
gl_curve->type = SHADER_COLOR_CURVE_LINPOW;
return true;
case WESTON_COLOR_CURVE_PARAMETRIC_TYPE_POWLIN:
gl_curve->type = SHADER_COLOR_CURVE_POWLIN;
return true;
}
weston_assert_not_reached(gr->compositor, "unknown parametric color curve");
}
static bool
gl_color_curve_lut_3x1d(struct gl_renderer *gr,
struct gl_renderer_color_curve *gl_curve,
@ -285,6 +317,10 @@ gl_renderer_color_transform_from(struct gl_renderer *gr,
ok = gl_color_curve_parametric(gr, &gl_xform->pre_curve,
&xform->pre_curve);
break;
case WESTON_COLOR_CURVE_TYPE_ENUM:
ok = gl_color_curve_enum(gr, &gl_xform->pre_curve,
&xform->pre_curve);
break;
}
if (!ok) {
gl_renderer_color_transform_destroy(gl_xform);
@ -323,6 +359,10 @@ gl_renderer_color_transform_from(struct gl_renderer *gr,
ok = gl_color_curve_parametric(gr, &gl_xform->post_curve,
&xform->post_curve);
break;
case WESTON_COLOR_CURVE_TYPE_ENUM:
ok = gl_color_curve_enum(gr, &gl_xform->post_curve,
&xform->post_curve);
break;
}
if (!ok) {
gl_renderer_color_transform_destroy(gl_xform);