diff options
author | Andrea Canciani <ranma42@gmail.com> | 2011-01-14 21:31:09 +0100 |
---|---|---|
committer | Andrea Canciani <ranma42@gmail.com> | 2011-01-15 00:41:06 +0100 |
commit | 3bcd40c2a5842519167c6ab37d2ad4628667b108 (patch) | |
tree | 3b50ca821a49aaa6f86d32e9075b61c9430f07c3 | |
parent | 7d1d3cd2ec103261e23199a6a72a02f744a18f25 (diff) |
Only compute the value of the interpolation parameter in gradientswip/itergradient
The color computation is performed in a later step using the gradient
walker over the computed row.
TODO:
- pass the double values to the gradient walker (all gradient compute
the parameter in double precision, so let's pass it as double to
the layer which translates it to color)
- use a special value for "no-value" (currently -1 is used for the
radial gradient transparency... urgh!)
- special case gradients upon iterator creation: affine/projective,
horizontal/vertical/generic linear, a==0/norepeat/repeat radial
(should make most gradients simple branchless tight loops, which
should be much easier for the compiler to optimize)
-rw-r--r-- | pixman/pixman-conical-gradient.c | 21 | ||||
-rw-r--r-- | pixman/pixman-gradient-walker.c | 72 | ||||
-rw-r--r-- | pixman/pixman-linear-gradient.c | 26 | ||||
-rw-r--r-- | pixman/pixman-private.h | 34 | ||||
-rw-r--r-- | pixman/pixman-radial-gradient.c | 37 |
5 files changed, 112 insertions, 78 deletions
diff --git a/pixman/pixman-conical-gradient.c b/pixman/pixman-conical-gradient.c index 9d7d2e8..a9da6b7 100644 --- a/pixman/pixman-conical-gradient.c +++ b/pixman/pixman-conical-gradient.c @@ -51,7 +51,7 @@ coordinates_to_parameter (double x, double y, double angle) } static uint32_t * -conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) +conical_get_scanline_parameter (pixman_iter_t *iter, const uint32_t *mask) { pixman_image_t *image = iter->image; int x = iter->x; @@ -59,10 +59,8 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) int width = iter->width; uint32_t *buffer = iter->buffer; - gradient_t *gradient = (gradient_t *)image; conical_gradient_t *conical = (conical_gradient_t *)image; uint32_t *end = buffer + width; - pixman_gradient_walker_t walker; pixman_bool_t affine = TRUE; double cx = 1.; double cy = 0.; @@ -71,8 +69,6 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) double ry = y + 0.5; double rz = 1.; - _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); - if (image->common.transform) { pixman_vector_t v; @@ -109,8 +105,7 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) { double t = coordinates_to_parameter (rx, ry, conical->angle); - *buffer = _pixman_gradient_walker_pixel ( - &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); + *buffer = pixman_double_to_fixed (t); } ++buffer; @@ -144,8 +139,7 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) t = coordinates_to_parameter (x, y, conical->angle); - *buffer = _pixman_gradient_walker_pixel ( - &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); + *buffer = pixman_double_to_fixed (t); } ++buffer; @@ -161,6 +155,15 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) } static uint32_t * +conical_get_scanline_narrow (pixman_iter_t *iter, + const uint32_t *mask) +{ + uint32_t *buffer = conical_get_scanline_parameter (iter, mask); + + return gradient_walker_get_scanline_narrow (buffer, iter->width, mask, iter->image); +} + +static uint32_t * conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { uint32_t *buffer = conical_get_scanline_narrow (iter, NULL); diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c index dd666b4..ec5285e 100644 --- a/pixman/pixman-gradient-walker.c +++ b/pixman/pixman-gradient-walker.c @@ -28,10 +28,26 @@ #endif #include "pixman-private.h" -void +typedef struct +{ + uint32_t left_ag; + uint32_t left_rb; + uint32_t right_ag; + uint32_t right_rb; + int32_t left_x; + int32_t right_x; + int32_t stepper; + + const pixman_gradient_stop_t *stops; + int num_stops; + unsigned int spread; + + int need_reset; +} pixman_gradient_walker_t; + +static void _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, - gradient_t * gradient, - unsigned int spread) + const gradient_t *gradient) { walker->num_stops = gradient->n_stops; walker->stops = gradient->stops; @@ -42,19 +58,19 @@ _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, walker->left_rb = 0; walker->right_ag = 0; walker->right_rb = 0; - walker->spread = spread; + walker->spread = gradient->common.repeat; walker->need_reset = TRUE; } -void +static void _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker, - pixman_fixed_32_32_t pos) + pixman_fixed_16_16_t pos) { int32_t x, left_x, right_x; - pixman_color_t *left_c, *right_c; + const pixman_color_t *left_c, *right_c; int n, count = walker->num_stops; - pixman_gradient_stop_t * stops = walker->stops; + const pixman_gradient_stop_t * stops = walker->stops; static const pixman_color_t transparent_black = { 0, 0, 0, 0 }; @@ -150,7 +166,7 @@ _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker, if ((int32_t)pos & 0x10000) { - pixman_color_t *tmp_c; + const pixman_color_t *tmp_c; int32_t tmp_x; tmp_x = 0x10000 - right_x; @@ -220,9 +236,9 @@ _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker, /* the following assumes that PIXMAN_GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */ -uint32_t +static uint32_t _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, - pixman_fixed_32_32_t x) + pixman_fixed_16_16_t x) { int dist, idist; uint32_t t1, t2, a, color; @@ -252,3 +268,37 @@ _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); } +uint32_t * +gradient_walker_get_scanline_narrow (uint32_t *buffer, + int width, + const uint32_t *mask, + const gradient_t *gradient) +{ + pixman_gradient_walker_t walker; + int i; + pixman_fixed_16_16_t t; + uint32_t old_c; + + _pixman_gradient_walker_init (&walker, gradient); + + t = -1; + for (i = 0; i < width; i++) + { + if (buffer[i] == (uint32_t) -1) + { + buffer[i] = 0; + } + else if (!mask || *mask++) + { + if (t != buffer[i]) + { + t = buffer[i]; + old_c = _pixman_gradient_walker_pixel (&walker, buffer[i]); + } + + buffer[i] = old_c; + } + } + + return buffer; +} diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c index 9208808..8504132 100644 --- a/pixman/pixman-linear-gradient.c +++ b/pixman/pixman-linear-gradient.c @@ -89,8 +89,8 @@ linear_gradient_is_horizontal (pixman_image_t *image, } static uint32_t * -linear_gradient_get_scanline_narrow (pixman_iter_t *iter, - const uint32_t *mask) +linear_gradient_get_scanline_parameter (pixman_iter_t *iter, + const uint32_t *mask) { pixman_image_t *image = iter->image; int x = iter->x; @@ -104,9 +104,6 @@ linear_gradient_get_scanline_narrow (pixman_iter_t *iter, gradient_t *gradient = (gradient_t *)image; linear_gradient_t *linear = (linear_gradient_t *)image; uint32_t *end = buffer + width; - pixman_gradient_walker_t walker; - - _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); /* reference point is the center of the pixel */ v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; @@ -160,11 +157,8 @@ linear_gradient_get_scanline_narrow (pixman_iter_t *iter, if (((pixman_fixed_32_32_t )(inc * width)) == 0) { - register uint32_t color; - - color = _pixman_gradient_walker_pixel (&walker, t); while (buffer < end) - *buffer++ = color; + *buffer++ = t; } else { @@ -175,8 +169,7 @@ linear_gradient_get_scanline_narrow (pixman_iter_t *iter, { if (!mask || *mask++) { - *buffer = _pixman_gradient_walker_pixel (&walker, - t + next_inc); + *buffer = t + next_inc; } i++; next_inc = inc * i; @@ -206,7 +199,7 @@ linear_gradient_get_scanline_narrow (pixman_iter_t *iter, (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; } - *buffer = _pixman_gradient_walker_pixel (&walker, t); + *buffer = t; } ++buffer; @@ -223,6 +216,15 @@ linear_gradient_get_scanline_narrow (pixman_iter_t *iter, } static uint32_t * +linear_gradient_get_scanline_narrow (pixman_iter_t *iter, + const uint32_t *mask) +{ + uint32_t *buffer = linear_gradient_get_scanline_parameter (iter, mask); + + return gradient_walker_get_scanline_narrow (buffer, iter->width, mask, iter->image); +} + +static uint32_t * linear_gradient_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { uint32_t *buffer = linear_gradient_get_scanline_narrow (iter, NULL); diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index 323bdf4..e0fd599 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -292,35 +292,11 @@ _pixman_image_validate (pixman_image_t *image); /* * Gradient walker */ -typedef struct -{ - uint32_t left_ag; - uint32_t left_rb; - uint32_t right_ag; - uint32_t right_rb; - int32_t left_x; - int32_t right_x; - int32_t stepper; - - pixman_gradient_stop_t *stops; - int num_stops; - unsigned int spread; - - int need_reset; -} pixman_gradient_walker_t; - -void -_pixman_gradient_walker_init (pixman_gradient_walker_t *walker, - gradient_t * gradient, - unsigned int spread); - -void -_pixman_gradient_walker_reset (pixman_gradient_walker_t *walker, - pixman_fixed_32_32_t pos); - -uint32_t -_pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, - pixman_fixed_32_32_t x); +uint32_t * +gradient_walker_get_scanline_narrow (uint32_t *buffer, + int width, + const uint32_t *mask, + const gradient_t *gradient); /* * Edges diff --git a/pixman/pixman-radial-gradient.c b/pixman/pixman-radial-gradient.c index 6523b82..5b88719 100644 --- a/pixman/pixman-radial-gradient.c +++ b/pixman/pixman-radial-gradient.c @@ -73,7 +73,6 @@ radial_compute_color (double a, double inva, double dr, double mindr, - pixman_gradient_walker_t *walker, pixman_repeat_t repeat) { /* @@ -99,21 +98,21 @@ radial_compute_color (double a, double t; if (b == 0) - return 0; + return -1; t = pixman_fixed_1 / 2 * c / b; if (repeat == PIXMAN_REPEAT_NONE) { if (0 <= t && t <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t); + return t; } else { if (t * dr > mindr) - return _pixman_gradient_walker_pixel (walker, t); + return t; } - return 0; + return -1; } det = fdot (b, a, 0, b, -c, 0); @@ -128,24 +127,24 @@ radial_compute_color (double a, if (repeat == PIXMAN_REPEAT_NONE) { if (0 <= t0 && t0 <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t0); + return t0; else if (0 <= t1 && t1 <= pixman_fixed_1) - return _pixman_gradient_walker_pixel (walker, t1); + return t1; } else { if (t0 * dr > mindr) - return _pixman_gradient_walker_pixel (walker, t0); + return t0; else if (t1 * dr > mindr) - return _pixman_gradient_walker_pixel (walker, t1); + return t1; } } - return 0; + return -1; } static uint32_t * -radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) +radial_get_scanline_parameter (pixman_iter_t *iter, const uint32_t *mask) { /* * Implementation of radial gradients following the PDF specification. @@ -234,10 +233,8 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) int width = iter->width; uint32_t *buffer = iter->buffer; - gradient_t *gradient = (gradient_t *)image; radial_gradient_t *radial = (radial_gradient_t *)image; uint32_t *end = buffer + width; - pixman_gradient_walker_t walker; pixman_vector_t v, unit; /* reference point is the center of the pixel */ @@ -245,8 +242,6 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; v.vector[2] = pixman_fixed_1; - _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); - if (image->common.transform) { if (!pixman_transform_point_3d (image->common.transform, &v)) @@ -323,7 +318,6 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) radial->inva, radial->delta.radius, radial->mindr, - &walker, image->common.repeat); } @@ -368,7 +362,6 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) radial->inva, radial->delta.radius, radial->mindr, - &walker, image->common.repeat); } else @@ -390,6 +383,16 @@ radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) } static uint32_t * +radial_get_scanline_narrow (pixman_iter_t *iter, + const uint32_t *mask) +{ + uint32_t *buffer = radial_get_scanline_parameter (iter, mask); + + return gradient_walker_get_scanline_narrow (buffer, iter->width, mask, iter->image); +} + + +static uint32_t * radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) { uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); |