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:
parent
4cdf66f89b
commit
df0f9a862f
11 changed files with 420 additions and 148 deletions
|
@ -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
|
||||
|
|
|
@ -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 <glib.h>
|
||||
|
||||
|
@ -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<<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, */
|
||||
|
||||
} CoglPipelineLayerState;
|
||||
|
@ -133,12 +138,14 @@ typedef enum
|
|||
(COGL_PIPELINE_LAYER_STATE_COMBINE | \
|
||||
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
|
||||
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 \
|
||||
(COGL_PIPELINE_LAYER_STATE_FILTERS | \
|
||||
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
|
||||
|
||||
|
@ -193,6 +200,7 @@ typedef struct
|
|||
|
||||
gboolean point_sprite_coords;
|
||||
|
||||
CoglPipelineSnippetList fragment_snippets;
|
||||
} CoglPipelineLayerBigState;
|
||||
|
||||
struct _CoglPipelineLayer
|
||||
|
|
|
@ -78,6 +78,10 @@ gboolean
|
|||
_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
|
||||
CoglPipelineLayer *authority1);
|
||||
|
||||
gboolean
|
||||
_cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0,
|
||||
CoglPipelineLayer *authority1);
|
||||
|
||||
void
|
||||
_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
|
||||
CoglPipelineLayer **authorities,
|
||||
|
@ -123,4 +127,9 @@ _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
|
|||
CoglPipelineLayer **authorities,
|
||||
CoglPipelineHashState *state);
|
||||
|
||||
void
|
||||
_cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority,
|
||||
CoglPipelineLayer **authorities,
|
||||
CoglPipelineHashState *state);
|
||||
|
||||
#endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */
|
||||
|
|
|
@ -774,6 +774,58 @@ cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
|
|||
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
|
||||
_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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <string.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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue