summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2011-01-14 21:31:09 +0100
committerAndrea Canciani <ranma42@gmail.com>2011-01-15 00:41:06 +0100
commit3bcd40c2a5842519167c6ab37d2ad4628667b108 (patch)
tree3b50ca821a49aaa6f86d32e9075b61c9430f07c3
parent7d1d3cd2ec103261e23199a6a72a02f744a18f25 (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.c21
-rw-r--r--pixman/pixman-gradient-walker.c72
-rw-r--r--pixman/pixman-linear-gradient.c26
-rw-r--r--pixman/pixman-private.h34
-rw-r--r--pixman/pixman-radial-gradient.c37
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);