[cairo] Special case pixman_rasterize_trapezoid() for boxes

Chris Wilson chris at chris-wilson.co.uk
Wed Aug 5 06:12:04 PDT 2009


Hi all,

I'd like some feedback on the sanity of adding a special case inside
pixman_rasterize_trapezoid() for the rectilinear condition. In
particular, guidance on handling the 1/8 bpp cases.
-ickle

>From 44065a33b4ea10c30173d5c5eeed924097175e28 Mon Sep 17 00:00:00 2001
From: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed, 5 Aug 2009 13:58:44 +0100
Subject: [PATCH] Special case rasterizing trapezoids with vertical
edges.

With the reorganisation of cairo to only use
pixman_rasterize_trapezoid() for rectilinear cases, the majority of all
trapezoids passed to pixman are now simple boxes. For these we can
skip edge walking and more simply reuse the same constants for each row.

Callgrinding firefox-20090601, shows a reduction of 58,993,651,031 to
52,599,458,809 instruction fetches. The inclusive cost of
pixman_rasterize_trapezoid() is reduced from 11.11% to 0.20%.
---
 pixman/Makefile.am            |    2 +
 pixman/pixman-box-accessors.c |    4 +
 pixman/pixman-box.c           |  251
+++++++++++++++++++++++++++++++++++++++++
 pixman/pixman-private.h       |   11 ++
 pixman/pixman-trap.c          |   58 +++++++---
 5 files changed, 308 insertions(+), 18 deletions(-)
 create mode 100644 pixman/pixman-box-accessors.c
 create mode 100644 pixman/pixman-box.c

diff --git a/pixman/Makefile.am b/pixman/Makefile.am
index e19fa6e..6a42060 100644
--- a/pixman/Makefile.am
+++ b/pixman/Makefile.am
@@ -7,6 +7,8 @@ libpixman_1_la_SOURCES =			\
 	pixman-accessor.h			\
 	pixman-access.c				\
 	pixman-access-accessors.c		\
+	pixman-box.c				\
+	pixman-box-accessors.c			\
 	pixman-cpu.c				\
 	pixman-gradient-walker.c		\
 	pixman-region16.c			\
