[cairo] [pixman] speedup nearest scaling

Jeff Muizelaar jeff at infidigm.net
Thu Nov 13 20:26:06 PST 2008


The attached patch speeds up the NEAREST scaling with
the source operator on matching surfaces by about 2x on my
x86 box.

There is more speedup possible, but I'm more interested in getting
something simple in at this point.

-Jeff
-------------- next part --------------
diff --git a/pixman/pixman-pict.c b/pixman/pixman-pict.c
index e2fd235..c16eb28 100644
--- a/pixman/pixman-pict.c
+++ b/pixman/pixman-pict.c
@@ -1208,6 +1208,92 @@ fbCompositeSrc_8888xx888 (pixman_op_t op,
 }
 
 static void
+fbCompositeSrcScaleNearest (pixman_op_t op,
+		      pixman_image_t * pSrc,
+		      pixman_image_t * pMask,
+		      pixman_image_t * pDst,
+		      int16_t      xSrc,
+		      int16_t      ySrc,
+		      int16_t      xMask,
+		      int16_t      yMask,
+		      int16_t      xDst,
+		      int16_t      yDst,
+		      uint16_t     width,
+		      uint16_t     height)
+{
+    uint32_t	*dst;
+    uint32_t    *src;
+    int		 dstStride, srcStride;
+    uint32_t	 n_bytes = width * sizeof (uint32_t);
+
+    //printf("nearest\n");
+    fbComposeGetStart (pDst, xDst, yDst, uint32_t, dstStride, dst, 1);
+    fbComposeGetStart (pSrc, 0, 0, uint32_t, srcStride, src, 1);
+
+    pixman_vector_t v;
+
+    /* reference point is the center of the pixel */
+    v.vector[0] = pixman_int_to_fixed(xSrc) + pixman_fixed_1 / 2;
+    v.vector[1] = pixman_int_to_fixed(ySrc) + pixman_fixed_1 / 2;
+    v.vector[2] = pixman_fixed_1;
+
+    if (!pixman_transform_point_3d (pSrc->common.transform, &v))
+        return;
+
+    /* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */
+    v.vector[0] -= pixman_fixed_e;
+    v.vector[1] -= pixman_fixed_e;
+
+    int i, j;
+    for (j = 0; j < height; j++) {
+        pixman_fixed_t vx = v.vector[0];
+        pixman_fixed_t vy = v.vector[1];
+        for (i = 0; i < width; ++i)
+        {
+            int x, y;
+            uint32_t result;
+            pixman_bool_t inside_bounds;
+            x = vx>>16;
+            y = vy>>16;
+            switch (pSrc->common.repeat)
+            {
+                case PIXMAN_REPEAT_NORMAL:
+                    x = MOD (x, pSrc->bits.width);
+                    y = MOD (y, pSrc->bits.height);
+                    inside_bounds = TRUE;
+                    break;
+
+                case PIXMAN_REPEAT_PAD:
+                    x = CLIP (x, 0, pSrc->bits.width-1);
+                    y = CLIP (y, 0, pSrc->bits.height-1);
+                    inside_bounds = TRUE;
+                    break;
+
+                case PIXMAN_REPEAT_REFLECT:
+                case PIXMAN_REPEAT_NONE:
+                default:
+                    inside_bounds = (x >= 0 && x < pSrc->bits.width && y >= 0 && y < pSrc->bits.height);
+                    break;
+            }
+            if (inside_bounds) {
+                result = READ(pSrc, src + y * srcStride + x);
+            } else {
+                result = 0;
+            }
+            WRITE(pDst, dst + i, result);
+
+            /* adjust the x location by a unit vector in the x direction:
+             * this is equivalent to transforming x+1 of the destination point to source space */
+            vx += pSrc->common.transform->matrix[0][0];
+        }
+        /* adjust the y location by a unit vector in the y direction
+         * this is equivalent to transforming y+1 of the destination point to source space */
+        v.vector[1] += pSrc->common.transform->matrix[1][1];
+        dst += dstStride;
+    }
+}
+
+static void
 pixman_walk_composite_region (pixman_op_t op,
 			      pixman_image_t * pSrc,
 			      pixman_image_t * pMask,
@@ -1854,6 +1940,28 @@ pixman_image_composite (pixman_op_t      op,
     if(op == PIXMAN_OP_DST)
         return;
 
+    if (pSrc->type == BITS
+            && srcTransform
+            && !pMask
+            && op == PIXMAN_OP_SRC
+            && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap
+            && (pSrc->common.filter == PIXMAN_FILTER_NEAREST)
+            && PIXMAN_FORMAT_BPP(pDst->bits.format) == 32
+            && pSrc->bits.format == pDst->bits.format
+            && pSrc->common.src_clip == &(pSrc->common.full_region)
+            && !pSrc->common.read_func && !pSrc->common.write_func
+            && !pDst->common.read_func && !pDst->common.write_func)
+    {
+        if (pSrc->common.transform->matrix[0][1] == 0 &&
+            pSrc->common.transform->matrix[1][0] == 0 &&
+            pSrc->common.transform->matrix[2][0] == 0 &&
+            pSrc->common.transform->matrix[2][1] == 0 &&
+            pSrc->common.transform->matrix[2][2] == pixman_fixed_1) {
+            func = fbCompositeSrcScaleNearest;
+        }
+    }
+
+
     if ((pSrc->type == BITS || pixman_image_can_get_solid (pSrc)) && (!pMask || pMask->type == BITS)
         && !srcTransform && !maskTransform
         && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap


More information about the cairo mailing list