pixman: Branch 'master' - 4 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Fri Mar 22 04:23:42 PDT 2013


 .gitignore                      |    2 
 demos/Makefile.am               |    2 
 demos/linear-gradient.c         |   50 ++++++++++++++++++
 pixman/pixman-combine-float.c   |   34 ++++++------
 pixman/pixman-gradient-walker.c |  106 +++++++++++++++++++++++++---------------
 pixman/pixman-private.h         |   13 +++-
 test/Makefile.sources           |    3 -
 test/radial-perf-test.c         |   58 +++++++++++++++++++++
 8 files changed, 206 insertions(+), 62 deletions(-)

New commits:
commit d8ac35af1208a4fa4d67f03fee10b5449fb8495a
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Feb 14 08:06:19 2013 -0500

    Improve precision of calculations in pixman-gradient-walker.c
    
    The computations in pixman-gradient-walker.c currently take place at
    very limited 8 bit precision which results in quite visible artefacts
    in gradients. An example is the one produced by demos/linear-gradient
    which currently looks like this:
    
        http://i.imgur.com/kQbX8nd.png
    
    With the changes in this commit, the gradient looks like this:
    
        http://i.imgur.com/nUlyuKI.png
    
    The images are also available here:
    
        http://people.freedesktop.org/~sandmann/gradients/before.png
        http://people.freedesktop.org/~sandmann/gradients/after.png
    
    This patch computes pixels using floating point, but uses a faster
    algorithm, which makes up for the loss of performance.
    
    == Theory:
    
    In both the new and the old algorithm, the various gradient
    implementations compute a parameter x that indicates how far along the
    gradient the current scanline is. The current algorithm has a cache of
    the two color stops surrounding the last parameter; those are used in
    a SIMD-within-register fashion in this way:
    
        t1 = walker->left_rb * idist + walker->right_rb * dist;
    
    where dist and idist are the distances to the left and right color
    stops respectively normalized to the distance between the left and
    right stops. The normalization (which involves a division) is captured
    in another cached variable "stepper". The cached values are recomputed
    whenever the parameter moves in between two different stops (called
    "reset" in the implementation).
    
    Because idist and dist are computed in 8 bits only, a lot of
    information is lost, which is quite visible as the image linked above
    shows.
    
    The new algorithm caches more information in the following way. When
    interpolating between stops, the formula to be used is this:
    
         t = ((x - left) / (right - left));
    
         result = lc * (1 - t) + rc * t;
    
    where
    
        - x is the parameter as computed by the main gradient code,
        - left is the position of the left color stop,
        - right is the position of the right color stop
        - lc is the color of the left color stop
        - rc is the color of the right color stop
    
    That formula can also be written like this:
    
        result
          = lc * (1 - t) + rc * t;
          = lc + (rc - lc) * t
          = lc + (rc - lc) * ((x - left) / (right - left))
          = (rc - lc) / (right - left) * x +
          	       lc - (left * (rc - lc)) / (right - left)
          = s * x + b
    
    where
    
        s = (rc - lc) / (right - left)
    
    and
    
        b = lc - left * (rc - lc) / (right - left)
          = (lc * (right - left) - left * (rc - lc)) / (right - left)
          = (lc * right - rc * left) / (right - left)
    
    To summarize, setting w = (right - left):
    
        s = (rc - lc) / w
        b = (lc * right - rc * left) / w
    
        r = s * x + b
    
    Since s and b only depend on the two active stops, both can be cached
    so that the computation only needs to do one multiplication and one
    addition per pixel (followed by premultiplication of the alpha
    channel). That is, seven multiplications in total, which is the same
    number as the old SIMD-within-register implementation had.
    
    == Implementation notes:
    
    The new formula described above is implemented in single precision
    floating point, and the eight divisions necessary to compute the
    cached values are done by multiplication with the reciprocal of the
    distance between the color stops.
    
    The alpha values used in the cached computation are scaled by 255.0,
    whereas the RGB values are kept in the [0, 1] interval. The ensures
    that after premultiplication, all values will be in the [0, 255]
    interval.
    
    This scaling is done by first dividing all the all the channels by
    257, and then later on dividing the r, g, b channels by 255. It would
    be more natural to do all this scaling in only one place, but
    inexplicably, that results in a (substantial) slowdown on Sandy Bridge
    with GCC v 4.7.
    
    == Performance impact (median of three runs of radial-perf-test):
    
       == Intel Sandy Bridge, Core i3 @ 1.2GHz
    
       Before: 0.014553
       After:  0.014410
       Change: 1.0% faster
    
       == AMD Barcelona @ 1.2 GHz
    
       Before: 0.021735
       After:  0.021328
       Change: 1.9% faster
    
    Ie., slightly faster, though conceivably there could be a negative
    impact on machines with a bigger difference between integer and
    floating point performance.
    
    V2:
    
    - Use 's' and 'b' in the variable names instead of 'm' and 'd'. This
      way they match the explanation above
    
    - Move variable declarations to the top of the function
    
    - Remove unused stepper field
    
    - Some formatting fixes
    
    - Don't pointlessly include pixman-combine32.h
    
    - Don't offset x for each pixel; go back to offsetting left_x and
      right_x at reset time. The offsets cancel out in the formula above,
      so there is no impact on the calcualations.

diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c
index e7e724f..5944a55 100644
--- a/pixman/pixman-gradient-walker.c
+++ b/pixman/pixman-gradient-walker.c
@@ -37,11 +37,14 @@ _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
     walker->stops     = gradient->stops;
     walker->left_x    = 0;
     walker->right_x   = 0x10000;
-    walker->stepper   = 0;
-    walker->left_ag   = 0;
-    walker->left_rb   = 0;
-    walker->right_ag  = 0;
-    walker->right_rb  = 0;
+    walker->a_s       = 0.0f;
+    walker->a_b       = 0.0f;
+    walker->r_s       = 0.0f;
+    walker->r_b       = 0.0f;
+    walker->g_s       = 0.0f;
+    walker->g_b       = 0.0f;
+    walker->b_s       = 0.0f;
+    walker->b_b       = 0.0f;
     walker->repeat    = repeat;
 
     walker->need_reset = TRUE;
@@ -55,6 +58,9 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
     pixman_color_t *left_c, *right_c;
     int n, count = walker->num_stops;
     pixman_gradient_stop_t *stops = walker->stops;
+    float la, lr, lg, lb;
+    float ra, rr, rg, rb;
+    float lx, rx;
 
     if (walker->repeat == PIXMAN_REPEAT_NORMAL)
     {
@@ -116,24 +122,49 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
 	    left_c = right_c;
     }
 
-    walker->left_x   = left_x;
-    walker->right_x  = right_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->left_x == walker->right_x                ||
-        (walker->left_ag == walker->right_ag &&
-	 walker->left_rb == walker->right_rb))
+    /* The alpha channel is scaled to be in the [0, 255] interval,
+     * and the red/green/blue channels are scaled to be in [0, 1].
+     * This ensures that after premultiplication all channels will
+     * be in the [0, 255] interval.
+     */
+    la = (left_c->alpha * (1.0f/257.0f));
+    lr = (left_c->red * (1.0f/257.0f));
+    lg = (left_c->green * (1.0f/257.0f));
+    lb = (left_c->blue * (1.0f/257.0f));
+
+    ra = (right_c->alpha * (1.0f/257.0f));
+    rr = (right_c->red * (1.0f/257.0f));
+    rg = (right_c->green * (1.0f/257.0f));
+    rb = (right_c->blue * (1.0f/257.0f));
+    
+    lx = left_x * (1.0f/65536.0f);
+    rx = right_x * (1.0f/65536.0f);
+    
+    if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
     {
-	walker->stepper = 0;
+	walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
+	walker->a_b = (la + ra) / 2.0f;
+	walker->r_b = (lr + rr) / 510.0f;
+	walker->g_b = (lg + rg) / 510.0f;
+	walker->b_b = (lb + rb) / 510.0f;
     }
     else
     {
-	int32_t width = right_x - left_x;
-	walker->stepper = ((1 << 24) + width / 2) / width;
+	float w_rec = 1.0f / (rx - lx);
+
+	walker->a_b = (la * rx - ra * lx) * w_rec;
+	walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
+	walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
+	walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
+
+	walker->a_s = (ra - la) * w_rec;
+	walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
+	walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
+	walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
     }
