[mutter/wip/shape: 2/3] shaped-texture: Turn blending off when drawing entirely opaque regions



commit c5cfc43a167f7463928edf2bd102da6c7102623b
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Tue Aug 27 16:17:34 2013 -0400

    shaped-texture: Turn blending off when drawing entirely opaque regions
    
    When drawing entirely opaque regions, we traditionally kept blending on
    simply because it made the code more convenient and obvious to handle.
    However, this can cause lots of performance issues on GPUs that aren't
    too powerful, as they have to readback the buffer underneath.
    
    Keep track of the opaque region set by windows (through _NET_WM_OPAQUE_REGION,
    standard RGB32 frame masks or similar), and draw those rectangles
    separately through a different path with blending turned off.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706930

 src/compositor/meta-shaped-texture.c |  169 ++++++++++++++++++++++++++++------
 src/compositor/meta-window-actor.c   |    3 +
 src/meta/meta-shaped-texture.h       |    3 +
 3 files changed, 147 insertions(+), 28 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index a0cb561..12a5c70 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -70,6 +70,7 @@ struct _MetaShapedTexturePrivate
   CoglTexture *mask_texture;
 
   cairo_region_t *clip_region;
+  cairo_region_t *opaque_region;
 
   guint tex_width, tex_height;
 
@@ -145,6 +146,55 @@ get_masked_pipeline (CoglContext *ctx)
   return cogl_pipeline_copy (template);
 }
 
