From 2656b569b9911b8aa427a5a02c8b1f4095de6ed7 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 29 Sep 2009 02:58:27 +0100 Subject: [PATCH] [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 54159f5a1d029db) 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. --- clutter/cogl/cogl/cogl-context.c | 4 + clutter/cogl/cogl/cogl-context.h | 5 +- clutter/cogl/cogl/cogl-current-matrix.c | 236 +++++------------------- clutter/cogl/cogl/cogl-internal.h | 12 ++ clutter/cogl/cogl/cogl-journal.c | 33 ++-- clutter/cogl/cogl/cogl-material.c | 22 ++- clutter/cogl/cogl/cogl-matrix-stack.c | 15 +- clutter/cogl/cogl/cogl.c | 59 ++++++ 8 files changed, 174 insertions(+), 212 deletions(-) diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c index e93b5dac0..cb93fdcd4 100644 --- a/clutter/cogl/cogl/cogl-context.c +++ b/clutter/cogl/cogl/cogl-context.c @@ -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); diff --git a/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h index aecf5cc3c..33d8948bc 100644 --- a/clutter/cogl/cogl/cogl-context.h +++ b/clutter/cogl/cogl/cogl-context.h @@ -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]; diff --git a/clutter/cogl/cogl/cogl-current-matrix.c b/clutter/cogl/cogl/cogl-current-matrix.c index 217eb2df4..75e4e4ac5 100644 --- a/clutter/cogl/cogl/cogl-current-matrix.c +++ b/clutter/cogl/cogl/cogl-current-matrix.c @@ -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, ¤t_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, ¤t_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); } diff --git a/clutter/cogl/cogl/cogl-internal.h b/clutter/cogl/cogl/cogl-internal.h index b488c5633..65c213b65 100644 --- a/clutter/cogl/cogl/cogl-internal.h +++ b/clutter/cogl/cogl/cogl-internal.h @@ -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 */ diff --git a/clutter/cogl/cogl/cogl-journal.c b/clutter/cogl/cogl/cogl-journal.c index e9a7b61dc..aa0d5892e 100644 --- a/clutter/cogl/cogl/cogl-journal.c +++ b/clutter/cogl/cogl/cogl-journal.c @@ -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 = diff --git a/clutter/cogl/cogl/cogl-material.c b/clutter/cogl/cogl/cogl-material.c index d47fad784..8ef18027c 100644 --- a/clutter/cogl/cogl/cogl-material.c +++ b/clutter/cogl/cogl/cogl-material.c @@ -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; diff --git a/clutter/cogl/cogl/cogl-matrix-stack.c b/clutter/cogl/cogl/cogl-matrix-stack.c index ceda0576f..39e4e8476 100644 --- a/clutter/cogl/cogl/cogl-matrix-stack.c +++ b/clutter/cogl/cogl/cogl-matrix-stack.c @@ -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 diff --git a/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c index e16637e32..c096d4450 100644 --- a/clutter/cogl/cogl/cogl.c +++ b/clutter/cogl/cogl/cogl.c @@ -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); +} +