pixman: Branch 'master' - 7 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Wed Sep 21 16:12:18 PDT 2011


 pixman/pixman-fast-path.c |    2 
 pixman/pixman-image.c     |   41 ++++++
 pixman/pixman-inlines.h   |   12 +-
 pixman/pixman-private.h   |   19 +--
 pixman/pixman.c           |  272 +++++++++++++++++++++++++---------------------
 test/affine-test.c        |   40 +++++-
 test/blitters-test.c      |    5 
 7 files changed, 244 insertions(+), 147 deletions(-)

New commits:
commit 9126f36b964c71b83c69235df4c3a46ab81ab5d5
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Sun May 22 22:51:00 2011 +0300

    BILINEAR->NEAREST filter optimization for simple rotation and translation
    
    Simple rotation and translation are the additional cases when BILINEAR
    filter can be safely reduced to NEAREST.

diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 88262f7..a3bb9b6 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -251,9 +251,46 @@ compute_image_info (pixman_image_t *image)
     case PIXMAN_FILTER_BEST:
 	flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
 
-	/* Reduce BILINEAR to NEAREST for identity transforms */
+	/* Here we have a chance to optimize BILINEAR filter to NEAREST if
+	 * they are equivalent for the currently used transformation matrix.
+	 */
 	if (flags & FAST_PATH_ID_TRANSFORM)
+	{
 	    flags |= FAST_PATH_NEAREST_FILTER;
+	}
+	else if (
+	    /* affine and integer translation components in matrix ... */
+	    ((flags & FAST_PATH_AFFINE_TRANSFORM) &&
+	     !pixman_fixed_frac (image->common.transform->matrix[0][2] |
+				 image->common.transform->matrix[1][2])) &&
+	    (
+		/* ... combined with a simple rotation */
+		(flags & (FAST_PATH_ROTATE_90_TRANSFORM |
+			  FAST_PATH_ROTATE_180_TRANSFORM |
+			  FAST_PATH_ROTATE_270_TRANSFORM)) ||
+		/* ... or combined with a simple non-rotated translation */
+		(image->common.transform->matrix[0][0] == pixman_fixed_1 &&
+		 image->common.transform->matrix[1][1] == pixman_fixed_1 &&
+		 image->common.transform->matrix[0][1] == 0 &&
+		 image->common.transform->matrix[1][0] == 0)
+		)
+	    )
+	{
+	    /* FIXME: there are some affine-test failures, showing that
+	     * handling of BILINEAR and NEAREST filter is not quite
+	     * equivalent when getting close to 32K for the translation
+	     * components of the matrix. That's likely some bug, but for
+	     * now just skip BILINEAR->NEAREST optimization in this case.
+	     */
+	    pixman_fixed_t magic_limit = pixman_int_to_fixed (30000);
+	    if (image->common.transform->matrix[0][2] <= magic_limit  &&
+	        image->common.transform->matrix[1][2] <= magic_limit  &&
+	        image->common.transform->matrix[0][2] >= -magic_limit &&
+	        image->common.transform->matrix[1][2] >= -magic_limit)
+	    {
+		flags |= FAST_PATH_NEAREST_FILTER;
+	    }
+	}
 	break;
 
     case PIXMAN_FILTER_CONVOLUTION:
commit ad5c6bbb36c1c5e72313f7c7bc7c6e6b7e79daba
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Sep 4 02:53:39 2011 -0400

    Strength-reduce BILINEAR filter to NEAREST filter for identity transforms
    
    An image with a bilinear filter and an identity transform is
    equivalent to one with a nearest filter, so there is no reason the
    standard fast paths shouldn't be usable.
    
    But because a BILINEAR filter samples a 2x2 pixel block in the source
    image, FAST_PATH_SAMPLES_COVER_CLIP can't be set in the case where the
    source area is the entire image, because some compositing operations
    might then read pixels outside the image.
    
    This patch fixes the problem by splitting the
    FAST_PATH_SAMPLES_COVER_CLIP flag into two separate flags
    FAST_PATH_SAMPLES_COVER_CLIP_NEAREST and
    FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR that indicate that the clip
    covers the samples taking into account NEAREST/BILINEAR filters
    respectively.
    
    All the existing compositing operations that require
    FAST_PATH_SAMPLES_COVER_CLIP then have their flags modified to pick
    either COVER_CLIP_NEAREST or COVER_CLIP_BILINEAR depending on which
    filter they depend on.
    
    In compute_image_info() both COVER_CILP_NEAREST and
    COVER_CLIP_BILINEAR can be set depending on how much room there is
    around the clip rectangle.
    
    Finally, images with an identity transform and a bilinear filter get
    FAST_PATH_NEAREST_FILTER set as well as FAST_PATH_BILINEAR_FILTER.
    
    Performance measurementas with render_bench against Xephyr:
    
    Before
    
    *** ROUND 1 ***
    ---------------------------------------------------------------
    Test: Test Xrender doing non-scaled Over blends
    Time: 5.720 sec.
    ---------------------------------------------------------------
    Test: Test Xrender (offscreen) doing non-scaled Over blends
    Time: 5.149 sec.
    ---------------------------------------------------------------
    Test: Test Imlib2 doing non-scaled Over blends
    Time: 6.237 sec.
    
    After:
    
    *** ROUND 1 ***
    ---------------------------------------------------------------
    Test: Test Xrender doing non-scaled Over blends
    Time: 4.947 sec.
    ---------------------------------------------------------------
    Test: Test Xrender (offscreen) doing non-scaled Over blends
    Time: 4.487 sec.
    ---------------------------------------------------------------
    Test: Test Imlib2 doing non-scaled Over blends
    Time: 6.235 sec.

