summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pixman/pixman-bits-image.c102
-rw-r--r--pixman/pixman-image.c19
-rw-r--r--pixman/pixman.c8
-rw-r--r--pixman/pixman.h23
4 files changed, 149 insertions, 3 deletions
diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 7787ef1..97db108 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -426,6 +426,104 @@ bits_image_fetch_pixel_convolution (bits_image_t *image,
return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot));
}
+static uint32_t
+bits_image_fetch_pixel_convolution_separable (bits_image_t *image,
+ pixman_fixed_t x,
+ pixman_fixed_t y,
+ get_pixel_t get_pixel)
+{
+ pixman_fixed_t *params = image->common.filter_params;
+ pixman_repeat_t repeat_mode = image->common.repeat;
+ int width = image->width;
+ int height = image->height;
+ int cwidth = pixman_fixed_to_int (params[0]);
+ int cheight = pixman_fixed_to_int (params[1]);
+ int x_phase_bits = pixman_fixed_to_int (params[2]);
+ int y_phase_bits = pixman_fixed_to_int (params[3]);
+ int x_phase_shift = 16 - x_phase_bits;
+ int y_phase_shift = 16 - y_phase_bits;
+ int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1;
+ int y_off = ((cheight << 16) - pixman_fixed_1) >> 1;
+ pixman_fixed_t *y_params;
+ int srtot, sgtot, sbtot, satot;
+ int32_t x1, x2, y1, y2;
+ int32_t px, py;
+ int i, j;
+
+ /* Round x and y to the middle of the closest phase before continuing. This
+ * ensures that the convolution matrix is aligned right, since it was
+ * positioned relative to a particular phase (and not relative to whatever
+ * exact fraction we happen to get here).
+ */
+ x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1);
+ y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1);
+
+ px = (x & 0xffff) >> x_phase_shift;
+ py = (y & 0xffff) >> y_phase_shift;
+
+ y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight;
+
+ x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
+ y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
+ x2 = x1 + cwidth;
+ y2 = y1 + cheight;
+
+ srtot = sgtot = sbtot = satot = 0;
+
+ for (i = y1; i < y2; ++i)
+ {
+ pixman_fixed_48_16_t fy = *y_params++;
+ pixman_fixed_t *x_params = params + 4 + px * cwidth;
+
+ if (fy)
+ {
+ for (j = x1; j < x2; ++j)
+ {
+ pixman_fixed_t fx = *x_params++;
+ int rx = j;
+ int ry = i;
+
+ if (fx)
+ {
+ pixman_fixed_t f;
+ uint32_t pixel;
+
+ if (repeat_mode != PIXMAN_REPEAT_NONE)
+ {
+ repeat (repeat_mode, &rx, width);
+ repeat (repeat_mode, &ry, height);
+
+ pixel = get_pixel (image, rx, ry, FALSE);
+ }
+ else
+ {
+ pixel = get_pixel (image, rx, ry, TRUE);
+ }
+
+ f = (fy * fx + 0x8000) >> 16;
+
+ srtot += (int)RED_8 (pixel) * f;
+ sgtot += (int)GREEN_8 (pixel) * f;
+ sbtot += (int)BLUE_8 (pixel) * f;
+ satot += (int)ALPHA_8 (pixel) * f;
+ }
+ }
+ }
+ }
+
+ satot = (satot + 0x8000) >> 16;
+ srtot = (srtot + 0x8000) >> 16;
+ sgtot = (sgtot + 0x8000) >> 16;
+ sbtot = (sbtot + 0x8000) >> 16;
+
+ satot = CLIP (satot, 0, 0xff);
+ srtot = CLIP (srtot, 0, 0xff);
+ sgtot = CLIP (sgtot, 0, 0xff);
+ sbtot = CLIP (sbtot, 0, 0xff);
+
+ return ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot));
+}
+
static force_inline uint32_t
bits_image_fetch_pixel_filtered (bits_image_t *image,
pixman_fixed_t x,
@@ -449,6 +547,10 @@ bits_image_fetch_pixel_filtered (bits_image_t *image,
return bits_image_fetch_pixel_convolution (image, x, y, get_pixel);
break;
+ case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
+ return bits_image_fetch_pixel_convolution_separable (image, x, y, get_pixel);
+ break;
+
default:
break;
}
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index d9c3034..93ed17e 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -371,6 +371,7 @@ compute_image_info (pixman_image_t *image)
break;
case PIXMAN_FILTER_CONVOLUTION:
+ case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
break;
default:
@@ -515,8 +516,9 @@ compute_image_info (pixman_image_t *image)
* if all channels are opaque, so we simply turn it off
* unconditionally for those images.
*/
- if (image->common.alpha_map ||
- image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
+ if (image->common.alpha_map ||
+ image->common.filter == PIXMAN_FILTER_CONVOLUTION ||
+ image->common.filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION ||
image->common.component_alpha)
{
flags &= ~(FAST_PATH_IS_OPAQUE | FAST_PATH_SAMPLES_OPAQUE);
@@ -679,6 +681,19 @@ pixman_image_set_filter (pixman_image_t * image,
if (params == common->filter_params && filter == common->filter)
return TRUE;
+ if (filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION)
+ {
+ int width = pixman_fixed_to_int (params[0]);
+ int height = pixman_fixed_to_int (params[1]);
+ int x_phase_bits = pixman_fixed_to_int (params[2]);
+ int y_phase_bits = pixman_fixed_to_int (params[3]);
+ int n_x_phases = (1 << x_phase_bits);
+ int n_y_phases = (1 << y_phase_bits);
+
+ return_val_if_fail (
+ n_params == 4 + n_x_phases * width + n_y_phases * height, FALSE);
+ }
+
new_params = NULL;
if (params)
{
diff --git a/pixman/pixman.c b/pixman/pixman.c
index e0ccd87..0661f41 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -455,6 +455,14 @@ analyze_extent (pixman_image_t *image,
height = params[1];
break;
+ case PIXMAN_FILTER_SEPARABLE_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 = params[0];
+ height = params[1];
+ break;
+
case PIXMAN_FILTER_GOOD:
case PIXMAN_FILTER_BEST:
case PIXMAN_FILTER_BILINEAR:
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 33ebf3f..20c95da 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -292,7 +292,28 @@ typedef enum
PIXMAN_FILTER_BEST,
PIXMAN_FILTER_NEAREST,
PIXMAN_FILTER_BILINEAR,
- PIXMAN_FILTER_CONVOLUTION
+ PIXMAN_FILTER_CONVOLUTION,
+
+ /* The SEPARABLE_CONVOLUTION filter takes the following parameters:
+ *
+ * width: integer given as 16.16 fixpoint number
+ * height: integer given as 16.16 fixpoint number
+ * x_phase_bits: integer given as 16.16 fixpoint
+ * y_phase_bits: integer given as 16.16 fixpoint
+ * xtables: (1 << x_phase_bits) tables of size width
+ * ytables: (1 << y_phase_bits) tables of size height
+ *
+ * When sampling at (x, y), the location is first rounded to one of
+ * n_x_phases * n_y_phases subpixel positions. These subpixel positions
+ * determine an xtable and a ytable to use.
+ *
+ * Conceptually a width x height matrix is then formed in which each entry
+ * is the product of the corresponding entries in the x and y tables.
+ * This matrix is then aligned with the image pixels such that its center
+ * is as close as possible to the subpixel location chosen earlier. Then
+ * the image is convolved with the matrix and the resulting pixel returned.
+ */
+ PIXMAN_FILTER_SEPARABLE_CONVOLUTION
} pixman_filter_t;
typedef enum