diff options
author | Alexander Larsson <alexl@redhat.com> | 2013-04-17 14:02:32 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2013-05-02 16:09:08 +0200 |
commit | 1dd823f6f6035bb6f392079fe21b39756bd1b018 (patch) | |
tree | d6dd8428d08b1557826f54d768ad1b826e07c53f | |
parent | 479b69a8bfe3654d9188660e5e7ea7a10c63b490 (diff) | |
download | gtk+-1dd823f6f6035bb6f392079fe21b39756bd1b018.tar.gz |
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.
-rw-r--r-- | gdk/gdkinternals.h | 2 | ||||
-rw-r--r-- | gdk/gdkwindow.c | 406 |
2 files changed, 14 insertions, 394 deletions
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index a14e7abc21..d4e867c3e9 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 1d4687be16..fd82e31b89 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; |