clutter/color-state: Encapsulate primaries, tf and luminance

These properties now are tagged unions:
- ClutterColorimetry:
    Can be from colorspace or primaries;
- ClutterEOTF:
    Can be from known tf or custom gamma exp (next commit);
- ClutterLuminance:
    Can be defined explicitly or derived;

Make the color management protocol use them too.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4020>
This commit is contained in:
Joan Torres 2024-09-20 12:02:28 +02:00 committed by Marge Bot
parent 8d9c70acda
commit eff17bf1b5
5 changed files with 369 additions and 304 deletions

View File

@ -67,12 +67,10 @@ typedef struct _ClutterColorStatePrivate
ClutterContext *context; ClutterContext *context;
unsigned int id; unsigned int id;
ClutterColorspace colorspace;
ClutterPrimaries *primaries; ClutterColorimetry colorimetry;
ClutterTransferFunction transfer_function; ClutterEOTF eotf;
float min_lum; ClutterLuminance luminance;
float max_lum;
float ref_lum;
} ClutterColorStatePrivate; } ClutterColorStatePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterColorState, G_DEFINE_TYPE_WITH_PRIVATE (ClutterColorState,
@ -109,8 +107,8 @@ clutter_color_transform_key_init (ClutterColorTransformKey *key,
ClutterColorStatePrivate *target_priv = ClutterColorStatePrivate *target_priv =
clutter_color_state_get_instance_private (target_color_state); clutter_color_state_get_instance_private (target_color_state);
key->source.transfer_function = priv->transfer_function; key->source.transfer_function = priv->eotf.tf_name;
key->target.transfer_function = target_priv->transfer_function; key->target.transfer_function = target_priv->eotf.tf_name;
} }
static const char * static const char *
@ -130,9 +128,9 @@ clutter_colorspace_to_string (ClutterColorspace colorspace)
} }
static const char * static const char *
clutter_transfer_function_to_string (ClutterTransferFunction transfer_function) clutter_eotf_to_string (ClutterEOTF eotf)
{ {
switch (transfer_function) switch (eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_DEFAULT: case CLUTTER_TRANSFER_FUNCTION_DEFAULT:
return "default"; return "default";
@ -159,95 +157,76 @@ clutter_color_state_get_id (ClutterColorState *color_state)
return priv->id; return priv->id;
} }
ClutterColorspace const ClutterColorimetry *
clutter_color_state_get_colorspace (ClutterColorState *color_state) clutter_color_state_get_colorimetry (ClutterColorState *color_state)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), NULL);
CLUTTER_COLORSPACE_DEFAULT);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
return priv->colorspace; return &priv->colorimetry;
} }
ClutterTransferFunction const ClutterEOTF *
clutter_color_state_get_transfer_function (ClutterColorState *color_state) clutter_color_state_get_eotf (ClutterColorState *color_state)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), NULL);
CLUTTER_TRANSFER_FUNCTION_DEFAULT);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
return priv->transfer_function; return &priv->eotf;
} }
void static const ClutterLuminance sdr_default_luminance = {
clutter_transfer_function_get_default_luminances (ClutterTransferFunction transfer_function, .type = CLUTTER_LUMINANCE_TYPE_DERIVED,
float *min_lum_out, .min = 0.2f,
float *max_lum_out, .max = 80.0f,
float *ref_lum_out) .ref = 80.0f,
{ };
float min_lum = -1.0f, max_lum = -1.0f, ref_lum = -1.0f;
switch (transfer_function) static const ClutterLuminance pq_default_luminance = {
.type = CLUTTER_LUMINANCE_TYPE_DERIVED,
.min = 0.005f,
.max = 10000.0f,
.ref = 203.0f,
};
const ClutterLuminance *
clutter_eotf_get_default_luminance (ClutterEOTF eotf)
{
switch (eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_DEFAULT: case CLUTTER_TRANSFER_FUNCTION_DEFAULT:
case CLUTTER_TRANSFER_FUNCTION_SRGB: case CLUTTER_TRANSFER_FUNCTION_SRGB:
case CLUTTER_TRANSFER_FUNCTION_LINEAR: case CLUTTER_TRANSFER_FUNCTION_LINEAR:
min_lum = 0.2f; return &sdr_default_luminance;
max_lum = 80.0f;
ref_lum = 80.0f;
break;
case CLUTTER_TRANSFER_FUNCTION_PQ: case CLUTTER_TRANSFER_FUNCTION_PQ:
min_lum = 0.005f; return &pq_default_luminance;
max_lum = 10000.0f;
ref_lum = 203.0f;
break;
} }
if (min_lum_out) g_assert_not_reached ();
*min_lum_out = min_lum;
if (max_lum_out)
*max_lum_out = max_lum;
if (ref_lum_out)
*ref_lum_out = ref_lum;
} }
void const ClutterLuminance *
clutter_color_state_get_luminances (ClutterColorState *color_state, clutter_color_state_get_luminance (ClutterColorState *color_state)
float *min_lum_out,
float *max_lum_out,
float *ref_lum_out)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
float min_lum, max_lum, ref_lum;
g_return_if_fail (CLUTTER_IS_COLOR_STATE (color_state)); g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), NULL);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
clutter_transfer_function_get_default_luminances (priv->transfer_function, switch (priv->luminance.type)
&min_lum, {
&max_lum, case CLUTTER_LUMINANCE_TYPE_DERIVED:
&ref_lum); return clutter_eotf_get_default_luminance (priv->eotf);
case CLUTTER_LUMINANCE_TYPE_EXPLICIT:
if (priv->min_lum >= 0.0f) return &priv->luminance;
min_lum = priv->min_lum; }
if (priv->max_lum >= 0.0f)
max_lum = priv->max_lum;
if (priv->ref_lum >= 0.0f)
ref_lum = priv->ref_lum;
if (min_lum_out)
*min_lum_out = min_lum;
if (max_lum_out)
*max_lum_out = max_lum;
if (ref_lum_out)
*ref_lum_out = ref_lum;
} }
void void
@ -273,7 +252,8 @@ clutter_color_state_finalize (GObject *object)
ClutterColorStatePrivate *priv = ClutterColorStatePrivate *priv =
clutter_color_state_get_instance_private (color_state); clutter_color_state_get_instance_private (color_state);
g_clear_pointer (&priv->primaries, g_free); if (priv->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_PRIMARIES)
g_clear_pointer (&priv->colorimetry.primaries, g_free);
G_OBJECT_CLASS (clutter_color_state_parent_class)->finalize (object); G_OBJECT_CLASS (clutter_color_state_parent_class)->finalize (object);
} }
@ -336,12 +316,31 @@ clutter_color_state_new_full (ClutterContext *context,
priv->context = context; priv->context = context;
priv->id = clutter_color_manager_get_next_id (color_manager); priv->id = clutter_color_manager_get_next_id (color_manager);
priv->colorspace = colorspace; if (primaries)
priv->transfer_function = transfer_function; {
priv->primaries = g_memdup2 (primaries, sizeof (*primaries)); priv->colorimetry.type = CLUTTER_COLORIMETRY_TYPE_PRIMARIES;
priv->min_lum = min_lum; priv->colorimetry.primaries = g_memdup2 (primaries, sizeof (*primaries));
priv->max_lum = max_lum; }
priv->ref_lum = ref_lum; else
{
priv->colorimetry.type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
priv->colorimetry.colorspace = colorspace;
}
priv->eotf.type = CLUTTER_EOTF_TYPE_NAMED;
priv->eotf.tf_name = transfer_function;
if (min_lum >= 0.0f && max_lum > 0.0f && ref_lum >= 0.0f)
{
priv->luminance.type = CLUTTER_LUMINANCE_TYPE_EXPLICIT;
priv->luminance.min = min_lum;
priv->luminance.max = max_lum;
priv->luminance.ref = ref_lum;
}
else
{
priv->luminance.type = CLUTTER_LUMINANCE_TYPE_DERIVED;
}
return color_state; return color_state;
} }
@ -462,15 +461,11 @@ append_shader_description (GString *snippet_source,
clutter_color_state_get_instance_private (color_state); clutter_color_state_get_instance_private (color_state);
ClutterColorStatePrivate *target_priv = ClutterColorStatePrivate *target_priv =
clutter_color_state_get_instance_private (target_color_state); clutter_color_state_get_instance_private (target_color_state);
const char *transfer_function =
clutter_transfer_function_to_string (priv->transfer_function);
const char *target_transfer_function =
clutter_transfer_function_to_string (target_priv->transfer_function);
g_string_append_printf (snippet_source, g_string_append_printf (snippet_source,
" // %s to %s\n", " // %s to %s\n",
transfer_function, clutter_eotf_to_string (priv->eotf),
target_transfer_function); clutter_eotf_to_string (target_priv->eotf));
} }
static const TransferFunction * static const TransferFunction *
@ -479,7 +474,7 @@ get_eotf (ClutterColorState *color_state)
ClutterColorStatePrivate *priv = ClutterColorStatePrivate *priv =
clutter_color_state_get_instance_private (color_state); clutter_color_state_get_instance_private (color_state);
switch (priv->transfer_function) switch (priv->eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_PQ: case CLUTTER_TRANSFER_FUNCTION_PQ:
return &pq_eotf; return &pq_eotf;
@ -491,7 +486,7 @@ get_eotf (ClutterColorState *color_state)
} }
g_warning ("Unhandled tranfer function %s", g_warning ("Unhandled tranfer function %s",
clutter_transfer_function_to_string (priv->transfer_function)); clutter_eotf_to_string (priv->eotf));
return NULL; return NULL;
} }
@ -501,7 +496,7 @@ get_inv_eotf (ClutterColorState *color_state)
ClutterColorStatePrivate *priv = ClutterColorStatePrivate *priv =
clutter_color_state_get_instance_private (color_state); clutter_color_state_get_instance_private (color_state);
switch (priv->transfer_function) switch (priv->eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_PQ: case CLUTTER_TRANSFER_FUNCTION_PQ:
return &pq_inv_eotf; return &pq_inv_eotf;
@ -513,7 +508,7 @@ get_inv_eotf (ClutterColorState *color_state)
} }
g_warning ("Unhandled tranfer function %s", g_warning ("Unhandled tranfer function %s",
clutter_transfer_function_to_string (priv->transfer_function)); clutter_eotf_to_string (priv->eotf));
return NULL; return NULL;
} }
@ -546,31 +541,30 @@ static const ClutterPrimaries bt2020_primaries = {
.w_x = 0.3127f, .w_y = 0.3290f, .w_x = 0.3127f, .w_y = 0.3290f,
}; };
const ClutterPrimaries * static const ClutterPrimaries *
clutter_color_state_get_primaries (ClutterColorState *color_state) get_primaries (ClutterColorState *color_state)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state),
NULL);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
if (priv->primaries) switch (priv->colorimetry.type)
return priv->primaries;
switch (priv->colorspace)
{ {
case CLUTTER_COLORSPACE_DEFAULT: case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
case CLUTTER_COLORSPACE_SRGB: return priv->colorimetry.primaries;
return &srgb_primaries; case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
case CLUTTER_COLORSPACE_BT2020: switch (priv->colorimetry.colorspace)
return &bt2020_primaries; {
case CLUTTER_COLORSPACE_DEFAULT:
case CLUTTER_COLORSPACE_SRGB:
return &srgb_primaries;
case CLUTTER_COLORSPACE_BT2020:
return &bt2020_primaries;
}
g_warning ("Unhandled colorspace %s",
clutter_colorspace_to_string (priv->colorimetry.colorspace));
} }
g_warning ("Unhandled colorspace %s",
clutter_colorspace_to_string (priv->colorspace));
return &srgb_primaries; return &srgb_primaries;
} }
@ -592,8 +586,8 @@ primaries_white_point_equal (ClutterColorState *color_state,
const ClutterPrimaries *primaries; const ClutterPrimaries *primaries;
const ClutterPrimaries *other_primaries; const ClutterPrimaries *other_primaries;
primaries = clutter_color_state_get_primaries (color_state); primaries = get_primaries (color_state);
other_primaries = clutter_color_state_get_primaries (other_color_state); other_primaries = get_primaries (other_color_state);
return chromaticity_equal (primaries->w_x, primaries->w_y, return chromaticity_equal (primaries->w_x, primaries->w_y,
other_primaries->w_x, other_primaries->w_y); other_primaries->w_x, other_primaries->w_y);
@ -660,8 +654,7 @@ get_color_space_trans_matrices (ClutterColorState *color_state,
graphene_matrix_t *rgb_to_xyz, graphene_matrix_t *rgb_to_xyz,
graphene_matrix_t *xyz_to_rgb) graphene_matrix_t *xyz_to_rgb)
{ {
const ClutterPrimaries *primaries = const ClutterPrimaries *primaries = get_primaries (color_state);
clutter_color_state_get_primaries (color_state);
graphene_matrix_t coefficients_mat; graphene_matrix_t coefficients_mat;
graphene_matrix_t inv_primaries_mat; graphene_matrix_t inv_primaries_mat;
graphene_matrix_t primaries_mat; graphene_matrix_t primaries_mat;
@ -731,10 +724,8 @@ get_chromatic_adaptation (ClutterColorState *color_state,
ClutterColorState *target_color_state, ClutterColorState *target_color_state,
graphene_matrix_t *chromatic_adaptation) graphene_matrix_t *chromatic_adaptation)
{ {
const ClutterPrimaries *source_primaries = const ClutterPrimaries *source_primaries = get_primaries (color_state);
clutter_color_state_get_primaries (color_state); const ClutterPrimaries *target_primaries = get_primaries (target_color_state);
const ClutterPrimaries *target_primaries =
clutter_color_state_get_primaries (target_color_state);
graphene_matrix_t coefficients_mat; graphene_matrix_t coefficients_mat;
graphene_matrix_t bradford_mat, inv_bradford_mat; graphene_matrix_t bradford_mat, inv_bradford_mat;
graphene_vec3_t src_white_point_XYZ, dst_white_point_XYZ; graphene_vec3_t src_white_point_XYZ, dst_white_point_XYZ;
@ -943,20 +934,15 @@ static float
get_luminance_mapping (ClutterColorState *color_state, get_luminance_mapping (ClutterColorState *color_state,
ClutterColorState *target_color_state) ClutterColorState *target_color_state)
{ {
float min_lum, max_lum, ref_lum; const ClutterLuminance *lum;
float target_min_lum, target_max_lum, target_ref_lum; const ClutterLuminance *target_lum;
clutter_color_state_get_luminances (color_state, lum = clutter_color_state_get_luminance (color_state);
&min_lum, &max_lum, &ref_lum); target_lum = clutter_color_state_get_luminance (target_color_state);
clutter_color_state_get_luminances (target_color_state,
&target_min_lum,
&target_max_lum,
&target_ref_lum);
/* this is a very basic, non-contrast preserving way of matching the reference /* this is a very basic, non-contrast preserving way of matching the reference
* luminance level */ * luminance level */
return (target_ref_lum / ref_lum) * (max_lum / target_max_lum); return (target_lum->ref / lum->ref) * (lum->max / target_lum->max);
} }
void void
@ -1028,25 +1014,20 @@ static gboolean
luminances_equal (ClutterColorState *color_state, luminances_equal (ClutterColorState *color_state,
ClutterColorState *other_color_state) ClutterColorState *other_color_state)
{ {
float min_lum, max_lum, ref_lum; const ClutterLuminance *lum;
float other_min_lum, other_max_lum, other_ref_lum; const ClutterLuminance *other_lum;
clutter_color_state_get_luminances (color_state, lum = clutter_color_state_get_luminance (color_state);
&min_lum, &max_lum, &ref_lum); other_lum = clutter_color_state_get_luminance (other_color_state);
clutter_color_state_get_luminances (other_color_state, return luminance_value_approx_equal (lum->min, other_lum->min, 0.1f) &&
&other_min_lum, luminance_value_approx_equal (lum->max, other_lum->max, 0.1f) &&
&other_max_lum, luminance_value_approx_equal (lum->ref, other_lum->ref, 0.1f);
&other_ref_lum);
return luminance_value_approx_equal (min_lum, other_min_lum, 0.1f) &&
luminance_value_approx_equal (max_lum, other_max_lum, 0.1f) &&
luminance_value_approx_equal (ref_lum, other_ref_lum, 0.1f);
} }
static gboolean static gboolean
primaries_equal (ClutterColorState *color_state, colorimetry_equal (ClutterColorState *color_state,
ClutterColorState *other_color_state) ClutterColorState *other_color_state)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
ClutterColorStatePrivate *other_priv; ClutterColorStatePrivate *other_priv;
@ -1056,12 +1037,12 @@ primaries_equal (ClutterColorState *color_state,
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
other_priv = clutter_color_state_get_instance_private (other_color_state); other_priv = clutter_color_state_get_instance_private (other_color_state);
if (priv->colorspace != CLUTTER_COLORSPACE_DEFAULT && if (priv->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_COLORSPACE &&
other_priv->colorspace != CLUTTER_COLORSPACE_DEFAULT) other_priv->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_COLORSPACE)
return priv->colorspace == other_priv->colorspace; return priv->colorimetry.colorspace == other_priv->colorimetry.colorspace;
primaries = clutter_color_state_get_primaries (color_state); primaries = get_primaries (color_state);
other_primaries = clutter_color_state_get_primaries (other_color_state); other_primaries = get_primaries (other_color_state);
return chromaticity_equal (primaries->r_x, primaries->r_y, return chromaticity_equal (primaries->r_x, primaries->r_y,
other_primaries->r_x, other_primaries->r_y) && other_primaries->r_x, other_primaries->r_y) &&
@ -1073,13 +1054,27 @@ primaries_equal (ClutterColorState *color_state,
other_primaries->w_x, other_primaries->w_y); other_primaries->w_x, other_primaries->w_y);
} }
gboolean static gboolean
clutter_color_state_equals (ClutterColorState *color_state, eotf_equal (ClutterColorState *color_state,
ClutterColorState *other_color_state) ClutterColorState *other_color_state)
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
ClutterColorStatePrivate *other_priv; ClutterColorStatePrivate *other_priv;
priv = clutter_color_state_get_instance_private (color_state);
other_priv = clutter_color_state_get_instance_private (other_color_state);
if (priv->eotf.type == CLUTTER_EOTF_TYPE_NAMED &&
other_priv->eotf.type == CLUTTER_EOTF_TYPE_NAMED)
return priv->eotf.tf_name == other_priv->eotf.tf_name;
return FALSE;
}
gboolean
clutter_color_state_equals (ClutterColorState *color_state,
ClutterColorState *other_color_state)
{
if (color_state == other_color_state) if (color_state == other_color_state)
return TRUE; return TRUE;
@ -1089,31 +1084,28 @@ clutter_color_state_equals (ClutterColorState *color_state,
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE); g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE);
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (other_color_state), FALSE); g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (other_color_state), FALSE);
priv = clutter_color_state_get_instance_private (color_state); return colorimetry_equal (color_state, other_color_state) &&
other_priv = clutter_color_state_get_instance_private (other_color_state); eotf_equal (color_state, other_color_state) &&
return priv->transfer_function == other_priv->transfer_function &&
primaries_equal (color_state, other_color_state) &&
luminances_equal (color_state, other_color_state); luminances_equal (color_state, other_color_state);
} }
static char * static char *
primaries_to_string (ClutterColorState *color_state) clutter_colorimetry_to_string (ClutterColorimetry colorimetry)
{ {
ClutterColorStatePrivate *priv;
const ClutterPrimaries *primaries; const ClutterPrimaries *primaries;
priv = clutter_color_state_get_instance_private (color_state); switch (colorimetry.type)
{
if (priv->colorspace != CLUTTER_COLORSPACE_DEFAULT) case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
return g_strdup (clutter_colorspace_to_string (priv->colorspace)); return g_strdup (clutter_colorspace_to_string (colorimetry.colorspace));
case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
primaries = clutter_color_state_get_primaries (color_state); primaries = colorimetry.primaries;
return g_strdup_printf ("[R: %f, %f G: %f, %f B: %f, %f W: %f, %f]", return g_strdup_printf ("[R: %f, %f G: %f, %f B: %f, %f W: %f, %f]",
primaries->r_x, primaries->r_y, primaries->r_x, primaries->r_y,
primaries->g_x, primaries->g_y, primaries->g_x, primaries->g_y,
primaries->b_x, primaries->b_y, primaries->b_x, primaries->b_y,
primaries->w_x, primaries->w_y); primaries->w_x, primaries->w_y);
}
} }
char * char *
@ -1122,18 +1114,17 @@ clutter_color_state_to_string (ClutterColorState *color_state)
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
g_autofree char *primaries_name = NULL; g_autofree char *primaries_name = NULL;
const char *transfer_function_name; const char *transfer_function_name;
float min_lum, max_lum, ref_lum; const ClutterLuminance *lum;
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE); g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
primaries_name = primaries_to_string (color_state); primaries_name = clutter_colorimetry_to_string (priv->colorimetry);
transfer_function_name = transfer_function_name = clutter_eotf_to_string (priv->eotf);
clutter_transfer_function_to_string (priv->transfer_function);
clutter_color_state_get_luminances (color_state, &min_lum, &max_lum, &ref_lum); lum = clutter_color_state_get_luminance (color_state);
return g_strdup_printf ("ClutterColorState %d " return g_strdup_printf ("ClutterColorState %d "
"(primaries: %s, transfer function: %s, " "(primaries: %s, transfer function: %s, "
@ -1141,9 +1132,9 @@ clutter_color_state_to_string (ClutterColorState *color_state)
priv->id, priv->id,
primaries_name, primaries_name,
transfer_function_name, transfer_function_name,
min_lum, lum->min,
max_lum, lum->max,
ref_lum); lum->ref);
} }
ClutterEncodingRequiredFormat ClutterEncodingRequiredFormat
@ -1155,7 +1146,7 @@ clutter_color_state_required_format (ClutterColorState *color_state)
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
switch (priv->transfer_function) switch (priv->eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_LINEAR: case CLUTTER_TRANSFER_FUNCTION_LINEAR:
return CLUTTER_ENCODING_REQUIRED_FORMAT_FP16; return CLUTTER_ENCODING_REQUIRED_FORMAT_FP16;
@ -1192,12 +1183,14 @@ clutter_color_state_get_blending (ClutterColorState *color_state,
{ {
ClutterColorStatePrivate *priv; ClutterColorStatePrivate *priv;
ClutterTransferFunction blending_tf; ClutterTransferFunction blending_tf;
ClutterColorspace colorspace;
ClutterPrimaries *primaries;
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE); g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE);
priv = clutter_color_state_get_instance_private (color_state); priv = clutter_color_state_get_instance_private (color_state);
switch (priv->transfer_function) switch (priv->eotf.tf_name)
{ {
case CLUTTER_TRANSFER_FUNCTION_PQ: case CLUTTER_TRANSFER_FUNCTION_PQ:
case CLUTTER_TRANSFER_FUNCTION_LINEAR: case CLUTTER_TRANSFER_FUNCTION_LINEAR:
@ -1206,7 +1199,7 @@ clutter_color_state_get_blending (ClutterColorState *color_state,
/* effectively this means we will blend sRGB content in sRGB, not linear */ /* effectively this means we will blend sRGB content in sRGB, not linear */
case CLUTTER_TRANSFER_FUNCTION_SRGB: case CLUTTER_TRANSFER_FUNCTION_SRGB:
case CLUTTER_TRANSFER_FUNCTION_DEFAULT: case CLUTTER_TRANSFER_FUNCTION_DEFAULT:
blending_tf = priv->transfer_function; blending_tf = priv->eotf.tf_name;
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -1215,14 +1208,26 @@ clutter_color_state_get_blending (ClutterColorState *color_state,
if (force) if (force)
blending_tf = CLUTTER_TRANSFER_FUNCTION_LINEAR; blending_tf = CLUTTER_TRANSFER_FUNCTION_LINEAR;
if (blending_tf == priv->transfer_function) if (priv->eotf.tf_name == blending_tf)
return g_object_ref (color_state); return g_object_ref (color_state);
switch (priv->colorimetry.type)
{
case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
colorspace = priv->colorimetry.colorspace;
primaries = NULL;
break;
case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
colorspace = CLUTTER_COLORSPACE_DEFAULT;
primaries = priv->colorimetry.primaries;
break;
}
return clutter_color_state_new_full (priv->context, return clutter_color_state_new_full (priv->context,
priv->colorspace, colorspace,
blending_tf, blending_tf,
priv->primaries, primaries,
priv->min_lum, priv->luminance.min,
priv->max_lum, priv->luminance.max,
priv->ref_lum); priv->luminance.ref);
} }

View File

@ -47,6 +47,23 @@ typedef enum
CLUTTER_TRANSFER_FUNCTION_LINEAR, CLUTTER_TRANSFER_FUNCTION_LINEAR,
} ClutterTransferFunction; } ClutterTransferFunction;
typedef enum
{
CLUTTER_COLORIMETRY_TYPE_COLORSPACE,
CLUTTER_COLORIMETRY_TYPE_PRIMARIES,
} ClutterColorimetryType;
typedef enum
{
CLUTTER_EOTF_TYPE_NAMED,
} ClutterEOTFType;
typedef enum
{
CLUTTER_LUMINANCE_TYPE_DERIVED,
CLUTTER_LUMINANCE_TYPE_EXPLICIT,
} ClutterLuminanceType;
typedef struct _ClutterPrimaries typedef struct _ClutterPrimaries
{ {
float r_x, r_y; float r_x, r_y;
@ -55,6 +72,30 @@ typedef struct _ClutterPrimaries
float w_x, w_y; float w_x, w_y;
} ClutterPrimaries; } ClutterPrimaries;
typedef struct _ClutterColorimetry
{
ClutterColorimetryType type : 1;
union
{
ClutterColorspace colorspace;
ClutterPrimaries *primaries;
};
} ClutterColorimetry;
typedef struct _ClutterEOTF
{
ClutterEOTFType type : 1;
ClutterTransferFunction tf_name;
} ClutterEOTF;
typedef struct _ClutterLuminance
{
ClutterLuminanceType type : 1;
float min;
float max;
float ref;
} ClutterLuminance;
#define CLUTTER_TYPE_COLOR_STATE (clutter_color_state_get_type ()) #define CLUTTER_TYPE_COLOR_STATE (clutter_color_state_get_type ())
CLUTTER_EXPORT CLUTTER_EXPORT
G_DECLARE_FINAL_TYPE (ClutterColorState, clutter_color_state, G_DECLARE_FINAL_TYPE (ClutterColorState, clutter_color_state,
@ -82,19 +123,13 @@ CLUTTER_EXPORT
unsigned int clutter_color_state_get_id (ClutterColorState *color_state); unsigned int clutter_color_state_get_id (ClutterColorState *color_state);
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterColorspace clutter_color_state_get_colorspace (ClutterColorState *color_state); const ClutterColorimetry * clutter_color_state_get_colorimetry (ClutterColorState *color_state);
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterTransferFunction clutter_color_state_get_transfer_function (ClutterColorState *color_state); const ClutterEOTF * clutter_color_state_get_eotf (ClutterColorState *color_state);
CLUTTER_EXPORT CLUTTER_EXPORT
const ClutterPrimaries * clutter_color_state_get_primaries (ClutterColorState *color_state); const ClutterLuminance * clutter_color_state_get_luminance (ClutterColorState *color_state);
CLUTTER_EXPORT
void clutter_color_state_get_luminances (ClutterColorState *color_state,
float *min_lum_out,
float *max_lum_out,
float *ref_lum_out);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_color_state_add_pipeline_transform (ClutterColorState *color_state, void clutter_color_state_add_pipeline_transform (ClutterColorState *color_state,
@ -119,10 +154,7 @@ ClutterColorState * clutter_color_state_get_blending (ClutterColorState *color_s
gboolean force); gboolean force);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_transfer_function_get_default_luminances (ClutterTransferFunction transfer_function, const ClutterLuminance * clutter_eotf_get_default_luminance (ClutterEOTF eotf);
float *min_lum_out,
float *max_lum_out,
float *ref_lum_out);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_primaries_ensure_normalized_range (ClutterPrimaries *primaries); void clutter_primaries_ensure_normalized_range (ClutterPrimaries *primaries);

View File

@ -639,30 +639,40 @@ get_color_space_from_monitor (MetaMonitor *monitor)
g_assert_not_reached (); g_assert_not_reached ();
} }
static ClutterTransferFunction static ClutterEOTF
get_transfer_function_from_monitor (MetaMonitor *monitor) get_eotf_from_monitor (MetaMonitor *monitor)
{ {
ClutterEOTF eotf;
const MetaOutputHdrMetadata *hdr_metadata = const MetaOutputHdrMetadata *hdr_metadata =
meta_monitor_get_hdr_metadata (monitor); meta_monitor_get_hdr_metadata (monitor);
eotf.type = CLUTTER_EOTF_TYPE_NAMED;
if (!hdr_metadata->active) if (!hdr_metadata->active)
return CLUTTER_TRANSFER_FUNCTION_DEFAULT; {
eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT;
return eotf;
}
switch (hdr_metadata->eotf) switch (hdr_metadata->eotf)
{ {
case META_OUTPUT_HDR_METADATA_EOTF_PQ: case META_OUTPUT_HDR_METADATA_EOTF_PQ:
return CLUTTER_TRANSFER_FUNCTION_PQ; eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_PQ;
break;
case META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_SDR: case META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_SDR:
return CLUTTER_TRANSFER_FUNCTION_DEFAULT; eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT;
break;
case META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_HDR: case META_OUTPUT_HDR_METADATA_EOTF_TRADITIONAL_GAMMA_HDR:
g_warning ("Unhandled HDR EOTF (traditional gamma hdr)"); g_warning ("Unhandled HDR EOTF (traditional gamma hdr)");
return CLUTTER_TRANSFER_FUNCTION_DEFAULT; eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT;
break;
case META_OUTPUT_HDR_METADATA_EOTF_HLG: case META_OUTPUT_HDR_METADATA_EOTF_HLG:
g_warning ("Unhandled HDR EOTF (HLG)"); g_warning ("Unhandled HDR EOTF (HLG)");
return CLUTTER_TRANSFER_FUNCTION_DEFAULT; eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT;
break;
} }
g_assert_not_reached (); return eotf;
} }
static UpdateResult static UpdateResult
@ -676,28 +686,28 @@ update_color_state (MetaColorDevice *color_device)
ClutterContext *clutter_context = meta_backend_get_clutter_context (backend); ClutterContext *clutter_context = meta_backend_get_clutter_context (backend);
g_autoptr (ClutterColorState) color_state = NULL; g_autoptr (ClutterColorState) color_state = NULL;
ClutterColorspace colorspace; ClutterColorspace colorspace;
ClutterTransferFunction transfer_function; ClutterEOTF eotf;
float min_lum, max_lum, ref_lum; const ClutterLuminance *luminance;
float reference_luminance_factor; float reference_luminance_factor;
float new_ref_luminance;
UpdateResult result = 0; UpdateResult result = 0;
colorspace = get_color_space_from_monitor (monitor); colorspace = get_color_space_from_monitor (monitor);
transfer_function = get_transfer_function_from_monitor (monitor); eotf = get_eotf_from_monitor (monitor);
clutter_transfer_function_get_default_luminances (transfer_function, luminance = clutter_eotf_get_default_luminance (eotf);
&min_lum,
&max_lum,
&ref_lum);
reference_luminance_factor = reference_luminance_factor =
meta_debug_control_get_luminance_percentage (debug_control) / 100.0f; meta_debug_control_get_luminance_percentage (debug_control) / 100.0f;
ref_lum = ref_lum * reference_luminance_factor; new_ref_luminance = luminance->ref * reference_luminance_factor;
color_state = clutter_color_state_new_full (clutter_context, color_state = clutter_color_state_new_full (clutter_context,
colorspace, colorspace,
transfer_function, eotf.tf_name,
NULL, NULL,
min_lum, max_lum, ref_lum); luminance->min,
luminance->max,
new_ref_luminance);
if (!color_device->color_state || if (!color_device->color_state ||
!clutter_color_state_equals (color_device->color_state, color_state)) !clutter_color_state_equals (color_device->color_state, color_state))

View File

@ -29,14 +29,15 @@ actor_color_state_default (void)
{ {
ClutterActor *actor; ClutterActor *actor;
ClutterColorState *color_state; ClutterColorState *color_state;
ClutterColorspace colorspace; const ClutterColorimetry *colorimetry;
actor = clutter_actor_new (); actor = clutter_actor_new ();
color_state = clutter_actor_get_color_state (actor); color_state = clutter_actor_get_color_state (actor);
colorspace = clutter_color_state_get_colorspace (color_state); colorimetry = clutter_color_state_get_colorimetry (color_state);
g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_DEFAULT); g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE);
g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_DEFAULT);
clutter_actor_destroy (actor); clutter_actor_destroy (actor);
} }
@ -49,8 +50,8 @@ actor_color_state_passed (void)
ClutterContext *context = clutter_test_get_context (); ClutterContext *context = clutter_test_get_context ();
ClutterActor *actor; ClutterActor *actor;
ClutterColorState *color_state; ClutterColorState *color_state;
ClutterColorspace colorspace; const ClutterColorimetry *colorimetry;
ClutterTransferFunction transfer_function; const ClutterEOTF *eotf;
color_state = clutter_color_state_new (context, color_state = clutter_color_state_new (context,
CLUTTER_COLORSPACE_BT2020, CLUTTER_COLORSPACE_BT2020,
@ -70,11 +71,13 @@ actor_color_state_passed (void)
g_critical ("Failed to create actor with provided color state."); g_critical ("Failed to create actor with provided color state.");
color_state = clutter_actor_get_color_state (actor); color_state = clutter_actor_get_color_state (actor);
colorspace = clutter_color_state_get_colorspace (color_state); colorimetry = clutter_color_state_get_colorimetry (color_state);
transfer_function = clutter_color_state_get_transfer_function (color_state); eotf = clutter_color_state_get_eotf (color_state);
g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_BT2020); g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE);
g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_PQ); g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_BT2020);
g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED);
g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_PQ);
clutter_actor_destroy (actor); clutter_actor_destroy (actor);
} }
@ -86,8 +89,8 @@ actor_change_color_state (void)
ClutterContext *context = clutter_test_get_context (); ClutterContext *context = clutter_test_get_context ();
ClutterActor *actor; ClutterActor *actor;
ClutterColorState *color_state; ClutterColorState *color_state;
ClutterColorspace colorspace; const ClutterColorimetry *colorimetry;
ClutterTransferFunction transfer_function; const ClutterEOTF *eotf;
actor = clutter_actor_new (); actor = clutter_actor_new ();
@ -101,11 +104,13 @@ actor_change_color_state (void)
clutter_actor_set_color_state (actor, color_state); clutter_actor_set_color_state (actor, color_state);
color_state = clutter_actor_get_color_state (actor); color_state = clutter_actor_get_color_state (actor);
colorspace = clutter_color_state_get_colorspace (color_state); colorimetry = clutter_color_state_get_colorimetry (color_state);
transfer_function = clutter_color_state_get_transfer_function (color_state); eotf = clutter_color_state_get_eotf (color_state);
g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_BT2020); g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE);
g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_PQ); g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_BT2020);
g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED);
g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_PQ);
clutter_actor_destroy (actor); clutter_actor_destroy (actor);
} }
@ -115,19 +120,21 @@ actor_unset_color_state (void)
{ {
ClutterActor *actor; ClutterActor *actor;
ClutterColorState *color_state; ClutterColorState *color_state;
ClutterColorspace colorspace; const ClutterColorimetry *colorimetry;
ClutterTransferFunction transfer_function; const ClutterEOTF *eotf;
actor = clutter_actor_new (); actor = clutter_actor_new ();
clutter_actor_unset_color_state (actor); clutter_actor_unset_color_state (actor);
color_state = clutter_actor_get_color_state (actor); color_state = clutter_actor_get_color_state (actor);
colorspace = clutter_color_state_get_colorspace (color_state); colorimetry = clutter_color_state_get_colorimetry (color_state);
transfer_function = clutter_color_state_get_transfer_function (color_state); eotf = clutter_color_state_get_eotf (color_state);
g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_DEFAULT); g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE);
g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_DEFAULT); g_assert_cmpuint (colorimetry->colorspace, ==, CLUTTER_COLORSPACE_DEFAULT);
g_assert_cmpuint (eotf->type, ==, CLUTTER_EOTF_TYPE_NAMED);
g_assert_cmpuint (eotf->tf_name, ==, CLUTTER_TRANSFER_FUNCTION_DEFAULT);
clutter_actor_destroy (actor); clutter_actor_destroy (actor);
} }

