[gtk+/wip/simple-draw2: 2/15] gdkwindow: Remove outstanding_moves stuff



commit 9f8e06265b3d6831e66ce788f8b1fcbc68dd482e
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Apr 17 14:02:32 2013 +0200

    gdkwindow: Remove outstanding_moves stuff
    
    Since we now never move regions directly on the window we can
    remove all the stuff that track outstanding moves and flushes then.

 gdk/gdkinternals.h |    2 -
 gdk/gdkwindow.c    |  406 ++--------------------------------------------------
 2 files changed, 14 insertions(+), 394 deletions(-)
---
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index a14e7ab..d4e867c 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -252,8 +252,6 @@ struct _GdkWindow
 
   GSList *implicit_paint;
 
-  GList *outstanding_moves;
-
   cairo_region_t *shape;
   cairo_region_t *input_shape;
 
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 1d4687b..fd82e31 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -136,20 +136,7 @@
  * so that eg. client side siblings that overlap the native child properly
  * draws over the native child window.
  *
- * In order to minimize flicker and for performance we use a couple of cacheing
- * tricks. First of all, every time we do a window to window copy area, for instance
- * when moving a client side window or when scrolling/moving a region in a window
- * we store this in outstanding_moves instead of applying immediately. We then
- * delay this move until we really need it (because something depends on being
- * able to read it), or until we're handing a redraw from an expose/invalidation
- * (actually we delay it past redraw, but before blitting the double buffer
- * to the window). This gives us two advantages. First of all it minimizes the time
- * from the window is moved to the exposes related to that move, secondly it allows
- * us to be smart about how to do the copy. We combine multiple moves into one (when
- * possible) and we don't actually do copies to anything that is or will be
- * invalidated and exposed anyway.
- *
- * Secondly, we use something called a "implicit paint" during repaint handling.
+ * We use something called a "implicit paint" during repaint handling.
  * An implicit paint is similar to a regular paint for the paint stack, but it is
  * not put on the stack. Instead, it is set on the impl window, and later when
  * regular gdk_window_begin_paint_region()  happen on a window of this impl window
@@ -191,11 +178,6 @@ struct _GdkWindowPaint
   guint uses_implicit : 1;
 };
 
-typedef struct {
-  cairo_region_t *dest_region; /* The destination region */
-  int dx, dy; /* The amount that the source was moved to reach dest_region */
-} GdkWindowRegionMove;
-
 /* Global info */
 
 static void             gdk_window_drop_cairo_surface (GdkWindow *private);
@@ -219,18 +201,13 @@ static void gdk_window_clear_backing_region (GdkWindow *window,
 static void recompute_visible_regions   (GdkWindow *private,
                                         gboolean recalculate_siblings,
                                         gboolean recalculate_children);
-static void gdk_window_flush_outstanding_moves (GdkWindow *window);
 static void gdk_window_flush_recursive  (GdkWindow *window);
-static void do_move_region_bits_on_impl (GdkWindow *window,
-                                        cairo_region_t *region, /* In impl window coords */
-                                        int dx, int dy);
 static void gdk_window_invalidate_in_parent (GdkWindow *private);
 static void move_native_children        (GdkWindow *private);
 static void update_cursor               (GdkDisplay *display,
                                          GdkDevice  *device);
 static void impl_window_add_update_area (GdkWindow *impl_window,
                                         cairo_region_t *region);
-static void gdk_window_region_move_free (GdkWindowRegionMove *move);
 static void gdk_window_invalidate_region_full (GdkWindow       *window,
                                               const cairo_region_t *region,
                                               gboolean         invalidate_children,
@@ -2148,9 +2125,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
              cairo_region_destroy (window->clip_region_with_children);
              window->clip_region_with_children = NULL;
            }
-
-         g_list_free_full (window->outstanding_moves, (GDestroyNotify) gdk_window_region_move_free);
-         window->outstanding_moves = NULL;
        }
       break;
     }
@@ -3212,8 +3186,6 @@ gdk_window_end_paint (GdkWindow *window)
     {
       cairo_t *cr;
 
-      gdk_window_flush_outstanding_moves (window);
-
       full_clip = cairo_region_copy (window->clip_region_with_children);
       cairo_region_intersect (full_clip, paint->region);
 
@@ -3281,242 +3253,6 @@ gdk_window_free_paint_stack (GdkWindow *window)
     }
 }
 