+   
+    walker->left_x = left_x;
+    walker->right_x = right_x;
 
     walker->need_reset = FALSE;
 }
@@ -142,31 +173,30 @@ uint32_t
 _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
                                pixman_fixed_48_16_t      x)
 {
-    int dist, idist;
-    uint32_t t1, t2, a, color;
+    float a, r, g, b;
+    uint8_t a8, r8, g8, b8;
+    uint32_t v;
+    float y;
 
     if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
-	gradient_walker_reset (walker, x);
-
-    dist  = ((int)(x - walker->left_x) * walker->stepper) >> 16;
-    idist = 256 - dist;
+        gradient_walker_reset (walker, x);
 
-    /* combined INTERPOLATE and premultiply */
-    t1 = walker->left_rb * idist + walker->right_rb * dist;
-    t1 = (t1 >> 8) & 0xff00ff;
+    y = x * (1.0f / 65536.0f);
 
-    t2  = walker->left_ag * idist + walker->right_ag * dist;
-    t2 &= 0xff00ff00;
+    a = walker->a_s * y + walker->a_b;
+    r = a * (walker->r_s * y + walker->r_b);
+    g = a * (walker->g_s * y + walker->g_b);
+    b = a * (walker->b_s * y + walker->b_b);
 
-    color = t2 & 0xff000000;
-    a     = t2 >> 24;
+    a8 = a + 0.5f;
+    r8 = r + 0.5f;
+    g8 = g + 0.5f;
+    b8 = b + 0.5f;
 
-    t1  = t1 * a + 0x800080;
-    t1  = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
+    v = ((a8 << 24) & 0xff000000) |
+        ((r8 << 16) & 0x00ff0000) |
+        ((g8 <<  8) & 0x0000ff00) |
+        ((b8 >>  0) & 0x000000ff);
 
-    t2  = (t2 >> 8) * a + 0x800080;
-    t2  = (t2 + ((t2 >> 8) & 0xff00ff));
-
-    return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
+    return v;
 }