View File

@ -118,10 +118,13 @@ typedef struct _MetaWaylandCreatorParams
MetaWaylandColorManager *color_manager; MetaWaylandColorManager *color_manager;
struct wl_resource *resource; struct wl_resource *resource;
ClutterColorspace colorspace; ClutterColorimetry colorimetry;
ClutterTransferFunction transfer_function; ClutterEOTF eotf;
ClutterPrimaries *primaries; ClutterLuminance lum;
float min_lum, max_lum, ref_lum;
gboolean is_colorimetry_set;
gboolean is_eotf_set;
gboolean is_luminance_set;
} MetaWaylandCreatorParams; } MetaWaylandCreatorParams;
static void meta_wayland_color_management_surface_free (MetaWaylandColorManagementSurface *cm_surface); static void meta_wayland_color_management_surface_free (MetaWaylandColorManagementSurface *cm_surface);
@ -177,15 +180,17 @@ float_to_scaled_uint32 (float value)
static gboolean static gboolean
wayland_tf_to_clutter (enum xx_color_manager_v4_transfer_function tf, wayland_tf_to_clutter (enum xx_color_manager_v4_transfer_function tf,
ClutterTransferFunction *tf_out) ClutterEOTF *eotf)
{ {
switch (tf) switch (tf)
{ {
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB:
*tf_out = CLUTTER_TRANSFER_FUNCTION_SRGB; eotf->type = CLUTTER_EOTF_TYPE_NAMED;
eotf->tf_name = CLUTTER_TRANSFER_FUNCTION_SRGB;
return TRUE; return TRUE;
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ:
*tf_out = CLUTTER_TRANSFER_FUNCTION_PQ; eotf->type = CLUTTER_EOTF_TYPE_NAMED;
eotf->tf_name = CLUTTER_TRANSFER_FUNCTION_PQ;
return TRUE; return TRUE;
default: default:
return FALSE; return FALSE;
@ -210,15 +215,17 @@ clutter_tf_to_wayland (ClutterTransferFunction tf)
static gboolean static gboolean
wayland_primaries_to_clutter (enum xx_color_manager_v4_primaries primaries, wayland_primaries_to_clutter (enum xx_color_manager_v4_primaries primaries,
ClutterColorspace *primaries_out) ClutterColorimetry *colorimetry)
{ {
switch (primaries) switch (primaries)
{ {
case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB:
*primaries_out = CLUTTER_COLORSPACE_SRGB; colorimetry->type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
colorimetry->colorspace = CLUTTER_COLORSPACE_SRGB;
return TRUE; return TRUE;
case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020:
*primaries_out = CLUTTER_COLORSPACE_BT2020; colorimetry->type = CLUTTER_COLORIMETRY_TYPE_COLORSPACE;
colorimetry->colorspace = CLUTTER_COLORSPACE_BT2020;
return TRUE; return TRUE;
default: default:
return FALSE; return FALSE;
@ -340,47 +347,43 @@ static void
send_information (struct wl_resource *info_resource, send_information (struct wl_resource *info_resource,
ClutterColorState *color_state) ClutterColorState *color_state)
{ {
ClutterColorspace clutter_colorspace; enum xx_color_manager_v4_primaries primaries;
const ClutterPrimaries *clutter_primaries;
ClutterTransferFunction clutter_tf;
enum xx_color_manager_v4_transfer_function tf; enum xx_color_manager_v4_transfer_function tf;
float min_lum, max_lum, ref_lum; const ClutterColorimetry *colorimetry;
const ClutterEOTF *eotf;
const ClutterLuminance *lum;
clutter_colorspace = clutter_color_state_get_colorspace (color_state); colorimetry = clutter_color_state_get_colorimetry (color_state);
if (clutter_colorspace != CLUTTER_COLORSPACE_DEFAULT) switch (colorimetry->type)
{ {
enum xx_color_manager_v4_primaries primaries; case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
primaries = clutter_primaries_to_wayland (colorimetry->colorspace);
primaries = clutter_primaries_to_wayland (clutter_colorspace);
xx_image_description_info_v4_send_primaries_named (info_resource, xx_image_description_info_v4_send_primaries_named (info_resource,
primaries); primaries);
} break;
case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
clutter_primaries = clutter_color_state_get_primaries (color_state);
if (clutter_primaries)
{
xx_image_description_info_v4_send_primaries ( xx_image_description_info_v4_send_primaries (
info_resource, info_resource,
float_to_scaled_uint32 (clutter_primaries->r_x), float_to_scaled_uint32 (colorimetry->primaries->r_x),
float_to_scaled_uint32 (clutter_primaries->r_y), float_to_scaled_uint32 (colorimetry->primaries->r_y),
float_to_scaled_uint32 (clutter_primaries->g_x), float_to_scaled_uint32 (colorimetry->primaries->g_x),
float_to_scaled_uint32 (clutter_primaries->g_y), float_to_scaled_uint32 (colorimetry->primaries->g_y),
float_to_scaled_uint32 (clutter_primaries->b_x), float_to_scaled_uint32 (colorimetry->primaries->b_x),
float_to_scaled_uint32 (clutter_primaries->b_y), float_to_scaled_uint32 (colorimetry->primaries->b_y),
float_to_scaled_uint32 (clutter_primaries->w_x), float_to_scaled_uint32 (colorimetry->primaries->w_x),
float_to_scaled_uint32 (clutter_primaries->w_y)); float_to_scaled_uint32 (colorimetry->primaries->w_y));
break;
} }
clutter_tf = clutter_color_state_get_transfer_function (color_state); eotf = clutter_color_state_get_eotf (color_state);
tf = clutter_tf_to_wayland (clutter_tf); tf = clutter_tf_to_wayland (eotf->tf_name);
xx_image_description_info_v4_send_tf_named (info_resource, tf); xx_image_description_info_v4_send_tf_named (info_resource, tf);
clutter_color_state_get_luminances (color_state, lum = clutter_color_state_get_luminance (color_state);
&min_lum, &max_lum, &ref_lum);
xx_image_description_info_v4_send_luminances (info_resource, xx_image_description_info_v4_send_luminances (info_resource,
float_to_scaled_uint32 (min_lum), float_to_scaled_uint32 (lum->min),
(uint32_t) max_lum, (uint32_t) lum->max,
(uint32_t) ref_lum); (uint32_t) lum->ref);
} }
static void static void
@ -825,20 +828,16 @@ meta_wayland_creator_params_new (MetaWaylandColorManager *color_manager,
creator_params->color_manager = color_manager; creator_params->color_manager = color_manager;
creator_params->resource = resource; creator_params->resource = resource;
creator_params->colorspace = CLUTTER_COLORSPACE_DEFAULT;
creator_params->transfer_function = CLUTTER_TRANSFER_FUNCTION_DEFAULT;
creator_params->min_lum = -1.0f;
creator_params->max_lum = -1.0f;
creator_params->ref_lum = -1.0f;
return creator_params; return creator_params;
} }
static void static void
meta_wayland_creator_params_free (MetaWaylandCreatorParams *creator_params) meta_wayland_creator_params_free (MetaWaylandCreatorParams *creator_params)
{ {
g_clear_pointer (&creator_params->primaries, g_free); if (creator_params->is_colorimetry_set &&
creator_params->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_PRIMARIES)
g_clear_pointer (&creator_params->colorimetry.primaries, g_free);
g_free (creator_params); g_free (creator_params);
} }
@ -862,10 +861,10 @@ creator_params_create (struct wl_client *client,
struct wl_resource *image_desc_resource; struct wl_resource *image_desc_resource;
g_autoptr (ClutterColorState) color_state = NULL; g_autoptr (ClutterColorState) color_state = NULL;
MetaWaylandImageDescription *image_desc; MetaWaylandImageDescription *image_desc;
ClutterColorspace colorspace;
ClutterPrimaries *primaries;
if ((creator_params->colorspace == CLUTTER_COLORSPACE_DEFAULT && if (!creator_params->is_colorimetry_set || !creator_params->is_eotf_set)
!creator_params->primaries) ||
creator_params->transfer_function == CLUTTER_TRANSFER_FUNCTION_DEFAULT)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET,
@ -879,14 +878,25 @@ creator_params_create (struct wl_client *client,
wl_resource_get_version (resource), wl_resource_get_version (resource),
id); id);
color_state = switch (creator_params->colorimetry.type)
clutter_color_state_new_full (clutter_context, {
creator_params->colorspace, case CLUTTER_COLORIMETRY_TYPE_COLORSPACE:
creator_params->transfer_function, colorspace = creator_params->colorimetry.colorspace;
creator_params->primaries, primaries = NULL;
creator_params->min_lum, break;
creator_params->max_lum, case CLUTTER_COLORIMETRY_TYPE_PRIMARIES:
creator_params->ref_lum); colorspace = CLUTTER_COLORSPACE_DEFAULT;
primaries = creator_params->colorimetry.primaries;
break;
}
color_state = clutter_color_state_new_full (clutter_context,
colorspace,
creator_params->eotf.tf_name,
primaries,
creator_params->lum.min,
creator_params->lum.max,
creator_params->lum.ref);
image_desc = image_desc =
meta_wayland_image_description_new_color_state (color_manager, meta_wayland_image_description_new_color_state (color_manager,
@ -909,9 +919,9 @@ creator_params_set_tf_named (struct wl_client *client,
{ {
MetaWaylandCreatorParams *creator_params = MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource); wl_resource_get_user_data (resource);
ClutterTransferFunction clutter_tf; ClutterEOTF eotf;
if (creator_params->transfer_function != CLUTTER_TRANSFER_FUNCTION_DEFAULT) if (creator_params->is_eotf_set)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
@ -919,7 +929,7 @@ creator_params_set_tf_named (struct wl_client *client,
return; return;
} }
if (!wayland_tf_to_clutter (tf, &clutter_tf)) if (!wayland_tf_to_clutter (tf, &eotf))
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF,
@ -927,7 +937,8 @@ creator_params_set_tf_named (struct wl_client *client,
return; return;
} }
creator_params->transfer_function = clutter_tf; creator_params->eotf = eotf;
creator_params->is_eotf_set = TRUE;
} }
static void static void
@ -947,10 +958,9 @@ creator_params_set_primaries_named (struct wl_client *client,
{ {
MetaWaylandCreatorParams *creator_params = MetaWaylandCreatorParams *creator_params =
wl_resource_get_user_data (resource); wl_resource_get_user_data (resource);
ClutterColorspace colorspace; ClutterColorimetry colorimetry;
if (creator_params->colorspace != CLUTTER_COLORSPACE_DEFAULT || if (creator_params->is_colorimetry_set)
creator_params->primaries)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
@ -958,7 +968,7 @@ creator_params_set_primaries_named (struct wl_client *client,
return; return;
} }
if (!wayland_primaries_to_clutter (primaries, &colorspace)) if (!wayland_primaries_to_clutter (primaries, &colorimetry))
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES,
@ -966,7 +976,8 @@ creator_params_set_primaries_named (struct wl_client *client,
return; return;
} }
creator_params->colorspace = colorspace; creator_params->colorimetry = colorimetry;
creator_params->is_colorimetry_set = TRUE;
} }
static void static void
@ -985,8 +996,7 @@ creator_params_set_primaries (struct wl_client *client,
wl_resource_get_user_data (resource); wl_resource_get_user_data (resource);
ClutterPrimaries *primaries; ClutterPrimaries *primaries;
if (creator_params->colorspace != CLUTTER_COLORSPACE_DEFAULT || if (creator_params->is_colorimetry_set)
creator_params->primaries)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
@ -1017,7 +1027,9 @@ creator_params_set_primaries (struct wl_client *client,
clutter_primaries_ensure_normalized_range (primaries); clutter_primaries_ensure_normalized_range (primaries);
} }
creator_params->primaries = primaries; creator_params->colorimetry.type = CLUTTER_COLORIMETRY_TYPE_PRIMARIES;
creator_params->colorimetry.primaries = primaries;
creator_params->is_colorimetry_set = TRUE;
} }
static void static void
@ -1031,9 +1043,7 @@ creator_params_set_luminance (struct wl_client *client,
wl_resource_get_user_data (resource); wl_resource_get_user_data (resource);
float min, max, ref; float min, max, ref;
if (creator_params->min_lum >= 0.0f || if (creator_params->is_luminance_set)
creator_params->max_lum >= 0.0f ||
creator_params->ref_lum >= 0.0f)
{ {
wl_resource_post_error (resource, wl_resource_post_error (resource,
XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET,
@ -1061,9 +1071,10 @@ creator_params_set_luminance (struct wl_client *client,
return; return;
} }
creator_params->min_lum = min; creator_params->lum.min = min;
creator_params->max_lum = max; creator_params->lum.max = max;
creator_params->ref_lum = ref; creator_params->lum.ref = ref;
creator_params->is_luminance_set = TRUE;
} }
static void static void