[mutter/meego-1.0: 25/30] mutter-window: stream raw updates to ClutterX11TexturePixmap



commit d34ae764769f68a5de00812120094ea5d59969cd
Author: Robert Bragg <robert linux intel com>
Date:   Tue Mar 2 18:02:28 2010 +0000

    mutter-window: stream raw updates to ClutterX11TexturePixmap
    
    This changes the way we handle Damage events so instead of getting an
    event when the damage region of a pixmap becomes non-empty we now get
    sent all damage rectangles and stream those all though to
    ClutterX11TexturePixmap using clutter_x11_texture_pixmap_update_area()
    
    For Clutter 1.2, ClutterGLXTexturePixmap was updated so that calls to
    clutter_x11_texture_pixmap_update_area are now cheap (glXBindTexImageEXT
    calls are now deferred until just before painting) and since
    ClutterGLXTexturePixmap is now capable of queueing clipped redraws that
    can result in only updating a sub-region of the stage during a repaint
    cycle (and using glXCopySubBufferMESA to present the sub-region redraw
    to the front buffer) this should improve performance and reduced power
    consumption for a range of use cases. (For example viewing a website
    that has animated adverts doesn't force the whole screen to be redrawn
    for each frame of the advert)
    
    Besides being able to take advantage of glXCopySubBuffer to only update
    a small region of the stage the fact that this patch makes Mutter now
    request RawRectangles from the X server means we no longer do a
    synchronous X request for a complete Damage Region for every window
    damaged each frame. This should also improve performance.
    
    CLUTTER_PAINT=redraws can be used to visualize what parts of the stage
    are redrawn and with this patch applied I can open a terminal and as I
    type I see that only the damaged areas of the terminal are being
    redrawn.

 src/compositor/mutter-window.c |  221 +++++++++++++++++++++++++---------------
 1 files changed, 140 insertions(+), 81 deletions(-)
---
diff --git a/src/compositor/mutter-window.c b/src/compositor/mutter-window.c
index 63dca4b..fe64b7b 100644
--- a/src/compositor/mutter-window.c
+++ b/src/compositor/mutter-window.c
@@ -48,6 +48,8 @@ struct _MutterWindowPrivate
    * texture */
   GdkRegion        *bounding_region;
 
+  guint             freeze_count;
+
   /*
    * These need to be counters rather than flags, since more plugins
    * can implement same effect; the practicality of stacking effects
@@ -66,7 +68,9 @@ struct _MutterWindowPrivate
   guint		    disposed               : 1;
   guint             redecorating           : 1;
 
-  guint		    needs_repair           : 1;
+  guint		    needs_damage_all       : 1;
+
+  guint		    needs_pixmap           : 1;
   guint		    needs_reshape          : 1;
   guint		    size_changed           : 1;
 
@@ -347,7 +351,8 @@ mutter_window_constructed (GObject *object)
   if (priv->attrs.class == InputOnly)
     priv->damage = None;
   else
-    priv->damage = XDamageCreate (xdisplay, xwindow, XDamageReportNonEmpty);
+    priv->damage = XDamageCreate (xdisplay, xwindow,
+                                  XDamageReportRawRectangles);
 
   format = XRenderFindVisualFormat (xdisplay, priv->attrs.visual);
 
@@ -812,6 +817,60 @@ mutter_window_showing_on_its_workspace (MutterWindow *self)
   return meta_window_showing_on_its_workspace (self->priv->window);
 }
 
+static void
+mutter_window_freeze (MutterWindow *self)
+{
+  self->priv->freeze_count++;
+}
+
+static void
+mutter_window_damage_all (MutterWindow *self)
+{
+  MutterWindowPrivate *priv = self->priv;
+  ClutterX11TexturePixmap *texture_x11 = CLUTTER_X11_TEXTURE_PIXMAP (priv->actor);
+  guint pixmap_width = 0;
+  guint pixmap_height = 0;
+
+  if (!priv->needs_damage_all)
+    return;
+
+  g_object_get (texture_x11,
+                "pixmap-width", &pixmap_width,
+                "pixmap-height", &pixmap_height,
+                NULL);
+
+  clutter_x11_texture_pixmap_update_area (texture_x11,
+                                          0,
+                                          0,
+                                          pixmap_width,
+                                          pixmap_height);
+
+  priv->needs_damage_all = FALSE;
+}
+
+static void
+mutter_window_thaw (MutterWindow *self)
+{
+  self->priv->freeze_count--;
+
+  if (G_UNLIKELY (self->priv->freeze_count < 0))
+    {
+      g_warning ("Error in freeze/thaw accounting.");
+      self->priv->freeze_count = 0;
+      return;
+    }
+
+  if (self->priv->freeze_count)
+    return;
+
+  /* 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. */
+
+  if (self->priv->needs_damage_all)
+    mutter_window_damage_all (self);
+}
+
 gboolean
 mutter_window_effect_in_progress (MutterWindow *self)
 {
@@ -823,11 +882,11 @@ mutter_window_effect_in_progress (MutterWindow *self)
 }
 
 static void