-static void
-do_move_region_bits_on_impl (GdkWindow *impl_window,
-                            cairo_region_t *dest_region, /* In impl window coords */
-                            int dx, int dy)
-{
-  GdkWindowImplClass *impl_class;
-
-  impl_class = GDK_WINDOW_IMPL_GET_CLASS (impl_window->impl);
-
-  impl_class->translate (impl_window, dest_region, dx, dy);
-}
-
-static GdkWindowRegionMove *
-gdk_window_region_move_new (cairo_region_t *region,
-                           int dx, int dy)
-{
-  GdkWindowRegionMove *move;
-
-  move = g_slice_new (GdkWindowRegionMove);
-  move->dest_region = cairo_region_copy (region);
-  move->dx = dx;
-  move->dy = dy;
-
-  return move;
-}
-
-static void
-gdk_window_region_move_free (GdkWindowRegionMove *move)
-{
-  cairo_region_destroy (move->dest_region);
-  g_slice_free (GdkWindowRegionMove, move);
-}
-
-static void
-append_move_region (GdkWindow *impl_window,
-                   cairo_region_t *new_dest_region,
-                   int dx, int dy)
-{
-  GdkWindowRegionMove *move, *old_move;
-  cairo_region_t *new_total_region, *old_total_region;
-  cairo_region_t *source_overlaps_destination;
-  cairo_region_t *non_overwritten;
-  gboolean added_move;
-  GList *l, *prev;
-
-  if (cairo_region_is_empty (new_dest_region))
-    return;
-
-  /* In principle this could just append the move to the list of outstanding
-     moves that will be replayed before drawing anything when we're handling
-     exposes. However, we'd like to do a bit better since its commonly the case
-     that we get multiple copies where A is copied to B and then B is copied
-     to C, and we'd like to express this as a simple copy A to C operation. */
-
-  /* We approach this by taking the new move and pushing it ahead of moves
-     starting at the end of the list and stopping when its not safe to do so.
-     It's not safe to push past a move if either the source of the new move
-     is in the destination of the old move, or if the destination of the new
-     move is in the source of the new move, or if the destination of the new
-     move overlaps the destination of the old move. We simplify this by
-     just comparing the total regions (src + dest) */
-  new_total_region = cairo_region_copy (new_dest_region);
-  cairo_region_translate (new_total_region, -dx, -dy);
-  cairo_region_union (new_total_region, new_dest_region);
-
-  added_move = FALSE;
-  for (l = g_list_last (impl_window->outstanding_moves); l != NULL; l = prev)
-    {
-      prev = l->prev;
-      old_move = l->data;
-
-      old_total_region = cairo_region_copy (old_move->dest_region);
-      cairo_region_translate (old_total_region, -old_move->dx, -old_move->dy);
-      cairo_region_union (old_total_region, old_move->dest_region);
-
-      cairo_region_intersect (old_total_region, new_total_region);
-      /* If these regions intersect then its not safe to push the
-        new region before the old one */
-      if (!cairo_region_is_empty (old_total_region))
-       {
-         /* The area where the new moves source overlaps the old ones
-            destination */
-         source_overlaps_destination = cairo_region_copy (new_dest_region);
-         cairo_region_translate (source_overlaps_destination, -dx, -dy);
-         cairo_region_intersect (source_overlaps_destination, old_move->dest_region);
-         cairo_region_translate (source_overlaps_destination, dx, dy);
-
-         /* We can do all sort of optimizations here, but to do things safely it becomes
-            quite complicated. However, a very common case is that you copy something first,
-            then copy all that or a subset of it to a new location (i.e. if you scroll twice
-            in the same direction). We'd like to detect this case and optimize it to one
-            copy. */
-         if (cairo_region_equal (source_overlaps_destination, new_dest_region))
-           {
-             /* This means we might be able to replace the old move and the new one
-                with the new one read from the old ones source, and a second copy of
-                the non-overwritten parts of the old move. However, such a split
-                is only valid if the source in the old move isn't overwritten
-                by the destination of the new one */
-
-             /* the new destination of old move if split is ok: */
-             non_overwritten = cairo_region_copy (old_move->dest_region);
-             cairo_region_subtract (non_overwritten, new_dest_region);
-             /* move to source region */
-             cairo_region_translate (non_overwritten, -old_move->dx, -old_move->dy);
-
-             cairo_region_intersect (non_overwritten, new_dest_region);
-             if (cairo_region_is_empty (non_overwritten))
-               {
-                 added_move = TRUE;
-                 move = gdk_window_region_move_new (new_dest_region,
-                                                    dx + old_move->dx,
-                                                    dy + old_move->dy);
-
-                 impl_window->outstanding_moves =
-                   g_list_insert_before (impl_window->outstanding_moves,
-                                         l, move);
-                 cairo_region_subtract (old_move->dest_region, new_dest_region);
-               }
-             cairo_region_destroy (non_overwritten);
-           }
-
-         cairo_region_destroy (source_overlaps_destination);
-         cairo_region_destroy (old_total_region);
-         break;
-       }
-      cairo_region_destroy (old_total_region);
-    }
-
-  cairo_region_destroy (new_total_region);
-
-  if (!added_move)
-    {
-      move = gdk_window_region_move_new (new_dest_region, dx, dy);
-
-      if (l == NULL)
-       impl_window->outstanding_moves =
-         g_list_prepend (impl_window->outstanding_moves,
-                         move);
-      else
-       impl_window->outstanding_moves =
-         g_list_insert_before (impl_window->outstanding_moves,
-                               l->next, move);
-    }
-}
-
-/* Moves bits and update area by dx/dy in impl window.
-   Takes ownership of region to avoid copy (because we may change it) */
-static void
-move_region_on_impl (GdkWindow *impl_window,
-                    cairo_region_t *region, /* In impl window coords */
-                    int dx, int dy)
-{
-  GSList *l;
-
-  if ((dx == 0 && dy == 0) ||
-      cairo_region_is_empty (region))
-    {
-      cairo_region_destroy (region);
-      return;
-    }
-
-  g_assert (impl_window == gdk_window_get_impl_window (impl_window));
-
-  /* Move any old invalid regions in the copy source area by dx/dy */
-  if (impl_window->update_area)
-    {
-      cairo_region_t *update_area;
-
-      update_area = cairo_region_copy (region);
-
-      /* Convert from target to source */
-      cairo_region_translate (update_area, -dx, -dy);
-      cairo_region_intersect (update_area, impl_window->update_area);
-      /* We only copy the area, so keep the old update area invalid.
-        It would be safe to remove it too, as code that uses
-        move_region_on_impl generally also invalidate the source
-        area. However, it would just use waste cycles. */
-
-      /* Convert back */
-      cairo_region_translate (update_area, dx, dy);
-      cairo_region_union (impl_window->update_area, update_area);
-
-      /* This area of the destination is now invalid,
-        so no need to copy to it.  */
-      cairo_region_subtract (region, update_area);
-
-      cairo_region_destroy (update_area);
-    }
-
-  /* If we're currently exposing this window, don't copy to this
-     destination, as it will be overdrawn when the expose is done,
-     instead invalidate it and repaint later. */
-  for (l = impl_window->implicit_paint; l != NULL; l = l->next)
-    {
-      GdkWindowPaint *implicit_paint = l->data;
-      cairo_region_t *exposing;
-
-      exposing = cairo_region_copy (implicit_paint->region);
-      cairo_region_intersect (exposing, region);
-      cairo_region_subtract (region, exposing);
-
-      impl_window_add_update_area (impl_window, exposing);
-      cairo_region_destroy (exposing);
-    }
-
-  append_move_region (impl_window, region, dx, dy);
-
-  cairo_region_destroy (region);
-}
-
-/* Flushes all outstanding changes to the window, call this
- * before drawing directly to the window (i.e. outside a begin/end_paint pair).
- */
-static void
-gdk_window_flush_outstanding_moves (GdkWindow *window)
-{
-  GdkWindow *impl_window;
-  GdkWindowRegionMove *move;
-
-  impl_window = gdk_window_get_impl_window (window);
-
-  while (impl_window->outstanding_moves)
-    {
-      move = impl_window->outstanding_moves->data;
-      impl_window->outstanding_moves = 
-       g_list_delete_link (impl_window->outstanding_moves,
-                           impl_window->outstanding_moves);
-
-      do_move_region_bits_on_impl (impl_window,
-                                  move->dest_region, move->dx, move->dy);
-
-      gdk_window_region_move_free (move);
-    }
-}
-
 /**
  * gdk_window_flush:
  * @window: a #GdkWindow
@@ -3527,9 +3263,7 @@ gdk_window_flush_outstanding_moves (GdkWindow *window)
  * Gdk uses multiple kinds of caching to get better performance and
  * nicer drawing. For instance, during exposes all paints to a window
  * using double buffered rendering are keep on a surface until the last
- * window has been exposed. It also delays window moves/scrolls until
- * as long as possible until next update to avoid tearing when moving
- * windows.
+ * window has been exposed.
  *
  * Normally this should be completely invisible to applications, as
  * we automatically flush the windows when required, but this might
@@ -3542,7 +3276,6 @@ gdk_window_flush_outstanding_moves (GdkWindow *window)
 void
 gdk_window_flush (GdkWindow *window)
 {
-  gdk_window_flush_outstanding_moves (window);
   gdk_window_flush_implicit_paint (window);
 }
 
@@ -4059,10 +3792,6 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
 
 /* Process and remove any invalid area on the native window by creating
  * expose events for the window and all non-native descendants.
- * Also processes any outstanding moves on the window before doing
- * any drawing. Note that its possible to have outstanding moves without
- * any invalid area as we use the update idle mechanism to coalesce
- * multiple moves as well as multiple invalidations.
  */
 static void
 gdk_window_process_updates_internal (GdkWindow *window)
