[cairo] Another Gradient rendering speedup patch
David Turner
david at freetype.org
Thu Feb 1 00:30:20 PST 2007
Hello,
here's a small patch that speeds up gradient rendering in the very common case
where all color stops are opaque. We simply avoid performing un-needed
alpha pre-multiplications :-)
cairo-perf-diff indicates, in the image backend, a 1.56 speedup for linear gradients,
and a 1.15 one for radial ones.
it also fixes a small bug in cairo-perf-diff that prevented it to work properly
when trying to compare perf files directly on my workstation.
Enjoy,
- David Turner
-------------- next part --------------
From b8cdb62c0a63e2f2ac843eecb0c673038380be89 Mon Sep 17 00:00:00 2001
From: David Turner <david at freetype.org>
Date: Thu, 1 Feb 2007 09:17:43 +0100
Subject: [PATCH] optimize the gradient fill for the case where all color stops are opaque,
cairo-perf-diff indicates a 1.56 speedup for linear gradients, and a 1.15 one for radial ones in the image backend
---
perf/cairo-perf-diff | 5 ++
pixman/src/fbcompose.c | 120 +++++++++++++++++++++++++++++++++++++++---------
2 files changed, 102 insertions(+), 23 deletions(-)
diff --git a/perf/cairo-perf-diff b/perf/cairo-perf-diff
index f873917..7228697 100755
--- a/perf/cairo-perf-diff
+++ b/perf/cairo-perf-diff
@@ -71,6 +71,9 @@ git_setup() {
SUBDIRECTORY_OK='Yes'
. git-sh-setup
CAIRO_DIR=$(dirname $GIT_DIR)
+ if [ "x$CAIRO_DIR" = "x" ]; then
+ CAIRO_DIR="."
+ fi
if [ "$CAIRO_DIR" = "." ]; then
CAIRO_DIR=$(pwd)
fi
@@ -152,6 +155,8 @@ run_cairo_perf_if_not_cached() {
cd $owd
}
+git_setup
+
if [ ! -e $old ]; then
git_setup
run_cairo_perf_if_not_cached $old old
diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c
index d698eb4..68a7cb3 100644
--- a/pixman/src/fbcompose.c
+++ b/pixman/src/fbcompose.c
@@ -2744,6 +2744,7 @@ typedef struct
pixman_gradient_stop_t *stops;
int num_stops;
+ int all_opaque; /* TRUE if all stops have opaque colors */
unsigned int spread;
} GradientWalker;
@@ -2763,6 +2764,24 @@ _gradient_walker_init (GradientWalker *
walker->right_ag = 0;
walker->right_rb = 0;
walker->spread = spread;
+
+ /* now check wether all stop colors are opaque or not
+ * if they are, we'll use a slightly optimized version of
+ * _gradient_walker_pixel that doesn't do any pre-multiplications
+ */
+ {
+ int nn;
+ int all_opaque = 1;
+
+ for (nn = 0; nn < walker->num_stops; nn++) {
+ if ( (walker->stops[nn].color.alpha >> 8) != 0xFF )
+ {
+ all_opaque = 0;
+ break;
+ }
+ }
+ walker->all_opaque = all_opaque;
+ }
}
static void
@@ -2948,6 +2967,29 @@ _gradient_walker_pixel (GradientWalker
}
+static CARD32
+_gradient_walker_pixel_opaque (GradientWalker *walker,
+ xFixed_32_32 x)
+{
+ int dist, idist;
+ uint32_t t1, t2;
+
+ if (GRADIENT_WALKER_NEED_RESET (walker, x))
+ _gradient_walker_reset (walker, x);
+
+ dist = ((int)(x - walker->left_x)*walker->stepper) >> 16;
+ idist = 256 - dist;
+
+ /* combined INTERPOLATE and premultiply */
+ t1 = walker->left_rb*idist + walker->right_rb*dist;
+ t1 = (t1 >> 8) & 0xff00ff;
+
+ t2 = walker->left_ag*idist + walker->right_ag*dist;
+ t2 &= 0xff00ff00;
+
+ return (t1 | t2);
+}
+
static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits)
{
@@ -3013,11 +3055,20 @@ static void fbFetchSourcePict(PicturePtr
else
{
if (!mask) {
- while (buffer < end)
- {
- *buffer = _gradient_walker_pixel (&walker, t);
- buffer += 1;
- t += inc;
+ if ( walker.all_opaque ) {
+ while (buffer < end)
+ {
+ *buffer = _gradient_walker_pixel_opaque (&walker, t);
+ buffer += 1;
+ t += inc;
+ }
+ }else {
+ while (buffer < end)
+ {
+ *buffer = _gradient_walker_pixel (&walker, t);
+ buffer += 1;
+ t += inc;
+ }
}
} else {
while (buffer < end) {
@@ -3112,25 +3163,48 @@ static void fbFetchSourcePict(PicturePtr
rx -= pGradient->radial.fx;
ry -= pGradient->radial.fy;
- while (buffer < end) {
- double b, c, det, s;
-
- if (!mask || *mask++ & maskBits)
- {
- xFixed_48_16 t;
-
- b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
- c = -(rx*rx + ry*ry);
- det = (b * b) - (4 * pGradient->radial.a * c);
- s = (-b + sqrt(det))/(2. * pGradient->radial.a);
-
- t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
-
- *buffer = _gradient_walker_pixel (&walker, t);
+ if (walker.all_opaque) {
+ while (buffer < end) {
+ double b, c, det, s;
+
+ if (!mask || *mask++ & maskBits)
+ {
+ xFixed_48_16 t;
+
+ b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
+ c = -(rx*rx + ry*ry);
+ det = (b * b) - (4 * pGradient->radial.a * c);
+ s = (-b + sqrt(det))/(2. * pGradient->radial.a);
+
+ t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
+
+ *buffer = _gradient_walker_pixel_opaque (&walker, t);
+ }
+ ++buffer;
+ rx += cx;
+ ry += cy;
+ }
+ } else {
+ while (buffer < end) {
+ double b, c, det, s;
+
+ if (!mask || *mask++ & maskBits)
+ {
+ xFixed_48_16 t;
+
+ b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
+ c = -(rx*rx + ry*ry);
+ det = (b * b) - (4 * pGradient->radial.a * c);
+ s = (-b + sqrt(det))/(2. * pGradient->radial.a);
+
+ t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
+
+ *buffer = _gradient_walker_pixel (&walker, t);
+ }
+ ++buffer;
+ rx += cx;
+ ry += cy;
}
- ++buffer;
- rx += cx;
- ry += cy;
}
} else {
while (buffer < end) {
--
1.4.1
More information about the cairo
mailing list