diff --git a/clutter/clutter/clutter-color-state.c b/clutter/clutter/clutter-color-state.c index bb9e6c271..c34a969fb 100644 --- a/clutter/clutter/clutter-color-state.c +++ b/clutter/clutter/clutter-color-state.c @@ -54,6 +54,8 @@ #include "clutter/clutter-enum-types.h" #include "clutter/clutter-private.h" +#define UNIFORM_NAME_LUMINANCE_MAPPING "luminance_mapping" + enum { PROP_0, @@ -505,9 +507,9 @@ clutter_color_state_new_full (ClutterContext *context, static const char pq_eotf_source[] = "// pq_eotf:\n" - "// @pq: Normalized ([0,1]) electrical signal value\n" - "// Returns: Luminance in cd/m²\n" - "vec3 pq_eotf (vec3 pq)\n" + "// @color: Normalized ([0,1]) electrical signal value\n" + "// Returns: tristimulus values ([0,1])\n" + "vec3 pq_eotf (vec3 color)\n" "{\n" " const float c1 = 0.8359375;\n" " const float c2 = 18.8515625;\n" @@ -516,44 +518,43 @@ static const char pq_eotf_source[] = " const float oo_m1 = 1.0 / 0.1593017578125;\n" " const float oo_m2 = 1.0 / 78.84375;\n" "\n" - " vec3 num = max (pow (pq, vec3 (oo_m2)) - c1, vec3 (0.0));\n" - " vec3 den = c2 - c3 * pow (pq, vec3 (oo_m2));\n" + " vec3 num = max (pow (color, vec3 (oo_m2)) - c1, vec3 (0.0));\n" + " vec3 den = c2 - c3 * pow (color, vec3 (oo_m2));\n" "\n" - " return 10000.0 * pow (num / den, vec3 (oo_m1));\n" + " return pow (num / den, vec3 (oo_m1));\n" "}\n" "\n" - "vec4 pq_eotf (vec4 pq)\n" + "vec4 pq_eotf (vec4 color)\n" "{\n" - " return vec4 (pq_eotf (pq.rgb), pq.a);\n" + " return vec4 (pq_eotf (color.rgb), color.a);\n" "}\n"; static const char pq_inv_eotf_source[] = "// pq_inv_eotf:\n" - "// @nits: Optical signal value in cd/m²\n" + "// @color: Normalized tristimulus values ([0,1])" "// Returns: Normalized ([0,1]) electrical signal value\n" - "vec3 pq_inv_eotf (vec3 nits)\n" + "vec3 pq_inv_eotf (vec3 color)\n" "{\n" - " vec3 normalized = clamp (nits / 10000.0, vec3 (0), vec3 (1));\n" " float m1 = 0.1593017578125;\n" " float m2 = 78.84375;\n" " float c1 = 0.8359375;\n" " float c2 = 18.8515625;\n" " float c3 = 18.6875;\n" - " vec3 normalized_pow_m1 = pow (normalized, vec3 (m1));\n" - " vec3 num = vec3 (c1) + c2 * normalized_pow_m1;\n" - " vec3 denum = vec3 (1.0) + c3 * normalized_pow_m1;\n" + " vec3 color_pow_m1 = pow (color, vec3 (m1));\n" + " vec3 num = vec3 (c1) + c2 * color_pow_m1;\n" + " vec3 denum = vec3 (1.0) + c3 * color_pow_m1;\n" " return pow (num / denum, vec3 (m2));\n" "}\n" "\n" - "vec4 pq_inv_eotf (vec4 nits)\n" + "vec4 pq_inv_eotf (vec4 color)\n" "{\n" - " return vec4 (pq_inv_eotf (nits.rgb), nits.a);\n" + " return vec4 (pq_inv_eotf (color.rgb), color.a);\n" "}\n"; static const char srgb_eotf_source[] = "// srgb_eotf:\n" "// @color: Normalized ([0,1]) electrical signal value.\n" - "// Returns: Normalized luminance ([0,1])\n" + "// Returns: Normalized tristimulus values ([0,1])\n" "vec3 srgb_eotf (vec3 color)\n" "{\n" " bvec3 is_low = lessThanEqual (color, vec3 (0.04045));\n" @@ -569,7 +570,7 @@ static const char srgb_eotf_source[] = static const char srgb_inv_eotf_source[] = "// srgb_inv_eotf:\n" - "// @color: Normalized ([0,1]) optical signal value\n" + "// @color: Normalized ([0,1]) tristimulus values\n" "// Returns: Normalized ([0,1]) electrical signal value\n" "vec3 srgb_inv_eotf (vec3 color)\n" "{\n" @@ -585,20 +586,6 @@ static const char srgb_inv_eotf_source[] = " return vec4 (srgb_inv_eotf (color.rgb), color.a);\n" "}\n"; -/* Luminance gain default value (203) retrieved from - * https://github.com/w3c/ColorWeb-CG/blob/feature/add-mastering-display-info/hdr_html_canvas_element.md#srgb-to-rec2100-pq */ -static const char srgb_luminance_gain_source[] = - "vec3 srgb_luminance_gain (vec3 value)\n" - "{\n" - " return 203.0 * value;\n" - "}\n"; - -static const char pq_luminance_clamp_source[] = - "vec3 pq_luminance_clamp (vec3 value)\n" - "{\n" - " return clamp (value, 0.0, 203.0) / 203.0;\n" - "}\n"; - /* Calculated using: * numpy.dot(colour.models.RGB_COLOURSPACE_BT2020.matrix_XYZ_to_RGB, * colour.models.RGB_COLOURSPACE_BT709.matrix_RGB_to_XYZ) @@ -652,16 +639,6 @@ static const TransferFunction srgb_inv_eotf = { .name = "srgb_inv_eotf", }; -static const TransferFunction srgb_luminance_gain = { - .source = srgb_luminance_gain_source, - .name = "srgb_luminance_gain", -}; - -static const TransferFunction pq_luminance_clamp = { - .source = pq_luminance_clamp_source, - .name = "pq_luminance_clamp", -}; - static const MatrixMultiplication bt709_to_bt2020 = { .source = bt709_to_bt2020_matrix_source, .name = "bt709_to_bt2020", @@ -741,85 +718,17 @@ get_inv_eotf (ClutterColorState *color_state) return NULL; } -static const TransferFunction * -get_denormalize_function (ClutterColorState *color_state, - ClutterColorState *target_color_state) -{ - ClutterColorStatePrivate *priv = - clutter_color_state_get_instance_private (color_state); - ClutterColorStatePrivate *target_priv = - clutter_color_state_get_instance_private (target_color_state); - - switch (priv->transfer_function) - { - case CLUTTER_TRANSFER_FUNCTION_SRGB: - case CLUTTER_TRANSFER_FUNCTION_DEFAULT: - switch (target_priv->transfer_function) - { - case CLUTTER_TRANSFER_FUNCTION_PQ: - case CLUTTER_TRANSFER_FUNCTION_LINEAR: - return &srgb_luminance_gain; - case CLUTTER_TRANSFER_FUNCTION_SRGB: - case CLUTTER_TRANSFER_FUNCTION_DEFAULT: - return NULL; - } - break; - case CLUTTER_TRANSFER_FUNCTION_PQ: - switch (target_priv->transfer_function) - { - case CLUTTER_TRANSFER_FUNCTION_PQ: - case CLUTTER_TRANSFER_FUNCTION_LINEAR: - return NULL; - case CLUTTER_TRANSFER_FUNCTION_SRGB: - case CLUTTER_TRANSFER_FUNCTION_DEFAULT: - return &pq_luminance_clamp; - } - break; - case CLUTTER_TRANSFER_FUNCTION_LINEAR: - return NULL; - } - - g_return_val_if_reached (NULL); -} - static void get_transfer_functions (ClutterColorState *color_state, ClutterColorState *target_color_state, const TransferFunction **pre_transfer_function, - const TransferFunction **denormalize_function, const TransferFunction **post_transfer_function) { - ClutterColorStatePrivate *priv = - clutter_color_state_get_instance_private (color_state); - ClutterColorStatePrivate *target_priv = - clutter_color_state_get_instance_private (target_color_state); - - if (priv->colorspace == target_priv->colorspace && - priv->transfer_function == target_priv->transfer_function) + if (clutter_color_state_equals (color_state, target_color_state)) return; - if (priv->transfer_function != CLUTTER_TRANSFER_FUNCTION_LINEAR && - target_priv->transfer_function == CLUTTER_TRANSFER_FUNCTION_LINEAR) - { - *pre_transfer_function = get_eotf (color_state); - *denormalize_function = get_denormalize_function (color_state, - target_color_state); - } - else if (priv->transfer_function == CLUTTER_TRANSFER_FUNCTION_LINEAR && - target_priv->transfer_function != CLUTTER_TRANSFER_FUNCTION_LINEAR) - { - *denormalize_function = get_denormalize_function (color_state, - target_color_state); - *post_transfer_function = get_inv_eotf (target_color_state); - } - else if (priv->transfer_function != CLUTTER_TRANSFER_FUNCTION_LINEAR && - target_priv->transfer_function != CLUTTER_TRANSFER_FUNCTION_LINEAR) - { - *pre_transfer_function = get_eotf (color_state); - *denormalize_function = get_denormalize_function (color_state, - target_color_state); - *post_transfer_function = get_inv_eotf (target_color_state); - } + *pre_transfer_function = get_eotf (color_state); + *post_transfer_function = get_inv_eotf (target_color_state); } static const MatrixMultiplication * @@ -869,7 +778,6 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state, CoglSnippet *snippet; const MatrixMultiplication *color_space_mapping = NULL; const TransferFunction *pre_transfer_function = NULL; - const TransferFunction *denormalize_function = NULL; const TransferFunction *post_transfer_function = NULL; g_autoptr (GString) globals_source = NULL; g_autoptr (GString) snippet_source = NULL; @@ -890,19 +798,19 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state, get_transfer_functions (color_state, target_color_state, &pre_transfer_function, - &denormalize_function, &post_transfer_function); globals_source = g_string_new (NULL); if (pre_transfer_function) g_string_append_printf (globals_source, "%s\n", pre_transfer_function->source); - if (denormalize_function) - g_string_append_printf (globals_source, "%s\n", denormalize_function->source); if (post_transfer_function) g_string_append_printf (globals_source, "%s\n", post_transfer_function->source); if (color_space_mapping) g_string_append_printf (globals_source, "%s\n", color_space_mapping->source); + g_string_append (globals_source, + "uniform float " UNIFORM_NAME_LUMINANCE_MAPPING ";\n"); + /* * The following statements generate a shader snippet that transforms colors * from one color state (transfer function, color space, color encoding) into @@ -938,12 +846,10 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state, pre_transfer_function->name); } - if (denormalize_function) - { - g_string_append_printf (snippet_source, - " color_state_color = %s (color_state_color);\n", - denormalize_function->name); - } + g_string_append (snippet_source, + " color_state_color = " + UNIFORM_NAME_LUMINANCE_MAPPING " * color_state_color;\n"); + if (color_space_mapping) { g_string_append_printf (snippet_source, @@ -974,6 +880,45 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state, return snippet; } +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; + + 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); + + /* 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); +} + +void +clutter_color_state_update_uniforms (ClutterColorState *color_state, + ClutterColorState *target_color_state, + CoglPipeline *pipeline) +{ + float luminance_mapping; + int uniform_location_luminance_mapping; + + luminance_mapping = get_luminance_mapping (color_state, target_color_state); + + uniform_location_luminance_mapping = + cogl_pipeline_get_uniform_location (pipeline, + UNIFORM_NAME_LUMINANCE_MAPPING); + + cogl_pipeline_set_uniform_1f (pipeline, + uniform_location_luminance_mapping, + luminance_mapping); +} + void clutter_color_state_add_pipeline_transform (ClutterColorState *color_state, ClutterColorState *target_color_state, @@ -987,6 +932,10 @@ clutter_color_state_add_pipeline_transform (ClutterColorState *color_state, snippet = clutter_color_state_get_transform_snippet (color_state, target_color_state); cogl_pipeline_add_snippet (pipeline, snippet); + + clutter_color_state_update_uniforms (color_state, + target_color_state, + pipeline); } static gboolean diff --git a/clutter/clutter/clutter-color-state.h b/clutter/clutter/clutter-color-state.h index d2a5d7792..dd2781008 100644 --- a/clutter/clutter/clutter-color-state.h +++ b/clutter/clutter/clutter-color-state.h @@ -74,6 +74,12 @@ void clutter_color_state_add_pipeline_transform (ClutterColorState *color_state, ClutterColorState *target_color_state, CoglPipeline *pipeline); +CLUTTER_EXPORT +void clutter_color_state_update_uniforms (ClutterColorState *color_state, + ClutterColorState *target_color_state, + CoglPipeline *pipeline); + + CLUTTER_EXPORT gboolean clutter_color_state_equals (ClutterColorState *color_state, ClutterColorState *other_color_state); diff --git a/clutter/clutter/clutter-pipeline-cache.c b/clutter/clutter/clutter-pipeline-cache.c index b2abaed3b..4d032bfa3 100644 --- a/clutter/clutter/clutter-pipeline-cache.c +++ b/clutter/clutter/clutter-pipeline-cache.c @@ -116,9 +116,20 @@ clutter_pipeline_cache_get_pipeline (ClutterPipelineCache *pipeline_cache, pipeline = g_hash_table_lookup (group_entry->slots[slot], &key); if (pipeline) - return cogl_pipeline_copy (pipeline); + { + CoglPipeline *new_pipeline; + + new_pipeline = cogl_pipeline_copy (pipeline); + clutter_color_state_update_uniforms (source_color_state, + target_color_state, + new_pipeline); + return new_pipeline; + } else - return NULL; + { + return NULL; + } + } /**