[mutter/wayland] meta-shaped-texture: Don't queue redraws for obscured regions



commit f08921bd0c1eb7df47755e725aa480cb2d60b9eb
Author: Adel Gadllah <adel gadllah gmail com>
Date:   Tue Aug 27 16:45:15 2013 +0200

    meta-shaped-texture: Don't queue redraws for obscured regions
    
    When we get a damage event we update the window by calling
    meta_shaped_texture_update_area which queues a redraw on the actor.
    We can avoid that for obscured regions by comparing the damage area to
    our visible area.
    
    This patch causes _NET_WM_FRAME_DRAWN messages to be not sent in some cases
    where they should be sent; they will be added back in a later commit.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=703332

 src/compositor/meta-shaped-texture.c       |   60 ++++++++++++++++++++++---
 src/compositor/meta-window-actor-private.h |   13 +++--
 src/compositor/meta-window-actor.c         |   67 +++++++++++++++++++++-------
 src/compositor/meta-window-group.c         |   67 ++++++++++++++++++++--------
 src/meta/meta-shaped-texture.h             |   11 +++--
 5 files changed, 165 insertions(+), 53 deletions(-)
---
diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c
index 838e3fe..01ff5f7 100644
--- a/src/compositor/meta-shaped-texture.c
+++ b/src/compositor/meta-shaped-texture.c
@@ -738,19 +738,38 @@ queue_damage_redraw_with_clip (MetaShapedTexture *stex,
   clutter_actor_queue_redraw_with_clip (self, &clip);
 }
 
-void
+/**
+ * meta_shaped_texture_update_area:
+ * @stex: #MetaShapedTexture
+ * @x: the x coordinate of the damaged area
+ * @y: the y coordinate of the damaged area
+ * @width: the width of the damaged area
+ * @height: the height of the damaged area
+ * @unobscured_region: The unobscured region of the window or %NULL if
+ * there is no valid one (like when the actor is transformed or
+ * has a mapped clone)
+ *
+ * Repairs the damaged area indicated by @x, @y, @width and @height
+ * and queues a redraw for the intersection @visibible_region and
+ * the damage area. If @visibible_region is %NULL a redraw will always
+ * get queued.
+ *
+ * Return value: Whether a redraw have been queued or not
+ */
+gboolean
 meta_shaped_texture_update_area (MetaShapedTexture *stex,
-                                 int                x,
-                                 int                y,
-                                 int                width,
-                                 int                height)
+                                int                x,
+                                int                y,
+                                int                width,
+                                int                height,
+                                cairo_region_t    *unobscured_region)
 {
   MetaShapedTexturePrivate *priv;
 
   priv = stex->priv;
 
   if (priv->texture == NULL)
-    return;
+    return FALSE;
 
   switch (priv->type)
     {
@@ -765,7 +784,34 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
 
   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
 
-  queue_damage_redraw_with_clip (stex, x, y, width, height);
+  if (unobscured_region)
+    {
+      cairo_region_t *intersection;
+
+      if (cairo_region_is_empty (unobscured_region))
+        return FALSE;
+
+      intersection = cairo_region_copy (unobscured_region);
+      cairo_region_intersect_rectangle (intersection, &clip);
+
+      if (!cairo_region_is_empty (intersection))
+        {
+          cairo_rectangle_int_t damage_rect;
+          cairo_region_get_extents (intersection, &damage_rect);
+          clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
+          cairo_region_destroy (intersection);
+
+          return TRUE;
+        }
+
+      cairo_region_destroy (intersection);
+
+      return FALSE;
+    }
+
+  clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
+
+  return TRUE;
 }
 
 /**
diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h
index cfe6c9d..235e221 100644
--- a/src/compositor/meta-window-actor-private.h
+++ b/src/compositor/meta-window-actor-private.h
@@ -70,11 +70,14 @@ void     meta_window_actor_queue_frame_drawn   (MetaWindowActor *self,
 
 cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
 
-void meta_window_actor_set_visible_region         (MetaWindowActor *self,
-                                                   cairo_region_t  *visible_region);
-void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
-                                                   cairo_region_t  *beneath_region);
-void meta_window_actor_reset_visible_regions      (MetaWindowActor *self);
+void meta_window_actor_set_clip_region         (MetaWindowActor *self,
+                                                   cairo_region_t  *clip_region);
+void meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
+                                                cairo_region_t  *beneath_region);
+void meta_window_actor_reset_clip_regions      (MetaWindowActor *self);
+
+void meta_window_actor_set_unobscured_region      (MetaWindowActor *self,
+                                                   cairo_region_t  *unobscured_region);
 
 void meta_window_actor_effect_completed (MetaWindowActor *actor,
                                          gulong           event);
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 1204322..537fded 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -77,6 +77,9 @@ struct _MetaWindowActorPrivate
   /* The region we should clip to when painting the shadow */
   cairo_region_t   *shadow_clip;
 
+  /* The region that is visible, used to optimize out redraws */
+  cairo_region_t   *unobscured_region;
+
   /* Extracted size-invariant shape used for shadows */
   MetaWindowShape  *shadow_shape;
 
@@ -445,6 +448,7 @@ meta_window_actor_dispose (GObject *object)
       meta_window_actor_detach_x11_pixmap (self);
     }
 
