summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-03-15 15:25:07 +0100
committerAlexander Larsson <alexl@redhat.com>2010-03-20 22:47:01 +0100
commit60a349000604df77dc8596abe866001b3bb2d8d4 (patch)
tree05b73bb5e723c56c94cb0e93664c018dcb826945
parent16e7196945884300036f5dd2a32df3c1e211e764 (diff)
Add fast path 8888 bilinear scalerfast-bilinear
-rw-r--r--pixman/pixman-fast-path.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/pixman/pixman-fast-path.c b/pixman/pixman-fast-path.c
index bf5b298..64d65db 100644
--- a/pixman/pixman-fast-path.c
+++ b/pixman/pixman-fast-path.c
@@ -1588,6 +1588,384 @@ FAST_NEAREST(565_565_normal, 0565, 0565, uint16_t, uint16_t, SRC, /*repeat: */ 1
FAST_NEAREST(8888_565_none, 8888, 0565, uint32_t, uint16_t, OVER, /*repeat: */ 0);
FAST_NEAREST(8888_565_normal, 8888, 0565, uint32_t, uint16_t, OVER, /*repeat: */ 1);
+#if SIZEOF_LONG > 4
+
+static force_inline uint32_t
+bilinear_interpolation (uint32_t tl, uint32_t tr,
+ uint32_t bl, uint32_t br,
+ int distx, int disty)
+{
+ uint64_t distxy, distxiy, distixy, distixiy;
+ uint64_t tl64, tr64, bl64, br64;
+ uint64_t f, r;
+
+ distxy = distx * disty;
+ distxiy = distx * (256 - disty);
+ distixy = (256 - distx) * disty;
+ distixiy = (256 - distx) * (256 - disty);
+
+ /* Alpha and Blue */
+ tl64 = tl & 0xff0000ff;
+ tr64 = tr & 0xff0000ff;
+ bl64 = bl & 0xff0000ff;
+ br64 = br & 0xff0000ff;
+
+ f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
+ r = f & 0x0000ff0000ff0000ull;
+
+ /* Red and Green */
+ tl64 = tl;
+ tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
+
+ tr64 = tr;
+ tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
+
+ bl64 = bl;
+ bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
+
+ br64 = br;
+ br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
+
+ f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
+ r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
+
+ return (uint32_t)(r >> 16);
+}
+
+#else
+
+static force_inline uint32_t
+bilinear_interpolation (uint32_t tl, uint32_t tr,
+ uint32_t bl, uint32_t br,
+ int distx, int disty)
+{
+ int distxy, distxiy, distixy, distixiy;
+ uint32_t f, r;
+
+ distxy = distx * disty;
+ distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
+ distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
+ distixiy =
+ 256 * 256 - (disty << 8) -
+ (distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
+
+ /* Blue */
+ r = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
+
+ /* Green */
+ f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
+ r |= f & 0xff000000;
+
+ tl >>= 16;
+ tr >>= 16;
+ bl >>= 16;
+ br >>= 16;
+ r >>= 16;
+
+ /* Red */
+ f = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
+ + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
+ r |= f & 0x00ff0000;
+
+ /* Alpha */
+ f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
+ + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
+ r |= f & 0xff000000;
+
+ return r;
+}
+
+#endif
+
+static force_inline uint32_t
+repeat_row (pixman_repeat_t repeat, uint32_t *row, int x, int size)
+{
+ if (repeat == PIXMAN_REPEAT_NONE)
+ {
+ if (x < 0 || x >= size)
+ return 0;
+ }
+ else if (repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ while (x >= size)
+ x -= size;
+ while (x < 0)
+ x += size;
+ }
+ else if (repeat == PIXMAN_REPEAT_PAD)
+ {
+ x = CLIP (x, 0, size - 1);
+ }
+ else /* REFLECT */
+ {
+ x = MOD (x, size * 2);
+ if (x >= size)
+ x = size * 2 - x - 1;
+ }
+
+ return row[x];
+}
+
+
+static void
+fast_composite_scaled_bilinear_8888 (pixman_implementation_t *imp,
+ pixman_op_t op,
+ pixman_image_t * src_image,
+ pixman_image_t * mask_image,
+ pixman_image_t * dst_image,
+ int32_t src_x,
+ int32_t src_y,
+ int32_t mask_x,
+ int32_t mask_y,
+ int32_t dst_x,
+ int32_t dst_y,
+ int32_t width,
+ int32_t height)
+{
+ uint32_t *dst_line;
+ uint32_t *src_first_line;
+ int w;
+ int x1, x2, y1, y2;
+ pixman_fixed_t orig_vx;
+ pixman_fixed_t max_vx, max_vy;
+ pixman_vector_t v;
+ pixman_fixed_t vx, vy;
+ pixman_fixed_t unit_x, unit_y;
+
+ uint32_t *top_row, *bottom_row, *left_column, *right_column;
+ uint32_t *dst;
+ int src_stride, column_stride, dst_stride, top_row_width, bottom_row_width;
+ uint32_t zero[2] = { 0, 0 };
+ pixman_repeat_t src_repeat;
+ int disty;
+
+ PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, uint32_t, dst_stride, dst_line, 1);
+ /* pass in 0 instead of src_x and src_y because src_x and src_y need to be
+ * transformed from destination space to source space */
+ PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, uint32_t, src_stride, src_first_line, 1);
+
+ /* reference point is the center of the pixel */
+ v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2;
+ v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2;
+ v.vector[2] = pixman_fixed_1;
+
+ if (!pixman_transform_point_3d (src_image->common.transform, &v))
+ return;
+
+ unit_x = src_image->common.transform->matrix[0][0];
+ unit_y = src_image->common.transform->matrix[1][1];
+
+ /* Convert from pixel coordinates to sample indexes */
+ vx = v.vector[0] - pixman_fixed_1/2;
+ vy = v.vector[1] - pixman_fixed_1/2;
+
+ max_vx = src_image->bits.width << 16;
+ max_vy = src_image->bits.height << 16;
+
+ src_repeat = src_image->common.repeat;
+
+ orig_vx = vx;
+
+ /* Top lines may read 1 pixel outside samples */
+ while (pixman_fixed_to_int (vy) < 0 && height-- > 0)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+
+ disty = (vy >> 8) & 0xff;
+ vy += unit_y;
+
+ if (src_repeat == PIXMAN_REPEAT_NONE)
+ {
+ top_row = zero;
+ top_row_width = 1;
+ }
+ else if (src_repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ top_row = src_first_line + src_stride * (src_image->bits.height - 1);
+ top_row_width = src_image->bits.width;
+ }
+ else /* pad / reflect */
+ {
+ top_row = src_first_line;
+ top_row_width = src_image->bits.width;
+ }
+ bottom_row = src_first_line;
+
+ vx = orig_vx;
+
+ w = width;
+ while (w-- > 0)
+ {
+ uint32_t tl, tr, bl, br;
+ int32_t distx;
+
+ x1 = vx >> 16;
+ x2 = x1 + 1;
+
+ tl = repeat_row (src_repeat, top_row, x1, top_row_width);
+ tr = repeat_row (src_repeat, top_row, x2, top_row_width);
+ bl = repeat_row (src_repeat, bottom_row, x1, src_image->bits.width);
+ br = repeat_row (src_repeat, bottom_row, x2, src_image->bits.width);
+
+ distx = (vx >> 8) & 0xff;
+
+ *dst++ = bilinear_interpolation (tl, tr, bl, br, distx, disty);
+
+ vx += unit_x;
+ }
+ }
+
+ /* Find the column one pixel to the left/right of the samples.
+ * Pixels near the left/right border may read these */
+ if (src_repeat == PIXMAN_REPEAT_NONE)
+ {
+ left_column = zero;
+ right_column = zero;
+ column_stride = 0;
+ }
+ else if (src_repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ left_column = src_first_line + (src_image->bits.width - 1);
+ right_column = src_first_line;
+ column_stride = src_stride;
+ }
+ else /* pad / reflect */
+ {
+ left_column = src_first_line;
+ right_column = src_first_line + (src_image->bits.width - 1);
+ column_stride = src_stride;
+ }
+
+ while (vy < max_vy - pixman_fixed_1 && height-- > 0)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+
+ disty = (vy >> 8) & 0xff;
+ y1 = pixman_fixed_to_int (vy);
+ y2 = y1 + 1;
+ vy += unit_y;
+
+ top_row = src_first_line + src_stride * y1;
+ bottom_row = top_row + src_stride;
+
+ vx = orig_vx;
+
+ w = width;
+
+ /* Left columns: */
+ while (vx < 0 && w-- > 0)
+ {
+ uint32_t tl, tr, bl, br;
+ int32_t distx;
+
+ tl = left_column[column_stride*y1];
+ tr = top_row [0];
+ bl = left_column[column_stride*y1 + column_stride];
+ br = bottom_row [0];
+
+ distx = (vx >> 8) & 0xff;
+
+ *dst++ = bilinear_interpolation (tl, tr, bl, br, distx, disty);
+
+ vx += unit_x;
+ }
+
+ /* Main columns: */
+ while (vx < max_vx - pixman_fixed_1 && w-- > 0)
+ {
+ uint32_t tl, tr, bl, br;
+ int32_t distx;
+
+ x1 = vx >> 16;
+ x2 = x1 + 1;
+
+ tl = top_row [x1];
+ tr = top_row [x2];
+ bl = bottom_row [x1];
+ br = bottom_row [x2];
+
+ distx = (vx >> 8) & 0xff;
+
+ *dst++ = bilinear_interpolation (tl, tr, bl, br, distx, disty);
+
+ vx += unit_x;
+ }
+
+ /* Rightmost column: */
+ while (w-- > 0)
+ {
+ uint32_t tl, tr, bl, br;
+ int32_t distx;
+
+ tl = top_row [src_image->bits.width-1];
+ tr = right_column[column_stride*y1];
+ bl = bottom_row [src_image->bits.width-1];
+ br = right_column[column_stride*y1 + column_stride];
+
+ distx = (vx >> 8) & 0xff;
+
+ *dst++ = bilinear_interpolation (tl, tr, bl, br, distx, disty);
+
+ vx += unit_x;
+ }
+ }
+
+ /* Bottom rows may read 1 pixel outside samples */
+ while (height-- > 0)
+ {
+ dst = dst_line;
+ dst_line += dst_stride;
+
+ disty = (vy >> 8) & 0xff;
+ vy += unit_y;
+
+ top_row = src_first_line + src_stride * (src_image->bits.height-1);
+
+ if (src_repeat == PIXMAN_REPEAT_NONE)
+ {
+ bottom_row = zero;
+ bottom_row_width = 1;
+ }
+ else if (src_repeat == PIXMAN_REPEAT_NORMAL)
+ {
+ bottom_row = src_first_line;
+ bottom_row_width = src_image->bits.width;
+ }
+ else /* pad / reflect */
+ {
+ bottom_row = src_first_line + src_stride * (src_image->bits.height - 1);
+ bottom_row_width = src_image->bits.width;
+ }
+
+ vx = orig_vx;
+
+ w = width;
+ while (w-- > 0)
+ {
+ uint32_t tl, tr, bl, br;
+ int32_t distx;
+
+ x1 = vx >> 16;
+ x2 = x1 + 1;
+
+ tl = repeat_row (src_repeat, top_row, x1, src_image->bits.width);
+ tr = repeat_row (src_repeat, top_row, x2, src_image->bits.width);
+ bl = repeat_row (src_repeat, bottom_row, x1, bottom_row_width);
+ br = repeat_row (src_repeat, bottom_row, x2, bottom_row_width);
+
+ distx = (vx >> 8) & 0xff;
+
+ *dst++ = bilinear_interpolation (tl, tr, bl, br, distx, disty);
+
+ vx += unit_x;
+ }
+ }
+}
+
static force_inline uint32_t
fetch_nearest (pixman_repeat_t src_repeat,
pixman_format_code_t format,
@@ -1878,6 +2256,29 @@ static const pixman_fast_path_t c_fast_paths[] =
NEAREST_FAST_PATH (OVER, x8b8g8r8, a8b8g8r8),
NEAREST_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8),
+#define SCALED_BILINEAR_FLAGS \
+ (FAST_PATH_SCALE_TRANSFORM | \
+ FAST_PATH_NO_ALPHA_MAP | \
+ FAST_PATH_BILINEAR_FILTER | \
+ FAST_PATH_NO_ACCESSORS | \
+ FAST_PATH_NO_WIDE_FORMAT)
+
+
+#define BILINEAR_FAST_PATH(op,s,d) \
+ { PIXMAN_OP_ ## op, \
+ PIXMAN_ ## s, SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
+ PIXMAN_null, 0, \
+ PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
+ fast_composite_scaled_bilinear_8888, \
+ }
+
+ BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8),
+ BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8),
+ BILINEAR_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8),
+ BILINEAR_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8),
+ BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8),
+ BILINEAR_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8),
+
{ PIXMAN_OP_NONE },
};