diff --git a/README b/README index aff1a6ea0..b1d1ca5de 100644 --- a/README +++ b/README @@ -231,6 +231,11 @@ Cogl API changes for Clutter 1.2 clip state and switching to/from offscreen rendering will automatically save and restore the clip state. +* cogl_material_copy() was added. It is advised that developers use + this instead of cogl_material_new() when creating a material that is in some + way derived from another. This will allow Cogl to track material + ancestries/similarities and reduce the cost of GPU state changes. + Release Notes for Clutter 1.0 ------------------------------- diff --git a/clutter/cogl/cogl/cogl-context.c b/clutter/cogl/cogl/cogl-context.c index 34c65d08c..a05745bb4 100644 --- a/clutter/cogl/cogl/cogl-context.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-context.h b/clutter/cogl/cogl/cogl-context.h index d10664f30..da7bb207b 100644 --- a/clutter/cogl/cogl/cogl-context.h +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-material-private.h b/clutter/cogl/cogl/cogl-material-private.h index 83ddaa48c..c70ea304f 100644 --- a/clutter/cogl/cogl/cogl-material-private.h +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-material.c b/clutter/cogl/cogl/cogl-material.c index 1f0ed068b..b7ed041c2 100644 --- a/clutter/cogl/cogl/cogl-material.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-material.h b/clutter/cogl/cogl/cogl-material.h index 5e4527de6..bfed4ee66 100644 --- a/clutter/cogl/cogl/cogl-material.h +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c index 1c660552e..04917e872 100644 --- a/clutter/cogl/cogl/cogl.c +++ b/clutter/cogl/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