st-theme-node-drawing: Don't create lots of one-shot materials

A few places in st-theme-node-drawing create one-shot material, paint
with it and then free it. This is suboptimal with current Cogl because
it will end up compiling an ARBfp program just for that single paint
and then it will throw it away when the material is destroyed.

There is a new function in st-private.c called
_st_create_texture_material. This creates a simple material for a
texture based on a common parent material that points to a dummy
texture. Any materials created with this function are likely to be
able to share the same program unless the material is further modified
to contain a different number of layers. It would be possible to use
cogl_set_source_texture for this instead except that it's not possible
to modify the material's color in that case so we couldn't render the
texture with opacity.

The corner textures are now stored as a handle to a material that
references the texture rather than storing the texure directly. There
is also a separate border_material member which always points to
border_texture as the only layer.

https://bugzilla.gnome.org/show_bug.cgi?id=633340
This commit is contained in:
Neil Roberts 2010-10-27 17:41:20 +01:00
parent f365484a5c
commit d66e7dd49e
4 changed files with 84 additions and 49 deletions

View File

@ -324,6 +324,49 @@ _st_set_text_from_style (ClutterText *text,
} }
} }
/**
* _st_create_texture_material:
* @src_texture: The CoglTexture for the material
*
* Creates a simple material which contains the given texture as a
* single layer.
*/
CoglHandle
_st_create_texture_material (CoglHandle src_texture)
{
static CoglHandle texture_material_template = COGL_INVALID_HANDLE;
CoglHandle material;
g_return_val_if_fail (src_texture != COGL_INVALID_HANDLE,
COGL_INVALID_HANDLE);
/* We use a material that has a dummy texture as a base for all
texture materials. The idea is that only the Cogl texture object
would be different in the children so it is likely that Cogl will
be able to share GL programs between all the textures. */
if (G_UNLIKELY (texture_material_template == COGL_INVALID_HANDLE))
{
static const guint8 white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
CoglHandle dummy_texture;
dummy_texture =
cogl_texture_new_from_data (1, 1,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
4, white_pixel);
texture_material_template = cogl_material_new ();
cogl_material_set_layer (texture_material_template, 0, dummy_texture);
cogl_handle_unref (dummy_texture);
}
material = cogl_material_copy (texture_material_template);
cogl_material_set_layer (material, 0, src_texture);
return material;
}
/***** /*****
* Shadows * Shadows

View File

@ -73,6 +73,8 @@ void _st_allocate_fill (StWidget *parent,
void _st_set_text_from_style (ClutterText *text, void _st_set_text_from_style (ClutterText *text,
StThemeNode *theme_node); StThemeNode *theme_node);
CoglHandle _st_create_texture_material (CoglHandle src_texture);
/* Helper for widgets which need to draw additional shadows */ /* Helper for widgets which need to draw additional shadows */
CoglHandle _st_create_shadow_material (StShadow *shadow_spec, CoglHandle _st_create_shadow_material (StShadow *shadow_spec,
CoglHandle src_texture); CoglHandle src_texture);

View File

