Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2 /*
3 * Copyright © 2000 SuSE, Inc.
4 * Copyright © 2007 Red Hat, Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of SuSE not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. SuSE makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
15 *
16 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: Keith Packard, SuSE, Inc.
24 */
26 #ifndef PIXMAN_FAST_PATH_H__
27 #define PIXMAN_FAST_PATH_H__
29 #include "pixman-private.h"
31 #define PIXMAN_REPEAT_COVER -1
33 static force_inline pixman_bool_t
34 repeat (pixman_repeat_t repeat, int *c, int size)
35 {
36 if (repeat == PIXMAN_REPEAT_NONE)
37 {
38 if (*c < 0 || *c >= size)
39 return FALSE;
40 }
41 else if (repeat == PIXMAN_REPEAT_NORMAL)
42 {
43 while (*c >= size)
44 *c -= size;
45 while (*c < 0)
46 *c += size;
47 }
48 else if (repeat == PIXMAN_REPEAT_PAD)
49 {
50 *c = CLIP (*c, 0, size - 1);
51 }
52 else /* REFLECT */
53 {
54 *c = MOD (*c, size * 2);
55 if (*c >= size)
56 *c = size * 2 - *c - 1;
57 }
58 return TRUE;
59 }
61 /*
62 * For each scanline fetched from source image with PAD repeat:
63 * - calculate how many pixels need to be padded on the left side
64 * - calculate how many pixels need to be padded on the right side
65 * - update width to only count pixels which are fetched from the image
66 * All this information is returned via 'width', 'left_pad', 'right_pad'
67 * arguments. The code is assuming that 'unit_x' is positive.
68 *
69 * Note: 64-bit math is used in order to avoid potential overflows, which
70 * is probably excessive in many cases. This particular function
71 * may need its own correctness test and performance tuning.
72 */
73 static force_inline void
74 pad_repeat_get_scanline_bounds (int32_t source_image_width,
75 pixman_fixed_t vx,
76 pixman_fixed_t unit_x,
77 int32_t * width,
78 int32_t * left_pad,
79 int32_t * right_pad)
80 {
81 int64_t max_vx = (int64_t) source_image_width << 16;
82 int64_t tmp;
83 if (vx < 0)
84 {
85 tmp = ((int64_t) unit_x - 1 - vx) / unit_x;
86 if (tmp > *width)
87 {
88 *left_pad = *width;
89 *width = 0;
90 }
91 else
92 {
93 *left_pad = (int32_t) tmp;
94 *width -= (int32_t) tmp;
95 }
96 }
97 else
98 {
99 *left_pad = 0;
100 }
101 tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad;
102 if (tmp < 0)
103 {
104 *right_pad = *width;
105 *width = 0;
106 }
107 else if (tmp >= *width)
108 {
109 *right_pad = 0;
110 }
111 else
112 {
113 *right_pad = *width - (int32_t) tmp;
114 *width = (int32_t) tmp;
115 }
116 }
118 /* A macroified version of specialized nearest scalers for some
119 * common 8888 and 565 formats. It supports SRC and OVER ops.
120 *
121 * There are two repeat versions, one that handles repeat normal,
122 * and one without repeat handling that only works if the src region
123 * used is completely covered by the pre-repeated source samples.
124 *
125 * The loops are unrolled to process two pixels per iteration for better
126 * performance on most CPU architectures (superscalar processors
127 * can issue several operations simultaneously, other processors can hide
128 * instructions latencies by pipelining operations). Unrolling more
129 * does not make much sense because the compiler will start running out
130 * of spare registers soon.
131 */
133 #define GET_8888_ALPHA(s) ((s) >> 24)
134 /* This is not actually used since we don't have an OVER with
135 565 source, but it is needed to build. */
136 #define GET_0565_ALPHA(s) 0xff
138 #define FAST_NEAREST_SCANLINE(scanline_func_name, SRC_FORMAT, DST_FORMAT, \
139 src_type_t, dst_type_t, OP, repeat_mode) \
140 static force_inline void \
141 scanline_func_name (dst_type_t *dst, \
142 const src_type_t *src, \
143 int32_t w, \
144 pixman_fixed_t vx, \
145 pixman_fixed_t unit_x, \
146 pixman_fixed_t max_vx, \
147 pixman_bool_t fully_transparent_src) \
148 { \
149 uint32_t d; \
150 src_type_t s1, s2; \
151 uint8_t a1, a2; \
152 int x1, x2; \
153 \
154 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER && fully_transparent_src) \
155 return; \
156 \
157 if (PIXMAN_OP_ ## OP != PIXMAN_OP_SRC && PIXMAN_OP_ ## OP != PIXMAN_OP_OVER) \
158 abort(); \
159 \
160 while ((w -= 2) >= 0) \
161 { \
162 x1 = vx >> 16; \
163 vx += unit_x; \
164 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
165 { \
166 /* This works because we know that unit_x is positive */ \
167 while (vx >= max_vx) \
168 vx -= max_vx; \
169 } \
170 s1 = src[x1]; \
171 \
172 x2 = vx >> 16; \
173 vx += unit_x; \
174 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
175 { \
176 /* This works because we know that unit_x is positive */ \
177 while (vx >= max_vx) \
178 vx -= max_vx; \
179 } \
180 s2 = src[x2]; \
181 \
182 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
183 { \
184 a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
185 a2 = GET_ ## SRC_FORMAT ## _ALPHA(s2); \
186 \
187 if (a1 == 0xff) \
188 { \
189 *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \
190 } \
191 else if (s1) \
192 { \
193 d = CONVERT_ ## DST_FORMAT ## _TO_8888 (*dst); \
194 s1 = CONVERT_ ## SRC_FORMAT ## _TO_8888 (s1); \
195 a1 ^= 0xff; \
196 UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
197 *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \
198 } \
199 dst++; \
200 \
201 if (a2 == 0xff) \
202 { \
203 *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s2); \
204 } \
205 else if (s2) \
206 { \
207 d = CONVERT_## DST_FORMAT ## _TO_8888 (*dst); \
208 s2 = CONVERT_## SRC_FORMAT ## _TO_8888 (s2); \
209 a2 ^= 0xff; \
210 UN8x4_MUL_UN8_ADD_UN8x4 (d, a2, s2); \
211 *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \
212 } \
213 dst++; \
214 } \
215 else /* PIXMAN_OP_SRC */ \
216 { \
217 *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \
218 *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s2); \
219 } \
220 } \
221 \
222 if (w & 1) \
223 { \
224 x1 = vx >> 16; \
225 s1 = src[x1]; \
226 \
227 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
228 { \
229 a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
230 \
231 if (a1 == 0xff) \
232 { \
233 *dst = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \
234 } \
235 else if (s1) \
236 { \
237 d = CONVERT_## DST_FORMAT ## _TO_8888 (*dst); \
238 s1 = CONVERT_ ## SRC_FORMAT ## _TO_8888 (s1); \
239 a1 ^= 0xff; \
240 UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
241 *dst = CONVERT_8888_TO_ ## DST_FORMAT (d); \
242 } \
243 dst++; \
244 } \
245 else /* PIXMAN_OP_SRC */ \
246 { \
247 *dst++ = CONVERT_ ## SRC_FORMAT ## _TO_ ## DST_FORMAT (s1); \
248 } \
249 } \
250 }
252 #define FAST_NEAREST_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
253 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
254 static void \
255 fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, \
256 pixman_op_t op, \
257 pixman_image_t * src_image, \
258 pixman_image_t * mask_image, \
259 pixman_image_t * dst_image, \
260 int32_t src_x, \
261 int32_t src_y, \
262 int32_t mask_x, \
263 int32_t mask_y, \
264 int32_t dst_x, \
265 int32_t dst_y, \
266 int32_t width, \
267 int32_t height) \
268 { \
269 dst_type_t *dst_line; \
270 mask_type_t *mask_line; \
271 src_type_t *src_first_line; \
272 int y; \
273 pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \
274 pixman_fixed_t max_vy; \
275 pixman_vector_t v; \
276 pixman_fixed_t vx, vy; \
277 pixman_fixed_t unit_x, unit_y; \
278 int32_t left_pad, right_pad; \
279 \
280 src_type_t *src; \
281 dst_type_t *dst; \
282 mask_type_t solid_mask; \
283 const mask_type_t *mask = &solid_mask; \
284 int src_stride, mask_stride, dst_stride; \
285 \
286 PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, dst_type_t, dst_stride, dst_line, 1); \
287 if (have_mask) \
288 { \
289 if (mask_is_solid) \
290 solid_mask = _pixman_image_get_solid (imp, mask_image, dst_image->bits.format); \
291 else \
292 PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
293 mask_stride, mask_line, 1); \
294 } \
295 /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
296 * transformed from destination space to source space */ \
297 PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
298 \
299 /* reference point is the center of the pixel */ \
300 v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
301 v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
302 v.vector[2] = pixman_fixed_1; \
303 \
304 if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
305 return; \
306 \
307 unit_x = src_image->common.transform->matrix[0][0]; \
308 unit_y = src_image->common.transform->matrix[1][1]; \
309 \
310 /* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */ \
311 v.vector[0] -= pixman_fixed_e; \
312 v.vector[1] -= pixman_fixed_e; \
313 \
314 vx = v.vector[0]; \
315 vy = v.vector[1]; \
316 \
317 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
318 { \
319 /* Clamp repeating positions inside the actual samples */ \
320 max_vx = src_image->bits.width << 16; \
321 max_vy = src_image->bits.height << 16; \
322 \
323 repeat (PIXMAN_REPEAT_NORMAL, &vx, max_vx); \
324 repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
325 } \
326 \
327 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
328 PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
329 { \
330 pad_repeat_get_scanline_bounds (src_image->bits.width, vx, unit_x, \
331 &width, &left_pad, &right_pad); \
332 vx += left_pad * unit_x; \
333 } \
334 \
335 while (--height >= 0) \
336 { \
337 dst = dst_line; \
338 dst_line += dst_stride; \
339 if (have_mask && !mask_is_solid) \
340 { \
341 mask = mask_line; \
342 mask_line += mask_stride; \
343 } \
344 \
345 y = vy >> 16; \
346 vy += unit_y; \
347 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
348 repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
349 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
350 { \
351 repeat (PIXMAN_REPEAT_PAD, &y, src_image->bits.height); \
352 src = src_first_line + src_stride * y; \
353 if (left_pad > 0) \
354 { \
355 scanline_func (mask, dst, src, left_pad, 0, 0, 0, FALSE); \
356 } \
357 if (width > 0) \
358 { \
359 scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
360 dst + left_pad, src, width, vx, unit_x, 0, FALSE); \
361 } \
362 if (right_pad > 0) \
363 { \
364 scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
365 dst + left_pad + width, src + src_image->bits.width - 1, \
366 right_pad, 0, 0, 0, FALSE); \
367 } \
368 } \
369 else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
370 { \
371 static const src_type_t zero[1] = { 0 }; \
372 if (y < 0 || y >= src_image->bits.height) \
373 { \
374 scanline_func (mask, dst, zero, left_pad + width + right_pad, 0, 0, 0, TRUE); \
375 continue; \
376 } \
377 src = src_first_line + src_stride * y; \
378 if (left_pad > 0) \
379 { \
380 scanline_func (mask, dst, zero, left_pad, 0, 0, 0, TRUE); \
381 } \
382 if (width > 0) \
383 { \
384 scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
385 dst + left_pad, src, width, vx, unit_x, 0, FALSE); \
386 } \
387 if (right_pad > 0) \
388 { \
389 scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
390 dst + left_pad + width, zero, right_pad, 0, 0, 0, TRUE); \
391 } \
392 } \
393 else \
394 { \
395 src = src_first_line + src_stride * y; \
396 scanline_func (mask, dst, src, width, vx, unit_x, max_vx, FALSE); \
397 } \
398 } \
399 }
401 /* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
402 #define FAST_NEAREST_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
403 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
404 FAST_NEAREST_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t, \
405 dst_type_t, repeat_mode, have_mask, mask_is_solid)
407 #define FAST_NEAREST_MAINLOOP_NOMASK(scale_func_name, scanline_func, src_type_t, dst_type_t, \
408 repeat_mode) \
409 static force_inline void \
410 scanline_func##scale_func_name##_wrapper ( \
411 const uint8_t *mask, \
412 dst_type_t *dst, \
413 const src_type_t *src, \
414 int32_t w, \
415 pixman_fixed_t vx, \
416 pixman_fixed_t unit_x, \
417 pixman_fixed_t max_vx, \
418 pixman_bool_t fully_transparent_src) \
419 { \
420 scanline_func (dst, src, w, vx, unit_x, max_vx, fully_transparent_src); \
421 } \
422 FAST_NEAREST_MAINLOOP_INT (scale_func_name, scanline_func##scale_func_name##_wrapper, \
423 src_type_t, uint8_t, dst_type_t, repeat_mode, FALSE, FALSE)
425 #define FAST_NEAREST_MAINLOOP(scale_func_name, scanline_func, src_type_t, dst_type_t, \
426 repeat_mode) \
427 FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name, scanline_func, src_type_t, \
428 dst_type_t, repeat_mode)
430 #define FAST_NEAREST(scale_func_name, SRC_FORMAT, DST_FORMAT, \
431 src_type_t, dst_type_t, OP, repeat_mode) \
432 FAST_NEAREST_SCANLINE(scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
433 SRC_FORMAT, DST_FORMAT, src_type_t, dst_type_t, \
434 OP, repeat_mode) \
435 FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name ## _ ## OP, \
436 scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
437 src_type_t, dst_type_t, repeat_mode)
440 #define SCALED_NEAREST_FLAGS \
441 (FAST_PATH_SCALE_TRANSFORM | \
442 FAST_PATH_NO_ALPHA_MAP | \
443 FAST_PATH_NEAREST_FILTER | \
444 FAST_PATH_NO_ACCESSORS | \
445 FAST_PATH_NARROW_FORMAT)
447 #define SIMPLE_NEAREST_FAST_PATH_NORMAL(op,s,d,func) \
448 { PIXMAN_OP_ ## op, \
449 PIXMAN_ ## s, \
450 (SCALED_NEAREST_FLAGS | \
451 FAST_PATH_NORMAL_REPEAT | \
452 FAST_PATH_X_UNIT_POSITIVE), \
453 PIXMAN_null, 0, \
454 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
455 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
456 }
458 #define SIMPLE_NEAREST_FAST_PATH_PAD(op,s,d,func) \
459 { PIXMAN_OP_ ## op, \
460 PIXMAN_ ## s, \
461 (SCALED_NEAREST_FLAGS | \
462 FAST_PATH_PAD_REPEAT | \
463 FAST_PATH_X_UNIT_POSITIVE), \
464 PIXMAN_null, 0, \
465 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
466 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
467 }
469 #define SIMPLE_NEAREST_FAST_PATH_NONE(op,s,d,func) \
470 { PIXMAN_OP_ ## op, \
471 PIXMAN_ ## s, \
472 (SCALED_NEAREST_FLAGS | \
473 FAST_PATH_NONE_REPEAT | \
474 FAST_PATH_X_UNIT_POSITIVE), \
475 PIXMAN_null, 0, \
476 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
477 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
478 }
480 #define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func) \
481 { PIXMAN_OP_ ## op, \
482 PIXMAN_ ## s, \
483 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
484 PIXMAN_null, 0, \
485 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
486 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
487 }
489 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \
490 { PIXMAN_OP_ ## op, \
491 PIXMAN_ ## s, \
492 (SCALED_NEAREST_FLAGS | \
493 FAST_PATH_NORMAL_REPEAT | \
494 FAST_PATH_X_UNIT_POSITIVE), \
495 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
496 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
497 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
498 }
500 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
501 { PIXMAN_OP_ ## op, \
502 PIXMAN_ ## s, \
503 (SCALED_NEAREST_FLAGS | \
504 FAST_PATH_PAD_REPEAT | \
505 FAST_PATH_X_UNIT_POSITIVE), \
506 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
507 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
508 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
509 }
511 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
512 { PIXMAN_OP_ ## op, \
513 PIXMAN_ ## s, \
514 (SCALED_NEAREST_FLAGS | \
515 FAST_PATH_NONE_REPEAT | \
516 FAST_PATH_X_UNIT_POSITIVE), \
517 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
518 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
519 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
520 }
522 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
523 { PIXMAN_OP_ ## op, \
524 PIXMAN_ ## s, \
525 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
526 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
527 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
528 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
529 }
531 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \
532 { PIXMAN_OP_ ## op, \
533 PIXMAN_ ## s, \
534 (SCALED_NEAREST_FLAGS | \
535 FAST_PATH_NORMAL_REPEAT | \
536 FAST_PATH_X_UNIT_POSITIVE), \
537 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
538 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
539 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
540 }
542 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
543 { PIXMAN_OP_ ## op, \
544 PIXMAN_ ## s, \
545 (SCALED_NEAREST_FLAGS | \
546 FAST_PATH_PAD_REPEAT | \
547 FAST_PATH_X_UNIT_POSITIVE), \
548 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
549 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
550 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
551 }
553 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
554 { PIXMAN_OP_ ## op, \
555 PIXMAN_ ## s, \
556 (SCALED_NEAREST_FLAGS | \
557 FAST_PATH_NONE_REPEAT | \
558 FAST_PATH_X_UNIT_POSITIVE), \
559 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
560 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
561 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
562 }
564 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
565 { PIXMAN_OP_ ## op, \
566 PIXMAN_ ## s, \
567 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
568 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
569 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
570 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
571 }
573 /* Prefer the use of 'cover' variant, because it is faster */
574 #define SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \
575 SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \
576 SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \
577 SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \
578 SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func)
580 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \
581 SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
582 SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
583 SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func)
585 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH(op,s,d,func) \
586 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
587 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
588 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func)
590 /*****************************************************************************/
592 /*
593 * Identify 5 zones in each scanline for bilinear scaling. Depending on
594 * whether 2 pixels to be interpolated are fetched from the image itself,
595 * from the padding area around it or from both image and padding area.
596 */
597 static force_inline void
598 bilinear_pad_repeat_get_scanline_bounds (int32_t source_image_width,
599 pixman_fixed_t vx,
600 pixman_fixed_t unit_x,
601 int32_t * left_pad,
602 int32_t * left_tz,
603 int32_t * width,
604 int32_t * right_tz,
605 int32_t * right_pad)
606 {
607 int width1 = *width, left_pad1, right_pad1;
608 int width2 = *width, left_pad2, right_pad2;
610 pad_repeat_get_scanline_bounds (source_image_width, vx, unit_x,
611 &width1, &left_pad1, &right_pad1);
612 pad_repeat_get_scanline_bounds (source_image_width, vx + pixman_fixed_1,
613 unit_x, &width2, &left_pad2, &right_pad2);
615 *left_pad = left_pad2;
616 *left_tz = left_pad1 - left_pad2;
617 *right_tz = right_pad2 - right_pad1;
618 *right_pad = right_pad1;
619 *width -= *left_pad + *left_tz + *right_tz + *right_pad;
620 }
622 /*
623 * Main loop template for single pass bilinear scaling. It needs to be
624 * provided with 'scanline_func' which should do the compositing operation.
625 * The needed function has the following prototype:
626 *
627 * scanline_func (dst_type_t * dst,
628 * const mask_type_ * mask,
629 * const src_type_t * src_top,
630 * const src_type_t * src_bottom,
631 * int32_t width,
632 * int weight_top,
633 * int weight_bottom,
634 * pixman_fixed_t vx,
635 * pixman_fixed_t unit_x,
636 * pixman_fixed_t max_vx,
637 * pixman_bool_t zero_src)
638 *
639 * Where:
640 * dst - destination scanline buffer for storing results
641 * mask - mask buffer (or single value for solid mask)
642 * src_top, src_bottom - two source scanlines
643 * width - number of pixels to process
644 * weight_top - weight of the top row for interpolation
645 * weight_bottom - weight of the bottom row for interpolation
646 * vx - initial position for fetching the first pair of
647 * pixels from the source buffer
648 * unit_x - position increment needed to move to the next pair
649 * of pixels
650 * max_vx - image size as a fixed point value, can be used for
651 * implementing NORMAL repeat (when it is supported)
652 * zero_src - boolean hint variable, which is set to TRUE when
653 * all source pixels are fetched from zero padding
654 * zone for NONE repeat
655 *
656 * Note: normally the sum of 'weight_top' and 'weight_bottom' is equal to 256,
657 * but sometimes it may be less than that for NONE repeat when handling
658 * fuzzy antialiased top or bottom image edges. Also both top and
659 * bottom weight variables are guaranteed to have value in 0-255
660 * range and can fit into unsigned byte or be used with 8-bit SIMD
661 * multiplication instructions.
662 */
663 #define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
664 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
665 static void \
666 fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \
667 pixman_op_t op, \
668 pixman_image_t * src_image, \
669 pixman_image_t * mask_image, \
670 pixman_image_t * dst_image, \
671 int32_t src_x, \
672 int32_t src_y, \
673 int32_t mask_x, \
674 int32_t mask_y, \
675 int32_t dst_x, \
676 int32_t dst_y, \
677 int32_t width, \
678 int32_t height) \
679 { \
680 dst_type_t *dst_line; \
681 mask_type_t *mask_line; \
682 src_type_t *src_first_line; \
683 int y1, y2; \
684 pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \
685 pixman_vector_t v; \
686 pixman_fixed_t vx, vy; \
687 pixman_fixed_t unit_x, unit_y; \
688 int32_t left_pad, left_tz, right_tz, right_pad; \
689 \
690 dst_type_t *dst; \
691 mask_type_t solid_mask; \
692 const mask_type_t *mask = &solid_mask; \
693 int src_stride, mask_stride, dst_stride; \
694 \
695 PIXMAN_IMAGE_GET_LINE (dst_image, dst_x, dst_y, dst_type_t, dst_stride, dst_line, 1); \
696 if (have_mask) \
697 { \
698 if (mask_is_solid) \
699 { \
700 solid_mask = _pixman_image_get_solid (imp, mask_image, dst_image->bits.format); \
701 mask_stride = 0; \
702 } \
703 else \
704 { \
705 PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
706 mask_stride, mask_line, 1); \
707 } \
708 } \
709 /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
710 * transformed from destination space to source space */ \
711 PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
712 \
713 /* reference point is the center of the pixel */ \
714 v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
715 v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
716 v.vector[2] = pixman_fixed_1; \
717 \
718 if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
719 return; \
720 \
721 unit_x = src_image->common.transform->matrix[0][0]; \
722 unit_y = src_image->common.transform->matrix[1][1]; \
723 \
724 v.vector[0] -= pixman_fixed_1 / 2; \
725 v.vector[1] -= pixman_fixed_1 / 2; \
726 \
727 vy = v.vector[1]; \
728 \
729 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
730 PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
731 { \
732 bilinear_pad_repeat_get_scanline_bounds (src_image->bits.width, v.vector[0], unit_x, \
733 &left_pad, &left_tz, &width, &right_tz, &right_pad); \
734 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
735 { \
736 /* PAD repeat does not need special handling for 'transition zones' and */ \
737 /* they can be combined with 'padding zones' safely */ \
738 left_pad += left_tz; \
739 right_pad += right_tz; \
740 left_tz = right_tz = 0; \
741 } \
742 v.vector[0] += left_pad * unit_x; \
743 } \
744 \
745 while (--height >= 0) \
746 { \
747 int weight1, weight2; \
748 dst = dst_line; \
749 dst_line += dst_stride; \
750 vx = v.vector[0]; \
751 if (have_mask && !mask_is_solid) \
752 { \
753 mask = mask_line; \
754 mask_line += mask_stride; \
755 } \
756 \
757 y1 = pixman_fixed_to_int (vy); \
758 weight2 = (vy >> 8) & 0xff; \
759 if (weight2) \
760 { \
761 /* normal case, both row weights are in 0-255 range and fit unsigned byte */ \
762 y2 = y1 + 1; \
763 weight1 = 256 - weight2; \
764 } \
765 else \
766 { \
767 /* set both top and bottom row to the same scanline, and weights to 128+128 */ \
768 y2 = y1; \
769 weight1 = weight2 = 128; \
770 } \
771 vy += unit_y; \
772 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
773 { \
774 src_type_t *src1, *src2; \
775 src_type_t buf1[2]; \
776 src_type_t buf2[2]; \
777 repeat (PIXMAN_REPEAT_PAD, &y1, src_image->bits.height); \
778 repeat (PIXMAN_REPEAT_PAD, &y2, src_image->bits.height); \
779 src1 = src_first_line + src_stride * y1; \
780 src2 = src_first_line + src_stride * y2; \
781 \
782 if (left_pad > 0) \
783 { \
784 buf1[0] = buf1[1] = src1[0]; \
785 buf2[0] = buf2[1] = src2[0]; \
786 scanline_func (dst, mask, \
787 buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, FALSE); \
788 dst += left_pad; \
789 if (have_mask && !mask_is_solid) \
790 mask += left_pad; \
791 } \
792 if (width > 0) \
793 { \
794 scanline_func (dst, mask, \
795 src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
796 dst += width; \
797 if (have_mask && !mask_is_solid) \
798 mask += width; \
799 } \
800 if (right_pad > 0) \
801 { \
802 buf1[0] = buf1[1] = src1[src_image->bits.width - 1]; \
803 buf2[0] = buf2[1] = src2[src_image->bits.width - 1]; \
804 scanline_func (dst, mask, \
805 buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, FALSE); \
806 } \
807 } \
808 else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
809 { \
810 src_type_t *src1, *src2; \
811 src_type_t buf1[2]; \
812 src_type_t buf2[2]; \
813 /* handle top/bottom zero padding by just setting weights to 0 if needed */ \
814 if (y1 < 0) \
815 { \
816 weight1 = 0; \
817 y1 = 0; \
818 } \
819 if (y1 >= src_image->bits.height) \
820 { \
821 weight1 = 0; \
822 y1 = src_image->bits.height - 1; \
823 } \
824 if (y2 < 0) \
825 { \
826 weight2 = 0; \
827 y2 = 0; \
828 } \
829 if (y2 >= src_image->bits.height) \
830 { \
831 weight2 = 0; \
832 y2 = src_image->bits.height - 1; \
833 } \
834 src1 = src_first_line + src_stride * y1; \
835 src2 = src_first_line + src_stride * y2; \
836 \
837 if (left_pad > 0) \
838 { \
839 buf1[0] = buf1[1] = 0; \
840 buf2[0] = buf2[1] = 0; \
841 scanline_func (dst, mask, \
842 buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, TRUE); \
843 dst += left_pad; \
844 if (have_mask && !mask_is_solid) \
845 mask += left_pad; \
846 } \
847 if (left_tz > 0) \
848 { \
849 buf1[0] = 0; \
850 buf1[1] = src1[0]; \
851 buf2[0] = 0; \
852 buf2[1] = src2[0]; \
853 scanline_func (dst, mask, \
854 buf1, buf2, left_tz, weight1, weight2, \
855 pixman_fixed_frac (vx), unit_x, 0, FALSE); \
856 dst += left_tz; \
857 if (have_mask && !mask_is_solid) \
858 mask += left_tz; \
859 vx += left_tz * unit_x; \
860 } \
861 if (width > 0) \
862 { \
863 scanline_func (dst, mask, \
864 src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
865 dst += width; \
866 if (have_mask && !mask_is_solid) \
867 mask += width; \
868 vx += width * unit_x; \
869 } \
870 if (right_tz > 0) \
871 { \
872 buf1[0] = src1[src_image->bits.width - 1]; \
873 buf1[1] = 0; \
874 buf2[0] = src2[src_image->bits.width - 1]; \
875 buf2[1] = 0; \
876 scanline_func (dst, mask, \
877 buf1, buf2, right_tz, weight1, weight2, \
878 pixman_fixed_frac (vx), unit_x, 0, FALSE); \
879 dst += right_tz; \
880 if (have_mask && !mask_is_solid) \
881 mask += right_tz; \
882 } \
883 if (right_pad > 0) \
884 { \
885 buf1[0] = buf1[1] = 0; \
886 buf2[0] = buf2[1] = 0; \
887 scanline_func (dst, mask, \
888 buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, TRUE); \
889 } \
890 } \
891 else \
892 { \
893 scanline_func (dst, mask, src_first_line + src_stride * y1, \
894 src_first_line + src_stride * y2, width, \
895 weight1, weight2, vx, unit_x, max_vx, FALSE); \
896 } \
897 } \
898 }
900 /* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
901 #define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
902 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
903 FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t,\
904 dst_type_t, repeat_mode, have_mask, mask_is_solid)
906 #define SCALED_BILINEAR_FLAGS \
907 (FAST_PATH_SCALE_TRANSFORM | \
908 FAST_PATH_NO_ALPHA_MAP | \
909 FAST_PATH_BILINEAR_FILTER | \
910 FAST_PATH_NO_ACCESSORS | \
911 FAST_PATH_NARROW_FORMAT)
913 #define SIMPLE_BILINEAR_FAST_PATH_PAD(op,s,d,func) \
914 { PIXMAN_OP_ ## op, \
915 PIXMAN_ ## s, \
916 (SCALED_BILINEAR_FLAGS | \
917 FAST_PATH_PAD_REPEAT | \
918 FAST_PATH_X_UNIT_POSITIVE), \
919 PIXMAN_null, 0, \
920 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
921 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
922 }
924 #define SIMPLE_BILINEAR_FAST_PATH_NONE(op,s,d,func) \
925 { PIXMAN_OP_ ## op, \
926 PIXMAN_ ## s, \
927 (SCALED_BILINEAR_FLAGS | \
928 FAST_PATH_NONE_REPEAT | \
929 FAST_PATH_X_UNIT_POSITIVE), \
930 PIXMAN_null, 0, \
931 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
932 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
933 }
935 #define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func) \
936 { PIXMAN_OP_ ## op, \
937 PIXMAN_ ## s, \
938 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
939 PIXMAN_null, 0, \
940 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
941 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
942 }
944 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
945 { PIXMAN_OP_ ## op, \
946 PIXMAN_ ## s, \
947 (SCALED_BILINEAR_FLAGS | \
948 FAST_PATH_PAD_REPEAT | \
949 FAST_PATH_X_UNIT_POSITIVE), \
950 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
951 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
952 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
953 }
955 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
956 { PIXMAN_OP_ ## op, \
957 PIXMAN_ ## s, \
958 (SCALED_BILINEAR_FLAGS | \
959 FAST_PATH_NONE_REPEAT | \
960 FAST_PATH_X_UNIT_POSITIVE), \
961 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
962 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
963 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
964 }
966 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
967 { PIXMAN_OP_ ## op, \
968 PIXMAN_ ## s, \
969 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
970 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
971 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
972 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
973 }
975 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
976 { PIXMAN_OP_ ## op, \
977 PIXMAN_ ## s, \
978 (SCALED_BILINEAR_FLAGS | \
979 FAST_PATH_PAD_REPEAT | \
980 FAST_PATH_X_UNIT_POSITIVE), \
981 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
982 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
983 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
984 }
986 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
987 { PIXMAN_OP_ ## op, \
988 PIXMAN_ ## s, \
989 (SCALED_BILINEAR_FLAGS | \
990 FAST_PATH_NONE_REPEAT | \
991 FAST_PATH_X_UNIT_POSITIVE), \
992 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
993 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
994 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
995 }
997 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
998 { PIXMAN_OP_ ## op, \
999 PIXMAN_ ## s, \
1000 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP, \
1001 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
1002 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1003 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
1004 }
1006 /* Prefer the use of 'cover' variant, because it is faster */
1007 #define SIMPLE_BILINEAR_FAST_PATH(op,s,d,func) \
1008 SIMPLE_BILINEAR_FAST_PATH_COVER (op,s,d,func), \
1009 SIMPLE_BILINEAR_FAST_PATH_NONE (op,s,d,func), \
1010 SIMPLE_BILINEAR_FAST_PATH_PAD (op,s,d,func)
1012 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH(op,s,d,func) \
1013 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
1014 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
1015 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD (op,s,d,func)
1017 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH(op,s,d,func) \
1018 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
1019 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
1020 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD (op,s,d,func)
1022 #endif