clutter/color-state: Cache snippets

The cogl shader cache uses snippet pointers as cache keys, meaning even
if we generate two identical snippets; if they have different pointer
addresses, they'll generate separate cache entries. Handle this by
caching our snippets on the context.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3433>
This commit is contained in:
Jonas Ådahl 2024-05-10 15:11:50 +02:00 committed by Sebastian Wick
parent d7bbc9712f
commit 2bd8216eb1

View File

@ -81,10 +81,88 @@ struct _ClutterColorStatePrivate
ClutterTransferFunction transfer_function;
};
typedef struct _SnippetCacheKey
{
struct {
ClutterColorspace colorspace;
ClutterTransferFunction transfer_function;
} source;
struct {
ClutterColorspace colorspace;
ClutterTransferFunction transfer_function;
} target;
} SnippetCacheKey;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterColorState,
clutter_color_state,
G_TYPE_OBJECT)
static GQuark snippet_cache_quark;
static guint
snippet_cache_key_hash (gconstpointer key)
{
const SnippetCacheKey *cache_key = key;
return (cache_key->source.colorspace ^
cache_key->source.transfer_function ^
cache_key->target.colorspace ^
cache_key->target.transfer_function);
}
static gboolean
snippet_cache_key_equal (gconstpointer key1,
gconstpointer key2)
{
const SnippetCacheKey *cache_key1 = key1;
const SnippetCacheKey *cache_key2 = key2;
return (cache_key1->source.colorspace == cache_key2->source.colorspace &&
cache_key1->source.transfer_function == cache_key2->source.transfer_function &&
cache_key1->target.colorspace == cache_key2->target.colorspace &&
cache_key1->target.transfer_function == cache_key2->target.transfer_function);
}
static void
init_snippet_cache_key (SnippetCacheKey *cache_key,
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);
cache_key->source.colorspace = priv->colorspace;
cache_key->source.transfer_function = priv->transfer_function;
cache_key->target.colorspace = target_priv->colorspace;
cache_key->target.transfer_function = target_priv->transfer_function;
}
static GHashTable *
ensure_snippet_cache (ClutterColorState *color_state)
{
ClutterColorStatePrivate *priv =
clutter_color_state_get_instance_private (color_state);
GHashTable *snippet_cache;
snippet_cache = g_object_get_qdata (G_OBJECT (priv->context),
snippet_cache_quark);
if (snippet_cache)
return snippet_cache;
snippet_cache = g_hash_table_new_full (snippet_cache_key_hash,
snippet_cache_key_equal,
g_free,
g_object_unref);
g_object_set_qdata_full (G_OBJECT (priv->context),
snippet_cache_quark,
snippet_cache,
(GDestroyNotify) g_hash_table_unref);
return snippet_cache;
}
static const char *
clutter_colorspace_to_string (ClutterColorspace colorspace)
{
@ -267,6 +345,9 @@ clutter_color_state_class_init (ClutterColorStateClass *klass)
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
snippet_cache_quark =
g_quark_from_static_string ("clutter-color-state-snippet-cache");
}
static void
@ -656,6 +737,9 @@ CoglSnippet *
clutter_color_state_get_transform_snippet (ClutterColorState *color_state,
ClutterColorState *target_color_state)
{
GHashTable *snippet_cache;
SnippetCacheKey cache_key;
CoglSnippet *snippet;
const MatrixMultiplication *color_space_mapping = NULL;
const TransferFunction *pre_transfer_function = NULL;
const TransferFunction *denormalize_function = NULL;
@ -665,6 +749,12 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state,
g_return_val_if_fail (CLUTTER_IS_COLOR_STATE (target_color_state), NULL);
init_snippet_cache_key (&cache_key, color_state, target_color_state);
snippet_cache = ensure_snippet_cache (color_state);
snippet = g_hash_table_lookup (snippet_cache, &cache_key);
if (snippet)
return g_object_ref (snippet);
color_space_mapping = get_color_space_mapping_matrix (color_state,
target_color_state);
@ -742,7 +832,11 @@ clutter_color_state_get_transform_snippet (ClutterColorState *color_state,
g_string_append (snippet_source,
" cogl_color_out = vec4 (color_state_color, cogl_color_out.a);\n");
return cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
globals_source->str,
snippet_source->str);
g_hash_table_insert (snippet_cache,
g_memdup2 (&cache_key, sizeof (cache_key)),
g_object_ref (snippet));
return snippet;
}