pixman: Branch 'master' - 4 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Wed Oct 20 13:13:55 PDT 2010


 pixman/pixman-image.c           |    1 
 pixman/pixman-linear-gradient.c |  193 ++++++++++++++++------------------------
 pixman/pixman-private.h         |    2 
 pixman/pixman-solid-fill.c      |    3 
 4 files changed, 83 insertions(+), 116 deletions(-)

New commits:
commit 70658f0a6bd451a21fbb43df7865a7dac95abe24
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Wed Oct 20 16:09:44 2010 -0400

    Remove the class field from source_image_t
    
    The linear gradient was the only image type that relied on the class
    being stored in the image struct itself. With the previous changes, it
    doesn't need that anymore, so we can delete the field.

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 7a9c423..fabcd63 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -48,7 +48,6 @@ _pixman_init_gradient (gradient_t *                  gradient,
     gradient->n_stops = n_stops;
 
     gradient->stop_range = 0xffff;
-    gradient->common.class = SOURCE_IMAGE_CLASS_UNKNOWN;
 
     return TRUE;
 }
diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index c6ac980..b048e7b 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -44,8 +44,9 @@ linear_gradient_classify (pixman_image_t *image,
     pixman_fixed_32_32_t l;
     pixman_fixed_48_16_t dx, dy;
     double inc;
+    source_image_class_t class;
 
-    source->class = SOURCE_IMAGE_CLASS_UNKNOWN;
+    class = SOURCE_IMAGE_CLASS_UNKNOWN;
 
     if (source->common.transform)
     {
@@ -54,7 +55,7 @@ linear_gradient_classify (pixman_image_t *image,
 	    source->common.transform->matrix[2][1] != 0 ||
 	    source->common.transform->matrix[2][2] == 0)
 	{
-	    return source->class;
+	    return class;
 	}
 
 	v.vector[0] = source->common.transform->matrix[0][1];
@@ -74,7 +75,7 @@ linear_gradient_classify (pixman_image_t *image,
     l = dx * dx + dy * dy;
 
     if (l == 0)
-	return source->class;	
+	return class;	
 
     /*
      * compute how much the input of the gradient walked changes
@@ -86,9 +87,9 @@ linear_gradient_classify (pixman_image_t *image,
 
     /* check that casting to integer would result in 0 */
     if (-1 < inc && inc < 1)
-	source->class = SOURCE_IMAGE_CLASS_HORIZONTAL;
+	class = SOURCE_IMAGE_CLASS_HORIZONTAL;
 
-    return source->class;
+    return class;
 }
 
 static void
@@ -253,7 +254,6 @@ pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
     linear->p2 = *p2;
 
     image->type = LINEAR;
-    image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
     image->common.classify = linear_gradient_classify;
     image->common.property_changed = linear_gradient_property_changed;
 
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 77f629a..c43172b 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -111,7 +111,6 @@ struct image_common
 struct source_image
 {
     image_common_t common;
-    source_image_class_t class;
 };
 
 struct solid_fill
diff --git a/pixman/pixman-solid-fill.c b/pixman/pixman-solid-fill.c
index 44f3362..1d911e9 100644
--- a/pixman/pixman-solid-fill.c
+++ b/pixman/pixman-solid-fill.c
@@ -66,7 +66,7 @@ solid_fill_classify (pixman_image_t *image,
                      int             width,
                      int             height)
 {
-    return (image->source.class = SOURCE_IMAGE_CLASS_HORIZONTAL);
+    return SOURCE_IMAGE_CLASS_HORIZONTAL;
 }
 
 static void
@@ -109,7 +109,6 @@ pixman_image_create_solid_fill (pixman_color_t *color)
     img->solid.color_32 = color_to_uint32 (color);
     img->solid.color_64 = color_to_uint64 (color);
 
-    img->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
     img->common.classify = solid_fill_classify;
     img->common.property_changed = solid_fill_property_changed;
 
commit 741c30d9d9cf445fa2e3a2c43d37c221d49831b4
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Wed Oct 20 21:24:32 2010 +0200

    Remove unused enum value
    
    The new linear gradient code doesn't use SOURCE_IMAGE_CLASS_VERTICAL
    anymore and it was not used anywhere else.

diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 71b96c1..77f629a 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -65,7 +65,6 @@ typedef enum
 {
     SOURCE_IMAGE_CLASS_UNKNOWN,
     SOURCE_IMAGE_CLASS_HORIZONTAL,
-    SOURCE_IMAGE_CLASS_VERTICAL,
 } source_image_class_t;
 
 typedef source_image_class_t (*classify_func_t) (pixman_image_t *image,
commit 9b72fd1b857494ea928795c89a4f827e56fe26d3
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Mon Oct 18 22:21:52 2010 +0200

    Make classification consistent with rasterization
    
    Use the same computations to classify the gradient and to
    rasterize it.
    This improves the correctness of the classification by
    avoiding integer division.

diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index 0865594..c6ac980 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -38,58 +38,57 @@ linear_gradient_classify (pixman_image_t *image,
                           int             width,
                           int             height)
 {
+    source_image_t *source = (source_image_t *)image;
     linear_gradient_t *linear = (linear_gradient_t *)image;
     pixman_vector_t v;
     pixman_fixed_32_32_t l;
-    pixman_fixed_48_16_t dx, dy, a, b, off;
-    pixman_fixed_48_16_t factors[4];
-    int i;
+    pixman_fixed_48_16_t dx, dy;
+    double inc;
 
-    image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
+    source->class = SOURCE_IMAGE_CLASS_UNKNOWN;
 
-    dx = linear->p2.x - linear->p1.x;
-    dy = linear->p2.y - linear->p1.y;
-
-    l = dx * dx + dy * dy;
-
-    if (l)
+    if (source->common.transform)
     {
-	a = (dx << 32) / l;
-	b = (dy << 32) / l;
+	/* projective transformation */
+	if (source->common.transform->matrix[2][0] != 0 ||
+	    source->common.transform->matrix[2][1] != 0 ||
+	    source->common.transform->matrix[2][2] == 0)
+	{
+	    return source->class;
+	}
+
+	v.vector[0] = source->common.transform->matrix[0][1];
+	v.vector[1] = source->common.transform->matrix[1][1];
+	v.vector[2] = source->common.transform->matrix[2][2];
     }
     else
     {
-	a = b = 0;
+	v.vector[0] = 0;
+	v.vector[1] = pixman_fixed_1;
+	v.vector[2] = pixman_fixed_1;
     }
 
-    off = (-a * linear->p1.x
-           -b * linear->p1.y) >> 16;
-
-    for (i = 0; i < 3; i++)
-    {
-	v.vector[0] = pixman_int_to_fixed ((i % 2) * (width  - 1) + x);
-	v.vector[1] = pixman_int_to_fixed ((i / 2) * (height - 1) + y);
-	v.vector[2] = pixman_fixed_1;
+    dx = linear->p2.x - linear->p1.x;
+    dy = linear->p2.y - linear->p1.y;
 
-	if (image->common.transform)
-	{
-	    if (!pixman_transform_point_3d (image->common.transform, &v))
-	    {
-		image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
+    l = dx * dx + dy * dy;
 
-		return image->source.class;
-	    }
-	}
+    if (l == 0)
+	return source->class;	
 
-	factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
-    }
+    /*
+     * compute how much the input of the gradient walked changes
+     * when moving vertically through the whole image
+     */
+    inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
+	(dx * v.vector[0] + dy * v.vector[1]) /
+	(v.vector[2] * (double) l);
 
-    if (factors[2] == factors[0])
-	image->source.class = SOURCE_IMAGE_CLASS_HORIZONTAL;
-    else if (factors[1] == factors[0])
-	image->source.class = SOURCE_IMAGE_CLASS_VERTICAL;
+    /* check that casting to integer would result in 0 */
+    if (-1 < inc && inc < 1)
+	source->class = SOURCE_IMAGE_CLASS_HORIZONTAL;
 
-    return image->source.class;
+    return source->class;
 }
 
 static void
commit 1d4f2d71facd5f2bbce74fbe3407ccea6cf4bea1
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Wed Aug 11 09:58:05 2010 +0200

    Improve precision of linear gradients
    
    Integer division (without keeping the remainder) can discard a lot
    of information. Doing the division maths in floating point (and
    paying attention to error propagation) allows to greatly improve
    the precision of linear gradients.

diff --git a/pixman/pixman-linear-gradient.c b/pixman/pixman-linear-gradient.c
index 01588c1..0865594 100644
--- a/pixman/pixman-linear-gradient.c
+++ b/pixman/pixman-linear-gradient.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
 /*
  * Copyright © 2000 SuSE, Inc.
  * Copyright © 2007 Red Hat, Inc.
@@ -101,7 +102,7 @@ linear_gradient_get_scanline_32 (pixman_image_t *image,
 {
     pixman_vector_t v, unit;
     pixman_fixed_32_32_t l;
-    pixman_fixed_48_16_t dx, dy, a, b, off;
+    pixman_fixed_48_16_t dx, dy;
     gradient_t *gradient = (gradient_t *)image;
     source_image_t *source = (source_image_t *)image;
     linear_gradient_t *linear = (linear_gradient_t *)image;
@@ -136,31 +137,31 @@ linear_gradient_get_scanline_32 (pixman_image_t *image,
 
     l = dx * dx + dy * dy;
 
-    if (l != 0)
+    if (l == 0 || unit.vector[2] == 0)
     {
-	a = (dx << 32) / l;
-	b = (dy << 32) / l;
-	off = (-a * linear->p1.x
-	       -b * linear->p1.y) >> 16;
-    }
-
-    if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1))
-    {
-	pixman_fixed_48_16_t inc, t;
-
 	/* affine transformation only */
-	if (l == 0)
+        pixman_fixed_32_32_t t, next_inc;
+	double inc;
+
+	if (l == 0 || v.vector[2] == 0)
 	{
 	    t = 0;
 	    inc = 0;
 	}
 	else
 	{
-	    t = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
-	    inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
+	    double invden, v2;
+
+	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
+		(l * (double) v.vector[2]);
+	    v2 = v.vector[2] * (1. / pixman_fixed_1);
+	    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
+	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
 	}
+	next_inc = 0;
 
-	if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
+	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
 	{
 	    register uint32_t color;
 
@@ -170,81 +171,52 @@ linear_gradient_get_scanline_32 (pixman_image_t *image,
 	}
 	else
 	{
-	    if (!mask)
-	    {
-		while (buffer < end)
-		{
-		    *buffer++ = _pixman_gradient_walker_pixel (&walker, t);
-		    
-		    t += inc;
-		}
-	    }
-	    else
+	    int i;
+
+	    i = 0;
+	    while (buffer < end)
 	    {
-		while (buffer < end)
+		if (!mask || *mask++)
 		{
-		    if (*mask++)
-			*buffer = _pixman_gradient_walker_pixel (&walker, t);
-
-		    buffer++;
-		    t += inc;
+		    *buffer = _pixman_gradient_walker_pixel (&walker,
+							     t + next_inc);
 		}
+		i++;
+		next_inc = inc * i;
+		buffer++;
 	    }
 	}
     }
     else
     {
 	/* projective transformation */
-	pixman_fixed_48_16_t t;
+        double t;
 
-	if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
-	{
-	    register uint32_t color;
+	t = 0;
 
-	    if (v.vector[2] == 0)
-	    {
-		t = 0;
-	    }
-	    else
-	    {
-		pixman_fixed_48_16_t x, y;
-
-		x = ((pixman_fixed_48_16_t) v.vector[0] << 16) / v.vector[2];
-		y = ((pixman_fixed_48_16_t) v.vector[1] << 16) / v.vector[2];
-		t = ((a * x + b * y) >> 16) + off;
-	    }
-
-	    color = _pixman_gradient_walker_pixel (&walker, t);
-	    while (buffer < end)
-		*buffer++ = color;
-	}
-	else
+	while (buffer < end)
 	{
-	    while (buffer < end)
+	    if (!mask || *mask++)
 	    {
-		if (!mask || *mask++)
+	        if (v.vector[2] != 0)
 		{
-		    if (v.vector[2] == 0)
-		    {
-			t = 0;
-		    }
-		    else
-		    {
-			pixman_fixed_48_16_t x, y;
-			x = ((pixman_fixed_48_16_t)v.vector[0] << 16) / v.vector[2];
-			y = ((pixman_fixed_48_16_t)v.vector[1] << 16) / v.vector[2];
-			t = ((a * x + b * y) >> 16) + off;
-		    }
-
-		    *buffer = _pixman_gradient_walker_pixel (&walker, t);
-		}
+		    double invden, v2;
 
-		++buffer;
+		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
+			(l * (double) v.vector[2]);
+		    v2 = v.vector[2] * (1. / pixman_fixed_1);
+		    t = ((dx * v.vector[0] + dy * v.vector[1]) - 
+			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
+		}
 
-		v.vector[0] += unit.vector[0];
-		v.vector[1] += unit.vector[1];
-		v.vector[2] += unit.vector[2];
+		*buffer = _pixman_gradient_walker_pixel (&walker, t);
 	    }
+
+	    ++buffer;
+
+	    v.vector[0] += unit.vector[0];
+	    v.vector[1] += unit.vector[1];
+	    v.vector[2] += unit.vector[2];
 	}
     }
 }


More information about the xorg-commit mailing list