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 <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-11-25 20:54:14 +00:00 committed by Robert Bragg
parent 5be5a03343
commit 09c2e4abe7
12 changed files with 270 additions and 174 deletions

View File

@ -481,7 +481,7 @@ ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state,
/* Wrap the texture lookup in any snippets that have been hooked */ /* Wrap the texture lookup in any snippets that have been hooked */
memset (&snippet_data, 0, sizeof (snippet_data)); memset (&snippet_data, 0, sizeof (snippet_data));
snippet_data.snippets = get_layer_fragment_snippets (layer); 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", snippet_data.chain_function = g_strdup_printf ("cogl_real_texture_lookup%i",
unit_index); unit_index);
snippet_data.final_name = g_strdup_printf ("cogl_texture_lookup%i", 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 */ /* Add all of the hooks for fragment processing */
memset (&snippet_data, 0, sizeof (snippet_data)); memset (&snippet_data, 0, sizeof (snippet_data));
snippet_data.snippets = get_fragment_snippets (pipeline); 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.chain_function = "cogl_generated_source";
snippet_data.final_name = "main"; snippet_data.final_name = "main";
snippet_data.function_prefix = "cogl_fragment_hook"; snippet_data.function_prefix = "cogl_fragment_hook";

View File

@ -34,6 +34,7 @@
#include "cogl-blend-string.h" #include "cogl-blend-string.h"
#include "cogl-util.h" #include "cogl-util.h"
#include "cogl-matrix.h" #include "cogl-matrix.h"
#include "cogl-snippet-private.h"
#include "string.h" #include "string.h"
#if 0 #if 0
@ -777,14 +778,11 @@ cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
static void static void
_cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline, _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline,
int layer_index, int layer_index,
CoglPipelineSnippetHook hook,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS;
CoglPipelineLayer *layer, *authority; CoglPipelineLayer *layer, *authority;
_COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
/* Note: this will ensure that the layer exists, creating one if it /* Note: this will ensure that the layer exists, creating one if it
* doesn't already. * 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); layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
_cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets, _cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets,
hook,
snippet); snippet);
/* If we weren't previously the authority on this state then we need /* If we weren't previously the authority on this state then we need
@ -815,14 +812,20 @@ _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline,
} }
void void
cogl_pipeline_add_texture_lookup_hook (CoglPipeline *pipeline, cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline,
int layer_index, int layer_index,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
CoglPipelineSnippetHook hook = COGL_PIPELINE_SNIPPET_HOOK_TEXTURE_LOOKUP; _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, _cogl_pipeline_layer_add_fragment_snippet (pipeline,
layer_index, layer_index,
hook,
snippet); snippet);
} }

View File

@ -497,45 +497,25 @@ cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
int layer_index, int layer_index,
CoglPipelineWrapMode mode); 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 * @pipeline: A #CoglPipeline
* @layer: The layer whose texutre lookup should be hooked * @layer: The layer to hook the snippet to
* @snippet: The #CoglSnippet to add to the texture lookup for @layer * @snippet: A #CoglSnippet
* *
* Adds a shader snippet that will hook on to the texture lookup part * Adds a shader snippet that will hook on to the given layer of the
* of a given layer. This gives a chance for the application to modify * pipeline. The exact part of the pipeline that the snippet wraps
* the coordinates that will be used for the texture lookup or to * around depends on the hook that is given to
* alter the returned texel. * 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.
* 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 * Since: 1.10
* Stability: Unstable * Stability: Unstable
*/ */
void void
cogl_pipeline_add_texture_lookup_hook (CoglPipeline *pipeline, cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline,
int layer_index, int layer,
CoglSnippet *snippet); CoglSnippet *snippet);
#endif /* COGL_ENABLE_EXPERIMENTAL_API */ #endif /* COGL_ENABLE_EXPERIMENTAL_API */

View File