-
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 91e329f..6d9c053 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -319,13 +319,12 @@ _pixman_image_validate (pixman_image_t *image);
  */
 typedef struct
 {
-    uint32_t                left_ag;
-    uint32_t                left_rb;
-    uint32_t                right_ag;
-    uint32_t                right_rb;
+    float		    a_s, a_b;
+    float		    r_s, r_b;
+    float		    g_s, g_b;
+    float		    b_s, b_b;
     pixman_fixed_t	    left_x;
     pixman_fixed_t          right_x;
-    pixman_fixed_t          stepper;
 
     pixman_gradient_stop_t *stops;
     int                     num_stops;
commit a1c2331e0eb35d87cf295518838debe1217ca9df
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Fri Mar 8 14:05:50 2013 -0500

    Move the IS_ZERO() to pixman-private.h and rename to FLOAT_IS_ZERO()
    
    Some upcoming changes to pixman-gradient-walker.c will need this
    macro.

diff --git a/pixman/pixman-combine-float.c b/pixman/pixman-combine-float.c
index 06ce203..5ea739f 100644
--- a/pixman/pixman-combine-float.c
+++ b/pixman/pixman-combine-float.c
@@ -42,8 +42,6 @@
 #define force_inline __inline__
 #endif
 
-#define IS_ZERO(f)     (-FLT_MIN < (f) && (f) < FLT_MIN)
-
 typedef float (* combine_channel_t) (float sa, float s, float da, float d);
 
 static force_inline void
@@ -203,56 +201,56 @@ get_factor (combine_factor_t factor, float sa, float da)
 	break;
 
     case SA_OVER_DA:
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	    f = 1.0f;
 	else
 	    f = CLAMP (sa / da);
 	break;
 
     case DA_OVER_SA:
-	if (IS_ZERO (sa))
+	if (FLOAT_IS_ZERO (sa))
 	    f = 1.0f;
 	else
 	    f = CLAMP (da / sa);
 	break;
 
     case INV_SA_OVER_DA:
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	    f = 1.0f;
 	else
 	    f = CLAMP ((1.0f - sa) / da);
 	break;
 
     case INV_DA_OVER_SA:
-	if (IS_ZERO (sa))
+	if (FLOAT_IS_ZERO (sa))
 	    f = 1.0f;
 	else
 	    f = CLAMP ((1.0f - da) / sa);
 	break;
 
     case ONE_MINUS_SA_OVER_DA:
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	    f = 0.0f;
 	else
 	    f = CLAMP (1.0f - sa / da);
 	break;
 
     case ONE_MINUS_DA_OVER_SA:
-	if (IS_ZERO (sa))
+	if (FLOAT_IS_ZERO (sa))
 	    f = 0.0f;
 	else
 	    f = CLAMP (1.0f - da / sa);
 	break;
 
     case ONE_MINUS_INV_DA_OVER_SA:
-	if (IS_ZERO (sa))
+	if (FLOAT_IS_ZERO (sa))
 	    f = 0.0f;
 	else
 	    f = CLAMP (1.0f - (1.0f - da) / sa);
 	break;
 
     case ONE_MINUS_INV_SA_OVER_DA:
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	    f = 0.0f;
 	else
 	    f = CLAMP (1.0f - (1.0f - sa) / da);
@@ -405,11 +403,11 @@ blend_lighten (float sa, float s, float da, float d)
 static force_inline float
 blend_color_dodge (float sa, float s, float da, float d)
 {
-    if (IS_ZERO (d))
+    if (FLOAT_IS_ZERO (d))
 	return 0.0f;
     else if (d * sa >= sa * da - s * da)
 	return sa * da;
-    else if (IS_ZERO (sa - s))
+    else if (FLOAT_IS_ZERO (sa - s))
 	return sa * da;
     else
 	return sa * sa * d / (sa - s);
@@ -422,7 +420,7 @@ blend_color_burn (float sa, float s, float da, float d)
 	return sa * da;
     else if (sa * (da - d) >= s * da)
 	return 0.0f;
-    else if (IS_ZERO (s))
+    else if (FLOAT_IS_ZERO (s))
 	return 0.0f;
     else
 	return sa * (da - sa * (da - d) / s);
@@ -442,14 +440,14 @@ blend_soft_light (float sa, float s, float da, float d)
 {
     if (2 * s < sa)
     {
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	    return d * sa;
 	else
 	    return d * sa - d * (da - d) * (sa - 2 * s) / da;
     }
     else
     {
-	if (IS_ZERO (da))
+	if (FLOAT_IS_ZERO (da))
 	{
 	    return 0.0f;
 	}
@@ -658,7 +656,7 @@ clip_color (rgb_t *color, float a)
     if (n < 0.0f)
     {
 	t = l - n;
-	if (IS_ZERO (t))
+	if (FLOAT_IS_ZERO (t))
 	{
 	    color->r = 0.0f;
 	    color->g = 0.0f;
@@ -674,7 +672,7 @@ clip_color (rgb_t *color, float a)
     if (x > a)
     {
 	t = x - l;
-	if (IS_ZERO (t))
+	if (FLOAT_IS_ZERO (t))
 	{
 	    color->r = a;
 	    color->g = a;
@@ -758,7 +756,7 @@ set_sat (rgb_t *src, float sat)
 
     t = *max - *min;
 
-    if (IS_ZERO (t))
+    if (FLOAT_IS_ZERO (t))
     {
 	*mid = *max = 0.0f;
     }
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 181ab5c..91e329f 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -1,3 +1,5 @@
+#include <float.h>
+
 #ifndef PIXMAN_PRIVATE_H
 #define PIXMAN_PRIVATE_H
 
@@ -879,6 +881,8 @@ pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link)
 
 #define CLIP(v, low, high) ((v) < (low) ? (low) : ((v) > (high) ? (high) : (v)))
 
+#define FLOAT_IS_ZERO(f)     (-FLT_MIN < (f) && (f) < FLT_MIN)
+
 /* Conversion between 8888 and 0565 */
 
 static force_inline uint16_t
commit 2c953e572f6c3c18046e768dd07d12150b1f2e94
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Feb 24 21:49:06 2013 -0500

    test: Add radial-perf-test, a microbenchmark for radial gradients
    
    This benchmark renders one of the radial gradients used in the
    swfdec-youtube cairo trace 500 times and reports the average time it
    took.
    
    V2: Update .gitignore

diff --git a/.gitignore b/.gitignore
index 584253b..0f11496 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,6 +67,7 @@ test/lowlevel-blt-bench
 test/oob-test
 test/pdf-op-test
 test/prng-test
+test/radial-perf-test
 test/region-contains-test
 test/region-test
 test/region-translate
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 5b30970..b5fc740 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -28,9 +28,10 @@ TESTPROGRAMS =			\
 	composite		\
 	$(NULL)
 
-# Benchmarks
+# Other programs
 OTHERPROGRAMS =                 \
 	lowlevel-blt-bench	\
+	radial-perf-test	\
         check-formats           \
 	$(NULL)
 
diff --git a/test/radial-perf-test.c b/test/radial-perf-test.c
new file mode 100644
index 0000000..71092e2
--- /dev/null
+++ b/test/radial-perf-test.c
@@ -0,0 +1,58 @@
+#include "utils.h"
+#include <stdio.h>
+
+int
+main ()
+{
+    static const pixman_point_fixed_t inner = { 0x0000, 0x0000 };
+    static const pixman_point_fixed_t outer = { 0x0000, 0x0000 };
+    static const pixman_fixed_t r_inner = 0;
+    static const pixman_fixed_t r_outer = 64 << 16;
+    static const pixman_gradient_stop_t stops[] = {
+	{ 0x00000, { 0x6666, 0x6666, 0x6666, 0xffff } },
+	{ 0x10000, { 0x0000, 0x0000, 0x0000, 0xffff } }
+    };
+    static const pixman_transform_t transform = {
+	{ { 0x0,        0x26ee, 0x0}, 
+	  { 0xffffeeef, 0x0,    0x0}, 
+	  { 0x0,        0x0,    0x10000}
+	}
+    };
+    static const pixman_color_t z = { 0x0000, 0x0000, 0x0000, 0x0000 };
+    pixman_image_t *dest, *radial, *zero;
+    int i;
+    double before, after;
+
+    dest = pixman_image_create_bits (
+	PIXMAN_x8r8g8b8, 640, 429, NULL, -1);
+    zero = pixman_image_create_solid_fill (&z);
+    radial = pixman_image_create_radial_gradient (
+	&inner, &outer, r_inner, r_outer, stops, ARRAY_LENGTH (stops));
+    pixman_image_set_transform (radial, &transform);
+    pixman_image_set_repeat (radial, PIXMAN_REPEAT_PAD);
+
+#define N_COMPOSITE	500
+
+    before = gettime();
+    for (i = 0; i < N_COMPOSITE; ++i)
+    {
+	before -= gettime();
+
+	pixman_image_composite (
+	    PIXMAN_OP_SRC, zero, NULL, dest,
+	    0, 0, 0, 0, 0, 0, 640, 429);
+
+	before += gettime();
+
+	pixman_image_composite32 (
+	    PIXMAN_OP_OVER, radial, NULL, dest,
+	    - 150, -158, 0, 0, 0, 0, 640, 361);
+    }
+
+    after = gettime();
+
+    write_png (dest, "radial.png");
+
+    printf ("Average time to composite: %f\n", (after - before) / N_COMPOSITE);
+    return 0;
+}
commit 460faaa41105c2939d041506f6ff08e2b12e7596
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Thu Feb 14 20:32:31 2013 -0500

    demos: Add linear-gradient demo program
    
    This program displays a linear gradient from blue to yellow. Due to
    limited precision in pixman-gradient-walker.c, it currently has some
    ugly artefacts that gives it a 'brushed metal' appearance.
    
    V2: Update .gitignore

diff --git a/.gitignore b/.gitignore
index 648699b..584253b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ demos/composite-test
 demos/conical-test
 demos/convolution-test
 demos/gradient-test
+demos/linear-gradient
 demos/quad2quad
 demos/radial-test
 demos/scale
diff --git a/demos/Makefile.am b/demos/Makefile.am
index 5f53407..9be9ab6 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -15,6 +15,7 @@ DEMOS =				\
 	composite-test		\
 	gradient-test		\
 	radial-test		\
+	linear-gradient		\
 	conical-test		\
 	alpha-test		\
 	screen-test		\
@@ -38,6 +39,7 @@ trap_test_SOURCES = trap-test.c $(GTK_UTILS)
 screen_test_SOURCES = screen-test.c $(GTK_UTILS)
 convolution_test_SOURCES = convolution-test.c $(GTK_UTILS)
 radial_test_SOURCES = radial-test.c $(GTK_UTILS)
+linear_gradient_SOURCES = linear-gradient.c $(GTK_UTILS)
 conical_test_SOURCES = conical-test.c $(GTK_UTILS)
 tri_test_SOURCES = tri-test.c $(GTK_UTILS)
 checkerboard_SOURCES = checkerboard.c $(GTK_UTILS)
diff --git a/demos/linear-gradient.c b/demos/linear-gradient.c
new file mode 100644
index 0000000..46433a6
--- /dev/null
+++ b/demos/linear-gradient.c
@@ -0,0 +1,50 @@
+#include "../test/utils.h"
+#include "gtk-utils.h"
+
+#define WIDTH 1024
+#define HEIGHT 640
+
+int
+main (int argc, char **argv)
+{
+    pixman_image_t *src_img, *dest_img;
+    pixman_gradient_stop_t stops[] = {
+        { 0x00000, { 0x0000, 0x0000, 0x4444, 0xdddd } },
+        { 0x10000, { 0xeeee, 0xeeee, 0x8888, 0xdddd } },
+#if 0
+        /* These colors make it very obvious that dithering
+         * is useful even for 8-bit gradients
+         */
+	{ 0x00000, { 0x6666, 0x3333, 0x3333, 0xffff } },
+	{ 0x10000, { 0x3333, 0x6666, 0x6666, 0xffff } },
+#endif
+    };
+    pixman_point_fixed_t p1, p2;
+
+    enable_divbyzero_exceptions ();
+
+    dest_img = pixman_image_create_bits (PIXMAN_x8r8g8b8,
+					 WIDTH, HEIGHT,
+					 NULL, 0);
+
+    p1.x = p1.y = 0x0000;
+    p2.x = WIDTH << 16;
+    p2.y = HEIGHT << 16;
+    
+    src_img = pixman_image_create_linear_gradient (&p1, &p2, stops, ARRAY_LENGTH (stops));
+
+    pixman_image_composite32 (PIXMAN_OP_OVER,
+			      src_img,
+			      NULL,
+			      dest_img,
+			      0, 0,
+			      0, 0,
+			      0, 0,
+			      WIDTH, HEIGHT);
+
+    show_image (dest_img);
+
+    pixman_image_unref (dest_img);
+
+    return 0;
+}


More information about the xorg-commit mailing list