+  g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
   g_clear_pointer (&priv->input_region, cairo_region_destroy);
   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
@@ -948,7 +952,8 @@ meta_window_actor_damage_all (MetaWindowActor *self)
   meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
                                    0, 0,
                                    cogl_texture_get_width (texture),
-                                   cogl_texture_get_height (texture));
+                                   cogl_texture_get_height (texture),
+                                   clutter_actor_has_mapped_clones (priv->actor) ? NULL : 
priv->unobscured_region);
 
   priv->needs_damage_all = FALSE;
   priv->repaint_scheduled = TRUE;
@@ -1734,40 +1739,67 @@ see_region (cairo_region_t *region,
 #endif
 
 /**
- * meta_window_actor_set_visible_region:
+ * meta_window_actor_set_unobscured_region:
+ * @self: a #MetaWindowActor
+ * @unobscured_region: the region of the screen that isn't completely
+ *  obscured.
+ *
+ * Provides a hint as to what areas of the window need to queue
+ * redraws when damaged. Regions not in @unobscured_region are completely obscured.
+ * Unlike meta_window_actor_set_clip_region(), the region here
+ * doesn't take into account any clipping that is in effect while drawing.
+ */
+void
+meta_window_actor_set_unobscured_region (MetaWindowActor *self,
+                                         cairo_region_t  *unobscured_region)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  if (priv->unobscured_region)
+    cairo_region_destroy (priv->unobscured_region);
+
+  if (unobscured_region)
+    priv->unobscured_region = cairo_region_copy (unobscured_region);
+  else
+    priv->unobscured_region = NULL;
+}
+
+/**
+ * meta_window_actor_set_clip_region:
  * @self: a #MetaWindowActor
- * @visible_region: the region of the screen that isn't completely
+ * @clip_region: the region of the screen that isn't completely
  *  obscured.
  *
  * Provides a hint as to what areas of the window need to be
- * drawn. Regions not in @visible_region are completely obscured.
+ * drawn. Regions not in @clip_region are completely obscured or
+ * not drawn in this frame.
  * This will be set before painting then unset afterwards.
  */
 void
