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



commit 55295d0fc3c33ce079982ca53422d8e8f6178905
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

 src/compositor/meta-shaped-texture.c |  171 ++++++++++++++++++++++++++++------
 src/compositor/meta-window-actor.c   |    3 +
 src/meta/meta-shaped-texture.h       |    3 +
 3 files changed, 150 insertions(+), 27 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index acb0d55..abb7691 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,56 @@ 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 >= 1.0)
+    {
+      cairo_region_t *region;
+      int n_rects;
+      int i;
+
+      pipeline = get_unblended_pipeline (ctx);
+      cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex);
+
+      region = cairo_region_copy (priv->clip_region);
+      cairo_region_intersect (region, priv->opaque_region);
+
+      if (cairo_region_is_empty (region))
+        goto paint_blended;
+
+      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);
+        }
+
+      cairo_region_destroy (region);
+
+      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:
+
+  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 +310,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 +325,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,27 +337,10 @@ 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);
             }
 
-         return;
+          goto out;
        }
     }
 
@@ -268,6 +348,10 @@ meta_shaped_texture_paint (ClutterActor *actor)
                                    0, 0,
                                    alloc.x2 - alloc.x1,
                                    alloc.y2 - alloc.y1);
+
+ out:
+  if (blended_region != NULL)
+    cairo_region_destroy (blended_region);
 }
 
 static void
@@ -610,6 +694,39 @@ 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);
+      priv->opaque_region = NULL;
+    }
+
+  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]