-mutter_window_mark_for_repair (MutterWindow *self)
+mutter_window_queue_create_pixmap (MutterWindow *self)
 {
   MutterWindowPrivate *priv = self->priv;
 
-  priv->needs_repair = TRUE;
+  priv->needs_pixmap = TRUE;
 
   if (!priv->mapped)
     return;
@@ -844,12 +903,28 @@ mutter_window_mark_for_repair (MutterWindow *self)
 }
 
 static gboolean
+is_freeze_thaw_effect (gulong event)
+{
+  switch (event)
+  {
+  case MUTTER_PLUGIN_DESTROY:
+  case MUTTER_PLUGIN_MAXIMIZE:
+  case MUTTER_PLUGIN_UNMAXIMIZE:
+    return TRUE;
+    break;
+  default:
+    return FALSE;
+  }
+}
+
+static gboolean
 start_simple_effect (MutterWindow *self,
                      gulong        event)
 {
   MutterWindowPrivate *priv = self->priv;
   MetaCompScreen *info = meta_screen_get_compositor_data (priv->screen);
   gint *counter = NULL;
+  gboolean use_freeze_thaw = FALSE;
 
   if (!info->plugin_mgr)
     return FALSE;
@@ -874,6 +949,11 @@ start_simple_effect (MutterWindow *self,
 
   g_assert (counter);
 
+  use_freeze_thaw = is_freeze_thaw_effect (event);
+
+  if (use_freeze_thaw)
+    mutter_window_freeze (self);
+
   (*counter)++;
 
   if (!mutter_plugin_manager_event_simple (info->plugin_mgr,
@@ -881,6 +961,8 @@ start_simple_effect (MutterWindow *self,
                                            event))
     {
       (*counter)--;
+      if (use_freeze_thaw)
+        mutter_window_thaw (self);
       return FALSE;
     }
 
@@ -904,7 +986,7 @@ mutter_window_after_effects (MutterWindow *self)
   if (!meta_window_is_mapped (priv->window))
     mutter_window_detach (self);
 
-  if (priv->needs_repair)
+  if (priv->needs_pixmap)
     clutter_actor_queue_redraw (priv->actor);
 }
 
@@ -973,6 +1055,9 @@ mutter_window_effect_completed (MutterWindow *self,
     break;
   }
 
+  if (is_freeze_thaw_effect (event))
+    mutter_window_thaw (self);
+
   if (!mutter_window_effect_in_progress (self))
     mutter_window_after_effects (self);
 }
@@ -1005,7 +1090,7 @@ mutter_window_detach (MutterWindow *self)
   clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
                                          None);
 
-  mutter_window_mark_for_repair (self);
+  mutter_window_queue_create_pixmap (self);
 }
 
 void
@@ -1071,7 +1156,7 @@ mutter_window_sync_actor_position (MutterWindow *self)
       priv->attrs.height != window_rect.height)
     {
       priv->size_changed = TRUE;
-      mutter_window_mark_for_repair (self);
+      mutter_window_queue_create_pixmap (self);
     }
 
   /* XXX deprecated: please use meta_window_get_outer_rect instead */
@@ -1265,7 +1350,7 @@ mutter_window_new (MetaWindow *window)
 
   priv->mapped = meta_window_toplevel_is_mapped (priv->window);
   if (priv->mapped)
-    mutter_window_mark_for_repair (self);
+    mutter_window_queue_create_pixmap (self);
 
   mutter_window_sync_actor_position (self);
 
@@ -1294,7 +1379,7 @@ mutter_window_mapped (MutterWindow *self)
 
   priv->mapped = TRUE;
 
-  mutter_window_mark_for_repair (self);
+  mutter_window_queue_create_pixmap (self);
 }
 
 void
@@ -1310,7 +1395,7 @@ mutter_window_unmapped (MutterWindow *self)
     return;
 
   mutter_window_detach (self);
-  priv->needs_repair = FALSE;
+  priv->needs_pixmap = FALSE;
 }
 
 static void
@@ -1526,7 +1611,7 @@ mutter_window_reset_visible_regions (MutterWindow *self)
 }
 
 static void