-meta_window_actor_set_visible_region (MetaWindowActor *self,
-                                      cairo_region_t  *visible_region)
+meta_window_actor_set_clip_region (MetaWindowActor *self,
+                                   cairo_region_t  *clip_region)
 {
   MetaWindowActorPrivate *priv = self->priv;
 
   meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
-                                       visible_region);
+                                       clip_region);
 }
 
 /**
- * meta_window_actor_set_visible_region_beneath:
+ * meta_window_actor_set_clip_region_beneath:
  * @self: a #MetaWindowActor
- * @visible_region: the region of the screen that isn't completely
+ * @clip_region: the region of the screen that isn't completely
  *  obscured beneath the main window texture.
  *
  * Provides a hint as to what areas need to be drawn *beneath*
- * the main window texture.  This is the relevant visible region
+ * the main window texture.  This is the relevant clip region
  * when drawing the shadow, properly accounting for areas of the
  * shadow hid by the window itself. This will be set before painting
  * then unset afterwards.
  */
 void
-meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
-                                              cairo_region_t  *beneath_region)
+meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
+                                           cairo_region_t  *beneath_region)
 {
   MetaWindowActorPrivate *priv = self->priv;
   gboolean appears_focused = meta_window_appears_focused (priv->window);
@@ -1786,14 +1818,14 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
 }
 
 /**
- * meta_window_actor_reset_visible_regions:
+ * meta_window_actor_reset_clip_regions:
  * @self: a #MetaWindowActor
  *
- * Unsets the regions set by meta_window_actor_set_visible_region() and
- * meta_window_actor_set_visible_region_beneath()
+ * Unsets the regions set by meta_window_actor_set_clip_region() and
+ * meta_window_actor_set_clip_region_beneath()
  */
 void
-meta_window_actor_reset_visible_regions (MetaWindowActor *self)
+meta_window_actor_reset_clip_regions (MetaWindowActor *self)
 {
   MetaWindowActorPrivate *priv = self->priv;
 
@@ -2019,7 +2051,8 @@ meta_window_actor_process_x11_damage (MetaWindowActor    *self,
                                    event->area.x,
                                    event->area.y,
                                    event->area.width,
-                                   event->area.height);
+                                   event->area.height,
+                                   clutter_actor_has_mapped_clones (priv->actor) ? NULL : 
priv->unobscured_region);
   priv->repaint_scheduled = TRUE;
 }
 
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index 65771f7..4acb588 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -90,17 +90,30 @@ painting_untransformed (MetaWindowGroup *window_group,
 static void
 meta_window_group_paint (ClutterActor *actor)
 {
-  cairo_region_t *visible_region;
-  ClutterActor *stage;
+  cairo_region_t *clip_region;
+  cairo_region_t *unobscured_region;
   ClutterActorIter iter;
   ClutterActor *child;
-  cairo_rectangle_int_t visible_rect;
+  cairo_rectangle_int_t visible_rect, clip_rect;
   int paint_x_origin, paint_y_origin;
   int actor_x_origin, actor_y_origin;
   int paint_x_offset, paint_y_offset;
 
   MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
-  MetaCompScreen *info;
+  MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
+  ClutterActor *stage = clutter_actor_get_stage (actor);
+
+  /* Start off by treating all windows as completely unobscured, so damage anywhere
+   * in a window queues redraws, but confine it more below. */
+  clutter_actor_iter_init (&iter, actor);
+  while (clutter_actor_iter_next (&iter, &child))
+    {
+      if (META_IS_WINDOW_ACTOR (child))
+        {
+          MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
+          meta_window_actor_set_unobscured_region (window_actor, NULL);
+        }
+    }
 
   /* Normally we expect an actor to be drawn at it's position on the screen.
    * However, if we're inside the paint of a ClutterClone, that won't be the
@@ -125,17 +138,22 @@ meta_window_group_paint (ClutterActor *actor)
   paint_x_offset = paint_x_origin - actor_x_origin;
   paint_y_offset = paint_y_origin - actor_y_origin;
 
+  visible_rect.x = visible_rect.y = 0;
+  visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
+  visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
+
+  unobscured_region = cairo_region_create_rectangle (&visible_rect);
+
   /* Get the clipped redraw bounds from Clutter so that we can avoid
    * painting shadows on windows that don't need to be painted in this
    * frame. In the case of a multihead setup with mismatched monitor
    * sizes, we could intersect this with an accurate union of the
    * monitors to avoid painting shadows that are visible only in the
    * holes. */
-  stage = clutter_actor_get_stage (actor);
   clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
-                                        &visible_rect);
+                                        &clip_rect);
 
