[cogl-material] Converts clutter-texture/clutter-clone-texture to the material API

This converts clutter-texture to use the new CoglMaterial API instead of
cogl_texture_rectangle.

This change does not add multi-texturing support to Clutter, it's more about
aiming to deprecate cogl_texture_rectangle, and moving everything over to the
cogl_set_source(material); cogl_draw_somthing(); coding pattern.

With this patch, the code can be built with/without CoglMaterial support so we
can do comparisons of the old/new code for a transient period. (look for the
USE_COGL_MATERIAL define)

Note: The FBO paths haven't currently been tested, so they may need some
tweaks.
This commit is contained in:
Robert Bragg 2008-12-23 16:39:11 +00:00
parent bb938ac4ff
commit 4e57972bd6
3 changed files with 242 additions and 23 deletions

View File

@ -61,6 +61,8 @@ G_DEFINE_TYPE (ClutterCloneTexture,
#define CLUTTER_CLONE_TEXTURE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_CLONE_TEXTURE, ClutterCloneTexturePrivate))
#define USE_COGL_MATERIAL 1
struct _ClutterCloneTexturePrivate
{
ClutterTexture *parent_texture;
@ -145,6 +147,10 @@ clutter_clone_texture_paint (ClutterActor *self)
CoglHandle cogl_texture;
ClutterFixed t_w, t_h;
guint tex_width, tex_height;
#if USE_COGL_MATERIAL
CoglHandle cogl_material;
CoglFixed tex_coords[4];
#endif
priv = CLUTTER_CLONE_TEXTURE (self)->priv;
@ -187,7 +193,14 @@ clutter_clone_texture_paint (ClutterActor *self)
x_1, y_1, x_2, y_2,
clutter_actor_get_opacity (self));
#if USE_COGL_MATERIAL
cogl_material = clutter_texture_get_cogl_material (priv->parent_texture);
/* FIXME: This is a lazy way of extracting the cogl_texture for the
* the first layer of the above material... */
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
#else
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
#endif
if (cogl_texture == COGL_INVALID_HANDLE)
return;
@ -206,11 +219,24 @@ clutter_clone_texture_paint (ClutterActor *self)
else
t_h = COGL_FIXED_1;
#if USE_COGL_MATERIAL
cogl_set_source (cogl_material);
tex_coords[0] = 0;
tex_coords[1] = 0;
tex_coords[2] = t_w;
tex_coords[3] = t_h;
cogl_material_rectangle (0, 0,
COGL_FIXED_FROM_INT (x_2 - x_1),
COGL_FIXED_FROM_INT (y_2 - y_1),
tex_coords);
#else
/* Parent paint translated us into position */
cogl_texture_rectangle (cogl_texture, 0, 0,
COGL_FIXED_FROM_INT (x_2 - x_1),
COGL_FIXED_FROM_INT (y_2 - y_1),
0, 0, t_w, t_h);
#endif
}
static void

View File

