summaryrefslogtreecommitdiff
path: root/cogl/cogl-matrix-stack.c
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2010-12-06 12:31:51 +0000
committerNeil Roberts <neil@linux.intel.com>2010-12-13 17:29:13 +0000
commita05c701e6b354f699b0886eb16b3863ed735d3c5 (patch)
treebb6fb534c8328ee59a6afd1155b5a9f2f5c099bc /cogl/cogl-matrix-stack.c
parent35b07f6b8394c0ca371183f9bd2709812c884754 (diff)
downloadcogl-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.c127
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;
}