Hello
This is the second attempt at bitmap supersampling in Pixman.
Changes:
1. There is a new fast path flag called FAST_PATH_NO_SUPERSAMPLING
(self-explanatory)
2. No divisions in inner loops, but this causes a proliferation of
variables. Note: using float or double for transformation matrices
would both simplify code and fix the problems encountered by Inkscape
when zooming into a bitmap.
3. Automatic sampling rate: by default, when the filter is better than
nearest neighbor, the image's sampling rate is automatically adjusted
to match the transform. This can be turned off by explicitly setting a
sampling rate using pixman_image_set_sampling_rate. This way the
quality of downscaling is vastly improved without the need for any
further changes to Cairo.
Regards, Krzysztof
diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index a32ebcc..eb5c40f 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -643,6 +643,154 @@ bits_image_fetch_affine_no_alpha (pixman_image_t * image,
}
}
+static void
+bits_image_fetch_affine_no_alpha_supersample (pixman_image_t * image,
+ int offset,
+ int line,
+ int width,
+ uint32_t * buffer,
+ const uint32_t * mask)
+{
+pixman_fixed_t x, y;
+pixman_fixed_t ux, uy, vx, vy;
+pixman_fixed_t uxfrac, uyfrac, vxfrac, vyfrac;
+pixman_fixed_t uxrem, uyrem, vxrem, vyrem;
+pixman_fixed_t uxstart, uystart, vxstart, vystart;
+pixman_vector_t v;
+int rate_x, rate_y, samples;
+int i, iy, ix;
+uint32_t result_a, result_r, result_g, result_b;
+
+/* reference point is the center of the pixel */
+v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
+v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
+v.vector[2] = pixman_fixed_1;
+
+if (image-common.transform)
+{
+ if (!pixman_transform_point_3d (image-common.transform, v))
+ return;
+
+ ux = image-common.transform-matrix[0][0];
+ uy = image-common.transform-matrix[1][0];
+ vx = image-common.transform-matrix[0][1];
+ vy = image-common.transform-matrix[1][1];
+}
+else
+{
+ ux = pixman_fixed_1;
+ uy = 0;
+ vx = 0;
+ vy = pixman_fixed_1;
+}
+
+x = v.vector[0];
+y = v.vector[1];
+
+rate_x = image-common.sampling_rate_x;
+rate_y = image-common.sampling_rate_y;
+samples = rate_x * rate_y;
+
+/* precompute subpixel grid increments */
+uxfrac = ux / rate_x;
+uxrem = ux % rate_x;
+uyfrac = uy / rate_x;
+uyrem = uy % rate_x;
+vxfrac = vx / rate_y;
+vxrem = vx % rate_y;
+vyfrac = vy / rate_y;
+vyrem = vy % rate_y;
+uxstart = (ux * (rate_x-1) + rate_x) / (2*rate_x);
+uystart = (uy * (rate_x-1) + rate_x) / (2*rate_x);
+vxstart = (vx * (rate_y-1) + rate_y) / (2*rate_y);
+vystart = (vy * (rate_y-1) + rate_y) / (2*rate_y);
+
+for (i = 0; i width; ++i)
+{
+ if (!mask || mask[i])
+ {
+ pixman_fixed_t tpx, tpy, tpxrem, tpyrem;
+
+ result_a = 0;
+ result_r = 0;
+ result_g = 0;
+ result_b = 0;
+
+ tpx = x - vxstart;
+ tpy = y - vystart;
+ tpxrem = 0;
+ tpyrem = 0;
+
+ for (iy = 0; iy rate_y; ++iy)
+ {
+ pixman_fixed_t spx, spy, spxrem, spyrem;
+
+ tpx += vxfrac;
+ tpy += vyfrac;
+ tpxrem += vxrem;
+ tpyrem += vyrem;
+
+ if (tpxrem = rate_y)
+ {
+ tpxrem -= rate_y;
+ ++tpx;
+ }
+ if (tpyrem = rate_y)
+ {
+ tpyrem -= rate_y;
+ ++tpy;
+ }
+
+ spx = tpx - uxstart;
+ spy = tpy - uystart;
+ spxrem = 0;
+ spyrem = 0;
+
+ for (ix = 0; ix rate_x; ++ix)
+ {
+ uint32_t pixel;
+
+ spx += uxfrac;
+ spy += uyfrac;
+ spxrem += uxrem;
+ spyrem += uyrem;
+
+ if (spxrem = rate_x)
+ {
+ spxrem -= rate_x;
+ ++spx;
+ }
+ if (spyrem = rate_x)
+ {
+ spyrem -= rate_x;
+ ++spy;
+ }
+
+ pixel = bits_image_fetch_pixel_filtered (
+ image-bits, spx, spy, fetch_pixel_no_alpha);
+
+ result_a += (pixel 0xff00) 24;
+ result_r += (pixel 0x00ff) 16;
+ result_g += (pixel 0xff00) 8;
+ result_b += (pixel 0x00ff) 0;
+ }
+ }
+ result_a = (result_a + samples/2) / samples;
+ result_r = (result_r + samples/2) / samples;
+ result_g = (result_g + samples/2) / samples;
+ result_b = (result_b + samples/2) / samples;
+
+ buffer[i] = (result_a 24)
+ | (result_r 16)
+ | (result_g 8)
+ | (result_b 0);
+ }
+
+ x += ux;
+ y += uy;
+}
+}
+
/* General fetcher */
static force_inline uint32_t
fetch_pixel_general (bits_image_t *image, int x, int y, pixman_bool_t check_bounds)
@@ -750,6 +898,196 @@ bits_image_fetch_general (pixman_image_t * image,
}
static void
+bits_image_fetch_general_supersample (pixman_image_t * image,
+ int offset,
+ int line,
+ int width,
+ uint32_t *