Flush matrices in the progend and flip with a vector

Previously flushing the matrices was performed as part of the
framebuffer state. When on GLES2 this matrix flushing is actually
diverted so that it only keeps a reference to the intended matrix
stack. This is necessary because on GLES2 there are no builtin
uniforms so it can't actually flush the matrices until the program for
the pipeline is generated. When the matrices are flushed it would
store the age of modifications on the matrix stack so that it could
detect when the matrix hasn't changed and avoid flushing it.

This patch changes it so that the pipeline is responsible for flushing
the matrices even when we are using the GL builtins. The same
mechanism for detecting unmodified matrix stacks is used in all
cases. There is a new CoglMatrixStackCache type which is used to store
a reference to the intended matrix stack along with its last flushed
age. There are now two of these attached to the CoglContext to track
the flushed state for the global matrix builtins and also two for each
glsl progend program state to track the flushed state for a
program. The framebuffer matrix flush now just updates the intended
matrix stacks without actually trying to flush.

When a vertex snippet is attached to the pipeline, the GLSL vertend
will now avoid using the projection matrix to flip the rendering. This
is necessary because any vertex snippet may cause the projection
matrix not to be used. Instead the flip is done as a forced final step
by multiplying cogl_position_out by a vec4 uniform. This uniform is
updated as part of the progend pre_paint depending on whether the
framebuffer is offscreen or not.

Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-11-29 14:21:07 +00:00 committed by Robert Bragg
parent 7590fc3ec3
commit f005f517fe
15 changed files with 558 additions and 356 deletions

View File

@ -271,6 +271,8 @@ cogl_sources_c = \
$(srcdir)/cogl-pipeline-vertend-glsl-private.h \ $(srcdir)/cogl-pipeline-vertend-glsl-private.h \
$(srcdir)/cogl-pipeline-vertend-fixed.c \ $(srcdir)/cogl-pipeline-vertend-fixed.c \
$(srcdir)/cogl-pipeline-vertend-fixed-private.h \ $(srcdir)/cogl-pipeline-vertend-fixed-private.h \
$(srcdir)/cogl-pipeline-progend-fixed.c \
$(srcdir)/cogl-pipeline-progend-fixed-private.h \
$(srcdir)/cogl-pipeline-progend-glsl.c \ $(srcdir)/cogl-pipeline-progend-glsl.c \
$(srcdir)/cogl-pipeline-progend-glsl-private.h \ $(srcdir)/cogl-pipeline-progend-glsl-private.h \
$(srcdir)/cogl-pipeline-snippet-private.h \ $(srcdir)/cogl-pipeline-snippet-private.h \

View File

@ -109,7 +109,13 @@ set_clip_plane (CoglFramebuffer *framebuffer,
_cogl_matrix_stack_translate (modelview_stack, _cogl_matrix_stack_translate (modelview_stack,
-vertex_a[0], -vertex_a[1], -vertex_a[2]); -vertex_a[0], -vertex_a[1], -vertex_a[2]);
_cogl_matrix_stack_flush_to_gl (ctx, modelview_stack, COGL_MATRIX_MODELVIEW); /* Clip planes can only be used when a fixed function backend is in
use so we know we can directly push this matrix to the builtin
state */
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
modelview_stack,
COGL_MATRIX_MODELVIEW,
FALSE /* don't disable flip */);
planef[0] = 0; planef[0] = 0;
planef[1] = -1.0; planef[1] = -1.0;
@ -218,12 +224,8 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
/* This can be called from the journal code which doesn't flush /* This can be called from the journal code which doesn't flush
the matrix stacks between calls so we need to ensure they're the matrix stacks between calls so we need to ensure they're
flushed now */ flushed now */
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_projection (ctx, projection_stack);
modelview_stack, _cogl_context_set_current_modelview (ctx, modelview_stack);
COGL_MATRIX_MODELVIEW);
_cogl_matrix_stack_flush_to_gl (ctx,
projection_stack,
COGL_MATRIX_PROJECTION);
if (first) if (first)
{ {
@ -258,12 +260,8 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
_cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_projection (ctx, projection_stack);
modelview_stack, _cogl_context_set_current_modelview (ctx, modelview_stack);
COGL_MATRIX_MODELVIEW);
_cogl_matrix_stack_flush_to_gl (ctx,
projection_stack,
COGL_MATRIX_PROJECTION);
_cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);
@ -301,12 +299,8 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
/* This can be called from the clip stack code which doesn't flush /* This can be called from the clip stack code which doesn't flush
the matrix stacks between calls so we need to ensure they're the matrix stacks between calls so we need to ensure they're
flushed now */ flushed now */
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_projection (ctx, projection_stack);
modelview_stack, _cogl_context_set_current_modelview (ctx, modelview_stack);
COGL_MATRIX_MODELVIEW);
_cogl_matrix_stack_flush_to_gl (ctx,
projection_stack,
COGL_MATRIX_PROJECTION);
/* Just setup a simple pipeline that doesn't use texturing... */ /* Just setup a simple pipeline that doesn't use texturing... */
_cogl_push_source (ctx->stencil_pipeline, FALSE); _cogl_push_source (ctx->stencil_pipeline, FALSE);
@ -366,15 +360,9 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
_cogl_matrix_stack_push (projection_stack); _cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (projection_stack); _cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_flush_to_gl (ctx,
projection_stack,
COGL_MATRIX_PROJECTION);
_cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx,
modelview_stack,
COGL_MATRIX_MODELVIEW);
_cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);
_cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);

View File