diff --git a/pixman/pixman-box-accessors.c
b/pixman/pixman-box-accessors.c
new file mode 100644
index 0000000..72f6f9e
--- /dev/null
+++ b/pixman/pixman-box-accessors.c
@@ -0,0 +1,4 @@
+#define PIXMAN_FB_ACCESSORS
+
+#include "pixman-box.c"
+
diff --git a/pixman/pixman-box.c b/pixman/pixman-box.c
new file mode 100644
index 0000000..f7cf535
--- /dev/null
+++ b/pixman/pixman-box.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright © 2004 Keith Packard
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
and its
+ * documentation for any purpose is hereby granted without fee,
provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software
without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any
purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "pixman-private.h"
+#include "pixman-accessor.h"
+
+#ifdef PIXMAN_FB_ACCESSORS
+#define PIXMAN_RASTERIZE_BOX pixman_rasterize_box_accessors
+#else
+#define PIXMAN_RASTERIZE_BOX pixman_rasterize_box_no_accessors
+#endif
+
+/*
+ * 8 bit alpha
+ */
+
+static force_inline uint8_t
+clip255 (int x)
+{
+    if (x > 255)
+	return 255;
+
+    return x;
+}
+
+static void
+rasterize_box_8 (pixman_image_t *image,
+		 pixman_fixed_t  l,
+		 pixman_fixed_t  r,
+		 pixman_fixed_t  t,
+		 pixman_fixed_t  b)
+{
+    int stride = sizeof (uint32_t) * image->bits.rowstride;
+    uint8_t *ap;
+    int li, ri, ls, rs;
+    int ti, bi, ts, bs;
+    int x, y;
+
+    if (l < 0)
+	l = 0;
+
+    /* Use the last pixel of the scanline, covered 100%.
+     * We can't use the first pixel following the scanline,
+     * because accessing it could result in a buffer overrun.
+     */
+    if (pixman_fixed_to_int (r) >= image->bits.width)
+	r = pixman_int_to_fixed (image->bits.width) - 1;
+
+    if (r <= l)
+	return;
+
+    if (t < 0)
+	t = 0;
+
+    if (pixman_fixed_to_int (b) >= image->bits.height)
+	b = pixman_int_to_fixed (image->bits.height) - 1;
+
+    if (b <= t)
+	return;
+
+    /* Find pixel bounds for spans. */
+    li = pixman_fixed_to_int (l);
+    ri = pixman_fixed_to_int (r);
+
+    ti = pixman_fixed_to_int (t);
+    bi = pixman_fixed_to_int (b);
+
+    /* Sample coverage for edge pixels */
+    ls = RENDER_SAMPLES_X (l, 8);
+    rs = RENDER_SAMPLES_X (r, 8);
+
+    ts = RENDER_SAMPLES_Y (t, 8);
+    bs = RENDER_SAMPLES_Y (b, 8);
+
+    ap = (uint8_t *) image->bits.bits + ti * stride;
+
+    /* a box has 9 regions: the 4 corners, the 4 edges and everything
inside */
+    if (li == ri)
+    {
+	if (ti != bi)
+	{
+	    WRITE (image, ap + li,
+		   clip255 (READ (image, ap + li) + (rs - ls) * (N_Y_FRAC (8) -
ts)));
+	    ap += stride;
+
+	    for (y = ti + 1; y < bi; y++)
+	    {
+		WRITE (image, ap + li,
+		       clip255 (READ (image, ap + li) + (rs - ls) * N_Y_FRAC (8)));
+		ap += stride;
+	    }
+
+	    if (bs)
+	    {
+		WRITE (image, ap + li,
+		       clip255 (READ (image, ap + li) + (rs - ls) * bs));
+	    }
+	}
+	else
+	{
+	    WRITE (image, ap + li,
+		   clip255 (READ (image, ap + li) + (rs - ls) * (bs - ts)));
+	}
+    }
+    else
+    {
+	if (ti != bi)
+	{
+	    /* top edge */
+	    WRITE (image, ap + li,
+		   clip255 (READ (image, ap + li) + (N_X_FRAC (8) - ls) * (N_Y_FRAC
(8) - ts)));
+
+	    for (x = li + 1; x < ri; x++)
+	    {
+		WRITE (image, ap + x,
+		       clip255 (READ (image, ap + x) + N_X_FRAC (8) * (N_Y_FRAC (8) -
ts)));
+	    }
+
+	    if (rs) {
+		WRITE (image, ap + ri,
+		       clip255 (READ (image, ap + ri) + rs * (N_Y_FRAC (8) - ts)));
+	    }
+	    ap += stride;
+
+	    /* middle */
+	    for (y = ti + 1; y < bi; y++)
+	    {
+		WRITE (image, ap + li,
+		       clip255 (READ (image, ap + li) + (N_X_FRAC (8) - ls) *
N_Y_FRAC (8)));
+
+		MEMSET_WRAPPED (image, ap + li + 1, 0xff, ri - li - 1);
+
+		if (rs)
+		{
+		    WRITE (image, ap + ri,
+			   clip255 (READ (image, ap + ri) + rs * N_Y_FRAC (8)));
+		}
+		ap += stride;
+	    }
+
+	    /* bottom edge */
+	    if (bs)
+	    {
+		WRITE (image, ap + li,
+		       clip255 (READ (image, ap + li) + (N_X_FRAC (8) - ls) * bs));
+
+		for (x = li + 1; x < ri; x++)
+		{
+		    WRITE (image, ap + x,
+			   clip255 (READ (image, ap + x) + N_X_FRAC (8) * bs));
+		}
+
+		if (rs) {
+		    WRITE (image, ap + ri,
+			   clip255 (READ (image, ap + ri) + rs * bs));
+		}
+	    }
+	}
+	else
+	{
+	    WRITE (image, ap + li,
+		   clip255 (READ (image, ap + li) + (N_X_FRAC (8) - ls) * (bs -
ts)));
+
+	    for (x = li + 1; x < ri; x++)
+	    {
+		WRITE (image, ap + x,
+		       clip255 (READ (image, ap + x) + N_X_FRAC (8) * (bs - ts)));
+	    }
+
+	    if (rs)
+	    {
+		WRITE (image, ap + ri,
+		       clip255 (READ (image, ap + ri) + rs * (bs - ts)));
+	    }
+	}
+    }
+}
+
+#ifndef PIXMAN_FB_ACCESSORS
+static
+#endif
+void
+PIXMAN_RASTERIZE_BOX (pixman_image_t *image,
+		      pixman_fixed_t  l,
+		      pixman_fixed_t  r,
+		      pixman_fixed_t  t,
+		      pixman_fixed_t  b)
+{
+    switch (PIXMAN_FORMAT_BPP (image->bits.format))
+    {
+    case 1:
+	// rasterize_box_1 (image, l, r, t, b);
+	assert (0);
+	break;
+
+    case 4:
+	//rasterize_box_4 (image, l, r, t, b);
+	assert (0);
+	break;
+
+    case 8:
+	rasterize_box_8 (image, l, r, t, b);
+	break;
+    }
+}
+
+#ifndef PIXMAN_FB_ACCESSORS
+
+PIXMAN_EXPORT void
+pixman_rasterize_box (pixman_image_t *image,
+		      pixman_fixed_t  l,
+		      pixman_fixed_t  r,
+		      pixman_fixed_t  t,
+		      pixman_fixed_t  b)
+{
+    return_if_fail (image->type == BITS);
+    return_if_fail (PIXMAN_FORMAT_BPP (image->bits.format) == 8);
+
+    if (image->bits.read_func || image->bits.write_func)
+	pixman_rasterize_box_accessors (image, l, r, t, b);
+    else
+	pixman_rasterize_box_no_accessors (image, l, r, t, b);
+}
+
+#endif
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 8e62d57..79ffc00 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -350,6 +350,10 @@ _pixman_gradient_walker_pixel
(pixman_gradient_walker_t *walker,
     ((n) == 1? 0 : (pixman_fixed_frac (x) +				\
 		    X_FRAC_FIRST (n)) / STEP_X_SMALL (n))
 
+#define RENDER_SAMPLES_Y(y, n)						\
+    ((n) == 1? 0 : (pixman_fixed_frac (y) +				\
+		    Y_FRAC_FIRST (n)) / STEP_Y_SMALL (n))
+
 void
 pixman_rasterize_edges_accessors (pixman_image_t *image,
                                   pixman_edge_t * l,
@@ -357,6 +361,13 @@ pixman_rasterize_edges_accessors (pixman_image_t
*image,
                                   pixman_fixed_t  t,
                                   pixman_fixed_t  b);
 
+void
+pixman_rasterize_box_accessors (pixman_image_t *image,
+				pixman_fixed_t  l,
+				pixman_fixed_t  r,
+				pixman_fixed_t  t,
+				pixman_fixed_t  b);
+
 /*
  * Implementations
  */
diff --git a/pixman/pixman-trap.c b/pixman/pixman-trap.c
index 4d7a90a..1a641fd 100644
--- a/pixman/pixman-trap.c
+++ b/pixman/pixman-trap.c
@@ -264,20 +264,31 @@ pixman_add_traps (pixman_image_t * image,
 
 	if (b >= t)
 	{
-	    /* initialize edge walkers */
-	    pixman_edge_init (&l, bpp, t,
-	                      traps->top.l + x_off_fixed,
-	                      traps->top.y + y_off_fixed,
-	                      traps->bot.l + x_off_fixed,
-	                      traps->bot.y + y_off_fixed);
-
-	    pixman_edge_init (&r, bpp, t,
-	                      traps->top.r + x_off_fixed,
-	                      traps->top.y + y_off_fixed,
-	                      traps->bot.r + x_off_fixed,
-	                      traps->bot.y + y_off_fixed);
-
-	    pixman_rasterize_edges (image, &l, &r, t, b);
+	    if (traps->top.l == traps->bot.l &&
+		traps->bot.r == traps->bot.r)
+	    {
+		pixman_rasterize_box (image,
+				      traps->top.l + x_off_fixed,
+				      traps->top.r + x_off_fixed,
+				      t, b);
+	    }
+	    else
+	    {
+		/* initialize edge walkers */
+		pixman_edge_init (&l, bpp, t,
+				  traps->top.l + x_off_fixed,
+				  traps->top.y + y_off_fixed,
+				  traps->bot.l + x_off_fixed,
+				  traps->bot.y + y_off_fixed);
+
+		pixman_edge_init (&r, bpp, t,
+				  traps->top.r + x_off_fixed,
+				  traps->top.y + y_off_fixed,
+				  traps->bot.r + x_off_fixed,
+				  traps->bot.y + y_off_fixed);
+
+		pixman_rasterize_edges (image, &l, &r, t, b);
+	    }
 	}
 
 	traps++;
@@ -379,10 +390,21 @@ pixman_rasterize_trapezoid (pixman_image_t *
image,
 
     if (b >= t)
     {
-	/* initialize edge walkers */
-	pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
-	pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
+	if (trap->left.p1.x == trap->left.p2.x &&
+	    trap->right.p1.x == trap->right.p2.x)
+	{
+	    pixman_rasterize_box (image,
+				  trap->left.p1.x + x_off_fixed,
+				  trap->right.p2.x + x_off_fixed,
+				  t, b);
+	}
+	else
+	{
+	    /* initialize edge walkers */
+	    pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off,
y_off);
+	    pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off,
y_off);
 
-	pixman_rasterize_edges (image, &l, &r, t, b);
+	    pixman_rasterize_edges (image, &l, &r, t, b);
+	}
     }
 }
-- 
1.6.3.3





More information about the cairo mailing list