From fffcf579d5c7e3d97f1641b0cb0433c23700f484 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Fri, 3 Jul 2009 00:34:10 +0100 Subject: [PATCH] [cogl matrix stack] Create a client side matrix stack for the projection matrix The cost of glGetFloatv with Mesa is still representing a majority of our time in OpenGL for some applications, and the last thing left using this is the current-matrix API when getting the projection matrix. This adds a matrix stack for the projection matrix, so all getting, setting and modification of the projection matrix is now managed by Cogl and it's only when we come to draw that we flush changes to the matrix to OpenGL. This also brings us closer to being able to drop internal use of the deprecated OpenGL matrix functions, re: commit 54159f5a1d02 --- common/cogl-current-matrix.c | 105 +++++++++++++++++++++-------------- common/cogl-current-matrix.h | 2 + common/cogl-matrix-stack.c | 8 +-- common/cogl-matrix.c | 1 + common/cogl-primitives.c | 10 +++- common/cogl-vertex-buffer.c | 4 +- common/cogl.c | 7 ++- gl/cogl-context.h | 1 + gl/cogl-primitives.c | 6 +- 9 files changed, 85 insertions(+), 59 deletions(-) diff --git a/common/cogl-current-matrix.c b/common/cogl-current-matrix.c index 6f70be880..217eb2df4 100644 --- a/common/cogl-current-matrix.c +++ b/common/cogl-current-matrix.c @@ -22,6 +22,7 @@ * * Authors: * Havoc Pennington for litl + * Robert Bragg */ #ifdef HAVE_CONFIG_H @@ -53,16 +54,43 @@ #include #include +static void +_cogl_get_client_stack (CoglContext *ctx, + CoglMatrixMode mode, + CoglMatrixStack **current_stack_p) +{ + if (ctx->modelview_stack && + mode == COGL_MATRIX_MODELVIEW) + *current_stack_p = ctx->modelview_stack; + else if (ctx->projection_stack && + mode == COGL_MATRIX_PROJECTION) + *current_stack_p = ctx->projection_stack; + else + *current_stack_p = NULL; +} + +#define _COGL_GET_CONTEXT_AND_STACK(contextvar, stackvar, rval) \ + CoglMatrixStack *stackvar; \ + _COGL_GET_CONTEXT (contextvar, rval); \ + _cogl_get_client_stack (contextvar, ctx->matrix_mode, &stackvar) + void _cogl_set_current_matrix (CoglMatrixMode mode) { GLenum gl_mode; + CoglMatrixStack *current_stack; \ _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (mode == ctx->matrix_mode) return; ctx->matrix_mode = mode; + /* If we have a client side stack then then the GL matrix mode only needs + * changing when we come to flush it to OpenGL */ + _cogl_get_client_stack (ctx, mode, ¤t_stack); + if (current_stack) + return; + gl_mode = 0; /* silence compiler warning */ switch (mode) { @@ -80,22 +108,6 @@ _cogl_set_current_matrix (CoglMatrixMode mode) GE (glMatrixMode (gl_mode)); } -static void -_cogl_get_client_stack (CoglContext *ctx, - CoglMatrixStack **current_stack_p) -{ - if (ctx->modelview_stack && - ctx->matrix_mode == COGL_MATRIX_MODELVIEW) - *current_stack_p = ctx->modelview_stack; - else - *current_stack_p = NULL; -} - -#define _COGL_GET_CONTEXT_AND_STACK(contextvar, stackvar, rval) \ - CoglMatrixStack *stackvar; \ - _COGL_GET_CONTEXT (contextvar, rval); \ - _cogl_get_client_stack (contextvar, &stackvar) - void _cogl_current_matrix_push (void) { @@ -204,7 +216,7 @@ _cogl_current_matrix_frustum (float left, if (current_stack != NULL) _cogl_matrix_stack_frustum (current_stack, left, right, - top, bottom, + bottom, top, near_val, far_val); else @@ -269,13 +281,13 @@ void _cogl_get_matrix (CoglMatrixMode mode, CoglMatrix *matrix) { + CoglMatrixStack *current_stack; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->modelview_stack != NULL && - mode == COGL_MATRIX_MODELVIEW) - { - _cogl_matrix_stack_get (ctx->modelview_stack, matrix); - } + _cogl_get_client_stack (ctx, mode, ¤t_stack); + + if (current_stack) + _cogl_matrix_stack_get (current_stack, matrix); else { GLenum gl_mode; @@ -319,24 +331,25 @@ _cogl_current_matrix_state_init (void) ctx->matrix_mode = COGL_MATRIX_MODELVIEW; ctx->modelview_stack = NULL; + ctx->projection_stack = NULL; #if 0 if (ctx->indirect || cogl_debug_flags & COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES) #endif { - ctx->modelview_stack = - _cogl_matrix_stack_new (); + ctx->modelview_stack = _cogl_matrix_stack_new (); + ctx->projection_stack = _cogl_matrix_stack_new (); } } void _cogl_current_matrix_state_destroy (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); - if (ctx->modelview_stack) - _cogl_matrix_stack_destroy (ctx->modelview_stack); + if (current_stack) + _cogl_matrix_stack_destroy (current_stack); } void @@ -344,32 +357,35 @@ _cogl_current_matrix_state_flush (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->matrix_mode != COGL_MATRIX_MODELVIEW) + if (ctx->matrix_mode != COGL_MATRIX_MODELVIEW && + ctx->matrix_mode != COGL_MATRIX_PROJECTION) { - g_warning ("matrix state must be flushed in MODELVIEW mode"); + g_warning ("matrix state must be flushed in " + "MODELVIEW or PROJECTION mode"); return; } - if (ctx->modelview_stack) + if (ctx->modelview_stack && + ctx->matrix_mode == COGL_MATRIX_MODELVIEW) { _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, GL_MODELVIEW); } + else if (ctx->projection_stack && + ctx->matrix_mode == COGL_MATRIX_PROJECTION) + { + _cogl_matrix_stack_flush_to_gl (ctx->projection_stack, + GL_PROJECTION); + } } void _cogl_current_matrix_state_dirty (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); - if (ctx->matrix_mode != COGL_MATRIX_MODELVIEW) - { - g_warning ("matrix state must be dirtied in MODELVIEW mode"); - return; - } - - if (ctx->modelview_stack) - _cogl_matrix_stack_dirty (ctx->modelview_stack); + if (current_stack) + _cogl_matrix_stack_dirty (current_stack); } void @@ -445,8 +461,6 @@ cogl_frustum (float left, z_near, z_far); - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - /* Calculate and store the inverse of the matrix */ memset (ctx->inverse_projection, 0, sizeof (float) * 16); @@ -524,3 +538,12 @@ cogl_set_projection_matrix (CoglMatrix *matrix) _cogl_current_matrix_load (matrix); } +void +_cogl_flush_matrix_stacks (void) +{ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_state_flush (); + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_state_flush (); +} + diff --git a/common/cogl-current-matrix.h b/common/cogl-current-matrix.h index 876c72bbb..eb2464888 100644 --- a/common/cogl-current-matrix.h +++ b/common/cogl-current-matrix.h @@ -90,4 +90,6 @@ void _cogl_current_matrix_state_destroy (void); void _cogl_current_matrix_state_flush (void); void _cogl_current_matrix_state_dirty (void); +void _cogl_flush_matrix_stacks (void); + #endif /* __COGL_CURRENT_MATRIX_H */ diff --git a/common/cogl-matrix-stack.c b/common/cogl-matrix-stack.c index e395ee1c6..ceda0576f 100644 --- a/common/cogl-matrix-stack.c +++ b/common/cogl-matrix-stack.c @@ -344,10 +344,7 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, if (stack->flushed_state == state) return; - /* NOTE we assume caller was in MODELVIEW mode */ - - if (gl_mode != GL_MODELVIEW) - GE (glMatrixMode (gl_mode)); + GE (glMatrixMode (gl_mode)); /* In theory it might help the GL implementation if we used our * local analysis of the matrix and called Translate/Scale rather @@ -356,9 +353,6 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix))); stack->flushed_state = state; - - if (gl_mode != GL_MODELVIEW) - GE (glMatrixMode (GL_MODELVIEW)); } void diff --git a/common/cogl-matrix.c b/common/cogl-matrix.c index 45f367d73..d4cacaedd 100644 --- a/common/cogl-matrix.c +++ b/common/cogl-matrix.c @@ -24,6 +24,7 @@ * Robert Bragg */ +#include #include #include diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c index 81f00f5c2..e2d9a2487 100644 --- a/common/cogl-primitives.c +++ b/common/cogl-primitives.c @@ -546,9 +546,13 @@ _cogl_journal_flush (void) state.vbo_offset = (char *)ctx->logged_vertices->data; /* Since the journal deals with emitting the modelview matrices manually - * we need to dirty our client side matrix stack cache... */ + * we need to dirty our client side modelview matrix stack cache... */ _cogl_current_matrix_state_dirty (); + /* And explicitly flush other matrix stacks... */ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_state_flush (); + /* If we have transformed all our quads at log time then the whole journal * then we ensure no further model transform is applied by loading the * identity matrix here...*/ @@ -1460,7 +1464,7 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices, options.layer0_override_texture = gl_handle; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); } @@ -1564,7 +1568,7 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR; options.fallback_layers = fallback_layers; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); } diff --git a/common/cogl-vertex-buffer.c b/common/cogl-vertex-buffer.c index 4f3a51413..2dda3198f 100644 --- a/common/cogl-vertex-buffer.c +++ b/common/cogl-vertex-buffer.c @@ -1751,7 +1751,7 @@ cogl_vertex_buffer_draw (CoglHandle handle, buffer = _cogl_vertex_buffer_pointer_from_handle (handle); cogl_clip_ensure (); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); enable_state_for_drawing_buffer (buffer); /* FIXME: flush cogl cache */ @@ -1888,7 +1888,7 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); cogl_clip_ensure (); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); enable_state_for_drawing_buffer (buffer); byte_offset = indices_offset * get_indices_type_size (indices->type); diff --git a/common/cogl.c b/common/cogl.c index a4d8feaec..e1796fb5d 100644 --- a/common/cogl.c +++ b/common/cogl.c @@ -324,7 +324,7 @@ set_clip_plane (GLint plane_num, _cogl_current_matrix_rotate (angle, 0.0f, 0.0f, 1.0f); _cogl_current_matrix_translate (-vertex_a[0], -vertex_a[1], -vertex_a[2]); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); plane[0] = 0; plane[1] = -1.0; @@ -568,6 +568,7 @@ _cogl_setup_viewport (guint width, cogl_get_projection_matrix (&projection_matrix); z_camera = 0.5 * projection_matrix.xx; + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); _cogl_current_matrix_identity (); _cogl_current_matrix_translate (-0.5f, -0.5f, -z_camera); _cogl_current_matrix_scale (1.0f / width, -1.0f / height, 1.0f / width); @@ -706,7 +707,7 @@ cogl_disable_fog (void) void cogl_flush_gl_state (int flags) { - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); } #endif @@ -800,7 +801,7 @@ cogl_begin_gl (void) cogl_clip_ensure (); /* Flush any client side matrix state */ - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); /* Setup the state for the current material */ diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 57facfa2f..b0a72eaf4 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -60,6 +60,7 @@ typedef struct /* Client-side matrix stack or NULL if none */ CoglMatrixMode matrix_mode; CoglMatrixStack *modelview_stack; + CoglMatrixStack *projection_stack; /* Cache of inverse projection matrix */ float inverse_projection[16]; diff --git a/gl/cogl-primitives.c b/gl/cogl-primitives.c index cb6671c08..bdc24f709 100644 --- a/gl/cogl-primitives.c +++ b/gl/cogl-primitives.c @@ -88,7 +88,7 @@ _cogl_path_stroke_nodes () options.disable_layers = (guint32)~0; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); while (path_start < ctx->path_nodes->len) { @@ -177,7 +177,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } ctx->n_texcoord_arrays_enabled = 0; - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); while (path_start < path_size) { @@ -226,7 +226,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _cogl_current_matrix_push (); _cogl_current_matrix_identity (); - _cogl_current_matrix_state_flush (); + _cogl_flush_matrix_stacks (); glRectf (-1.0, -1.0, 1.0, 1.0); glRectf (-1.0, -1.0, 1.0, 1.0);