@@ -4070,7 +3799,6 @@ gdk_window_process_updates_internal (GdkWindow *window)
   GdkWindowImplClass *impl_class;
   gboolean save_region = FALSE;
   GdkRectangle clip_box;
-  int iteration;
 
   /* Ensure the window lives while updating it */
   g_object_ref (window);
@@ -4078,15 +3806,8 @@ gdk_window_process_updates_internal (GdkWindow *window)
   /* If an update got queued during update processing, we can get a
    * window in the update queue that has an empty update_area.
    * just ignore it.
-   *
-   * We run this multiple times if needed because on win32 the
-   * first run can cause new (synchronous) updates from
-   * gdk_window_flush_outstanding_moves(). However, we
-   * limit it to two iterations to avoid any potential loops.
    */
-  iteration = 0;
-  while (window->update_area &&
-        iteration++ < 2)
+  if (window->update_area)
     {
       cairo_region_t *update_area = window->update_area;
       window->update_area = NULL;
@@ -4106,51 +3827,8 @@ gdk_window_process_updates_internal (GdkWindow *window)
              g_usleep (70000);
            }
 
-         /* At this point we will be completely redrawing all of update_area.
-          * If we have any outstanding moves that end up moving stuff inside
-          * this area we don't actually need to move that as that part would
-          * be overdrawn by the expose anyway. So, in order to copy less data
-          * we remove these areas from the outstanding moves.
-          */
-         if (window->outstanding_moves)
-           {
-             GdkWindowRegionMove *move;
-             cairo_region_t *remove;
-             GList *l, *prev;
-
-             remove = cairo_region_copy (update_area);
-             /* We iterate backwards, starting from the state that would be
-                if we had applied all the moves. */
-             for (l = g_list_last (window->outstanding_moves); l != NULL; l = prev)
-               {
-                 prev = l->prev;
-                 move = l->data;
-
-                 /* Don't need this area */
-                 cairo_region_subtract (move->dest_region, remove);
-
-                 /* However if any of the destination we do need has a source
-                    in the updated region we do need that as a destination for
-                    the earlier moves */
-                 cairo_region_translate (move->dest_region, -move->dx, -move->dy);
-                 cairo_region_subtract (remove, move->dest_region);
-
-                 if (cairo_region_is_empty (move->dest_region))
-                   {
-                     gdk_window_region_move_free (move);
-                     window->outstanding_moves =
-                       g_list_delete_link (window->outstanding_moves, l);
-                   }
-                 else /* move back */
-                   cairo_region_translate (move->dest_region, move->dx, move->dy);
-               }
-             cairo_region_destroy (remove);
-           }
-
-         /* By now we a set of window moves that should be applied, and then
-          * an update region that should be repainted. A trivial implementation
-          * would just do that in order, however in order to get nicer drawing
-          * we do some tricks:
+         /* By now we an update region that should be repainted. However in order to
+          * get nicer drawing we do some tricks:
           *
           * First of all, each subwindow expose may be double buffered by
           * itself (depending on widget setting) via
@@ -4165,20 +3843,12 @@ gdk_window_process_updates_internal (GdkWindow *window)
           * gdk double buffering there. Secondly, some subwindow could be
           * non-double buffered and draw directly to the window outside a
           * begin/end_paint pair. That will be lead to a gdk_window_flush
-          * which immediately executes all outstanding moves and paints+removes
-          * the implicit paint (further paints will allocate their own surfaces).
-          *
-          * Secondly, in the case of implicit double buffering we expose all
-          * the child windows into the implicit surface before we execute
-          * the outstanding moves. This way we minimize the time between
-          * doing the moves and rendering the new update area, thus minimizing
-          * flashing. Of course, if any subwindow is non-double buffered we
-          * well flush earlier than that.
+          * which immediately paints+removes the implicit paint (further
+          * paints will allocate their own surfaces).
           *
-          * Thirdly, after having done the outstanding moves we queue an
-          * "antiexpose" on the area that will be drawn by the expose, which
-          * means that any invalid region on the native window side before
-          * the first expose drawing operation will be discarded, as it
+          * Secondly, we queue an "antiexpose" on the area that will be drawn by
+          * the expose, which means that any invalid region on the native window side
+          * before the first expose drawing operation will be discarded, as it
           * has by then been overdrawn with valid data. This means we can
           * avoid doing the unnecessary repaint any outstanding expose events.
           */