@ -94,16 +94,18 @@ struct _CoglContext
CoglMatrix identity_matrix; CoglMatrix identity_matrix;
CoglMatrix y_flip_matrix; CoglMatrix y_flip_matrix;
/* Client-side matrix stack or NULL if none */ /* Value that was last used when calling glMatrixMode to avoid
calling it multiple times */
CoglMatrixMode flushed_matrix_mode; CoglMatrixMode flushed_matrix_mode;
/* On GLES2 we need to track the matrices separately because the are /* The matrix stack that should be used for the next render */
stored in GLSL uniforms rather than using the fixed function CoglMatrixStack *current_projection_stack;
API. We keep track of the matrix stack that Cogl is trying to CoglMatrixStack *current_modelview_stack;
flush so we can flush it later after the program is generated. A
reference is taken on the stacks. */ /* The last matrix stack with age that was flushed to the GL matrix
CoglMatrixStack *flushed_modelview_stack; builtins */
CoglMatrixStack *flushed_projection_stack; CoglMatrixStackCache builtin_flushed_projection;
CoglMatrixStackCache builtin_flushed_modelview;
GArray *texture_units; GArray *texture_units;
int active_texture_unit; int active_texture_unit;
@ -320,4 +322,12 @@ if (ctxvar == NULL) return retval;
#define NO_RETVAL #define NO_RETVAL
void
_cogl_context_set_current_projection (CoglContext *context,
CoglMatrixStack *stack);
void
_cogl_context_set_current_modelview (CoglContext *context,
CoglMatrixStack *stack);
#endif /* __COGL_CONTEXT_PRIVATE_H */ #endif /* __COGL_CONTEXT_PRIVATE_H */

View File

@ -371,10 +371,10 @@ cogl_context_new (CoglDisplay *display,
GE (context, glEnable (GL_ALPHA_TEST)); GE (context, glEnable (GL_ALPHA_TEST));
#endif #endif
#ifdef HAVE_COGL_GLES2 _context->current_modelview_stack = NULL;
_context->flushed_modelview_stack = NULL; _context->current_projection_stack = NULL;
_context->flushed_projection_stack = NULL; _cogl_matrix_stack_init_cache (&_context->builtin_flushed_projection);
#endif _cogl_matrix_stack_init_cache (&_context->builtin_flushed_modelview);
/* Create default textures used for fall backs */ /* Create default textures used for fall backs */
context->default_gl_texture_2d_tex = context->default_gl_texture_2d_tex =
@ -491,12 +491,12 @@ _cogl_context_free (CoglContext *context)
g_slist_free (context->texture_types); g_slist_free (context->texture_types);
g_slist_free (context->buffer_types); g_slist_free (context->buffer_types);
#ifdef HAVE_COGL_GLES2 if (_context->current_modelview_stack)
if (_context->flushed_modelview_stack) cogl_object_unref (_context->current_modelview_stack);
cogl_object_unref (_context->flushed_modelview_stack); if (_context->current_projection_stack)
if (_context->flushed_projection_stack) cogl_object_unref (_context->current_projection_stack);
cogl_object_unref (_context->flushed_projection_stack); _cogl_matrix_stack_destroy_cache (&context->builtin_flushed_projection);
#endif _cogl_matrix_stack_destroy_cache (&context->builtin_flushed_modelview);
cogl_pipeline_cache_free (context->pipeline_cache); cogl_pipeline_cache_free (context->pipeline_cache);
@ -569,3 +569,23 @@ _cogl_context_update_features (CoglContext *context,
g_assert_not_reached (); g_assert_not_reached ();
} }
void
_cogl_context_set_current_projection (CoglContext *context,
CoglMatrixStack *stack)
{
cogl_object_ref (stack);
if (context->current_projection_stack)
cogl_object_unref (context->current_projection_stack);
context->current_projection_stack = stack;
}
void
_cogl_context_set_current_modelview (CoglContext *context,
CoglMatrixStack *stack)
{
cogl_object_ref (stack);
if (context->current_modelview_stack)
cogl_object_unref (context->current_modelview_stack);
context->current_modelview_stack = stack;
}

View File

@ -1382,20 +1382,20 @@ static unsigned long
_cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a, _cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a,
CoglFramebuffer *b) CoglFramebuffer *b)
{ {
if (!_cogl_matrix_stack_equal (a->modelview_stack, b->modelview_stack)) /* We always want to flush the modelview state. All this does is set
return COGL_FRAMEBUFFER_STATE_MODELVIEW; the current modelview stack on the context to the framebuffer's
else stack. */
return 0; return COGL_FRAMEBUFFER_STATE_MODELVIEW;
} }
static unsigned long static unsigned long
_cogl_framebuffer_compare_projection_state (CoglFramebuffer *a, _cogl_framebuffer_compare_projection_state (CoglFramebuffer *a,
CoglFramebuffer *b) CoglFramebuffer *b)
{ {
if (!_cogl_matrix_stack_equal (a->projection_stack, b->projection_stack)) /* We always want to flush the projection state. All this does is
return COGL_FRAMEBUFFER_STATE_MODELVIEW; set the current projection stack on the context to the
else framebuffer's stack. */
return 0; return COGL_FRAMEBUFFER_STATE_PROJECTION;
} }
static unsigned long static unsigned long
@ -1533,17 +1533,15 @@ _cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer)
static void static void
_cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer) _cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
{ {
_cogl_matrix_stack_flush_to_gl (framebuffer->context, _cogl_context_set_current_modelview (framebuffer->context,
framebuffer->modelview_stack, framebuffer->modelview_stack);
COGL_MATRIX_MODELVIEW);
} }
static void static void
_cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer) _cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
{ {
_cogl_matrix_stack_flush_to_gl (framebuffer->context, _cogl_context_set_current_projection (framebuffer->context,
framebuffer->projection_stack, framebuffer->projection_stack);
COGL_MATRIX_PROJECTION);
} }
static void static void

