[current-matrix] Adds texture matrix stacks + removes GL matrix API usage

This relates back to an earlier commitment to stop using the OpenGL matrix
API which is considered deprecated. (ref 54159f5a1d)

The new texture matrix stacks are hung from a list of (internal only)
CoglTextureUnit structures which the CoglMaterial code internally references
via _cogl_get_texure_unit ().

So we would be left with only the cogl-matrix-stack code being responsible
for glMatrixMode, glLoadMatrix and glLoadIdentity this commit updates the
journal code so it now uses the matrix-stack API instead of GL directly.
This commit is contained in:
Robert Bragg 2009-09-29 02:58:27 +01:00
parent d8107c5ef5
commit 1402d1eb3c
8 changed files with 174 additions and 212 deletions

View File

@ -65,6 +65,8 @@ cogl_create_context (void)
_context->indirect = gl_is_indirect;
_context->texture_units = NULL;
_context->default_material = cogl_material_new ();
_context->source_material = NULL;
@ -151,6 +153,8 @@ _cogl_destroy_context ()
_cogl_current_matrix_state_destroy ();
_cogl_destroy_texture_units ();
if (_context->path_nodes)
g_array_free (_context->path_nodes, TRUE);

View File

@ -58,10 +58,11 @@ typedef struct
gboolean indirect;
/* Client-side matrix stack or NULL if none */
CoglMatrixMode matrix_mode;
CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack;
CoglMatrixStack *modelview_stack;
GList *texture_units;
/* Cache of inverse projection matrix */
float inverse_projection[16];

View File

