[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.
This commit is contained in:
Robert Bragg 2009-11-11 12:50:48 +00:00
parent 78fb882a4b
commit 16a09763ef
6 changed files with 95 additions and 17 deletions

View File

@ -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);
}

View File

@ -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 */

View File

@ -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:

View File

@ -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

View File

@ -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.

View File

@ -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