[PATCH] Add new compute_sample_extents() and use it for FAST_PATH_SAMPLES_COVER_CLIP

Søren Sandmann Pedersen ssp at redhat.com
Thu Jul 22 01:27:45 PDT 2010


Previously we were using pixman_transform_bounds() to compute which
source samples would be used for a composite operation. This is
incorrect though because (a) pixman_transform_bounds() is transforming
the bounding box of the destination samples, which means it is too
pessimistic, (b) it isn't rounding the same way as we do during
sampling, which could make it too optimistic in some cases, and (c) it
didn't take the filter of the operation into account.

The new function takes care of all three issues.
---
 pixman/pixman.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 107 insertions(+), 8 deletions(-)

diff --git a/pixman/pixman.c b/pixman/pixman.c
index 80a766a..9d184ed 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -488,6 +488,108 @@ walk_region_internal (pixman_implementation_t *imp,
     }
 }
 
+static pixman_bool_t
+compute_sample_extent (pixman_image_t *image,
+		       pixman_box16_t *box)
+{
+    pixman_transform_t *transform = image->common.transform;
+    pixman_filter_t filter = image->common.filter;
+    int x1, y1, x2, y2;
+    pixman_fixed_t *params;
+    pixman_fixed_t x_off, y_off;
+    int width, height;
+    pixman_vector_t v[4];
+    int i;
+
+    switch (filter)
+    {
+    case PIXMAN_FILTER_CONVOLUTION:
+	params = image->common.filter_params;
+	x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1);
+	y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1);
+	width = pixman_fixed_to_int (params[0]);
+	height = pixman_fixed_to_int (params[1]);
+	break;
+
+    case PIXMAN_FILTER_GOOD:
+    case PIXMAN_FILTER_BEST:
+    case PIXMAN_FILTER_BILINEAR:
+	x_off = - pixman_fixed_1 / 2;
+	y_off = - pixman_fixed_1 / 2;
+	width = 1;
+	height = 1;
+	break;
+
+    case PIXMAN_FILTER_FAST:
+    case PIXMAN_FILTER_NEAREST:
+	x_off = - pixman_fixed_e;
+	y_off = - pixman_fixed_e;
+	width = 0;
+	height = 0;
+	break;
+
+    default:
+	return FALSE;
+    }
+
+    if (!transform)
+    {
+	box->x1 = pixman_fixed_to_int (pixman_int_to_fixed (box->x1) + pixman_fixed_1 / 2 + x_off);
+	box->y1 = pixman_fixed_to_int (pixman_int_to_fixed (box->y1) + pixman_fixed_1 / 2 + y_off);
+	box->x2 = pixman_fixed_to_int (pixman_int_to_fixed (box->x2) - pixman_fixed_1 / 2 + x_off) + width + 1;
+	box->y2 = pixman_fixed_to_int (pixman_int_to_fixed (box->y2) - pixman_fixed_1 / 2 + y_off) + height + 1;
+	return TRUE;
+    }
+    
+    v[0].vector[0] = pixman_int_to_fixed (box->x1) + pixman_fixed_1 / 2;
+    v[0].vector[1] = pixman_int_to_fixed (box->y1) + pixman_fixed_1 / 2;
+    v[0].vector[2] = pixman_int_to_fixed (1);
+
+    v[1].vector[0] = pixman_int_to_fixed (box->x2) - pixman_fixed_1 / 2;
+    v[1].vector[1] = pixman_int_to_fixed (box->y1) + pixman_fixed_1 / 2;
+    v[1].vector[2] = pixman_int_to_fixed (1);
+
+    v[2].vector[0] = pixman_int_to_fixed (box->x2) - pixman_fixed_1 / 2;
+    v[2].vector[1] = pixman_int_to_fixed (box->y2) - pixman_fixed_1 / 2;
+    v[2].vector[2] = pixman_int_to_fixed (1);
+
+    v[3].vector[0] = pixman_int_to_fixed (box->x1) + pixman_fixed_1 / 2;
+    v[3].vector[1] = pixman_int_to_fixed (box->y2) - pixman_fixed_1 / 2;
+    v[3].vector[2] = pixman_int_to_fixed (1);
+
+    for (i = 0; i < 4; ++i)
+    {
+	if (!pixman_transform_point (transform, &v[i]))
+	    return FALSE;
+
+	x1 = pixman_fixed_to_int (v[i].vector[0] + x_off);
+	y1 = pixman_fixed_to_int (v[i].vector[1] + y_off);
+	x2 = x1 + width + 1;
+	y2 = y1 + height + 1;
+
+	if (i == 0)
+	{
+	    box->x1 = x1;
+	    box->y1 = y1;
+	    box->x2 = x2;
+	    box->y2 = y2;
+	}
+	else
+	{
+	    if (x1 < box->x1)
+		box->x1 = x1;
+	    if (y1 < box->y1)
+		box->y1 = y1;
+	    if (x2 > box->x2)
+		box->x2 = x2;
+	    if (y2 > box->y2)
+		box->y2 = y2;
+	}
+    }
+
+    return TRUE;
+}
+
 #define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX))
 
 static force_inline uint32_t
@@ -522,15 +624,12 @@ compute_src_extents_flags (pixman_image_t *image,
 	extents16.x2 = extents->x2 - x;
 	extents16.y2 = extents->y2 - y;
 
-	if (!image->common.transform ||
-	    pixman_transform_bounds (image->common.transform, &extents16))
+	if (compute_sample_extent (image, &extents16) &&
+	    extents16.x1 >= 0  && extents16.y1 >= 0 &&
+	    extents16.x2 <= image->bits.width &&
+	    extents16.y2 <= image->bits.height)
 	{
-	    if (extents16.x1 >= 0  && extents16.y1 >= 0 &&
-		extents16.x2 <= image->bits.width &&
-		extents16.y2 <= image->bits.height)
-	    {
-		flags |= FAST_PATH_SAMPLES_COVER_CLIP;
-	    }
+	    flags |= FAST_PATH_SAMPLES_COVER_CLIP;
 	}
     }
 
-- 
1.7.0.1


More information about the Pixman mailing list