diff --git a/pixman/pixman-fast-path.c b/pixman/pixman-fast-path.c
index bbdc8e8..033efd7 100644
--- a/pixman/pixman-fast-path.c
+++ b/pixman/pixman-fast-path.c
@@ -1764,7 +1764,7 @@ static const pixman_fast_path_t c_fast_paths[] =
 #define SIMPLE_ROTATE_FLAGS(angle)					  \
     (FAST_PATH_ROTATE_ ## angle ## _TRANSFORM	|			  \
      FAST_PATH_NEAREST_FILTER			|			  \
-     FAST_PATH_SAMPLES_COVER_CLIP		|			  \
+     FAST_PATH_SAMPLES_COVER_CLIP_NEAREST	|			  \
      FAST_PATH_STANDARD_FLAGS)
 
 #define SIMPLE_ROTATE_FAST_PATH(op,s,d,suffix)				  \
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 84bacf8..88262f7 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -250,6 +250,10 @@ compute_image_info (pixman_image_t *image)
     case PIXMAN_FILTER_GOOD:
     case PIXMAN_FILTER_BEST:
 	flags |= (FAST_PATH_BILINEAR_FILTER | FAST_PATH_NO_CONVOLUTION_FILTER);
+
+	/* Reduce BILINEAR to NEAREST for identity transforms */
+	if (flags & FAST_PATH_ID_TRANSFORM)
+	    flags |= FAST_PATH_NEAREST_FILTER;
 	break;
 
     case PIXMAN_FILTER_CONVOLUTION:
diff --git a/pixman/pixman-inlines.h b/pixman/pixman-inlines.h
index f1e0cbd..3532867 100644
--- a/pixman/pixman-inlines.h
+++ b/pixman/pixman-inlines.h
@@ -585,7 +585,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func)			\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST,    \
 	PIXMAN_null, 0,							\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op,	\
@@ -627,7 +627,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func)		\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST,	\
 	PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA),		\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op,	\
@@ -669,7 +669,7 @@ fast_composite_scaled_nearest  ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func)		\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST,	\
 	PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA),	\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op,	\
@@ -1157,7 +1157,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func)			\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR,	\
 	PIXMAN_null, 0,							\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op,	\
@@ -1199,7 +1199,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func)		\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR,	\
 	PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA),		\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op,	\
@@ -1241,7 +1241,7 @@ fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp,
 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func)		\
     {   PIXMAN_OP_ ## op,						\
 	PIXMAN_ ## s,							\
-	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP,		\
+	SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR,	\
 	PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA),	\
 	PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS,				\
 	fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op,	\
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 90d9011..6e716c6 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -609,14 +609,15 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 #define FAST_PATH_IS_OPAQUE			(1 << 13)
 #define FAST_PATH_NO_NORMAL_REPEAT		(1 << 14)
 #define FAST_PATH_NO_NONE_REPEAT		(1 << 15)