@@ -4189,10 +3859,6 @@ gdk_window_process_updates_internal (GdkWindow *window)
          impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
          if (!end_implicit)
            {
-             /* Rendering is not double buffered by gdk, do outstanding
-              * moves and queue antiexposure immediately. No need to do
-              * any tricks */
-             gdk_window_flush_outstanding_moves (window);
              save_region = impl_class->queue_antiexpose (window, update_area);
            }
          /* Render the invalid areas to the implicit paint, by sending exposes.
@@ -4201,12 +3867,9 @@ gdk_window_process_updates_internal (GdkWindow *window)
 
          if (end_implicit)
            {
-             /* Do moves right before exposes are rendered to the window */
-             gdk_window_flush_outstanding_moves (window);
-
              /* By this time we know that any outstanding expose for this
               * area is invalid and we can avoid it, so queue an antiexpose.
-              * we have already started drawing to the window, so it would
+              * If we flushed we have already started drawing to the window, so it would
               * be to late to anti-expose now. Since this is merely an
               * optimization we just avoid doing it at all in that case.
               */
@@ -4221,13 +3884,6 @@ gdk_window_process_updates_internal (GdkWindow *window)
        cairo_region_destroy (update_area);
     }
 
-  if (window->outstanding_moves)
-    {
-      /* Flush any outstanding moves, may happen if we moved a window but got
-        no actual invalid area */
-      gdk_window_flush_outstanding_moves (window);
-    }
-
   g_object_unref (window);
 }
 