@ -59,14 +59,21 @@ _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;
switch (mode)
{
case COGL_MATRIX_MODELVIEW:
*current_stack_p = ctx->modelview_stack;
break;
case COGL_MATRIX_PROJECTION:
*current_stack_p = ctx->projection_stack;
break;
case COGL_MATRIX_TEXTURE:
g_critical ("The current-matrix API doesn't support the texture matrix "
"you must deal with the CoglMatrixStack directly");
*current_stack_p = NULL;
break;
}
g_assert (*current_stack_p);
}
#define _COGL_GET_CONTEXT_AND_STACK(contextvar, stackvar, rval) \
@ -77,90 +84,46 @@ _cogl_get_client_stack (CoglContext *ctx,
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)
{
case COGL_MATRIX_MODELVIEW:
gl_mode = GL_MODELVIEW;
break;
case COGL_MATRIX_PROJECTION:
gl_mode = GL_PROJECTION;
break;
case COGL_MATRIX_TEXTURE:
gl_mode = GL_TEXTURE;
break;
}
GE (glMatrixMode (gl_mode));
}
void
_cogl_current_matrix_push (void)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_push (current_stack);
else
GE (glPushMatrix ());
_cogl_matrix_stack_push (current_stack);
}
void
_cogl_current_matrix_pop (void)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_pop (current_stack);
else
GE (glPopMatrix ());
_cogl_matrix_stack_pop (current_stack);
}
void
_cogl_current_matrix_identity (void)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_load_identity (current_stack);
else
GE (glLoadIdentity ());
_cogl_matrix_stack_load_identity (current_stack);
}
void
_cogl_current_matrix_load (const CoglMatrix *matrix)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_set (current_stack, matrix);
else
GE (glLoadMatrixf (cogl_matrix_get_array (matrix)));
_cogl_matrix_stack_set (current_stack, matrix);
}
void
_cogl_current_matrix_multiply (const CoglMatrix *matrix)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_multiply (current_stack, matrix);
else
GE (glMultMatrixf (cogl_matrix_get_array (matrix)));
_cogl_matrix_stack_multiply (current_stack, matrix);
}
void
@ -170,11 +133,7 @@ _cogl_current_matrix_rotate (float angle,
float z)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_rotate (current_stack, angle, x, y, z);
else
GE (glRotatef (angle, x, y, z));
_cogl_matrix_stack_rotate (current_stack, angle, x, y, z);
}
void
@ -183,11 +142,7 @@ _cogl_current_matrix_scale (float x,
float z)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_scale (current_stack, x, y, z);
else
GE (glScalef (x, y, z));
_cogl_matrix_stack_scale (current_stack, x, y, z);
}
void
@ -196,11 +151,7 @@ _cogl_current_matrix_translate (float x,
float z)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_translate (current_stack, x, y, z);
else
GE (glTranslatef (x, y, z));
_cogl_matrix_stack_translate (current_stack, x, y, z);
}
void
@ -212,15 +163,11 @@ _cogl_current_matrix_frustum (float left,
float far_val)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_frustum (current_stack,
left, right,
bottom, top,
near_val,
far_val);
else
GE (glFrustum (left, right, bottom, top, near_val, far_val));
_cogl_matrix_stack_frustum (current_stack,
left, right,
bottom, top,
near_val,
far_val);
}
void
@ -230,20 +177,8 @@ _cogl_current_matrix_perspective (float fov_y,
float z_far)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_perspective (current_stack,
fov_y, aspect, z_near, z_far);
else
{
/* NB: There is no glPerspective() (only gluPerspective()) so we use
* cogl_matrix_perspective: */
CoglMatrix matrix;
_cogl_get_matrix (ctx->matrix_mode, &matrix);
cogl_matrix_perspective (&matrix,
fov_y, aspect, z_near, z_far);
_cogl_current_matrix_load (&matrix);
}
_cogl_matrix_stack_perspective (current_stack,
fov_y, aspect, z_near, z_far);
}
void
@ -255,26 +190,11 @@ _cogl_current_matrix_ortho (float left,
float far_val)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack != NULL)
_cogl_matrix_stack_ortho (current_stack,
left, right,
bottom, top,
near_val,
far_val);
else
{
#ifdef HAVE_COGL_GLES2
/* NB: GLES 2 has no glOrtho(): */
CoglMatrix matrix;
_cogl_get_matrix (ctx->matrix_mode, &matrix);
cogl_matrix_ortho (&matrix,
left, right, bottom, top, near_val, far_val);
_cogl_current_matrix_load (&matrix);
#else
GE (glOrtho (left, right, bottom, top, near_val, far_val));
#endif
}
_cogl_matrix_stack_ortho (current_stack,
left, right,
bottom, top,
near_val,
far_val);
}
void
@ -286,36 +206,7 @@ _cogl_get_matrix (CoglMatrixMode mode,
_cogl_get_client_stack (ctx, mode, &current_stack);
if (current_stack)
_cogl_matrix_stack_get (current_stack, matrix);
else
{
GLenum gl_mode;
GLfloat gl_matrix[16];
gl_mode = 0; /* silence compiler warning */
switch (mode)
{
case COGL_MATRIX_MODELVIEW:
gl_mode = GL_MODELVIEW_MATRIX;
break;
case COGL_MATRIX_PROJECTION:
gl_mode = GL_PROJECTION_MATRIX;
break;
case COGL_MATRIX_TEXTURE:
gl_mode = GL_TEXTURE_MATRIX;
break;
}
/* Note: we have a redundant copy happening here. If that turns out to be
* a problem then, since this is internal to Cogl, we could pass the
* CoglMatrix pointer directly to glGetFloatv; the only problem with that
* is that if we later add internal flags to CoglMatrix they will need to
* be initialized seperatly.
*/
GE (glGetFloatv (gl_mode, gl_matrix));
cogl_matrix_init_from_array (matrix, gl_matrix);
}
_cogl_matrix_stack_get (current_stack, matrix);
}
void
@ -330,62 +221,31 @@ _cogl_current_matrix_state_init (void)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
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->projection_stack = _cogl_matrix_stack_new ();
}
ctx->projection_stack = _cogl_matrix_stack_new ();
ctx->modelview_stack = _cogl_matrix_stack_new ();
}
void
_cogl_current_matrix_state_destroy (void)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (current_stack)
_cogl_matrix_stack_destroy (current_stack);
_cogl_matrix_stack_destroy (ctx->projection_stack);
_cogl_matrix_stack_destroy (ctx->modelview_stack);
}
void
_cogl_current_matrix_state_flush (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->matrix_mode != COGL_MATRIX_MODELVIEW &&
ctx->matrix_mode != COGL_MATRIX_PROJECTION)
{
g_warning ("matrix state must be flushed in "
"MODELVIEW or PROJECTION mode");
return;
}
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);
}
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
_cogl_matrix_stack_flush_to_gl (current_stack, ctx->matrix_mode);
}
void
_cogl_current_matrix_state_dirty (void)
{
_COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL);
if (current_stack)
_cogl_matrix_stack_dirty (current_stack);
_cogl_matrix_stack_dirty (current_stack);
}
void
@ -541,9 +401,9 @@ cogl_set_projection_matrix (CoglMatrix *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 ();
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack, COGL_MATRIX_PROJECTION);
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, COGL_MATRIX_MODELVIEW);
}

