diff --git a/clutter/clutter/clutter-color-state.c b/clutter/clutter/clutter-color-state.c index a031406c2..c74bb8610 100644 --- a/clutter/clutter/clutter-color-state.c +++ b/clutter/clutter/clutter-color-state.c @@ -67,12 +67,10 @@ typedef struct _ClutterColorStatePrivate ClutterContext *context; unsigned int id; - ClutterColorspace colorspace; - ClutterPrimaries *primaries; - ClutterTransferFunction transfer_function; - float min_lum; - float max_lum; - float ref_lum; + + ClutterColorimetry colorimetry; + ClutterEOTF eotf; + ClutterLuminance luminance; } ClutterColorStatePrivate; G_DEFINE_TYPE_WITH_PRIVATE (ClutterColorState, @@ -109,8 +107,8 @@ clutter_color_transform_key_init (ClutterColorTransformKey *key, ClutterColorStatePrivate *target_priv = clutter_color_state_get_instance_private (target_color_state); - key->source.transfer_function = priv->transfer_function; - key->target.transfer_function = target_priv->transfer_function; + key->source.transfer_function = priv->eotf.tf_name; + key->target.transfer_function = target_priv->eotf.tf_name; } static const char * @@ -130,9 +128,9 @@ clutter_colorspace_to_string (ClutterColorspace colorspace) } 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: return "default"; @@ -159,95 +157,76 @@ clutter_color_state_get_id (ClutterColorState *color_state) return priv->id; } -ClutterColorspace -clutter_color_state_get_colorspace (ClutterColorState *color_state) +const ClutterColorimetry * +clutter_color_state_get_colorimetry (ClutterColorState *color_state) { ClutterColorStatePrivate *priv; - g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), - CLUTTER_COLORSPACE_DEFAULT); + g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), NULL); priv = clutter_color_state_get_instance_private (color_state); - return priv->colorspace; + return &priv->colorimetry; } -ClutterTransferFunction -clutter_color_state_get_transfer_function (ClutterColorState *color_state) +const ClutterEOTF * +clutter_color_state_get_eotf (ClutterColorState *color_state) { ClutterColorStatePrivate *priv; - g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), - CLUTTER_TRANSFER_FUNCTION_DEFAULT); + g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), NULL); priv = clutter_color_state_get_instance_private (color_state); - return priv->transfer_function; + return &priv->eotf; } -void -clutter_transfer_function_get_default_luminances (ClutterTransferFunction transfer_function, - float *min_lum_out, - float *max_lum_out, - float *ref_lum_out) -{ - float min_lum = -1.0f, max_lum = -1.0f, ref_lum = -1.0f; +static const ClutterLuminance sdr_default_luminance = { + .type = CLUTTER_LUMINANCE_TYPE_DERIVED, + .min = 0.2f, + .max = 80.0f, + .ref = 80.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_SRGB: case CLUTTER_TRANSFER_FUNCTION_LINEAR: - min_lum = 0.2f; - max_lum = 80.0f; - ref_lum = 80.0f; - break; + return &sdr_default_luminance; case CLUTTER_TRANSFER_FUNCTION_PQ: - min_lum = 0.005f; - max_lum = 10000.0f; - ref_lum = 203.0f; - break; + return &pq_default_luminance; } - 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; + g_assert_not_reached (); } -void -clutter_color_state_get_luminances (ClutterColorState *color_state, - float *min_lum_out, - float *max_lum_out, - float *ref_lum_out) +const ClutterLuminance * +clutter_color_state_get_luminance (ClutterColorState *color_state) { 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); - clutter_transfer_function_get_default_luminances (priv->transfer_function, - &min_lum, - &max_lum, - &ref_lum); - - if (priv->min_lum >= 0.0f) - 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; + switch (priv->luminance.type) + { + case CLUTTER_LUMINANCE_TYPE_DERIVED: + return clutter_eotf_get_default_luminance (priv->eotf); + case CLUTTER_LUMINANCE_TYPE_EXPLICIT: + return &priv->luminance; + } } void @@ -273,7 +252,8 @@ clutter_color_state_finalize (GObject *object) ClutterColorStatePrivate *priv = 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); } @@ -336,12 +316,31 @@ clutter_color_state_new_full (ClutterContext *context, priv->context = context; priv->id = clutter_color_manager_get_next_id (color_manager); - priv->colorspace = colorspace; - priv->transfer_function = transfer_function; - priv->primaries = g_memdup2 (primaries, sizeof (*primaries)); - priv->min_lum = min_lum; - priv->max_lum = max_lum; - priv->ref_lum = ref_lum; + if (primaries) + { + priv->colorimetry.type = CLUTTER_COLORIMETRY_TYPE_PRIMARIES; + priv->colorimetry.primaries = g_memdup2 (primaries, sizeof (*primaries)); + } + 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; } @@ -462,15 +461,11 @@ append_shader_description (GString *snippet_source, clutter_color_state_get_instance_private (color_state); ClutterColorStatePrivate *target_priv = 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, " // %s to %s\n", - transfer_function, - target_transfer_function); + clutter_eotf_to_string (priv->eotf), + clutter_eotf_to_string (target_priv->eotf)); } static const TransferFunction * @@ -479,7 +474,7 @@ get_eotf (ClutterColorState *color_state) ClutterColorStatePrivate *priv = clutter_color_state_get_instance_private (color_state); - switch (priv->transfer_function) + switch (priv->eotf.tf_name) { case CLUTTER_TRANSFER_FUNCTION_PQ: return &pq_eotf; @@ -491,7 +486,7 @@ get_eotf (ClutterColorState *color_state) } g_warning ("Unhandled tranfer function %s", - clutter_transfer_function_to_string (priv->transfer_function)); + clutter_eotf_to_string (priv->eotf)); return NULL; } @@ -501,7 +496,7 @@ get_inv_eotf (ClutterColorState *color_state) ClutterColorStatePrivate *priv = clutter_color_state_get_instance_private (color_state); - switch (priv->transfer_function) + switch (priv->eotf.tf_name) { case CLUTTER_TRANSFER_FUNCTION_PQ: return &pq_inv_eotf; @@ -513,7 +508,7 @@ get_inv_eotf (ClutterColorState *color_state) } g_warning ("Unhandled tranfer function %s", - clutter_transfer_function_to_string (priv->transfer_function)); + clutter_eotf_to_string (priv->eotf)); return NULL; } @@ -546,31 +541,30 @@ static const ClutterPrimaries bt2020_primaries = { .w_x = 0.3127f, .w_y = 0.3290f, }; -const ClutterPrimaries * -clutter_color_state_get_primaries (ClutterColorState *color_state) +static const ClutterPrimaries * +get_primaries (ClutterColorState *color_state) { ClutterColorStatePrivate *priv; - g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), - NULL); - priv = clutter_color_state_get_instance_private (color_state); - if (priv->primaries) - return priv->primaries; - - switch (priv->colorspace) + switch (priv->colorimetry.type) { - case CLUTTER_COLORSPACE_DEFAULT: - case CLUTTER_COLORSPACE_SRGB: - return &srgb_primaries; - case CLUTTER_COLORSPACE_BT2020: - return &bt2020_primaries; + case CLUTTER_COLORIMETRY_TYPE_PRIMARIES: + return priv->colorimetry.primaries; + case CLUTTER_COLORIMETRY_TYPE_COLORSPACE: + switch (priv->colorimetry.colorspace) + { + 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; } @@ -592,8 +586,8 @@ primaries_white_point_equal (ClutterColorState *color_state, const ClutterPrimaries *primaries; const ClutterPrimaries *other_primaries; - primaries = clutter_color_state_get_primaries (color_state); - other_primaries = clutter_color_state_get_primaries (other_color_state); + primaries = get_primaries (color_state); + other_primaries = get_primaries (other_color_state); return chromaticity_equal (primaries->w_x, 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 *xyz_to_rgb) { - const ClutterPrimaries *primaries = - clutter_color_state_get_primaries (color_state); + const ClutterPrimaries *primaries = get_primaries (color_state); graphene_matrix_t coefficients_mat; graphene_matrix_t inv_primaries_mat; graphene_matrix_t primaries_mat; @@ -731,10 +724,8 @@ get_chromatic_adaptation (ClutterColorState *color_state, ClutterColorState *target_color_state, graphene_matrix_t *chromatic_adaptation) { - const ClutterPrimaries *source_primaries = - clutter_color_state_get_primaries (color_state); - const ClutterPrimaries *target_primaries = - clutter_color_state_get_primaries (target_color_state); + const ClutterPrimaries *source_primaries = get_primaries (color_state); + const ClutterPrimaries *target_primaries = get_primaries (target_color_state); graphene_matrix_t coefficients_mat; graphene_matrix_t bradford_mat, inv_bradford_mat; graphene_vec3_t src_white_point_XYZ, dst_white_point_XYZ; @@ -943,20 +934,15 @@ static float get_luminance_mapping (ClutterColorState *color_state, ClutterColorState *target_color_state) { - float min_lum, max_lum, ref_lum; - float target_min_lum, target_max_lum, target_ref_lum; + const ClutterLuminance *lum; + const ClutterLuminance *target_lum; - clutter_color_state_get_luminances (color_state, - &min_lum, &max_lum, &ref_lum); - - clutter_color_state_get_luminances (target_color_state, - &target_min_lum, - &target_max_lum, - &target_ref_lum); + lum = clutter_color_state_get_luminance (color_state); + target_lum = clutter_color_state_get_luminance (target_color_state); /* this is a very basic, non-contrast preserving way of matching the reference * 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 @@ -1028,25 +1014,20 @@ static gboolean luminances_equal (ClutterColorState *color_state, ClutterColorState *other_color_state) { - float min_lum, max_lum, ref_lum; - float other_min_lum, other_max_lum, other_ref_lum; + const ClutterLuminance *lum; + const ClutterLuminance *other_lum; - clutter_color_state_get_luminances (color_state, - &min_lum, &max_lum, &ref_lum); + lum = clutter_color_state_get_luminance (color_state); + other_lum = clutter_color_state_get_luminance (other_color_state); - clutter_color_state_get_luminances (other_color_state, - &other_min_lum, - &other_max_lum, - &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); + return luminance_value_approx_equal (lum->min, other_lum->min, 0.1f) && + luminance_value_approx_equal (lum->max, other_lum->max, 0.1f) && + luminance_value_approx_equal (lum->ref, other_lum->ref, 0.1f); } static gboolean -primaries_equal (ClutterColorState *color_state, - ClutterColorState *other_color_state) +colorimetry_equal (ClutterColorState *color_state, + ClutterColorState *other_color_state) { ClutterColorStatePrivate *priv; ClutterColorStatePrivate *other_priv; @@ -1056,12 +1037,12 @@ primaries_equal (ClutterColorState *color_state, priv = clutter_color_state_get_instance_private (color_state); other_priv = clutter_color_state_get_instance_private (other_color_state); - if (priv->colorspace != CLUTTER_COLORSPACE_DEFAULT && - other_priv->colorspace != CLUTTER_COLORSPACE_DEFAULT) - return priv->colorspace == other_priv->colorspace; + if (priv->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_COLORSPACE && + other_priv->colorimetry.type == CLUTTER_COLORIMETRY_TYPE_COLORSPACE) + return priv->colorimetry.colorspace == other_priv->colorimetry.colorspace; - primaries = clutter_color_state_get_primaries (color_state); - other_primaries = clutter_color_state_get_primaries (other_color_state); + primaries = get_primaries (color_state); + other_primaries = get_primaries (other_color_state); return chromaticity_equal (primaries->r_x, 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); } -gboolean -clutter_color_state_equals (ClutterColorState *color_state, - ClutterColorState *other_color_state) +static gboolean +eotf_equal (ClutterColorState *color_state, + ClutterColorState *other_color_state) { ClutterColorStatePrivate *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) 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 (other_color_state), FALSE); - priv = clutter_color_state_get_instance_private (color_state); - other_priv = clutter_color_state_get_instance_private (other_color_state); - - return priv->transfer_function == other_priv->transfer_function && - primaries_equal (color_state, other_color_state) && + return colorimetry_equal (color_state, other_color_state) && + eotf_equal (color_state, other_color_state) && luminances_equal (color_state, other_color_state); } static char * -primaries_to_string (ClutterColorState *color_state) +clutter_colorimetry_to_string (ClutterColorimetry colorimetry) { - ClutterColorStatePrivate *priv; const ClutterPrimaries *primaries; - priv = clutter_color_state_get_instance_private (color_state); - - if (priv->colorspace != CLUTTER_COLORSPACE_DEFAULT) - return g_strdup (clutter_colorspace_to_string (priv->colorspace)); - - primaries = clutter_color_state_get_primaries (color_state); - return g_strdup_printf ("[R: %f, %f G: %f, %f B: %f, %f W: %f, %f]", - primaries->r_x, primaries->r_y, - primaries->g_x, primaries->g_y, - primaries->b_x, primaries->b_y, - primaries->w_x, primaries->w_y); + switch (colorimetry.type) + { + case CLUTTER_COLORIMETRY_TYPE_COLORSPACE: + return g_strdup (clutter_colorspace_to_string (colorimetry.colorspace)); + case CLUTTER_COLORIMETRY_TYPE_PRIMARIES: + primaries = colorimetry.primaries; + return g_strdup_printf ("[R: %f, %f G: %f, %f B: %f, %f W: %f, %f]", + primaries->r_x, primaries->r_y, + primaries->g_x, primaries->g_y, + primaries->b_x, primaries->b_y, + primaries->w_x, primaries->w_y); + } } char * @@ -1122,18 +1114,17 @@ clutter_color_state_to_string (ClutterColorState *color_state) ClutterColorStatePrivate *priv; g_autofree char *primaries_name = NULL; 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); 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 = - clutter_transfer_function_to_string (priv->transfer_function); + transfer_function_name = clutter_eotf_to_string (priv->eotf); - 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 " "(primaries: %s, transfer function: %s, " @@ -1141,9 +1132,9 @@ clutter_color_state_to_string (ClutterColorState *color_state) priv->id, primaries_name, transfer_function_name, - min_lum, - max_lum, - ref_lum); + lum->min, + lum->max, + lum->ref); } ClutterEncodingRequiredFormat @@ -1155,7 +1146,7 @@ clutter_color_state_required_format (ClutterColorState *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: return CLUTTER_ENCODING_REQUIRED_FORMAT_FP16; @@ -1192,12 +1183,14 @@ clutter_color_state_get_blending (ClutterColorState *color_state, { ClutterColorStatePrivate *priv; ClutterTransferFunction blending_tf; + ClutterColorspace colorspace; + ClutterPrimaries *primaries; g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (color_state), FALSE); 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_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 */ case CLUTTER_TRANSFER_FUNCTION_SRGB: case CLUTTER_TRANSFER_FUNCTION_DEFAULT: - blending_tf = priv->transfer_function; + blending_tf = priv->eotf.tf_name; break; default: g_assert_not_reached (); @@ -1215,14 +1208,26 @@ clutter_color_state_get_blending (ClutterColorState *color_state, if (force) 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); + 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, - priv->colorspace, + colorspace, blending_tf, - priv->primaries, - priv->min_lum, - priv->max_lum, - priv->ref_lum); + primaries, + priv->luminance.min, + priv->luminance.max, + priv->luminance.ref); } diff --git a/clutter/clutter/clutter-color-state.h b/clutter/clutter/clutter-color-state.h index a8530628f..10581b3ea 100644 --- a/clutter/clutter/clutter-color-state.h +++ b/clutter/clutter/clutter-color-state.h @@ -47,6 +47,23 @@ typedef enum CLUTTER_TRANSFER_FUNCTION_LINEAR, } 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 { float r_x, r_y; @@ -55,6 +72,30 @@ typedef struct _ClutterPrimaries float w_x, w_y; } 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 ()) CLUTTER_EXPORT G_DECLARE_FINAL_TYPE (ClutterColorState, clutter_color_state, @@ -82,19 +123,13 @@ CLUTTER_EXPORT unsigned int clutter_color_state_get_id (ClutterColorState *color_state); CLUTTER_EXPORT -ClutterColorspace clutter_color_state_get_colorspace (ClutterColorState *color_state); +const ClutterColorimetry * clutter_color_state_get_colorimetry (ClutterColorState *color_state); CLUTTER_EXPORT -ClutterTransferFunction clutter_color_state_get_transfer_function (ClutterColorState *color_state); +const ClutterEOTF * clutter_color_state_get_eotf (ClutterColorState *color_state); CLUTTER_EXPORT -const ClutterPrimaries * clutter_color_state_get_primaries (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); +const ClutterLuminance * clutter_color_state_get_luminance (ClutterColorState *color_state); CLUTTER_EXPORT 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); CLUTTER_EXPORT -void clutter_transfer_function_get_default_luminances (ClutterTransferFunction transfer_function, - float *min_lum_out, - float *max_lum_out, - float *ref_lum_out); +const ClutterLuminance * clutter_eotf_get_default_luminance (ClutterEOTF eotf); CLUTTER_EXPORT void clutter_primaries_ensure_normalized_range (ClutterPrimaries *primaries); diff --git a/src/backends/meta-color-device.c b/src/backends/meta-color-device.c index 3860bd8d5..1c853a152 100644 --- a/src/backends/meta-color-device.c +++ b/src/backends/meta-color-device.c @@ -639,30 +639,40 @@ get_color_space_from_monitor (MetaMonitor *monitor) g_assert_not_reached (); } -static ClutterTransferFunction -get_transfer_function_from_monitor (MetaMonitor *monitor) +static ClutterEOTF +get_eotf_from_monitor (MetaMonitor *monitor) { + ClutterEOTF eotf; const MetaOutputHdrMetadata *hdr_metadata = meta_monitor_get_hdr_metadata (monitor); + eotf.type = CLUTTER_EOTF_TYPE_NAMED; + if (!hdr_metadata->active) - return CLUTTER_TRANSFER_FUNCTION_DEFAULT; + { + eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT; + return eotf; + } switch (hdr_metadata->eotf) { 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: - return CLUTTER_TRANSFER_FUNCTION_DEFAULT; + eotf.tf_name = CLUTTER_TRANSFER_FUNCTION_DEFAULT; + break; case META_OUTPUT_HDR_METADATA_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: 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 @@ -676,28 +686,28 @@ update_color_state (MetaColorDevice *color_device) ClutterContext *clutter_context = meta_backend_get_clutter_context (backend); g_autoptr (ClutterColorState) color_state = NULL; ClutterColorspace colorspace; - ClutterTransferFunction transfer_function; - float min_lum, max_lum, ref_lum; + ClutterEOTF eotf; + const ClutterLuminance *luminance; float reference_luminance_factor; + float new_ref_luminance; UpdateResult result = 0; 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, - &min_lum, - &max_lum, - &ref_lum); + luminance = clutter_eotf_get_default_luminance (eotf); reference_luminance_factor = 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, colorspace, - transfer_function, + eotf.tf_name, NULL, - min_lum, max_lum, ref_lum); + luminance->min, + luminance->max, + new_ref_luminance); if (!color_device->color_state || !clutter_color_state_equals (color_device->color_state, color_state)) diff --git a/src/tests/clutter/conform/actor-color-state.c b/src/tests/clutter/conform/actor-color-state.c index 7782e38a7..8de1a27ea 100644 --- a/src/tests/clutter/conform/actor-color-state.c +++ b/src/tests/clutter/conform/actor-color-state.c @@ -29,14 +29,15 @@ actor_color_state_default (void) { ClutterActor *actor; ClutterColorState *color_state; - ClutterColorspace colorspace; + const ClutterColorimetry *colorimetry; actor = clutter_actor_new (); 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); } @@ -49,8 +50,8 @@ actor_color_state_passed (void) ClutterContext *context = clutter_test_get_context (); ClutterActor *actor; ClutterColorState *color_state; - ClutterColorspace colorspace; - ClutterTransferFunction transfer_function; + const ClutterColorimetry *colorimetry; + const ClutterEOTF *eotf; color_state = clutter_color_state_new (context, CLUTTER_COLORSPACE_BT2020, @@ -70,11 +71,13 @@ actor_color_state_passed (void) g_critical ("Failed to create actor with provided color state."); color_state = clutter_actor_get_color_state (actor); - colorspace = clutter_color_state_get_colorspace (color_state); - transfer_function = clutter_color_state_get_transfer_function (color_state); + colorimetry = clutter_color_state_get_colorimetry (color_state); + eotf = clutter_color_state_get_eotf (color_state); - g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_BT2020); - g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_PQ); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + 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); } @@ -86,8 +89,8 @@ actor_change_color_state (void) ClutterContext *context = clutter_test_get_context (); ClutterActor *actor; ClutterColorState *color_state; - ClutterColorspace colorspace; - ClutterTransferFunction transfer_function; + const ClutterColorimetry *colorimetry; + const ClutterEOTF *eotf; actor = clutter_actor_new (); @@ -101,11 +104,13 @@ actor_change_color_state (void) clutter_actor_set_color_state (actor, color_state); color_state = clutter_actor_get_color_state (actor); - colorspace = clutter_color_state_get_colorspace (color_state); - transfer_function = clutter_color_state_get_transfer_function (color_state); + colorimetry = clutter_color_state_get_colorimetry (color_state); + eotf = clutter_color_state_get_eotf (color_state); - g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_BT2020); - g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_PQ); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + 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); } @@ -115,19 +120,21 @@ actor_unset_color_state (void) { ClutterActor *actor; ClutterColorState *color_state; - ClutterColorspace colorspace; - ClutterTransferFunction transfer_function; + const ClutterColorimetry *colorimetry; + const ClutterEOTF *eotf; actor = clutter_actor_new (); clutter_actor_unset_color_state (actor); color_state = clutter_actor_get_color_state (actor); - colorspace = clutter_color_state_get_colorspace (color_state); - transfer_function = clutter_color_state_get_transfer_function (color_state); + colorimetry = clutter_color_state_get_colorimetry (color_state); + eotf = clutter_color_state_get_eotf (color_state); - g_assert_cmpuint (colorspace, ==, CLUTTER_COLORSPACE_DEFAULT); - g_assert_cmpuint (transfer_function, ==, CLUTTER_TRANSFER_FUNCTION_DEFAULT); + g_assert_cmpuint (colorimetry->type, ==, CLUTTER_COLORIMETRY_TYPE_COLORSPACE); + 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); } diff --git a/src/wayland/meta-wayland-color-management.c b/src/wayland/meta-wayland-color-management.c index ec0c8996f..93f92f882 100644 --- a/src/wayland/meta-wayland-color-management.c +++ b/src/wayland/meta-wayland-color-management.c @@ -118,10 +118,13 @@ typedef struct _MetaWaylandCreatorParams MetaWaylandColorManager *color_manager; struct wl_resource *resource; - ClutterColorspace colorspace; - ClutterTransferFunction transfer_function; - ClutterPrimaries *primaries; - float min_lum, max_lum, ref_lum; + ClutterColorimetry colorimetry; + ClutterEOTF eotf; + ClutterLuminance lum; + + gboolean is_colorimetry_set; + gboolean is_eotf_set; + gboolean is_luminance_set; } MetaWaylandCreatorParams; static void meta_wayland_color_management_surface_free (MetaWaylandColorManagementSurface *cm_surface); @@ -177,15 +180,17 @@ float_to_scaled_uint32 (float value) static gboolean wayland_tf_to_clutter (enum xx_color_manager_v4_transfer_function tf, - ClutterTransferFunction *tf_out) + ClutterEOTF *eotf) { switch (tf) { 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; 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; default: return FALSE; @@ -210,15 +215,17 @@ clutter_tf_to_wayland (ClutterTransferFunction tf) static gboolean wayland_primaries_to_clutter (enum xx_color_manager_v4_primaries primaries, - ClutterColorspace *primaries_out) + ClutterColorimetry *colorimetry) { switch (primaries) { 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; 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; default: return FALSE; @@ -340,47 +347,43 @@ static void send_information (struct wl_resource *info_resource, ClutterColorState *color_state) { - ClutterColorspace clutter_colorspace; - const ClutterPrimaries *clutter_primaries; - ClutterTransferFunction clutter_tf; + enum xx_color_manager_v4_primaries primaries; 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); - if (clutter_colorspace != CLUTTER_COLORSPACE_DEFAULT) + colorimetry = clutter_color_state_get_colorimetry (color_state); + switch (colorimetry->type) { - enum xx_color_manager_v4_primaries primaries; - - primaries = clutter_primaries_to_wayland (clutter_colorspace); + case CLUTTER_COLORIMETRY_TYPE_COLORSPACE: + primaries = clutter_primaries_to_wayland (colorimetry->colorspace); xx_image_description_info_v4_send_primaries_named (info_resource, primaries); - } - - clutter_primaries = clutter_color_state_get_primaries (color_state); - if (clutter_primaries) - { + break; + case CLUTTER_COLORIMETRY_TYPE_PRIMARIES: xx_image_description_info_v4_send_primaries ( info_resource, - float_to_scaled_uint32 (clutter_primaries->r_x), - float_to_scaled_uint32 (clutter_primaries->r_y), - float_to_scaled_uint32 (clutter_primaries->g_x), - float_to_scaled_uint32 (clutter_primaries->g_y), - float_to_scaled_uint32 (clutter_primaries->b_x), - float_to_scaled_uint32 (clutter_primaries->b_y), - float_to_scaled_uint32 (clutter_primaries->w_x), - float_to_scaled_uint32 (clutter_primaries->w_y)); + float_to_scaled_uint32 (colorimetry->primaries->r_x), + float_to_scaled_uint32 (colorimetry->primaries->r_y), + float_to_scaled_uint32 (colorimetry->primaries->g_x), + float_to_scaled_uint32 (colorimetry->primaries->g_y), + float_to_scaled_uint32 (colorimetry->primaries->b_x), + float_to_scaled_uint32 (colorimetry->primaries->b_y), + float_to_scaled_uint32 (colorimetry->primaries->w_x), + float_to_scaled_uint32 (colorimetry->primaries->w_y)); + break; } - clutter_tf = clutter_color_state_get_transfer_function (color_state); - tf = clutter_tf_to_wayland (clutter_tf); + eotf = clutter_color_state_get_eotf (color_state); + tf = clutter_tf_to_wayland (eotf->tf_name); xx_image_description_info_v4_send_tf_named (info_resource, tf); - clutter_color_state_get_luminances (color_state, - &min_lum, &max_lum, &ref_lum); + lum = clutter_color_state_get_luminance (color_state); xx_image_description_info_v4_send_luminances (info_resource, - float_to_scaled_uint32 (min_lum), - (uint32_t) max_lum, - (uint32_t) ref_lum); + float_to_scaled_uint32 (lum->min), + (uint32_t) lum->max, + (uint32_t) lum->ref); } static void @@ -825,20 +828,16 @@ meta_wayland_creator_params_new (MetaWaylandColorManager *color_manager, creator_params->color_manager = color_manager; 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; } static void 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); } @@ -862,10 +861,10 @@ creator_params_create (struct wl_client *client, struct wl_resource *image_desc_resource; g_autoptr (ClutterColorState) color_state = NULL; MetaWaylandImageDescription *image_desc; + ClutterColorspace colorspace; + ClutterPrimaries *primaries; - if ((creator_params->colorspace == CLUTTER_COLORSPACE_DEFAULT && - !creator_params->primaries) || - creator_params->transfer_function == CLUTTER_TRANSFER_FUNCTION_DEFAULT) + if (!creator_params->is_colorimetry_set || !creator_params->is_eotf_set) { wl_resource_post_error (resource, 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), id); - color_state = - clutter_color_state_new_full (clutter_context, - creator_params->colorspace, - creator_params->transfer_function, - creator_params->primaries, - creator_params->min_lum, - creator_params->max_lum, - creator_params->ref_lum); + switch (creator_params->colorimetry.type) + { + case CLUTTER_COLORIMETRY_TYPE_COLORSPACE: + colorspace = creator_params->colorimetry.colorspace; + primaries = NULL; + break; + case CLUTTER_COLORIMETRY_TYPE_PRIMARIES: + 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 = 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 = 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, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, @@ -919,7 +929,7 @@ creator_params_set_tf_named (struct wl_client *client, return; } - if (!wayland_tf_to_clutter (tf, &clutter_tf)) + if (!wayland_tf_to_clutter (tf, &eotf)) { wl_resource_post_error (resource, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, @@ -927,7 +937,8 @@ creator_params_set_tf_named (struct wl_client *client, return; } - creator_params->transfer_function = clutter_tf; + creator_params->eotf = eotf; + creator_params->is_eotf_set = TRUE; } static void @@ -947,10 +958,9 @@ creator_params_set_primaries_named (struct wl_client *client, { MetaWaylandCreatorParams *creator_params = wl_resource_get_user_data (resource); - ClutterColorspace colorspace; + ClutterColorimetry colorimetry; - if (creator_params->colorspace != CLUTTER_COLORSPACE_DEFAULT || - creator_params->primaries) + if (creator_params->is_colorimetry_set) { wl_resource_post_error (resource, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, @@ -958,7 +968,7 @@ creator_params_set_primaries_named (struct wl_client *client, return; } - if (!wayland_primaries_to_clutter (primaries, &colorspace)) + if (!wayland_primaries_to_clutter (primaries, &colorimetry)) { wl_resource_post_error (resource, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, @@ -966,7 +976,8 @@ creator_params_set_primaries_named (struct wl_client *client, return; } - creator_params->colorspace = colorspace; + creator_params->colorimetry = colorimetry; + creator_params->is_colorimetry_set = TRUE; } static void @@ -985,8 +996,7 @@ creator_params_set_primaries (struct wl_client *client, wl_resource_get_user_data (resource); ClutterPrimaries *primaries; - if (creator_params->colorspace != CLUTTER_COLORSPACE_DEFAULT || - creator_params->primaries) + if (creator_params->is_colorimetry_set) { wl_resource_post_error (resource, 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); } - 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 @@ -1031,9 +1043,7 @@ creator_params_set_luminance (struct wl_client *client, wl_resource_get_user_data (resource); float min, max, ref; - if (creator_params->min_lum >= 0.0f || - creator_params->max_lum >= 0.0f || - creator_params->ref_lum >= 0.0f) + if (creator_params->is_luminance_set) { wl_resource_post_error (resource, XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, @@ -1061,9 +1071,10 @@ creator_params_set_luminance (struct wl_client *client, return; } - creator_params->min_lum = min; - creator_params->max_lum = max; - creator_params->ref_lum = ref; + creator_params->lum.min = min; + creator_params->lum.max = max; + creator_params->lum.ref = ref; + creator_params->is_luminance_set = TRUE; } static void