window-actor: Use MetaRegionBuilder when scanning the visible region

This gives a pretty solid performance improvement when resizing windows.
This commit is contained in:
Jasper St. Pierre 2012-04-29 07:10:15 -04:00
parent 1e9268045d
commit 865b9df9a9
3 changed files with 46 additions and 28 deletions

View File

@ -26,6 +26,7 @@
#include "meta-shadow-factory-private.h"
#include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h"
#include "region-utils.h"
enum {
POSITION_CHANGED,
@ -2006,14 +2007,15 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
}
}
static void
static cairo_region_t *
scan_visible_region (guchar *mask_data,
int stride,
cairo_region_t *scan_area,
cairo_region_t *union_against)
cairo_region_t *scan_area)
{
int i, n_rects;
n_rects = cairo_region_num_rectangles (scan_area);
int i, n_rects = cairo_region_num_rectangles (scan_area);
MetaRegionBuilder builder;
meta_region_builder_init (&builder);
for (i = 0; i < n_rects; i++)
{
@ -2032,13 +2034,14 @@ scan_visible_region (guchar *mask_data,
if (w > 0)
{
cairo_rectangle_int_t tmp = { x, y, w - x, 1 };
cairo_region_union_rectangle (union_against, &tmp);
meta_region_builder_add_rectangle (&builder, x, y, w - x, 1);
x = w;
}
}
}
}
return meta_region_builder_finish (&builder);
}
static void
@ -2078,7 +2081,7 @@ build_and_scan_frame_mask (MetaWindowActor *self,
if (priv->window->frame != NULL)
{
cairo_region_t *frame_paint_region;
cairo_region_t *frame_paint_region, *scanned_region;
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
/* Make sure we don't paint the frame over the client window. */
@ -2099,7 +2102,9 @@ build_and_scan_frame_mask (MetaWindowActor *self,
cairo_paint (cr);
cairo_surface_flush (surface);
scan_visible_region (mask_data, stride, frame_paint_region, shape_region);
scanned_region = scan_visible_region (mask_data, stride, frame_paint_region);
cairo_region_union (shape_region, scanned_region);
cairo_region_destroy (scanned_region);
}
cairo_destroy (cr);

View File

@ -43,25 +43,10 @@
/* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower.
* But using 8 may be more robust to systems with slow malloc(). */
#define MAX_CHUNK_RECTANGLES 8
/* XXX: keep in sync with region-utils.h */
#define MAX_LEVELS 16
typedef struct
{
/* To merge regions in binary tree order, we need to keep track of
* the regions that we've already merged together at different
* levels of the tree. We fill in an array in the pattern:
*
* |a |
* |b |a |
* |c | |ab |
* |d |c |ab |
* |e | | |abcd|
*/
cairo_region_t *levels[MAX_LEVELS];
int n_levels;
} MetaRegionBuilder;
static void
void
meta_region_builder_init (MetaRegionBuilder *builder)
{
int i;
@ -70,7 +55,7 @@ meta_region_builder_init (MetaRegionBuilder *builder)
builder->n_levels = 1;
}
static void
void
meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x,
int y,
@ -115,7 +100,7 @@ meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
}
}
static cairo_region_t *
cairo_region_t *
meta_region_builder_finish (MetaRegionBuilder *builder)
{
cairo_region_t *result = NULL;

View File

@ -63,6 +63,34 @@ struct _MetaRegionIterator {
cairo_rectangle_int_t next_rectangle;
};
typedef struct _MetaRegionBuilder MetaRegionBuilder;
/* XXX: keep in sync with region-utils.c */
#define MAX_LEVELS 16
struct _MetaRegionBuilder {
/* To merge regions in binary tree order, we need to keep track of
* the regions that we've already merged together at different
* levels of the tree. We fill in an array in the pattern:
*
* |a |
* |b |a |
* |c | |ab |
* |d |c |ab |
* |e | | |abcd|
*/
cairo_region_t *levels[MAX_LEVELS];
int n_levels;
};
#undef MAX_LEVELS
void meta_region_builder_init (MetaRegionBuilder *builder);
void meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x,
int y,
int width,
int height);
cairo_region_t * meta_region_builder_finish (MetaRegionBuilder *builder);
void meta_region_iterator_init (MetaRegionIterator *iter,
cairo_region_t *region);
gboolean meta_region_iterator_at_end (MetaRegionIterator *iter);