diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c index 825e8fde8..1a3413594 100644 --- a/cogl/cogl-pipeline-fragend-glsl.c +++ b/cogl/cogl-pipeline-fragend-glsl.c @@ -191,6 +191,15 @@ get_fragment_snippets (CoglPipeline *pipeline) return &pipeline->big_state->fragment_snippets; } +static CoglPipelineSnippetList * +get_layer_fragment_snippets (CoglPipelineLayer *layer) +{ + unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; + layer = _cogl_pipeline_layer_get_authority (layer, state); + + return &layer->big_state->fragment_snippets; +} + static gboolean _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, int n_layers, @@ -368,6 +377,7 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, CoglHandle texture; int unit_index = _cogl_pipeline_layer_get_unit_index (layer); const char *target_string, *tex_coord_swizzle; + CoglPipelineSnippetData snippet_data; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -377,16 +387,29 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, shader_state->unit_state[unit_index].sampled = TRUE; g_string_append_printf (shader_state->source, - " vec4 texel%i = ", + " vec4 texel%i = cogl_texture_lookup%i (", + unit_index, unit_index); - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) - { - g_string_append (shader_state->source, - "vec4 (1.0, 1.0, 1.0, 1.0);\n"); + /* If point sprite coord generation is being used then divert to the + built-in varying var for that instead of the texture + coordinates. We don't want to do this under GL because in that + case we will instead use glTexEnv(GL_COORD_REPLACE) to replace + the texture coords with the point sprite coords. Although GL also + supports the gl_PointCoord variable, it requires GLSL 1.2 which + would mean we would have to declare the GLSL version and check + for it */ + if (ctx->driver == COGL_DRIVER_GLES2 && + cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline, + layer->index)) + g_string_append_printf (shader_state->source, + "gl_PointCoord"); + else + g_string_append_printf (shader_state->source, + "cogl_tex_coord_in[%d]", + unit_index); - return; - } + g_string_append (shader_state->source, ");\n"); texture = _cogl_pipeline_layer_get_texture (layer); @@ -432,35 +455,50 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, } /* Create a sampler uniform */ + if (G_LIKELY (!COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) + g_string_append_printf (shader_state->header, + "uniform sampler%s _cogl_sampler_%i;\n", + target_string, + unit_index); + g_string_append_printf (shader_state->header, - "uniform sampler%s _cogl_sampler_%i;\n", - target_string, + "vec4\n" + "cogl_real_texture_lookup%i (vec4 coords)\n" + "{\n" + " return ", unit_index); - g_string_append_printf (shader_state->source, - "texture%s (_cogl_sampler_%i, ", - target_string, unit_index); - - /* If point sprite coord generation is being used then divert to the - built-in varying var for that instead of the texture - coordinates. We don't want to do this under GL because in that - case we will instead use glTexEnv(GL_COORD_REPLACE) to replace - the texture coords with the point sprite coords. Although GL also - supports the gl_PointCoord variable, it requires GLSL 1.2 which - would mean we would have to declare the GLSL version and check - for it */ - if (ctx->driver == COGL_DRIVER_GLES2 && - cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline, - layer->index)) - g_string_append_printf (shader_state->source, - "gl_PointCoord.%s", - tex_coord_swizzle); + if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) + g_string_append (shader_state->header, + "vec4 (1.0, 1.0, 1.0, 1.0);\n"); else - g_string_append_printf (shader_state->source, - "cogl_tex_coord_in[%d].%s", - unit_index, tex_coord_swizzle); + g_string_append_printf (shader_state->header, + "texture%s (_cogl_sampler_%i, coords.%s);\n", + target_string, unit_index, tex_coord_swizzle); - g_string_append (shader_state->source, ");\n"); + g_string_append (shader_state->header, "}\n"); + + /* 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.chain_function = g_strdup_printf ("cogl_real_texture_lookup%i", + unit_index); + snippet_data.final_name = g_strdup_printf ("cogl_texture_lookup%i", + unit_index); + snippet_data.function_prefix = g_strdup_printf ("cogl_texture_lookup_hook%i", + unit_index); + snippet_data.return_type = "vec4"; + snippet_data.return_variable = "cogl_texel"; + snippet_data.arguments = "cogl_tex_coord"; + snippet_data.argument_declarations = "vec4 cogl_tex_coord"; + snippet_data.source_buf = shader_state->header; + + _cogl_pipeline_snippet_generate_code (&snippet_data); + + g_free ((char *) snippet_data.chain_function); + g_free ((char *) snippet_data.final_name); + g_free ((char *) snippet_data.function_prefix); } static void diff --git a/cogl/cogl-pipeline-layer-private.h b/cogl/cogl-pipeline-layer-private.h index 76fcf23bf..e42859938 100644 --- a/cogl/cogl-pipeline-layer-private.h +++ b/cogl/cogl-pipeline-layer-private.h @@ -34,6 +34,7 @@ #include "cogl-matrix.h" #include "cogl-pipeline-layer-state.h" #include "cogl-internal.h" +#include "cogl-pipeline-snippet-private.h" #include @@ -78,6 +79,7 @@ typedef enum COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX, COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX, COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX, + COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX, /* note: layers don't currently have any non-sparse state */ @@ -115,6 +117,9 @@ typedef enum COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS = 1L<big_state->point_sprite_coords; } +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. + * + * Note: If the layer already existed it's possibly owned by another + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + 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 + * to extended our differences mask and so it's possible that some + * of our ancestry will now become redundant, so we aim to reparent + * ourselves if that's true... */ + if (layer != authority) + { + layer->differences |= change; + _cogl_pipeline_layer_prune_redundant_ancestry (layer); + } +} + +void +cogl_pipeline_add_texture_lookup_hook (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); +} + gboolean _cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0, CoglPipelineLayer *authority1, @@ -911,6 +963,16 @@ _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, return big_state0->point_sprite_coords == big_state1->point_sprite_coords; } +gboolean +_cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + return _cogl_pipeline_snippet_list_equal (&authority0->big_state-> + fragment_snippets, + &authority1->big_state-> + fragment_snippets); +} + static void setup_texture_combine_state (CoglBlendStringStatement *statement, CoglPipelineCombineFunc *texture_combine_func, @@ -1664,4 +1726,11 @@ _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, sizeof (big_state->point_sprite_coords)); } - +void +_cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets, + &state->hash); +} diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h index b1f57367e..7d6965b26 100644 --- a/cogl/cogl-pipeline-layer-state.h +++ b/cogl/cogl-pipeline-layer-state.h @@ -497,6 +497,47 @@ cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, int layer_index, CoglPipelineWrapMode mode); +/** + * cogl_pipeline_add_texture_lookup_hook: + * @pipeline: A #CoglPipeline + * @layer: The layer whose texutre lookup should be hooked + * @snippet: The #CoglSnippet to add to the texture lookup for @layer + * + * 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 + */ +void +cogl_pipeline_add_texture_lookup_hook (CoglPipeline *pipeline, + int layer_index, + CoglSnippet *snippet); + #endif /* COGL_ENABLE_EXPERIMENTAL_API */ G_END_DECLS diff --git a/cogl/cogl-pipeline-layer.c b/cogl/cogl-pipeline-layer.c index 0b5693fe1..86e075089 100644 --- a/cogl/cogl-pipeline-layer.c +++ b/cogl/cogl-pipeline-layer.c @@ -204,6 +204,11 @@ _cogl_pipeline_layer_init_multi_property_sparse_state ( } break; } + case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS: + _cogl_pipeline_snippet_list_copy (&layer->big_state->fragment_snippets, + &authority->big_state-> + fragment_snippets); + break; } } @@ -579,6 +584,12 @@ _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0, _cogl_pipeline_layer_point_sprite_coords_equal)) return FALSE; + if (layers_difference & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS && + !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX, + authorities0, authorities1, + _cogl_pipeline_layer_fragment_snippets_equal)) + return FALSE; + return TRUE; } @@ -591,6 +602,9 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer) layer->texture != NULL) cogl_object_unref (layer->texture); + if (layer->differences & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS) + _cogl_pipeline_snippet_list_free (&layer->big_state->fragment_snippets); + if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) g_slice_free (CoglPipelineLayerBigState, layer->big_state); diff --git a/cogl/cogl-pipeline-snippet-private.h b/cogl/cogl-pipeline-snippet-private.h index 49fd6e552..0df497264 100644 --- a/cogl/cogl-pipeline-snippet-private.h +++ b/cogl/cogl-pipeline-snippet-private.h @@ -32,18 +32,12 @@ #include "cogl-queue.h" /* Enumeration of all the hook points that a snippet can be attached - to within a pipeline. Note that although there are currently only - two points that directly correspond to the two state flags, the - idea isn't that each new enum here will mean a state flag. The - state flags are just intended to mark the split between hooks that - affect the fragment shader and hooks that affect the vertex - shader. For example, if we add a hook to wrap around the processing - for a particular layer then that hook would be part of the fragment - snippets state. */ + to within a pipeline. */ typedef enum { COGL_PIPELINE_SNIPPET_HOOK_VERTEX, - COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT + COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT, + COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP } CoglPipelineSnippetHook; typedef struct _CoglPipelineSnippet CoglPipelineSnippet; @@ -99,5 +93,25 @@ typedef struct void _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data); +void +_cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list); + +void +_cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, + CoglPipelineSnippetHook hook, + CoglSnippet *snippet); + +void +_cogl_pipeline_snippet_list_copy (CoglPipelineSnippetList *dst, + const CoglPipelineSnippetList *src); + +void +_cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, + unsigned int *hash); + +gboolean +_cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, + CoglPipelineSnippetList *list1); + #endif /* __COGL_PIPELINE_SNIPPET_PRIVATE_H */ diff --git a/cogl/cogl-pipeline-snippet.c b/cogl/cogl-pipeline-snippet.c index b7a694c71..bb57abd6c 100644 --- a/cogl/cogl-pipeline-snippet.c +++ b/cogl/cogl-pipeline-snippet.c @@ -32,6 +32,8 @@ #include #include "cogl-pipeline-snippet-private.h" +#include "cogl-snippet-private.h" +#include "cogl-util.h" /* Helper functions that are used by both GLSL pipeline backends */ @@ -158,3 +160,101 @@ _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data) data->arguments ? data->arguments : ""); } } + +static void +_cogl_pipeline_snippet_free (CoglPipelineSnippet *pipeline_snippet) +{ + cogl_object_unref (pipeline_snippet->snippet); + g_slice_free (CoglPipelineSnippet, pipeline_snippet); +} + +void +_cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list) +{ + CoglPipelineSnippet *pipeline_snippet, *tmp; + + COGL_LIST_FOREACH_SAFE (pipeline_snippet, list, list_node, tmp) + _cogl_pipeline_snippet_free (pipeline_snippet); +} + +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); + + if (COGL_LIST_EMPTY (list)) + COGL_LIST_INSERT_HEAD (list, pipeline_snippet, list_node); + else + { + CoglPipelineSnippet *tail; + + for (tail = COGL_LIST_FIRST (list); + COGL_LIST_NEXT (tail, list_node); + tail = COGL_LIST_NEXT (tail, list_node)); + + COGL_LIST_INSERT_AFTER (tail, pipeline_snippet, list_node); + } +} + +void +_cogl_pipeline_snippet_list_copy (CoglPipelineSnippetList *dst, + const CoglPipelineSnippetList *src) +{ + CoglPipelineSnippet *tail = NULL; + const CoglPipelineSnippet *l; + + COGL_LIST_INIT (dst); + + COGL_LIST_FOREACH (l, src, list_node) + { + CoglPipelineSnippet *copy = g_slice_dup (CoglPipelineSnippet, l); + + cogl_object_ref (copy->snippet); + + if (tail) + COGL_LIST_INSERT_AFTER (tail, copy, list_node); + else + COGL_LIST_INSERT_HEAD (dst, copy, list_node); + + tail = copy; + } +} + +void +_cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, + unsigned int *hash) +{ + CoglPipelineSnippet *l; + + 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 *)); + } +} + +gboolean +_cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, + CoglPipelineSnippetList *list1) +{ + CoglPipelineSnippet *l0, *l1; + + 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) + return FALSE; + + return l0 == NULL && l1 == NULL; +} diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c index 56cdb1629..04caa918c 100644 --- a/cogl/cogl-pipeline-state.c +++ b/cogl/cogl-pipeline-state.c @@ -340,21 +340,6 @@ _cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0, return TRUE; } -static gboolean -_cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0, - CoglPipelineSnippetList *list1) -{ - CoglPipelineSnippet *l0, *l1; - - 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) - return FALSE; - - return l0 == NULL && l1 == NULL; -} - gboolean _cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0, CoglPipeline *authority1) @@ -1584,32 +1569,6 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, value); } -static 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); - - if (COGL_LIST_EMPTY (list)) - COGL_LIST_INSERT_HEAD (list, pipeline_snippet, list_node); - else - { - CoglPipelineSnippet *tail; - - for (tail = COGL_LIST_FIRST (list); - COGL_LIST_NEXT (tail, list_node); - tail = COGL_LIST_NEXT (tail, list_node)); - - COGL_LIST_INSERT_AFTER (tail, pipeline_snippet, list_node); - } -} - static void _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, CoglPipelineSnippetHook hook, @@ -1682,14 +1641,40 @@ _cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline) return !COGL_LIST_EMPTY (&authority->big_state->vertex_snippets); } +static gboolean +check_layer_has_fragment_snippet (CoglPipelineLayer *layer, + void *user_data) +{ + unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, state); + gboolean *found_fragment_snippet = user_data; + + if (!COGL_LIST_EMPTY (&authority->big_state->fragment_snippets)) + { + *found_fragment_snippet = TRUE; + return FALSE; + } + + return TRUE; +} + gboolean _cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); + gboolean found_fragment_snippet = FALSE; - return !COGL_LIST_EMPTY (&authority->big_state->fragment_snippets); + if (!COGL_LIST_EMPTY (&authority->big_state->fragment_snippets)) + return TRUE; + + _cogl_pipeline_foreach_layer_internal (pipeline, + check_layer_has_fragment_snippet, + &found_fragment_snippet); + + return found_fragment_snippet; } void @@ -1973,31 +1958,12 @@ _cogl_pipeline_compare_uniform_differences (unsigned long *differences, } } -static void -_cogl_pipeline_snippet_list_hash (CoglPipelineSnippetList *list, - CoglPipelineHashState *state) -{ - CoglPipelineSnippet *l; - - COGL_LIST_FOREACH (l, list, list_node) - { - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, - &l->hook, - sizeof (CoglPipelineSnippetHook)); - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, - &l->snippet, - sizeof (CoglSnippet *)); - } -} - void _cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets, - state); + &state->hash); } void @@ -2005,5 +1971,5 @@ _cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority, CoglPipelineHashState *state) { _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets, - state); + &state->hash); } diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c index e47a5deb0..2831b55f7 100644 --- a/cogl/cogl-pipeline.c +++ b/cogl/cogl-pipeline.c @@ -444,22 +444,6 @@ destroy_weak_children_cb (CoglNode *node, return TRUE; } -static void -_cogl_pipeline_snippet_free (CoglPipelineSnippet *pipeline_snippet) -{ - cogl_object_unref (pipeline_snippet->snippet); - g_slice_free (CoglPipelineSnippet, pipeline_snippet); -} - -static void -_cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list) -{ - CoglPipelineSnippet *pipeline_snippet, *tmp; - - COGL_LIST_FOREACH_SAFE (pipeline_snippet, list, list_node, tmp) - _cogl_pipeline_snippet_free (pipeline_snippet); -} - static void _cogl_pipeline_free (CoglPipeline *pipeline) { @@ -852,30 +836,6 @@ _cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend) pipeline->vertend = vertend; } -static void -_cogl_pipeline_snippet_list_copy (CoglPipelineSnippetList *dst, - const CoglPipelineSnippetList *src) -{ - CoglPipelineSnippet *tail = NULL; - const CoglPipelineSnippet *l; - - COGL_LIST_INIT (dst); - - COGL_LIST_FOREACH (l, src, list_node) - { - CoglPipelineSnippet *copy = g_slice_dup (CoglPipelineSnippet, l); - - cogl_object_ref (copy->snippet); - - if (tail) - COGL_LIST_INSERT_AFTER (tail, copy, list_node); - else - COGL_LIST_INSERT_HEAD (dst, copy, list_node); - - tail = copy; - } -} - static void _cogl_pipeline_copy_differences (CoglPipeline *dest, CoglPipeline *src, @@ -2642,9 +2602,12 @@ _cogl_pipeline_init_layer_state_hash_functions (void) _index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX; layer_state_hash_functions[_index] = _cogl_pipeline_layer_hash_point_sprite_state; + _index = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX; + layer_state_hash_functions[_index] = + _cogl_pipeline_layer_hash_fragment_snippets_state; /* So we get a big error if we forget to update this code! */ - g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 9); + g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 10); } static gboolean @@ -2928,7 +2891,8 @@ _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context) (COGL_PIPELINE_LAYER_STATE_COMBINE | COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | - COGL_PIPELINE_LAYER_STATE_UNIT); + COGL_PIPELINE_LAYER_STATE_UNIT | + COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS); if (context->driver == COGL_DRIVER_GLES2) state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; diff --git a/tests/conform/test-snippets.c b/tests/conform/test-snippets.c index f3e9ae118..2d96a9928 100644 --- a/tests/conform/test-snippets.c +++ b/tests/conform/test-snippets.c @@ -9,6 +9,37 @@ typedef struct _TestState int stub; } TestState; +static CoglPipeline * +create_texture_pipeline (void) +{ + CoglPipeline *pipeline; + CoglHandle tex; + static const guint8 tex_data[] = + { + 0xff, 0x00, 0x00, 0xff, /* red */ 0x00, 0xff, 0x00, 0xff, /* green */ + 0x00, 0x00, 0xff, 0xff, /* blue */ 0xff, 0xff, 0x00, 0xff, /* yellow */ + }; + + tex = cogl_texture_new_from_data (2, 2, /* width/height */ + COGL_TEXTURE_NO_ATLAS, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + COGL_PIXEL_FORMAT_ANY, + 8, /* rowstride */ + tex_data); + + pipeline = cogl_pipeline_new (); + + cogl_pipeline_set_layer_texture (pipeline, 0, tex); + + cogl_pipeline_set_layer_filters (pipeline, 0, + COGL_PIPELINE_FILTER_NEAREST, + COGL_PIPELINE_FILTER_NEAREST); + + cogl_handle_unref (tex); + + return pipeline; +} + static void paint (TestState *state) { @@ -170,6 +201,23 @@ paint (TestState *state) cogl_object_unref (snippet); + /* Check the texture lookup hook */ + snippet = cogl_snippet_new (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_push_source (pipeline); + cogl_rectangle_with_texture_coords (80, 0, 90, 10, + 0, 0, 0, 0); + cogl_pop_source (); + cogl_object_unref (pipeline); + + cogl_object_unref (snippet); + /* Sanity check modifying the snippet */ snippet = cogl_snippet_new ("foo", "bar"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo"); @@ -213,6 +261,7 @@ validate_result (void) test_utils_check_pixel (55, 5, 0x00ff00ff); test_utils_check_pixel (65, 5, 0x00ff00ff); test_utils_check_pixel (75, 5, 0x808000ff); + test_utils_check_pixel (85, 5, 0x00ffffff); } void