@ -79,7 +79,12 @@ struct _ClutterTexturePrivate
gint height;
gint max_tile_waste;
ClutterTextureQuality filter_quality;
#if USE_COGL_MATERIAL
CoglHandle material;
#else
CoglHandle texture;
#endif
CoglHandle fbo_texture;
gboolean no_slice;
ClutterActor *fbo_source;
@ -109,6 +114,9 @@ enum
PROP_REPEAT_X,
PROP_FILTER_QUALITY,
PROP_COGL_TEXTURE,
#if USE_COGL_MATERIAL
PROP_COGL_MATERIAL,
#endif
PROP_FILENAME,
PROP_KEEP_ASPECT_RATIO
};
@ -175,11 +183,15 @@ texture_free_gl_resources (ClutterTexture *texture)
CLUTTER_MARK();
#if USE_COGL_MATERIAL
cogl_material_remove_layer (priv->material, 0);
#else
if (priv->texture != COGL_INVALID_HANDLE)
{
cogl_texture_unref (priv->texture);
priv->texture = COGL_INVALID_HANDLE;
}
#endif
}
static void
@ -191,8 +203,13 @@ clutter_texture_unrealize (ClutterActor *actor)
texture = CLUTTER_TEXTURE(actor);
priv = texture->priv;
#if USE_COGL_MATERIAL
if (priv->material == COGL_INVALID_HANDLE)
return;
#else
if (priv->texture == COGL_INVALID_HANDLE)
return;
#endif
/* there's no need to read the pixels back when unrealizing inside
* a dispose run, and the dispose() call will release the GL
@ -249,10 +266,10 @@ clutter_texture_realize (ClutterActor *actor)
{
/* Handle FBO's */
if (priv->texture != COGL_INVALID_HANDLE)
cogl_texture_unref (priv->texture);
if (priv->fbo_texture != COGL_INVALID_HANDLE)
cogl_texture_unref (priv->fbo_texture);
priv->texture
priv->fbo_texture
= cogl_texture_new_with_size
(priv->width,
priv->height,
@ -260,11 +277,11 @@ clutter_texture_realize (ClutterActor *actor)
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
COGL_PIXEL_FORMAT_RGBA_8888);
cogl_texture_set_filters (priv->texture,
cogl_texture_set_filters (priv->fbo_texture,
clutter_texture_quality_to_cogl_min_filter (priv->filter_quality),
clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality));
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->texture);
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->fbo_texture);
if (priv->fbo_handle == COGL_INVALID_HANDLE)
{
@ -475,6 +492,9 @@ clutter_texture_paint (ClutterActor *self)
gint x_1, y_1, x_2, y_2;
CoglColor transparent_col;
ClutterFixed t_w, t_h;
#if USE_COGL_MATERIAL
CoglFixed tex_coords[4];
#endif
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR(texture)))
clutter_actor_realize (CLUTTER_ACTOR(texture));
@ -587,10 +607,23 @@ clutter_texture_paint (ClutterActor *self)
t_h = COGL_FIXED_1;
/* Paint will have translated us */
#if USE_COGL_MATERIAL
cogl_set_source (priv->material);
tex_coords[0] = 0;
tex_coords[1] = 0;
tex_coords[2] = t_w;
tex_coords[3] = t_h;
cogl_material_rectangle (0, 0,
COGL_FIXED_FROM_INT (x_2 - x_1),
COGL_FIXED_FROM_INT (y_2 - y_1),
tex_coords);
#else
cogl_texture_rectangle (priv->texture, 0, 0,
COGL_FIXED_FROM_INT (x_2 - x_1),
COGL_FIXED_FROM_INT (y_2 - y_1),
0, 0, t_w, t_h);
#endif
}
static void
@ -667,6 +700,11 @@ clutter_texture_set_property (GObject *object,
clutter_texture_set_cogl_texture
(texture, (CoglHandle) g_value_get_boxed (value));
break;
#if USE_COGL_MATERIAL
clutter_texture_set_cogl_material
(texture, (CoglHandle) g_value_get_boxed (value));
break;
#endif
case PROP_FILENAME:
clutter_texture_set_from_file (texture,
g_value_get_string (value),
@ -692,6 +730,7 @@ clutter_texture_get_property (GObject *object,
{
ClutterTexture *texture;
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
texture = CLUTTER_TEXTURE(object);
priv = texture->priv;
@ -702,10 +741,11 @@ clutter_texture_get_property (GObject *object,
g_value_set_int (value, clutter_texture_get_max_tile_waste (texture));
break;
case PROP_PIXEL_FORMAT:
if (priv->texture == COGL_INVALID_HANDLE)
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
g_value_set_int (value, COGL_PIXEL_FORMAT_ANY);
else
g_value_set_int (value, cogl_texture_get_format (priv->texture));
g_value_set_int (value, cogl_texture_get_format (cogl_texture));
break;
case PROP_SYNC_SIZE:
g_value_set_boolean (value, priv->sync_actor_size);
@ -722,6 +762,11 @@ clutter_texture_get_property (GObject *object,
case PROP_COGL_TEXTURE:
g_value_set_boxed (value, clutter_texture_get_cogl_texture (texture));
break;
#if USE_COGL_MATERIAL
case PROP_COGL_MATERIAL:
g_value_set_boxed (value, clutter_texture_get_cogl_material (texture));
break;
#endif
case PROP_NO_SLICE:
g_value_set_boolean (value, priv->no_slice);
break;
@ -836,6 +881,17 @@ clutter_texture_class_init (ClutterTextureClass *klass)
CLUTTER_TYPE_TEXTURE_HANDLE,
G_PARAM_READWRITE));
#if USE_COGL_MATERIAL
g_object_class_install_property
(gobject_class, PROP_COGL_MATERIAL,
g_param_spec_boxed ("cogl-material",
"COGL Material",
"The underlying COGL material handle used to draw "
"this actor",
CLUTTER_TYPE_MATERIAL_HANDLE,
G_PARAM_READWRITE));
#endif
g_object_class_install_property
(gobject_class, PROP_FILENAME,
g_param_spec_string ("filename",
@ -956,7 +1012,12 @@ clutter_texture_init (ClutterTexture *self)
priv->repeat_x = FALSE;
priv->repeat_y = FALSE;
priv->sync_actor_size = TRUE;
#if USE_COGL_MATERIAL
priv->material = cogl_material_new ();
priv->fbo_texture = COGL_INVALID_HANDLE;
#else
priv->texture = COGL_INVALID_HANDLE;
#endif
priv->fbo_handle = COGL_INVALID_HANDLE;
priv->local_data = NULL;
priv->keep_aspect_ratio = FALSE;
@ -968,6 +1029,7 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
ClutterTexturePrivate *priv;
int bpp;
CoglPixelFormat pixel_format;
CoglHandle cogl_texture;
priv = texture->priv;
@ -977,12 +1039,23 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
priv->local_data = NULL;
}
#if USE_COGL_MATERIAL
if (priv->material == COGL_INVALID_HANDLE)
return;
#else
if (priv->texture == COGL_INVALID_HANDLE)
return;
#endif
priv->local_data_width = cogl_texture_get_width (priv->texture);
priv->local_data_height = cogl_texture_get_height (priv->texture);
pixel_format = cogl_texture_get_format (priv->texture);
#if USE_COGL_MATERIAL
cogl_texture = clutter_texture_get_cogl_texture (texture);
#else
cogl_texture = priv->texture;
#endif
priv->local_data_width = cogl_texture_get_width (cogl_texture);
priv->local_data_height = cogl_texture_get_height (cogl_texture);
pixel_format = cogl_texture_get_format (cogl_texture);
priv->local_data_has_alpha = pixel_format & COGL_A_BIT;
bpp = priv->local_data_has_alpha ? 4 : 3;
@ -998,7 +1071,7 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
priv->local_data = g_malloc (priv->local_data_rowstride
* priv->local_data_height);
if (cogl_texture_get_data (priv->texture,
if (cogl_texture_get_data (cogl_texture,
priv->local_data_has_alpha
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
@ -1033,6 +1106,58 @@ clutter_texture_load_from_local_data (ClutterTexture *texture)
priv->local_data = NULL;
}
#if USE_COGL_MATERIAL
/**
* clutter_texture_get_cogl_material:
* @texture: A #ClutterTexture
*
* Returns a handle to the underlying COGL material used for drawing
* the actor. No extra reference is taken so if you need to keep the
* handle then you should call cogl_material_ref on it.
*
* Since: 1.0
*
* Return value: COGL material handle
*/
CoglHandle
clutter_texture_get_cogl_material (ClutterTexture *texture)
{
return texture->priv->material;
}
/**
* clutter_texture_set_cogl_material:
* @texture: A #ClutterTexture
* @cogl_material: A CoglHandle for a material
*
* Replaces the underlying COGL texture drawn by this actor with
* @cogl_tex. A reference to the texture is taken so if the handle is
* no longer needed it should be deref'd with cogl_texture_unref.
*
* Since: 0.8
*
*/
void
clutter_texture_set_cogl_material (ClutterTexture *texture,
CoglHandle cogl_material)
{
CoglHandle cogl_texture;
/* This */
if (texture->priv->material)
cogl_material_unref (texture->priv->material);
texture->priv->material = cogl_material;
/* XXX: We are re-asserting the first layer of the new material to ensure the
* priv state is in sync with the contents of the material. */
cogl_texture = clutter_texture_get_cogl_texture (texture);
clutter_texture_set_cogl_texture (texture, cogl_texture);
/* XXX: If we add support for more material layers, this will need
* extending */
}
#endif
/**
* clutter_texture_get_cogl_texture
* @texture: A #ClutterTexture
@ -1048,9 +1173,25 @@ clutter_texture_load_from_local_data (ClutterTexture *texture)
CoglHandle
clutter_texture_get_cogl_texture (ClutterTexture *texture)
{
#if USE_COGL_MATERIAL
const GList *layers;
int n_layers;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), COGL_INVALID_HANDLE);
layers = cogl_material_get_layers (texture->priv->material);
n_layers = g_list_length ((GList *)layers);
if (n_layers == 0)
return COGL_INVALID_HANDLE;
else if (n_layers != 1)
{
g_warning ("FIXME: Clutter texture only works with single layer"
" materials at the moment!\n");
}
return cogl_material_layer_get_texture (layers->data);
#else
return texture->priv->texture;
#endif
}
/**
@ -1090,7 +1231,12 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
/* Remove old texture */
texture_free_gl_resources (texture);
/* Use the new texture */
#if USE_COGL_MATERIAL
cogl_material_set_layer (priv->material, 0, cogl_tex);
#else
priv->texture = cogl_tex;
#endif
size_change = width != priv->width || height != priv->height;
priv->width = width;
@ -1379,11 +1525,12 @@ clutter_texture_set_filter_quality (ClutterTexture *texture,
if (filter_quality != old_quality)
{
CoglHandle cogl_texture = clutter_texture_get_cogl_texture (texture);
priv->filter_quality = filter_quality;
/* Is this actually needed - causes problems with TFP mipmaps */
if (priv->texture != COGL_INVALID_HANDLE)
cogl_texture_set_filters (priv->texture,
if (cogl_texture != COGL_INVALID_HANDLE)
cogl_texture_set_filters (cogl_texture,
clutter_texture_quality_to_cogl_min_filter (priv->filter_quality),
clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality));
@ -1451,15 +1598,21 @@ clutter_texture_set_max_tile_waste (ClutterTexture *texture,
gint max_tile_waste)
{
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
g_return_if_fail (CLUTTER_IS_TEXTURE (texture));
priv = texture->priv;
#if USE_COGL_MATERIAL
cogl_texture = clutter_texture_get_cogl_texture (texture);
#else
cogl_texture = priv->texture;
#endif
/* There's no point in changing the max_tile_waste if the texture
has already been created because it will be overridden with the
value from the texture handle */
if (priv->texture == COGL_INVALID_HANDLE)
if (cogl_texture == COGL_INVALID_HANDLE)
priv->max_tile_waste = max_tile_waste;
}
@ -1479,17 +1632,23 @@ gint
clutter_texture_get_max_tile_waste (ClutterTexture *texture)
{
ClutterTexturePrivate *priv;
CoglHandle cogl_texture;
g_return_val_if_fail (CLUTTER_IS_TEXTURE (texture), 0);
priv = texture->priv;
#if USE_COGL_MATERIAL
cogl_texture = clutter_texture_get_cogl_texture (texture);
#else
cogl_texture = priv->texture;
#endif
if (priv->texture == COGL_INVALID_HANDLE)
if (cogl_texture == COGL_INVALID_HANDLE)
return texture->priv->max_tile_waste;
else
/* If we have a valid texture handle then use the value from that
instead */
return cogl_texture_get_max_waste (texture->priv->texture);
return cogl_texture_get_max_waste (cogl_texture);
}
/**
@ -1603,6 +1762,7 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
{
ClutterTexturePrivate *priv;
CoglPixelFormat source_format;
CoglHandle cogl_texture;
priv = texture->priv;
@ -1635,7 +1795,8 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
clutter_actor_realize (CLUTTER_ACTOR (texture));
if (priv->texture == COGL_INVALID_HANDLE)
cogl_texture = clutter_texture_get_cogl_texture (texture);
if (cogl_texture == COGL_INVALID_HANDLE)
{
g_set_error (error, CLUTTER_TEXTURE_ERROR,
CLUTTER_TEXTURE_ERROR_BAD_FORMAT,
@ -1643,7 +1804,7 @@ clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
return FALSE;
}
if (!cogl_texture_set_region (priv->texture,
if (!cogl_texture_set_region (cogl_texture,
0, 0,
x, y, width, height,
width, height,
@ -1686,17 +1847,17 @@ on_fbo_source_size_change (GObject *object,
priv->width = w;
priv->height = h;
priv->texture = cogl_texture_new_with_size (MAX (priv->width, 1),
priv->fbo_texture = cogl_texture_new_with_size (MAX (priv->width, 1),
MAX (priv->height, 1),
-1,
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
COGL_PIXEL_FORMAT_RGBA_8888);
cogl_texture_set_filters (priv->texture,
cogl_texture_set_filters (priv->fbo_texture,
clutter_texture_quality_to_cogl_min_filter (priv->filter_quality),
clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality));
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->texture);
priv->fbo_handle = cogl_offscreen_new_to_texture (priv->fbo_texture);
if (priv->fbo_handle == COGL_INVALID_HANDLE)
{
@ -1940,3 +2101,22 @@ clutter_texture_handle_get_type (void)
return our_type;
}
#if USE_COGL_MATERIAL
GType
clutter_material_handle_get_type (void)
{
static GType our_type = 0;
if (G_UNLIKELY (!our_type))
{
our_type =
g_boxed_type_register_static (I_("ClutterMaterialHandle"),
(GBoxedCopyFunc) cogl_material_ref,
(GBoxedFreeFunc) cogl_material_unref);
}
return our_type;
}
#endif

View File

@ -33,6 +33,8 @@
G_BEGIN_DECLS
#define USE_COGL_MATERIAL 1
#define CLUTTER_TYPE_TEXTURE (clutter_texture_get_type ())
#define CLUTTER_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXTURE, ClutterTexture))
#define CLUTTER_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TEXTURE, ClutterTextureClass))
@ -41,6 +43,9 @@ G_BEGIN_DECLS
#define CLUTTER_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXTURE, ClutterTextureClass))
#define CLUTTER_TYPE_TEXTURE_HANDLE (clutter_texture_handle_get_type ())
#if USE_COGL_MATERIAL
#define CLUTTER_TYPE_MATERIAL_HANDLE (clutter_material_handle_get_type ())
#endif
/**
* ClutterTextureError:
@ -135,6 +140,9 @@ typedef enum { /*< prefix=CLUTTER_TEXTURE_QUALITY >*/
GType clutter_texture_get_type (void) G_GNUC_CONST;
GType clutter_texture_handle_get_type (void) G_GNUC_CONST;
#if USE_COGL_MATERIAL
GType clutter_material_handle_get_type (void) G_GNUC_CONST;
#endif
ClutterActor * clutter_texture_new (void);
ClutterActor * clutter_texture_new_from_file (const gchar *filename,
@ -181,6 +189,11 @@ gint clutter_texture_get_max_tile_waste (ClutterTexture
CoglHandle clutter_texture_get_cogl_texture (ClutterTexture *texture);
void clutter_texture_set_cogl_texture (ClutterTexture *texture,
CoglHandle cogl_tex);
#if USE_COGL_MATERIAL
CoglHandle clutter_texture_get_cogl_material (ClutterTexture *texture);
void clutter_texture_set_cogl_material (ClutterTexture *texture,
CoglHandle cogl_material);
#endif
G_END_DECLS