@@ -4368,8 +4024,7 @@ gdk_window_process_updates_with_mode (GdkWindow     *window,
   g_object_ref (window);
 
   impl_window = gdk_window_get_impl_window (window);
-  if ((impl_window->update_area ||
-       impl_window->outstanding_moves) &&
+  if ((impl_window->update_area) &&
       !impl_window->update_freeze_count &&
       !gdk_window_is_toplevel_frozen (window) &&
 
@@ -4594,11 +4249,7 @@ gdk_window_invalidate_maybe_recurse_full (GdkWindow            *window,
 
   impl_window = gdk_window_get_impl_window (window);
 
-  if (!cairo_region_is_empty (visible_region)  ||
-      /* Even if we're not exposing anything, make sure we process
-        idles for windows with outstanding moves */
-      (impl_window->outstanding_moves != NULL &&
-       impl_window->update_area == NULL))
+  if (!cairo_region_is_empty (visible_region))
     {
       if (debug_updates)
        draw_ugly_color (window, region);
@@ -4734,34 +4385,6 @@ void
 _gdk_window_invalidate_for_expose (GdkWindow       *window,
                                   cairo_region_t       *region)
 {
-  GdkWindowRegionMove *move;
-  cairo_region_t *move_region;
-  GList *l;
-
-  /* Any invalidations comming from the windowing system will
-     be in areas that may be moved by outstanding moves,
-     so we need to modify the expose region correspondingly,
-     otherwise we would expose in the wrong place, as the
-     outstanding moves will be copied before we draw the
-     exposes. */
-  for (l = window->outstanding_moves; l != NULL; l = l->next)
-    {
-      move = l->data;
-
-      /* covert to move source region */
-      move_region = cairo_region_copy (move->dest_region);
-      cairo_region_translate (move_region, -move->dx, -move->dy);
-
-      /* Move area of region that intersects with move source
-        by dx, dy of the move*/
-      cairo_region_intersect (move_region, region);
-      cairo_region_subtract (region, move_region);
-      cairo_region_translate (move_region, move->dx, move->dy);
-      cairo_region_union (region, move_region);
-
-      cairo_region_destroy (move_region);
-    }
-
   gdk_window_invalidate_maybe_recurse_full (window, region, CLEAR_BG_WINCLEARED,
                                            (gboolean (*) (GdkWindow *, gpointer))gdk_window_has_no_impl,
                                            NULL);
@@ -4821,8 +4444,7 @@ gdk_window_get_update_area (GdkWindow *window)
 
          cairo_region_destroy (to_remove);
 
-         if (cairo_region_is_empty (impl_window->update_area) &&
-             impl_window->outstanding_moves == NULL)
+         if (cairo_region_is_empty (impl_window->update_area))
            {
              cairo_region_destroy (impl_window->update_area);
              impl_window->update_area = NULL;


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