diff --git a/clutter/clutter/clutter-context.c b/clutter/clutter/clutter-context.c
index 72e99c346..90f68ba1c 100644
--- a/clutter/clutter/clutter-context.c
+++ b/clutter/clutter/clutter-context.c
@@ -79,6 +79,8 @@ static const GDebugKey clutter_paint_debug_keys[] = {
typedef struct _ClutterContextPrivate
{
ClutterTextDirection text_direction;
+
+ ClutterPipelineCache *pipeline_cache;
} ClutterContextPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterContext, clutter_context, G_TYPE_OBJECT)
@@ -87,7 +89,9 @@ static void
clutter_context_dispose (GObject *object)
{
ClutterContext *context = CLUTTER_CONTEXT (object);
+ ClutterContextPrivate *priv = clutter_context_get_instance_private (context);
+ g_clear_object (&priv->pipeline_cache);
g_clear_pointer (&context->events_queue, g_async_queue_unref);
g_clear_pointer (&context->backend, clutter_backend_destroy);
@@ -252,8 +256,10 @@ clutter_context_new (ClutterContextFlags flags,
GError **error)
{
ClutterContext *context;
+ ClutterContextPrivate *priv;
context = g_object_new (CLUTTER_TYPE_CONTEXT, NULL);
+ priv = clutter_context_get_instance_private (context);
init_clutter_debug (context);
context->show_fps = clutter_show_fps;
@@ -268,6 +274,8 @@ clutter_context_new (ClutterContextFlags flags,
g_async_queue_new_full ((GDestroyNotify) clutter_event_free);
context->last_repaint_id = 1;
+ priv->pipeline_cache = g_object_new (CLUTTER_TYPE_PIPELINE_CACHE, NULL);
+
if (!clutter_context_init_real (context, flags, error))
return NULL;
@@ -317,3 +325,14 @@ clutter_context_get_text_direction (ClutterContext *context)
return priv->text_direction;
}
+
+/**
+ * clutter_context_get_pipeline_cache: (skip)
+ */
+ClutterPipelineCache *
+clutter_context_get_pipeline_cache (ClutterContext *context)
+{
+ ClutterContextPrivate *priv = clutter_context_get_instance_private (context);
+
+ return priv->pipeline_cache;
+}
diff --git a/clutter/clutter/clutter-context.h b/clutter/clutter/clutter-context.h
index 8bc2aa73a..d4be1f631 100644
--- a/clutter/clutter/clutter-context.h
+++ b/clutter/clutter/clutter-context.h
@@ -65,3 +65,6 @@ ClutterBackend * clutter_context_get_backend (ClutterContext *context);
CoglPangoFontMap * clutter_context_get_pango_fontmap (ClutterContext *context);
ClutterTextDirection clutter_context_get_text_direction (ClutterContext *context);
+
+CLUTTER_EXPORT
+ClutterPipelineCache * clutter_context_get_pipeline_cache (ClutterContext *clutter_context);
diff --git a/clutter/clutter/clutter-pipeline-cache.c b/clutter/clutter/clutter-pipeline-cache.c
new file mode 100644
index 000000000..74dc70c58
--- /dev/null
+++ b/clutter/clutter/clutter-pipeline-cache.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2023 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ */
+
+#include "config.h"
+
+#include "clutter-pipeline-cache.h"
+
+typedef struct _PipelineGroupEntry
+{
+ GHashTable **slots;
+ size_t n_slots;
+} PipelineGroupEntry;
+
+struct _ClutterPipelineCache
+{
+ GObject parent;
+
+ GHashTable *groups;
+};
+
+G_DEFINE_TYPE (ClutterPipelineCache, clutter_pipeline_cache, G_TYPE_OBJECT)
+
+static PipelineGroupEntry *
+pipeline_group_entry_new (void)
+{
+ PipelineGroupEntry *group_entry;
+
+ group_entry = g_new0 (PipelineGroupEntry, 1);
+
+ return group_entry;
+}
+
+static void
+pipeline_group_entry_free (PipelineGroupEntry *group_entry)
+{
+ size_t i;
+
+ for (i = 0; i < group_entry->n_slots; i++)
+ g_clear_pointer (&group_entry->slots[i], g_hash_table_unref);
+ g_free (group_entry->slots);
+ g_free (group_entry);
+}
+
+static void
+clutter_pipeline_cache_dispose (GObject *object)
+{
+ ClutterPipelineCache *pipeline_cache = CLUTTER_PIPELINE_CACHE (object);
+
+ g_clear_pointer (&pipeline_cache->groups, g_hash_table_unref);
+
+ G_OBJECT_CLASS (clutter_pipeline_cache_parent_class)->dispose (object);
+}
+
+static void
+clutter_pipeline_cache_class_init (ClutterPipelineCacheClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = clutter_pipeline_cache_dispose;
+}
+
+static void
+clutter_pipeline_cache_init (ClutterPipelineCache *pipeline_cache)
+{
+ pipeline_cache->groups =
+ g_hash_table_new_full (NULL,
+ NULL,
+ NULL,
+ (GDestroyNotify) pipeline_group_entry_free);
+}
+
+static uint32_t
+calculate_color_state_key (ClutterColorState *color_state)
+{
+ ClutterColorspace colorspace =
+ clutter_color_state_get_colorspace (color_state);
+ ClutterTransferFunction transfer_function =
+ clutter_color_state_get_transfer_function (color_state);
+
+ return (colorspace |
+ transfer_function << 8);
+}
+
+static uint64_t
+calculate_key (ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state)
+{
+ uint64_t source_key;
+ uint64_t target_key;
+
+ source_key = calculate_color_state_key (source_color_state);
+ target_key = calculate_color_state_key (target_color_state);
+
+ return (source_key |
+ target_key << 32);
+}
+
+/**
+ * clutter_pipeline_cache_get_pipeline: (skip)
+ */
+CoglPipeline *
+clutter_pipeline_cache_get_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state)
+{
+ PipelineGroupEntry *group_entry;
+ uint64_t key;
+
+ group_entry = g_hash_table_lookup (pipeline_cache->groups, group);
+ if (!group_entry)
+ return NULL;
+
+ if (slot >= group_entry->n_slots)
+ return NULL;
+
+ if (!group_entry->slots[slot])
+ return NULL;
+
+ key = calculate_key (source_color_state, target_color_state);
+ return g_hash_table_lookup (group_entry->slots[slot], &key);
+}
+
+/**
+ * clutter_pipeline_cache_sdd_pipeline: (skip)
+ */
+void
+clutter_pipeline_cache_set_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state,
+ CoglPipeline *pipeline)
+{
+ PipelineGroupEntry *group_entry;
+ uint64_t key;
+
+ group_entry = g_hash_table_lookup (pipeline_cache->groups, group);
+ if (!group_entry)
+ {
+ group_entry = pipeline_group_entry_new ();
+ g_hash_table_insert (pipeline_cache->groups, group, group_entry);
+ }
+
+ if (slot >= group_entry->n_slots)
+ {
+ size_t new_n_slots;
+
+ new_n_slots = slot + 1;
+ group_entry->slots = g_realloc_n (group_entry->slots,
+ new_n_slots,
+ sizeof (GHashTable *));
+ memset (group_entry->slots + group_entry->n_slots,
+ 0,
+ (new_n_slots - group_entry->n_slots) * sizeof (GHashTable *));
+ group_entry->n_slots = new_n_slots;
+ }
+
+ if (!group_entry->slots[slot])
+ {
+ group_entry->slots[slot] = g_hash_table_new_full (g_int64_hash,
+ g_int64_equal,
+ g_free,
+ g_object_unref);
+ }
+
+ key = calculate_key (source_color_state, target_color_state);
+ g_hash_table_replace (group_entry->slots[slot],
+ g_memdup2 (&key, sizeof (key)),
+ g_object_ref (pipeline));
+}
+
+/**
+ * clutter_pipeline_cache_unset_pipeline: (skip)
+ */
+void
+clutter_pipeline_cache_unset_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state)
+
+{
+ PipelineGroupEntry *group_entry;
+ uint64_t key;
+
+ group_entry = g_hash_table_lookup (pipeline_cache->groups, group);
+
+ if (!group_entry)
+ return;
+
+ if (slot >= group_entry->n_slots)
+ return;
+
+ if (!group_entry->slots[slot])
+ return;
+
+ key = calculate_key (source_color_state, target_color_state);
+ g_hash_table_remove (group_entry->slots[slot], &key);
+}
+
+/**
+ * clutter_pipeline_cache_unset_all_pipeline: (skip)
+ */
+void
+clutter_pipeline_cache_unset_all_pipelines (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group)
+{
+ g_hash_table_remove (pipeline_cache->groups, group);
+}
diff --git a/clutter/clutter/clutter-pipeline-cache.h b/clutter/clutter/clutter-pipeline-cache.h
new file mode 100644
index 000000000..bc4585211
--- /dev/null
+++ b/clutter/clutter/clutter-pipeline-cache.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ */
+
+#pragma once
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include "clutter/clutter-color-state.h"
+#include "cogl/cogl.h"
+
+typedef gpointer ClutterPipelineGroup;
+
+#define CLUTTER_TYPE_PIPELINE_CACHE (clutter_pipeline_cache_get_type ())
+CLUTTER_EXPORT
+G_DECLARE_FINAL_TYPE (ClutterPipelineCache, clutter_pipeline_cache,
+ CLUTTER, PIPELINE_CACHE, GObject)
+
+CLUTTER_EXPORT
+CoglPipeline * clutter_pipeline_cache_get_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state);
+
+CLUTTER_EXPORT
+void clutter_pipeline_cache_set_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state,
+ CoglPipeline *pipeline);
+
+CLUTTER_EXPORT
+void clutter_pipeline_cache_unset_pipeline (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group,
+ int slot,
+ ClutterColorState *source_color_state,
+ ClutterColorState *target_color_state);
+
+CLUTTER_EXPORT
+void clutter_pipeline_cache_unset_all_pipelines (ClutterPipelineCache *pipeline_cache,
+ ClutterPipelineGroup group);
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index 172fa8b22..48cfef25d 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -36,6 +36,7 @@
#include "clutter/clutter-effect.h"
#include "clutter/clutter-event.h"
#include "clutter/clutter-layout-manager.h"
+#include "clutter/clutter-pipeline-cache.h"
#include "clutter/clutter-settings.h"
#include "clutter/clutter-stage-manager.h"
#include "clutter/clutter-stage.h"
diff --git a/clutter/clutter/clutter-types.h b/clutter/clutter/clutter-types.h
index 211f1d2d6..7408d0d30 100644
--- a/clutter/clutter/clutter-types.h
+++ b/clutter/clutter/clutter-types.h
@@ -52,6 +52,7 @@ typedef struct _ClutterLayoutManager ClutterLayoutManager;
typedef struct _ClutterActorIter ClutterActorIter;
typedef struct _ClutterPaintContext ClutterPaintContext;
typedef struct _ClutterPaintNode ClutterPaintNode;
+typedef struct _ClutterPipelineCache ClutterPipelineCache;
typedef struct _ClutterContent ClutterContent; /* dummy */
typedef struct _ClutterScrollActor ClutterScrollActor;
typedef struct _ClutterFrameClock ClutterFrameClock;
diff --git a/clutter/clutter/clutter.h b/clutter/clutter/clutter.h
index 360333a6c..109358540 100644
--- a/clutter/clutter/clutter.h
+++ b/clutter/clutter/clutter.h
@@ -80,6 +80,7 @@
#include "clutter/clutter-paint-nodes.h"
#include "clutter/clutter-paint-node.h"
#include "clutter/clutter-pan-action.h"
+#include "clutter/clutter-pipeline-cache.h"
#include "clutter/clutter-property-transition.h"
#include "clutter/clutter-rotate-action.h"
#include "clutter/clutter-scroll-actor.h"
diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build
index 190499930..22af0b2b1 100644
--- a/clutter/clutter/meson.build
+++ b/clutter/clutter/meson.build
@@ -58,6 +58,7 @@ clutter_headers = [
'clutter-paint-node.h',
'clutter-pan-action.h',
'clutter-pick-context.h',
+ 'clutter-pipeline-cache.h',
'clutter-property-transition.h',
'clutter-rotate-action.h',
'clutter-scroll-actor.h',
@@ -144,6 +145,7 @@ clutter_sources = [
'clutter-pan-action.c',
'clutter-pick-context.c',
'clutter-pick-stack.c',
+ 'clutter-pipeline-cache.c',
'clutter-property-transition.c',
'clutter-rotate-action.c',
'clutter-scroll-actor.c',
diff --git a/src/tests/clutter/conform/meson.build b/src/tests/clutter/conform/meson.build
index 019c1f223..adcd3b095 100644
--- a/src/tests/clutter/conform/meson.build
+++ b/src/tests/clutter/conform/meson.build
@@ -39,6 +39,7 @@ clutter_conform_tests_general_tests = [
'gesture',
'gesture-relationship',
'interval',
+ 'pipeline-cache',
'timeline',
'timeline-interpolate',
'timeline-progress',
diff --git a/src/tests/clutter/conform/pipeline-cache.c b/src/tests/clutter/conform/pipeline-cache.c
new file mode 100644
index 000000000..2e53391f4
--- /dev/null
+++ b/src/tests/clutter/conform/pipeline-cache.c
@@ -0,0 +1,208 @@
+#include
+#include
+
+#include
+
+#include "tests/clutter-test-utils.h"
+
+static void
+take_snippet (CoglPipeline *pipeline,
+ CoglSnippet *snippet)
+{
+ cogl_pipeline_add_snippet (pipeline, snippet);
+ g_object_unref (snippet);
+}
+
+static void
+pipeline_cache_group_pipelines (void)
+{
+ ClutterContext *context = clutter_test_get_context ();
+ ClutterBackend *backend = clutter_test_get_backend ();
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
+ ClutterPipelineCache *pipeline_cache = clutter_context_get_pipeline_cache (context);
+ static ClutterPipelineGroup group1 = &group1;
+ static ClutterPipelineGroup group2 = &group2;
+ ClutterColorState *srgb_srgb;
+ ClutterColorState *srgb_linear;
+ ClutterColorState *bt2020_pq;
+ ClutterColorState *bt2020_linear;
+ /* SDR content with HDR output */
+ CoglPipeline *srgb_srgb_to_bt2020_linear;
+ CoglPipeline *bt2020_linear_to_bt2020_pq;
+ /* HDR content with HDR output */
+ CoglPipeline *bt2020_pq_to_bt2020_linear;
+ CoglPipeline *srgb_linear_to_srgb_srgb;
+ /* Copy for group2 */
+ CoglPipeline *srgb_srgb_to_bt2020_linear_copy;
+
+ srgb_srgb = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_SRGB,
+ CLUTTER_TRANSFER_FUNCTION_SRGB);
+ srgb_linear = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_SRGB,
+ CLUTTER_TRANSFER_FUNCTION_LINEAR);
+ bt2020_pq = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_BT2020,
+ CLUTTER_TRANSFER_FUNCTION_PQ);
+ bt2020_linear = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_BT2020,
+ CLUTTER_TRANSFER_FUNCTION_LINEAR);
+
+ srgb_srgb_to_bt2020_linear = cogl_pipeline_new (cogl_context);
+ bt2020_linear_to_bt2020_pq = cogl_pipeline_new (cogl_context);
+ bt2020_pq_to_bt2020_linear = cogl_pipeline_new (cogl_context);
+ srgb_linear_to_srgb_srgb = cogl_pipeline_new (cogl_context);
+
+ take_snippet (srgb_srgb_to_bt2020_linear,
+ clutter_color_state_get_transform_snippet (srgb_srgb,
+ bt2020_linear));
+ take_snippet (bt2020_linear_to_bt2020_pq,
+ clutter_color_state_get_transform_snippet (bt2020_linear,
+ bt2020_pq));
+ take_snippet (bt2020_pq_to_bt2020_linear,
+ clutter_color_state_get_transform_snippet (bt2020_pq,
+ bt2020_linear));
+ take_snippet (srgb_linear_to_srgb_srgb,
+ clutter_color_state_get_transform_snippet (srgb_linear,
+ srgb_srgb));
+
+ /* Check that it's all empty. */
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group1, 0,
+ srgb_srgb, bt2020_linear));
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group1, 0,
+ bt2020_linear, bt2020_pq));
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group2, 0,
+ srgb_srgb, bt2020_linear));
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group2, 0,
+ bt2020_linear, bt2020_pq));
+
+ /* Adding sRGB to HDR pipeline to group1 should not effect group2. */
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group1, 0,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear);
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group1, 0,
+ bt2020_linear, bt2020_pq,
+ bt2020_linear_to_bt2020_pq);
+
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group1, 0,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear);
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group1, 0,
+ bt2020_linear, bt2020_pq) ==
+ bt2020_linear_to_bt2020_pq);
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group2, 0,
+ srgb_srgb, bt2020_linear));
+ g_assert_null (clutter_pipeline_cache_get_pipeline (pipeline_cache, group2, 0,
+ bt2020_linear, bt2020_pq));
+
+ srgb_srgb_to_bt2020_linear_copy =
+ cogl_pipeline_copy (srgb_srgb_to_bt2020_linear);
+ g_assert_true (srgb_srgb_to_bt2020_linear_copy !=
+ srgb_srgb_to_bt2020_linear);
+
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group2, 0,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear_copy);
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group1, 0,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear);
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group2, 0,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear_copy);
+}
+
+static void
+pipeline_cache_replace_pipeline (void)
+{
+ ClutterContext *context = clutter_test_get_context ();
+ ClutterBackend *backend = clutter_test_get_backend ();
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
+ ClutterPipelineCache *pipeline_cache = clutter_context_get_pipeline_cache (context);
+ static ClutterPipelineGroup group = &group;
+ ClutterColorState *srgb_srgb;
+ ClutterColorState *bt2020_linear;
+ CoglPipeline *srgb_srgb_to_bt2020_linear;
+ CoglPipeline *srgb_srgb_to_bt2020_linear_copy;
+
+ srgb_srgb = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_SRGB,
+ CLUTTER_TRANSFER_FUNCTION_SRGB);
+ bt2020_linear = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_BT2020,
+ CLUTTER_TRANSFER_FUNCTION_PQ);
+
+ srgb_srgb_to_bt2020_linear = cogl_pipeline_new (cogl_context);
+ srgb_srgb_to_bt2020_linear_copy =
+ cogl_pipeline_copy (srgb_srgb_to_bt2020_linear);
+
+ g_object_add_weak_pointer (G_OBJECT (srgb_srgb_to_bt2020_linear),
+ (gpointer *) &srgb_srgb_to_bt2020_linear);
+
+ take_snippet (srgb_srgb_to_bt2020_linear,
+ clutter_color_state_get_transform_snippet (srgb_srgb,
+ bt2020_linear));
+
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group, 0,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear);
+
+ g_object_unref (srgb_srgb_to_bt2020_linear);
+ g_assert_nonnull (srgb_srgb_to_bt2020_linear);
+
+ take_snippet (srgb_srgb_to_bt2020_linear_copy,
+ clutter_color_state_get_transform_snippet (srgb_srgb,
+ bt2020_linear));
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group, 0,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear_copy);
+ g_assert_null (srgb_srgb_to_bt2020_linear);
+
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group, 0,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear_copy);
+}
+
+static void
+pipeline_slots (void)
+{
+ ClutterContext *context = clutter_test_get_context ();
+ ClutterBackend *backend = clutter_test_get_backend ();
+ CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
+ ClutterPipelineCache *pipeline_cache = clutter_context_get_pipeline_cache (context);
+ static ClutterPipelineGroup group = &group;
+ ClutterColorState *srgb_srgb;
+ ClutterColorState *bt2020_linear;
+ CoglPipeline *srgb_srgb_to_bt2020_linear;
+ CoglPipeline *srgb_srgb_to_bt2020_linear_copy;
+
+ srgb_srgb = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_SRGB,
+ CLUTTER_TRANSFER_FUNCTION_SRGB);
+ bt2020_linear = clutter_color_state_new (context,
+ CLUTTER_COLORSPACE_BT2020,
+ CLUTTER_TRANSFER_FUNCTION_PQ);
+
+ srgb_srgb_to_bt2020_linear = cogl_pipeline_new (cogl_context);
+ srgb_srgb_to_bt2020_linear_copy =
+ cogl_pipeline_copy (srgb_srgb_to_bt2020_linear);
+
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group, 0,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear);
+ clutter_pipeline_cache_set_pipeline (pipeline_cache, group, 1,
+ srgb_srgb, bt2020_linear,
+ srgb_srgb_to_bt2020_linear_copy);
+
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group, 0,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear);
+ g_assert_true (clutter_pipeline_cache_get_pipeline (pipeline_cache, group, 1,
+ srgb_srgb, bt2020_linear) ==
+ srgb_srgb_to_bt2020_linear_copy);
+}
+
+CLUTTER_TEST_SUITE (
+ CLUTTER_TEST_UNIT ("/pipeline-cache/group-pipelines", pipeline_cache_group_pipelines)
+ CLUTTER_TEST_UNIT ("/pipeline-cache/replace-pipeline", pipeline_cache_replace_pipeline)
+ CLUTTER_TEST_UNIT ("/pipeline-cache/pipeline-slots", pipeline_slots)
+)