pipeline: Add a snippet hook for the texture lookup

This adds a per-layer snippet hook for the texure lookup. Here the
snippet can modify the texture coordinates used for the lookup or
modify the texel resulting from the lookup. This is the first
per-layer hook so this also adds the
COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS state and all of the
boilerplate needed to make that work.

Most of the functions used by the pipeline state to manage the snippet
list has been moved into cogl-pipeline-snippet.c so that it can be
shared with the layer state.

Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-11-25 17:36:03 +00:00 committed by Robert Bragg
parent 4cdf66f89b
commit df0f9a862f
11 changed files with 420 additions and 148 deletions

View File

@ -191,6 +191,15 @@ get_fragment_snippets (CoglPipeline *pipeline)
return &pipeline->big_state->fragment_snippets; 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 static gboolean
_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
int n_layers, int n_layers,
@ -368,6 +377,7 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state,
CoglHandle texture; CoglHandle texture;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer); int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
const char *target_string, *tex_coord_swizzle; const char *target_string, *tex_coord_swizzle;
CoglPipelineSnippetData snippet_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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; shader_state->unit_state[unit_index].sampled = TRUE;
g_string_append_printf (shader_state->source, g_string_append_printf (shader_state->source,
" vec4 texel%i = ", " vec4 texel%i = cogl_texture_lookup%i (",
unit_index,
unit_index); unit_index);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) /* If point sprite coord generation is being used then divert to the
{ built-in varying var for that instead of the texture
g_string_append (shader_state->source, coordinates. We don't want to do this under GL because in that
"vec4 (1.0, 1.0, 1.0, 1.0);\n"); 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); texture = _cogl_pipeline_layer_get_texture (layer);
@ -432,35 +455,50 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state,
} }
/* Create a sampler uniform */ /* 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, g_string_append_printf (shader_state->header,
"uniform sampler%s _cogl_sampler_%i;\n", "vec4\n"
target_string, "cogl_real_texture_lookup%i (vec4 coords)\n"
"{\n"
" return ",
unit_index); unit_index);
g_string_append_printf (shader_state->source, if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
"texture%s (_cogl_sampler_%i, ", g_string_append (shader_state->header,
target_string, unit_index); "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.%s",
tex_coord_swizzle);
else else
g_string_append_printf (shader_state->source, g_string_append_printf (shader_state->header,
"cogl_tex_coord_in[%d].%s", "texture%s (_cogl_sampler_%i, coords.%s);\n",
unit_index, tex_coord_swizzle); 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 static void

View File

@ -34,6 +34,7 @@
#include "cogl-matrix.h" #include "cogl-matrix.h"
#include "cogl-pipeline-layer-state.h" #include "cogl-pipeline-layer-state.h"
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-pipeline-snippet-private.h"
#include <glib.h> #include <glib.h>
@ -78,6 +79,7 @@ typedef enum
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX, COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_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 */ /* note: layers don't currently have any non-sparse state */
@ -115,6 +117,9 @@ typedef enum
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS =
1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX, 1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS =
1L<<COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX,
/* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN = 1L<<8, */ /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN = 1L<<8, */
} CoglPipelineLayerState; } CoglPipelineLayerState;
@ -133,12 +138,14 @@ typedef enum
(COGL_PIPELINE_LAYER_STATE_COMBINE | \ (COGL_PIPELINE_LAYER_STATE_COMBINE | \
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \ COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \ COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS) COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | \
COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS)
#define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \ #define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \
(COGL_PIPELINE_LAYER_STATE_FILTERS | \ (COGL_PIPELINE_LAYER_STATE_FILTERS | \
COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \ COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \
COGL_PIPELINE_LAYER_STATE_COMBINE) COGL_PIPELINE_LAYER_STATE_COMBINE | \
COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS)
#define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN 0 #define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN 0
@ -193,6 +200,7 @@ typedef struct
gboolean point_sprite_coords; gboolean point_sprite_coords;
CoglPipelineSnippetList fragment_snippets;
} CoglPipelineLayerBigState; } CoglPipelineLayerBigState;
struct _CoglPipelineLayer struct _CoglPipelineLayer

View File

@ -78,6 +78,10 @@ gboolean
_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1); CoglPipelineLayer *authority1);
gboolean
_cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1);
void void
_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
CoglPipelineLayer **authorities, CoglPipelineLayer **authorities,
@ -123,4 +127,9 @@ _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
CoglPipelineLayer **authorities, CoglPipelineLayer **authorities,
CoglPipelineHashState *state); CoglPipelineHashState *state);
void
_cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority,
CoglPipelineLayer **authorities,
CoglPipelineHashState *state);
#endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */ #endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */

View File

@ -774,6 +774,58 @@ cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
return authority->big_state->point_sprite_coords; return authority->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 gboolean
_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0, _cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1, 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; 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 static void
setup_texture_combine_state (CoglBlendStringStatement *statement, setup_texture_combine_state (CoglBlendStringStatement *statement,
CoglPipelineCombineFunc *texture_combine_func, CoglPipelineCombineFunc *texture_combine_func,
@ -1664,4 +1726,11 @@ _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
sizeof (big_state->point_sprite_coords)); 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);
}