View File

@ -292,9 +292,7 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
{ {
_cogl_matrix_stack_set (state->modelview_stack, _cogl_matrix_stack_set (state->modelview_stack,
&batch_start->model_view); &batch_start->model_view);
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_modelview (ctx, state->modelview_stack);
state->modelview_stack,
COGL_MATRIX_MODELVIEW);
} }
attributes = (CoglAttribute **)state->attributes->data; attributes = (CoglAttribute **)state->attributes->data;
@ -725,17 +723,13 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))) if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))))
{ {
_cogl_matrix_stack_load_identity (state->modelview_stack); _cogl_matrix_stack_load_identity (state->modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_modelview (ctx, state->modelview_stack);
state->modelview_stack,
COGL_MATRIX_MODELVIEW);
} }
/* Setting up the clip state can sometimes also flush the projection /* Setting up the clip state can sometimes also flush the projection
matrix so we should flush it again. This will be a no-op if the matrix so we should flush it again. This will be a no-op if the
clip code didn't modify the projection */ clip code didn't modify the projection */
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_context_set_current_projection (ctx, state->projection_stack);
state->projection_stack,
COGL_MATRIX_PROJECTION);
batch_and_call (batch_start, batch_and_call (batch_start,
batch_len, batch_len,

View File

@ -362,124 +362,117 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack,
stack->age++; stack->age++;
} }
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
static void static void
flush_to_fixed_api_gl (CoglContext *context, _cogl_matrix_stack_flush_matrix_to_gl_builtin (CoglContext *ctx,
gboolean is_identity, gboolean is_identity,
const CoglMatrix *matrix, CoglMatrix *matrix,
void *user_data) CoglMatrixMode mode)
{ {
if (is_identity) g_assert (ctx->driver == COGL_DRIVER_GL ||
GE (context, glLoadIdentity ()); ctx->driver == COGL_DRIVER_GLES1);
else
GE (context, glLoadMatrixf (cogl_matrix_get_array (matrix)) );
}
#endif #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
if (ctx->flushed_matrix_mode != mode)
void
_cogl_prepare_matrix_stack_for_flush (CoglContext *context,
CoglMatrixStack *stack,
CoglMatrixMode mode,
CoglMatrixStackFlushFunc callback,
void *user_data)
{
CoglMatrixState *state = _cogl_matrix_stack_top (stack);
/* Because Cogl defines texture coordinates to have a top left origin and
* because offscreen framebuffers may be used for rendering to textures we
* always render upside down to offscreen buffers.
*/
if (mode == COGL_MATRIX_PROJECTION &&
cogl_is_offscreen (cogl_get_draw_framebuffer ()))
{ {
CoglMatrix flipped_projection; GLenum gl_mode = 0;
CoglMatrix *projection =
state->is_identity ? &context->identity_matrix : &state->matrix;
cogl_matrix_multiply (&flipped_projection,
&context->y_flip_matrix, projection);
callback (context, FALSE, &flipped_projection, user_data);
}
else
{
CoglMatrix *modelview =
state->is_identity ? &context->identity_matrix : &state->matrix;
callback (context, state->is_identity, modelview, user_data);
}
}
void
_cogl_matrix_stack_flush_to_gl (CoglContext *context,
CoglMatrixStack *stack,
CoglMatrixMode mode)
{
if (context->driver == COGL_DRIVER_GLES2)
{
/* Under GLES2 we need to flush the matrices differently because
they are stored in uniforms attached to the program instead of
the global GL context state. At this point we can't be sure that
the right program will be generated so instead we'll just store a
reference to the matrix stack that is intended to be flushed and
update the uniform once the program is ready. */
switch (mode) switch (mode)
{ {
case COGL_MATRIX_MODELVIEW: case COGL_MATRIX_MODELVIEW:
cogl_object_ref (stack); gl_mode = GL_MODELVIEW;
if (context->flushed_modelview_stack)
cogl_object_unref (context->flushed_modelview_stack);
context->flushed_modelview_stack = stack;
break; break;
case COGL_MATRIX_PROJECTION: case COGL_MATRIX_PROJECTION:
cogl_object_ref (stack); gl_mode = GL_PROJECTION;
if (context->flushed_projection_stack)
cogl_object_unref (context->flushed_projection_stack);
context->flushed_projection_stack = stack;
break; break;
case COGL_MATRIX_TEXTURE: case COGL_MATRIX_TEXTURE:
/* This shouldn't happen because the texture matrices are gl_mode = GL_TEXTURE;
handled by the GLSL pipeline backend */
g_assert_not_reached ();
break; break;
} }
GE (ctx, glMatrixMode (gl_mode));
ctx->flushed_matrix_mode = mode;
} }
if (is_identity)
GE (ctx, glLoadIdentity ());
else
GE (ctx, glLoadMatrixf (cogl_matrix_get_array (matrix)));
#endif
}
void
_cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx,
CoglMatrixStack *stack,
CoglMatrixMode mode,
gboolean disable_flip)
{
g_assert (ctx->driver == COGL_DRIVER_GL ||
ctx->driver == COGL_DRIVER_GLES1);
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
else {
{ gboolean needs_flip;
if (context->flushed_matrix_mode != mode) CoglMatrixState *state;
{ CoglMatrixStackCache *cache;
GLenum gl_mode = 0;
switch (mode) state = _cogl_matrix_stack_top (stack);
{
case COGL_MATRIX_MODELVIEW:
gl_mode = GL_MODELVIEW;
break;
case COGL_MATRIX_PROJECTION: if (mode == COGL_MATRIX_PROJECTION)
gl_mode = GL_PROJECTION; {
break; /* Because Cogl defines texture coordinates to have a top left
* origin and because offscreen framebuffers may be used for
* rendering to textures we always render upside down to
* offscreen buffers. Also for some backends we need to render
* onscreen buffers upside-down too.
*/
if (disable_flip)
needs_flip = FALSE;
else
needs_flip = cogl_is_offscreen (cogl_get_draw_framebuffer ());
case COGL_MATRIX_TEXTURE: cache = &ctx->builtin_flushed_projection;
gl_mode = GL_TEXTURE; }
break; else
} {
needs_flip = FALSE;
GE (context, glMatrixMode (gl_mode)); if (mode == COGL_MATRIX_MODELVIEW)
context->flushed_matrix_mode = mode; cache = &ctx->builtin_flushed_modelview;
} else
cache = NULL;
}
_cogl_prepare_matrix_stack_for_flush (context, /* We don't need to do anything if the state is the same */
stack, if (!cache ||
mode, _cogl_matrix_stack_check_and_update_cache (stack, cache, needs_flip))
flush_to_fixed_api_gl, {
stack); gboolean is_identity = state->is_identity && !needs_flip;
}
if (needs_flip)
{
CoglMatrix flipped_matrix;
cogl_matrix_multiply (&flipped_matrix,
&ctx->y_flip_matrix,
state->is_identity ?
&ctx->identity_matrix :
&state->matrix);
_cogl_matrix_stack_flush_matrix_to_gl_builtin (ctx,
/* not identity */
FALSE,
&flipped_matrix,
mode);
}
else
_cogl_matrix_stack_flush_matrix_to_gl_builtin (ctx,
is_identity,
&state->matrix,
mode);
}
}
#endif #endif
} }
@ -510,3 +503,51 @@ _cogl_matrix_stack_equal (CoglMatrixStack *stack0,
else else
return cogl_matrix_equal (&state0->matrix, &state1->matrix); return cogl_matrix_equal (&state0->matrix, &state1->matrix);
} }
gboolean
_cogl_matrix_stack_check_and_update_cache (CoglMatrixStack *stack,
CoglMatrixStackCache *cache,
gboolean flip)
{
gboolean is_identity =
_cogl_matrix_stack_has_identity_flag (stack) && !flip;
gboolean is_dirty;
if (is_identity && cache->flushed_identity)
is_dirty = FALSE;
else if (cache->stack == NULL ||
cache->stack->age != cache->age ||
flip != cache->flipped)
is_dirty = TRUE;
else
is_dirty = (cache->stack != stack &&
!_cogl_matrix_stack_equal (cache->stack, stack));
/* We'll update the cache values even if the stack isn't dirty in
case the reason it wasn't dirty is because we compared the
matrices and found them to be the same. In that case updating the
cache values will avoid the comparison next time */
cache->age = stack->age;
cogl_object_ref (stack);
if (cache->stack)
cogl_object_unref (cache->stack);
cache->stack = stack;
cache->flushed_identity = is_identity;
cache->flipped = flip;
return is_dirty;
}
void
_cogl_matrix_stack_init_cache (CoglMatrixStackCache *cache)
{
cache->stack = NULL;
cache->flushed_identity = FALSE;
}
void
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache)
{
if (cache->stack)
cogl_object_unref (cache->stack);
}

