|
1 summary: Bug 689707. Use lower precision bilinear interpolation. r=joe |
|
2 |
|
3 diff --git a/gfx/cairo/libpixman/src/pixman-bits-image.c b/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
4 --- a/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
5 +++ b/gfx/cairo/libpixman/src/pixman-bits-image.c |
|
6 @@ -124,18 +124,18 @@ bits_image_fetch_pixel_bilinear (bits_im |
|
7 int height = image->height; |
|
8 int x1, y1, x2, y2; |
|
9 uint32_t tl, tr, bl, br; |
|
10 int32_t distx, disty; |
|
11 |
|
12 x1 = x - pixman_fixed_1 / 2; |
|
13 y1 = y - pixman_fixed_1 / 2; |
|
14 |
|
15 - distx = (x1 >> 8) & 0xff; |
|
16 - disty = (y1 >> 8) & 0xff; |
|
17 + distx = interpolation_coord(x1); |
|
18 + disty = interpolation_coord(y1); |
|
19 |
|
20 x1 = pixman_fixed_to_int (x1); |
|
21 y1 = pixman_fixed_to_int (y1); |
|
22 x2 = x1 + 1; |
|
23 y2 = y1 + 1; |
|
24 |
|
25 if (repeat_mode != PIXMAN_REPEAT_NONE) |
|
26 { |
|
27 @@ -190,17 +190,17 @@ bits_image_fetch_bilinear_no_repeat_8888 |
|
28 |
|
29 if (!pixman_transform_point_3d (bits->common.transform, &v)) |
|
30 return; |
|
31 |
|
32 ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; |
|
33 x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; |
|
34 |
|
35 y = v.vector[1] - pixman_fixed_1/2; |
|
36 - disty = (y >> 8) & 0xff; |
|
37 + disty = interpolation_coord(y); |
|
38 |
|
39 /* Load the pointers to the first and second lines from the source |
|
40 * image that bilinear code must read. |
|
41 * |
|
42 * The main trick in this code is about the check if any line are |
|
43 * outside of the image; |
|
44 * |
|
45 * When I realize that a line (any one) is outside, I change |
|
46 @@ -299,17 +299,17 @@ bits_image_fetch_bilinear_no_repeat_8888 |
|
47 while (buffer < end && x < 0) |
|
48 { |
|
49 uint32_t tr, br; |
|
50 int32_t distx; |
|
51 |
|
52 tr = top_row[pixman_fixed_to_int (x_top) + 1] | top_mask; |
|
53 br = bottom_row[pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; |
|
54 |
|
55 - distx = (x >> 8) & 0xff; |
|
56 + distx = interpolation_coord(x); |
|
57 |
|
58 *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); |
|
59 |
|
60 x += ux; |
|
61 x_top += ux_top; |
|
62 x_bottom += ux_bottom; |
|
63 mask += mask_inc; |
|
64 } |
|
65 @@ -324,17 +324,17 @@ bits_image_fetch_bilinear_no_repeat_8888 |
|
66 uint32_t tl, tr, bl, br; |
|
67 int32_t distx; |
|
68 |
|
69 tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; |
|
70 tr = top_row [pixman_fixed_to_int (x_top) + 1] | top_mask; |
|
71 bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; |
|
72 br = bottom_row [pixman_fixed_to_int (x_bottom) + 1] | bottom_mask; |
|
73 |
|
74 - distx = (x >> 8) & 0xff; |
|
75 + distx = interpolation_coord(x); |
|
76 |
|
77 *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); |
|
78 } |
|
79 |
|
80 buffer++; |
|
81 x += ux; |
|
82 x_top += ux_top; |
|
83 x_bottom += ux_bottom; |
|
84 @@ -348,17 +348,17 @@ bits_image_fetch_bilinear_no_repeat_8888 |
|
85 if (*mask) |
|
86 { |
|
87 uint32_t tl, bl; |
|
88 int32_t distx; |
|
89 |
|
90 tl = top_row [pixman_fixed_to_int (x_top)] | top_mask; |
|
91 bl = bottom_row [pixman_fixed_to_int (x_bottom)] | bottom_mask; |
|
92 |
|
93 - distx = (x >> 8) & 0xff; |
|
94 + distx = interpolation_coord(x); |
|
95 |
|
96 *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); |
|
97 } |
|
98 |
|
99 buffer++; |
|
100 x += ux; |
|
101 x_top += ux_top; |
|
102 x_bottom += ux_bottom; |
|
103 @@ -675,18 +675,18 @@ bits_image_fetch_bilinear_affine (pixman |
|
104 const uint8_t *row2; |
|
105 |
|
106 if (mask && !mask[i]) |
|
107 goto next; |
|
108 |
|
109 x1 = x - pixman_fixed_1 / 2; |
|
110 y1 = y - pixman_fixed_1 / 2; |
|
111 |
|
112 - distx = (x1 >> 8) & 0xff; |
|
113 - disty = (y1 >> 8) & 0xff; |
|
114 + distx = interpolation_coord(x1); |
|
115 + disty = interpolation_coord(y1); |
|
116 |
|
117 y1 = pixman_fixed_to_int (y1); |
|
118 y2 = y1 + 1; |
|
119 x1 = pixman_fixed_to_int (x1); |
|
120 x2 = x1 + 1; |
|
121 |
|
122 if (repeat_mode != PIXMAN_REPEAT_NONE) |
|
123 { |
|
124 diff --git a/gfx/cairo/libpixman/src/pixman-inlines.h b/gfx/cairo/libpixman/src/pixman-inlines.h |
|
125 --- a/gfx/cairo/libpixman/src/pixman-inlines.h |
|
126 +++ b/gfx/cairo/libpixman/src/pixman-inlines.h |
|
127 @@ -76,16 +76,31 @@ repeat (pixman_repeat_t repeat, int *c, |
|
128 { |
|
129 *c = MOD (*c, size * 2); |
|
130 if (*c >= size) |
|
131 *c = size * 2 - *c - 1; |
|
132 } |
|
133 return TRUE; |
|
134 } |
|
135 |
|
136 +#ifdef MOZ_GFX_OPTIMIZE_MOBILE |
|
137 +#define LOW_QUALITY_INTERPOLATION |
|
138 +#endif |
|
139 + |
|
140 +static force_inline int32_t |
|
141 +interpolation_coord(pixman_fixed_t t) |
|
142 +{ |
|
143 +#ifdef LOW_QUALITY_INTERPOLATION |
|
144 + return (t >> 12) & 0xf; |
|
145 +#else |
|
146 + return (t >> 8) & 0xff; |
|
147 +#endif |
|
148 +} |
|
149 + |
|
150 + |
|
151 #if SIZEOF_LONG > 4 |
|
152 |
|
153 static force_inline uint32_t |
|
154 bilinear_interpolation (uint32_t tl, uint32_t tr, |
|
155 uint32_t bl, uint32_t br, |
|
156 int distx, int disty) |
|
157 { |
|
158 uint64_t distxy, distxiy, distixy, distixiy; |
|
159 @@ -122,16 +137,44 @@ bilinear_interpolation (uint32_t tl, uin |
|
160 f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy; |
|
161 r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull); |
|
162 |
|
163 return (uint32_t)(r >> 16); |
|
164 } |
|
165 |
|
166 #else |
|
167 |
|
168 +#ifdef LOW_QUALITY_INTERPOLATION |
|
169 +/* Based on Filter_32_opaque_portable from Skia */ |
|
170 +static force_inline uint32_t |
|
171 +bilinear_interpolation(uint32_t a00, uint32_t a01, |
|
172 + uint32_t a10, uint32_t a11, |
|
173 + int x, int y) |
|
174 +{ |
|
175 + int xy = x * y; |
|
176 + static const uint32_t mask = 0xff00ff; |
|
177 + |
|
178 + int scale = 256 - 16*y - 16*x + xy; |
|
179 + uint32_t lo = (a00 & mask) * scale; |
|
180 + uint32_t hi = ((a00 >> 8) & mask) * scale; |
|
181 + |
|
182 + scale = 16*x - xy; |
|
183 + lo += (a01 & mask) * scale; |
|
184 + hi += ((a01 >> 8) & mask) * scale; |
|
185 + |
|
186 + scale = 16*y - xy; |
|
187 + lo += (a10 & mask) * scale; |
|
188 + hi += ((a10 >> 8) & mask) * scale; |
|
189 + |
|
190 + lo += (a11 & mask) * xy; |
|
191 + hi += ((a11 >> 8) & mask) * xy; |
|
192 + |
|
193 + return ((lo >> 8) & mask) | (hi & ~mask); |
|
194 +} |
|
195 +#else |
|
196 static force_inline uint32_t |
|
197 bilinear_interpolation (uint32_t tl, uint32_t tr, |
|
198 uint32_t bl, uint32_t br, |
|
199 int distx, int disty) |
|
200 { |
|
201 int distxy, distxiy, distixy, distixiy; |
|
202 uint32_t f, r; |
|
203 |
|
204 @@ -164,17 +207,17 @@ bilinear_interpolation (uint32_t tl, uin |
|
205 |
|
206 /* Alpha */ |
|
207 f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy |
|
208 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy; |
|
209 r |= f & 0xff000000; |
|
210 |
|
211 return r; |
|
212 } |
|
213 - |
|
214 +#endif |
|
215 #endif |
|
216 |
|
217 /* |
|
218 * For each scanline fetched from source image with PAD repeat: |
|
219 * - calculate how many pixels need to be padded on the left side |
|
220 * - calculate how many pixels need to be padded on the right side |
|
221 * - update width to only count pixels which are fetched from the image |
|
222 * All this information is returned via 'width', 'left_pad', 'right_pad' |