Inline fetch functions in pixman-transformed.c
authorSøren Sandmann Pedersen <sandmann@daimi.au.dk>
Thu, 18 Sep 2008 23:28:31 +0000 (19:28 -0400)
committerSøren Sandmann Pedersen <sandmann@daimi.au.dk>
Thu, 18 Sep 2008 23:28:31 +0000 (19:28 -0400)
There was significant performance overhead associated with indirect
call to the fetch functions, so inline them.

Also, the old code assumed that if the number of rectangles in the
source clip was 1, then the clip was identical to the image
boundaries. Fix that by running a full region_contains_point()
whenever the source clip is different from pict->common.full_region.

Based on a patch from Antoine Azar.

pixman/pixman-region.c
pixman/pixman-transformed.c

index 559454a..3718d65 100644 (file)
@@ -1998,7 +1998,9 @@ PREFIX(_contains_point) (region_type_t * region,
         return(FALSE);
     if (numRects == 1)
     {
-       *box = region->extents;
+        if (box)
+           *box = region->extents;
+
        return(TRUE);
     }
     for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
@@ -2011,7 +2013,10 @@ PREFIX(_contains_point) (region_type_t * region,
           break;               /* missed it */
        if (x >= pbox->x2)
           continue;            /* not there yet */
-       *box = *pbox;
+
+        if (box)
+           *box = *pbox;
+
        return(TRUE);
     }
     return(FALSE);
index 5ad92ae..fca1cdb 100644 (file)
  */
 typedef FASTCALL uint32_t (*fetchFromRegionProc)(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc32 fetch, pixman_box32_t *box);
 
+/*
+ * There are two properties we can make use of when fetching pixels
+ *
+ * (a) Is the source clip just the image itself?
+ *
+ * (b) Do we know the coordinates of the pixel to fetch are
+ *     within the image boundaries;
+ *
+ * Source clips are almost never used, so the important case to optimize
+ * for is when src_clip is false. Since inside_bounds is statically known,
+ * the last part of the if statement will normally be optimized away.
+ */
 static inline uint32_t
-fbFetchFromNoRegion(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc32 fetch, pixman_box32_t *box)
+do_fetch (bits_image_t *pict, int x, int y, fetchPixelProc32 fetch,
+         pixman_bool_t src_clip,
+         pixman_bool_t inside_bounds)
 {
-    return fetch (pict, x, y);
-}
-
-static uint32_t
-fbFetchFromNRectangles(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc32 fetch, pixman_box32_t *box)
-{
-    pixman_box32_t box2;
-    if (pixman_region32_contains_point (pict->common.src_clip, x, y, &box2))
-        return fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+    if (src_clip)
+    {
+       if (pixman_region32_contains_point (pict->common.src_clip, x, y,NULL))
+           return fetch (pict, x, y);
+       else
+           return 0;
+    }
+    else if (inside_bounds)
+    {
+       return fetch (pict, x, y);
+    }
     else
-        return 0;
-}
-
-static uint32_t
-fbFetchFromOneRectangle(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc32 fetch, pixman_box32_t *box)
-{
-    pixman_box32_t box2 = *box;
-    return ((x < box2.x1) | (x >= box2.x2) | (y < box2.y1) | (y >= box2.y2)) ?
-        0 : fbFetchFromNoRegion(pict, x, y, buffer, fetch, box);
+    {
+       if (x >= 0 && x < pict->width && y >= 0 && y < pict->height)
+           return fetch (pict, x, y);
+       else
+           return 0;
+    }
 }
 
 /*
@@ -77,18 +90,14 @@ fbFetchFromOneRectangle(bits_image_t *pict, int x, int y, uint32_t *buffer, fetc
 static void
 fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t* box = NULL;
     fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
+    pixman_bool_t src_clip;
     int x, y, i;
 
     /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-        fetchFromRegion = fbFetchFromNoRegion;
-    else
-        fetchFromRegion = fbFetchFromNRectangles;
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for ( i = 0; i < width; ++i)
     {
@@ -110,7 +119,8 @@ fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buff
                     y = MOD(v.vector[1]>>16, pict->height);
                     x = MOD(v.vector[0]>>16, pict->width);
                 }
-                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+
+                *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, TRUE);
             }
         }
 
@@ -123,18 +133,14 @@ fbFetchTransformed_Nearest_Normal(bits_image_t * pict, int width, uint32_t *buff
 static void
 fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t *box = NULL;
-    fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
+    pixman_bool_t src_clip;
+    fetchPixelProc32 fetch;
     int x, y, i;
 
     /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-        fetchFromRegion = fbFetchFromNoRegion;
-    else
-        fetchFromRegion = fbFetchFromNRectangles;
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for (i = 0; i < width; ++i)
     {
@@ -157,7 +163,7 @@ fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer,
                     x = CLIP(v.vector[0]>>16, 0, pict->width-1);
                 }
 
-                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+                *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, TRUE);
             }
         }
 
@@ -170,23 +176,13 @@ fbFetchTransformed_Nearest_Pad(bits_image_t * pict, int width, uint32_t *buffer,
 static void
 fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t *box = NULL;
     fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
+    pixman_bool_t src_clip;
     int x, y, i;
 
-    /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-    {
-        box = &(pict->common.src_clip->extents);
-        fetchFromRegion = fbFetchFromOneRectangle;
-    }
-    else
-    {
-        fetchFromRegion = fbFetchFromNRectangles;
-    }
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for (i = 0; i < width; ++i) {
         if (!mask || mask[i] & maskBits)
@@ -201,7 +197,8 @@ fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buf
                     y = v.vector[1]>>16;
                     x = v.vector[0]>>16;
                 }
-                *(buffer + i) = fetchFromRegion(pict, x, y, buffer, fetch, box);
+
+                *(buffer + i) = do_fetch (pict, x, y, fetch, src_clip, FALSE);
             }
         }
         v.vector[0] += unit.vector[0];
@@ -213,18 +210,13 @@ fbFetchTransformed_Nearest_General(bits_image_t * pict, int width, uint32_t *buf
 static void
 fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t *box = NULL;
+    pixman_bool_t src_clip;
     fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
     int i;
 
-    /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-        fetchFromRegion = fbFetchFromNoRegion;
-    else
-        fetchFromRegion = fbFetchFromNRectangles;
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for (i = 0; i < width; ++i) {
         if (!mask || mask[i] & maskBits)
@@ -261,10 +253,10 @@ fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buf
                 y1 = MOD (y1, pict->height);
                 y2 = MOD (y2, pict->height);
 
-                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
-                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
-                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
-                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+                tl = do_fetch (pict, x1, y1, fetch, src_clip, TRUE);
+                tr = do_fetch (pict, x2, y1, fetch, src_clip, TRUE);
+                bl = do_fetch (pict, x1, y2, fetch, src_clip, TRUE);
+                br = do_fetch (pict, x2, y2, fetch, src_clip, TRUE);
 
                 ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
                 fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
@@ -290,18 +282,14 @@ fbFetchTransformed_Bilinear_Normal(bits_image_t * pict, int width, uint32_t *buf
 static void
 fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t *box = NULL;
+    pixman_bool_t src_clip;
     fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
     int i;
 
     /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-        fetchFromRegion = fbFetchFromNoRegion;
-    else
-        fetchFromRegion = fbFetchFromNRectangles;
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for (i = 0; i < width; ++i) {
         if (!mask || mask[i] & maskBits)
@@ -338,10 +326,10 @@ fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer
                 y1 = CLIP (y1, 0, pict->height-1);
                 y2 = CLIP (y2, 0, pict->height-1);
 
-                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
-                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
-                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
-                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+                tl = do_fetch(pict, x1, y1, fetch, src_clip, TRUE);
+                tr = do_fetch(pict, x2, y1, fetch, src_clip, TRUE);
+                bl = do_fetch(pict, x1, y2, fetch, src_clip, TRUE);
+                br = do_fetch(pict, x2, y2, fetch, src_clip, TRUE);
 
                 ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
                 fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
@@ -367,23 +355,14 @@ fbFetchTransformed_Bilinear_Pad(bits_image_t * pict, int width, uint32_t *buffer
 static void
 fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t *box = NULL;
+    pixman_bool_t src_clip;
     fetchPixelProc32   fetch;
-    fetchFromRegionProc fetchFromRegion;
     int i;
 
     /* initialize the two function pointers */
     fetch = ACCESS(pixman_fetchPixelProcForPicture32)(pict);
 
-    if(pixman_region32_n_rects (pict->common.src_clip) == 1)
-    {
-        box = &(pict->common.src_clip->extents);
-        fetchFromRegion = fbFetchFromOneRectangle;
-    }
-    else
-    {
-        fetchFromRegion = fbFetchFromNRectangles;
-    }
+    src_clip = pict->common.src_clip != &(pict->common.full_region);
 
     for (i = 0; i < width; ++i)
     {
@@ -416,10 +395,10 @@ fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *bu
                 idistx = 256 - distx;
                 idisty = 256 - disty;
 
-                tl = fetchFromRegion(pict, x1, y1, buffer, fetch, box);
-                tr = fetchFromRegion(pict, x2, y1, buffer, fetch, box);
-                bl = fetchFromRegion(pict, x1, y2, buffer, fetch, box);
-                br = fetchFromRegion(pict, x2, y2, buffer, fetch, box);
+                tl = do_fetch(pict, x1, y1, fetch, src_clip, FALSE);
+                tr = do_fetch(pict, x2, y1, fetch, src_clip, FALSE);
+                bl = do_fetch(pict, x1, y2, fetch, src_clip, FALSE);
+                br = do_fetch(pict, x2, y2, fetch, src_clip, FALSE);
 
                 ft = FbGet8(tl,0) * idistx + FbGet8(tr,0) * distx;
                 fb = FbGet8(bl,0) * idistx + FbGet8(br,0) * distx;
@@ -446,7 +425,6 @@ fbFetchTransformed_Bilinear_General(bits_image_t * pict, int width, uint32_t *bu
 static void
 fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits, pixman_bool_t affine, pixman_vector_t v, pixman_vector_t unit)
 {
-    pixman_box32_t dummy;
     fetchPixelProc32 fetch;
     int i;
 
@@ -508,7 +486,7 @@ fbFetchTransformed_Convolution(bits_image_t * pict, int width, uint32_t *buffer,
                                 default:
                                     tx = x;
                             }
-                            if (pixman_region32_contains_point (pict->common.src_clip, tx, ty, &dummy)) {
+                            if (pixman_region32_contains_point (pict->common.src_clip, tx, ty, NULL)) {
                                 uint32_t c = fetch(pict, tx, ty);
 
                                 srtot += Red(c) * *p;