[cairo] pixman box filtering code prototype
Jeff Muizelaar
jeff at infidigm.net
Tue Oct 7 15:12:49 PDT 2008
It works by projecting each pixel of the destination surface to a
parallelogram on the source surface. All of the pixels in the
parallelogram are summed to produce the value of the destination pixel.
I've attached a patch against pixman revision
6449782f8a4bea0274a30f86d56214c2c73c0303. It does not merge without
conflicts so it will need some manual merging.
I've also attached a test program that generates the output something
like: http://people.freedesktop.org/~jrmuizel/box-filter.png vs. the
existing bilinear code at:
http://people.freedesktop.org/~jrmuizel/bilinear.png
This example isn't the best at showcasing the code because it's scaling
down a simple image and not scaling too much, however it was a very
useful test case for getting things correct.
-Jeff
-------------- next part --------------
A non-text attachment was scrubbed...
Name: scale.c
Type: text/x-csrc
Size: 6612 bytes
Desc: not available
Url : http://lists.cairographics.org/archives/cairo/attachments/20081007/e81a2e9d/attachment.c
-------------- next part --------------
diff --git a/pixman/pixman-compose.c b/pixman/pixman-compose.c
index faf2523..5880f4e 100644
--- a/pixman/pixman-compose.c
+++ b/pixman/pixman-compose.c
@@ -33,6 +33,8 @@
#include <assert.h>
#include <limits.h>
+#include <stdio.h>
+
#include "pixman-private.h"
/*
@@ -3682,6 +3684,12 @@ static void pixmanFetchSourcePict(source_image_t * pict, int x, int y, int width
* Fetch from region strategies
*/
typedef FASTCALL uint32_t (*fetchFromRegionProc)(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box);
+/* Note: the DIV macro returns the integer part of the division */
+static inline pixman_fixed_t pixman_fixed_div(pixman_fixed_t a, pixman_fixed_t b) {
+ return pixman_double_to_fixed(
+ pixman_fixed_to_double(a)/
+ pixman_fixed_to_double(b));
+}
static inline uint32_t
fbFetchFromNoRegion(bits_image_t *pict, int x, int y, uint32_t *buffer, fetchPixelProc fetch, pixman_box16_t *box)
@@ -4250,6 +4258,127 @@ fbFetchTransformed(bits_image_t * pict, int x, int y, int width, uint32_t *buffe
{
fbFetchTransformed_Nearest_General(pict, width, buffer, mask, maskBits, affine, v, unit);
}
+ } else if (pict->common.filter == PIXMAN_FILTER_POSTSCRIPT)
+ {
+ //printf("filter postscript - for (%d %d) - %d\n", x, y, width);
+ /* use the whole pixel */
+ int i;
+ pixman_vector_t v0, v1, v2;
+ v0.vector[0] = pixman_int_to_fixed(x);
+ v0.vector[1] = pixman_int_to_fixed(y);
+ v0.vector[2] = pixman_fixed_1;
+
+ v1.vector[0] = pixman_int_to_fixed(x+1);
+ v1.vector[1] = pixman_int_to_fixed(y);
+ v1.vector[2] = pixman_fixed_1;
+
+ v2.vector[0] = pixman_int_to_fixed(x);
+ v2.vector[1] = pixman_int_to_fixed(y+1);
+ v2.vector[2] = pixman_fixed_1;
+ fetchPixelProc fetch;
+ fetchFromRegionProc fetchFromRegion;
+ pixman_box16_t *box = NULL;
+
+ /* initialize the two function pointers */
+ fetch = fetchPixelProcForPicture(pict);
+
+ assert(pict->common.transform);
+
+ pixman_transform_point_3d (pict->common.transform, &v0);
+ pixman_transform_point_3d (pict->common.transform, &v1);
+ pixman_transform_point_3d (pict->common.transform, &v2);
+ /*printf("initial %d %d, %d %d, %d %d\n",
+ v0.vector[0] >> 16,
+ v0.vector[1] >> 16,
+ v1.vector[0] >> 16,
+ v1.vector[1] >> 16,
+ v2.vector[0] >> 16,
+ v2.vector[1] >> 16
+
+ );
+ */
+ //XXX: not strictly useful if they are both true, but that should only happen with a degenerate matrix
+ //printf("%x %x %x\n", v0.vector[1], v1.vector[1], v2.vector[1]);
+ /* Setup the transformed vectors so that v0 is always at the top
+ and v2 is to the left of v1. */
+ if (v0.vector[1] >= v1.vector[1] && v0.vector[1] >= v2.vector[1]) {
+ //printf("flip\n");
+ // flip v0 vector
+ // XXX: elaborate
+ v0.vector[1] = v2.vector[1] - (v0.vector[1] - v1.vector[1]);
+ v0.vector[0] = v2.vector[0] - (v0.vector[0] - v1.vector[0]);
+ } else if (v0.vector[1] > v1.vector[1]) {
+ //printf("swap one\n");
+ pixman_vector_t tmp = v1;
+ v1 = v0;
+ v0 = tmp;
+ // adjust the location of the other point
+ v2.vector[0] += v0.vector[0] - v1.vector[0];
+ v2.vector[1] += v0.vector[1] - v1.vector[1];
+ } else if (v0.vector[1] > v2.vector[1]) {
+ //printf("swap two\n");
+ pixman_vector_t tmp = v2;
+ v2 = v0;
+ v0 = tmp;
+ // adjust the location of the other point
+ v1.vector[0] += v0.vector[0] - v2.vector[0];
+ v1.vector[1] += v0.vector[1] - v2.vector[1];
+ }
+
+ if (v1.vector[0] < v2.vector[0]) {
+ //XXX this check is not sufficient
+ pixman_vector_t tmp = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ /* these deltas are not used elsewhere */
+ pixman_fixed_t deltax = v1.vector[0] - v0.vector[0];
+ pixman_fixed_t deltay = v1.vector[1] - v0.vector[1];
+ pixman_fixed_t deltax2 = v2.vector[0] - v0.vector[0];
+ pixman_fixed_t deltay2 = v2.vector[1] - v0.vector[1];
+
+ pixman_fixed_t slope = pixman_fixed_div(deltax, deltay);
+ pixman_fixed_t slope2 = pixman_fixed_div(deltax2, deltay2);
+
+ /* we don't handle non-affine transformations at all */
+ assert(affine);
+
+ if (pict->common.repeat == PIXMAN_REPEAT_NORMAL) {
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+#define FETCH int ix = MOD(x, pict->width); \
+ int iy = MOD(y, pict->height); \
+ tl = fetchFromRegion(pict, ix, iy, buffer, fetch, box);
+#include "postscript-resize.c"
+#undef FETCH
+ } else if (pict->common.repeat == PIXMAN_REPEAT_PAD) {
+ if(pixman_region_n_rects (pict->common.src_clip) == 1)
+ fetchFromRegion = fbFetchFromNoRegion;
+ else
+ fetchFromRegion = fbFetchFromNRectangles;
+
+#define FETCH int ix = CLIP(x, 0, pict->width-1); \
+ int iy = CLIP(y, 0, pict->height-1); \
+ tl = fetchFromRegion(pict, ix, iy, buffer, fetch, box);
+#include "postscript-resize.c"
+#undef FETCH
+
+ } else {
+ if(pixman_region_n_rects (pict->common.src_clip) == 1) {
+ box = &(pict->common.src_clip->extents);
+ fetchFromRegion = fbFetchFromOneRectangle;
+ } else {
+ fetchFromRegion = fbFetchFromNRectangles;
+ }
+
+#define FETCH tl = fetchFromRegion(pict, x, y, buffer, fetch, box);
+#include "postscript-resize.c"
+#undef FETCH
+ }
} else if (pict->common.filter == PIXMAN_FILTER_BILINEAR ||
pict->common.filter == PIXMAN_FILTER_GOOD ||
pict->common.filter == PIXMAN_FILTER_BEST)
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 2965acd..7634fa8 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -185,7 +185,8 @@ typedef enum
PIXMAN_FILTER_BEST,
PIXMAN_FILTER_NEAREST,
PIXMAN_FILTER_BILINEAR,
- PIXMAN_FILTER_CONVOLUTION
+ PIXMAN_FILTER_CONVOLUTION,
+ PIXMAN_FILTER_POSTSCRIPT
} pixman_filter_t;
typedef enum
diff --git a/pixman/postscript-resize.c b/pixman/postscript-resize.c
new file mode 100644
index 0000000..cea2ceb
--- /dev/null
+++ b/pixman/postscript-resize.c
@@ -0,0 +1,134 @@
+#define dprintf(a, ...)
+#define fixed_mul(a, b) ((int32_t)((((int64_t)a)*(b))>>32))
+ for (i = 0; i < width; ++i) {
+ if (!mask || mask[i] & maskBits)
+ {
+ if (!v.vector[2]) {
+ *(buffer + i) = 0;
+ } else {
+
+ /* assert(v2.vector[1] + v1.vector[1] > 2 * v0.vector[1]); */
+ int y1 = (v2.vector[1] - (v0.vector[1] - v1.vector[1])) >> 16;
+ int y0 = (v0.vector[1]) >> 16;
+ /* claim(y1 > y0);
+ * proof:
+ * v2.vector[1] + v1.vector[1] > 2 * v0.vector[1]
+ * v2.vector[1] + v1.vector[1] - v0.vector[1] > v0.vector[1] */
+
+ int ry = v1.vector[1]>>16;
+ int ly = v2.vector[1]>>16;
+
+ pixman_fixed_t rx_start_y = v0.vector[1] & 0xffff;
+ pixman_fixed_t rx_start_x = v0.vector[0];
+ pixman_fixed_t rx_slope = slope;
+ pixman_fixed_t lx_start_y = v0.vector[1] & 0xffff;
+ pixman_fixed_t lx_start_x = v0.vector[0];
+ pixman_fixed_t lx_slope = slope2;
+
+ dprintf("**--YY: %d: %d, %d %d %d\n",y1-y0, y0, y1, ry, ly);
+ dprintf("v0: %x %x\n", v0.vector[0], v0.vector[1]);
+ dprintf("v1: %x %x\n", v1.vector[0], v1.vector[1]);
+ dprintf("v2: %x %x\n", v2.vector[0], v2.vector[1]);
+ dprintf("slope,: %x %x\n", slope, slope2);
+
+ uint32_t c1_accum, c2_accum, c3_accum, c4_accum;
+ /* note watch for including pixels in more than one sample.
+ * i.e. use a one-sided interval */
+ c1_accum = c2_accum = c3_accum = c4_accum = 0;
+ int y; // this y shadows
+ int total = 0;
+ dprintf("%d %d, %d %d, %d %d\n",
+ v0.vector[0] >> 16,
+ v0.vector[1] >> 16,
+ v1.vector[0] >> 16,
+ v1.vector[1] >> 16,
+ v2.vector[0] >> 16,
+ v2.vector[1] >> 16
+
+ );
+ dprintf("y1: %d %d\n", y0, y1);
+ dprintf("%x %x\n", slope, slope2);
+ for (y = y0; y <= y1; y++) {
+ int x;
+ pixman_fixed_t rx, lx;
+
+ if (y == ry) {
+ rx_start_x = v1.vector[0];
+ rx_start_y = v1.vector[1] & 0xffff;
+ rx_slope = slope2;
+ }
+
+ if (y == ly) {
+ lx_start_x = v2.vector[0];
+ lx_start_y = v2.vector[1] & 0xffff;
+ lx_slope = slope;
+ }
+
+ /* it may be possible to move these
+ * multiplications into the conditions above
+ * and use an addition the rest of the time */
+ rx = rx_start_x + fixed_mul(rx_start_y, rx_slope);
+ rx_start_y += (1 << 16);
+
+ lx = lx_start_x + fixed_mul(lx_start_y, lx_slope);
+ lx_start_y += (1 << 16);
+
+ for (x = (lx >> 16); x <= (rx >> 16); x++) {
+ uint32_t tl;
+ FETCH
+ dprintf("x,y -> %d %d %x\n", x, y, tl);
+ c1_accum += FbGet8(tl,24);
+ c2_accum += FbGet8(tl,16);
+ c3_accum += FbGet8(tl,8);
+ c4_accum += FbGet8(tl,0);
+ total++;
+ }
+ }
+ dprintf("total: %d\n", total);
+ if (!total) {
+ printf("y0: %d, y1: %d\n", y0, y1);
+ printf("%x %x, %x %x, %x %x\n",
+ v0.vector[0] >> 16,
+ v0.vector[1] >> 16,
+ v1.vector[0] >> 16,
+ v1.vector[1] >> 16,
+ v2.vector[0] >> 16,
+ v2.vector[1] >> 16
+
+ );
+ {
+ int i,j;
+ for (i=0; i<3; i++) {
+ for (j=0; j<3; j++) {
+ printf("%x ", pict->common.transform->matrix[i][j]);
+ }
+ printf("\n");
+ }
+ }
+
+ assert(total);
+ }
+ /* use component numbers instead of names because we don't know
+ * which will actually be red etc. */
+ c1_accum /= total;
+ c2_accum /= total;
+ c3_accum /= total;
+ c4_accum /= total;
+ dprintf("total %d\n", total);
+ uint32_t r = (c1_accum << 24) | ((c2_accum<<16)&0xff0000) | ((c3_accum<<8)&0xff00) | (c4_accum&0xff);
+
+ *(buffer + i) = r;
+ }
+ }
+
+ v0.vector[0] += unit.vector[0];
+ v0.vector[1] += unit.vector[1];
+ v0.vector[2] += unit.vector[2];
+ v1.vector[0] += unit.vector[0];
+ v1.vector[1] += unit.vector[1];
+ v1.vector[2] += unit.vector[2];
+ v2.vector[0] += unit.vector[0];
+ v2.vector[1] += unit.vector[1];
+ v2.vector[2] += unit.vector[2];
+ }
+
More information about the cairo
mailing list