clutter: Introduce color transform aware pipeline cache

Color aware rendering needs shaders / pipelines that adapt to what
output they render to. For example if we want to render to a linear
BT.2020 intermediate framebuffer on one monitor, and a non-linear sRGB
direct target buffer on another, the shader for the same paint node or
content will depend on where they are going to be presented.

In order to help keeping track of what shader should target what
monitor, without having to regenerate them each time, introduce a
pipeline cache that knows how to handle differentiating between
transforming between different color state.

The cache is meant to handle caches for multiple pipeline users, where
each user might potentially want to keep track of multiple pipelines
itself. Lookup should be O(1), and in order to achieve this, separate
the cache into 3 levels.

The first level is the "pipeline group", where e.g. a ClutterContent
type allocates a group where it can store its pipelines. Each group has
a fixed number of "slots" where it can store a pipeline. Each slot has a
hash table where the key is derived from a color state transform, and
where the value is a CoglPipeline where the thame color state
transformation is expected to be handled.

A content will when painting know about its own color state, and the
target state it should render into, retrieve a cached pipeline for the
correct transform, or if the cache didn't have it, generate it.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3433>
This commit is contained in:
Jonas Ådahl
2023-11-01 22:28:39 +08:00
committed by Sebastian Wick
parent 0c2fa8e9a8
commit 4238512764
10 changed files with 521 additions and 0 deletions

View File

@ -39,6 +39,7 @@ clutter_conform_tests_general_tests = [
'gesture',
'gesture-relationship',
'interval',
'pipeline-cache',
'timeline',
'timeline-interpolate',
'timeline-progress',

View File

@ -0,0 +1,208 @@
#include <stdlib.h>
#include <string.h>
#include <clutter/clutter.h>
#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)
)