-#define FAST_PATH_SAMPLES_COVER_CLIP		(1 << 16)
-#define FAST_PATH_X_UNIT_POSITIVE		(1 << 17)
-#define FAST_PATH_AFFINE_TRANSFORM		(1 << 18)
-#define FAST_PATH_Y_UNIT_ZERO			(1 << 19)
-#define FAST_PATH_BILINEAR_FILTER		(1 << 20)
-#define FAST_PATH_ROTATE_90_TRANSFORM		(1 << 21)
-#define FAST_PATH_ROTATE_180_TRANSFORM		(1 << 22)
-#define FAST_PATH_ROTATE_270_TRANSFORM		(1 << 23)
+#define FAST_PATH_X_UNIT_POSITIVE		(1 << 16)
+#define FAST_PATH_AFFINE_TRANSFORM		(1 << 17)
+#define FAST_PATH_Y_UNIT_ZERO			(1 << 18)
+#define FAST_PATH_BILINEAR_FILTER		(1 << 19)
+#define FAST_PATH_ROTATE_90_TRANSFORM		(1 << 20)
+#define FAST_PATH_ROTATE_180_TRANSFORM		(1 << 21)
+#define FAST_PATH_ROTATE_270_TRANSFORM		(1 << 22)
+#define FAST_PATH_SAMPLES_COVER_CLIP_NEAREST	(1 << 23)
+#define FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR	(1 << 24)
 
 #define FAST_PATH_PAD_REPEAT						\
     (FAST_PATH_NO_NONE_REPEAT		|				\
@@ -652,7 +653,7 @@ _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask);
 #define SOURCE_FLAGS(format)						\
     (FAST_PATH_STANDARD_FLAGS |						\
      ((PIXMAN_ ## format == PIXMAN_solid) ?				\
-      0 : (FAST_PATH_SAMPLES_COVER_CLIP | FAST_PATH_ID_TRANSFORM)))
+      0 : (FAST_PATH_SAMPLES_COVER_CLIP_NEAREST | FAST_PATH_NEAREST_FILTER | FAST_PATH_ID_TRANSFORM)))
 
 #define MASK_FLAGS(format, extra)					\
     ((PIXMAN_ ## format == PIXMAN_null) ? 0 : (SOURCE_FLAGS (format) | extra))
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 19eda08..87f5a93 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -524,9 +524,9 @@ analyze_extent (pixman_image_t       *image,
 		uint32_t             *flags)
 {
     pixman_transform_t *transform;
-    pixman_fixed_t *params;
     pixman_fixed_t x_off, y_off;
     pixman_fixed_t width, height;
+    pixman_fixed_t *params;
     box_48_16_t transformed;
     pixman_box32_t exp_extents;
 
@@ -556,15 +556,13 @@ analyze_extent (pixman_image_t       *image,
 	if (image->bits.width >= 0x7fff	|| image->bits.height >= 0x7fff)
 	    return FALSE;
 
-#define ID_AND_NEAREST (FAST_PATH_ID_TRANSFORM | FAST_PATH_NEAREST_FILTER)
-
-	if ((image->common.flags & ID_AND_NEAREST) == ID_AND_NEAREST &&
+	if ((image->common.flags & FAST_PATH_ID_TRANSFORM) == FAST_PATH_ID_TRANSFORM &&
 	    extents->x1 >= 0 &&
 	    extents->y1 >= 0 &&
 	    extents->x2 <= image->bits.width &&
 	    extents->y2 <= image->bits.height)
 	{
-	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP;
+	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
 	    return TRUE;
 	}
 
@@ -614,18 +612,28 @@ analyze_extent (pixman_image_t       *image,
      * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
      * 0.5 so this won't cause the area computed to be overly pessimistic.
      */
-    transformed.x1 += x_off - 8 * pixman_fixed_e;
-    transformed.y1 += y_off - 8 * pixman_fixed_e;
-    transformed.x2 += x_off + width + 8 * pixman_fixed_e;
-    transformed.y2 += y_off + height + 8 * pixman_fixed_e;
-
-    if (image->common.type == BITS					&&
-	pixman_fixed_to_int (transformed.x1) >= 0			&&
-	pixman_fixed_to_int (transformed.y1) >= 0			&&
-	pixman_fixed_to_int (transformed.x2) < image->bits.width	&&
-	pixman_fixed_to_int (transformed.y2) < image->bits.height)
+    transformed.x1 -= 8 * pixman_fixed_e;
+    transformed.y1 -= 8 * pixman_fixed_e;
+    transformed.x2 += 8 * pixman_fixed_e;
+    transformed.y2 += 8 * pixman_fixed_e;
+
+    if (image->common.type == BITS)
     {
-	*flags |= FAST_PATH_SAMPLES_COVER_CLIP;
+	if (pixman_fixed_to_int (transformed.x1) >= 0			&&
+	    pixman_fixed_to_int (transformed.y1) >= 0			&&
+	    pixman_fixed_to_int (transformed.x2) < image->bits.width	&&
+	    pixman_fixed_to_int (transformed.y2) < image->bits.height)
+	{
+	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST;
+	}
+
+	if (pixman_fixed_to_int (transformed.x1 - pixman_fixed_1 / 2) >= 0		  &&
+	    pixman_fixed_to_int (transformed.y1 - pixman_fixed_1 / 2) >= 0		  &&
+	    pixman_fixed_to_int (transformed.x2 + pixman_fixed_1 / 2) < image->bits.width &&
+	    pixman_fixed_to_int (transformed.y2 + pixman_fixed_1 / 2) < image->bits.height)
+	{
+	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR;
+	}
     }
 
     /* Check we don't overflow when the destination extents are expanded by one.
@@ -753,16 +761,27 @@ pixman_image_composite32 (pixman_op_t      op,
     if (!analyze_extent (mask, &extents, &mask_flags))
 	goto out;
 
-    /* If the clip is within the source samples, and the samples are opaque,
-     * then the source is effectively opaque.
+    /* If the clip is within the source samples, and the samples are
+     * opaque, then the source is effectively opaque.
      */
-#define BOTH (FAST_PATH_SAMPLES_OPAQUE | FAST_PATH_SAMPLES_COVER_CLIP)
-
-    if ((src_flags & BOTH) == BOTH)
+#define NEAREST_OPAQUE	(FAST_PATH_SAMPLES_OPAQUE |			\
+			 FAST_PATH_NEAREST_FILTER |			\
+			 FAST_PATH_SAMPLES_COVER_CLIP_NEAREST)
+#define BILINEAR_OPAQUE	(FAST_PATH_SAMPLES_OPAQUE |			\
+			 FAST_PATH_BILINEAR_FILTER |			\
+			 FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR)
+
+    if ((src_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE ||
+	(src_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE)
+    {
 	src_flags |= FAST_PATH_IS_OPAQUE;
+    }
 
-    if ((mask_flags & BOTH) == BOTH)
+    if ((mask_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE ||
+	(mask_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE)
+    {
 	mask_flags |= FAST_PATH_IS_OPAQUE;
+    }
 
     /*
      * Check if we can replace our operator by a simpler one
commit eb2e7ed81b324af730c1a7639c9ca9ed60152875
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Sep 5 14:43:25 2011 -0400

    test: Occasionally use a BILINEAR filter in blitters-test
    
    To test that reductions of BILINEAR->NEAREST for identity
    transformations happen correctly, occasionally use a bilinear filter
    in blitters test.

diff --git a/test/blitters-test.c b/test/blitters-test.c
index 790a27f..4f931c4 100644
--- a/test/blitters-test.c
+++ b/test/blitters-test.c
@@ -68,6 +68,9 @@ create_random_image (pixman_format_code_t *allowed_formats,
 	pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)]));
     }
 
+    if (lcg_rand_n (16) == 0)
+	pixman_image_set_filter (img, PIXMAN_FILTER_BILINEAR, NULL, 0);
+
     image_endian_swap (img);
 
     if (used_fmt) *used_fmt = fmt;
@@ -422,6 +425,6 @@ main (int argc, const char *argv[])
     }
 
     return fuzzer_test_main("blitters", 2000000,
-			    0xB610300B,
+			    0x29137844,
 			    test_composite, argc, argv);
 }
commit 2a9f88430e7088eccfbbbd6c6b4f4e534126b1e1
Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
Date:   Sun May 22 22:16:38 2011 +0300

    test: better coverage for BILINEAR->NEAREST filter optimization
    
    The upcoming optimization which is going to be able to replace BILINEAR filter
    with NEAREST where appropriate needs to analyze the transformation matrix
    and not to make any mistakes.
    
    The changes to affine-test include:
    1. Higher chance of using the same scale factor for x and y axes. This can help
       to stress some special cases (for example the case when both x and y scale
       factors are integer). The same applies to x/y translation.
    2. Introduced a small chance for "corrupting" transformation matrix by flipping
       random bits. This supposedly can help to identify the cases when some of the
       fast paths or other code logic is wrongly activated due to insufficient checks.

diff --git a/test/affine-test.c b/test/affine-test.c
index ed8000c..a4ceed3 100644
--- a/test/affine-test.c
+++ b/test/affine-test.c
@@ -99,14 +99,23 @@ test_composite (int      testnum,
     image_endian_swap (dst_img);
 
     pixman_transform_init_identity (&transform);
-    
-    if (lcg_rand_n (8) > 0)
+
+    if (lcg_rand_n (3) > 0)
     {
-	scale_x = -32768 * 3 + lcg_rand_N (65536 * 5);
-	scale_y = -32768 * 3 + lcg_rand_N (65536 * 5);
-	translate_x = lcg_rand_N (65536);
-	translate_y = lcg_rand_N (65536);
+	scale_x = -65536 * 3 + lcg_rand_N (65536 * 6);
+	if (lcg_rand_n (2))
+	    scale_y = -65536 * 3 + lcg_rand_N (65536 * 6);
+	else
+	    scale_y = scale_x;
 	pixman_transform_init_scale (&transform, scale_x, scale_y);
+    }
+    if (lcg_rand_n (3) > 0)
+    {
+	translate_x = -65536 * 3 + lcg_rand_N (6 * 65536);
+	if (lcg_rand_n (2))
+	    translate_y = -65536 * 3 + lcg_rand_N (6 * 65536);
+	else
+	    translate_y = translate_x;
 	pixman_transform_translate (&transform, NULL, translate_x, translate_y);
     }
 
@@ -144,8 +153,23 @@ test_composite (int      testnum,
 	pixman_transform_translate (&transform, NULL, tx, ty);
     }
 
+    if (lcg_rand_n (8) == 0)
+    {
+	/* Flip random bits */
+	int maxflipcount = 8;
+	while (maxflipcount--)
+	{
+	    int i = lcg_rand_n (2);
+	    int j = lcg_rand_n (3);
+	    int bitnum = lcg_rand_n (32);
+	    transform.matrix[i][j] ^= 1 << bitnum;
+	    if (lcg_rand_n (2))
+		break;
+	}
+    }
+
     pixman_image_set_transform (src_img, &transform);
-    
+
     switch (lcg_rand_n (4))
     {
     case 0:
@@ -282,6 +306,6 @@ main (int argc, const char *argv[])
 {
     pixman_disable_out_of_bounds_workaround ();
 
-    return fuzzer_test_main ("affine", 8000000, 0x4B5D1852,
+    return fuzzer_test_main ("affine", 8000000, 0x1EF2175A,
 			     test_composite, argc, argv);
 }
commit 054922e2fce1f8d9db4b9b756e54b0fa5655956d
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Mon Sep 5 00:19:51 2011 -0400

    Eliminate compute_sample_extents() function
    
    In analyze_extents(), instead of calling compute_sample_extents() call
    compute_transformed_extents() and inline the remaining part of
    compute_sample_extents(). The upcoming bilinear->nearest optimization
    will do something different with these two pieces of code.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index c15dd73..19eda08 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -514,45 +514,9 @@ compute_transformed_extents (pixman_transform_t *transform,
     return TRUE;
 }
 
-static pixman_bool_t
-compute_sample_extents (pixman_transform_t *transform,
-			pixman_box32_t *extents,
-			pixman_fixed_t x_off, pixman_fixed_t y_off,
-			pixman_fixed_t width, pixman_fixed_t height)
-{
-    box_48_16_t transformed;
-
-    if (!compute_transformed_extents (transform, extents, &transformed))
-	return FALSE;
-
-    /* Expand the source area by a tiny bit so account of different rounding that
-     * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
-     * 0.5 so this won't cause the area computed to be overly pessimistic.
-     */
-    transformed.x1 += x_off - 8 * pixman_fixed_e;
-    transformed.y1 += y_off - 8 * pixman_fixed_e;
-    transformed.x2 += x_off + width + 8 * pixman_fixed_e;
-    transformed.y2 += y_off + height + 8 * pixman_fixed_e;
-
-    if (transformed.x1 < pixman_min_fixed_48_16 || transformed.x1 > pixman_max_fixed_48_16 ||
-	transformed.y1 < pixman_min_fixed_48_16 || transformed.y1 > pixman_max_fixed_48_16 ||
-	transformed.x2 < pixman_min_fixed_48_16 || transformed.x2 > pixman_max_fixed_48_16 ||
-	transformed.y2 < pixman_min_fixed_48_16 || transformed.y2 > pixman_max_fixed_48_16)
-    {
-	return FALSE;
-    }
-    else
-    {
-	extents->x1 = pixman_fixed_to_int (transformed.x1);
-	extents->y1 = pixman_fixed_to_int (transformed.y1);
-	extents->x2 = pixman_fixed_to_int (transformed.x2) + 1;
-	extents->y2 = pixman_fixed_to_int (transformed.y2) + 1;
-
-	return TRUE;
-    }
-}
-
 #define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX))
+#define ABS(f)      (((f) < 0)?  (-(f)) : (f))
+#define IS_16_16(f) (((f) >= pixman_min_fixed_48_16 && ((f) <= pixman_max_fixed_48_16)))
 
 static pixman_bool_t
 analyze_extent (pixman_image_t       *image,
@@ -563,7 +527,8 @@ analyze_extent (pixman_image_t       *image,
     pixman_fixed_t *params;
     pixman_fixed_t x_off, y_off;
     pixman_fixed_t width, height;
-    pixman_box32_t ex;
+    box_48_16_t transformed;
+    pixman_box32_t exp_extents;
 
     if (!image)
 	return TRUE;
@@ -633,17 +598,6 @@ analyze_extent (pixman_image_t       *image,
 	default:
 	    return FALSE;
 	}
-
-	/* Check whether the non-expanded, transformed extent is entirely within
-	 * the source image, and set the FAST_PATH_SAMPLES_COVER_CLIP if it is.
-	 */
-	ex = *extents;
-	if (compute_sample_extents (transform, &ex, x_off, y_off, width, height) &&
-	    ex.x1 >= 0 && ex.y1 >= 0 &&
-	    ex.x2 <= image->bits.width && ex.y2 <= image->bits.height)
-	{
-	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP;
-	}
     }
     else
     {
@@ -653,17 +607,47 @@ analyze_extent (pixman_image_t       *image,
 	height = 0;
     }
 
-    /* Check that the extents expanded by one don't overflow. This ensures that
-     * compositing functions can simply walk the source space using 16.16
-     * variables without worrying about overflow.
+    if (!compute_transformed_extents (transform, extents, &transformed))
+	return FALSE;
+
+    /* Expand the source area by a tiny bit so account of different rounding that
+     * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
+     * 0.5 so this won't cause the area computed to be overly pessimistic.
      */
-    ex.x1 = extents->x1 - 1;
-    ex.y1 = extents->y1 - 1;
-    ex.x2 = extents->x2 + 1;
-    ex.y2 = extents->y2 + 1;
+    transformed.x1 += x_off - 8 * pixman_fixed_e;
+    transformed.y1 += y_off - 8 * pixman_fixed_e;
+    transformed.x2 += x_off + width + 8 * pixman_fixed_e;
+    transformed.y2 += y_off + height + 8 * pixman_fixed_e;
+
+    if (image->common.type == BITS					&&
+	pixman_fixed_to_int (transformed.x1) >= 0			&&
+	pixman_fixed_to_int (transformed.y1) >= 0			&&
+	pixman_fixed_to_int (transformed.x2) < image->bits.width	&&
+	pixman_fixed_to_int (transformed.y2) < image->bits.height)
+    {
+	*flags |= FAST_PATH_SAMPLES_COVER_CLIP;
+    }
 
-    if (!compute_sample_extents (transform, &ex, x_off, y_off, width, height))
+    /* Check we don't overflow when the destination extents are expanded by one.
+     * This ensures that compositing functions can simply walk the source space
+     * using 16.16 variables without worrying about overflow.
+     */
+    exp_extents = *extents;
+    exp_extents.x1 -= 1;
+    exp_extents.y1 -= 1;
+    exp_extents.x2 += 1;
+    exp_extents.y2 += 1;
+
+    if (!compute_transformed_extents (transform, &exp_extents, &transformed))
+	return FALSE;
+    
+    if (!IS_16_16 (transformed.x1 + x_off - 8 * pixman_fixed_e)	||
+	!IS_16_16 (transformed.y1 + y_off - 8 * pixman_fixed_e)	||
+	!IS_16_16 (transformed.x2 + x_off + 8 * pixman_fixed_e + width)	||
+	!IS_16_16 (transformed.y2 + y_off + 8 * pixman_fixed_e + height))
+    {
 	return FALSE;
+    }
 
     return TRUE;
 }
commit 577b6c46fd39c43c2c328fed48854b50b9e85e5b
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Sep 4 17:43:29 2011 -0400

    Split computation of sample area into own function
    
    compute_sample_extents() have two parts: one that computes the
    transformed extents, and one that checks whether the computed extents
    fit within the 16.16 coordinate space.
    
    Split the first part into its own function
    compute_transformed_extents().

diff --git a/pixman/pixman.c b/pixman/pixman.c
index 9af6e2f..c15dd73 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -446,93 +446,107 @@ update_cache:
     return TRUE;
 }
 
+typedef struct
+{
+    pixman_fixed_48_16_t	x1;
+    pixman_fixed_48_16_t	y1;
+    pixman_fixed_48_16_t	x2;
+    pixman_fixed_48_16_t	y2;
+} box_48_16_t;
+
 static pixman_bool_t
-compute_sample_extents (pixman_transform_t *transform,
-			pixman_box32_t *extents,
-			pixman_fixed_t x_off, pixman_fixed_t y_off,
-			pixman_fixed_t width, pixman_fixed_t height)
+compute_transformed_extents (pixman_transform_t *transform,
+			     const pixman_box32_t *extents,
+			     box_48_16_t *transformed)
 {
-    pixman_fixed_t x1, y1, x2, y2;
     pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
+    pixman_fixed_t x1, y1, x2, y2;
+    int i;
 
-    /* We have checked earlier that (extents->x1 - x) etc. fit in a pixman_fixed_t */
-    x1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2;
-    y1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2;
-    x2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2;
-    y2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2;
+    x1 = pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2;
+    y1 = pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2;
+    x2 = pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2;
+    y2 = pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2;
 
     if (!transform)
     {
-	tx1 = (pixman_fixed_48_16_t)x1;
-	ty1 = (pixman_fixed_48_16_t)y1;
-	tx2 = (pixman_fixed_48_16_t)x2;
-	ty2 = (pixman_fixed_48_16_t)y2;
+	transformed->x1 = x1;
+	transformed->y1 = y1;
+	transformed->x2 = x2;
+	transformed->y2 = y2;
+
+	return TRUE;
     }
-    else
+
+    tx1 = ty1 = INT64_MAX;
+    tx2 = ty2 = INT64_MIN;
+
+    for (i = 0; i < 4; ++i)
     {
-	int i;
+	pixman_fixed_48_16_t tx, ty;
+	pixman_vector_t v;
 
-	/* Silence GCC */
-	tx1 = ty1 = tx2 = ty2 = 0;
+	v.vector[0] = (i & 0x01)? x1 : x2;
+	v.vector[1] = (i & 0x02)? y1 : y2;
+	v.vector[2] = pixman_fixed_1;
 
-	for (i = 0; i < 4; ++i)
-	{
-	    pixman_fixed_48_16_t tx, ty;
-	    pixman_vector_t v;
+	if (!pixman_transform_point (transform, &v))
+	    return FALSE;
 
-	    v.vector[0] = (i & 0x01)? x1 : x2;
-	    v.vector[1] = (i & 0x02)? y1 : y2;
-	    v.vector[2] = pixman_fixed_1;
+	tx = (pixman_fixed_48_16_t)v.vector[0];
+	ty = (pixman_fixed_48_16_t)v.vector[1];
+
+	if (tx < tx1)
+	    tx1 = tx;
+	if (ty < ty1)
+	    ty1 = ty;
+	if (tx > tx2)
+	    tx2 = tx;
+	if (ty > ty2)
+	    ty2 = ty;
+    }
 
-	    if (!pixman_transform_point (transform, &v))
-		return FALSE;
+    transformed->x1 = tx1;
+    transformed->y1 = ty1;
+    transformed->x2 = tx2;
+    transformed->y2 = ty2;
 
-	    tx = (pixman_fixed_48_16_t)v.vector[0];
-	    ty = (pixman_fixed_48_16_t)v.vector[1];
+    return TRUE;
+}
 
-	    if (i == 0)
-	    {
-		tx1 = tx;
-		ty1 = ty;
-		tx2 = tx;
-		ty2 = ty;
-	    }
-	    else
-	    {
-		if (tx < tx1)
-		    tx1 = tx;
-		if (ty < ty1)
-		    ty1 = ty;
-		if (tx > tx2)
-		    tx2 = tx;
-		if (ty > ty2)
-		    ty2 = ty;
-	    }
-	}
-    }
+static pixman_bool_t
+compute_sample_extents (pixman_transform_t *transform,
+			pixman_box32_t *extents,
+			pixman_fixed_t x_off, pixman_fixed_t y_off,
+			pixman_fixed_t width, pixman_fixed_t height)
+{
+    box_48_16_t transformed;
+
+    if (!compute_transformed_extents (transform, extents, &transformed))
+	return FALSE;
 
     /* Expand the source area by a tiny bit so account of different rounding that
      * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from
      * 0.5 so this won't cause the area computed to be overly pessimistic.
      */
-    tx1 += x_off - 8 * pixman_fixed_e;
-    ty1 += y_off - 8 * pixman_fixed_e;
-    tx2 += x_off + width + 8 * pixman_fixed_e;
-    ty2 += y_off + height + 8 * pixman_fixed_e;
-
-    if (tx1 < pixman_min_fixed_48_16 || tx1 > pixman_max_fixed_48_16 ||
-	ty1 < pixman_min_fixed_48_16 || ty1 > pixman_max_fixed_48_16 ||
-	tx2 < pixman_min_fixed_48_16 || tx2 > pixman_max_fixed_48_16 ||
-	ty2 < pixman_min_fixed_48_16 || ty2 > pixman_max_fixed_48_16)
+    transformed.x1 += x_off - 8 * pixman_fixed_e;
+    transformed.y1 += y_off - 8 * pixman_fixed_e;
+    transformed.x2 += x_off + width + 8 * pixman_fixed_e;
+    transformed.y2 += y_off + height + 8 * pixman_fixed_e;
+
+    if (transformed.x1 < pixman_min_fixed_48_16 || transformed.x1 > pixman_max_fixed_48_16 ||
+	transformed.y1 < pixman_min_fixed_48_16 || transformed.y1 > pixman_max_fixed_48_16 ||
+	transformed.x2 < pixman_min_fixed_48_16 || transformed.x2 > pixman_max_fixed_48_16 ||
+	transformed.y2 < pixman_min_fixed_48_16 || transformed.y2 > pixman_max_fixed_48_16)
     {
 	return FALSE;
     }
     else
     {
-	extents->x1 = pixman_fixed_to_int (tx1);
-	extents->y1 = pixman_fixed_to_int (ty1);
-	extents->x2 = pixman_fixed_to_int (tx2) + 1;
-	extents->y2 = pixman_fixed_to_int (ty2) + 1;
+	extents->x1 = pixman_fixed_to_int (transformed.x1);
+	extents->y1 = pixman_fixed_to_int (transformed.y1);
+	extents->x2 = pixman_fixed_to_int (transformed.x2) + 1;
+	extents->y2 = pixman_fixed_to_int (transformed.y2) + 1;
 
 	return TRUE;
     }
commit 5064f1803136cbc28d1e9f636feb2ff8ccfbdded
Author: Søren Sandmann Pedersen <ssp at redhat.com>
Date:   Sun Sep 4 17:17:53 2011 -0400

    Remove x and y coordinates from analyze_extents() and compute_sample_extents()
    
    These coordinates were only ever used for subtracting from the extents
    box to put it into the coordinate space of the image, so we might as
    well do this coordinate translation only once before entering the
    functions.

diff --git a/pixman/pixman.c b/pixman/pixman.c
index 75b80c0..9af6e2f 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -448,7 +448,7 @@ update_cache:
 
 static pixman_bool_t
 compute_sample_extents (pixman_transform_t *transform,
-			pixman_box32_t *extents, int x, int y, 
+			pixman_box32_t *extents,
 			pixman_fixed_t x_off, pixman_fixed_t y_off,
 			pixman_fixed_t width, pixman_fixed_t height)
 {
@@ -456,10 +456,10 @@ compute_sample_extents (pixman_transform_t *transform,
     pixman_fixed_48_16_t tx1, ty1, tx2, ty2;
 
     /* We have checked earlier that (extents->x1 - x) etc. fit in a pixman_fixed_t */
-    x1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x1 - x) + pixman_fixed_1 / 2;
-    y1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y1 - y) + pixman_fixed_1 / 2;
-    x2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x2 - x) - pixman_fixed_1 / 2;
-    y2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y2 - y) - pixman_fixed_1 / 2;
+    x1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2;
+    y1 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2;
+    x2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2;
+    y2 = (pixman_fixed_48_16_t)pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2;
 
     if (!transform)
     {
@@ -474,7 +474,7 @@ compute_sample_extents (pixman_transform_t *transform,
 
 	/* Silence GCC */
 	tx1 = ty1 = tx2 = ty2 = 0;
-    
+
 	for (i = 0; i < 4; ++i)
 	{
 	    pixman_fixed_48_16_t tx, ty;
@@ -541,8 +541,9 @@ compute_sample_extents (pixman_transform_t *transform,
 #define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX))
 
 static pixman_bool_t
-analyze_extent (pixman_image_t *image, int x, int y,
-		const pixman_box32_t *extents, uint32_t *flags)
+analyze_extent (pixman_image_t       *image,
+		const pixman_box32_t *extents,
+		uint32_t             *flags)
 {
     pixman_transform_t *transform;
     pixman_fixed_t *params;
@@ -558,10 +559,10 @@ analyze_extent (pixman_image_t *image, int x, int y,
      * check here that the expanded-by-one source
      * extents in destination space fits in 16 bits
      */
-    if (!IS_16BIT (extents->x1 - x - 1)		||
-	!IS_16BIT (extents->y1 - y - 1)		||
-	!IS_16BIT (extents->x2 - x + 1)		||
-	!IS_16BIT (extents->y2 - y + 1))
+    if (!IS_16BIT (extents->x1 - 1)		||
+	!IS_16BIT (extents->y1 - 1)		||
+	!IS_16BIT (extents->x2 + 1)		||
+	!IS_16BIT (extents->y2 + 1))
     {
 	return FALSE;
     }
@@ -577,17 +578,17 @@ analyze_extent (pixman_image_t *image, int x, int y,
 	    return FALSE;
 
 #define ID_AND_NEAREST (FAST_PATH_ID_TRANSFORM | FAST_PATH_NEAREST_FILTER)
-	
+
 	if ((image->common.flags & ID_AND_NEAREST) == ID_AND_NEAREST &&
-	    extents->x1 - x >= 0 &&
-	    extents->y1 - y >= 0 &&
-	    extents->x2 - x <= image->bits.width &&
-	    extents->y2 - y <= image->bits.height)
+	    extents->x1 >= 0 &&
+	    extents->y1 >= 0 &&
+	    extents->x2 <= image->bits.width &&
+	    extents->y2 <= image->bits.height)
 	{
 	    *flags |= FAST_PATH_SAMPLES_COVER_CLIP;
 	    return TRUE;
 	}
-    
+
 	switch (image->common.filter)
 	{
 	case PIXMAN_FILTER_CONVOLUTION:
@@ -623,7 +624,7 @@ analyze_extent (pixman_image_t *image, int x, int y,
 	 * the source image, and set the FAST_PATH_SAMPLES_COVER_CLIP if it is.
 	 */
 	ex = *extents;
-	if (compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height) &&
+	if (compute_sample_extents (transform, &ex, x_off, y_off, width, height) &&
 	    ex.x1 >= 0 && ex.y1 >= 0 &&
 	    ex.x2 <= image->bits.width && ex.y2 <= image->bits.height)
 	{
@@ -647,7 +648,7 @@ analyze_extent (pixman_image_t *image, int x, int y,
     ex.x2 = extents->x2 + 1;
     ex.y2 = extents->y2 + 1;
 
-    if (!compute_sample_extents (transform, &ex, x, y, x_off, y_off, width, height))
+    if (!compute_sample_extents (transform, &ex, x_off, y_off, width, height))
 	return FALSE;
 
     return TRUE;
@@ -689,7 +690,7 @@ pixman_image_composite32 (pixman_op_t      op,
     pixman_format_code_t src_format, mask_format, dest_format;
     uint32_t src_flags, mask_flags, dest_flags;
     pixman_region32_t region;
-    pixman_box32_t *extents;
+    pixman_box32_t extents;
     pixman_implementation_t *imp;
     pixman_composite_func_t func;
 
@@ -736,12 +737,22 @@ pixman_image_composite32 (pixman_op_t      op,
 	goto out;
     }
 
-    extents = pixman_region32_extents (&region);
+    extents = *pixman_region32_extents (&region);
+
+    extents.x1 -= dest_x - src_x;
+    extents.y1 -= dest_y - src_y;
+    extents.x2 -= dest_x - src_x;
+    extents.y2 -= dest_y - src_y;
 
-    if (!analyze_extent (src, dest_x - src_x, dest_y - src_y, extents, &src_flags))
+    if (!analyze_extent (src, &extents, &src_flags))
 	goto out;
 
-    if (!analyze_extent (mask, dest_x - mask_x, dest_y - mask_y, extents, &mask_flags))
+    extents.x1 -= src_x - mask_x;
+    extents.y1 -= src_y - mask_y;
+    extents.x2 -= src_x - mask_x;
+    extents.y2 -= src_y - mask_y;
+
+    if (!analyze_extent (mask, &extents, &mask_flags))
 	goto out;
 
     /* If the clip is within the source samples, and the samples are opaque,
@@ -751,10 +762,10 @@ pixman_image_composite32 (pixman_op_t      op,
 
     if ((src_flags & BOTH) == BOTH)
 	src_flags |= FAST_PATH_IS_OPAQUE;
-    
+
     if ((mask_flags & BOTH) == BOTH)
 	mask_flags |= FAST_PATH_IS_OPAQUE;
-    
+
     /*
      * Check if we can replace our operator by a simpler one
      * if the src or dest are opaque. The output operator should be


More information about the xorg-commit mailing list