From 09c2e4abe796e5f4cc5b164a3770be754099d9ff Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 25 Nov 2011 20:54:14 +0000 Subject: [PATCH] snippet: Move the hook to be a property of the snippet Instead of specifying the hook point when adding to the pipeline using a separate function for each hook, the hook is now a property of the snippet. The hook is set on construction and is then read-only. Reviewed-by: Robert Bragg --- cogl/cogl-pipeline-fragend-glsl.c | 4 +- cogl/cogl-pipeline-layer-state.c | 27 ++--- cogl/cogl-pipeline-layer-state.h | 44 +++----- cogl/cogl-pipeline-snippet-private.h | 15 +-- cogl/cogl-pipeline-snippet.c | 9 +- cogl/cogl-pipeline-state.c | 34 ++---- cogl/cogl-pipeline-state.h | 67 ++---------- cogl/cogl-pipeline-vertend-glsl.c | 2 +- cogl/cogl-snippet-private.h | 16 +++ cogl/cogl-snippet.c | 13 ++- cogl/cogl-snippet.h | 151 ++++++++++++++++++++++++++- tests/conform/test-snippets.c | 62 +++++++---- 12 files changed, 270 insertions(+), 174 deletions(-) diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c index 1a3413594..d23541b97 100644 --- a/cogl/cogl-pipeline-fragend-glsl.c +++ b/cogl/cogl-pipeline-fragend-glsl.c @@ -481,7 +481,7 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, /* Wrap the texture lookup in any snippets that have been hooked */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_layer_fragment_snippets (layer); - snippet_data.hook = COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP; + snippet_data.hook = COGL_SNIPPET_HOOK_TEXTURE_LOOKUP; snippet_data.chain_function = g_strdup_printf ("cogl_real_texture_lookup%i", unit_index); snippet_data.final_name = g_strdup_printf ("cogl_texture_lookup%i", @@ -977,7 +977,7 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline, /* Add all of the hooks for fragment processing */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_fragment_snippets (pipeline); - snippet_data.hook = COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT; + snippet_data.hook = COGL_SNIPPET_HOOK_FRAGMENT; snippet_data.chain_function = "cogl_generated_source"; snippet_data.final_name = "main"; snippet_data.function_prefix = "cogl_fragment_hook"; diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c index 8df86fcad..1523d3644 100644 --- a/cogl/cogl-pipeline-layer-state.c +++ b/cogl/cogl-pipeline-layer-state.c @@ -34,6 +34,7 @@ #include "cogl-blend-string.h" #include "cogl-util.h" #include "cogl-matrix.h" +#include "cogl-snippet-private.h" #include "string.h" #if 0 @@ -777,14 +778,11 @@ cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, static void _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline, int layer_index, - CoglPipelineSnippetHook hook, CoglSnippet *snippet) { CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; CoglPipelineLayer *layer, *authority; - _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); - /* Note: this will ensure that the layer exists, creating one if it * doesn't already. * @@ -800,7 +798,6 @@ _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline, layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change); _cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets, - hook, snippet); /* If we weren't previously the authority on this state then we need @@ -815,15 +812,21 @@ _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline, } void -cogl_pipeline_add_texture_lookup_hook (CoglPipeline *pipeline, - int layer_index, - CoglSnippet *snippet) +cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline, + int layer_index, + CoglSnippet *snippet) { - CoglPipelineSnippetHook hook = COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP; - _cogl_pipeline_layer_add_fragment_snippet (pipeline, - layer_index, - hook, - snippet); + _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline)); + _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); + _COGL_RETURN_IF_FAIL (snippet->hook >= COGL_SNIPPET_FIRST_LAYER_HOOK); + + if (snippet->hook < COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK) + /* TODO */ + g_assert_not_reached (); + else + _cogl_pipeline_layer_add_fragment_snippet (pipeline, + layer_index, + snippet); } gboolean diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h index 7d6965b26..a4ad16b22 100644 --- a/cogl/cogl-pipeline-layer-state.h +++ b/cogl/cogl-pipeline-layer-state.h @@ -497,46 +497,26 @@ cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); +#define cogl_pipeline_add_layer_snippet cogl_pipeline_add_layer_snippet_EXP /** - * cogl_pipeline_add_texture_lookup_hook: + * cogl_pipeline_add_layer_snippet: * @pipeline: A #CoglPipeline - * @layer: The layer whose texutre lookup should be hooked - * @snippet: The #CoglSnippet to add to the texture lookup for @layer + * @layer: The layer to hook the snippet to + * @snippet: A #CoglSnippet * - * Adds a shader snippet that will hook on to the texture lookup part - * of a given layer. This gives a chance for the application to modify - * the coordinates that will be used for the texture lookup or to - * alter the returned texel. - * - * Within the snippet code for this hook there are two extra variables - * available. ‘cogl_tex_coord’ is a vec4 which contains the texture - * coordinates that will be used for the texture lookup this can be - * modified. ‘cogl_texel’ will contain the result of the texture - * lookup. This can be modified. - * - * The ‘declarations’ string in @snippet will be inserted in the - * global scope of the shader. Use this to declare any uniforms, - * attributes or functions that the snippet requires. - * - * The ‘pre’ string in @snippet will be inserted at the top of the - * main() function before any fragment processing is done. This is a - * good place to modify the cogl_tex_coord variable. - * - * If a ‘replace’ string is given then this will be used instead of a - * the default texture lookup. The snippet would typically use its own - * sampler in this case. - * - * The ‘post’ string in @snippet will be inserted after texture lookup - * has been preformed. Here the snippet can modify the cogl_texel - * variable to alter the returned texel. + * Adds a shader snippet that will hook on to the given layer of the + * pipeline. The exact part of the pipeline that the snippet wraps + * around depends on the hook that is given to + * cogl_snippet_new(). Note that some hooks can't be used with a layer + * and need to be added with cogl_pipeline_add_snippet() instead. * * Since: 1.10 * Stability: Unstable */ void -cogl_pipeline_add_texture_lookup_hook (CoglPipeline *pipeline, - int layer_index, - CoglSnippet *snippet); +cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline, + int layer, + CoglSnippet *snippet); #endif /* COGL_ENABLE_EXPERIMENTAL_API */ diff --git a/cogl/cogl-pipeline-snippet-private.h b/cogl/cogl-pipeline-snippet-private.h index 0df497264..24ff610bc 100644 --- a/cogl/cogl-pipeline-snippet-private.h +++ b/cogl/cogl-pipeline-snippet-private.h @@ -31,15 +31,6 @@ #include "cogl-snippet.h" #include "cogl-queue.h" -/* Enumeration of all the hook points that a snippet can be attached - to within a pipeline. */ -typedef enum -{ - COGL_PIPELINE_SNIPPET_HOOK_VERTEX, - COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT, - COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP -} CoglPipelineSnippetHook; - typedef struct _CoglPipelineSnippet CoglPipelineSnippet; COGL_LIST_HEAD (CoglPipelineSnippetList, CoglPipelineSnippet); @@ -48,9 +39,6 @@ struct _CoglPipelineSnippet { COGL_LIST_ENTRY (CoglPipelineSnippet) list_node; - /* Hook where this snippet is attached */ - CoglPipelineSnippetHook hook; - CoglSnippet *snippet; }; @@ -60,7 +48,7 @@ typedef struct CoglPipelineSnippetList *snippets; /* Only snippets at this hook point will be used */ - CoglPipelineSnippetHook hook; + CoglSnippetHook hook; /* The final function to chain on to after all of the snippets code has been run */ @@ -98,7 +86,6 @@ _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list); void _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, - CoglPipelineSnippetHook hook, CoglSnippet *snippet); void diff --git a/cogl/cogl-pipeline-snippet.c b/cogl/cogl-pipeline-snippet.c index bb57abd6c..794e163c5 100644 --- a/cogl/cogl-pipeline-snippet.c +++ b/cogl/cogl-pipeline-snippet.c @@ -44,7 +44,7 @@ _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data) int snippet_num = 0; COGL_LIST_FOREACH (snippet, data->snippets, list_node) - if (snippet->hook == data->hook) + if (snippet->snippet->hook == data->hook) { const char *source; @@ -179,12 +179,10 @@ _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list) void _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, - CoglPipelineSnippetHook hook, CoglSnippet *snippet) { CoglPipelineSnippet *pipeline_snippet = g_slice_new (CoglPipelineSnippet); - pipeline_snippet->hook = hook; pipeline_snippet->snippet = cogl_object_ref (snippet); _cogl_snippet_make_immutable (pipeline_snippet->snippet); @@ -235,9 +233,6 @@ _cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, COGL_LIST_FOREACH (l, list, list_node) { - *hash = _cogl_util_one_at_a_time_hash (*hash, - &l->hook, - sizeof (CoglPipelineSnippetHook)); *hash = _cogl_util_one_at_a_time_hash (*hash, &l->snippet, sizeof (CoglSnippet *)); @@ -253,7 +248,7 @@ _cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, for (l0 = COGL_LIST_FIRST (list0), l1 = COGL_LIST_FIRST (list1); l0 && l1; l0 = COGL_LIST_NEXT (l0, list_node), l1 = COGL_LIST_NEXT (l1, list_node)) - if (l0->hook != l1->hook || l0->snippet != l1->snippet) + if (l0->snippet != l1->snippet) return FALSE; return l0 == NULL && l1 == NULL; diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c index 3477820c8..44384ed5c 100644 --- a/cogl/cogl-pipeline-state.c +++ b/cogl/cogl-pipeline-state.c @@ -1571,14 +1571,10 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, static void _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, - CoglPipelineSnippetHook hook, CoglSnippet *snippet) { CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS; - g_return_if_fail (cogl_is_pipeline (pipeline)); - g_return_if_fail (cogl_is_snippet (snippet)); - /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being @@ -1587,29 +1583,15 @@ _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); _cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets, - hook, snippet); } -void -cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline, - CoglSnippet *snippet) -{ - _cogl_pipeline_add_vertex_snippet (pipeline, - COGL_PIPELINE_SNIPPET_HOOK_VERTEX, - snippet); -} - static void _cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline, - CoglPipelineSnippetHook hook, CoglSnippet *snippet) { CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS; - g_return_if_fail (cogl_is_pipeline (pipeline)); - g_return_if_fail (cogl_is_snippet (snippet)); - /* - Flush journal primitives referencing the current state. * - Make sure the pipeline has no dependants so it may be modified. * - If the pipeline isn't currently an authority for the state being @@ -1618,17 +1600,21 @@ _cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline, _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); _cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets, - hook, snippet); } void -cogl_pipeline_add_fragment_hook (CoglPipeline *pipeline, - CoglSnippet *snippet) +cogl_pipeline_add_snippet (CoglPipeline *pipeline, + CoglSnippet *snippet) { - _cogl_pipeline_add_fragment_snippet (pipeline, - COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT, - snippet); + g_return_if_fail (cogl_is_pipeline (pipeline)); + g_return_if_fail (cogl_is_snippet (snippet)); + g_return_if_fail (snippet->hook < COGL_SNIPPET_FIRST_LAYER_HOOK); + + if (snippet->hook < COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK) + _cogl_pipeline_add_vertex_snippet (pipeline, snippet); + else + _cogl_pipeline_add_fragment_snippet (pipeline, snippet); } gboolean diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h index 027287628..b3500bf3f 100644 --- a/cogl/cogl-pipeline-state.h +++ b/cogl/cogl-pipeline-state.h @@ -937,73 +937,24 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, gboolean transpose, const float *value); +#define cogl_pipeline_add_snippet cogl_pipeline_add_snippet_EXP /** - * cogl_pipeline_add_vertex_hook: + * cogl_pipeline_add_snippet: * @pipeline: A #CoglPipeline * @snippet: The #CoglSnippet to add to the vertex processing hook * - * Adds a shader snippet that will hook on to the vertex processing - * stage of @pipeline. This gives a chance for the application to - * modify the vertex attributes generated by the shader. Typically the - * snippet will modify cogl_color_out or cogl_position_out builtins. - * - * The ‘declarations’ string in @snippet will be inserted in the - * global scope of the shader. Use this to declare any uniforms, - * attributes or functions that the snippet requires. - * - * The ‘pre’ string in @snippet will be inserted at the top of the - * main() function before any vertex processing is done. - * - * The ‘replace’ string in @snippet will be used instead of the - * generated vertex processing if it is present. This can be used if - * the application wants to provide a complete vertex shader and - * doesn't need the generated output from Cogl. - * - * The ‘post’ string in @snippet will be inserted after all of the - * standard vertex processing is done. This can be used to modify the - * outputs. + * Adds a shader snippet that to @pipeline. The snippet will wrap + * around or replace some part of the pipeline as defined by the hook + * point in @snippet. Note that some hook points are specific to a + * layer and must be added with cogl_pipeline_add_layer_snippet() + * instead. * * Since: 1.10 * Stability: Unstable */ void -cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline, - CoglSnippet *snippet); - -/** - * cogl_pipeline_add_fragment_hook: - * @pipeline: A #CoglPipeline - * @snippet: The #CoglSnippet to add to the fragment processing hook - * - * Adds a shader snippet that will hook on to the fragment processing - * stage of @pipeline. This gives a chance for the application to - * modify the fragment color generated by the shader. Typically the - * snippet will modify cogl_color_out. - * - * The ‘declarations’ string in @snippet will be inserted in the - * global scope of the shader. Use this to declare any uniforms, - * attributes or functions that the snippet requires. - * - * The ‘pre’ string in @snippet will be inserted at the top of the - * main() function before any fragment processing is done. - * - * The ‘replace’ string in @snippet will be used instead of the - * generated fragment processing if it is present. This can be used if - * the application wants to provide a complete fragment shader and - * doesn't need the generated output from Cogl. - * - * The ‘post’ string in @snippet will be inserted after all of the - * standard fragment processing is done. At this point the generated - * value for the rest of the pipeline state will already be in - * cogl_color_out so the application can modify the result by altering - * this variable. - * - * Since: 1.10 - * Stability: Unstable - */ -void -cogl_pipeline_add_fragment_hook (CoglPipeline *pipeline, - CoglSnippet *snippet); +cogl_pipeline_add_snippet (CoglPipeline *pipeline, + CoglSnippet *snippet); #endif /* COGL_ENABLE_EXPERIMENTAL_API */ diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c index 64b4737bb..a6f04ca6d 100644 --- a/cogl/cogl-pipeline-vertend-glsl.c +++ b/cogl/cogl-pipeline-vertend-glsl.c @@ -381,7 +381,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline, /* Add all of the hooks for vertex processing */ memset (&snippet_data, 0, sizeof (snippet_data)); snippet_data.snippets = get_vertex_snippets (pipeline); - snippet_data.hook = COGL_PIPELINE_SNIPPET_HOOK_VERTEX; + snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX; snippet_data.chain_function = "cogl_generated_source"; snippet_data.final_name = "main"; snippet_data.function_prefix = "cogl_vertex_hook"; diff --git a/cogl/cogl-snippet-private.h b/cogl/cogl-snippet-private.h index bcc6abe0a..519738b0e 100644 --- a/cogl/cogl-snippet-private.h +++ b/cogl/cogl-snippet-private.h @@ -33,10 +33,26 @@ #include "cogl-snippet.h" #include "cogl-object-private.h" +/* These values are also used in the enum for CoglSnippetHook. They + are copied here because we don't really want these names to be part + of the public API */ +#define COGL_SNIPPET_HOOK_BAND_SIZE 2048 +#define COGL_SNIPPET_FIRST_PIPELINE_HOOK 0 +#define COGL_SNIPPET_FIRST_PIPELINE_VERTEX_HOOK \ + COGL_SNIPPET_FIRST_PIPELINE_HOOK +#define COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK \ + (COGL_SNIPPET_FIRST_PIPELINE_VERTEX_HOOK + COGL_SNIPPET_HOOK_BAND_SIZE) +#define COGL_SNIPPET_FIRST_LAYER_HOOK (COGL_SNIPPET_HOOK_BAND_SIZE * 2) +#define COGL_SNIPPET_FIRST_LAYER_VERTEX_HOOK COGL_SNIPPET_FIRST_LAYER_HOOK +#define COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK \ + (COGL_SNIPPET_FIRST_LAYER_VERTEX_HOOK + COGL_SNIPPET_HOOK_BAND_SIZE) + struct _CoglSnippet { CoglObject _parent; + CoglSnippetHook hook; + /* This is set to TRUE the first time the snippet is attached to the pipeline. After that any attempts to modify the snippet will be ignored. */ diff --git a/cogl/cogl-snippet.c b/cogl/cogl-snippet.c index d3a066f15..0af6473eb 100644 --- a/cogl/cogl-snippet.c +++ b/cogl/cogl-snippet.c @@ -38,19 +38,30 @@ _cogl_snippet_free (CoglSnippet *snippet); COGL_OBJECT_DEFINE (Snippet, snippet); CoglSnippet * -cogl_snippet_new (const char *declarations, +cogl_snippet_new (CoglSnippetHook hook, + const char *declarations, const char *post) { CoglSnippet *snippet = g_slice_new0 (CoglSnippet); _cogl_snippet_object_new (snippet); + snippet->hook = hook; + cogl_snippet_set_declarations (snippet, declarations); cogl_snippet_set_post (snippet, post); return snippet; } +CoglSnippetHook +cogl_snippet_get_hook (CoglSnippet *snippet) +{ + _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), 0); + + return snippet->hook; +} + static gboolean _cogl_snippet_modify (CoglSnippet *snippet) { diff --git a/cogl/cogl-snippet.h b/cogl/cogl-snippet.h index 260aed916..81817d76a 100644 --- a/cogl/cogl-snippet.h +++ b/cogl/cogl-snippet.h @@ -46,9 +46,146 @@ typedef struct _CoglSnippet CoglSnippet; #define COGL_SNIPPET(OBJECT) ((CoglSnippet *)OBJECT) +/* Enumeration of all the hook points that a snippet can be attached + to within a pipeline. */ +/** + * CoglSnippetHook: + * @COGL_SNIPPET_HOOK_VERTEX: A hook for the entire vertex processing + * stage of the pipeline. + * @COGL_SNIPPET_HOOK_FRAGMENT: A hook for the entire fragment + * processing stage of the pipeline. + * @COGL_SNIPPET_HOOK_TEXTURE_LOOKUP: A hook for the texture lookup + * stage of a given layer in a pipeline. + * + * #CoglSnippetHook is used to specify a location within a + * #CoglPipeline where the code of the snippet should be used when it + * is attached to a pipeline. + * + * + * + * %COGL_SNIPPET_HOOK_VERTEX + * + * + * Adds a shader snippet that will hook on to the vertex processing + * stage of the pipeline. This gives a chance for the application to + * modify the vertex attributes generated by the shader. Typically the + * snippet will modify cogl_color_out or cogl_position_out builtins. + * + * + * The ‘declarations’ string in @snippet will be inserted in the + * global scope of the shader. Use this to declare any uniforms, + * attributes or functions that the snippet requires. + * + * + * The ‘pre’ string in @snippet will be inserted at the top of the + * main() function before any vertex processing is done. + * + * + * The ‘replace’ string in @snippet will be used instead of the + * generated vertex processing if it is present. This can be used if + * the application wants to provide a complete vertex shader and + * doesn't need the generated output from Cogl. + * + * + * The ‘post’ string in @snippet will be inserted after all of the + * standard vertex processing is done. This can be used to modify the + * outputs. + * + * + * + * + * %COGL_SNIPPET_HOOK_FRAGMENT + * + * + * Adds a shader snippet that will hook on to the fragment processing + * stage of the pipeline. This gives a chance for the application to + * modify the fragment color generated by the shader. Typically the + * snippet will modify cogl_color_out. + * + * + * The ‘declarations’ string in @snippet will be inserted in the + * global scope of the shader. Use this to declare any uniforms, + * attributes or functions that the snippet requires. + * + * + * The ‘pre’ string in @snippet will be inserted at the top of the + * main() function before any fragment processing is done. + * + * + * The ‘replace’ string in @snippet will be used instead of the + * generated fragment processing if it is present. This can be used if + * the application wants to provide a complete fragment shader and + * doesn't need the generated output from Cogl. + * + * + * The ‘post’ string in @snippet will be inserted after all of the + * standard fragment processing is done. At this point the generated + * value for the rest of the pipeline state will already be in + * cogl_color_out so the application can modify the result by altering + * this variable. + * + * + * + * + * %COGL_SNIPPET_HOOK_TEXTURE_LOOKUP + * Adds a shader snippet that will hook on to the texture lookup part + * of a given layer. This gives a chance for the application to modify + * the coordinates that will be used for the texture lookup or to + * alter the returned texel. + * + * + * Within the snippet code for this hook there are two extra variables + * available. ‘cogl_tex_coord’ is a vec4 which contains the texture + * coordinates that will be used for the texture lookup this can be + * modified. ‘cogl_texel’ will contain the result of the texture + * lookup. This can be modified. + * + * + * The ‘declarations’ string in @snippet will be inserted in the + * global scope of the shader. Use this to declare any uniforms, + * attributes or functions that the snippet requires. + * + * + * The ‘pre’ string in @snippet will be inserted at the top of the + * main() function before any fragment processing is done. This is a + * good place to modify the cogl_tex_coord variable. + * + * + * If a ‘replace’ string is given then this will be used instead of a + * the default texture lookup. The snippet would typically use its own + * sampler in this case. + * + * + * The ‘post’ string in @snippet will be inserted after texture lookup + * has been preformed. Here the snippet can modify the cogl_texel + * variable to alter the returned texel. + * + * + * + * + * Since: 1.10 + * Stability: Unstable + */ +typedef enum { + /* Per pipeline vertex hooks */ + COGL_SNIPPET_HOOK_VERTEX = 0, + + /* Per pipeline fragment hooks */ + COGL_SNIPPET_HOOK_FRAGMENT = 2048, + + /* Per layer vertex hooks */ + /* TODO */ + /* ... = 4096 */ + + /* Per layer fragment hooks */ + COGL_SNIPPET_HOOK_TEXTURE_LOOKUP = 6144 +} CoglSnippetHook; + #define cogl_snippet_new cogl_snippet_new_EXP /** * cogl_snippet_new: + * @hook: The point in the pipeline that this snippet will wrap around + * or replace. * @declarations: The source code for the declarations for this * snippet or %NULL. See cogl_snippet_set_declarations(). * @post: The source code to run after the hook point where this @@ -62,9 +199,21 @@ typedef struct _CoglSnippet CoglSnippet; * Stability: Unstable */ CoglSnippet * -cogl_snippet_new (const char *declarations, +cogl_snippet_new (CoglSnippetHook hook, + const char *declarations, const char *post); +#define cogl_snippet_get_hook cogl_snipet_get_hook_EXP +/** + * cogl_snippet_get_hook: + * @snippet: A #CoglSnippet + * + * Return value: the hook that was set when cogl_snippet_new() was + * called. + */ +CoglSnippetHook +cogl_snippet_get_hook (CoglSnippet *snippet); + #define cogl_is_snippet cogl_is_snippet_EXP /** * cogl_is_snippet: diff --git a/tests/conform/test-snippets.c b/tests/conform/test-snippets.c index 2d96a9928..b53aeca4b 100644 --- a/tests/conform/test-snippets.c +++ b/tests/conform/test-snippets.c @@ -57,8 +57,10 @@ paint (TestState *state) cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); - snippet = cogl_snippet_new (NULL, "cogl_color_out.g += 1.0;"); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, + NULL, /* declarations */ + "cogl_color_out.g += 1.0;"); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_push_source (pipeline); @@ -72,8 +74,10 @@ paint (TestState *state) cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); - snippet = cogl_snippet_new (NULL, "cogl_color_out.b += 1.0;"); - cogl_pipeline_add_vertex_hook (pipeline, snippet); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, + NULL, + "cogl_color_out.b += 1.0;"); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_push_source (pipeline); @@ -82,8 +86,8 @@ paint (TestState *state) cogl_object_unref (pipeline); - /* Single snippet used with in both the vertex and fragment hooks - with a uniform */ + /* Snippets sharing a uniform across the vertex and fragment + hooks */ pipeline = cogl_pipeline_new (); location = cogl_pipeline_get_uniform_location (pipeline, "a_value"); @@ -91,10 +95,15 @@ paint (TestState *state) cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); - snippet = cogl_snippet_new ("uniform float a_value;", + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, + "uniform float a_value;", "cogl_color_out.b += a_value;"); - cogl_pipeline_add_fragment_hook (pipeline, snippet); - cogl_pipeline_add_vertex_hook (pipeline, snippet); + cogl_pipeline_add_snippet (pipeline, snippet); + cogl_object_unref (snippet); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, + "uniform float a_value;", + "cogl_color_out.b += a_value;"); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_push_source (pipeline); @@ -121,8 +130,10 @@ paint (TestState *state) location = cogl_pipeline_get_uniform_location (pipeline, uniform_name); cogl_pipeline_set_uniform_1f (pipeline, location, (i + 1) * 0.1f); - snippet = cogl_snippet_new (declarations, code); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, + declarations, + code); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); g_free (code); @@ -142,10 +153,11 @@ paint (TestState *state) cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255); - snippet = cogl_snippet_new (NULL, "cogl_color_out = redvec;"); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, + NULL, /* declarations */ + "cogl_color_out = redvec;"); cogl_snippet_set_pre (snippet, "vec4 redvec = vec4 (1.0, 0.0, 0.0, 1.0);"); - cogl_pipeline_add_vertex_hook (pipeline, snippet); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_object_unref (snippet); cogl_push_source (pipeline); @@ -159,21 +171,22 @@ paint (TestState *state) the conformance test but at least it should be possible to see by setting COGL_DEBUG=show-source to check whether this shader gets generated twice */ - snippet = cogl_snippet_new ("/* This comment should only be seen ONCE\n" + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, + "/* This comment should only be seen ONCE\n" " when COGL_DEBUG=show-source is TRUE\n" " even though it is used in two different\n" " unrelated pipelines */", "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);\n"); pipeline = cogl_pipeline_new (); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_push_source (pipeline); cogl_rectangle (50, 0, 60, 10); cogl_pop_source (); cogl_object_unref (pipeline); pipeline = cogl_pipeline_new (); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_push_source (pipeline); cogl_rectangle (60, 0, 70, 10); cogl_pop_source (); @@ -182,7 +195,7 @@ paint (TestState *state) cogl_object_unref (snippet); /* Check the replace string */ - snippet = cogl_snippet_new (NULL, NULL); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, NULL, NULL); cogl_snippet_set_pre (snippet, "cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);"); /* Remove the generated output. If the replace string isn't working @@ -193,7 +206,7 @@ paint (TestState *state) "cogl_color_out += vec4 (0.5, 0.0, 0.0, 1.0);"); pipeline = cogl_pipeline_new (); - cogl_pipeline_add_fragment_hook (pipeline, snippet); + cogl_pipeline_add_snippet (pipeline, snippet); cogl_push_source (pipeline); cogl_rectangle (70, 0, 80, 10); cogl_pop_source (); @@ -202,14 +215,15 @@ paint (TestState *state) cogl_object_unref (snippet); /* Check the texture lookup hook */ - snippet = cogl_snippet_new (NULL, + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, + NULL, "cogl_texel.b += 1.0;"); /* Flip the texture coordinates around the y axis so that it will get the green texel */ cogl_snippet_set_pre (snippet, "cogl_tex_coord.x = 1.0 - cogl_tex_coord.x;"); pipeline = create_texture_pipeline (); - cogl_pipeline_add_texture_lookup_hook (pipeline, 0, snippet); + cogl_pipeline_add_layer_snippet (pipeline, 0, snippet); cogl_push_source (pipeline); cogl_rectangle_with_texture_coords (80, 0, 90, 10, 0, 0, 0, 0); @@ -219,7 +233,7 @@ paint (TestState *state) cogl_object_unref (snippet); /* Sanity check modifying the snippet */ - snippet = cogl_snippet_new ("foo", "bar"); + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "foo", "bar"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); @@ -248,6 +262,10 @@ paint (TestState *state) g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba"); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); + + g_assert_cmpint (cogl_snippet_get_hook (snippet), + ==, + COGL_SNIPPET_HOOK_FRAGMENT); } static void