From 934c9d8546b71ddea91ac16b0928101903e2608e Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=B8ren=20Sandmann=20Pedersen?= Date: Mon, 28 May 2012 02:36:22 -0400 Subject: [PATCH] Speed up _pixman_composite_glyphs_no_mask() Bypass much of the overhead of pixman_image_composite32() by only computing the composite region once instead of once per glyph, and by only looking up the composite function whenever the glyph format or flags change. As part of this, the pixman_compute_composite_region32() was renamed to _pixman_compute_composite_region32() and exported in pixman-private.h. I couldn't find a trace that would reliably demonstrate that this is actually an improvement by itself (since _pixman_composite_glyphs_no_mask() is called so rarely), but together with the following optimization for solid sources, there is a small but reliable improvement to the xfce4-a1-terminal cairo trace. --- pixman/pixman-glyph.c | 91 ++++++++++++++++++++++++++++++++++++++++++++----- pixman/pixman-private.h | 13 +++++++ pixman/pixman.c | 30 ++++++++-------- 3 files changed, 111 insertions(+), 23 deletions(-) diff --git a/pixman/pixman-glyph.c b/pixman/pixman-glyph.c index 186ef47..921eff1 100644 --- a/pixman/pixman-glyph.c +++ b/pixman/pixman-glyph.c @@ -399,24 +399,99 @@ pixman_composite_glyphs_no_mask (pixman_op_t op, int n_glyphs, pixman_glyph_t *glyphs) { + pixman_region32_t region; + pixman_format_code_t glyph_format = PIXMAN_null; + uint32_t glyph_flags = 0; + pixman_format_code_t dest_format; + uint32_t dest_flags; + pixman_composite_func_t func = NULL; + pixman_implementation_t *implementation = NULL; + pixman_composite_info_t info; int i; + _pixman_image_validate (src); + _pixman_image_validate (dest); + + dest_format = dest->common.extended_format_code; + dest_flags = dest->common.flags; + + pixman_region32_init (®ion); + if (!_pixman_compute_composite_region32 ( + ®ion, + src, NULL, dest, + src_x - dest_x, src_y - dest_y, 0, 0, 0, 0, + dest->bits.width, dest->bits.height)) + { + goto out; + } + + info.op = op; + info.src_image = src; + info.dest_image = dest; + info.src_flags = src->common.flags; + info.dest_flags = dest->common.flags; + for (i = 0; i < n_glyphs; ++i) { glyph_t *glyph = (glyph_t *)glyphs[i].glyph; pixman_image_t *glyph_img = glyph->image; + pixman_box32_t glyph_box; + pixman_box32_t *pbox; + uint32_t extra = FAST_PATH_SAMPLES_COVER_CLIP_NEAREST; + pixman_box32_t composite_box; + int n; - pixman_image_composite32 (op, src, glyph_img, dest, - src_x + glyphs[i].x - glyph->origin_x, - src_y + glyphs[i].y - glyph->origin_y, - 0, 0, - dest_x + glyphs[i].x - glyph->origin_x, - dest_y + glyphs[i].y - glyph->origin_y, - glyph_img->bits.width, - glyph_img->bits.height); + glyph_box.x1 = dest_x + glyphs[i].x - glyph->origin_x; + glyph_box.y1 = dest_y + glyphs[i].y - glyph->origin_y; + glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width; + glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height; + + pbox = pixman_region32_rectangles (®ion, &n); + + info.mask_image = glyph_img; + + while (n--) + { + if (box32_intersect (&composite_box, pbox, &glyph_box)) + { + if (glyph_img->common.extended_format_code != glyph_format || + glyph_img->common.flags != glyph_flags) + { + glyph_format = glyph_img->common.extended_format_code; + glyph_flags = glyph_img->common.flags; + + _pixman_lookup_composite_function ( + get_implementation(), op, + src->common.extended_format_code, src->common.flags, + glyph_format, glyph_flags | extra, + dest_format, dest_flags, + &implementation, &func); + + if (!func) + goto out; + } + + info.src_x = src_x + composite_box.x1 - dest_x; + info.src_y = src_y + composite_box.y1 - dest_y; + info.mask_x = composite_box.x1 - (dest_x + glyphs[i].x - glyph->origin_x); + info.mask_y = composite_box.y1 - (dest_y + glyphs[i].y - glyph->origin_y); + info.dest_x = composite_box.x1; + info.dest_y = composite_box.y1; + info.width = composite_box.x2 - composite_box.x1; + info.height = composite_box.y2 - composite_box.y1; + + info.mask_flags = glyph_flags; + + func (implementation, &info); + } + pbox++; + } pixman_list_move_to_front (&cache->mru, &glyph->mru_link); } + +out: + pixman_region32_fini (®ion); } static void diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index 8323426..873f321 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -581,6 +581,19 @@ _pixman_choose_implementation (void); /* * Utilities */ +pixman_bool_t +_pixman_compute_composite_region32 (pixman_region32_t * region, + pixman_image_t * src_image, + pixman_image_t * mask_image, + pixman_image_t * dest_image, + int32_t src_x, + int32_t src_y, + int32_t mask_x, + int32_t mask_y, + int32_t dest_x, + int32_t dest_y, + int32_t width, + int32_t height); uint32_t * _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask); diff --git a/pixman/pixman.c b/pixman/pixman.c index 7d841d3..0137c3c 100644 --- a/pixman/pixman.c +++ b/pixman/pixman.c @@ -224,19 +224,19 @@ clip_source_image (pixman_region32_t * region, * returns FALSE if the final region is empty. Indistinguishable from * an allocation failure, but rendering ignores those anyways. */ -static pixman_bool_t -pixman_compute_composite_region32 (pixman_region32_t * region, - pixman_image_t * src_image, - pixman_image_t * mask_image, - pixman_image_t * dest_image, - int32_t src_x, - int32_t src_y, - int32_t mask_x, - int32_t mask_y, - int32_t dest_x, - int32_t dest_y, - int32_t width, - int32_t height) +pixman_bool_t +_pixman_compute_composite_region32 (pixman_region32_t * region, + pixman_image_t * src_image, + pixman_image_t * mask_image, + pixman_image_t * dest_image, + int32_t src_x, + int32_t src_y, + int32_t mask_x, + int32_t mask_y, + int32_t dest_x, + int32_t dest_y, + int32_t width, + int32_t height) { region->extents.x1 = dest_x; region->extents.x2 = dest_x + width; @@ -615,7 +615,7 @@ pixman_image_composite32 (pixman_op_t op, pixman_region32_init (®ion); - if (!pixman_compute_composite_region32 ( + if (!_pixman_compute_composite_region32 ( ®ion, src, mask, dest, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height)) { @@ -1114,7 +1114,7 @@ pixman_compute_composite_region (pixman_region16_t * region, pixman_region32_init (&r32); - retval = pixman_compute_composite_region32 ( + retval = _pixman_compute_composite_region32 ( &r32, src_image, mask_image, dest_image, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height); -- 2.7.4