View File

@ -34,6 +34,14 @@
typedef struct _CoglMatrixStack CoglMatrixStack; typedef struct _CoglMatrixStack CoglMatrixStack;
typedef struct
{
CoglMatrixStack *stack;
unsigned int age;
gboolean flushed_identity;
gboolean flipped;
} CoglMatrixStackCache;
typedef enum { typedef enum {
COGL_MATRIX_MODELVIEW, COGL_MATRIX_MODELVIEW,
COGL_MATRIX_PROJECTION, COGL_MATRIX_PROJECTION,
@ -107,10 +115,12 @@ _cogl_matrix_stack_get (CoglMatrixStack *stack,
void void
_cogl_matrix_stack_set (CoglMatrixStack *stack, _cogl_matrix_stack_set (CoglMatrixStack *stack,
const CoglMatrix *matrix); const CoglMatrix *matrix);
void void
_cogl_matrix_stack_flush_to_gl (CoglContext *ctx, _cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx,
CoglMatrixStack *stack, CoglMatrixStack *stack,
CoglMatrixMode mode); CoglMatrixMode mode,
gboolean disable_flip);
unsigned int unsigned int
_cogl_matrix_stack_get_age (CoglMatrixStack *stack); _cogl_matrix_stack_get_age (CoglMatrixStack *stack);
@ -122,15 +132,19 @@ _cogl_matrix_stack_get_age (CoglMatrixStack *stack);
gboolean gboolean
_cogl_matrix_stack_has_identity_flag (CoglMatrixStack *stack); _cogl_matrix_stack_has_identity_flag (CoglMatrixStack *stack);
void
_cogl_prepare_matrix_stack_for_flush (CoglContext *context,
CoglMatrixStack *stack,
CoglMatrixMode mode,
CoglMatrixStackFlushFunc callback,
void *user_data);
gboolean gboolean
_cogl_matrix_stack_equal (CoglMatrixStack *stack0, _cogl_matrix_stack_equal (CoglMatrixStack *stack0,
CoglMatrixStack *stack1); CoglMatrixStack *stack1);
void
_cogl_matrix_stack_init_cache (CoglMatrixStackCache *cache);
gboolean
_cogl_matrix_stack_check_and_update_cache (CoglMatrixStack *stack,
CoglMatrixStackCache *cache,
gboolean flip);
void
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache);
#endif /* __COGL_MATRIX_STACK_H */ #endif /* __COGL_MATRIX_STACK_H */

View File

@ -137,11 +137,21 @@
/* If we have either of the GLSL backends then we also need a GLSL /* If we have either of the GLSL backends then we also need a GLSL
progend to combine the shaders generated into a single progend to combine the shaders generated into a single
program. Currently there is only one progend but if we ever add program. Same goes for the fixed progends which are used to flush
other languages they would likely need their own progend too. The the matrices */
progends are different from the other backends because there can be #ifdef COGL_PIPELINE_FRAGEND_FIXED
more than one in use for each pipeline. All of the progends are
invoked whenever a pipeline is flushed. */ #define COGL_PIPELINE_PROGEND_FIXED 0
#ifdef COGL_PIPELINE_FRAGEND_GLSL
#define COGL_PIPELINE_PROGEND_GLSL 1
#define COGL_PIPELINE_N_PROGENDS 2
#else
#define COGL_PIPELINE_N_PROGENDS 1
#endif
#else /* COGL_PIPELINE_FRAGEND_FIXED */
#ifdef COGL_PIPELINE_FRAGEND_GLSL #ifdef COGL_PIPELINE_FRAGEND_GLSL
#define COGL_PIPELINE_PROGEND_GLSL 0 #define COGL_PIPELINE_PROGEND_GLSL 0
#define COGL_PIPELINE_N_PROGENDS 1 #define COGL_PIPELINE_N_PROGENDS 1
@ -149,6 +159,8 @@
#define COGL_PIPELINE_N_PROGENDS 0 #define COGL_PIPELINE_N_PROGENDS 0
#endif #endif
#endif /* COGL_PIPELINE_FRAGEND_FIXED */
/* XXX: should I rename these as /* XXX: should I rename these as
* COGL_PIPELINE_STATE_INDEX_XYZ... ? * COGL_PIPELINE_STATE_INDEX_XYZ... ?
*/ */

View File

@ -0,0 +1,36 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifndef __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H
#define __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H
#include "cogl-pipeline-private.h"
extern const CoglPipelineProgend _cogl_pipeline_fixed_progend;
#endif /* __COGL_PIPELINE_PROGEND_FIXED_PRIVATE_H */

View File

@ -0,0 +1,69 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "cogl-pipeline-private.h"
#ifdef COGL_PIPELINE_PROGEND_FIXED
#include "cogl-context.h"
#include "cogl-context-private.h"
static void
_cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED)
return;
if (ctx->current_projection_stack)
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
ctx->current_projection_stack,
COGL_MATRIX_PROJECTION,
FALSE /* enable flip */);
if (ctx->current_modelview_stack)
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
ctx->current_modelview_stack,
COGL_MATRIX_MODELVIEW,
FALSE /* enable flip */);
}
const CoglPipelineProgend _cogl_pipeline_fixed_progend =
{
NULL, /* end */
NULL, /* pre_change_notify */
NULL, /* layer_pre_change_notify */
_cogl_pipeline_progend_fixed_pre_paint
};
#endif /* COGL_PIPELINE_PROGEND_FIXED */

