From a8f11835c5c59755c0477b289019a4cfab761628 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 9 Oct 2014 10:09:51 +0200 Subject: [PATCH] Change the way the update area is tracked during paint First of all we track the current update area during an update in window->active_update_area. This will be used later in end_paint to know the damaged area. Secondly we keep track of old update areas for the last 2 frames. This will later allow us to reuse old framebuffer contents in double or tripple buffer setups, only painting what has changed since then. --- gdk/gdkinternals.h | 6 ++++++ gdk/gdkwindow.c | 47 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 07df2f15de..d70b6c4742 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -213,6 +213,12 @@ struct _GdkWindow cairo_region_t *update_area; guint update_freeze_count; + /* This is the update_area that was in effect when the current expose + started. It may be smaller than the expose area if we'e painting + more than we have to, but it represents the "true" damage. */ + cairo_region_t *active_update_area; + /* We store the old expose areas to support buffer-age optimizations */ + cairo_region_t *old_updated_area[2]; GdkWindowState state; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index da01a8c6ea..f5c06100bb 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -1024,9 +1024,35 @@ recompute_visible_regions (GdkWindow *private, recalculate_children); } +static void +gdk_window_clear_old_updated_area (GdkWindow *window) +{ + int i; + + for (i = 0; i < 2; i++) + { + if (window->old_updated_area[i]) + { + cairo_region_destroy (window->old_updated_area[i]); + window->old_updated_area[i] = NULL; + } + } +} + +static void +gdk_window_append_old_updated_area (GdkWindow *window, + cairo_region_t *region) +{ + if (window->old_updated_area[1]) + cairo_region_destroy (window->old_updated_area[1]); + window->old_updated_area[1] = window->old_updated_area[0]; + window->old_updated_area[0] = cairo_region_reference (region); +} + void _gdk_window_update_size (GdkWindow *window) { + gdk_window_clear_old_updated_area (window); recompute_visible_regions (window, FALSE); } @@ -3375,15 +3401,19 @@ gdk_window_process_updates_internal (GdkWindow *window) */ if (window->update_area) { - cairo_region_t *update_area = window->update_area; + g_assert (window->active_update_area == NULL); /* No reentrancy */ + + window->active_update_area = window->update_area; window->update_area = NULL; if (gdk_window_is_viewable (window)) { cairo_region_t *expose_region; + expose_region = cairo_region_copy (window->active_update_area); + /* Clip to part visible in impl window */ - cairo_region_intersect (update_area, window->clip_region); + cairo_region_intersect (expose_region, window->clip_region); if (debug_updates) { @@ -3395,14 +3425,15 @@ gdk_window_process_updates_internal (GdkWindow *window) impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl); if (impl_class->queue_antiexpose) - impl_class->queue_antiexpose (window, update_area); + impl_class->queue_antiexpose (window, expose_region); - expose_region = cairo_region_copy (update_area); impl_class->process_updates_recurse (window, expose_region); - cairo_region_destroy (expose_region); - } - cairo_region_destroy (update_area); + gdk_window_append_old_updated_area (window, window->active_update_area); + } + + cairo_region_destroy (window->active_update_area); + window->active_update_area = NULL; } window->in_update = FALSE; @@ -5046,6 +5077,7 @@ gdk_window_hide (GdkWindow *window) impl_class->hide (window); } + gdk_window_clear_old_updated_area (window); recompute_visible_regions (window, FALSE); /* all decendants became non-visible, we need to send visibility notify */ @@ -5105,6 +5137,7 @@ gdk_window_withdraw (GdkWindow *window) } recompute_visible_regions (window, FALSE); + gdk_window_clear_old_updated_area (window); } }