View File

@ -497,6 +497,47 @@ cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
int layer_index, int layer_index,
CoglPipelineWrapMode mode); 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 */ #endif /* COGL_ENABLE_EXPERIMENTAL_API */
G_END_DECLS G_END_DECLS

View File

@ -204,6 +204,11 @@ _cogl_pipeline_layer_init_multi_property_sparse_state (
} }
break; 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)) _cogl_pipeline_layer_point_sprite_coords_equal))
return FALSE; 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; return TRUE;
} }
@ -591,6 +602,9 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer)
layer->texture != NULL) layer->texture != NULL)
cogl_object_unref (layer->texture); 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) if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE)
g_slice_free (CoglPipelineLayerBigState, layer->big_state); g_slice_free (CoglPipelineLayerBigState, layer->big_state);

View File

@ -32,18 +32,12 @@
#include "cogl-queue.h" #include "cogl-queue.h"
/* Enumeration of all the hook points that a snippet can be attached /* Enumeration of all the hook points that a snippet can be attached
to within a pipeline. Note that although there are currently only to within a pipeline. */
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. */
typedef enum typedef enum
{ {
COGL_PIPELINE_SNIPPET_HOOK_VERTEX, COGL_PIPELINE_SNIPPET_HOOK_VERTEX,
COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT,
COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP
} CoglPipelineSnippetHook; } CoglPipelineSnippetHook;
typedef struct _CoglPipelineSnippet CoglPipelineSnippet; typedef struct _CoglPipelineSnippet CoglPipelineSnippet;
@ -99,5 +93,25 @@ typedef struct
void void
_cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data); _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 */ #endif /* __COGL_PIPELINE_SNIPPET_PRIVATE_H */

View File

@ -32,6 +32,8 @@
#include <string.h> #include <string.h>
#include "cogl-pipeline-snippet-private.h" #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 */ /* 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 : ""); 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;
}

View File

@ -340,21 +340,6 @@ _cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0,
return TRUE; 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 gboolean
_cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0, _cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0,
CoglPipeline *authority1) CoglPipeline *authority1)
@ -1584,32 +1569,6 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
value); 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 static void
_cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline,
CoglPipelineSnippetHook hook, CoglPipelineSnippetHook hook,
@ -1682,14 +1641,40 @@ _cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline)
return !COGL_LIST_EMPTY (&authority->big_state->vertex_snippets); 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 gboolean
_cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline) _cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline)
{ {
CoglPipeline *authority = CoglPipeline *authority =
_cogl_pipeline_get_authority (pipeline, _cogl_pipeline_get_authority (pipeline,
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); 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 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 void
_cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority, _cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority,
CoglPipelineHashState *state) CoglPipelineHashState *state)
{ {
_cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets, _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets,
state); &state->hash);
} }
void void
@ -2005,5 +1971,5 @@ _cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority,
CoglPipelineHashState *state) CoglPipelineHashState *state)
{ {
_cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets, _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
state); &state->hash);
} }

View File

@ -444,22 +444,6 @@ destroy_weak_children_cb (CoglNode *node,
return TRUE; 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 static void
_cogl_pipeline_free (CoglPipeline *pipeline) _cogl_pipeline_free (CoglPipeline *pipeline)
{ {
@ -852,30 +836,6 @@ _cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
pipeline->vertend = 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 static void
_cogl_pipeline_copy_differences (CoglPipeline *dest, _cogl_pipeline_copy_differences (CoglPipeline *dest,
CoglPipeline *src, CoglPipeline *src,
@ -2642,9 +2602,12 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
_index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX; _index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX;
layer_state_hash_functions[_index] = layer_state_hash_functions[_index] =
_cogl_pipeline_layer_hash_point_sprite_state; _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! */ /* 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 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_COMBINE |
COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET |
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | 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) if (context->driver == COGL_DRIVER_GLES2)
state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;

View File

@ -9,6 +9,37 @@ typedef struct _TestState
int stub; int stub;
} TestState; } 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 static void
paint (TestState *state) paint (TestState *state)
{ {
@ -170,6 +201,23 @@ paint (TestState *state)
cogl_object_unref (snippet); 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 */ /* Sanity check modifying the snippet */
snippet = cogl_snippet_new ("foo", "bar"); snippet = cogl_snippet_new ("foo", "bar");
g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo"); 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 (55, 5, 0x00ff00ff);
test_utils_check_pixel (65, 5, 0x00ff00ff); test_utils_check_pixel (65, 5, 0x00ff00ff);
test_utils_check_pixel (75, 5, 0x808000ff); test_utils_check_pixel (75, 5, 0x808000ff);
test_utils_check_pixel (85, 5, 0x00ffffff);
} }
void void