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 60c05a0dac
commit ac18f41ed1
3 changed files with 45 additions and 31 deletions

View File

@ -26,6 +26,7 @@
#include "meta-shadow-factory-private.h" #include "meta-shadow-factory-private.h"
#include "meta-window-actor-private.h" #include "meta-window-actor-private.h"
#include "meta-texture-rectangle.h" #include "meta-texture-rectangle.h"
#include "region-utils.h"
enum { enum {
POSITION_CHANGED, POSITION_CHANGED,
@ -2058,14 +2059,15 @@ install_corners (MetaWindow *window,
cairo_fill (cr); cairo_fill (cr);
} }
static void static cairo_region_t *
scan_visible_region (guchar *mask_data, scan_visible_region (guchar *mask_data,
int stride, int stride,
cairo_region_t *scan_area, cairo_region_t *scan_area)
cairo_region_t *union_against)
{ {
int i, n_rects; int i, n_rects = cairo_region_num_rectangles (scan_area);
n_rects = cairo_region_num_rectangles (scan_area); MetaRegionBuilder builder;
meta_region_builder_init (&builder);
for (i = 0; i < n_rects; i++) for (i = 0; i < n_rects; i++)
{ {
@ -2084,13 +2086,14 @@ scan_visible_region (guchar *mask_data,
if (w > 0) if (w > 0)
{ {
cairo_rectangle_int_t tmp = { x, y, w - x, 1 }; meta_region_builder_add_rectangle (&builder, x, y, w - x, 1);
cairo_region_union_rectangle (union_against, &tmp);
x = w; x = w;
} }
} }
} }
} }
return meta_region_builder_finish (&builder);
} }
static void static void
@ -2131,7 +2134,7 @@ build_and_scan_frame_mask (MetaWindowActor *self,
if (priv->window->frame != NULL) 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 }; cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
/* Make sure we don't paint the frame over the client window. */ /* Make sure we don't paint the frame over the client window. */
@ -2144,7 +2147,9 @@ build_and_scan_frame_mask (MetaWindowActor *self,
install_corners (priv->window, borders, cr); install_corners (priv->window, borders, cr);
cairo_surface_flush (surface); 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); cairo_destroy (cr);

View File

@ -43,34 +43,17 @@
/* Optimium performance seems to be with MAX_CHUNK_RECTANGLES=4; 8 is about 10% slower. /* 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(). */ * But using 8 may be more robust to systems with slow malloc(). */
#define MAX_CHUNK_RECTANGLES 8 #define MAX_CHUNK_RECTANGLES 8
#define MAX_LEVELS 16
typedef struct void
{
/* 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
meta_region_builder_init (MetaRegionBuilder *builder) meta_region_builder_init (MetaRegionBuilder *builder)
{ {
int i; int i;
for (i = 0; i < MAX_LEVELS; i++) for (i = 0; i < META_REGION_BUILDER_MAX_LEVELS; i++)
builder->levels[i] = NULL; builder->levels[i] = NULL;
builder->n_levels = 1; builder->n_levels = 1;
} }
static void void
meta_region_builder_add_rectangle (MetaRegionBuilder *builder, meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
int x, int x,
int y, int y,
@ -95,7 +78,7 @@ meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
{ {
if (builder->levels[i] == NULL) if (builder->levels[i] == NULL)
{ {
if (i < MAX_LEVELS) if (i < META_REGION_BUILDER_MAX_LEVELS)
{ {
builder->levels[i] = builder->levels[i - 1]; builder->levels[i] = builder->levels[i - 1];
builder->levels[i - 1] = NULL; builder->levels[i - 1] = NULL;
@ -115,7 +98,7 @@ meta_region_builder_add_rectangle (MetaRegionBuilder *builder,
} }
} }
static cairo_region_t * cairo_region_t *
meta_region_builder_finish (MetaRegionBuilder *builder) meta_region_builder_finish (MetaRegionBuilder *builder)
{ {
cairo_region_t *result = NULL; cairo_region_t *result = NULL;

View File

@ -63,6 +63,32 @@ struct _MetaRegionIterator {
cairo_rectangle_int_t next_rectangle; cairo_rectangle_int_t next_rectangle;
}; };
typedef struct _MetaRegionBuilder MetaRegionBuilder;
#define META_REGION_BUILDER_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[META_REGION_BUILDER_MAX_LEVELS];
int n_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, void meta_region_iterator_init (MetaRegionIterator *iter,
cairo_region_t *region); cairo_region_t *region);
gboolean meta_region_iterator_at_end (MetaRegionIterator *iter); gboolean meta_region_iterator_at_end (MetaRegionIterator *iter);