-  visible_region = cairo_region_create_rectangle (&visible_rect);
+  clip_region = cairo_region_create_rectangle (&clip_rect);
 
   if (!meta_is_wayland_compositor ())
     {
@@ -146,7 +164,8 @@ meta_window_group_paint (ClutterActor *actor)
           MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
 
           meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
-          cairo_region_subtract_rectangle (visible_region, &unredirected_rect);
+          cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
+          cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
         }
     }
 
@@ -195,20 +214,28 @@ meta_window_group_paint (ClutterActor *actor)
           x += paint_x_offset;
           y += paint_y_offset;
 
+
           /* Temporarily move to the coordinate system of the actor */
-          cairo_region_translate (visible_region, - x, - y);
+          cairo_region_translate (unobscured_region, - x, - y);
+          cairo_region_translate (clip_region, - x, - y);
 
-          meta_window_actor_set_visible_region (window_actor, visible_region);
+          meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
+          meta_window_actor_set_clip_region (window_actor, clip_region);
 
           if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
             {
               cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
               if (obscured_region)
-                cairo_region_subtract (visible_region, obscured_region);
+                {
+                  cairo_region_subtract (unobscured_region, obscured_region);
+                  cairo_region_subtract (clip_region, obscured_region);
+                }
             }
 
-          meta_window_actor_set_visible_region_beneath (window_actor, visible_region);
-          cairo_region_translate (visible_region, x, y);
+          meta_window_actor_set_clip_region_beneath (window_actor, clip_region);
+
+          cairo_region_translate (unobscured_region, x, y);
+          cairo_region_translate (clip_region, x, y);
         }
       else if (META_IS_BACKGROUND_ACTOR (child) ||
                META_IS_BACKGROUND_GROUP (child))
@@ -221,17 +248,19 @@ meta_window_group_paint (ClutterActor *actor)
           x += paint_x_offset;
           y += paint_y_offset;
 
-          cairo_region_translate (visible_region, - x, - y);
+          cairo_region_translate (clip_region, - x, - y);
 
           if (META_IS_BACKGROUND_GROUP (child))
-            meta_background_group_set_visible_region (META_BACKGROUND_GROUP (child), visible_region);
+            meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), clip_region);
           else
-            meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), visible_region);
-          cairo_region_translate (visible_region, x, y);
+            meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), clip_region);
+
+          cairo_region_translate (clip_region, x, y);
         }
     }
 
-  cairo_region_destroy (visible_region);
+  cairo_region_destroy (unobscured_region);
+  cairo_region_destroy (clip_region);
 
   CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
 
@@ -244,7 +273,7 @@ meta_window_group_paint (ClutterActor *actor)
       if (META_IS_WINDOW_ACTOR (child))
         {
           MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
-          meta_window_actor_reset_visible_regions (window_actor);
+          meta_window_actor_reset_clip_regions (window_actor);
         }
       else if (META_IS_BACKGROUND_ACTOR (child))
         {
diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h
index 2b6d325..d757ced 100644
--- a/src/meta/meta-shaped-texture.h
+++ b/src/meta/meta-shaped-texture.h
@@ -67,11 +67,12 @@ GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
 void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
                                             gboolean           create_mipmaps);
 
-void meta_shaped_texture_update_area (MetaShapedTexture *stex,
-                                      int                x,
-                                      int                y,
-                                      int                width,
-                                      int                height);
+gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
+                                          int                x,
+                                          int                y,
+                                          int                width,
+                                          int                height,
+                                          cairo_region_t    *unobscured_region);
 
 CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);
 


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