View File

@ -48,6 +48,7 @@
#include "cogl-pipeline-cache.h" #include "cogl-pipeline-cache.h"
#include "cogl-pipeline-state-private.h" #include "cogl-pipeline-state-private.h"
#include "cogl-attribute-private.h" #include "cogl-attribute-private.h"
#include "cogl-framebuffer-private.h"
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
@ -121,11 +122,8 @@ typedef struct
GLint projection_uniform; GLint projection_uniform;
GLint mvp_uniform; GLint mvp_uniform;
CoglMatrixStack *flushed_modelview_stack; CoglMatrixStackCache projection_cache;
unsigned int flushed_modelview_stack_age; CoglMatrixStackCache modelview_cache;
gboolean flushed_modelview_is_identity;
CoglMatrixStack *flushed_projection_stack;
unsigned int flushed_projection_stack_age;
#endif #endif
/* We need to track the last pipeline that the program was used with /* We need to track the last pipeline that the program was used with
@ -140,6 +138,13 @@ typedef struct
/* Array of attribute locations. */ /* Array of attribute locations. */
GArray *attribute_locations; GArray *attribute_locations;
/* The 'flip' uniform is used to flip the geometry upside-down when
the framebuffer requires it only when there are vertex
snippets. Otherwise this is acheived using the projection
matrix */
GLint flip_uniform;
int flushed_flip_state;
UnitState *unit_state; UnitState *unit_state;
} CoglPipelineProgramState; } CoglPipelineProgramState;
@ -225,17 +230,10 @@ clear_attribute_cache (CoglPipelineProgramState *program_state)
static void static void
clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state) clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
{ {
if (program_state->flushed_modelview_stack) _cogl_matrix_stack_destroy_cache (&program_state->projection_cache);
{ _cogl_matrix_stack_init_cache (&program_state->projection_cache);
cogl_object_unref (program_state->flushed_modelview_stack); _cogl_matrix_stack_destroy_cache (&program_state->modelview_cache);
program_state->flushed_modelview_stack = NULL; _cogl_matrix_stack_init_cache (&program_state->modelview_cache);
}
if (program_state->flushed_projection_stack)
{
cogl_object_unref (program_state->flushed_projection_stack);
program_state->flushed_projection_stack = NULL;
}
program_state->flushed_modelview_is_identity = FALSE;
} }
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
@ -253,9 +251,8 @@ program_state_new (int n_layers)
program_state->uniform_locations = NULL; program_state->uniform_locations = NULL;
program_state->attribute_locations = NULL; program_state->attribute_locations = NULL;
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
program_state->flushed_modelview_stack = NULL; _cogl_matrix_stack_init_cache (&program_state->modelview_cache);
program_state->flushed_modelview_is_identity = FALSE; _cogl_matrix_stack_init_cache (&program_state->projection_cache);
program_state->flushed_projection_stack = NULL;
#endif #endif
return program_state; return program_state;
@ -282,7 +279,10 @@ destroy_program_state (void *user_data,
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
if (ctx->driver == COGL_DRIVER_GLES2) if (ctx->driver == COGL_DRIVER_GLES2)
clear_flushed_matrix_stacks (program_state); {
_cogl_matrix_stack_destroy_cache (&program_state->projection_cache);
_cogl_matrix_stack_destroy_cache (&program_state->modelview_cache);
}
#endif #endif
if (program_state->program) if (program_state->program)
@ -793,6 +793,10 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
get_uniform_cb, get_uniform_cb,
&state); &state);
clear_attribute_cache (program_state); clear_attribute_cache (program_state);
GE_RET (program_state->flip_uniform,
ctx, glGetUniformLocation (gl_program, "_cogl_flip_vector"));
program_state->flushed_flip_state = -1;
} }
state.unit = 0; state.unit = 0;
@ -923,174 +927,158 @@ _cogl_pipeline_progend_glsl_layer_pre_change_notify (
} }
} }
#ifdef HAVE_COGL_GLES2
static void
flush_modelview_cb (CoglContext *ctx,
gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
CoglPipelineProgramState *program_state = user_data;
GE( ctx, glUniformMatrix4fv (program_state->modelview_uniform, 1, FALSE,
cogl_matrix_get_array (matrix)) );
}
static void
flush_projection_cb (CoglContext *ctx,
gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
CoglPipelineProgramState *program_state = user_data;
GE( ctx, glUniformMatrix4fv (program_state->projection_uniform, 1, FALSE,
cogl_matrix_get_array (matrix)) );
}
typedef struct
{
CoglPipelineProgramState *program_state;
const CoglMatrix *projection_matrix;
} FlushCombinedData;
static void
flush_combined_step_two_cb (CoglContext *ctx,
gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
FlushCombinedData *data = user_data;
CoglMatrix mvp_matrix;
/* If the modelview is the identity then we can bypass the matrix
multiplication */
if (is_identity)
{
const float *array = cogl_matrix_get_array (data->projection_matrix);
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform,
1, FALSE, array ) );
}
else
{
cogl_matrix_multiply (&mvp_matrix,
data->projection_matrix,
matrix);
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform, 1, FALSE,
cogl_matrix_get_array (&mvp_matrix)) );
}
}
static void
flush_combined_step_one_cb (CoglContext *ctx,
gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
FlushCombinedData data;
data.program_state = user_data;
data.projection_matrix = matrix;
_cogl_prepare_matrix_stack_for_flush (ctx,
ctx->flushed_modelview_stack,
COGL_MATRIX_MODELVIEW,
flush_combined_step_two_cb,
&data);
}
static void static void
_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline) _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
{ {
CoglPipelineProgramState *program_state = get_program_state (pipeline); gboolean needs_flip;
gboolean modelview_changed; CoglMatrixStack *projection_stack;
gboolean projection_changed; CoglMatrixStack *modelview_stack;
CoglPipelineProgramState *program_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->driver != COGL_DRIVER_GLES2) if (pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
return; return;
/* We only need to update the matrices if we're using the the GLSL
vertend, but this is a requirement on GLES2 anyway */
_COGL_RETURN_IF_FAIL (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL);
program_state = get_program_state (pipeline); program_state = get_program_state (pipeline);
projection_stack = ctx->current_projection_stack;
modelview_stack = ctx->current_modelview_stack;
/* An initial pipeline is flushed while creating the context. At /* An initial pipeline is flushed while creating the context. At
this point there are no matrices flushed so we can't do this point there are no matrices selected so we can't do
anything */ anything */
if (ctx->flushed_modelview_stack == NULL || if (modelview_stack == NULL || projection_stack == NULL)
ctx->flushed_projection_stack == NULL)
return; return;
/* When flushing from the journal the modelview matrix is usually needs_flip = cogl_is_offscreen (cogl_get_draw_framebuffer ());
the identity matrix so it makes sense to optimise this case by
specifically checking whether we already have the identity matrix #ifdef HAVE_COGL_GLES2
which will catch a lot of common cases of redundant flushing */ if (ctx->driver == COGL_DRIVER_GLES2)
if (program_state->flushed_modelview_is_identity && {
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack)) gboolean modelview_changed;
modelview_changed = FALSE; gboolean projection_changed;
gboolean need_modelview;
gboolean need_projection;
CoglMatrix modelview, projection;
projection_changed =
_cogl_matrix_stack_check_and_update_cache (projection_stack,
&program_state->
projection_cache,
needs_flip &&
program_state->
flip_uniform == -1);
modelview_changed =
_cogl_matrix_stack_check_and_update_cache (modelview_stack,
&program_state->
modelview_cache,
/* never flip modelview */
FALSE);
if (modelview_changed || projection_changed)
{
if (program_state->mvp_uniform != -1)
need_modelview = need_projection = TRUE;
else
{
need_projection = (program_state->projection_uniform != -1 &&
projection_changed);
need_modelview = (program_state->modelview_uniform != -1 &&
modelview_changed);
}
if (need_modelview)
_cogl_matrix_stack_get (modelview_stack, &modelview);
if (need_projection)
{
if (needs_flip && program_state->flip_uniform == -1)
{
CoglMatrix tmp_matrix;
_cogl_matrix_stack_get (projection_stack, &tmp_matrix);
cogl_matrix_multiply (&projection,
&ctx->y_flip_matrix,
&tmp_matrix);
}
else
_cogl_matrix_stack_get (projection_stack, &projection);
}
if (projection_changed && program_state->projection_uniform != -1)
GE (ctx, glUniformMatrix4fv (program_state->projection_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&projection)));
if (modelview_changed && program_state->modelview_uniform != -1)
GE (ctx, glUniformMatrix4fv (program_state->modelview_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&modelview)));
if (program_state->mvp_uniform != -1)
{
/* The journal usually uses an identity matrix for the
modelview so we can optimise this common case by
avoiding the matrix multiplication */
if (_cogl_matrix_stack_has_identity_flag (modelview_stack))
{
GE (ctx,
glUniformMatrix4fv (program_state->mvp_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&projection)));
}
else
{
CoglMatrix combined;
cogl_matrix_multiply (&combined,
&projection,
&modelview);
GE (ctx,
glUniformMatrix4fv (program_state->mvp_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&combined)));
}
}
}
}
else else
modelview_changed = #endif
program_state->flushed_modelview_stack != ctx->flushed_modelview_stack ||
program_state->flushed_modelview_stack_age !=
_cogl_matrix_stack_get_age (program_state->flushed_modelview_stack);
projection_changed =
program_state->flushed_projection_stack != ctx->flushed_projection_stack ||
program_state->flushed_projection_stack_age !=
_cogl_matrix_stack_get_age (program_state->flushed_projection_stack);
if (modelview_changed)
{ {
cogl_object_ref (ctx->flushed_modelview_stack); gboolean disable_flip;
if (program_state->flushed_modelview_stack)
cogl_object_unref (program_state->flushed_modelview_stack);
program_state->flushed_modelview_stack = ctx->flushed_modelview_stack;
program_state->flushed_modelview_stack_age =
_cogl_matrix_stack_get_age (ctx->flushed_modelview_stack);
program_state->flushed_modelview_is_identity =
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack);
if (program_state->modelview_uniform != -1) /* If there are vertex snippets, then we'll disable flipping the
_cogl_prepare_matrix_stack_for_flush (ctx, geometry via the matrix and use the flip vertex instead */
program_state disable_flip = program_state->flip_uniform != -1;
->flushed_modelview_stack,
COGL_MATRIX_MODELVIEW, _cogl_matrix_stack_flush_to_gl_builtins (ctx,
flush_modelview_cb, projection_stack,
program_state); COGL_MATRIX_PROJECTION,
disable_flip);
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
modelview_stack,
COGL_MATRIX_MODELVIEW,
disable_flip);
} }
if (projection_changed) if (program_state->flip_uniform != -1
&& program_state->flushed_flip_state != needs_flip)
{ {
cogl_object_ref (ctx->flushed_projection_stack); static const float do_flip[4] = { 1.0f, -1.0f, 1.0f, 1.0f };
if (program_state->flushed_projection_stack) static const float dont_flip[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
cogl_object_unref (program_state->flushed_projection_stack); GE( ctx, glUniform4fv (program_state->flip_uniform,
program_state->flushed_projection_stack = ctx->flushed_projection_stack; 1, /* count */
program_state->flushed_projection_stack_age = needs_flip ? do_flip : dont_flip) );
_cogl_matrix_stack_get_age (ctx->flushed_projection_stack); program_state->flushed_flip_state = needs_flip;
if (program_state->projection_uniform != -1)
_cogl_prepare_matrix_stack_for_flush (ctx,
program_state
->flushed_projection_stack,
COGL_MATRIX_PROJECTION,
flush_projection_cb,
program_state);
} }
if (program_state->mvp_uniform != -1 &&
(modelview_changed || projection_changed))
_cogl_prepare_matrix_stack_for_flush (ctx,
ctx->flushed_projection_stack,
COGL_MATRIX_PROJECTION,
flush_combined_step_one_cb,
program_state);
} }
#ifdef HAVE_COGL_GLES2
static void static void
update_float_uniform (CoglPipeline *pipeline, update_float_uniform (CoglPipeline *pipeline,
int uniform_location, int uniform_location,
@ -1112,12 +1100,7 @@ const CoglPipelineProgend _cogl_pipeline_glsl_progend =
_cogl_pipeline_progend_glsl_end, _cogl_pipeline_progend_glsl_end,
_cogl_pipeline_progend_glsl_pre_change_notify, _cogl_pipeline_progend_glsl_pre_change_notify,
_cogl_pipeline_progend_glsl_layer_pre_change_notify, _cogl_pipeline_progend_glsl_layer_pre_change_notify,
#ifdef HAVE_COGL_GLES2
_cogl_pipeline_progend_glsl_pre_paint _cogl_pipeline_progend_glsl_pre_paint
#else
NULL
#endif
}; };
#endif /* COGL_PIPELINE_PROGEND_GLSL */ #endif /* COGL_PIPELINE_PROGEND_GLSL */