-check_needs_repair (MutterWindow *self)
+check_needs_pixmap (MutterWindow *self)
 {
   MutterWindowPrivate *priv     = self->priv;
   MetaScreen          *screen   = priv->screen;
@@ -1537,7 +1622,7 @@ check_needs_repair (MutterWindow *self)
   Window               xwindow  = priv->xwindow;
   gboolean             full     = FALSE;
 
-  if (!priv->needs_repair)
+  if (!priv->needs_pixmap)
     return;
 
   if (!priv->mapped)
@@ -1613,74 +1698,50 @@ check_needs_repair (MutterWindow *self)
       full = TRUE;
     }
 
- /*
-   * TODO -- on some gfx hardware updating the whole texture instead of
-   * the individual rectangles is actually quicker, so we might want to
-   * make this a configurable option (on desktop HW with multiple pipelines
-   * it is usually quicker to just update the damaged parts).
-   *
-   * If we are using TFP we update the whole texture (this simply trigers
-   * the texture rebind).
-   */
-  if (full
-#ifdef HAVE_GLX_TEXTURE_PIXMAP
-      || (CLUTTER_GLX_IS_TEXTURE_PIXMAP (priv->actor) &&
-          clutter_glx_texture_pixmap_using_extension
-                  (CLUTTER_GLX_TEXTURE_PIXMAP (priv->actor)))
-#endif /* HAVE_GLX_TEXTURE_PIXMAP */
-      )
-    {
-      XDamageSubtract (xdisplay, priv->damage, None, None);
-
-      clutter_x11_texture_pixmap_update_area
-	(CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
-	 0,
-	 0,
-	 clutter_actor_get_width (priv->actor),
-	 clutter_actor_get_height (priv->actor));
-    }
-  else
-    {
-      XRectangle   *r_damage;
-      XRectangle    r_bounds;
-      XserverRegion parts;
-      int           i, r_count;
-
-      parts = XFixesCreateRegion (xdisplay, 0, 0);
-      XDamageSubtract (xdisplay, priv->damage, None, parts);
-
-      r_damage = XFixesFetchRegionAndBounds (xdisplay,
-					     parts,
-					     &r_count,
-					     &r_bounds);
-
-      if (r_damage)
-	{
-	  for (i = 0; i < r_count; ++i)
-	    {
-	      clutter_x11_texture_pixmap_update_area
-		(CLUTTER_X11_TEXTURE_PIXMAP (priv->actor),
-		 r_damage[i].x,
-		 r_damage[i].y,
-		 r_damage[i].width,
-		 r_damage[i].height);
-	    }
-	}
-
-      XFree (r_damage);
-      XFixesDestroyRegion (xdisplay, parts);
-    }
-
   meta_error_trap_pop (display, FALSE);
 
-  priv->needs_repair = FALSE;
+  priv->needs_pixmap = FALSE;
+}
+
+static gboolean
+is_frozen (MutterWindow *self)
+{
+  return self->priv->freeze_count ? TRUE : FALSE;
 }
 
 void
 mutter_window_process_damage (MutterWindow       *self,
 			      XDamageNotifyEvent *event)
 {
-  mutter_window_mark_for_repair (self);
+  MutterWindowPrivate *priv = self->priv;
+  ClutterX11TexturePixmap *texture_x11 = CLUTTER_X11_TEXTURE_PIXMAP (priv->actor);
+
+  if (is_frozen (self))
+    {
+      /* The window is frozen due to an effect in progress: we ignore damage
+       * 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.
+       *
+       * It should be noted that this is an unreliable mechanism since it's
+       * quite likely that drivers will aim to provide a zero-copy
+       * implementation of the texture_from_pixmap extension and in those cases
+       * any drawing done to the window is always immediately reflected in the
+       * texture regardless of damage event handling.
+       */
+      priv->needs_damage_all = TRUE;
+      return;
+    }
+
+
+  clutter_x11_texture_pixmap_update_area (texture_x11,
+                                          event->area.x,
+                                          event->area.y,
+                                          event->area.width,
+                                          event->area.height);
 }
 
 void
@@ -1751,17 +1812,15 @@ mutter_window_update_shape (MutterWindow   *self,
 void
 mutter_window_pre_paint (MutterWindow *self)
 {
-  MutterWindowPrivate *priv = self->priv;
-
-  /* The window is frozen due to a pending animation: we'll wait until
-   * the animation finishes to reshape and repair the window */
-  if (priv->destroy_in_progress    ||
-      priv->maximize_in_progress   ||
-      priv->unmaximize_in_progress)
-    return;
+  if (is_frozen (self))
+    {
+      /* The window is frozen due to a pending animation: we'll wait until
+       * the animation finishes to reshape and repair the window */
+      return;
+    }
 
   check_needs_reshape (self);
-  check_needs_repair (self);
+  check_needs_pixmap (self);
 }
 
 void



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