+static CoglPipeline *
+get_unblended_pipeline (CoglContext *ctx)
+{
+  static CoglPipeline *template = NULL;
+  if (G_UNLIKELY (template == NULL))
+    {
+      CoglColor color;
+      template = cogl_pipeline_new (ctx);
+      cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
+      cogl_pipeline_set_blend (template,
+                               "RGBA = ADD (SRC_COLOR, 0)",
+                               NULL);
+      cogl_pipeline_set_color (template, &color);
+    }
+
+  return cogl_pipeline_copy (template);
+}
+
+static void
+paint_clipped_rectangle (CoglFramebuffer       *fb,
+                         CoglPipeline          *pipeline,
+                         cairo_rectangle_int_t *rect,
+                         ClutterActorBox       *alloc)
+{
+  float coords[8];
+  float x1, y1, x2, y2;
+
+  x1 = rect->x;
+  y1 = rect->y;
+  x2 = rect->x + rect->width;
+  y2 = rect->y + rect->height;
+
+  coords[0] = rect->x / (alloc->x2 - alloc->x1);
+  coords[1] = rect->y / (alloc->y2 - alloc->y1);
+  coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
+  coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
+
+  coords[4] = coords[0];
+  coords[5] = coords[1];
+  coords[6] = coords[2];
+  coords[7] = coords[3];
+
+  cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
+                                                 x1, y1, x2, y2,
+                                                 &coords[0], 8);
+
+}
+
+
 static void
 meta_shaped_texture_paint (ClutterActor *actor)
 {
@@ -156,6 +206,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
   CoglContext *ctx;
   CoglPipeline *pipeline;
   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
+  guchar opacity;
+  cairo_region_t *blended_region = NULL;
 
   if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
     return;
@@ -194,6 +246,57 @@ meta_shaped_texture_paint (ClutterActor *actor)
 
   ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
 
+  opacity = clutter_actor_get_paint_opacity (actor);
+
+  clutter_actor_get_allocation_box (actor, &alloc);
+
+  if (priv->opaque_region != NULL && opacity == 255)
+    {
+      cairo_region_t *region;
+      int n_rects;
+      int i;
+
+      region = cairo_region_copy (priv->clip_region);
+      cairo_region_intersect (region, priv->opaque_region);
+
+      if (cairo_region_is_empty (region))
+        goto paint_blended;
+
+      pipeline = get_unblended_pipeline (ctx);
+      cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex);
+
+      n_rects = cairo_region_num_rectangles (region);
+      for (i = 0; i < n_rects; i++)
+        {
+          cairo_rectangle_int_t rect;
+          cairo_region_get_rectangle (region, i, &rect);
+          paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
+        }
+
+      cogl_object_unref (pipeline);
+
+      if (priv->clip_region != NULL)
+        {
+          blended_region = cairo_region_copy (priv->clip_region);
+        }
+      else
+        {
+          cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
+          blended_region = cairo_region_create_rectangle (&rect);
+        }
+
+      cairo_region_subtract (blended_region, priv->opaque_region);
+
+    paint_blended:
+      cairo_region_destroy (region);
+    }
+
+  if (blended_region == NULL && priv->clip_region != NULL)
+    blended_region = cairo_region_reference (priv->clip_region);
+
+  if (blended_region != NULL && cairo_region_is_empty (blended_region))
+    goto out;
+
   if (priv->mask_texture == NULL)
     {
       pipeline = get_unmasked_pipeline (ctx);
@@ -208,18 +311,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
 
   {
     CoglColor color;
-    guchar opacity = clutter_actor_get_paint_opacity (actor);
     cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
     cogl_pipeline_set_color (pipeline, &color);
   }
 
-  clutter_actor_get_allocation_box (actor, &alloc);
-
-  if (priv->clip_region)
+  if (blended_region != NULL)
     {
       int n_rects;
-      int i;
-      cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
 
       /* Limit to how many separate rectangles we'll draw; beyond this just
        * fall back and draw the whole thing */
@@ -228,8 +326,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
       n_rects = cairo_region_num_rectangles (priv->clip_region);
       if (n_rects <= MAX_RECTS)
        {
-         float coords[8];
-          float x1, y1, x2, y2;
+          int i;
+          cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
 
          for (i = 0; i < n_rects; i++)
            {
@@ -240,24 +338,7 @@ meta_shaped_texture_paint (ClutterActor *actor)
              if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
                continue;
 
-             x1 = rect.x;
-             y1 = rect.y;
-             x2 = rect.x + rect.width;
-             y2 = rect.y + rect.height;
-
-             coords[0] = rect.x / (alloc.x2 - alloc.x1);
-             coords[1] = rect.y / (alloc.y2 - alloc.y1);
-             coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
-             coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
-
-              coords[4] = coords[0];
-              coords[5] = coords[1];
-              coords[6] = coords[2];
-              coords[7] = coords[3];
-
-              cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
-                                                             x1, y1, x2, y2,
-                                                             &coords[0], 8);
+              paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
             }
 
           goto out;
@@ -271,6 +352,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
 
  out:
   cogl_object_unref (pipeline);
+  if (blended_region != NULL)
+    cairo_region_destroy (blended_region);
 }
 
 static void
@@ -309,8 +392,8 @@ meta_shaped_texture_pick (ClutterActor       *actor,
 
       cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
 
-      pipeline = cogl_pipeline_new (ctx);
-      cogl_pipeline_set_layer_texture (pipeline, 0, priv->mask_texture);
+      pipeline = get_masked_pipeline (ctx);
+      cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
       cogl_pipeline_set_color (pipeline, &cogl_color);
 
       clutter_actor_get_allocation_box (actor, &alloc);
@@ -611,6 +694,36 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
 }
 
 /**
+ * meta_shaped_texture_set_opaque_region:
+ * @stex: a #MetaShapedTexture
+ * @opaque_region: (transfer full): the region of the texture that
+ *   can have blending turned off.
+ *
+ * As most windows have a large portion that does not require blending,
+ * we can easily turn off blending if we know the areas that do not
+ * require blending. This sets the region where we will not blend for
+ * optimization purposes.
+ */
+void
+meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
+                                       cairo_region_t    *opaque_region)
+{
+  MetaShapedTexturePrivate *priv;
+
+  g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
+
+  priv = stex->priv;
+
+  if (priv->opaque_region)
+    cairo_region_destroy (priv->opaque_region);
+
+  if (opaque_region)
+    priv->opaque_region = cairo_region_reference (opaque_region);
+  else
+    priv->opaque_region = NULL;
+}
+
+/**
  * meta_shaped_texture_get_image:
  * @stex: A #MetaShapedTexture
  * @clip: A clipping rectangle, to help prevent extra processing.
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index a32afed..4a28d10 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -2289,6 +2289,9 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self)
     priv->opaque_region = NULL;
   else
     priv->opaque_region = cairo_region_reference (priv->shape_region);
+
+  meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
+                                         priv->opaque_region);
 }
 
 static void
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
index 06b119b..9300cd3 100644
--- a/src/meta/meta-shaped-texture.h
+++ b/src/meta/meta-shaped-texture.h
@@ -87,6 +87,9 @@ void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
 void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
                                          cairo_region_t    *clip_region);
 
+void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
+                                            cairo_region_t    *opaque_region);
+
 cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture     *stex,
                                                  cairo_rectangle_int_t *clip);
 


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