mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 17:23:59 +00:00
4a37a54063
This takes the bilinear interpolation code from Skia. It uses 4 bits of precision instead of 8. This lets it interpolate two components at a time because the results fit in 16 bits. The lower precision code is only used in the fallback code and not in any of the specialized code for NEON. This means pixman gives different results depending on the cpu which isn't great. However, this was easiest and the NEON code doesn't gain as much from using lower precision. Skia actually uses even lower interpolation when working with 565 but that's harder to plug in right now, and this gives a reasonable improvement.
223 lines
6.1 KiB
Diff
223 lines
6.1 KiB
Diff
summary: Bug 689707. Use lower precision bilinear interpolation. r=joe
|
|
|
|
diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c
|
|
--- a/gfx/cairo/libpixman/src/pixman-bits-image.c
|
|
+++ b/gfx/cairo/libpixman/src/pixman-bits-image.c
|
|
@@ -124,18 +124,18 @@ bits_image_fetch_pixel_bilinear (bits_im
|
|
int height = image->height;
|
|
int x1, y1, x2, y2;
|
|
uint32_t tl, tr, bl, br;
|
|
int32_t distx, disty;
|
|
|
|
x1 = x - pixman_fixed_1 / 2;
|
|
y1 = y - pixman_fixed_1 / 2;
|
|
|
|
- distx = (x1 >> 8) & 0xff;
|
|
- disty = (y1 >> 8) & 0xff;
|
|
+ distx = interpolation_coord(x1);
|
|
+ disty = interpolation_coord(y1);
|
|
|
|
x1 = pixman_fixed_to_int (x1);
|
|
y1 = pixman_fixed_to_int (y1);
|
|
x2 = x1 + 1;
|
|
y2 = y1 + 1;
|
|
|
|
if (repeat_mode != PIXMAN_REPEAT_NONE)
|
|
{
|
|
@@ -190,17 +190,17 @@ bits_image_fetch_bilinear_no_repeat_8888
|
|
|
|
if (!pixman_transform_point_3d (bits->common.transform, &v))
|
|
return;
|
|
|
|
ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0];
|
|
x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2;
|
|
|
|
y = v.vector[1] - pixman_fixed_1/2;
|
|
- disty = (y >> 8) & 0xff;
|
|
+ disty = interpolation_coord(y);
|
|
|
|
/* Load the pointers to the first and second lines from the source
|
|
* image that bilinear code must read.
|
|
*
|
|
* The main trick in this code is about the check if any line are
|
|
* outside of the image;
|
|
*
|
|
* When I realize that a line (any one) is outside, I change
|
|
@@ -299,17 +299,17 @@ bits_image_fetch_bilinear_no_repeat_8888
|
|
while (buffer < end && x < 0)
|
|
{
|
|
uint32_t tr, br;
|
|
int32_t distx;
|
|
|
|
tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask;
|
|
br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
|
|
|
|
- distx = (x >> 8) & 0xff;
|
|
+ distx = interpolation_coord(x);
|
|
|
|
*buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty);
|
|
|
|
x += ux;
|
|
x_top += ux_top;
|
|
x_bottom += ux_bottom;
|
|
mask += mask_inc;
|
|
}
|
|
@@ -324,17 +324,17 @@ bits_image_fetch_bilinear_no_repeat_8888
|
|
uint32_t tl, tr, bl, br;
|
|
int32_t distx;
|
|
|
|
tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
|
|
tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask;
|
|
bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
|
|
br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask;
|
|
|
|
- distx = (x >> 8) & 0xff;
|
|
+ distx = interpolation_coord(x);
|
|
|
|
*buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty);
|
|
}
|
|
|
|
buffer++;
|
|
x += ux;
|
|
x_top += ux_top;
|
|
x_bottom += ux_bottom;
|
|
@@ -348,17 +348,17 @@ bits_image_fetch_bilinear_no_repeat_8888
|
|
if (*mask)
|
|
{
|
|
uint32_t tl, bl;
|
|
int32_t distx;
|
|
|
|
tl = top_row [pixman_fixed_to_int (x_top)] | top_mask;
|
|
bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask;
|
|
|
|
- distx = (x >> 8) & 0xff;
|
|
+ distx = interpolation_coord(x);
|
|
|
|
*buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty);
|
|
}
|
|
|
|
buffer++;
|
|
x += ux;
|
|
x_top += ux_top;
|
|
x_bottom += ux_bottom;
|
|
@@ -675,18 +675,18 @@ bits_image_fetch_bilinear_affine (pixman
|
|
const uint8_t *row2;
|
|
|
|
if (mask && !mask[i])
|
|
goto next;
|
|
|
|
x1 = x - pixman_fixed_1 / 2;
|
|
y1 = y - pixman_fixed_1 / 2;
|
|
|
|
- distx = (x1 >> 8) & 0xff;
|
|
- disty = (y1 >> 8) & 0xff;
|
|
+ distx = interpolation_coord(x1);
|
|
+ disty = interpolation_coord(y1);
|
|
|
|
y1 = pixman_fixed_to_int (y1);
|
|
y2 = y1 + 1;
|
|
x1 = pixman_fixed_to_int (x1);
|
|
x2 = x1 + 1;
|
|
|
|
if (repeat_mode != PIXMAN_REPEAT_NONE)
|
|
{
|
|
diff --git a/gfx/cairo/libpixman/src/pixman-inlines.h b/gfx/cairo/libpixman/src/pixman-inlines.h
|
|
--- a/gfx/cairo/libpixman/src/pixman-inlines.h
|
|
+++ b/gfx/cairo/libpixman/src/pixman-inlines.h
|
|
@@ -76,16 +76,31 @@ repeat (pixman_repeat_t repeat, int *c,
|
|
{
|
|
*c = MOD (*c, size * 2);
|
|
if (*c >= size)
|
|
*c = size * 2 - *c - 1;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
|
+#define LOW_QUALITY_INTERPOLATION
|
|
+#endif
|
|
+
|
|
+static force_inline int32_t
|
|
+interpolation_coord(pixman_fixed_t t)
|
|
+{
|
|
+#ifdef LOW_QUALITY_INTERPOLATION
|
|
+ return (t >> 12) & 0xf;
|
|
+#else
|
|
+ return (t >> 8) & 0xff;
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
#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;
|
|
@@ -122,16 +137,44 @@ bilinear_interpolation (uint32_t tl, uin
|
|
f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
|
|
r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
|
|
|
|
return (uint32_t)(r >> 16);
|
|
}
|
|
|
|
#else
|
|
|
|
+#ifdef LOW_QUALITY_INTERPOLATION
|
|
+/* Based on Filter_32_opaque_portable from Skia */
|
|
+static force_inline uint32_t
|
|
+bilinear_interpolation(uint32_t a00, uint32_t a01,
|
|
+ uint32_t a10, uint32_t a11,
|
|
+ int x, int y)
|
|
+{
|
|
+ int xy = x * y;
|
|
+ static const uint32_t mask = 0xff00ff;
|
|
+
|
|
+ int scale = 256 - 16*y - 16*x + xy;
|
|
+ uint32_t lo = (a00 & mask) * scale;
|
|
+ uint32_t hi = ((a00 >> 8) & mask) * scale;
|
|
+
|
|
+ scale = 16*x - xy;
|
|
+ lo += (a01 & mask) * scale;
|
|
+ hi += ((a01 >> 8) & mask) * scale;
|
|
+
|
|
+ scale = 16*y - xy;
|
|
+ lo += (a10 & mask) * scale;
|
|
+ hi += ((a10 >> 8) & mask) * scale;
|
|
+
|
|
+ lo += (a11 & mask) * xy;
|
|
+ hi += ((a11 >> 8) & mask) * xy;
|
|
+
|
|
+ return ((lo >> 8) & mask) | (hi & ~mask);
|
|
+}
|
|
+#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;
|
|
|
|
@@ -164,17 +207,17 @@ bilinear_interpolation (uint32_t tl, uin
|
|
|
|
/* Alpha */
|
|
f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
|
|
+ (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
|
|
r |= f & 0xff000000;
|
|
|
|
return r;
|
|
}
|
|
-
|
|
+#endif
|
|
#endif
|
|
|
|
/*
|
|
* For each scanline fetched from source image with PAD repeat:
|
|
* - calculate how many pixels need to be padded on the left side
|
|
* - calculate how many pixels need to be padded on the right side
|
|
* - update width to only count pixels which are fetched from the image
|
|
* All this information is returned via 'width', 'left_pad', 'right_pad'
|