@ -52,7 +52,7 @@ typedef struct {
} StCornerSpec; } StCornerSpec;
static CoglHandle static CoglHandle
create_corner_texture (StCornerSpec *corner) create_corner_material (StCornerSpec *corner)
{ {
CoglHandle texture; CoglHandle texture;
cairo_t *cr; cairo_t *cr;
@ -167,7 +167,7 @@ load_corner (StTextureCache *cache,
{ {
LoadCornerData *data = datap; LoadCornerData *data = datap;
return create_corner_texture (data->corner); return create_corner_material (data->corner);
} }
/* To match the CSS specification, we want the border to look like it was /* To match the CSS specification, we want the border to look like it was
@ -222,7 +222,7 @@ static CoglHandle
st_theme_node_lookup_corner (StThemeNode *node, st_theme_node_lookup_corner (StThemeNode *node,
StCorner corner_id) StCorner corner_id)
{ {
CoglHandle texture; CoglHandle texture, material;
char *key; char *key;
StTextureCache *cache; StTextureCache *cache;
StCornerSpec corner; StCornerSpec corner;
@ -269,10 +269,12 @@ st_theme_node_lookup_corner (StThemeNode *node,
data.node = node; data.node = node;
data.corner = &corner; data.corner = &corner;
texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &data, NULL); texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &data, NULL);
material = _st_create_texture_material (texture);
cogl_handle_unref (texture);
g_free (key); g_free (key);
return texture; return material;
} }
static void static void
@ -511,12 +513,14 @@ _st_theme_node_free_drawing_state (StThemeNode *node)
cogl_handle_unref (node->background_shadow_material); cogl_handle_unref (node->background_shadow_material);
if (node->border_texture != COGL_INVALID_HANDLE) if (node->border_texture != COGL_INVALID_HANDLE)
cogl_handle_unref (node->border_texture); cogl_handle_unref (node->border_texture);
if (node->border_material != COGL_INVALID_HANDLE)
cogl_handle_unref (node->border_material);
if (node->border_shadow_material != COGL_INVALID_HANDLE) if (node->border_shadow_material != COGL_INVALID_HANDLE)
cogl_handle_unref (node->border_shadow_material); cogl_handle_unref (node->border_shadow_material);
for (corner_id = 0; corner_id < 4; corner_id++) for (corner_id = 0; corner_id < 4; corner_id++)
if (node->corner_texture[corner_id] != COGL_INVALID_HANDLE) if (node->corner_material[corner_id] != COGL_INVALID_HANDLE)
cogl_handle_unref (node->corner_texture[corner_id]); cogl_handle_unref (node->corner_material[corner_id]);
_st_theme_node_init_drawing_state (node); _st_theme_node_init_drawing_state (node);
} }
@ -530,9 +534,10 @@ _st_theme_node_init_drawing_state (StThemeNode *node)
node->background_shadow_material = COGL_INVALID_HANDLE; node->background_shadow_material = COGL_INVALID_HANDLE;
node->border_shadow_material = COGL_INVALID_HANDLE; node->border_shadow_material = COGL_INVALID_HANDLE;
node->border_texture = COGL_INVALID_HANDLE; node->border_texture = COGL_INVALID_HANDLE;
node->border_material = COGL_INVALID_HANDLE;
for (corner_id = 0; corner_id < 4; corner_id++) for (corner_id = 0; corner_id < 4; corner_id++)
node->corner_texture[corner_id] = COGL_INVALID_HANDLE; node->corner_material[corner_id] = COGL_INVALID_HANDLE;
} }
static void st_theme_node_paint_borders (StThemeNode *node, static void st_theme_node_paint_borders (StThemeNode *node,
@ -581,6 +586,11 @@ st_theme_node_render_resources (StThemeNode *node,
node->border_texture = st_theme_node_render_gradient (node); node->border_texture = st_theme_node_render_gradient (node);
} }
if (node->border_texture)
node->border_material = _st_create_texture_material (node->border_texture);
else
node->border_material = COGL_INVALID_HANDLE;
if (shadow_spec) if (shadow_spec)
{ {
if (node->border_texture != COGL_INVALID_HANDLE) if (node->border_texture != COGL_INVALID_HANDLE)
@ -630,40 +640,26 @@ st_theme_node_render_resources (StThemeNode *node,
} }
} }
node->corner_texture[ST_CORNER_TOPLEFT] = node->corner_material[ST_CORNER_TOPLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPLEFT); st_theme_node_lookup_corner (node, ST_CORNER_TOPLEFT);
node->corner_texture[ST_CORNER_TOPRIGHT] = node->corner_material[ST_CORNER_TOPRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPRIGHT); st_theme_node_lookup_corner (node, ST_CORNER_TOPRIGHT);
node->corner_texture[ST_CORNER_BOTTOMRIGHT] = node->corner_material[ST_CORNER_BOTTOMRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMRIGHT); st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMRIGHT);
node->corner_texture[ST_CORNER_BOTTOMLEFT] = node->corner_material[ST_CORNER_BOTTOMLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMLEFT); st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMLEFT);
} }
static void static void
paint_texture_with_opacity (CoglHandle texture, paint_material_with_opacity (CoglHandle material,
ClutterActorBox *box, ClutterActorBox *box,
guint8 paint_opacity) guint8 paint_opacity)
{ {
if (paint_opacity == 255)
{
/* Minor: optimization use the default material if we can */
cogl_set_source_texture (texture);
cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
return;
}
CoglHandle material;
material = cogl_material_new ();
cogl_material_set_layer (material, 0, texture);
cogl_material_set_color4ub (material, cogl_material_set_color4ub (material,
paint_opacity, paint_opacity, paint_opacity, paint_opacity); paint_opacity, paint_opacity, paint_opacity, paint_opacity);
cogl_set_source (material); cogl_set_source (material);
cogl_rectangle (box->x1, box->y1, box->x2, box->y2); cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
cogl_handle_unref (material);
} }
static void static void
@ -678,7 +674,6 @@ st_theme_node_paint_borders (StThemeNode *node,
int max_width_radius[4]; int max_width_radius[4];
int corner_id; int corner_id;
ClutterColor border_color; ClutterColor border_color;
CoglHandle material;
width = box->x2 - box->x1; width = box->x2 - box->x1;
height = box->y2 - box->y1; height = box->y2 - box->y1;
@ -753,19 +748,15 @@ st_theme_node_paint_borders (StThemeNode *node,
/* corners */ /* corners */
if (max_border_radius > 0) if (max_border_radius > 0)
{ {
material = cogl_material_new ();
cogl_material_set_color4ub (material,
paint_opacity, paint_opacity,
paint_opacity, paint_opacity);
cogl_set_source (material);
for (corner_id = 0; corner_id < 4; corner_id++) for (corner_id = 0; corner_id < 4; corner_id++)
{ {
if (node->corner_texture[corner_id] == COGL_INVALID_HANDLE) if (node->corner_material[corner_id] == COGL_INVALID_HANDLE)
continue; continue;
cogl_material_set_layer (material, cogl_material_set_color4ub (node->corner_material[corner_id],
0, node->corner_texture[corner_id]); paint_opacity, paint_opacity,
paint_opacity, paint_opacity);
cogl_set_source (node->corner_material[corner_id]);
switch (corner_id) switch (corner_id)
{ {
@ -791,7 +782,6 @@ st_theme_node_paint_borders (StThemeNode *node,
break; break;
} }
} }
cogl_handle_unref (material);
} }
/* background color */ /* background color */
@ -930,8 +920,7 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node,
if (ey < 0) if (ey < 0)
ey = border_bottom; /* FIXME ? */ ey = border_bottom; /* FIXME ? */
material = cogl_material_new (); material = node->border_material;
cogl_material_set_layer (material, 0, node->border_texture);
cogl_material_set_color4ub (material, cogl_material_set_color4ub (material,
paint_opacity, paint_opacity, paint_opacity, paint_opacity); paint_opacity, paint_opacity, paint_opacity, paint_opacity);
@ -988,8 +977,6 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node,
cogl_rectangles_with_texture_coords (rectangles, 9); cogl_rectangles_with_texture_coords (rectangles, 9);
} }
cogl_handle_unref (material);
} }
static void static void
@ -1096,11 +1083,11 @@ st_theme_node_paint (StThemeNode *node,
&allocation, &allocation,
paint_opacity); paint_opacity);
if (node->border_texture != COGL_INVALID_HANDLE) if (node->border_material != COGL_INVALID_HANDLE)
{ {
/* Gradients and border images are mutually exclusive at this time */ /* Gradients and border images are mutually exclusive at this time */
if (node->background_gradient_type != ST_GRADIENT_NONE) if (node->background_gradient_type != ST_GRADIENT_NONE)
paint_texture_with_opacity (node->border_texture, &allocation, paint_opacity); paint_material_with_opacity (node->border_material, &allocation, paint_opacity);
else else
st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity); st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity);
} }
@ -1133,7 +1120,7 @@ st_theme_node_paint (StThemeNode *node,
&background_box, &background_box,
paint_opacity); paint_opacity);
paint_texture_with_opacity (node->background_texture, &background_box, paint_opacity); paint_material_with_opacity (node->border_material, &background_box, paint_opacity);
} }
} }
@ -1172,7 +1159,9 @@ st_theme_node_copy_cached_paint_state (StThemeNode *node,
node->background_texture = cogl_handle_ref (other->background_texture); node->background_texture = cogl_handle_ref (other->background_texture);
if (other->border_texture) if (other->border_texture)
node->border_texture = cogl_handle_ref (other->border_texture); node->border_texture = cogl_handle_ref (other->border_texture);
if (other->border_material)
node->border_material = cogl_handle_ref (other->border_material);
for (corner_id = 0; corner_id < 4; corner_id++) for (corner_id = 0; corner_id < 4; corner_id++)
if (other->corner_texture[corner_id]) if (other->corner_material[corner_id])
node->corner_texture[corner_id] = cogl_handle_ref (other->corner_texture[corner_id]); node->corner_material[corner_id] = cogl_handle_ref (other->corner_material[corner_id]);
} }

View File

@ -78,7 +78,8 @@ struct _StThemeNode {
CoglHandle border_shadow_material; CoglHandle border_shadow_material;
CoglHandle background_texture; CoglHandle background_texture;
CoglHandle border_texture; CoglHandle border_texture;
CoglHandle corner_texture[4]; CoglHandle border_material;
CoglHandle corner_material[4];
}; };
struct _StThemeNodeClass { struct _StThemeNodeClass {