Blob Blame History Raw
From 8a951218911168ab386642769b98de42f177a279 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 17 Jun 2016 17:45:20 +0200
Subject: [PATCH] surface-actor: Keep track of ignored damage

We ignore all damage while a surface is frozen and queue a full
update instead once it's thawed. While not super efficient, this
isn't overly bad for the intended case of catching up with any
updates that happened during a compositor effect. However when
extended frame sync is used, surfaces are also frozen while the
client is drawing a frame, in which case the current behavior is
pretty damaging (pun intended), as we end up redrawing the entire
window each frame. To address this, keep track of the actual damage
we ignore and apply it when the surface is thawed.

https://bugzilla.gnome.org/show_bug.cgi?id=767798
---
 src/compositor/meta-surface-actor.c | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c
index bb85478..5844b37 100644
--- a/src/compositor/meta-surface-actor.c
+++ b/src/compositor/meta-surface-actor.c
@@ -25,7 +25,7 @@ struct _MetaSurfaceActorPrivate
   cairo_region_t *input_region;
 
   /* Freeze/thaw accounting */
-  guint needs_damage_all : 1;
+  cairo_region_t *pending_damage;
   guint frozen : 1;
 };
 
@@ -247,9 +247,8 @@ meta_surface_actor_process_damage (MetaSurfaceActor *self,
        * here on the off chance that this will stop the corresponding
        * texture_from_pixmap from being update.
        *
-       * needs_damage_all tracks that some unknown damage happened while the
-       * window was frozen so that when the window becomes unfrozen we can
-       * issue a full window update to cover any lost damage.
+       * pending_damage tracks any damage that happened while the window was
+       * frozen so that when can apply it when the window becomes unfrozen.
        *
        * It should be noted that this is an unreliable mechanism since it's
        * quite likely that drivers will aim to provide a zero-copy
@@ -257,7 +256,12 @@ meta_surface_actor_process_damage (MetaSurfaceActor *self,
        * any drawing done to the window is always immediately reflected in the
        * texture regardless of damage event handling.
        */
-      priv->needs_damage_all = TRUE;
+      cairo_rectangle_int_t rect = { .x = x, .y = y, .width = width, .height = height };
+
+      if (!priv->pending_damage)
+        priv->pending_damage = cairo_region_create_rectangle (&rect);
+      else
+        cairo_region_union_rectangle (priv->pending_damage, &rect);
       return;
     }
 
@@ -318,16 +322,21 @@ meta_surface_actor_set_frozen (MetaSurfaceActor *self,
 
   priv->frozen = frozen;
 
-  if (!frozen && priv->needs_damage_all)
+  if (!frozen && priv->pending_damage)
     {
+      int i, n_rects = cairo_region_num_rectangles (priv->pending_damage);
+      cairo_rectangle_int_t rect;
+
       /* Since we ignore damage events while a window is frozen for certain effects
-       * we may need to issue an update_area() covering the whole pixmap if we
-       * don't know what real damage has happened. */
+       * we need to apply the tracked damage now. */
 
-      meta_surface_actor_process_damage (self, 0, 0,
-                                         clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)),
-                                         clutter_actor_get_height (CLUTTER_ACTOR (priv->texture)));
-      priv->needs_damage_all = FALSE;
+      for (i = 0; i < n_rects; i++)
+        {
+          cairo_region_get_rectangle (priv->pending_damage, i, &rect);
+          meta_surface_actor_process_damage (self, rect.x, rect.y,
+                                             rect.width, rect.height);
+        }
+      g_clear_pointer (&priv->pending_damage, cairo_region_destroy);
     }
 }
 
-- 
2.7.4