cogl-pipeline: Add two hook points for adding shader snippets
This adds two new public experimental functions for attaching CoglSnippets to two hook points on a CoglPipeline: void cogl_pipeline_add_vertex_hook (CoglPipeline *, CoglSnippet *) void cogl_pipeline_add_fragment_hook (CoglPipeline *, CoglSnippet *) The hooks are intended to be around the entire vertex or fragment processing. That means the pre string in the snippet will be inserted at the very top of the main function and the post function will be inserted at the very end. The declarations get inserted in the global scope. The snippets are stored in two separate linked lists with a structure containing an enum representing the hook point and a pointer to the snippet. The lists are meant to be for hooks that affect the vertex shader and fragment shader respectively. Although there are currently only two hooks and the names match these two lists, the intention is *not* that each new hook will be in a separate list. The separation of the lists is just to make it easier to determine which shader needs to be regenerated when a new snippet is added. When a pipeline becomes the authority for either the vertex or fragment snipper state, it simply copies the entire list from the previous authority (although of course the shader snippet objects are referenced instead of copied so it doesn't duplicate the source strings). Each string is inserted into its own block in the shader. This means that each string has its own scope so it doesn't need to worry about name collisions with variables in other snippets. However it does mean that the pre and post strings can't share variables. It could be possible to wrap both parts in one block and then wrap the actual inner hook code in another block, however this would mean that any further snippets within the outer snippet would be able to see those variables. Perhaps something to consider would be to put each snippet into its own function which calls another function between the pre and post strings to do further processing. The pipeline cache for generated programs was previously shared with the fragment shader cache because the state that affects vertex shaders was a subset of the state that affects fragment shaders. This is no longer the case because there is a separate state mask for vertex snippets so the program cache now has its own hash table. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
f37738453e
commit
d38ae0284b
@ -37,6 +37,7 @@ struct _CoglPipelineCache
|
|||||||
{
|
{
|
||||||
GHashTable *fragment_hash;
|
GHashTable *fragment_hash;
|
||||||
GHashTable *vertex_hash;
|
GHashTable *vertex_hash;
|
||||||
|
GHashTable *combined_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
@ -101,6 +102,46 @@ pipeline_vertex_equal (const void *a, const void *b)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
pipeline_combined_hash (const void *data)
|
||||||
|
{
|
||||||
|
unsigned int combined_state;
|
||||||
|
unsigned int layer_combined_state;
|
||||||
|
|
||||||
|
_COGL_GET_CONTEXT (ctx, 0);
|
||||||
|
|
||||||
|
combined_state =
|
||||||
|
_cogl_pipeline_get_state_for_fragment_codegen (ctx) |
|
||||||
|
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||||
|
layer_combined_state =
|
||||||
|
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
|
||||||
|
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||||
|
|
||||||
|
return _cogl_pipeline_hash ((CoglPipeline *)data,
|
||||||
|
combined_state, layer_combined_state,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pipeline_combined_equal (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
unsigned int combined_state;
|
||||||
|
unsigned int layer_combined_state;
|
||||||
|
|
||||||
|
_COGL_GET_CONTEXT (ctx, 0);
|
||||||
|
|
||||||
|
combined_state =
|
||||||
|
_cogl_pipeline_get_state_for_fragment_codegen (ctx) |
|
||||||
|
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||||
|
layer_combined_state =
|
||||||
|
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
|
||||||
|
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN;
|
||||||
|
|
||||||
|
return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
|
||||||
|
combined_state, layer_combined_state,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
CoglPipelineCache *
|
CoglPipelineCache *
|
||||||
cogl_pipeline_cache_new (void)
|
cogl_pipeline_cache_new (void)
|
||||||
{
|
{
|
||||||
@ -114,6 +155,10 @@ cogl_pipeline_cache_new (void)
|
|||||||
pipeline_vertex_equal,
|
pipeline_vertex_equal,
|
||||||
cogl_object_unref,
|
cogl_object_unref,
|
||||||
cogl_object_unref);
|
cogl_object_unref);
|
||||||
|
cache->combined_hash = g_hash_table_new_full (pipeline_combined_hash,
|
||||||
|
pipeline_combined_equal,
|
||||||
|
cogl_object_unref,
|
||||||
|
cogl_object_unref);
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@ -123,6 +168,7 @@ cogl_pipeline_cache_free (CoglPipelineCache *cache)
|
|||||||
{
|
{
|
||||||
g_hash_table_destroy (cache->fragment_hash);
|
g_hash_table_destroy (cache->fragment_hash);
|
||||||
g_hash_table_destroy (cache->vertex_hash);
|
g_hash_table_destroy (cache->vertex_hash);
|
||||||
|
g_hash_table_destroy (cache->combined_hash);
|
||||||
g_free (cache);
|
g_free (cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,27 +256,27 @@ CoglPipeline *
|
|||||||
_cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
|
_cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache,
|
||||||
CoglPipeline *key_pipeline)
|
CoglPipeline *key_pipeline)
|
||||||
{
|
{
|
||||||
unsigned int pipeline_state_for_fragment_codegen;
|
CoglPipeline *template =
|
||||||
unsigned int pipeline_layer_state_for_fragment_codegen;
|
g_hash_table_lookup (cache->combined_hash, key_pipeline);
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NULL);
|
if (template == NULL)
|
||||||
|
{
|
||||||
|
template = cogl_pipeline_copy (key_pipeline);
|
||||||
|
|
||||||
pipeline_state_for_fragment_codegen =
|
g_hash_table_insert (cache->combined_hash,
|
||||||
_cogl_pipeline_get_state_for_fragment_codegen (ctx);
|
template,
|
||||||
pipeline_layer_state_for_fragment_codegen =
|
cogl_object_ref (template));
|
||||||
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx);
|
|
||||||
|
|
||||||
/* Currently the vertex shader state is a subset of the fragment
|
if (G_UNLIKELY (g_hash_table_size (cache->combined_hash) > 50))
|
||||||
shader state so we can avoid a third hash table here by just
|
{
|
||||||
using the fragment shader table. This assert should catch it if
|
static gboolean seen = FALSE;
|
||||||
that ever changes */
|
if (!seen)
|
||||||
|
g_warning ("Over 50 separate programs have been "
|
||||||
|
"generated which is very unusual, so something "
|
||||||
|
"is probably wrong!\n");
|
||||||
|
seen = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_assert ((pipeline_state_for_fragment_codegen |
|
return template;
|
||||||
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN) ==
|
|
||||||
pipeline_state_for_fragment_codegen);
|
|
||||||
g_assert ((pipeline_layer_state_for_fragment_codegen |
|
|
||||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN) ==
|
|
||||||
pipeline_layer_state_for_fragment_codegen);
|
|
||||||
|
|
||||||
return _cogl_pipeline_cache_get_fragment_template (cache, key_pipeline);
|
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "cogl-debug.h"
|
#include "cogl-debug.h"
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
#include "cogl-pipeline-private.h"
|
#include "cogl-pipeline-private.h"
|
||||||
|
#include "cogl-pipeline-state-private.h"
|
||||||
#include "cogl-pipeline-layer-private.h"
|
#include "cogl-pipeline-layer-private.h"
|
||||||
|
|
||||||
#ifdef COGL_PIPELINE_FRAGEND_ARBFP
|
#ifdef COGL_PIPELINE_FRAGEND_ARBFP
|
||||||
@ -178,6 +179,10 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||||||
if (_cogl_pipeline_get_fog_enabled (pipeline))
|
if (_cogl_pipeline_get_fog_enabled (pipeline))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* Fragment snippets are only supported in the GLSL fragend */
|
||||||
|
if (_cogl_pipeline_has_fragment_snippets (pipeline))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
user_program = cogl_pipeline_get_user_program (pipeline);
|
user_program = cogl_pipeline_get_user_program (pipeline);
|
||||||
if (user_program != COGL_INVALID_HANDLE)
|
if (user_program != COGL_INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
#include "cogl-pipeline-private.h"
|
#include "cogl-pipeline-private.h"
|
||||||
|
#include "cogl-pipeline-state-private.h"
|
||||||
#include "cogl-pipeline-opengl-private.h"
|
#include "cogl-pipeline-opengl-private.h"
|
||||||
|
|
||||||
#ifdef COGL_PIPELINE_FRAGEND_FIXED
|
#ifdef COGL_PIPELINE_FRAGEND_FIXED
|
||||||
@ -101,6 +102,10 @@ _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
|
|||||||
if (ctx->driver == COGL_DRIVER_GLES2)
|
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* Fragment snippets are only supported in the GLSL fragend */
|
||||||
|
if (_cogl_pipeline_has_fragment_snippets (pipeline))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* If there is a user program with a fragment shader then the
|
/* If there is a user program with a fragment shader then the
|
||||||
appropriate backend for that language should handle it. We can
|
appropriate backend for that language should handle it. We can
|
||||||
still use the fixed fragment backend if the program only contains
|
still use the fixed fragment backend if the program only contains
|
||||||
|
@ -181,6 +181,16 @@ _cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CoglPipelineSnippetList *
|
||||||
|
get_fragment_snippets (CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
pipeline =
|
||||||
|
_cogl_pipeline_get_authority (pipeline,
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
|
||||||
|
|
||||||
|
return &pipeline->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,
|
||||||
@ -190,6 +200,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||||||
CoglPipelineShaderState *shader_state;
|
CoglPipelineShaderState *shader_state;
|
||||||
CoglPipeline *authority;
|
CoglPipeline *authority;
|
||||||
CoglPipeline *template_pipeline = NULL;
|
CoglPipeline *template_pipeline = NULL;
|
||||||
|
CoglPipelineSnippet *snippet;
|
||||||
CoglProgram *user_program;
|
CoglProgram *user_program;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -319,6 +330,37 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||||||
"main ()\n"
|
"main ()\n"
|
||||||
"{\n");
|
"{\n");
|
||||||
|
|
||||||
|
COGL_LIST_FOREACH (snippet, get_fragment_snippets (pipeline), list_node)
|
||||||
|
{
|
||||||
|
const char *declarations =
|
||||||
|
cogl_snippet_get_declarations (snippet->snippet);
|
||||||
|
|
||||||
|
/* Add all of the declarations for fragment snippets */
|
||||||
|
if (declarations)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->header, declarations);
|
||||||
|
g_string_append_c (shader_state->header, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add all of the pre-hooks for fragment processing */
|
||||||
|
if (snippet->hook == COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT)
|
||||||
|
{
|
||||||
|
const char *pre =
|
||||||
|
cogl_snippet_get_pre (snippet->snippet);
|
||||||
|
|
||||||
|
if (pre)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
g_string_append (shader_state->source, pre);
|
||||||
|
g_string_append (shader_state->source, " }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enclose the generated fragment processing in a block so that any
|
||||||
|
variables declared in it won't be in the scope of the snippets */
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
|
||||||
for (i = 0; i < n_layers; i++)
|
for (i = 0; i < n_layers; i++)
|
||||||
{
|
{
|
||||||
shader_state->unit_state[i].sampled = FALSE;
|
shader_state->unit_state[i].sampled = FALSE;
|
||||||
@ -885,6 +927,7 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
|
|||||||
GLint lengths[2];
|
GLint lengths[2];
|
||||||
GLint compile_status;
|
GLint compile_status;
|
||||||
GLuint shader;
|
GLuint shader;
|
||||||
|
CoglPipelineSnippet *snippet;
|
||||||
|
|
||||||
COGL_STATIC_COUNTER (fragend_glsl_compile_counter,
|
COGL_STATIC_COUNTER (fragend_glsl_compile_counter,
|
||||||
"glsl fragment compile counter",
|
"glsl fragment compile counter",
|
||||||
@ -922,6 +965,24 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
|
|||||||
add_alpha_test_snippet (pipeline, shader_state);
|
add_alpha_test_snippet (pipeline, shader_state);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Close the block surrounding the generated fragment processing */
|
||||||
|
g_string_append (shader_state->source, " }\n");
|
||||||
|
|
||||||
|
/* Add all of the post-hooks for fragment processing */
|
||||||
|
COGL_LIST_FOREACH (snippet, get_fragment_snippets (pipeline), list_node)
|
||||||
|
if (snippet->hook == COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT)
|
||||||
|
{
|
||||||
|
const char *post =
|
||||||
|
cogl_snippet_get_post (snippet->snippet);
|
||||||
|
|
||||||
|
if (post)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
g_string_append (shader_state->source, post);
|
||||||
|
g_string_append (shader_state->source, " }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_string_append (shader_state->source, "}\n");
|
g_string_append (shader_state->source, "}\n");
|
||||||
|
|
||||||
GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) );
|
GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) );
|
||||||
|
@ -168,6 +168,8 @@ typedef enum
|
|||||||
COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
|
COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
|
||||||
COGL_PIPELINE_STATE_CULL_FACE_INDEX,
|
COGL_PIPELINE_STATE_CULL_FACE_INDEX,
|
||||||
COGL_PIPELINE_STATE_UNIFORMS_INDEX,
|
COGL_PIPELINE_STATE_UNIFORMS_INDEX,
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX,
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX,
|
||||||
|
|
||||||
/* non-sparse */
|
/* non-sparse */
|
||||||
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
|
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
|
||||||
@ -217,6 +219,10 @@ typedef enum _CoglPipelineState
|
|||||||
1L<<COGL_PIPELINE_STATE_CULL_FACE_INDEX,
|
1L<<COGL_PIPELINE_STATE_CULL_FACE_INDEX,
|
||||||
COGL_PIPELINE_STATE_UNIFORMS =
|
COGL_PIPELINE_STATE_UNIFORMS =
|
||||||
1L<<COGL_PIPELINE_STATE_UNIFORMS_INDEX,
|
1L<<COGL_PIPELINE_STATE_UNIFORMS_INDEX,
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS =
|
||||||
|
1L<<COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX,
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS =
|
||||||
|
1L<<COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX,
|
||||||
|
|
||||||
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
|
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
|
||||||
1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
|
1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
|
||||||
@ -240,7 +246,9 @@ typedef enum _CoglPipelineState
|
|||||||
COGL_PIPELINE_STATE_LAYERS | \
|
COGL_PIPELINE_STATE_LAYERS | \
|
||||||
COGL_PIPELINE_STATE_LIGHTING | \
|
COGL_PIPELINE_STATE_LIGHTING | \
|
||||||
COGL_PIPELINE_STATE_BLEND | \
|
COGL_PIPELINE_STATE_BLEND | \
|
||||||
COGL_PIPELINE_STATE_USER_SHADER)
|
COGL_PIPELINE_STATE_USER_SHADER | \
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS | \
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||||
|
|
||||||
#define COGL_PIPELINE_STATE_NEEDS_BIG_STATE \
|
#define COGL_PIPELINE_STATE_NEEDS_BIG_STATE \
|
||||||
(COGL_PIPELINE_STATE_LIGHTING | \
|
(COGL_PIPELINE_STATE_LIGHTING | \
|
||||||
@ -253,7 +261,9 @@ typedef enum _CoglPipelineState
|
|||||||
COGL_PIPELINE_STATE_POINT_SIZE | \
|
COGL_PIPELINE_STATE_POINT_SIZE | \
|
||||||
COGL_PIPELINE_STATE_LOGIC_OPS | \
|
COGL_PIPELINE_STATE_LOGIC_OPS | \
|
||||||
COGL_PIPELINE_STATE_CULL_FACE | \
|
COGL_PIPELINE_STATE_CULL_FACE | \
|
||||||
COGL_PIPELINE_STATE_UNIFORMS)
|
COGL_PIPELINE_STATE_UNIFORMS | \
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS | \
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||||
|
|
||||||
#define COGL_PIPELINE_STATE_MULTI_PROPERTY \
|
#define COGL_PIPELINE_STATE_MULTI_PROPERTY \
|
||||||
(COGL_PIPELINE_STATE_LAYERS | \
|
(COGL_PIPELINE_STATE_LAYERS | \
|
||||||
@ -263,11 +273,14 @@ typedef enum _CoglPipelineState
|
|||||||
COGL_PIPELINE_STATE_FOG | \
|
COGL_PIPELINE_STATE_FOG | \
|
||||||
COGL_PIPELINE_STATE_LOGIC_OPS | \
|
COGL_PIPELINE_STATE_LOGIC_OPS | \
|
||||||
COGL_PIPELINE_STATE_CULL_FACE | \
|
COGL_PIPELINE_STATE_CULL_FACE | \
|
||||||
COGL_PIPELINE_STATE_UNIFORMS)
|
COGL_PIPELINE_STATE_UNIFORMS | \
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS | \
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||||
|
|
||||||
#define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \
|
#define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \
|
||||||
(COGL_PIPELINE_STATE_LAYERS | \
|
(COGL_PIPELINE_STATE_LAYERS | \
|
||||||
COGL_PIPELINE_STATE_USER_SHADER)
|
COGL_PIPELINE_STATE_USER_SHADER | \
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@ -353,6 +366,35 @@ typedef struct
|
|||||||
CoglBitmask changed_mask;
|
CoglBitmask changed_mask;
|
||||||
} CoglPipelineUniformsState;
|
} CoglPipelineUniformsState;
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
COGL_PIPELINE_SNIPPET_HOOK_VERTEX,
|
||||||
|
COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT
|
||||||
|
} CoglPipelineSnippetHook;
|
||||||
|
|
||||||
|
typedef struct _CoglPipelineSnippet CoglPipelineSnippet;
|
||||||
|
|
||||||
|
COGL_LIST_HEAD (CoglPipelineSnippetList, CoglPipelineSnippet);
|
||||||
|
|
||||||
|
struct _CoglPipelineSnippet
|
||||||
|
{
|
||||||
|
COGL_LIST_ENTRY (CoglPipelineSnippet) list_node;
|
||||||
|
|
||||||
|
/* Hook where this snippet is attached */
|
||||||
|
CoglPipelineSnippetHook hook;
|
||||||
|
|
||||||
|
CoglSnippet *snippet;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
CoglPipelineLightingState lighting_state;
|
CoglPipelineLightingState lighting_state;
|
||||||
@ -365,6 +407,8 @@ typedef struct
|
|||||||
CoglPipelineLogicOpsState logic_ops_state;
|
CoglPipelineLogicOpsState logic_ops_state;
|
||||||
CoglPipelineCullFaceState cull_face_state;
|
CoglPipelineCullFaceState cull_face_state;
|
||||||
CoglPipelineUniformsState uniforms_state;
|
CoglPipelineUniformsState uniforms_state;
|
||||||
|
CoglPipelineSnippetList vertex_snippets;
|
||||||
|
CoglPipelineSnippetList fragment_snippets;
|
||||||
} CoglPipelineBigState;
|
} CoglPipelineBigState;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -31,6 +31,12 @@
|
|||||||
CoglPipeline *
|
CoglPipeline *
|
||||||
_cogl_pipeline_get_user_program (CoglPipeline *pipeline);
|
_cogl_pipeline_get_user_program (CoglPipeline *pipeline);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline);
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
|
_cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
|
||||||
const CoglPipelineFogState *fog_state);
|
const CoglPipelineFogState *fog_state);
|
||||||
@ -83,6 +89,14 @@ gboolean
|
|||||||
_cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0,
|
_cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0,
|
||||||
CoglPipeline *authority1);
|
CoglPipeline *authority1);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0,
|
||||||
|
CoglPipeline *authority1);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0,
|
||||||
|
CoglPipeline *authority1);
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_pipeline_hash_color_state (CoglPipeline *authority,
|
_cogl_pipeline_hash_color_state (CoglPipeline *authority,
|
||||||
CoglPipelineHashState *state);
|
CoglPipelineHashState *state);
|
||||||
@ -139,6 +153,14 @@ void
|
|||||||
_cogl_pipeline_hash_uniforms_state (CoglPipeline *authority,
|
_cogl_pipeline_hash_uniforms_state (CoglPipeline *authority,
|
||||||
CoglPipelineHashState *state);
|
CoglPipelineHashState *state);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority,
|
||||||
|
CoglPipelineHashState *state);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority,
|
||||||
|
CoglPipelineHashState *state);
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_pipeline_compare_uniform_differences (unsigned long *differences,
|
_cogl_pipeline_compare_uniform_differences (unsigned long *differences,
|
||||||
CoglPipeline *pipeline0,
|
CoglPipeline *pipeline0,
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "cogl-util.h"
|
#include "cogl-util.h"
|
||||||
#include "cogl-depth-state-private.h"
|
#include "cogl-depth-state-private.h"
|
||||||
#include "cogl-pipeline-state-private.h"
|
#include "cogl-pipeline-state-private.h"
|
||||||
|
#include "cogl-snippet-private.h"
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
|
||||||
@ -339,6 +340,41 @@ _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
|
||||||
|
_cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0,
|
||||||
|
CoglPipeline *authority1)
|
||||||
|
{
|
||||||
|
return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
|
||||||
|
vertex_snippets,
|
||||||
|
&authority1->big_state->
|
||||||
|
vertex_snippets);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0,
|
||||||
|
CoglPipeline *authority1)
|
||||||
|
{
|
||||||
|
return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
|
||||||
|
fragment_snippets,
|
||||||
|
&authority1->big_state->
|
||||||
|
fragment_snippets);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cogl_pipeline_get_color (CoglPipeline *pipeline,
|
cogl_pipeline_get_color (CoglPipeline *pipeline,
|
||||||
CoglColor *color)
|
CoglColor *color)
|
||||||
@ -1548,6 +1584,114 @@ 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
|
||||||
|
_cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline,
|
||||||
|
CoglPipelineSnippetHook hook,
|
||||||
|
CoglSnippet *snippet)
|
||||||
|
{
|
||||||
|
CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS;
|
||||||
|
|
||||||
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
||||||
|
g_return_if_fail (cogl_is_snippet (snippet));
|
||||||
|
|
||||||
|
/* - Flush journal primitives referencing the current state.
|
||||||
|
* - Make sure the pipeline has no dependants so it may be modified.
|
||||||
|
* - If the pipeline isn't currently an authority for the state being
|
||||||
|
* changed, then initialize that state from the current authority.
|
||||||
|
*/
|
||||||
|
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
|
||||||
|
|
||||||
|
_cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets,
|
||||||
|
hook,
|
||||||
|
snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline,
|
||||||
|
CoglSnippet *snippet)
|
||||||
|
{
|
||||||
|
_cogl_pipeline_add_vertex_snippet (pipeline,
|
||||||
|
COGL_PIPELINE_SNIPPET_HOOK_VERTEX,
|
||||||
|
snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline,
|
||||||
|
CoglPipelineSnippetHook hook,
|
||||||
|
CoglSnippet *snippet)
|
||||||
|
{
|
||||||
|
CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS;
|
||||||
|
|
||||||
|
g_return_if_fail (cogl_is_pipeline (pipeline));
|
||||||
|
g_return_if_fail (cogl_is_snippet (snippet));
|
||||||
|
|
||||||
|
/* - Flush journal primitives referencing the current state.
|
||||||
|
* - Make sure the pipeline has no dependants so it may be modified.
|
||||||
|
* - If the pipeline isn't currently an authority for the state being
|
||||||
|
* changed, then initialize that state from the current authority.
|
||||||
|
*/
|
||||||
|
_cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
|
||||||
|
|
||||||
|
_cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets,
|
||||||
|
hook,
|
||||||
|
snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_pipeline_add_fragment_hook (CoglPipeline *pipeline,
|
||||||
|
CoglSnippet *snippet)
|
||||||
|
{
|
||||||
|
_cogl_pipeline_add_fragment_snippet (pipeline,
|
||||||
|
COGL_PIPELINE_SNIPPET_HOOK_FRAGMENT,
|
||||||
|
snippet);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
CoglPipeline *authority =
|
||||||
|
_cogl_pipeline_get_authority (pipeline,
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS);
|
||||||
|
|
||||||
|
return !COGL_LIST_EMPTY (&authority->big_state->vertex_snippets);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
CoglPipeline *authority =
|
||||||
|
_cogl_pipeline_get_authority (pipeline,
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
|
||||||
|
|
||||||
|
return !COGL_LIST_EMPTY (&authority->big_state->fragment_snippets);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_pipeline_hash_color_state (CoglPipeline *authority,
|
_cogl_pipeline_hash_color_state (CoglPipeline *authority,
|
||||||
CoglPipelineHashState *state)
|
CoglPipelineHashState *state)
|
||||||
@ -1828,3 +1972,38 @@ _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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority,
|
||||||
|
CoglPipelineHashState *state)
|
||||||
|
{
|
||||||
|
_cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
|
||||||
|
state);
|
||||||
|
}
|
||||||
|
@ -937,6 +937,64 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
|
|||||||
gboolean transpose,
|
gboolean transpose,
|
||||||
const float *value);
|
const float *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pipeline_add_vertex_hook:
|
||||||
|
* @pipeline: A #CoglPipeline
|
||||||
|
* @snippet: The #CoglSnippet to add to the vertex processing hook
|
||||||
|
*
|
||||||
|
* Adds a shader snippet that will hook on to the vertex processing
|
||||||
|
* stage of @pipeline. This gives a chance for the application to
|
||||||
|
* modify the vertex attributes generated by the shader. Typically the
|
||||||
|
* snippet will modify cogl_color_out or cogl_position_out builtins.
|
||||||
|
*
|
||||||
|
* The ‘declarations’ string in @snippet will be inserted in the
|
||||||
|
* global scope of the shader. Use this to declare any uniforms,
|
||||||
|
* attributes or functions that the snippet requires.
|
||||||
|
*
|
||||||
|
* The ‘pre’ string in @snippet will be inserted at the top of the
|
||||||
|
* main() function before any vertex processing is done.
|
||||||
|
*
|
||||||
|
* The ‘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
|
||||||
|
* Stability: Unstable
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline,
|
||||||
|
CoglSnippet *snippet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_pipeline_add_fragment_hook:
|
||||||
|
* @pipeline: A #CoglPipeline
|
||||||
|
* @snippet: The #CoglSnippet to add to the fragment processing hook
|
||||||
|
*
|
||||||
|
* Adds a shader snippet that will hook on to the fragment processing
|
||||||
|
* stage of @pipeline. This gives a chance for the application to
|
||||||
|
* modify the fragment color generated by the shader. Typically the
|
||||||
|
* snippet will modify cogl_color_out.
|
||||||
|
*
|
||||||
|
* The ‘declarations’ string in @snippet will be inserted in the
|
||||||
|
* global scope of the shader. Use this to declare any uniforms,
|
||||||
|
* attributes or functions that the snippet requires.
|
||||||
|
*
|
||||||
|
* The ‘pre’ string in @snippet will be inserted at the top of the
|
||||||
|
* main() function before any fragment processing is done.
|
||||||
|
*
|
||||||
|
* The ‘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);
|
||||||
|
|
||||||
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
|
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
#include "cogl-pipeline-private.h"
|
#include "cogl-pipeline-private.h"
|
||||||
|
#include "cogl-pipeline-state-private.h"
|
||||||
#include "cogl-pipeline-opengl-private.h"
|
#include "cogl-pipeline-opengl-private.h"
|
||||||
|
|
||||||
#ifdef COGL_PIPELINE_VERTEND_FIXED
|
#ifdef COGL_PIPELINE_VERTEND_FIXED
|
||||||
@ -59,6 +60,10 @@ _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
|
|||||||
if (ctx->driver == COGL_DRIVER_GLES2)
|
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* Vertex snippets are only supported in the GLSL fragend */
|
||||||
|
if (_cogl_pipeline_has_vertex_snippets (pipeline))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* If there is a user program with a vertex shader then the
|
/* If there is a user program with a vertex shader then the
|
||||||
appropriate backend for that language should handle it. We can
|
appropriate backend for that language should handle it. We can
|
||||||
still use the fixed vertex backend if the program only contains
|
still use the fixed vertex backend if the program only contains
|
||||||
|
@ -128,6 +128,16 @@ _cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CoglPipelineSnippetList *
|
||||||
|
get_vertex_snippets (CoglPipeline *pipeline)
|
||||||
|
{
|
||||||
|
pipeline =
|
||||||
|
_cogl_pipeline_get_authority (pipeline,
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS);
|
||||||
|
|
||||||
|
return &pipeline->big_state->vertex_snippets;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
||||||
int n_layers,
|
int n_layers,
|
||||||
@ -136,6 +146,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||||||
{
|
{
|
||||||
CoglPipelineShaderState *shader_state;
|
CoglPipelineShaderState *shader_state;
|
||||||
CoglPipeline *template_pipeline = NULL;
|
CoglPipeline *template_pipeline = NULL;
|
||||||
|
CoglPipelineSnippet *snippet;
|
||||||
CoglProgram *user_program;
|
CoglProgram *user_program;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
@ -254,6 +265,37 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||||||
"main ()\n"
|
"main ()\n"
|
||||||
"{\n");
|
"{\n");
|
||||||
|
|
||||||
|
COGL_LIST_FOREACH (snippet, get_vertex_snippets (pipeline), list_node)
|
||||||
|
{
|
||||||
|
const char *declarations =
|
||||||
|
cogl_snippet_get_declarations (snippet->snippet);
|
||||||
|
|
||||||
|
/* Add all of the declarations for vertex snippets */
|
||||||
|
if (declarations)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->header, declarations);
|
||||||
|
g_string_append_c (shader_state->header, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add all of the pre-hooks for vertex processing */
|
||||||
|
if (snippet->hook == COGL_PIPELINE_SNIPPET_HOOK_VERTEX)
|
||||||
|
{
|
||||||
|
const char *pre =
|
||||||
|
cogl_snippet_get_pre (snippet->snippet);
|
||||||
|
|
||||||
|
if (pre)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
g_string_append (shader_state->source, pre);
|
||||||
|
g_string_append (shader_state->source, " }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enclose the generated vertex processing in a block so that any
|
||||||
|
variables declared in it won't be in the scope of the snippets */
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
|
||||||
if (ctx->driver == COGL_DRIVER_GLES2)
|
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||||
/* There is no builtin uniform for the pointsize on GLES2 so we need
|
/* There is no builtin uniform for the pointsize on GLES2 so we need
|
||||||
to copy it from the custom uniform in the vertex shader */
|
to copy it from the custom uniform in the vertex shader */
|
||||||
@ -350,6 +392,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
|||||||
GLint lengths[2];
|
GLint lengths[2];
|
||||||
GLint compile_status;
|
GLint compile_status;
|
||||||
GLuint shader;
|
GLuint shader;
|
||||||
|
CoglPipelineSnippet *snippet;
|
||||||
|
|
||||||
COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
|
COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
|
||||||
"glsl vertex compile counter",
|
"glsl vertex compile counter",
|
||||||
@ -363,7 +406,24 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
|||||||
"cogl_modelview_projection_matrix * "
|
"cogl_modelview_projection_matrix * "
|
||||||
"cogl_position_in;\n"
|
"cogl_position_in;\n"
|
||||||
" cogl_color_out = cogl_color_in;\n"
|
" cogl_color_out = cogl_color_in;\n"
|
||||||
"}\n");
|
" }\n");
|
||||||
|
|
||||||
|
/* Add all of the post-hooks for vertex processing */
|
||||||
|
COGL_LIST_FOREACH (snippet, get_vertex_snippets (pipeline), list_node)
|
||||||
|
if (snippet->hook == COGL_PIPELINE_SNIPPET_HOOK_VERTEX)
|
||||||
|
{
|
||||||
|
const char *post =
|
||||||
|
cogl_snippet_get_post (snippet->snippet);
|
||||||
|
|
||||||
|
if (post)
|
||||||
|
{
|
||||||
|
g_string_append (shader_state->source, " {\n");
|
||||||
|
g_string_append (shader_state->source, post);
|
||||||
|
g_string_append (shader_state->source, " }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append (shader_state->source, "}\n");
|
||||||
|
|
||||||
GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
|
GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
|
||||||
|
|
||||||
|
@ -444,6 +444,22 @@ 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)
|
||||||
{
|
{
|
||||||
@ -488,6 +504,12 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
|
|||||||
g_list_free (pipeline->layer_differences);
|
g_list_free (pipeline->layer_differences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pipeline->differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
|
||||||
|
_cogl_pipeline_snippet_list_free (&pipeline->big_state->vertex_snippets);
|
||||||
|
|
||||||
|
if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||||
|
_cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets);
|
||||||
|
|
||||||
g_list_free (pipeline->deprecated_get_layers_list);
|
g_list_free (pipeline->deprecated_get_layers_list);
|
||||||
|
|
||||||
recursively_free_layer_caches (pipeline);
|
recursively_free_layer_caches (pipeline);
|
||||||
@ -830,6 +852,30 @@ _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,
|
||||||
@ -973,6 +1019,14 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest,
|
|||||||
_cogl_bitmask_init (&big_state->uniforms_state.changed_mask);
|
_cogl_bitmask_init (&big_state->uniforms_state.changed_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
|
||||||
|
_cogl_pipeline_snippet_list_copy (&big_state->vertex_snippets,
|
||||||
|
&src->big_state->vertex_snippets);
|
||||||
|
|
||||||
|
if (differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
|
||||||
|
_cogl_pipeline_snippet_list_copy (&big_state->fragment_snippets,
|
||||||
|
&src->big_state->fragment_snippets);
|
||||||
|
|
||||||
/* XXX: we shouldn't bother doing this in most cases since
|
/* XXX: we shouldn't bother doing this in most cases since
|
||||||
* _copy_differences is typically used to initialize pipeline state
|
* _copy_differences is typically used to initialize pipeline state
|
||||||
* by copying it from the current authority, so it's not actually
|
* by copying it from the current authority, so it's not actually
|
||||||
@ -1066,6 +1120,16 @@ _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
|
|||||||
uniforms_state->override_values = NULL;
|
uniforms_state->override_values = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case COGL_PIPELINE_STATE_VERTEX_SNIPPETS:
|
||||||
|
_cogl_pipeline_snippet_list_copy (&pipeline->big_state->vertex_snippets,
|
||||||
|
&authority->big_state->vertex_snippets);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS:
|
||||||
|
_cogl_pipeline_snippet_list_copy (&pipeline->big_state->fragment_snippets,
|
||||||
|
&authority->big_state->
|
||||||
|
fragment_snippets);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2260,6 +2324,18 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
|
|||||||
_cogl_pipeline_uniforms_state_equal))
|
_cogl_pipeline_uniforms_state_equal))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
if (!simple_property_equal (authorities0, authorities1,
|
||||||
|
pipelines_difference,
|
||||||
|
COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX,
|
||||||
|
_cogl_pipeline_vertex_snippets_state_equal))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!simple_property_equal (authorities0, authorities1,
|
||||||
|
pipelines_difference,
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX,
|
||||||
|
_cogl_pipeline_fragment_snippets_state_equal))
|
||||||
|
goto done;
|
||||||
|
|
||||||
if (pipelines_difference & COGL_PIPELINE_STATE_LAYERS)
|
if (pipelines_difference & COGL_PIPELINE_STATE_LAYERS)
|
||||||
{
|
{
|
||||||
CoglPipelineStateIndex state_index = COGL_PIPELINE_STATE_LAYERS_INDEX;
|
CoglPipelineStateIndex state_index = COGL_PIPELINE_STATE_LAYERS_INDEX;
|
||||||
@ -2669,9 +2745,13 @@ _cogl_pipeline_init_state_hash_functions (void)
|
|||||||
_cogl_pipeline_hash_logic_ops_state;
|
_cogl_pipeline_hash_logic_ops_state;
|
||||||
state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] =
|
state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] =
|
||||||
_cogl_pipeline_hash_uniforms_state;
|
_cogl_pipeline_hash_uniforms_state;
|
||||||
|
state_hash_functions[COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX] =
|
||||||
|
_cogl_pipeline_hash_vertex_snippets_state;
|
||||||
|
state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] =
|
||||||
|
_cogl_pipeline_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_STATE_SPARSE_COUNT == 14);
|
g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
@ -2860,7 +2940,8 @@ CoglPipelineState
|
|||||||
_cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context)
|
_cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context)
|
||||||
{
|
{
|
||||||
CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS |
|
CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS |
|
||||||
COGL_PIPELINE_STATE_USER_SHADER);
|
COGL_PIPELINE_STATE_USER_SHADER |
|
||||||
|
COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
|
||||||
|
|
||||||
if (context->driver == COGL_DRIVER_GLES2)
|
if (context->driver == COGL_DRIVER_GLES2)
|
||||||
state |= COGL_PIPELINE_STATE_ALPHA_FUNC;
|
state |= COGL_PIPELINE_STATE_ALPHA_FUNC;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define __COGL_PIPELINE_H__
|
#define __COGL_PIPELINE_H__
|
||||||
|
|
||||||
#include <cogl/cogl-types.h>
|
#include <cogl/cogl-types.h>
|
||||||
|
#include <cogl/cogl-snippet.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user