clutter/color-state-params: Improve create transform snippet

Make create_transform_snippet method more consistent.

Abstract TransferFunction struct: convert it to ColorOpSnippet.

This transform snippet will be defined by these ColorOpSnippets.
These ColorOpSnippets are similar to the prescriptive DRM API for
color transformation.

A standard transform snippet would have as ColorOpSnippets:
  1. eotf
  2. luminance_mapping
  3. color_space_mapping
  4. inv_eotf

Update uniforms the same way the transform snippet is defined.

Update color transform key to consider how the transform snippet is
generated.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4144>
This commit is contained in:
Joan Torres 2024-10-25 16:26:18 +02:00 committed by Marge Bot
parent 7f8df9d9a1
commit 0095e7d50a
3 changed files with 240 additions and 112 deletions

View File

@ -33,8 +33,8 @@
#define UNIFORM_NAME_GAMMA_EXP "gamma_exp"
#define UNIFORM_NAME_INV_GAMMA_EXP "inv_gamma_exp"
#define UNIFORM_NAME_COLOR_SPACE_MAPPING "color_space_mapping"
#define UNIFORM_NAME_LUMINANCE_MAPPING "luminance_mapping"
#define UNIFORM_NAME_COLOR_SPACE_MAPPING "color_transformation_matrix"
#define UNIFORM_NAME_LUMINANCE_MAPPING "luminance_factor"
typedef struct _ClutterColorStateParams
{
@ -376,8 +376,12 @@ clutter_color_state_params_init_color_transform_key (ClutterColorState *c
ClutterColorStateParams *target_color_state_params =
CLUTTER_COLOR_STATE_PARAMS (target_color_state);
key->source.eotf_key = get_eotf_key (color_state_params->eotf);
key->target.eotf_key = get_eotf_key (target_color_state_params->eotf);
key->source_eotf_bits = get_eotf_key (color_state_params->eotf);
key->target_eotf_bits = get_eotf_key (target_color_state_params->eotf);
key->luminance_bit = luminances_equal (color_state_params,
target_color_state_params) ? 0 : 1;
key->color_trans_bit = colorimetry_equal (color_state_params,
target_color_state_params) ? 0 : 1;
}
static const char srgb_eotf_source[] =
@ -525,65 +529,54 @@ static const char gamma_inv_eotf_source[] =
" return vec4 (gamma_inv_eotf (color.rgb), color.a);\n"
"}\n";
typedef struct _TransferFunction
typedef struct _ColorOpSnippet
{
const char *source;
const char *name;
} TransferFunction;
} ColorOpSnippet;
static const TransferFunction srgb_eotf = {
static const ColorOpSnippet srgb_eotf = {
.source = srgb_eotf_source,
.name = "srgb_eotf",
};
static const TransferFunction srgb_inv_eotf = {
static const ColorOpSnippet srgb_inv_eotf = {
.source = srgb_inv_eotf_source,
.name = "srgb_inv_eotf",
};
static const TransferFunction pq_eotf = {
static const ColorOpSnippet pq_eotf = {
.source = pq_eotf_source,
.name = "pq_eotf",
};
static const TransferFunction pq_inv_eotf = {
static const ColorOpSnippet pq_inv_eotf = {
.source = pq_inv_eotf_source,
.name = "pq_inv_eotf",
};
static const TransferFunction bt709_eotf = {
static const ColorOpSnippet bt709_eotf = {
.source = bt709_eotf_source,
.name = "bt709_eotf",
};
static const TransferFunction bt709_inv_eotf = {
static const ColorOpSnippet bt709_inv_eotf = {
.source = bt709_inv_eotf_source,
.name = "bt709_inv_eotf",
};
static const TransferFunction gamma_eotf = {
static const ColorOpSnippet gamma_eotf = {
.source = gamma_eotf_source,
.name = "gamma_eotf",
};
static const TransferFunction gamma_inv_eotf = {
static const ColorOpSnippet gamma_inv_eotf = {
.source = gamma_inv_eotf_source,
.name = "gamma_inv_eotf",
};
static void
append_shader_description (GString *snippet_source,
ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params)
{
g_string_append_printf (snippet_source,
" // %s to %s\n",
clutter_eotf_to_string (color_state_params->eotf),
clutter_eotf_to_string (target_color_state_params->eotf));
}
static const TransferFunction *
get_eotf (ClutterColorStateParams *color_state_params)
static const ColorOpSnippet *
get_eotf_snippet (ClutterColorStateParams *color_state_params)
{
switch (color_state_params->eotf.type)
{
@ -609,8 +602,8 @@ get_eotf (ClutterColorStateParams *color_state_params)
return NULL;
}
static const TransferFunction *
get_inv_eotf (ClutterColorStateParams *color_state_params)
static const ColorOpSnippet *
get_inv_eotf_snippet (ClutterColorStateParams *color_state_params)
{
switch (color_state_params->eotf.type)
{
@ -637,13 +630,92 @@ get_inv_eotf (ClutterColorStateParams *color_state_params)
}
static void
get_transfer_functions (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
const TransferFunction **pre_transfer_function,
const TransferFunction **post_transfer_function)
get_eotf_snippets (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
const ColorOpSnippet **eotf_snippet,
const ColorOpSnippet **inv_eotf_snippet)
{
*pre_transfer_function = get_eotf (color_state_params);
*post_transfer_function = get_inv_eotf (target_color_state_params);
*eotf_snippet = get_eotf_snippet (color_state_params);
*inv_eotf_snippet = get_inv_eotf_snippet (target_color_state_params);
}
static const char luminance_mapping_source[] =
"uniform float " UNIFORM_NAME_LUMINANCE_MAPPING ";\n"
"// luminance_mapping:\n"
"// @color: Normalized ([0,1]) in origin luminance\n"
"// Returns: Normalized ([0,1]) in target luminance\n"
"vec3 luminance_mapping (vec3 color)\n"
"{\n"
" return " UNIFORM_NAME_LUMINANCE_MAPPING " * color;\n"
"}\n"
"\n"
"vec4 luminance_mapping (vec4 color)\n"
"{\n"
" return vec4 (luminance_mapping (color.rgb), color.a);\n"
"}\n";
static const ColorOpSnippet luminance_mapping = {
.source = luminance_mapping_source,
.name = "luminance_mapping",
};
static void
get_luminance_mapping_snippet (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
const ColorOpSnippet **luminance_mapping_snippet)
{
if (luminances_equal (color_state_params, target_color_state_params))
return;
*luminance_mapping_snippet = &luminance_mapping;
}
static const char color_space_mapping_source[] =
"uniform mat3 " UNIFORM_NAME_COLOR_SPACE_MAPPING ";\n"
"// color_space_mapping:\n"
"// @color: Normalized ([0,1]) in origin colorspace\n"
"// Returns: Normalized ([0,1]) in target colorspace\n"
"vec3 color_space_mapping (vec3 color)\n"
"{\n"
" return " UNIFORM_NAME_COLOR_SPACE_MAPPING " * color;\n"
"}\n"
"\n"
"vec4 color_space_mapping (vec4 color)\n"
"{\n"
" return vec4 (color_space_mapping (color.rgb), color.a);\n"
"}\n";
static const ColorOpSnippet color_space_mapping = {
.source = color_space_mapping_source,
.name = "color_space_mapping",
};
static void
get_color_space_mapping_snippet (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
const ColorOpSnippet **color_space_mapping_snippet)
{
if (colorimetry_equal (color_state_params, target_color_state_params))
return;
*color_space_mapping_snippet = &color_space_mapping;
}
static void
append_color_op_snippet (const ColorOpSnippet *color_snippet,
GString *snippet_globals,
GString *snippet_source,
const char *snippet_color_var)
{
if (!color_snippet)
return;
g_string_append_printf (snippet_globals, "%s\n", color_snippet->source);
g_string_append_printf (snippet_source,
" %s = %s (%s);\n",
snippet_color_var,
color_snippet->name,
snippet_color_var);
}
static CoglSnippet *
@ -651,30 +723,32 @@ clutter_color_state_params_create_transform_snippet (ClutterColorState *color_st
ClutterColorState *target_color_state)
{
CoglSnippet *snippet;
const TransferFunction *pre_transfer_function = NULL;
const TransferFunction *post_transfer_function = NULL;
g_autoptr (GString) globals_source = NULL;
const char *snippet_color_var;
g_autoptr (GString) snippet_globals = NULL;
g_autoptr (GString) snippet_source = NULL;
const ColorOpSnippet *eotf_snippet = NULL;
const ColorOpSnippet *inv_eotf_snippet = NULL;
const ColorOpSnippet *color_space_mapping_snippet = NULL;
const ColorOpSnippet *luminance_mapping_snippet = NULL;
ClutterColorStateParams *color_state_params =
CLUTTER_COLOR_STATE_PARAMS (color_state);
ClutterColorStateParams *target_color_state_params =
CLUTTER_COLOR_STATE_PARAMS (target_color_state);
get_transfer_functions (color_state_params,
target_color_state_params,
&pre_transfer_function,
&post_transfer_function);
snippet_globals = g_string_new (NULL);
snippet_source = g_string_new (NULL);
snippet_color_var = "color_state_color";
globals_source = g_string_new (NULL);
if (pre_transfer_function)
g_string_append_printf (globals_source, "%s\n", pre_transfer_function->source);
if (post_transfer_function)
g_string_append_printf (globals_source, "%s\n", post_transfer_function->source);
g_string_append (globals_source,
"uniform float " UNIFORM_NAME_LUMINANCE_MAPPING ";\n");
g_string_append (globals_source,
"uniform mat3 " UNIFORM_NAME_COLOR_SPACE_MAPPING ";\n");
get_eotf_snippets (color_state_params,
target_color_state_params,
&eotf_snippet,
&inv_eotf_snippet);
get_luminance_mapping_snippet (color_state_params,
target_color_state_params,
&luminance_mapping_snippet);
get_color_space_mapping_snippet (color_state_params,
target_color_state_params,
&color_space_mapping_snippet);
/*
* The following statements generate a shader snippet that transforms colors
@ -691,49 +765,43 @@ clutter_color_state_params_create_transform_snippet (ClutterColorState *color_st
*
* The snippet contains a pipeline that roughly looks like this:
*
* color = pre_transfer_function (color)
* color *= luminance_gain
* color = color_space_mapping_matrix * color
* color = post_transfer_function (color)
* color = eotf (color)
* color = luminance_mapping (color)
* color = color_space_mapping (color)
* color = inv_eotf (color)
*
*/
snippet_source = g_string_new (NULL);
append_shader_description (snippet_source,
color_state_params,
target_color_state_params);
g_string_append_printf (snippet_source,
" vec3 %s = cogl_color_out.rgb;\n",
snippet_color_var);
g_string_append (snippet_source,
" vec3 color_state_color = cogl_color_out.rgb;\n");
append_color_op_snippet (eotf_snippet,
snippet_globals,
snippet_source,
snippet_color_var);
if (pre_transfer_function)
{
g_string_append_printf (snippet_source,
" color_state_color = %s (color_state_color);\n",
pre_transfer_function->name);
}
append_color_op_snippet (luminance_mapping_snippet,
snippet_globals,
snippet_source,
snippet_color_var);
g_string_append (snippet_source,
" color_state_color = "
UNIFORM_NAME_LUMINANCE_MAPPING " * color_state_color;\n");
append_color_op_snippet (color_space_mapping_snippet,
snippet_globals,
snippet_source,
snippet_color_var);
g_string_append (snippet_source,
" color_state_color = "
UNIFORM_NAME_COLOR_SPACE_MAPPING " * color_state_color;\n");
append_color_op_snippet (inv_eotf_snippet,
snippet_globals,
snippet_source,
snippet_color_var);
if (post_transfer_function)
{
g_string_append_printf (snippet_source,
" // Post transfer function\n"
" color_state_color = %s (color_state_color);\n",
post_transfer_function->name);
}
g_string_append (snippet_source,
" cogl_color_out = vec4 (color_state_color, cogl_color_out.a);\n");
g_string_append_printf (snippet_source,
" cogl_color_out = vec4 (%s, cogl_color_out.a);\n",
snippet_color_var);
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
globals_source->str,
snippet_globals->str,
snippet_source->str);
cogl_snippet_set_capability (snippet,
CLUTTER_PIPELINE_CAPABILITY,
@ -1006,22 +1074,11 @@ get_color_space_mapping_matrix (ClutterColorStateParams *color_state_params,
}
static void
clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
ClutterColorState *target_color_state,
CoglPipeline *pipeline)
update_eotf_uniforms (ClutterColorStateParams *color_state_params,
CoglPipeline *pipeline)
{
const ClutterEOTF *eotf;
const ClutterEOTF *target_eotf;
float lum_mapping;
float color_space_mapping[9] = { 0 };
int uniform_location_gamma_exp;
int uniform_location_inv_gamma_exp;
int uniform_location_luminance_mapping;
int uniform_location_color_space_mapping;
ClutterColorStateParams *color_state_params =
CLUTTER_COLOR_STATE_PARAMS (color_state);
ClutterColorStateParams *target_color_state_params =
CLUTTER_COLOR_STATE_PARAMS (target_color_state);
eotf = clutter_color_state_params_get_eotf (color_state_params);
if (eotf->type == CLUTTER_EOTF_TYPE_GAMMA)
@ -1034,8 +1091,16 @@ clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
uniform_location_gamma_exp,
eotf->gamma_exp);
}
}
target_eotf = clutter_color_state_params_get_eotf (target_color_state_params);
static void
update_inv_eotf_uniforms (ClutterColorStateParams *color_state_params,
CoglPipeline *pipeline)
{
const ClutterEOTF *target_eotf;
int uniform_location_inv_gamma_exp;
target_eotf = clutter_color_state_params_get_eotf (color_state_params);
if (target_eotf->type == CLUTTER_EOTF_TYPE_GAMMA)
{
uniform_location_inv_gamma_exp =
@ -1046,6 +1111,27 @@ clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
uniform_location_inv_gamma_exp,
1.0f / target_eotf->gamma_exp);
}
}
static void
update_eotfs_uniforms (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
CoglPipeline *pipeline)
{
update_eotf_uniforms (color_state_params, pipeline);
update_inv_eotf_uniforms (target_color_state_params, pipeline);
}
static void
update_luminance_mapping_uniforms (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
CoglPipeline *pipeline)
{
float lum_mapping;
int uniform_location_luminance_mapping;
if (luminances_equal (color_state_params, target_color_state_params))
return;
lum_mapping = get_luminance_mapping (color_state_params,
target_color_state_params);
@ -1057,9 +1143,22 @@ clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
cogl_pipeline_set_uniform_1f (pipeline,
uniform_location_luminance_mapping,
lum_mapping);
}
get_color_space_mapping_matrix (color_state_params, target_color_state_params,
color_space_mapping);
static void
update_color_space_mapping_uniforms (ClutterColorStateParams *color_state_params,
ClutterColorStateParams *target_color_state_params,
CoglPipeline *pipeline)
{
float color_space_mapping_matrix[9] = { 0 };
int uniform_location_color_space_mapping;
if (colorimetry_equal (color_state_params, target_color_state_params))
return;
get_color_space_mapping_matrix (color_state_params,
target_color_state_params,
color_space_mapping_matrix);
uniform_location_color_space_mapping =
cogl_pipeline_get_uniform_location (pipeline,
@ -1070,7 +1169,30 @@ clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
3,
1,
FALSE,
color_space_mapping);
color_space_mapping_matrix);
}
static void
clutter_color_state_params_update_uniforms (ClutterColorState *color_state,
ClutterColorState *target_color_state,
CoglPipeline *pipeline)
{
ClutterColorStateParams *color_state_params =
CLUTTER_COLOR_STATE_PARAMS (color_state);
ClutterColorStateParams *target_color_state_params =
CLUTTER_COLOR_STATE_PARAMS (target_color_state);
update_eotfs_uniforms (color_state_params,
target_color_state_params,
pipeline);
update_luminance_mapping_uniforms (color_state_params,
target_color_state_params,
pipeline);
update_color_space_mapping_uniforms (color_state_params,
target_color_state_params,
pipeline);
}
static gboolean

View File

@ -26,12 +26,14 @@
typedef struct _ClutterColorTransformKey
{
struct {
guint eotf_key;
} source;
struct {
guint eotf_key;
} target;
/* 3 bits to define TransferFunction enums
* + 1 bit to define Gamma TF */
guint source_eotf_bits : 4;
guint target_eotf_bits : 4;
/* When there is a luminance mapping snippet */
guint luminance_bit : 1;
/* When there is a color trans snippet */
guint color_trans_bit : 1;
} ClutterColorTransformKey;
void clutter_color_transform_key_init (ClutterColorTransformKey *key,

View File

@ -78,8 +78,10 @@ clutter_color_transform_key_hash (gconstpointer data)
{
const ClutterColorTransformKey *key = data;
return (key->source.eotf_key ^
key->target.eotf_key);
return key->source_eotf_bits << 0 &
key->target_eotf_bits << 4 &
key->luminance_bit << 8 &
key->color_trans_bit << 9;
}
gboolean
@ -89,8 +91,10 @@ clutter_color_transform_key_equal (gconstpointer data1,
const ClutterColorTransformKey *key1 = data1;
const ClutterColorTransformKey *key2 = data2;
return (key1->source.eotf_key == key2->source.eotf_key &&
key1->target.eotf_key == key2->target.eotf_key);
return (key1->source_eotf_bits == key2->source_eotf_bits &&
key1->target_eotf_bits == key2->target_eotf_bits &&
key1->luminance_bit == key2->luminance_bit &&
key1->color_trans_bit == key2->color_trans_bit);
}
void