@ -31,15 +31,6 @@
#include "cogl-snippet.h" #include "cogl-snippet.h"
#include "cogl-queue.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; typedef struct _CoglPipelineSnippet CoglPipelineSnippet;
COGL_LIST_HEAD (CoglPipelineSnippetList, CoglPipelineSnippet); COGL_LIST_HEAD (CoglPipelineSnippetList, CoglPipelineSnippet);
@ -48,9 +39,6 @@ struct _CoglPipelineSnippet
{ {
COGL_LIST_ENTRY (CoglPipelineSnippet) list_node; COGL_LIST_ENTRY (CoglPipelineSnippet) list_node;
/* Hook where this snippet is attached */
CoglPipelineSnippetHook hook;
CoglSnippet *snippet; CoglSnippet *snippet;
}; };
@ -60,7 +48,7 @@ typedef struct
CoglPipelineSnippetList *snippets; CoglPipelineSnippetList *snippets;
/* Only snippets at this hook point will be used */ /* 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 /* The final function to chain on to after all of the snippets code
has been run */ has been run */
@ -98,7 +86,6 @@ _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list);
void void
_cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list,
CoglPipelineSnippetHook hook,
CoglSnippet *snippet); CoglSnippet *snippet);
void void

View File

@ -44,7 +44,7 @@ _cogl_pipeline_snippet_generate_code (const CoglPipelineSnippetData *data)
int snippet_num = 0; int snippet_num = 0;
COGL_LIST_FOREACH (snippet, data->snippets, list_node) COGL_LIST_FOREACH (snippet, data->snippets, list_node)
if (snippet->hook == data->hook) if (snippet->snippet->hook == data->hook)
{ {
const char *source; const char *source;
@ -179,12 +179,10 @@ _cogl_pipeline_snippet_list_free (CoglPipelineSnippetList *list)
void void
_cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list, _cogl_pipeline_snippet_list_add (CoglPipelineSnippetList *list,
CoglPipelineSnippetHook hook,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
CoglPipelineSnippet *pipeline_snippet = g_slice_new (CoglPipelineSnippet); CoglPipelineSnippet *pipeline_snippet = g_slice_new (CoglPipelineSnippet);
pipeline_snippet->hook = hook;
pipeline_snippet->snippet = cogl_object_ref (snippet); pipeline_snippet->snippet = cogl_object_ref (snippet);
_cogl_snippet_make_immutable (pipeline_snippet->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) 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, *hash = _cogl_util_one_at_a_time_hash (*hash,
&l->snippet, &l->snippet,
sizeof (CoglSnippet *)); sizeof (CoglSnippet *));
@ -253,7 +248,7 @@ _cogl_pipeline_snippet_list_equal (CoglPipelineSnippetList *list0,
for (l0 = COGL_LIST_FIRST (list0), l1 = COGL_LIST_FIRST (list1); for (l0 = COGL_LIST_FIRST (list0), l1 = COGL_LIST_FIRST (list1);
l0 && l1; l0 && l1;
l0 = COGL_LIST_NEXT (l0, list_node), l1 = COGL_LIST_NEXT (l1, list_node)) 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 FALSE;
return l0 == NULL && l1 == NULL; return l0 == NULL && l1 == NULL;

View File

@ -1571,14 +1571,10 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
static void static void
_cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline, _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline,
CoglPipelineSnippetHook hook,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS; 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. /* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified. * - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being * - 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_pre_change_notify (pipeline, state, NULL, FALSE);
_cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets, _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); snippet);
} }
static void static void
_cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline, _cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline,
CoglPipelineSnippetHook hook,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS; 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. /* - Flush journal primitives referencing the current state.
* - Make sure the pipeline has no dependants so it may be modified. * - Make sure the pipeline has no dependants so it may be modified.
* - If the pipeline isn't currently an authority for the state being * - 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_pre_change_notify (pipeline, state, NULL, FALSE);
_cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets, _cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets,
hook,
snippet); snippet);
} }
void void
cogl_pipeline_add_fragment_hook (CoglPipeline *pipeline, cogl_pipeline_add_snippet (CoglPipeline *pipeline,
CoglSnippet *snippet) CoglSnippet *snippet)
{ {
_cogl_pipeline_add_fragment_snippet (pipeline, g_return_if_fail (cogl_is_pipeline (pipeline));
COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT, g_return_if_fail (cogl_is_snippet (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 gboolean

View File

@ -937,72 +937,23 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
gboolean transpose, gboolean transpose,
const float *value); 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 * @pipeline: A #CoglPipeline
* @snippet: The #CoglSnippet to add to the vertex processing hook * @snippet: The #CoglSnippet to add to the vertex processing hook
* *
* Adds a shader snippet that will hook on to the vertex processing * Adds a shader snippet that to @pipeline. The snippet will wrap
* stage of @pipeline. This gives a chance for the application to * around or replace some part of the pipeline as defined by the hook
* modify the vertex attributes generated by the shader. Typically the * point in @snippet. Note that some hook points are specific to a
* snippet will modify cogl_color_out or cogl_position_out builtins. * layer and must be added with cogl_pipeline_add_layer_snippet()
* * instead.
* 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.
* *
* Since: 1.10 * Since: 1.10
* Stability: Unstable * Stability: Unstable
*/ */
void void
cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline, cogl_pipeline_add_snippet (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); CoglSnippet *snippet);
#endif /* COGL_ENABLE_EXPERIMENTAL_API */ #endif /* COGL_ENABLE_EXPERIMENTAL_API */

View File

@ -381,7 +381,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
/* Add all of the hooks for vertex processing */ /* Add all of the hooks for vertex processing */
memset (&snippet_data, 0, sizeof (snippet_data)); memset (&snippet_data, 0, sizeof (snippet_data));
snippet_data.snippets = get_vertex_snippets (pipeline); 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.chain_function = "cogl_generated_source";
snippet_data.final_name = "main"; snippet_data.final_name = "main";
snippet_data.function_prefix = "cogl_vertex_hook"; snippet_data.function_prefix = "cogl_vertex_hook";

View File

@ -33,10 +33,26 @@
#include "cogl-snippet.h" #include "cogl-snippet.h"
#include "cogl-object-private.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 struct _CoglSnippet
{ {
CoglObject _parent; CoglObject _parent;
CoglSnippetHook hook;
/* This is set to TRUE the first time the snippet is attached to the /* 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 pipeline. After that any attempts to modify the snippet will be
ignored. */ ignored. */

View File

@ -38,19 +38,30 @@ _cogl_snippet_free (CoglSnippet *snippet);
COGL_OBJECT_DEFINE (Snippet, snippet); COGL_OBJECT_DEFINE (Snippet, snippet);
CoglSnippet * CoglSnippet *
cogl_snippet_new (const char *declarations, cogl_snippet_new (CoglSnippetHook hook,
const char *declarations,
const char *post) const char *post)
{ {
CoglSnippet *snippet = g_slice_new0 (CoglSnippet); CoglSnippet *snippet = g_slice_new0 (CoglSnippet);
_cogl_snippet_object_new (snippet); _cogl_snippet_object_new (snippet);
snippet->hook = hook;
cogl_snippet_set_declarations (snippet, declarations); cogl_snippet_set_declarations (snippet, declarations);
cogl_snippet_set_post (snippet, post); cogl_snippet_set_post (snippet, post);
return snippet; return snippet;
} }
CoglSnippetHook
cogl_snippet_get_hook (CoglSnippet *snippet)
{
_COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), 0);
return snippet->hook;
}
static gboolean static gboolean
_cogl_snippet_modify (CoglSnippet *snippet) _cogl_snippet_modify (CoglSnippet *snippet)
{ {

View File

@ -46,9 +46,146 @@ typedef struct _CoglSnippet CoglSnippet;
#define COGL_SNIPPET(OBJECT) ((CoglSnippet *)OBJECT) #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.
*
* <glosslist>
* <glossentry>
* <glossterm>%COGL_SNIPPET_HOOK_VERTEX</glossterm>
* <glossdef>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* The pre string in @snippet will be inserted at the top of the
* main() function before any vertex processing is done.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* </glossdef>
* </glossentry>
* <glossentry>
* <glossterm>%COGL_SNIPPET_HOOK_FRAGMENT</glossterm>
* <glossdef>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* The pre string in @snippet will be inserted at the top of the
* main() function before any fragment processing is done.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* </glossdef>
* </glossentry>
* <glossentry>
* <glossterm>%COGL_SNIPPET_HOOK_TEXTURE_LOOKUP</glossterm>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* <para>
* 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.
* </para>
* </glossentry>
* </glosslist>
*
* 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 #define cogl_snippet_new cogl_snippet_new_EXP
/** /**
* cogl_snippet_new: * 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 * @declarations: The source code for the declarations for this
* snippet or %NULL. See cogl_snippet_set_declarations(). * snippet or %NULL. See cogl_snippet_set_declarations().
* @post: The source code to run after the hook point where this * @post: The source code to run after the hook point where this
@ -62,9 +199,21 @@ typedef struct _CoglSnippet CoglSnippet;
* Stability: Unstable * Stability: Unstable
*/ */
CoglSnippet * CoglSnippet *
cogl_snippet_new (const char *declarations, cogl_snippet_new (CoglSnippetHook hook,
const char *declarations,
const char *post); 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 #define cogl_is_snippet cogl_is_snippet_EXP
/** /**
* cogl_is_snippet: * cogl_is_snippet:

View File

@ -57,8 +57,10 @@ paint (TestState *state)
cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
snippet = cogl_snippet_new (NULL, "cogl_color_out.g += 1.0;"); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
cogl_pipeline_add_fragment_hook (pipeline, snippet); NULL, /* declarations */
"cogl_color_out.g += 1.0;");
cogl_pipeline_add_snippet (pipeline, snippet);
cogl_object_unref (snippet); cogl_object_unref (snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
@ -72,8 +74,10 @@ paint (TestState *state)
cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255); cogl_pipeline_set_color4ub (pipeline, 255, 0, 0, 255);
snippet = cogl_snippet_new (NULL, "cogl_color_out.b += 1.0;"); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
cogl_pipeline_add_vertex_hook (pipeline, snippet); NULL,
"cogl_color_out.b += 1.0;");
cogl_pipeline_add_snippet (pipeline, snippet);
cogl_object_unref (snippet); cogl_object_unref (snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
@ -82,8 +86,8 @@ paint (TestState *state)
cogl_object_unref (pipeline); cogl_object_unref (pipeline);
/* Single snippet used with in both the vertex and fragment hooks /* Snippets sharing a uniform across the vertex and fragment
with a uniform */ hooks */
pipeline = cogl_pipeline_new (); pipeline = cogl_pipeline_new ();
location = cogl_pipeline_get_uniform_location (pipeline, "a_value"); 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); 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_color_out.b += a_value;");
cogl_pipeline_add_fragment_hook (pipeline, snippet); cogl_pipeline_add_snippet (pipeline, snippet);
cogl_pipeline_add_vertex_hook (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_object_unref (snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
@ -121,8 +130,10 @@ paint (TestState *state)
location = cogl_pipeline_get_uniform_location (pipeline, uniform_name); location = cogl_pipeline_get_uniform_location (pipeline, uniform_name);
cogl_pipeline_set_uniform_1f (pipeline, location, (i + 1) * 0.1f); cogl_pipeline_set_uniform_1f (pipeline, location, (i + 1) * 0.1f);
snippet = cogl_snippet_new (declarations, code); snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
cogl_pipeline_add_fragment_hook (pipeline, snippet); declarations,
code);
cogl_pipeline_add_snippet (pipeline, snippet);
cogl_object_unref (snippet); cogl_object_unref (snippet);
g_free (code); g_free (code);
@ -142,10 +153,11 @@ paint (TestState *state)
cogl_pipeline_set_color4ub (pipeline, 255, 255, 255, 255); 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_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_snippet (pipeline, snippet);
cogl_pipeline_add_fragment_hook (pipeline, snippet);
cogl_object_unref (snippet); cogl_object_unref (snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
@ -159,21 +171,22 @@ paint (TestState *state)
the conformance test but at least it should be possible to see by the conformance test but at least it should be possible to see by
setting COGL_DEBUG=show-source to check whether this shader gets setting COGL_DEBUG=show-source to check whether this shader gets
generated twice */ 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" " when COGL_DEBUG=show-source is TRUE\n"
" even though it is used in two different\n" " even though it is used in two different\n"
" unrelated pipelines */", " unrelated pipelines */",
"cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);\n"); "cogl_color_out = vec4 (0.0, 1.0, 0.0, 1.0);\n");
pipeline = cogl_pipeline_new (); pipeline = cogl_pipeline_new ();
cogl_pipeline_add_fragment_hook (pipeline, snippet); cogl_pipeline_add_snippet (pipeline, snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
cogl_rectangle (50, 0, 60, 10); cogl_rectangle (50, 0, 60, 10);
cogl_pop_source (); cogl_pop_source ();
cogl_object_unref (pipeline); cogl_object_unref (pipeline);
pipeline = cogl_pipeline_new (); pipeline = cogl_pipeline_new ();
cogl_pipeline_add_fragment_hook (pipeline, snippet); cogl_pipeline_add_snippet (pipeline, snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
cogl_rectangle (60, 0, 70, 10); cogl_rectangle (60, 0, 70, 10);
cogl_pop_source (); cogl_pop_source ();
@ -182,7 +195,7 @@ paint (TestState *state)
cogl_object_unref (snippet); cogl_object_unref (snippet);
/* Check the replace string */ /* 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_snippet_set_pre (snippet,
"cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);"); "cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);");
/* Remove the generated output. If the replace string isn't working /* 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);"); "cogl_color_out += vec4 (0.5, 0.0, 0.0, 1.0);");
pipeline = cogl_pipeline_new (); pipeline = cogl_pipeline_new ();
cogl_pipeline_add_fragment_hook (pipeline, snippet); cogl_pipeline_add_snippet (pipeline, snippet);
cogl_push_source (pipeline); cogl_push_source (pipeline);
cogl_rectangle (70, 0, 80, 10); cogl_rectangle (70, 0, 80, 10);
cogl_pop_source (); cogl_pop_source ();
@ -202,14 +215,15 @@ paint (TestState *state)
cogl_object_unref (snippet); cogl_object_unref (snippet);
/* Check the texture lookup hook */ /* 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;"); "cogl_texel.b += 1.0;");
/* Flip the texture coordinates around the y axis so that it will /* Flip the texture coordinates around the y axis so that it will
get the green texel */ get the green texel */
cogl_snippet_set_pre (snippet, "cogl_tex_coord.x = 1.0 - cogl_tex_coord.x;"); cogl_snippet_set_pre (snippet, "cogl_tex_coord.x = 1.0 - cogl_tex_coord.x;");
pipeline = create_texture_pipeline (); 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_push_source (pipeline);
cogl_rectangle_with_texture_coords (80, 0, 90, 10, cogl_rectangle_with_texture_coords (80, 0, 90, 10,
0, 0, 0, 0); 0, 0, 0, 0);
@ -219,7 +233,7 @@ paint (TestState *state)
cogl_object_unref (snippet); cogl_object_unref (snippet);
/* Sanity check modifying the 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_declarations (snippet), ==, "foo");
g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar");
g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); 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_post (snippet), ==, "ba");
g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba"); g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba");
g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba");
g_assert_cmpint (cogl_snippet_get_hook (snippet),
==,
COGL_SNIPPET_HOOK_FRAGMENT);
} }
static void static void