[Pixman] [PATCH v2 6/8] Speed up pixman_composite_glyphs()

Søren Sandmann sandmann at cs.au.dk
Sat Jun 2 06:23:55 PDT 2012


From: Søren Sandmann Pedersen <ssp at redhat.com>

When adding glyphs to the mask, bypass most of the overhead of
pixman_image_composite32() by:

- Only looking up the composite function when the glyph changes either
  format or flags.

- Only using a white source when the glyph format is different from
  the mask format.

- Simply intersecting the glyph rectangle with the destination
  rectangle instead of doing the full _pixman_composite_region32().

Performance results:

[ # ]  backend                         test   min(s) median(s) stddev. count
Before:
[  0]    image            firefox-talos-gfx    6.570    6.577   0.13%    8/10
After:
[  0]    image            firefox-talos-gfx    4.272    4.289   0.28%   10/10

V2: Changes to deal with white sources
---
 pixman/pixman-glyph.c   |  157 ++++++++++++++++++++++++++++++++++++++++-------
 pixman/pixman-private.h |   12 ++++
 pixman/pixman.c         |   12 +---
 3 files changed, 149 insertions(+), 32 deletions(-)

diff --git a/pixman/pixman-glyph.c b/pixman/pixman-glyph.c
index 30acc36..186ef47 100644
--- a/pixman/pixman-glyph.c
+++ b/pixman/pixman-glyph.c
@@ -374,6 +374,19 @@ pixman_glyph_get_mask_format (pixman_glyph_cache_t *cache,
     return format;
 }
 
+static pixman_bool_t
+box32_intersect (pixman_box32_t *dest,
+		 const pixman_box32_t *box1,
+		 const pixman_box32_t *box2)
+{
+    dest->x1 = MAX (box1->x1, box2->x1);
+    dest->y1 = MAX (box1->y1, box2->y1);
+    dest->x2 = MIN (box1->x2, box2->x2);
+    dest->y2 = MIN (box1->y2, box2->y2);
+
+    return dest->x2 > dest->x1 && dest->y2 > dest->y1;
+}
+
 PIXMAN_EXPORT void
 pixman_composite_glyphs_no_mask (pixman_op_t            op,
 				 pixman_image_t        *src,
@@ -406,6 +419,128 @@ pixman_composite_glyphs_no_mask (pixman_op_t            op,
     }
 }
 
+static void
+add_glyphs (pixman_glyph_cache_t *cache,
+	    pixman_image_t *dest,
+	    int off_x, int off_y,
+	    int n_glyphs, pixman_glyph_t *glyphs)
+{
+    pixman_format_code_t glyph_format = PIXMAN_null;
+    uint32_t glyph_flags = 0;
+    pixman_composite_func_t func = NULL;
+    pixman_implementation_t *implementation = NULL;
+    uint32_t dest_format;
+    uint32_t dest_flags;
+    pixman_box32_t dest_box;
+    pixman_composite_info_t info;
+    pixman_image_t *white_img = NULL;
+    pixman_bool_t white_src = FALSE;
+    int i;
+
+    _pixman_image_validate (dest);
+
+    dest_format = dest->common.extended_format_code;
+    dest_flags = dest->common.flags;
+
+    info.op = PIXMAN_OP_ADD;
+    info.dest_image = dest;
+    info.src_x = 0;
+    info.src_y = 0;
+    info.dest_flags = dest_flags;
+
+    dest_box.x1 = 0;
+    dest_box.y1 = 0;
+    dest_box.x2 = dest->bits.width;
+    dest_box.y2 = dest->bits.height;
+
+    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 composite_box;
+
+	if (glyph_img->common.extended_format_code != glyph_format	||
+	    glyph_img->common.flags != glyph_flags)
+	{
+	    pixman_format_code_t src_format, mask_format;
+
+	    glyph_format = glyph_img->common.extended_format_code;
+	    glyph_flags = glyph_img->common.flags;
+
+	    if (glyph_format == dest->bits.format)
+	    {
+		src_format = glyph_format;
+		mask_format = PIXMAN_null;
+		info.src_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
+		info.mask_flags = FAST_PATH_IS_OPAQUE;
+		info.mask_image = NULL;
+		white_src = FALSE;
+	    }
+	    else
+	    {
+		if (!white_img)
+		{
+		    pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
+
+		    if (!(white_img = pixman_image_create_solid_fill (&white)))
+			goto out;
+
+		    _pixman_image_validate (white_img);
+		}
+
+		src_format = PIXMAN_solid;
+		mask_format = glyph_format;
+		info.src_flags = white_img->common.flags;
+		info.mask_flags = glyph_flags | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
+		info.src_image = white_img;
+		white_src = TRUE;
+	    }
+
+	    _pixman_lookup_composite_function (
+		get_implementation(), PIXMAN_OP_ADD,
+		src_format, info.src_flags,
+		mask_format, info.mask_flags,
+		dest_format, dest_flags,
+		&implementation, &func);
+
+	    if (!func)
+		goto out;
+	}
+
+	glyph_box.x1 = glyphs[i].x - glyph->origin_x + off_x;
+	glyph_box.y1 = glyphs[i].y - glyph->origin_y + off_y;
+	glyph_box.x2 = glyph_box.x1 + glyph->image->bits.width;
+	glyph_box.y2 = glyph_box.y1 + glyph->image->bits.height;
+	
+	if (box32_intersect (&composite_box, &glyph_box, &dest_box))
+	{
+	    int src_x = composite_box.x1 - glyph_box.x1;
+	    int src_y = composite_box.y1 - glyph_box.y1;
+
+	    if (white_src)
+		info.mask_image = glyph_img;
+	    else
+		info.src_image = glyph_img;
+
+	    info.mask_x = info.src_x = src_x;
+	    info.mask_y = info.src_y = src_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;
+
+	    func (implementation, &info);
+
+	    pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
+	}
+    }
+
+out:
+    if (white_img)
+	pixman_image_unref (white_img);
+}
+
 /* Conceptually, for each glyph, (white IN glyph) is PIXMAN_OP_ADDed to an
  * infinitely big mask image at the position such that the glyph origin point
  * is positioned at the (glyphs[i].x, glyphs[i].y) point.
@@ -439,37 +574,18 @@ pixman_composite_glyphs (pixman_op_t            op,
 			 int			n_glyphs,
 			 pixman_glyph_t        *glyphs)
 {
-    pixman_color_t white_color = { 0xffff, 0xffff, 0xffff, 0xffff };
-    pixman_image_t *white;
     pixman_image_t *mask;
-    int i;
 
     if (!(mask = pixman_image_create_bits (mask_format, width, height, NULL, -1)))
 	return;
 
-    if (!(white = pixman_image_create_solid_fill (&white_color)))
-	goto out;
-
     if (PIXMAN_FORMAT_A   (mask_format) != 0 &&
 	PIXMAN_FORMAT_RGB (mask_format) != 0)
     {
 	pixman_image_set_component_alpha (mask, TRUE);
     }
 
-    for (i = 0; i < n_glyphs; ++i)
-    {
-	glyph_t *glyph = (glyph_t *)glyphs[i].glyph;
-	pixman_image_t *glyph_img = glyph->image;
-
-	pixman_image_composite32 (PIXMAN_OP_ADD, white, glyph_img, mask,
-				  0, 0, 0, 0,
-				  glyphs[i].x - glyph->origin_x - mask_x,
-				  glyphs[i].y - glyph->origin_y - mask_y,
-				  glyph->image->bits.width,
-				  glyph->image->bits.height);
-
-	pixman_list_move_to_front (&cache->mru, &glyph->mru_link);
-    }
+    add_glyphs (cache, mask, - mask_x, - mask_y, n_glyphs, glyphs);
 
     pixman_image_composite32 (op, src, mask, dest,
 			      src_x, src_y,
@@ -477,6 +593,5 @@ pixman_composite_glyphs (pixman_op_t            op,
 			      dest_x, dest_y,
 			      width, height);
 
-out:
     pixman_image_unref (mask);
 }
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 76d65e2..8323426 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -688,6 +688,18 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 	    dest, FAST_PATH_STD_DEST_FLAGS,				\
 	    func) }
 
+extern pixman_implementation_t *global_implementation;
+
+static force_inline pixman_implementation_t *
+get_implementation (void)
+{
+#ifndef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
+    if (!global_implementation)
+	global_implementation = _pixman_choose_implementation ();
+#endif
+    return global_implementation;
+}
+
 /* Memory allocation helpers */
 void *
 pixman_malloc_ab (unsigned int n, unsigned int b);
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 8fb5356..7d841d3 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -30,7 +30,7 @@
 
 #include <stdlib.h>
 
-static pixman_implementation_t *global_implementation;
+pixman_implementation_t *global_implementation;
 
 #ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
 static void __attribute__((constructor))
@@ -40,16 +40,6 @@ pixman_constructor (void)
 }
 #endif
 
-static force_inline pixman_implementation_t *
-get_implementation (void)
-{
-#ifndef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
-    if (!global_implementation)
-	global_implementation = _pixman_choose_implementation ();
-#endif
-    return global_implementation;
-}
-
 typedef struct operator_info_t operator_info_t;
 
 struct operator_info_t
-- 
1.7.10.2



More information about the Pixman mailing list