matrix-stack: more optimization for load_identity case

This goes a bit further than the previous patch, and as a special case
we now simply represent identity matrices using a boolean, and only
lazily initialize them when they need to be modified.
This commit is contained in:
Robert Bragg 2009-10-06 12:36:32 +01:00
parent 460025d603
commit b1f9f0a97d

View File

@ -35,6 +35,7 @@
typedef struct { typedef struct {
CoglMatrix matrix; CoglMatrix matrix;
gboolean is_identity;
/* count of pushes with no changes; when a change is /* count of pushes with no changes; when a change is
* requested, we create a new state and decrement this * requested, we create a new state and decrement this
*/ */
@ -54,6 +55,7 @@ struct _CoglMatrixStack
/* which state does GL have, NULL if unknown */ /* which state does GL have, NULL if unknown */
CoglMatrixState *flushed_state; CoglMatrixState *flushed_state;
gboolean flushed_identity;
}; };
/* XXX: this doesn't initialize the matrix! */ /* XXX: this doesn't initialize the matrix! */
@ -64,6 +66,7 @@ _cogl_matrix_state_new (void)
state = g_slice_new (CoglMatrixState); state = g_slice_new (CoglMatrixState);
state->push_count = 0; state->push_count = 0;
state->is_identity = FALSE;
return state; return state;
} }
@ -71,7 +74,6 @@ _cogl_matrix_state_new (void)
static void static void
_cogl_matrix_state_destroy (CoglMatrixState *state) _cogl_matrix_state_destroy (CoglMatrixState *state)
{ {
g_slice_free (CoglMatrixState, state); g_slice_free (CoglMatrixState, state);
} }
@ -81,6 +83,18 @@ _cogl_matrix_stack_top (CoglMatrixStack *stack)
return stack->stack->data; return stack->stack->data;
} }
/* XXX:
* Operations like scale, translate, rotate etc need to have an
* initialized state->matrix to work with, so they will pass
* initialize = TRUE.
*
* _cogl_matrix_stack_load_identity and _cogl_matrix_stack_set on the
* other hand don't so they will pass initialize = FALSE
*
* NB: Identity matrices are represented by setting
* state->is_identity=TRUE in which case state->matrix will be
* uninitialized.
*/
static CoglMatrixState * static CoglMatrixState *
_cogl_matrix_stack_top_mutable (CoglMatrixStack *stack, _cogl_matrix_stack_top_mutable (CoglMatrixStack *stack,
gboolean initialize) gboolean initialize)
@ -91,7 +105,11 @@ _cogl_matrix_stack_top_mutable (CoglMatrixStack *stack,
state = _cogl_matrix_stack_top (stack); state = _cogl_matrix_stack_top (stack);
if (state->push_count == 0) if (state->push_count == 0)
{
if (state->is_identity && initialize)
cogl_matrix_init_identity (&state->matrix);
return state; return state;
}
state->push_count -= 1; state->push_count -= 1;
@ -99,6 +117,9 @@ _cogl_matrix_stack_top_mutable (CoglMatrixStack *stack,
if (initialize) if (initialize)
{ {
if (state->is_identity)
cogl_matrix_init_identity (&new_top->matrix);
else
new_top->matrix = state->matrix; new_top->matrix = state->matrix;
if (stack->flushed_state == state) if (stack->flushed_state == state)
@ -119,7 +140,7 @@ _cogl_matrix_stack_new (void)
stack = g_slice_new0 (CoglMatrixStack); stack = g_slice_new0 (CoglMatrixStack);
state = _cogl_matrix_state_new (); state = _cogl_matrix_state_new ();
cogl_matrix_init_identity (&state->matrix); state->is_identity = TRUE;
stack->stack = g_slist_prepend (stack->stack, state); stack->stack = g_slist_prepend (stack->stack, state);
@ -192,12 +213,22 @@ _cogl_matrix_stack_load_identity (CoglMatrixStack *stack)
{ {
CoglMatrixState *state; CoglMatrixState *state;
/* XXX: In this case an uninitialized top is acceptable */
state = _cogl_matrix_stack_top_mutable (stack, FALSE); state = _cogl_matrix_stack_top_mutable (stack, FALSE);
cogl_matrix_init_identity (&state->matrix);
/* NB: Identity matrices are represented by setting
* state->is_identity = TRUE and leaving state->matrix
* uninitialized.
*
* This is done to optimize the heavy usage of
* _cogl_matrix_stack_load_identity by the Cogl Journal.
*/
if (!state->is_identity)
{
state->is_identity = TRUE;
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
}
} }
void void
@ -212,6 +243,7 @@ _cogl_matrix_stack_scale (CoglMatrixStack *stack,
cogl_matrix_scale (&state->matrix, x, y, z); cogl_matrix_scale (&state->matrix, x, y, z);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -226,6 +258,7 @@ _cogl_matrix_stack_translate (CoglMatrixStack *stack,
cogl_matrix_translate (&state->matrix, x, y, z); cogl_matrix_translate (&state->matrix, x, y, z);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -241,6 +274,7 @@ _cogl_matrix_stack_rotate (CoglMatrixStack *stack,
cogl_matrix_rotate (&state->matrix, angle, x, y, z); cogl_matrix_rotate (&state->matrix, angle, x, y, z);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -253,6 +287,7 @@ _cogl_matrix_stack_multiply (CoglMatrixStack *stack,
cogl_matrix_multiply (&state->matrix, &state->matrix, matrix); cogl_matrix_multiply (&state->matrix, &state->matrix, matrix);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -272,6 +307,7 @@ _cogl_matrix_stack_frustum (CoglMatrixStack *stack,
z_near, z_far); z_near, z_far);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -288,6 +324,7 @@ _cogl_matrix_stack_perspective (CoglMatrixStack *stack,
fov_y, aspect, z_near, z_far); fov_y, aspect, z_near, z_far);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -306,6 +343,7 @@ _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
left, right, bottom, top, z_near, z_far); left, right, bottom, top, z_near, z_far);
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -316,6 +354,16 @@ _cogl_matrix_stack_get (CoglMatrixStack *stack,
state = _cogl_matrix_stack_top (stack); state = _cogl_matrix_stack_top (stack);
/* NB: identity matrices are lazily initialized because we can often avoid
* initializing them at all if nothing is pushed on top of them since we
* load them using glLoadIdentity()
*
* The Cogl journal typically loads an identiy matrix because it performs
* software transformations, which is why we have optimized this case.
*/
if (state->is_identity)
cogl_matrix_init_identity (matrix);
else
*matrix = state->matrix; *matrix = state->matrix;
} }
@ -325,10 +373,11 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack,
{ {
CoglMatrixState *state; CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack, TRUE); state = _cogl_matrix_stack_top_mutable (stack, FALSE);
state->matrix = *matrix; state->matrix = *matrix;
/* mark dirty */ /* mark dirty */
stack->flushed_state = NULL; stack->flushed_state = NULL;
state->is_identity = FALSE;
} }
void void
@ -362,7 +411,17 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
* than LoadMatrix to send a 2D matrix * than LoadMatrix to send a 2D matrix
*/ */
if (state->is_identity)
{
if (!stack->flushed_identity)
GE (glLoadIdentity ());
stack->flushed_identity = TRUE;
}
else
{
GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix))); GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix)));
stack->flushed_identity = FALSE;
}
stack->flushed_state = state; stack->flushed_state = state;
} }
@ -370,5 +429,6 @@ void
_cogl_matrix_stack_dirty (CoglMatrixStack *stack) _cogl_matrix_stack_dirty (CoglMatrixStack *stack)
{ {
stack->flushed_state = NULL; stack->flushed_state = NULL;
stack->flushed_identity = FALSE;
} }