diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-03-15 15:25:07 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-03-20 22:47:01 +0100 |
commit | 60a349000604df77dc8596abe866001b3bb2d8d4 (patch) | |
tree | 05b73bb5e723c56c94cb0e93664c018dcb826945 | |
parent | 16e7196945884300036f5dd2a32df3c1e211e764 (diff) |
Add fast path 8888 bilinear scalerfast-bilinear
-rw-r--r-- | pixman/pixman-fast-path.c | 401 |
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 }, }; |