[gnome-shell] st-theme-node-drawing: Don't create lots of one-shot materials



commit d66e7dd49edc589577477a98c2806b7930335e24
Author: Neil Roberts <neil linux intel com>
Date:   Wed Oct 27 17:41:20 2010 +0100

    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

 src/st/st-private.c            |   43 ++++++++++++++++++++
 src/st/st-private.h            |    2 +
 src/st/st-theme-node-drawing.c |   85 +++++++++++++++++----------------------
 src/st/st-theme-node-private.h |    3 +-
 4 files changed, 84 insertions(+), 49 deletions(-)
---
diff --git a/src/st/st-private.c b/src/st/st-private.c
index 264ed72..f1f3aab 100644
--- a/src/st/st-private.c
+++ b/src/st/st-private.c
@@ -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
diff --git a/src/st/st-private.h b/src/st/st-private.h
index 33d58d4..0d0e642 100644
--- a/src/st/st-private.h
+++ b/src/st/st-private.h
@@ -73,6 +73,8 @@ void _st_allocate_fill (StWidget        *parent,
 void _st_set_text_from_style (ClutterText *text,
                               StThemeNode *theme_node);
 
+CoglHandle _st_create_texture_material (CoglHandle src_texture);
+
 /* Helper for widgets which need to draw additional shadows */
 CoglHandle _st_create_shadow_material (StShadow   *shadow_spec,
                                        CoglHandle  src_texture);
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index 718a156..d28f03e 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -52,7 +52,7 @@ typedef struct {
 } StCornerSpec;
 
 static CoglHandle
-create_corner_texture (StCornerSpec *corner)
+create_corner_material (StCornerSpec *corner)
 {
   CoglHandle texture;
   cairo_t *cr;
@@ -167,7 +167,7 @@ load_corner (StTextureCache  *cache,
 {
   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
@@ -222,7 +222,7 @@ static CoglHandle
 st_theme_node_lookup_corner (StThemeNode    *node,
                              StCorner        corner_id)
 {
-  CoglHandle texture;
+  CoglHandle texture, material;
   char *key;
   StTextureCache *cache;
   StCornerSpec corner;
@@ -269,10 +269,12 @@ st_theme_node_lookup_corner (StThemeNode    *node,
   data.node = node;
   data.corner = &corner;
   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);
 
-  return texture;
+  return material;
 }
 
 static void
@@ -511,12 +513,14 @@ _st_theme_node_free_drawing_state (StThemeNode  *node)
     cogl_handle_unref (node->background_shadow_material);
   if (node->border_texture != COGL_INVALID_HANDLE)
     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)
     cogl_handle_unref (node->border_shadow_material);
 
   for (corner_id = 0; corner_id < 4; corner_id++)
-    if (node->corner_texture[corner_id] != COGL_INVALID_HANDLE)
-      cogl_handle_unref (node->corner_texture[corner_id]);
+    if (node->corner_material[corner_id] != COGL_INVALID_HANDLE)
+      cogl_handle_unref (node->corner_material[corner_id]);
 
   _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->border_shadow_material = COGL_INVALID_HANDLE;
   node->border_texture = COGL_INVALID_HANDLE;
+  node->border_material = COGL_INVALID_HANDLE;
 
   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,
@@ -581,6 +586,11 @@ st_theme_node_render_resources (StThemeNode   *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 (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);
-  node->corner_texture[ST_CORNER_TOPRIGHT] =
+  node->corner_material[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);
-  node->corner_texture[ST_CORNER_BOTTOMLEFT] =
+  node->corner_material[ST_CORNER_BOTTOMLEFT] =
     st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMLEFT);
 }
 
 static void
-paint_texture_with_opacity (CoglHandle       texture,
-                            ClutterActorBox *box,
-                            guint8           paint_opacity)
+paint_material_with_opacity (CoglHandle       material,
+                             ClutterActorBox *box,
+                             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,
                               paint_opacity, paint_opacity, paint_opacity, paint_opacity);
 
   cogl_set_source (material);
   cogl_rectangle (box->x1, box->y1, box->x2, box->y2);
-
-  cogl_handle_unref (material);
 }
 
 static void
@@ -678,7 +674,6 @@ st_theme_node_paint_borders (StThemeNode           *node,
   int max_width_radius[4];
   int corner_id;
   ClutterColor border_color;
-  CoglHandle material;
 
   width = box->x2 - box->x1;
   height = box->y2 - box->y1;
@@ -753,19 +748,15 @@ st_theme_node_paint_borders (StThemeNode           *node,
   /* corners */
   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++)
         {
-          if (node->corner_texture[corner_id] == COGL_INVALID_HANDLE)
+          if (node->corner_material[corner_id] == COGL_INVALID_HANDLE)
             continue;
 
-          cogl_material_set_layer (material,
-                                   0, node->corner_texture[corner_id]);
+          cogl_material_set_color4ub (node->corner_material[corner_id],
+                                      paint_opacity, paint_opacity,
+                                      paint_opacity, paint_opacity);
+          cogl_set_source (node->corner_material[corner_id]);
 
           switch (corner_id)
             {
@@ -791,7 +782,6 @@ st_theme_node_paint_borders (StThemeNode           *node,
                 break;
             }
         }
-      cogl_handle_unref (material);
     }
 
   /* background color */
@@ -930,8 +920,7 @@ st_theme_node_paint_sliced_border_image (StThemeNode           *node,
   if (ey < 0)
     ey = border_bottom;          /* FIXME ? */
 
-  material = cogl_material_new ();
-  cogl_material_set_layer (material, 0, node->border_texture);
+  material = node->border_material;
   cogl_material_set_color4ub (material,
                               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_handle_unref (material);
 }
 
 static void
@@ -1096,11 +1083,11 @@ st_theme_node_paint (StThemeNode           *node,
                                    &allocation,
                                    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 */
       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
         st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity);
     }
@@ -1133,7 +1120,7 @@ st_theme_node_paint (StThemeNode           *node,
                                        &background_box,
                                        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);
   if (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++)
-    if (other->corner_texture[corner_id])
-      node->corner_texture[corner_id] = cogl_handle_ref (other->corner_texture[corner_id]);
+    if (other->corner_material[corner_id])
+      node->corner_material[corner_id] = cogl_handle_ref (other->corner_material[corner_id]);
 }
diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h
index 9267a6e..c6078fc 100644
--- a/src/st/st-theme-node-private.h
+++ b/src/st/st-theme-node-private.h
@@ -78,7 +78,8 @@ struct _StThemeNode {
   CoglHandle border_shadow_material;
   CoglHandle background_texture;
   CoglHandle border_texture;
-  CoglHandle corner_texture[4];
+  CoglHandle border_material;
+  CoglHandle corner_material[4];
 };
 
 struct _StThemeNodeClass {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]