[mutter/configurable-shadows: 12/14] Implement more accurate clipping of obscured shadows



commit d45a0b831a3c063d70247e181f3c40190473035a
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Nov 11 18:23:25 2010 -0500

    Implement more accurate clipping of obscured shadows
    
    Instead of making optimizing obscured shadows an all-or-none operation,
    pass the clip region to meta_shadow_paint() and only paint the 9-slices
    that are at least partially visible.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=592382

 src/compositor/meta-shadow-factory-private.h |    3 +-
 src/compositor/meta-shadow-factory.c         |   49 +++++++++++++-----
 src/compositor/meta-window-actor.c           |   69 +++++++++++++-------------
 3 files changed, 73 insertions(+), 48 deletions(-)
---
diff --git a/src/compositor/meta-shadow-factory-private.h b/src/compositor/meta-shadow-factory-private.h
index 70a6623..c3414ac 100644
--- a/src/compositor/meta-shadow-factory-private.h
+++ b/src/compositor/meta-shadow-factory-private.h
@@ -46,7 +46,8 @@ void        meta_shadow_paint       (MetaShadow            *shadow,
                                      int                    window_y,
                                      int                    window_width,
                                      int                    window_height,
-                                     guint8                 opacity);
+                                     guint8                 opacity,
+                                     cairo_region_t        *clip);
 void        meta_shadow_get_bounds  (MetaShadow            *shadow,
                                      int                    window_x,
                                      int                    window_y,
diff --git a/src/compositor/meta-shadow-factory.c b/src/compositor/meta-shadow-factory.c
index b38dfe4..fed858a 100644
--- a/src/compositor/meta-shadow-factory.c
+++ b/src/compositor/meta-shadow-factory.c
@@ -188,6 +188,9 @@ meta_shadow_unref (MetaShadow *shadow)
  * @window_y: y position of the region to paint a shadow for
  * @window_width: actual width of the region to paint a shadow for
  * @window_height: actual height of the region to paint a shadow for
+ * @clip: (allow-none): if non-%NULL specifies the visible portion
+ *   of the shadow. Drawing won't be strictly clipped to this region
+ *   but it will be used to optimize what is drawn.
  *
  * Paints the shadow at the given position, for the specified actual
  * size of the region. (Since a #MetaShadow can be shared between
@@ -195,20 +198,21 @@ meta_shadow_unref (MetaShadow *shadow)
  * size needs to be passed in here.)
  */
 void
-meta_shadow_paint (MetaShadow *shadow,
-                   int         window_x,
-                   int         window_y,
-                   int         window_width,
-                   int         window_height,
-                   guint8      opacity)
+meta_shadow_paint (MetaShadow     *shadow,
+                   int             window_x,
+                   int             window_y,
+                   int             window_width,
+                   int             window_height,
+                   guint8          opacity,
+                   cairo_region_t *clip)
 {
   float texture_width = cogl_texture_get_width (shadow->texture);
   float texture_height = cogl_texture_get_height (shadow->texture);
   int i, j;
   float src_x[4];
   float src_y[4];
-  float dest_x[4];
-  float dest_y[4];
+  int dest_x[4];
+  int dest_y[4];
   int n_x, n_y;
 
   cogl_material_set_color4ub (shadow->material,
@@ -267,11 +271,30 @@ meta_shadow_paint (MetaShadow *shadow,
     }
 
   for (j = 0; j < n_y; j++)
-    for (i = 0; i < n_x; i++)
-      cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
-                                          dest_x[i + 1], dest_y[j + 1],
-                                          src_x[i], src_y[j],
-                                          src_x[i + 1], src_y[j + 1]);
+    {
+      cairo_rectangle_int_t dest_rect;
+      dest_rect.y = dest_y[j];
+      dest_rect.height = dest_y[j + 1] - dest_y[j];
+
+      for (i = 0; i < n_x; i++)
+        {
+          cairo_region_overlap_t overlap;
+
+          dest_rect.x = dest_x[i];
+          dest_rect.width = dest_x[i + 1] - dest_x[i];
+
+          if (clip)
+            overlap = cairo_region_contains_rectangle (clip, &dest_rect);
+          else
+            overlap = CAIRO_REGION_OVERLAP_PART;
+
+          if (overlap != CAIRO_REGION_OVERLAP_OUT)
+            cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
+                                                dest_x[i + 1], dest_y[j + 1],
+                                                src_x[i], src_y[j],
+                                                src_x[i + 1], src_y[j + 1]);
+        }
+    }
 }
 
 /**
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index cd8167d..4c14fae 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -60,6 +60,8 @@ struct _MetaWindowActorPrivate
   /* A rectangular region with the unshaped extends of the window
    * texture */
   cairo_region_t   *bounding_region;
