diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index e93b5dac0..cb93fdcd4 100644 --- a/cogl/cogl-context.c +++ b/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/cogl/cogl-context.h b/cogl/cogl-context.h index aecf5cc3c..33d8948bc 100644 --- a/cogl/cogl-context.h +++ b/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/cogl/cogl-current-matrix.c b/cogl/cogl-current-matrix.c index 217eb2df4..75e4e4ac5 100644 --- a/cogl/cogl-current-matrix.c +++ b/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/cogl/cogl-internal.h b/cogl/cogl-internal.h index b488c5633..65c213b65 100644 --- a/cogl/cogl-internal.h +++ b/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/cogl/cogl-journal.c b/cogl/cogl-journal.c index e9a7b61dc..aa0d5892e 100644 --- a/cogl/cogl-journal.c +++ b/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/cogl/cogl-material.c b/cogl/cogl-material.c index d47fad784..8ef18027c 100644 --- a/cogl/cogl-material.c +++ b/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/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c index ceda0576f..39e4e8476 100644 --- a/cogl/cogl-matrix-stack.c +++ b/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/cogl/cogl.c b/cogl/cogl.c index e16637e32..c096d4450 100644 --- a/cogl/cogl.c +++ b/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); +} +