[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 54159f5a1d
This commit is contained in:
Robert Bragg 2009-07-03 00:34:10 +01:00
parent fcc3d56209
commit fffcf579d5
9 changed files with 85 additions and 59 deletions

View File

@ -22,6 +22,7 @@
*
* Authors:
* Havoc Pennington <hp@pobox.com> for litl
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
@ -53,16 +54,43 @@
#include <string.h>
#include <math.h>
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, &current_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, &current_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 ();
}

View File

@ -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 */

View File

@ -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

View File

@ -24,6 +24,7 @@
* Robert Bragg <robert@linux.intel.com>
*/
#include <cogl.h>
#include <cogl-matrix.h>
#include <glib.h>

View File

@ -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));
}

View File

@ -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);

View File

@ -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 */

View File

@ -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];

View File

@ -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);