View File

@ -26,6 +26,7 @@
#include "cogl-debug.h"
#include "cogl-types.h"
#include "cogl-context.h"
#ifdef HAVE_COGL_GLES2
typedef enum {
@ -85,4 +86,15 @@ gint _cogl_get_format_bpp (CoglPixelFormat format);
void cogl_enable (gulong flags);
gulong cogl_get_enable (void);
typedef struct _CoglTextureUnit
{
int index;
CoglMatrixStack *matrix_stack;
} CoglTextureUnit;
CoglTextureUnit *
_cogl_get_texture_unit (int index_);
void
_cogl_destroy_texture_units (void);
#endif /* __COGL_INTERNAL_H */

View File

@ -96,6 +96,7 @@ typedef struct _CoglJournalFlushState
CoglJournalIndices *indices;
size_t indices_type_size;
#endif
CoglMatrixStack *modelview_stack;
} CoglJournalFlushState;
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
@ -193,7 +194,12 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
g_print ("BATCHING: modelview batch len = %d\n", batch_len);
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
GE (glLoadMatrixf ((GLfloat *)&batch_start->model_view));
{
_cogl_matrix_stack_set (state->modelview_stack,
&batch_start->model_view);
_cogl_matrix_stack_flush_to_gl (state->modelview_stack,
COGL_MATRIX_MODELVIEW);
}
#ifdef HAVE_COGL_GL
@ -541,21 +547,20 @@ _cogl_journal_flush (void)
else
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 modelview matrix stack cache... */
_cogl_current_matrix_state_dirty ();
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
COGL_MATRIX_PROJECTION);
/* And explicitly flush other matrix stacks... */
_cogl_set_current_matrix (COGL_MATRIX_PROJECTION);
_cogl_current_matrix_state_flush ();
state.modelview_stack = ctx->modelview_stack;
_cogl_matrix_stack_push (ctx->modelview_stack);
/* 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...*/
if (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
/* If we have transformed all our quads at log time then we ensure no
* further model transform is applied by loading the identity matrix
* here... */
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{
GE (glMatrixMode (GL_MODELVIEW));
glLoadIdentity ();
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack,
COGL_MATRIX_MODELVIEW);
}
/* batch_and_call() batches a list of journal entries according to some
@ -586,6 +591,8 @@ _cogl_journal_flush (void)
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
&state); /* data */
_cogl_matrix_stack_pop (ctx->modelview_stack);
for (i = 0; i < ctx->journal->len; i++)
{
CoglJournalEntry *entry =

View File

@ -1169,8 +1169,11 @@ is_mipmap_filter (CoglMaterialFilter filter)
|| filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR);
}
/* FIXME: All direct manipulation of GL texture unit state should be dealt with
* by extending the CoglTextureUnit abstraction */
static void
_cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer,
CoglTextureUnit *unit,
CoglLayerInfo *gl_layer_info)
{
int n_rgb_func_args;
@ -1246,16 +1249,17 @@ _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer,
layer->texture_combine_constant));
}
#ifndef DISABLE_MATERIAL_CACHE
if ((gl_layer_info &&
gl_layer_info->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX) ||
(layer->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX))
#endif
{
_cogl_set_current_matrix (COGL_MATRIX_TEXTURE);
_cogl_current_matrix_load (&layer->matrix);
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
}
_cogl_matrix_stack_set (unit->matrix_stack, &layer->matrix);
else
_cogl_matrix_stack_load_identity (unit->matrix_stack);
/* TODO: Eventually we should just have something like
* _cogl_flush_texture_units() that we can call in
* _cogl_material_flush_layers_gl_state */
_cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
}
/*
@ -1327,6 +1331,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
#ifdef HAVE_COGL_GLES2
GLenum gl_internal_format;
#endif
CoglTextureUnit *unit;
new_gl_layer_info.layer0_overridden =
layer0_override_texture ? TRUE : FALSE;
@ -1366,6 +1371,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
}
GE (glActiveTexture (GL_TEXTURE0 + i));
unit = _cogl_get_texture_unit (i);
_cogl_texture_set_filters (layer->texture,
layer->min_filter,
@ -1453,7 +1459,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
}
}
_cogl_material_layer_flush_gl_sampler_state (layer, gl_layer_info);
_cogl_material_layer_flush_gl_sampler_state (layer, unit, gl_layer_info);
new_gl_layer_info.handle = layer_handle;
new_gl_layer_info.flags = layer->flags;

View File

@ -335,15 +335,28 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack,
void
_cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
GLenum gl_mode)
CoglMatrixMode mode)
{
CoglMatrixState *state;
GLenum gl_mode;
state = _cogl_matrix_stack_top (stack);
if (stack->flushed_state == state)
return;
switch (mode)
{
case COGL_MATRIX_MODELVIEW:
gl_mode = GL_MODELVIEW;
break;
case COGL_MATRIX_PROJECTION:
gl_mode = GL_PROJECTION;
break;
case COGL_MATRIX_TEXTURE:
gl_mode = GL_TEXTURE;
break;
}
GE (glMatrixMode (gl_mode));
/* In theory it might help the GL implementation if we used our

View File

@ -877,3 +877,62 @@ cogl_end_gl (void)
ctx->in_begin_gl_block = FALSE;
}
static CoglTextureUnit *
_cogl_texture_unit_new (void)
{
CoglTextureUnit *unit = g_new0 (CoglTextureUnit, 1);
unit->matrix_stack = _cogl_matrix_stack_new ();
return unit;
}
static void
_cogl_texture_unit_free (CoglTextureUnit *unit)
{
_cogl_matrix_stack_destroy (unit->matrix_stack);
g_free (unit);
}
CoglTextureUnit *
_cogl_get_texture_unit (int index_)
{
GList *l;
CoglTextureUnit *unit;
_COGL_GET_CONTEXT (ctx, NULL);
for (l = ctx->texture_units; l; l = l->next)
{
unit = l->data;
if (unit->index == index_)
return unit;
/* The units are always sorted, so at this point we know this unit
* doesn't exist */
if (unit->index > index_)
break;
}
/* NB: if we now insert a new layer before l, that will maintain order.
*/
unit = _cogl_texture_unit_new ();
/* Note: see comment after for() loop above */
ctx->texture_units =
g_list_insert_before (ctx->texture_units, l, unit);
return unit;
}
void
_cogl_destroy_texture_units (void)
{
GList *l;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
for (l = ctx->texture_units; l; l = l->next)
_cogl_texture_unit_free (l->data);
g_list_free (ctx->texture_units);
}