View File

@ -99,8 +99,9 @@ _cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
_cogl_set_active_texture_unit (unit_index); _cogl_set_active_texture_unit (unit_index);
_cogl_matrix_stack_flush_to_gl (ctx, unit->matrix_stack, _cogl_matrix_stack_flush_to_gl_builtins (ctx, unit->matrix_stack,
COGL_MATRIX_TEXTURE); COGL_MATRIX_TEXTURE,
FALSE /* enable flip */);
} }
return TRUE; return TRUE;

View File

@ -43,6 +43,7 @@
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-program-private.h" #include "cogl-program-private.h"
#include "cogl-pipeline-vertend-glsl-private.h" #include "cogl-pipeline-vertend-glsl-private.h"
#include "cogl-pipeline-state-private.h"
const CoglPipelineVertend _cogl_pipeline_glsl_vertend; const CoglPipelineVertend _cogl_pipeline_glsl_vertend;
@ -328,9 +329,10 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
_cogl_set_active_texture_unit (unit_index); _cogl_set_active_texture_unit (unit_index);
_cogl_matrix_stack_flush_to_gl (ctx, _cogl_matrix_stack_flush_to_gl_builtins (ctx,
unit->matrix_stack, unit->matrix_stack,
COGL_MATRIX_TEXTURE); COGL_MATRIX_TEXTURE,
FALSE /* do flip */);
} }
} }
@ -410,6 +412,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
GLint compile_status; GLint compile_status;
GLuint shader; GLuint shader;
CoglPipelineSnippetData snippet_data; CoglPipelineSnippetData snippet_data;
CoglPipelineSnippetList *vertex_snippets;
COGL_STATIC_COUNTER (vertend_glsl_compile_counter, COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
"glsl vertex compile counter", "glsl vertex compile counter",
@ -432,9 +435,11 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
" cogl_color_out = cogl_color_in;\n" " cogl_color_out = cogl_color_in;\n"
"}\n"); "}\n");
vertex_snippets = get_vertex_snippets (pipeline);
/* Add hooks for the vertex transform part */ /* Add hooks for the vertex transform part */
memset (&snippet_data, 0, sizeof (snippet_data)); memset (&snippet_data, 0, sizeof (snippet_data));
snippet_data.snippets = get_vertex_snippets (pipeline); snippet_data.snippets = vertex_snippets;
snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX_TRANSFORM; snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX_TRANSFORM;
snippet_data.chain_function = "cogl_real_vertex_transform"; snippet_data.chain_function = "cogl_real_vertex_transform";
snippet_data.final_name = "cogl_vertex_transform"; snippet_data.final_name = "cogl_vertex_transform";
@ -444,14 +449,35 @@ _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 = vertex_snippets;
snippet_data.hook = COGL_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 = "cogl_vertex_hook";
snippet_data.function_prefix = "cogl_vertex_hook"; snippet_data.function_prefix = "cogl_vertex_hook";
snippet_data.source_buf = shader_state->source; snippet_data.source_buf = shader_state->source;
_cogl_pipeline_snippet_generate_code (&snippet_data); _cogl_pipeline_snippet_generate_code (&snippet_data);
g_string_append (shader_state->source,
"void\n"
"main ()\n"
"{\n"
" cogl_vertex_hook ();\n");
/* If there are any snippets then we can't rely on the
projection matrix to flip the rendering for offscreen buffers
so we'll need to flip it using an extra statement and a
uniform */
if (_cogl_pipeline_has_vertex_snippets (pipeline))
{
g_string_append (shader_state->header,
"uniform vec4 _cogl_flip_vector;\n");
g_string_append (shader_state->source,
" cogl_position_out *= _cogl_flip_vector;\n");
}
g_string_append (shader_state->source,
"}\n");
GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) ); GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
lengths[0] = shader_state->header->len; lengths[0] = shader_state->header->len;

