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.
This commit is contained in:
Alexander Larsson 2014-10-09 10:09:51 +02:00 committed by Matthias Clasen
parent ceeed1c48d
commit a8f11835c5
2 changed files with 46 additions and 7 deletions

View File

@ -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;

View File

@ -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);
}
}