diff options
author | David Turner <david@alice.localdomain> | 2006-12-14 06:55:58 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-12-14 09:27:45 -0800 |
commit | e9bef30d2bcdf41c7b7f20b3517839c37e752f75 (patch) | |
tree | d13cb712d4048ee1c2faa334c3007d3dd0dd24c4 | |
parent | af9cce6aa295327b5256f55900b3debf9112b6ca (diff) |
Optimize gradient computations
We update the test suite reference images where needed, (pdiff
avoided a few, but most still needed updating). We take advantage
of the need for new reference images to shrink some of the giant
tests to speed them up a bit.
This optimization provides a 2x improvement in linear gradient
generation performance (numbers from an x86 laptop):
image-rgb paint_linear_rgba_source-512 26.13 -> 11.13: 2.35x speedup
█▍
image-rgb paint_linear_rgba_source-256 6.47 -> 2.76: 2.34x speedup
█▍
image-rgba paint_linear_rgb_over-256 6.51 -> 2.86: 2.28x speedup
█▎
image-rgb paint_linear_rgba_over-512 28.62 -> 13.70: 2.09x speedup
█▏
image-rgba fill_linear_rgb_over-256 3.24 -> 1.94: 1.66x speedup
▋
image-rgb stroke_linear_rgba_over-256 5.68 -> 4.10: 1.39x speedup
▍
24 files changed, 316 insertions, 145 deletions
diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 49582416..d698eb4e 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -2731,78 +2731,231 @@ static void fbFetch(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CA #define DIV(a,b) ((((a) < 0) == ((b) < 0)) ? (a) / (b) :\ ((a) - (b) + 1 - (((b) < 0) << 1)) / (b)) -static CARD32 -xRenderColorMultToCard32 (pixman_color_t *c) -{ - return - ((((uint32_t) c->red * c->alpha) >> 24) << 16) | - ((((uint32_t) c->green * c->alpha) >> 24) << 8) | - ((((uint32_t) c->blue * c->alpha) >> 24) << 0) | - ((((uint32_t) c->alpha ) >> 8) << 24); +typedef struct +{ + CARD32 left_ag; + CARD32 left_rb; + CARD32 right_ag; + CARD32 right_rb; + int32_t left_x; + int32_t right_x; + int32_t width_x; + int32_t stepper; + + pixman_gradient_stop_t *stops; + int num_stops; + unsigned int spread; +} GradientWalker; + +static void +_gradient_walker_init (GradientWalker *walker, + SourcePictPtr pGradient, + unsigned int spread) +{ + walker->num_stops = pGradient->gradient.nstops; + walker->stops = pGradient->gradient.stops; + walker->left_x = 0; + walker->right_x = 0x10000; + walker->width_x = 0; /* will force a reset */ + walker->stepper = 0; + walker->left_ag = 0; + walker->left_rb = 0; + walker->right_ag = 0; + walker->right_rb = 0; + walker->spread = spread; } -static CARD32 gradientPixel(const SourcePictPtr pGradient, xFixed_48_16 pos, unsigned int spread) +static void +_gradient_walker_reset (GradientWalker *walker, + xFixed_32_32 pos) { - int ipos = (pos * pGradient->gradient.stopRange - 1) >> 16; + int32_t x, left_x, right_x; + pixman_color_t *left_c, *right_c; + int n, count = walker->num_stops; + pixman_gradient_stop_t *stops = walker->stops; + + static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; - /* calculate the actual offset. */ - if (ipos < 0 || ipos >= pGradient->gradient.stopRange) + switch (walker->spread) { - if (pGradient->type == SourcePictTypeConical || spread == RepeatNormal) - { - ipos = ipos % pGradient->gradient.stopRange; - ipos = ipos < 0 ? pGradient->gradient.stopRange + ipos : ipos; + case RepeatNormal: + x = (int32_t)pos & 0xFFFF; + for (n = 0; n < count; n++) + if (x < stops[n].x) + break; + if (n == 0) { + left_x = stops[count-1].x - 0x10000; + left_c = &stops[count-1].color; + } else { + left_x = stops[n-1].x; + left_c = &stops[n-1].color; + } + if (n == count) { + right_x = stops[0].x + 0x10000; + right_c = &stops[0].color; + } else { + right_x = stops[n].x; + right_c = &stops[n].color; } - else if (spread == RepeatReflect) - { - const int limit = pGradient->gradient.stopRange * 2 - 1; + left_x += (pos - x); + right_x += (pos - x); + break; + + case RepeatPad: + for (n = 0; n < count; n++) + if (pos < stops[n].x) + break; + + if (n == 0) { + left_x = INT_MIN; + left_c = &stops[0].color; + } else { + left_x = stops[n-1].x; + left_c = &stops[n-1].color; + } + + if (n == count) { + right_x = INT_MAX; + right_c = &stops[n-1].color; + } else { + right_x = stops[n].x; + right_c = &stops[n].color; + } + break; + + case RepeatReflect: + x = (int32_t)pos & 0xFFFF; + if ((int32_t)pos & 0x10000) + x = 0x10000 - x; + for (n = 0; n < count; n++) + if (x < stops[n].x) + break; + + if (n == 0) { + left_x = -stops[0].x; + left_c = &stops[0].color; + } else { + left_x = stops[n-1].x; + left_c = &stops[n-1].color; + } + + if (n == count) { + right_x = 0x20000 - stops[n-1].x; + right_c = &stops[n-1].color; + } else { + right_x = stops[n].x; + right_c = &stops[n].color; + } + + if ((int32_t)pos & 0x10000) { + pixman_color_t *tmp_c; + int32_t tmp_x; + + tmp_x = 0x20000 - right_x; + right_x = 0x20000 - left_x; + left_x = tmp_x; + + tmp_c = right_c; + right_c = left_c; + left_c = tmp_c; + } + left_x += (pos - x); + right_x += (pos - x); + break; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= pGradient->gradient.stopRange ? limit - ipos : ipos; + default: /* RepeatNone */ + for (n = 0; n < count; n++) + if (pos < stops[n].x) + break; + if (n == 0) + { + left_x = INT_MIN; + right_x = stops[0].x; + left_c = right_c = (pixman_color_t*) &transparent_black; } - else if (spread == RepeatPad) + else if (n == count) { - if (ipos < 0) - ipos = 0; - else - ipos = pGradient->gradient.stopRange - 1; + left_x = stops[n-1].x; + right_x = INT_MAX; + left_c = right_c = (pixman_color_t*) &transparent_black; } - else /* RepeatNone */ + else { - return 0; + left_x = stops[n-1].x; + right_x = stops[n].x; + left_c = &stops[n-1].color; + right_c = &stops[n].color; } } - if (pGradient->gradient.colorTableSize) + walker->left_x = left_x; + walker->right_x = right_x; + walker->width_x = right_x - left_x; + walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8); + walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8); + walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8); + walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8); + + if ( walker->width_x == 0 || + ( walker->left_ag == walker->right_ag && + walker->left_rb == walker->right_rb ) ) { - return pGradient->gradient.colorTable[ipos]; + walker->width_x = 1; + walker->stepper = 0; } else { - int i; + walker->stepper = ((1 << 24) + walker->width_x/2)/walker->width_x; + } +} - if (ipos <= pGradient->gradient.stops->x) - return xRenderColorMultToCard32 (&pGradient->gradient.stops->color); +#define GRADIENT_WALKER_NEED_RESET(w,x) \ + ( (x) < (w)->left_x || (x) - (w)->left_x >= (w)->width_x ) - for (i = 1; i < pGradient->gradient.nstops; i++) - { - if (pGradient->gradient.stops[i].x >= ipos) - return PictureGradientColor (&pGradient->gradient.stops[i - 1], - &pGradient->gradient.stops[i], - ipos); - } +/* the following assumes that GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */ +static CARD32 +_gradient_walker_pixel (GradientWalker *walker, + xFixed_32_32 x) +{ + int dist, idist; + uint32_t t1, t2, a, color; - return xRenderColorMultToCard32 (&pGradient->gradient.stops[--i].color); - } + 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; + + color = t2 & 0xff000000; + a = t2 >> 24; + + t1 = t1*a + 0x800080; + t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8; + + t2 = (t2 >> 8)*a + 0x800080; + t2 = (t2 + ((t2 >> 8) & 0xff00ff)); + + return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); } + + static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits) { - SourcePictPtr pGradient = pict->pSourcePict; - CARD32 *end = buffer + width; + SourcePictPtr pGradient = pict->pSourcePict; + GradientWalker walker; + CARD32 *end = buffer + width; + + _gradient_walker_init (&walker, pGradient, pict->repeat); if (pGradient->type == SourcePictTypeSolidFill) { register CARD32 color = pGradient->solidFill.color; @@ -2853,20 +3006,29 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * { register CARD32 color; - color = gradientPixel (pGradient, t, pict->repeat); + color = _gradient_walker_pixel( &walker, t ); while (buffer < end) *buffer++ = color; } else { - while (buffer < end) { - if (!mask || *mask++ & maskBits) - { - *buffer = gradientPixel (pGradient, t, pict->repeat); - } - ++buffer; - t += inc; - } + if (!mask) { + while (buffer < end) + { + *buffer = _gradient_walker_pixel (&walker, t); + buffer += 1; + t += inc; + } + } else { + while (buffer < end) { + if (*mask++ & maskBits) + { + *buffer = _gradient_walker_pixel (&walker, t); + } + buffer += 1; + t += inc; + } + } } } else /* projective transformation */ @@ -2890,31 +3052,31 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * t = ((a * x + b * y) >> 16) + off; } - color = gradientPixel (pGradient, t, pict->repeat); + color = _gradient_walker_pixel( &walker, t ); while (buffer < end) *buffer++ = color; } else { - while (buffer < end) - { - if (!mask || *mask++ & maskBits) - { - if (v.vector[2] == 0) { - t = 0; - } else { - xFixed_48_16 x, y; - x = ((xFixed_48_16)v.vector[0] << 16) / v.vector[2]; - y = ((xFixed_48_16)v.vector[1] << 16) / v.vector[2]; - t = ((a*x + b*y) >> 16) + off; - } - *buffer = gradientPixel(pGradient, t, pict->repeat); - } - ++buffer; - v.vector[0] += unit.vector[0]; - v.vector[1] += unit.vector[1]; - v.vector[2] += unit.vector[2]; - } + while (buffer < end) + { + if (!mask || *mask++ & maskBits) + { + if (v.vector[2] == 0) { + t = 0; + } else { + xFixed_48_16 x, y; + x = ((xFixed_48_16)v.vector[0] << 16) / v.vector[2]; + y = ((xFixed_48_16)v.vector[1] << 16) / v.vector[2]; + t = ((a*x + b*y) >> 16) + off; + } + *buffer = _gradient_walker_pixel (&walker, t); + } + ++buffer; + v.vector[0] += unit.vector[0]; + v.vector[1] += unit.vector[1]; + v.vector[2] += unit.vector[2]; + } } } } else { @@ -2951,19 +3113,22 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * ry -= pGradient->radial.fy; while (buffer < end) { - double b, c, det, s; + double b, c, det, s; - if (!mask || *mask++ & maskBits) - { - 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); - *buffer = gradientPixel(pGradient, - (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536), - pict->repeat); - } - ++buffer; + 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; } @@ -2972,25 +3137,27 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * double x, y; double b, c, det, s; - if (!mask || *mask++ & maskBits) - { - if (rz != 0) { - x = rx/rz; - y = ry/rz; - } else { - x = y = 0.; - } - x -= pGradient->radial.fx; - y -= pGradient->radial.fy; - b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy); - c = -(x*x + y*y); - det = (b * b) - (4 * pGradient->radial.a * c); - s = (-b + sqrt(det))/(2. * pGradient->radial.a); - *buffer = gradientPixel(pGradient, - (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536), - pict->repeat); - } - ++buffer; + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; + + if (rz != 0) { + x = rx/rz; + y = ry/rz; + } else { + x = y = 0.; + } + x -= pGradient->radial.fx; + y -= pGradient->radial.fy; + b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy); + c = -(x*x + y*y); + 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; rz += cz; @@ -3005,37 +3172,41 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 * while (buffer < end) { double angle; - if (!mask || *mask++ & maskBits) - { - angle = atan2(ry, rx) + a; + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; - *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))), - pict->repeat); - } + angle = atan2(ry, rx) + a; + t = (xFixed_48_16) (angle * (65536. / (2*M_PI))); + + *buffer = _gradient_walker_pixel (&walker, t); + } ++buffer; rx += cx; ry += cy; } } else { - while (buffer < end) { double x, y; - double angle; + double angle; - if (!mask || *mask++ & maskBits) - { - if (rz != 0) { - x = rx/rz; - y = ry/rz; - } else { - x = y = 0.; - } - x -= pGradient->conical.center.x/65536.; - y -= pGradient->conical.center.y/65536.; - angle = atan2(y, x) + a; - *buffer = gradientPixel(pGradient, (xFixed_48_16) (angle * (65536. / (2*M_PI))), - pict->repeat); - } + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; + + if (rz != 0) { + x = rx/rz; + y = ry/rz; + } else { + x = y = 0.; + } + x -= pGradient->conical.center.x/65536.; + y -= pGradient->conical.center.y/65536.; + angle = atan2(y, x) + a; + t = (xFixed_48_16) (angle * (65536. / (2*M_PI))); + + *buffer = _gradient_walker_pixel (&walker, t); + } ++buffer; rx += cx; ry += cy; diff --git a/test/clip-operator-ref.png b/test/clip-operator-ref.png Binary files differindex cc8d8327..9f4eff09 100644 --- a/test/clip-operator-ref.png +++ b/test/clip-operator-ref.png diff --git a/test/clip-operator-rgb24-ref.png b/test/clip-operator-rgb24-ref.png Binary files differindex 7be49f0c..7ab964c3 100644 --- a/test/clip-operator-rgb24-ref.png +++ b/test/clip-operator-rgb24-ref.png diff --git a/test/clip-operator.c b/test/clip-operator.c index 2e014a94..4d7f81e5 100644 --- a/test/clip-operator.c +++ b/test/clip-operator.c @@ -27,9 +27,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 const char png_filename[] = "romedalen.png"; diff --git a/test/mask-ref.png b/test/mask-ref.png Binary files differindex b7cee991..909d9f29 100644 --- a/test/mask-ref.png +++ b/test/mask-ref.png diff --git a/test/mask-rgb24-ref.png b/test/mask-rgb24-ref.png Binary files differindex 5e60fee7..70323672 100644 --- a/test/mask-rgb24-ref.png +++ b/test/mask-rgb24-ref.png diff --git a/test/mask-svg-argb32-ref.png b/test/mask-svg-argb32-ref.png Binary files differindex 5ac50a75..4a7f758a 100644 --- a/test/mask-svg-argb32-ref.png +++ b/test/mask-svg-argb32-ref.png diff --git a/test/mask-svg-rgb24-ref.png b/test/mask-svg-rgb24-ref.png Binary files differdeleted file mode 100644 index 0bf98d90..00000000 --- a/test/mask-svg-rgb24-ref.png +++ /dev/null diff --git a/test/mask.c b/test/mask.c index 84ebf386..984b82df 100644 --- a/test/mask.c +++ b/test/mask.c @@ -28,9 +28,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 const char png_filename[] = "romedalen.png"; diff --git a/test/operator-clear-ref.png b/test/operator-clear-ref.png Binary files differindex ff7afb4d..a3f8b7f0 100644 --- a/test/operator-clear-ref.png +++ b/test/operator-clear-ref.png diff --git a/test/operator-clear-rgb24-ref.png b/test/operator-clear-rgb24-ref.png Binary files differindex ebb02b3a..d80da8be 100644 --- a/test/operator-clear-rgb24-ref.png +++ b/test/operator-clear-rgb24-ref.png diff --git a/test/operator-clear.c b/test/operator-clear.c index 84123fb8..89b50e41 100644 --- a/test/operator-clear.c +++ b/test/operator-clear.c @@ -28,9 +28,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 const char png_filename[] = "romedalen.png"; diff --git a/test/operator-source-ref.png b/test/operator-source-ref.png Binary files differindex 9f1a6266..fe59f7fb 100644 --- a/test/operator-source-ref.png +++ b/test/operator-source-ref.png diff --git a/test/operator-source-rgb24-ref.png b/test/operator-source-rgb24-ref.png Binary files differindex 41316eec..a762d60a 100644 --- a/test/operator-source-rgb24-ref.png +++ b/test/operator-source-rgb24-ref.png diff --git a/test/operator-source.c b/test/operator-source.c index 9984ca2c..912fec68 100644 --- a/test/operator-source.c +++ b/test/operator-source.c @@ -28,9 +28,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 const char png_filename[] = "romedalen.png"; diff --git a/test/text-pattern-ref.png b/test/text-pattern-ref.png Binary files differindex 38529cfe..ac1dd84e 100644 --- a/test/text-pattern-ref.png +++ b/test/text-pattern-ref.png diff --git a/test/text-pattern-rgb24-ref.png b/test/text-pattern-rgb24-ref.png Binary files differindex ae87c6f4..54b214b4 100644 --- a/test/text-pattern-rgb24-ref.png +++ b/test/text-pattern-rgb24-ref.png diff --git a/test/trap-clip-ref.png b/test/trap-clip-ref.png Binary files differindex 3ce2431d..93302976 100644 --- a/test/trap-clip-ref.png +++ b/test/trap-clip-ref.png diff --git a/test/trap-clip-rgb24-ref.png b/test/trap-clip-rgb24-ref.png Binary files differindex 6908ca3a..15068aa5 100644 --- a/test/trap-clip-rgb24-ref.png +++ b/test/trap-clip-rgb24-ref.png diff --git a/test/trap-clip-svg-argb32-ref.png b/test/trap-clip-svg-argb32-ref.png Binary files differdeleted file mode 100644 index 30dfa4f4..00000000 --- a/test/trap-clip-svg-argb32-ref.png +++ /dev/null diff --git a/test/trap-clip.c b/test/trap-clip.c index e98d865d..ba4d148e 100644 --- a/test/trap-clip.c +++ b/test/trap-clip.c @@ -27,9 +27,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 const char png_filename[] = "romedalen.png"; diff --git a/test/unbounded-operator-ref.png b/test/unbounded-operator-ref.png Binary files differindex 231019d8..03c7bc8f 100644 --- a/test/unbounded-operator-ref.png +++ b/test/unbounded-operator-ref.png diff --git a/test/unbounded-operator-rgb24-ref.png b/test/unbounded-operator-rgb24-ref.png Binary files differindex c12d9bba..b2f1a84d 100644 --- a/test/unbounded-operator-rgb24-ref.png +++ b/test/unbounded-operator-rgb24-ref.png diff --git a/test/unbounded-operator.c b/test/unbounded-operator.c index 7986c7c9..e04ec803 100644 --- a/test/unbounded-operator.c +++ b/test/unbounded-operator.c @@ -28,9 +28,9 @@ #include "cairo-test.h" #include <stdio.h> -#define WIDTH 64 -#define HEIGHT 64 -#define PAD 10 +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 static void draw_mask (cairo_t *cr, int x, int y) |