+  /* The region we should clip to when painting the shadow */
+  cairo_region_t   *shadow_clip;
 
   /* Extracted size-invariant shape used for shadows */
   MetaWindowShape  *shadow_shape;
@@ -93,7 +95,6 @@ struct _MetaWindowActorPrivate
   guint             needs_reshape          : 1;
   guint             recompute_focused_shadow   : 1;
   guint             recompute_unfocused_shadow : 1;
-  guint             paint_shadow           : 1;
   guint		    size_changed           : 1;
 
   guint		    needs_destroy	   : 1;
@@ -140,6 +141,7 @@ static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
 
 static void meta_window_actor_clear_shape_region    (MetaWindowActor *self);
 static void meta_window_actor_clear_bounding_region (MetaWindowActor *self);
+static void meta_window_actor_clear_shadow_clip     (MetaWindowActor *self);
 
 static gboolean is_shaped                (MetaDisplay  *display,
                                           Window        xwindow);
@@ -283,7 +285,6 @@ meta_window_actor_init (MetaWindowActor *self)
 						   MetaWindowActorPrivate);
   priv->opacity = 0xff;
   priv->shadow_class = NULL;
-  priv->paint_shadow = TRUE;
 }
 
 static void
@@ -439,6 +440,7 @@ meta_window_actor_dispose (GObject *object)
 
   meta_window_actor_clear_shape_region (self);
   meta_window_actor_clear_bounding_region (self);
+  meta_window_actor_clear_shadow_clip (self);
 
   if (priv->shadow_class != NULL)
     {
@@ -659,27 +661,24 @@ meta_window_actor_paint (ClutterActor *actor)
 {
   MetaWindowActor *self = META_WINDOW_ACTOR (actor);
   MetaWindowActorPrivate *priv = self->priv;
+  gboolean appears_focused = meta_window_appears_focused (priv->window);
+  MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
 
-  if (priv->paint_shadow)
+  if (shadow != NULL)
     {
-      gboolean appears_focused = meta_window_appears_focused (priv->window);
-      MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
+      MetaShadowParams params;
+      cairo_rectangle_int_t shape_bounds;
 
-      if (shadow != NULL)
-        {
-          MetaShadowParams params;
-          cairo_rectangle_int_t shape_bounds;
-
-          meta_window_actor_get_shape_bounds (self, &shape_bounds);
-          meta_window_actor_get_shadow_params (self, appears_focused, &params);
-
-          meta_shadow_paint (shadow,
-                             params.x_offset + shape_bounds.x,
-                             params.y_offset + shape_bounds.y,
-                             shape_bounds.width,
-                             shape_bounds.height,
-                             (clutter_actor_get_paint_opacity (actor) * params.opacity) / 255);
-        }
+      meta_window_actor_get_shape_bounds (self, &shape_bounds);
+      meta_window_actor_get_shadow_params (self, appears_focused, &params);
+
+      meta_shadow_paint (shadow,
+                         params.x_offset + shape_bounds.x,
+                         params.y_offset + shape_bounds.y,
+                         shape_bounds.width,
+                         shape_bounds.height,
+                         (clutter_actor_get_paint_opacity (actor) * params.opacity) / 255,
+                         priv->shadow_clip);
     }
 
   CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
@@ -1540,6 +1539,18 @@ meta_window_actor_clear_bounding_region (MetaWindowActor *self)
 }
 
 static void
+meta_window_actor_clear_shadow_clip (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+
+  if (priv->shadow_clip)
+    {
+      cairo_region_destroy (priv->shadow_clip);
+      priv->shadow_clip = NULL;
+    }
+}
+
+static void
 meta_window_actor_update_bounding_region (MetaWindowActor *self,
                                           int              width,
                                           int              height)
@@ -1699,18 +1710,8 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
 
   if (appears_focused ? priv->focused_shadow : priv->unfocused_shadow)
     {
-      cairo_rectangle_int_t shadow_bounds;
-      cairo_region_overlap_t overlap;
-
-      /* We could compute an full clip region as we do for the window
-       * texture, but the shadow is relatively cheap to draw, and
-       * a little more complex to clip, so we just catch the case where
-       * the shadow is completely obscured and doesn't need to be drawn
-       * at all.
-       */
-      meta_window_actor_get_shadow_bounds (self, appears_focused, &shadow_bounds);
-      overlap = cairo_region_contains_rectangle (beneath_region, &shadow_bounds);
-      priv->paint_shadow = overlap != CAIRO_REGION_OVERLAP_OUT;
+      meta_window_actor_clear_shadow_clip (self);
+      priv->shadow_clip = cairo_region_copy (beneath_region);
     }
 }
 
@@ -1728,7 +1729,7 @@ meta_window_actor_reset_visible_regions (MetaWindowActor *self)
 
   meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
                                        NULL);
-  priv->paint_shadow = TRUE;
+  meta_window_actor_clear_shadow_clip (self);
 }
 
 static void



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