View File

@ -71,9 +71,6 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
#ifdef COGL_PIPELINE_FRAGEND_FIXED #ifdef COGL_PIPELINE_FRAGEND_FIXED
#include "cogl-pipeline-fragend-fixed-private.h" #include "cogl-pipeline-fragend-fixed-private.h"
#endif #endif
#ifdef COGL_PIPELINE_PROGEND_GLSL
#include "cogl-pipeline-progend-glsl-private.h"
#endif
#ifdef COGL_PIPELINE_VERTEND_GLSL #ifdef COGL_PIPELINE_VERTEND_GLSL
#include "cogl-pipeline-vertend-glsl-private.h" #include "cogl-pipeline-vertend-glsl-private.h"
@ -82,6 +79,13 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
#include "cogl-pipeline-vertend-fixed-private.h" #include "cogl-pipeline-vertend-fixed-private.h"
#endif #endif
#ifdef COGL_PIPELINE_PROGEND_FIXED
#include "cogl-pipeline-progend-fixed-private.h"
#endif
#ifdef COGL_PIPELINE_PROGEND_GLSL
#include "cogl-pipeline-progend-glsl-private.h"
#endif
COGL_OBJECT_DEFINE (Pipeline, pipeline); COGL_OBJECT_DEFINE (Pipeline, pipeline);
GQuark GQuark
@ -128,6 +132,10 @@ _cogl_pipeline_init_default_pipeline (void)
_cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] = _cogl_pipeline_fragends[COGL_PIPELINE_FRAGEND_FIXED] =
&_cogl_pipeline_fixed_fragend; &_cogl_pipeline_fixed_fragend;
#endif #endif
#ifdef COGL_PIPELINE_PROGEND_FIXED
_cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] =
&_cogl_pipeline_fixed_progend;
#endif
#ifdef COGL_PIPELINE_PROGEND_GLSL #ifdef COGL_PIPELINE_PROGEND_GLSL
_cogl_pipeline_progends[COGL_PIPELINE_PROGEND_GLSL] = _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_GLSL] =
&_cogl_pipeline_glsl_progend; &_cogl_pipeline_glsl_progend;