mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 689707. Use lower precision bilinear interpolation. r=joe
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.
This commit is contained in:
parent
5e7b552f26
commit
4a37a54063
@ -192,6 +192,8 @@ pixman-export.patch: use cairo_public for PIXMAN_EXPORT to make sure pixman symb
|
||||
|
||||
pixman-limits.patch: include limits.h for SIZE_MAX
|
||||
|
||||
pixman-lowres-interp.patch: Use lower quality interpolation for more speed.
|
||||
|
||||
==== disable printing patch ====
|
||||
|
||||
disable-printing.patch: allows us to use NS_PRINTING to disable printing.
|
||||
|
@ -129,8 +129,8 @@ bits_image_fetch_pixel_bilinear (bits_image_t *image,
|
||||
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);
|
||||
@ -195,7 +195,7 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
|
||||
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.
|
||||
@ -304,7 +304,7 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
|
||||
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);
|
||||
|
||||
@ -329,7 +329,7 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
|
||||
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);
|
||||
}
|
||||
@ -353,7 +353,7 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima,
|
||||
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);
|
||||
}
|
||||
@ -680,8 +680,8 @@ bits_image_fetch_bilinear_affine (pixman_image_t * image,
|
||||
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;
|
||||
|
@ -81,6 +81,21 @@ repeat (pixman_repeat_t repeat, int *c, int size)
|
||||
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
|
||||
@ -127,6 +142,34 @@ bilinear_interpolation (uint32_t tl, uint32_t tr,
|
||||
|
||||
#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,
|
||||
@ -169,7 +212,7 @@ bilinear_interpolation (uint32_t tl, uint32_t tr,
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
222
gfx/cairo/pixman-lowres-interp.patch
Normal file
222
gfx/cairo/pixman-lowres-interp.patch
Normal file
@ -0,0 +1,222 @@
|
||||
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'
|
@ -10,7 +10,7 @@
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body style="margin:0; filter:url(#thresholdAt150);">
|
||||
<body style="margin:0; filter:url(#thresholdAt159);">
|
||||
<div style="background: white; overflow: hidden;">
|
||||
<div style="margin:20px 0px 20px 40px; width:40px; height:20px;
|
||||
background:-moz-element(#p);
|
||||
@ -27,11 +27,11 @@
|
||||
</svg>
|
||||
|
||||
<svg>
|
||||
<filter id="thresholdAt150" color-interpolation-filters="sRGB">
|
||||
<filter id="thresholdAt159" color-interpolation-filters="sRGB">
|
||||
<feComponentTransfer>
|
||||
<feFuncR type="linear" slope="255" intercept="-150"/>
|
||||
<feFuncG type="linear" slope="255" intercept="-150"/>
|
||||
<feFuncB type="linear" slope="255" intercept="-150"/>
|
||||
<feFuncR type="linear" slope="255" intercept="-159"/>
|
||||
<feFuncG type="linear" slope="255" intercept="-159"/>
|
||||
<feFuncB type="linear" slope="255" intercept="-159"/>
|
||||
</feComponentTransfer>
|
||||
</filter>
|
||||
</svg>
|
||||
|
Loading…
Reference in New Issue
Block a user