diff options
author | Neil Roberts <neil@linux.intel.com> | 2010-12-06 12:31:51 +0000 |
---|---|---|
committer | Neil Roberts <neil@linux.intel.com> | 2010-12-13 17:29:13 +0000 |
commit | a05c701e6b354f699b0886eb16b3863ed735d3c5 (patch) | |
tree | bb6fb534c8328ee59a6afd1155b5a9f2f5c099bc /cogl/cogl-matrix-stack.c | |
parent | 35b07f6b8394c0ca371183f9bd2709812c884754 (diff) | |
download | cogl-a05c701e6b354f699b0886eb16b3863ed735d3c5.tar.gz |
cogl: upload matrices with uniforms on GLES2
Once the GLES2 wrapper is removed we won't be able to upload the
matrices with the fixed function API any more. The fixed function API
gives a global state for setting the matrix but if a custom shader
uniform is used for the matrices then the state is per
program. _cogl_matrix_stack_flush_to_gl is called in a few places and
it is assumed the current pipeline doesn't need to be flushed before
it is called. To allow these semantics to continue to work, on GLES2
the matrix flush now just stores a reference to the matrix stack in
the CoglContext. A pre_paint virtual is added to the progend which is
called whenever a pipeline is flushed, even if the same pipeline was
flushed already. This gives the GLSL progend a chance to upload the
matrices to the uniforms. The combined modelview/projection matrix is
only calculated if it is used. The generated programs end up never
using the modelview or projection matrix so it usually only has to
upload the combined matrix. When a matrix stack is flushed a reference
is taked to it by the pipeline progend and the age is stored so that
if the same state is used with the same program again then we don't
need to reupload the uniform.
Diffstat (limited to 'cogl/cogl-matrix-stack.c')
-rw-r--r-- | cogl/cogl-matrix-stack.c | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c index d4defd1c..d0d34ef9 100644 --- a/cogl/cogl-matrix-stack.c +++ b/cogl/cogl-matrix-stack.c @@ -390,6 +390,64 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack, /* mark dirty */ stack->flushed_state = NULL; state->is_identity = FALSE; + stack->age++; +} + +#ifndef HAVE_COGL_GLES2 + +static void +flush_to_fixed_api_gl (gboolean is_identity, + const CoglMatrix *matrix, + void *user_data) +{ + CoglMatrixStack *stack = user_data; + + if (is_identity) + { + if (!stack->flushed_identity) + GE (glLoadIdentity ()); + stack->flushed_identity = TRUE; + } + else + { + GE (glLoadMatrixf (cogl_matrix_get_array (matrix)) ); + stack->flushed_identity = FALSE; + } +} + +#endif /* HAVE_COGL_GLES2 */ + +void +_cogl_matrix_stack_prepare_for_flush (CoglMatrixStack *stack, + CoglMatrixMode mode, + CoglMatrixStackFlushFunc callback, + void *user_data) +{ + CoglMatrixState *state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + 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_framebuffer ())) + { + CoglMatrix flipped_projection; + CoglMatrix *projection = + state->is_identity ? &ctx->identity_matrix : &state->matrix; + + cogl_matrix_multiply (&flipped_projection, + &ctx->y_flip_matrix, projection); + callback (FALSE, &flipped_projection, user_data); + } + else + callback (state->is_identity, + state->is_identity ? &ctx->identity_matrix : &state->matrix, + user_data); } void @@ -402,6 +460,40 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, state = _cogl_matrix_stack_top (stack); +#ifdef HAVE_COGL_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) + { + case COGL_MATRIX_MODELVIEW: + cogl_object_ref (stack); + if (ctx->flushed_modelview_stack) + cogl_object_unref (ctx->flushed_modelview_stack); + ctx->flushed_modelview_stack = stack; + break; + + case COGL_MATRIX_PROJECTION: + cogl_object_ref (stack); + if (ctx->flushed_projection_stack) + cogl_object_unref (ctx->flushed_projection_stack); + ctx->flushed_projection_stack = stack; + break; + + case COGL_MATRIX_TEXTURE: + /* This shouldn't happen because the texture matrices are + handled by the GLSL pipeline backend */ + g_assert_not_reached (); + break; + } + +#else /* HAVE_COGL_GLES2 */ + if (stack->flushed_state == state) return; @@ -428,36 +520,13 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, ctx->flushed_matrix_mode = mode; } - /* 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_framebuffer ())) - { - CoglMatrix flipped_projection; - CoglMatrix *projection = - state->is_identity ? &ctx->identity_matrix : &state->matrix; + _cogl_matrix_stack_prepare_for_flush (stack, + mode, + flush_to_fixed_api_gl, + stack); + +#endif /* HAVE_COGL_GLES2 */ - cogl_matrix_multiply (&flipped_projection, - &ctx->y_flip_matrix, projection); - GE (glLoadMatrixf (cogl_matrix_get_array (&flipped_projection))); - stack->flushed_identity = FALSE; - } - else - { - if (state->is_identity) - { - if (!stack->flushed_identity) - GE (glLoadIdentity ()); - stack->flushed_identity = TRUE; - } - else - { - GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix))); - stack->flushed_identity = FALSE; - } - } stack->flushed_state = state; } |