From 16a09763efcf5067975e9036ebba6aaf405260e3 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 11 Nov 2009 12:50:48 +0000 Subject: [PATCH] [cogl-material] Adds cogl_material_copy() API cogl_material_copy can be used to create a new CoglHandle referencing a copy of some given material. From now on we will advise that developers always aim to use this function instead of cogl_material_new() when creating a material that is in any way derived from another. By using cogl_material_copy, Cogl can maintain an ancestry for each material and keep track of "similar" materials. The plan is that Cogl will use this information to minimize the cost of GPU state transitions. --- cogl/cogl-context.c | 13 +++++--- cogl/cogl-context.h | 4 ++- cogl/cogl-material-private.h | 9 ++++++ cogl/cogl-material.c | 62 ++++++++++++++++++++++++++++++------ cogl/cogl-material.h | 18 +++++++++++ cogl/cogl.c | 6 ++-- 6 files changed, 95 insertions(+), 17 deletions(-) diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 34c65d08c..a05745bb4 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -64,6 +64,8 @@ cogl_create_context (void) _cogl_create_context_driver (_context); _cogl_features_init (); + _cogl_material_init_default_material (); + _context->enable_flags = 0; _context->color_alpha = 0; @@ -79,7 +81,7 @@ cogl_create_context (void) _context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; _context->texture_units = NULL; - _context->default_material = cogl_material_new (); + _context->simple_material = cogl_material_new (); _context->source_material = NULL; _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE; @@ -137,7 +139,7 @@ cogl_create_context (void) 0, /* auto calc row stride */ default_texture_data); - cogl_set_source (_context->default_material); + cogl_set_source (_context->simple_material); _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = _cogl_material_get_cogl_enable_flags (_context->source_material); @@ -166,8 +168,8 @@ _cogl_destroy_context () if (_context->default_gl_texture_rect_tex) cogl_handle_unref (_context->default_gl_texture_rect_tex); - if (_context->default_material) - cogl_handle_unref (_context->default_material); + if (_context->simple_material) + cogl_handle_unref (_context->simple_material); if (_context->journal) g_array_free (_context->journal, TRUE); @@ -182,6 +184,9 @@ _cogl_destroy_context () if (_context->quad_indices_short) cogl_handle_unref (_context->quad_indices_short); + if (_context->default_material) + cogl_handle_unref (_context->default_material); + g_free (_context); } diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index d10664f30..da7bb207b 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -44,6 +44,8 @@ typedef struct CoglFeatureFlags feature_flags; gboolean features_cached; + CoglHandle default_material; + /* Enable cache */ gulong enable_flags; guint8 color_alpha; @@ -62,7 +64,7 @@ typedef struct GList *texture_units; /* Materials */ - CoglHandle default_material; + CoglHandle simple_material; CoglHandle source_material; /* Textures */ diff --git a/cogl/cogl-material-private.h b/cogl/cogl-material-private.h index 83ddaa48c..c70ea304f 100644 --- a/cogl/cogl-material-private.h +++ b/cogl/cogl-material-private.h @@ -156,6 +156,15 @@ struct _CoglMaterial * able to fill your geometry according to a given Cogl material. */ +/* + * _cogl_material_init_default_material: + * + * This initializes the first material owned by the Cogl context. All + * subsequently instantiated materials created via the cogl_material_new() + * API will initially be a copy of this material. + */ +void +_cogl_material_init_default_material (void); /* * cogl_material_get_cogl_enable_flags: diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c index 1f0ed068b..b7ed041c2 100644 --- a/cogl/cogl-material.c +++ b/cogl/cogl-material.c @@ -57,6 +57,8 @@ #define glBlendEquationSeparate ctx->drv.pf_glBlendEquationSeparate #endif +static CoglHandle _cogl_material_layer_copy (CoglHandle layer_handle); + static void _cogl_material_free (CoglMaterial *tex); static void _cogl_material_layer_free (CoglMaterialLayer *layer); @@ -71,17 +73,19 @@ _cogl_material_error_quark (void) return g_quark_from_static_string ("cogl-material-error-quark"); } -CoglHandle -cogl_material_new (void) +void +_cogl_material_init_default_material (void) { /* Create new - blank - material */ - CoglMaterial *material = g_new0 (CoglMaterial, 1); + CoglMaterial *material = g_slice_new0 (CoglMaterial); GLubyte *unlit = material->unlit; GLfloat *ambient = material->ambient; GLfloat *diffuse = material->diffuse; GLfloat *specular = material->specular; GLfloat *emission = material->emission; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* Use the same defaults as the GL spec... */ unlit[0] = 0xff; unlit[1] = 0xff; unlit[2] = 0xff; unlit[3] = 0xff; material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR; @@ -116,9 +120,34 @@ cogl_material_new (void) material->layers = NULL; material->n_layers = 0; + ctx->default_material = _cogl_material_handle_new (material); +} + +CoglHandle +cogl_material_copy (CoglHandle handle) +{ + CoglMaterial *material = g_slice_new (CoglMaterial); + GList *l; + + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + memcpy (material, handle, sizeof (CoglMaterial)); + + material->layers = g_list_copy (material->layers); + for (l = material->layers; l; l = l->next) + l->data = _cogl_material_layer_copy (l->data); + return _cogl_material_handle_new (material); } +CoglHandle +cogl_material_new (void) +{ + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + return cogl_material_copy (ctx->default_material); +} + static void _cogl_material_free (CoglMaterial *material) { @@ -128,7 +157,7 @@ _cogl_material_free (CoglMaterial *material) g_list_foreach (material->layers, (GFunc)cogl_handle_unref, NULL); g_list_free (material->layers); - g_free (material); + g_slice_free (CoglMaterial, material); } static gboolean @@ -727,7 +756,7 @@ _cogl_material_get_layer (CoglMaterial *material, /* possibly flush primitives referencing the current state... */ _cogl_material_pre_change_notify (material, FALSE, NULL); - layer = g_new0 (CoglMaterialLayer, 1); + layer = g_slice_new0 (CoglMaterialLayer); layer_handle = _cogl_material_layer_handle_new (layer); layer->index = index_; @@ -1016,7 +1045,7 @@ _cogl_material_layer_free (CoglMaterialLayer *layer) { if (layer->texture != COGL_INVALID_HANDLE) cogl_handle_unref (layer->texture); - g_free (layer); + g_slice_free (CoglMaterialLayer, layer); } void @@ -1140,6 +1169,21 @@ _cogl_material_layer_get_flags (CoglHandle layer_handle) return layer->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX; } +static CoglHandle +_cogl_material_layer_copy (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer = + _cogl_material_layer_pointer_from_handle (layer_handle); + CoglMaterialLayer *layer_copy = g_slice_new (CoglMaterialLayer); + + memcpy (layer_copy, layer, sizeof (CoglMaterialLayer)); + + if (layer_copy->texture != COGL_INVALID_HANDLE) + cogl_handle_ref (layer_copy->texture); + + return _cogl_material_layer_handle_new (layer_copy); +} + static guint get_n_args_for_combine_func (GLint func) { @@ -1926,10 +1970,10 @@ cogl_set_source_texture (CoglHandle texture_handle) g_return_if_fail (texture_handle != COGL_INVALID_HANDLE); - cogl_material_set_layer (ctx->default_material, 0, texture_handle); + cogl_material_set_layer (ctx->simple_material, 0, texture_handle); cogl_color_set_from_4ub (&white, 0xff, 0xff, 0xff, 0xff); - cogl_material_set_color (ctx->default_material, &white); - cogl_set_source (ctx->default_material); + cogl_material_set_color (ctx->simple_material, &white); + cogl_set_source (ctx->simple_material); } CoglMaterialFilter diff --git a/cogl/cogl-material.h b/cogl/cogl-material.h index 5e4527de6..bfed4ee66 100644 --- a/cogl/cogl-material.h +++ b/cogl/cogl-material.h @@ -90,6 +90,24 @@ CoglHandle cogl_material_new (void); #ifndef COGL_DISABLE_DEPRECATED +/** + * cogl_material_copy: + * + * Creates a new material handle with the configuration copied from the + * source material. + * + * We would strongly advise developers to always aim to use + * cogl_material_copy() instead of cogl_material_new() whenever there will + * be any similarity between two materials. Copying a material helps Cogl + * keep track of a materials ancestry which we may use to help minimize GPU + * state changes. + * + * Returns: a handle to the new material + * + * Since: 1.2 + */ +CoglHandle cogl_material_copy (CoglHandle source); + /** * cogl_material_ref: * @handle: a @CoglHandle. diff --git a/cogl/cogl.c b/cogl/cogl.c index 1c660552e..04917e872 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -328,13 +328,13 @@ cogl_set_source_color (const CoglColor *color) _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* In case cogl_set_source_texture was previously used... */ - cogl_material_remove_layer (ctx->default_material, 0); + cogl_material_remove_layer (ctx->simple_material, 0); premultiplied = *color; cogl_color_premultiply (&premultiplied); - cogl_material_set_color (ctx->default_material, &premultiplied); + cogl_material_set_color (ctx->simple_material, &premultiplied); - cogl_set_source (ctx->default_material); + cogl_set_source (ctx->simple_material); } void