beta-0.89.2
[luatex.git] / source / libs / pixman / pixman-src / pixman / pixman-inlines.h
blob1c8441d6dabef89ca42f9e454b3ff92e844ee379
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.
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.
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.
23 * Author: Keith Packard, SuSE, Inc.
26 #ifndef PIXMAN_FAST_PATH_H__
27 #define PIXMAN_FAST_PATH_H__
29 #include "pixman-private.h"
31 #define PIXMAN_REPEAT_COVER -1
33 /* Flags describing input parameters to fast path macro template.
34 * Turning on some flag values may indicate that
35 * "some property X is available so template can use this" or
36 * "some property X should be handled by template".
38 * FLAG_HAVE_SOLID_MASK
39 * Input mask is solid so template should handle this.
41 * FLAG_HAVE_NON_SOLID_MASK
42 * Input mask is bits mask so template should handle this.
44 * FLAG_HAVE_SOLID_MASK and FLAG_HAVE_NON_SOLID_MASK are mutually
45 * exclusive. (It's not allowed to turn both flags on)
47 #define FLAG_NONE (0)
48 #define FLAG_HAVE_SOLID_MASK (1 << 1)
49 #define FLAG_HAVE_NON_SOLID_MASK (1 << 2)
51 /* To avoid too short repeated scanline function calls, extend source
52 * scanlines having width less than below constant value.
54 #define REPEAT_NORMAL_MIN_WIDTH 64
56 static force_inline pixman_bool_t
57 repeat (pixman_repeat_t repeat, int *c, int size)
59 if (repeat == PIXMAN_REPEAT_NONE)
61 if (*c < 0 || *c >= size)
62 return FALSE;
64 else if (repeat == PIXMAN_REPEAT_NORMAL)
66 while (*c >= size)
67 *c -= size;
68 while (*c < 0)
69 *c += size;
71 else if (repeat == PIXMAN_REPEAT_PAD)
73 *c = CLIP (*c, 0, size - 1);
75 else /* REFLECT */
77 *c = MOD (*c, size * 2);
78 if (*c >= size)
79 *c = size * 2 - *c - 1;
81 return TRUE;
84 static force_inline int
85 pixman_fixed_to_bilinear_weight (pixman_fixed_t x)
87 return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
88 ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
91 #if BILINEAR_INTERPOLATION_BITS <= 4
92 /* Inspired by Filter_32_opaque from Skia */
93 static force_inline uint32_t
94 bilinear_interpolation (uint32_t tl, uint32_t tr,
95 uint32_t bl, uint32_t br,
96 int distx, int disty)
98 int distxy, distxiy, distixy, distixiy;
99 uint32_t lo, hi;
101 distx <<= (4 - BILINEAR_INTERPOLATION_BITS);
102 disty <<= (4 - BILINEAR_INTERPOLATION_BITS);
104 distxy = distx * disty;
105 distxiy = (distx << 4) - distxy; /* distx * (16 - disty) */
106 distixy = (disty << 4) - distxy; /* disty * (16 - distx) */
107 distixiy =
108 16 * 16 - (disty << 4) -
109 (distx << 4) + distxy; /* (16 - distx) * (16 - disty) */
111 lo = (tl & 0xff00ff) * distixiy;
112 hi = ((tl >> 8) & 0xff00ff) * distixiy;
114 lo += (tr & 0xff00ff) * distxiy;
115 hi += ((tr >> 8) & 0xff00ff) * distxiy;
117 lo += (bl & 0xff00ff) * distixy;
118 hi += ((bl >> 8) & 0xff00ff) * distixy;
120 lo += (br & 0xff00ff) * distxy;
121 hi += ((br >> 8) & 0xff00ff) * distxy;
123 return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff);
126 #else
127 #if SIZEOF_LONG > 4
129 static force_inline uint32_t
130 bilinear_interpolation (uint32_t tl, uint32_t tr,
131 uint32_t bl, uint32_t br,
132 int distx, int disty)
134 uint64_t distxy, distxiy, distixy, distixiy;
135 uint64_t tl64, tr64, bl64, br64;
136 uint64_t f, r;
138 distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
139 disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
141 distxy = distx * disty;
142 distxiy = distx * (256 - disty);
143 distixy = (256 - distx) * disty;
144 distixiy = (256 - distx) * (256 - disty);
146 /* Alpha and Blue */
147 tl64 = tl & 0xff0000ff;
148 tr64 = tr & 0xff0000ff;
149 bl64 = bl & 0xff0000ff;
150 br64 = br & 0xff0000ff;
152 f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
153 r = f & 0x0000ff0000ff0000ull;
155 /* Red and Green */
156 tl64 = tl;
157 tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
159 tr64 = tr;
160 tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
162 bl64 = bl;
163 bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
165 br64 = br;
166 br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
168 f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
169 r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
171 return (uint32_t)(r >> 16);
174 #else
176 static force_inline uint32_t
177 bilinear_interpolation (uint32_t tl, uint32_t tr,
178 uint32_t bl, uint32_t br,
179 int distx, int disty)
181 int distxy, distxiy, distixy, distixiy;
182 uint32_t f, r;
184 distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
185 disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
187 distxy = distx * disty;
188 distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
189 distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
190 distixiy =
191 256 * 256 - (disty << 8) -
192 (distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
194 /* Blue */
195 r = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
196 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
198 /* Green */
199 f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
200 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
201 r |= f & 0xff000000;
203 tl >>= 16;
204 tr >>= 16;
205 bl >>= 16;
206 br >>= 16;
207 r >>= 16;
209 /* Red */
210 f = (tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
211 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy;
212 r |= f & 0x00ff0000;
214 /* Alpha */
215 f = (tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
216 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy;
217 r |= f & 0xff000000;
219 return r;
222 #endif
223 #endif // BILINEAR_INTERPOLATION_BITS <= 4
226 * For each scanline fetched from source image with PAD repeat:
227 * - calculate how many pixels need to be padded on the left side
228 * - calculate how many pixels need to be padded on the right side
229 * - update width to only count pixels which are fetched from the image
230 * All this information is returned via 'width', 'left_pad', 'right_pad'
231 * arguments. The code is assuming that 'unit_x' is positive.
233 * Note: 64-bit math is used in order to avoid potential overflows, which
234 * is probably excessive in many cases. This particular function
235 * may need its own correctness test and performance tuning.
237 static force_inline void
238 pad_repeat_get_scanline_bounds (int32_t source_image_width,
239 pixman_fixed_t vx,
240 pixman_fixed_t unit_x,
241 int32_t * width,
242 int32_t * left_pad,
243 int32_t * right_pad)
245 int64_t max_vx = (int64_t) source_image_width << 16;
246 int64_t tmp;
247 if (vx < 0)
249 tmp = ((int64_t) unit_x - 1 - vx) / unit_x;
250 if (tmp > *width)
252 *left_pad = *width;
253 *width = 0;
255 else
257 *left_pad = (int32_t) tmp;
258 *width -= (int32_t) tmp;
261 else
263 *left_pad = 0;
265 tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad;
266 if (tmp < 0)
268 *right_pad = *width;
269 *width = 0;
271 else if (tmp >= *width)
273 *right_pad = 0;
275 else
277 *right_pad = *width - (int32_t) tmp;
278 *width = (int32_t) tmp;
282 /* A macroified version of specialized nearest scalers for some
283 * common 8888 and 565 formats. It supports SRC and OVER ops.
285 * There are two repeat versions, one that handles repeat normal,
286 * and one without repeat handling that only works if the src region
287 * used is completely covered by the pre-repeated source samples.
289 * The loops are unrolled to process two pixels per iteration for better
290 * performance on most CPU architectures (superscalar processors
291 * can issue several operations simultaneously, other processors can hide
292 * instructions latencies by pipelining operations). Unrolling more
293 * does not make much sense because the compiler will start running out
294 * of spare registers soon.
297 #define GET_8888_ALPHA(s) ((s) >> 24)
298 /* This is not actually used since we don't have an OVER with
299 565 source, but it is needed to build. */
300 #define GET_0565_ALPHA(s) 0xff
301 #define GET_x888_ALPHA(s) 0xff
303 #define FAST_NEAREST_SCANLINE(scanline_func_name, SRC_FORMAT, DST_FORMAT, \
304 src_type_t, dst_type_t, OP, repeat_mode) \
305 static force_inline void \
306 scanline_func_name (dst_type_t *dst, \
307 const src_type_t *src, \
308 int32_t w, \
309 pixman_fixed_t vx, \
310 pixman_fixed_t unit_x, \
311 pixman_fixed_t src_width_fixed, \
312 pixman_bool_t fully_transparent_src) \
314 uint32_t d; \
315 src_type_t s1, s2; \
316 uint8_t a1, a2; \
317 int x1, x2; \
319 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER && fully_transparent_src) \
320 return; \
322 if (PIXMAN_OP_ ## OP != PIXMAN_OP_SRC && PIXMAN_OP_ ## OP != PIXMAN_OP_OVER) \
323 abort(); \
325 while ((w -= 2) >= 0) \
327 x1 = pixman_fixed_to_int (vx); \
328 vx += unit_x; \
329 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
331 /* This works because we know that unit_x is positive */ \
332 while (vx >= 0) \
333 vx -= src_width_fixed; \
335 s1 = *(src + x1); \
337 x2 = pixman_fixed_to_int (vx); \
338 vx += unit_x; \
339 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
341 /* This works because we know that unit_x is positive */ \
342 while (vx >= 0) \
343 vx -= src_width_fixed; \
345 s2 = *(src + x2); \
347 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
349 a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
350 a2 = GET_ ## SRC_FORMAT ## _ALPHA(s2); \
352 if (a1 == 0xff) \
354 *dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
356 else if (s1) \
358 d = convert_ ## DST_FORMAT ## _to_8888 (*dst); \
359 s1 = convert_ ## SRC_FORMAT ## _to_8888 (s1); \
360 a1 ^= 0xff; \
361 UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
362 *dst = convert_8888_to_ ## DST_FORMAT (d); \
364 dst++; \
366 if (a2 == 0xff) \
368 *dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s2); \
370 else if (s2) \
372 d = convert_## DST_FORMAT ## _to_8888 (*dst); \
373 s2 = convert_## SRC_FORMAT ## _to_8888 (s2); \
374 a2 ^= 0xff; \
375 UN8x4_MUL_UN8_ADD_UN8x4 (d, a2, s2); \
376 *dst = convert_8888_to_ ## DST_FORMAT (d); \
378 dst++; \
380 else /* PIXMAN_OP_SRC */ \
382 *dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
383 *dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s2); \
387 if (w & 1) \
389 x1 = pixman_fixed_to_int (vx); \
390 s1 = *(src + x1); \
392 if (PIXMAN_OP_ ## OP == PIXMAN_OP_OVER) \
394 a1 = GET_ ## SRC_FORMAT ## _ALPHA(s1); \
396 if (a1 == 0xff) \
398 *dst = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
400 else if (s1) \
402 d = convert_## DST_FORMAT ## _to_8888 (*dst); \
403 s1 = convert_ ## SRC_FORMAT ## _to_8888 (s1); \
404 a1 ^= 0xff; \
405 UN8x4_MUL_UN8_ADD_UN8x4 (d, a1, s1); \
406 *dst = convert_8888_to_ ## DST_FORMAT (d); \
408 dst++; \
410 else /* PIXMAN_OP_SRC */ \
412 *dst++ = convert_ ## SRC_FORMAT ## _to_ ## DST_FORMAT (s1); \
417 #define FAST_NEAREST_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
418 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
419 static void \
420 fast_composite_scaled_nearest ## scale_func_name (pixman_implementation_t *imp, \
421 pixman_composite_info_t *info) \
423 PIXMAN_COMPOSITE_ARGS (info); \
424 dst_type_t *dst_line; \
425 mask_type_t *mask_line; \
426 src_type_t *src_first_line; \
427 int y; \
428 pixman_fixed_t src_width_fixed = pixman_int_to_fixed (src_image->bits.width); \
429 pixman_fixed_t max_vy; \
430 pixman_vector_t v; \
431 pixman_fixed_t vx, vy; \
432 pixman_fixed_t unit_x, unit_y; \
433 int32_t left_pad, right_pad; \
435 src_type_t *src; \
436 dst_type_t *dst; \
437 mask_type_t solid_mask; \
438 const mask_type_t *mask = &solid_mask; \
439 int src_stride, mask_stride, dst_stride; \
441 PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type_t, dst_stride, dst_line, 1); \
442 if (have_mask) \
444 if (mask_is_solid) \
445 solid_mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format); \
446 else \
447 PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
448 mask_stride, mask_line, 1); \
450 /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
451 * transformed from destination space to source space */ \
452 PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
454 /* reference point is the center of the pixel */ \
455 v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
456 v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
457 v.vector[2] = pixman_fixed_1; \
459 if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
460 return; \
462 unit_x = src_image->common.transform->matrix[0][0]; \
463 unit_y = src_image->common.transform->matrix[1][1]; \
465 /* Round down to closest integer, ensuring that 0.5 rounds to 0, not 1 */ \
466 v.vector[0] -= pixman_fixed_e; \
467 v.vector[1] -= pixman_fixed_e; \
469 vx = v.vector[0]; \
470 vy = v.vector[1]; \
472 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
474 max_vy = pixman_int_to_fixed (src_image->bits.height); \
476 /* Clamp repeating positions inside the actual samples */ \
477 repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
478 repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
481 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
482 PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
484 pad_repeat_get_scanline_bounds (src_image->bits.width, vx, unit_x, \
485 &width, &left_pad, &right_pad); \
486 vx += left_pad * unit_x; \
489 while (--height >= 0) \
491 dst = dst_line; \
492 dst_line += dst_stride; \
493 if (have_mask && !mask_is_solid) \
495 mask = mask_line; \
496 mask_line += mask_stride; \
499 y = pixman_fixed_to_int (vy); \
500 vy += unit_y; \
501 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
502 repeat (PIXMAN_REPEAT_NORMAL, &vy, max_vy); \
503 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
505 repeat (PIXMAN_REPEAT_PAD, &y, src_image->bits.height); \
506 src = src_first_line + src_stride * y; \
507 if (left_pad > 0) \
509 scanline_func (mask, dst, \
510 src + src_image->bits.width - src_image->bits.width + 1, \
511 left_pad, -pixman_fixed_e, 0, src_width_fixed, FALSE); \
513 if (width > 0) \
515 scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
516 dst + left_pad, src + src_image->bits.width, width, \
517 vx - src_width_fixed, unit_x, src_width_fixed, FALSE); \
519 if (right_pad > 0) \
521 scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
522 dst + left_pad + width, src + src_image->bits.width, \
523 right_pad, -pixman_fixed_e, 0, src_width_fixed, FALSE); \
526 else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
528 static const src_type_t zero[1] = { 0 }; \
529 if (y < 0 || y >= src_image->bits.height) \
531 scanline_func (mask, dst, zero + 1, left_pad + width + right_pad, \
532 -pixman_fixed_e, 0, src_width_fixed, TRUE); \
533 continue; \
535 src = src_first_line + src_stride * y; \
536 if (left_pad > 0) \
538 scanline_func (mask, dst, zero + 1, left_pad, \
539 -pixman_fixed_e, 0, src_width_fixed, TRUE); \
541 if (width > 0) \
543 scanline_func (mask + (mask_is_solid ? 0 : left_pad), \
544 dst + left_pad, src + src_image->bits.width, width, \
545 vx - src_width_fixed, unit_x, src_width_fixed, FALSE); \
547 if (right_pad > 0) \
549 scanline_func (mask + (mask_is_solid ? 0 : left_pad + width), \
550 dst + left_pad + width, zero + 1, right_pad, \
551 -pixman_fixed_e, 0, src_width_fixed, TRUE); \
554 else \
556 src = src_first_line + src_stride * y; \
557 scanline_func (mask, dst, src + src_image->bits.width, width, vx - src_width_fixed, \
558 unit_x, src_width_fixed, FALSE); \
563 /* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
564 #define FAST_NEAREST_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
565 dst_type_t, repeat_mode, have_mask, mask_is_solid) \
566 FAST_NEAREST_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t, \
567 dst_type_t, repeat_mode, have_mask, mask_is_solid)
569 #define FAST_NEAREST_MAINLOOP_NOMASK(scale_func_name, scanline_func, src_type_t, dst_type_t, \
570 repeat_mode) \
571 static force_inline void \
572 scanline_func##scale_func_name##_wrapper ( \
573 const uint8_t *mask, \
574 dst_type_t *dst, \
575 const src_type_t *src, \
576 int32_t w, \
577 pixman_fixed_t vx, \
578 pixman_fixed_t unit_x, \
579 pixman_fixed_t max_vx, \
580 pixman_bool_t fully_transparent_src) \
582 scanline_func (dst, src, w, vx, unit_x, max_vx, fully_transparent_src); \
584 FAST_NEAREST_MAINLOOP_INT (scale_func_name, scanline_func##scale_func_name##_wrapper, \
585 src_type_t, uint8_t, dst_type_t, repeat_mode, FALSE, FALSE)
587 #define FAST_NEAREST_MAINLOOP(scale_func_name, scanline_func, src_type_t, dst_type_t, \
588 repeat_mode) \
589 FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name, scanline_func, src_type_t, \
590 dst_type_t, repeat_mode)
592 #define FAST_NEAREST(scale_func_name, SRC_FORMAT, DST_FORMAT, \
593 src_type_t, dst_type_t, OP, repeat_mode) \
594 FAST_NEAREST_SCANLINE(scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
595 SRC_FORMAT, DST_FORMAT, src_type_t, dst_type_t, \
596 OP, repeat_mode) \
597 FAST_NEAREST_MAINLOOP_NOMASK(_ ## scale_func_name ## _ ## OP, \
598 scaled_nearest_scanline_ ## scale_func_name ## _ ## OP, \
599 src_type_t, dst_type_t, repeat_mode)
602 #define SCALED_NEAREST_FLAGS \
603 (FAST_PATH_SCALE_TRANSFORM | \
604 FAST_PATH_NO_ALPHA_MAP | \
605 FAST_PATH_NEAREST_FILTER | \
606 FAST_PATH_NO_ACCESSORS | \
607 FAST_PATH_NARROW_FORMAT)
609 #define SIMPLE_NEAREST_FAST_PATH_NORMAL(op,s,d,func) \
610 { PIXMAN_OP_ ## op, \
611 PIXMAN_ ## s, \
612 (SCALED_NEAREST_FLAGS | \
613 FAST_PATH_NORMAL_REPEAT | \
614 FAST_PATH_X_UNIT_POSITIVE), \
615 PIXMAN_null, 0, \
616 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
617 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
620 #define SIMPLE_NEAREST_FAST_PATH_PAD(op,s,d,func) \
621 { PIXMAN_OP_ ## op, \
622 PIXMAN_ ## s, \
623 (SCALED_NEAREST_FLAGS | \
624 FAST_PATH_PAD_REPEAT | \
625 FAST_PATH_X_UNIT_POSITIVE), \
626 PIXMAN_null, 0, \
627 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
628 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
631 #define SIMPLE_NEAREST_FAST_PATH_NONE(op,s,d,func) \
632 { PIXMAN_OP_ ## op, \
633 PIXMAN_ ## s, \
634 (SCALED_NEAREST_FLAGS | \
635 FAST_PATH_NONE_REPEAT | \
636 FAST_PATH_X_UNIT_POSITIVE), \
637 PIXMAN_null, 0, \
638 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
639 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
642 #define SIMPLE_NEAREST_FAST_PATH_COVER(op,s,d,func) \
643 { PIXMAN_OP_ ## op, \
644 PIXMAN_ ## s, \
645 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
646 PIXMAN_null, 0, \
647 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
648 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
651 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \
652 { PIXMAN_OP_ ## op, \
653 PIXMAN_ ## s, \
654 (SCALED_NEAREST_FLAGS | \
655 FAST_PATH_NORMAL_REPEAT | \
656 FAST_PATH_X_UNIT_POSITIVE), \
657 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
658 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
659 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
662 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
663 { PIXMAN_OP_ ## op, \
664 PIXMAN_ ## s, \
665 (SCALED_NEAREST_FLAGS | \
666 FAST_PATH_PAD_REPEAT | \
667 FAST_PATH_X_UNIT_POSITIVE), \
668 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
669 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
670 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
673 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
674 { PIXMAN_OP_ ## op, \
675 PIXMAN_ ## s, \
676 (SCALED_NEAREST_FLAGS | \
677 FAST_PATH_NONE_REPEAT | \
678 FAST_PATH_X_UNIT_POSITIVE), \
679 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
680 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
681 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
684 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
685 { PIXMAN_OP_ ## op, \
686 PIXMAN_ ## s, \
687 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
688 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
689 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
690 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
693 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \
694 { PIXMAN_OP_ ## op, \
695 PIXMAN_ ## s, \
696 (SCALED_NEAREST_FLAGS | \
697 FAST_PATH_NORMAL_REPEAT | \
698 FAST_PATH_X_UNIT_POSITIVE), \
699 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
700 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
701 fast_composite_scaled_nearest_ ## func ## _normal ## _ ## op, \
704 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
705 { PIXMAN_OP_ ## op, \
706 PIXMAN_ ## s, \
707 (SCALED_NEAREST_FLAGS | \
708 FAST_PATH_PAD_REPEAT | \
709 FAST_PATH_X_UNIT_POSITIVE), \
710 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
711 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
712 fast_composite_scaled_nearest_ ## func ## _pad ## _ ## op, \
715 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
716 { PIXMAN_OP_ ## op, \
717 PIXMAN_ ## s, \
718 (SCALED_NEAREST_FLAGS | \
719 FAST_PATH_NONE_REPEAT | \
720 FAST_PATH_X_UNIT_POSITIVE), \
721 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
722 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
723 fast_composite_scaled_nearest_ ## func ## _none ## _ ## op, \
726 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
727 { PIXMAN_OP_ ## op, \
728 PIXMAN_ ## s, \
729 SCALED_NEAREST_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST, \
730 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
731 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
732 fast_composite_scaled_nearest_ ## func ## _cover ## _ ## op, \
735 /* Prefer the use of 'cover' variant, because it is faster */
736 #define SIMPLE_NEAREST_FAST_PATH(op,s,d,func) \
737 SIMPLE_NEAREST_FAST_PATH_COVER (op,s,d,func), \
738 SIMPLE_NEAREST_FAST_PATH_NONE (op,s,d,func), \
739 SIMPLE_NEAREST_FAST_PATH_PAD (op,s,d,func), \
740 SIMPLE_NEAREST_FAST_PATH_NORMAL (op,s,d,func)
742 #define SIMPLE_NEAREST_A8_MASK_FAST_PATH(op,s,d,func) \
743 SIMPLE_NEAREST_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
744 SIMPLE_NEAREST_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
745 SIMPLE_NEAREST_A8_MASK_FAST_PATH_PAD (op,s,d,func)
747 #define SIMPLE_NEAREST_SOLID_MASK_FAST_PATH(op,s,d,func) \
748 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
749 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
750 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_PAD (op,s,d,func), \
751 SIMPLE_NEAREST_SOLID_MASK_FAST_PATH_NORMAL (op,s,d,func)
753 /*****************************************************************************/
756 * Identify 5 zones in each scanline for bilinear scaling. Depending on
757 * whether 2 pixels to be interpolated are fetched from the image itself,
758 * from the padding area around it or from both image and padding area.
760 static force_inline void
761 bilinear_pad_repeat_get_scanline_bounds (int32_t source_image_width,
762 pixman_fixed_t vx,
763 pixman_fixed_t unit_x,
764 int32_t * left_pad,
765 int32_t * left_tz,
766 int32_t * width,
767 int32_t * right_tz,
768 int32_t * right_pad)
770 int width1 = *width, left_pad1, right_pad1;
771 int width2 = *width, left_pad2, right_pad2;
773 pad_repeat_get_scanline_bounds (source_image_width, vx, unit_x,
774 &width1, &left_pad1, &right_pad1);
775 pad_repeat_get_scanline_bounds (source_image_width, vx + pixman_fixed_1,
776 unit_x, &width2, &left_pad2, &right_pad2);
778 *left_pad = left_pad2;
779 *left_tz = left_pad1 - left_pad2;
780 *right_tz = right_pad2 - right_pad1;
781 *right_pad = right_pad1;
782 *width -= *left_pad + *left_tz + *right_tz + *right_pad;
786 * Main loop template for single pass bilinear scaling. It needs to be
787 * provided with 'scanline_func' which should do the compositing operation.
788 * The needed function has the following prototype:
790 * scanline_func (dst_type_t * dst,
791 * const mask_type_ * mask,
792 * const src_type_t * src_top,
793 * const src_type_t * src_bottom,
794 * int32_t width,
795 * int weight_top,
796 * int weight_bottom,
797 * pixman_fixed_t vx,
798 * pixman_fixed_t unit_x,
799 * pixman_fixed_t max_vx,
800 * pixman_bool_t zero_src)
802 * Where:
803 * dst - destination scanline buffer for storing results
804 * mask - mask buffer (or single value for solid mask)
805 * src_top, src_bottom - two source scanlines
806 * width - number of pixels to process
807 * weight_top - weight of the top row for interpolation
808 * weight_bottom - weight of the bottom row for interpolation
809 * vx - initial position for fetching the first pair of
810 * pixels from the source buffer
811 * unit_x - position increment needed to move to the next pair
812 * of pixels
813 * max_vx - image size as a fixed point value, can be used for
814 * implementing NORMAL repeat (when it is supported)
815 * zero_src - boolean hint variable, which is set to TRUE when
816 * all source pixels are fetched from zero padding
817 * zone for NONE repeat
819 * Note: normally the sum of 'weight_top' and 'weight_bottom' is equal to
820 * BILINEAR_INTERPOLATION_RANGE, but sometimes it may be less than that
821 * for NONE repeat when handling fuzzy antialiased top or bottom image
822 * edges. Also both top and bottom weight variables are guaranteed to
823 * have value, which is less than BILINEAR_INTERPOLATION_RANGE.
824 * For example, the weights can fit into unsigned byte or be used
825 * with 8-bit SIMD multiplication instructions for 8-bit interpolation
826 * precision.
828 #define FAST_BILINEAR_MAINLOOP_INT(scale_func_name, scanline_func, src_type_t, mask_type_t, \
829 dst_type_t, repeat_mode, flags) \
830 static void \
831 fast_composite_scaled_bilinear ## scale_func_name (pixman_implementation_t *imp, \
832 pixman_composite_info_t *info) \
834 PIXMAN_COMPOSITE_ARGS (info); \
835 dst_type_t *dst_line; \
836 mask_type_t *mask_line; \
837 src_type_t *src_first_line; \
838 int y1, y2; \
839 pixman_fixed_t max_vx = INT32_MAX; /* suppress uninitialized variable warning */ \
840 pixman_vector_t v; \
841 pixman_fixed_t vx, vy; \
842 pixman_fixed_t unit_x, unit_y; \
843 int32_t left_pad, left_tz, right_tz, right_pad; \
845 dst_type_t *dst; \
846 mask_type_t solid_mask; \
847 const mask_type_t *mask = &solid_mask; \
848 int src_stride, mask_stride, dst_stride; \
850 int src_width; \
851 pixman_fixed_t src_width_fixed; \
852 int max_x; \
853 pixman_bool_t need_src_extension; \
855 PIXMAN_IMAGE_GET_LINE (dest_image, dest_x, dest_y, dst_type_t, dst_stride, dst_line, 1); \
856 if (flags & FLAG_HAVE_SOLID_MASK) \
858 solid_mask = _pixman_image_get_solid (imp, mask_image, dest_image->bits.format); \
859 mask_stride = 0; \
861 else if (flags & FLAG_HAVE_NON_SOLID_MASK) \
863 PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, mask_type_t, \
864 mask_stride, mask_line, 1); \
867 /* pass in 0 instead of src_x and src_y because src_x and src_y need to be \
868 * transformed from destination space to source space */ \
869 PIXMAN_IMAGE_GET_LINE (src_image, 0, 0, src_type_t, src_stride, src_first_line, 1); \
871 /* reference point is the center of the pixel */ \
872 v.vector[0] = pixman_int_to_fixed (src_x) + pixman_fixed_1 / 2; \
873 v.vector[1] = pixman_int_to_fixed (src_y) + pixman_fixed_1 / 2; \
874 v.vector[2] = pixman_fixed_1; \
876 if (!pixman_transform_point_3d (src_image->common.transform, &v)) \
877 return; \
879 unit_x = src_image->common.transform->matrix[0][0]; \
880 unit_y = src_image->common.transform->matrix[1][1]; \
882 v.vector[0] -= pixman_fixed_1 / 2; \
883 v.vector[1] -= pixman_fixed_1 / 2; \
885 vy = v.vector[1]; \
887 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD || \
888 PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
890 bilinear_pad_repeat_get_scanline_bounds (src_image->bits.width, v.vector[0], unit_x, \
891 &left_pad, &left_tz, &width, &right_tz, &right_pad); \
892 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
894 /* PAD repeat does not need special handling for 'transition zones' and */ \
895 /* they can be combined with 'padding zones' safely */ \
896 left_pad += left_tz; \
897 right_pad += right_tz; \
898 left_tz = right_tz = 0; \
900 v.vector[0] += left_pad * unit_x; \
903 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
905 vx = v.vector[0]; \
906 repeat (PIXMAN_REPEAT_NORMAL, &vx, pixman_int_to_fixed(src_image->bits.width)); \
907 max_x = pixman_fixed_to_int (vx + (width - 1) * (int64_t)unit_x) + 1; \
909 if (src_image->bits.width < REPEAT_NORMAL_MIN_WIDTH) \
911 src_width = 0; \
913 while (src_width < REPEAT_NORMAL_MIN_WIDTH && src_width <= max_x) \
914 src_width += src_image->bits.width; \
916 need_src_extension = TRUE; \
918 else \
920 src_width = src_image->bits.width; \
921 need_src_extension = FALSE; \
924 src_width_fixed = pixman_int_to_fixed (src_width); \
927 while (--height >= 0) \
929 int weight1, weight2; \
930 dst = dst_line; \
931 dst_line += dst_stride; \
932 vx = v.vector[0]; \
933 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
935 mask = mask_line; \
936 mask_line += mask_stride; \
939 y1 = pixman_fixed_to_int (vy); \
940 weight2 = pixman_fixed_to_bilinear_weight (vy); \
941 if (weight2) \
943 /* both weight1 and weight2 are smaller than BILINEAR_INTERPOLATION_RANGE */ \
944 y2 = y1 + 1; \
945 weight1 = BILINEAR_INTERPOLATION_RANGE - weight2; \
947 else \
949 /* set both top and bottom row to the same scanline and tweak weights */ \
950 y2 = y1; \
951 weight1 = weight2 = BILINEAR_INTERPOLATION_RANGE / 2; \
953 vy += unit_y; \
954 if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_PAD) \
956 src_type_t *src1, *src2; \
957 src_type_t buf1[2]; \
958 src_type_t buf2[2]; \
959 repeat (PIXMAN_REPEAT_PAD, &y1, src_image->bits.height); \
960 repeat (PIXMAN_REPEAT_PAD, &y2, src_image->bits.height); \
961 src1 = src_first_line + src_stride * y1; \
962 src2 = src_first_line + src_stride * y2; \
964 if (left_pad > 0) \
966 buf1[0] = buf1[1] = src1[0]; \
967 buf2[0] = buf2[1] = src2[0]; \
968 scanline_func (dst, mask, \
969 buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, FALSE); \
970 dst += left_pad; \
971 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
972 mask += left_pad; \
974 if (width > 0) \
976 scanline_func (dst, mask, \
977 src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
978 dst += width; \
979 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
980 mask += width; \
982 if (right_pad > 0) \
984 buf1[0] = buf1[1] = src1[src_image->bits.width - 1]; \
985 buf2[0] = buf2[1] = src2[src_image->bits.width - 1]; \
986 scanline_func (dst, mask, \
987 buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, FALSE); \
990 else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NONE) \
992 src_type_t *src1, *src2; \
993 src_type_t buf1[2]; \
994 src_type_t buf2[2]; \
995 /* handle top/bottom zero padding by just setting weights to 0 if needed */ \
996 if (y1 < 0) \
998 weight1 = 0; \
999 y1 = 0; \
1001 if (y1 >= src_image->bits.height) \
1003 weight1 = 0; \
1004 y1 = src_image->bits.height - 1; \
1006 if (y2 < 0) \
1008 weight2 = 0; \
1009 y2 = 0; \
1011 if (y2 >= src_image->bits.height) \
1013 weight2 = 0; \
1014 y2 = src_image->bits.height - 1; \
1016 src1 = src_first_line + src_stride * y1; \
1017 src2 = src_first_line + src_stride * y2; \
1019 if (left_pad > 0) \
1021 buf1[0] = buf1[1] = 0; \
1022 buf2[0] = buf2[1] = 0; \
1023 scanline_func (dst, mask, \
1024 buf1, buf2, left_pad, weight1, weight2, 0, 0, 0, TRUE); \
1025 dst += left_pad; \
1026 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1027 mask += left_pad; \
1029 if (left_tz > 0) \
1031 buf1[0] = 0; \
1032 buf1[1] = src1[0]; \
1033 buf2[0] = 0; \
1034 buf2[1] = src2[0]; \
1035 scanline_func (dst, mask, \
1036 buf1, buf2, left_tz, weight1, weight2, \
1037 pixman_fixed_frac (vx), unit_x, 0, FALSE); \
1038 dst += left_tz; \
1039 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1040 mask += left_tz; \
1041 vx += left_tz * unit_x; \
1043 if (width > 0) \
1045 scanline_func (dst, mask, \
1046 src1, src2, width, weight1, weight2, vx, unit_x, 0, FALSE); \
1047 dst += width; \
1048 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1049 mask += width; \
1050 vx += width * unit_x; \
1052 if (right_tz > 0) \
1054 buf1[0] = src1[src_image->bits.width - 1]; \
1055 buf1[1] = 0; \
1056 buf2[0] = src2[src_image->bits.width - 1]; \
1057 buf2[1] = 0; \
1058 scanline_func (dst, mask, \
1059 buf1, buf2, right_tz, weight1, weight2, \
1060 pixman_fixed_frac (vx), unit_x, 0, FALSE); \
1061 dst += right_tz; \
1062 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1063 mask += right_tz; \
1065 if (right_pad > 0) \
1067 buf1[0] = buf1[1] = 0; \
1068 buf2[0] = buf2[1] = 0; \
1069 scanline_func (dst, mask, \
1070 buf1, buf2, right_pad, weight1, weight2, 0, 0, 0, TRUE); \
1073 else if (PIXMAN_REPEAT_ ## repeat_mode == PIXMAN_REPEAT_NORMAL) \
1075 int32_t num_pixels; \
1076 int32_t width_remain; \
1077 src_type_t * src_line_top; \
1078 src_type_t * src_line_bottom; \
1079 src_type_t buf1[2]; \
1080 src_type_t buf2[2]; \
1081 src_type_t extended_src_line0[REPEAT_NORMAL_MIN_WIDTH*2]; \
1082 src_type_t extended_src_line1[REPEAT_NORMAL_MIN_WIDTH*2]; \
1083 int i, j; \
1085 repeat (PIXMAN_REPEAT_NORMAL, &y1, src_image->bits.height); \
1086 repeat (PIXMAN_REPEAT_NORMAL, &y2, src_image->bits.height); \
1087 src_line_top = src_first_line + src_stride * y1; \
1088 src_line_bottom = src_first_line + src_stride * y2; \
1090 if (need_src_extension) \
1092 for (i=0; i<src_width;) \
1094 for (j=0; j<src_image->bits.width; j++, i++) \
1096 extended_src_line0[i] = src_line_top[j]; \
1097 extended_src_line1[i] = src_line_bottom[j]; \
1101 src_line_top = &extended_src_line0[0]; \
1102 src_line_bottom = &extended_src_line1[0]; \
1105 /* Top & Bottom wrap around buffer */ \
1106 buf1[0] = src_line_top[src_width - 1]; \
1107 buf1[1] = src_line_top[0]; \
1108 buf2[0] = src_line_bottom[src_width - 1]; \
1109 buf2[1] = src_line_bottom[0]; \
1111 width_remain = width; \
1113 while (width_remain > 0) \
1115 /* We use src_width_fixed because it can make vx in original source range */ \
1116 repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
1118 /* Wrap around part */ \
1119 if (pixman_fixed_to_int (vx) == src_width - 1) \
1121 /* for positive unit_x \
1122 * num_pixels = max(n) + 1, where vx + n*unit_x < src_width_fixed \
1124 * vx is in range [0, src_width_fixed - pixman_fixed_e] \
1125 * So we are safe from overflow. \
1126 */ \
1127 num_pixels = ((src_width_fixed - vx - pixman_fixed_e) / unit_x) + 1; \
1129 if (num_pixels > width_remain) \
1130 num_pixels = width_remain; \
1132 scanline_func (dst, mask, buf1, buf2, num_pixels, \
1133 weight1, weight2, pixman_fixed_frac(vx), \
1134 unit_x, src_width_fixed, FALSE); \
1136 width_remain -= num_pixels; \
1137 vx += num_pixels * unit_x; \
1138 dst += num_pixels; \
1140 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1141 mask += num_pixels; \
1143 repeat (PIXMAN_REPEAT_NORMAL, &vx, src_width_fixed); \
1146 /* Normal scanline composite */ \
1147 if (pixman_fixed_to_int (vx) != src_width - 1 && width_remain > 0) \
1149 /* for positive unit_x \
1150 * num_pixels = max(n) + 1, where vx + n*unit_x < (src_width_fixed - 1) \
1152 * vx is in range [0, src_width_fixed - pixman_fixed_e] \
1153 * So we are safe from overflow here. \
1154 */ \
1155 num_pixels = ((src_width_fixed - pixman_fixed_1 - vx - pixman_fixed_e) \
1156 / unit_x) + 1; \
1158 if (num_pixels > width_remain) \
1159 num_pixels = width_remain; \
1161 scanline_func (dst, mask, src_line_top, src_line_bottom, num_pixels, \
1162 weight1, weight2, vx, unit_x, src_width_fixed, FALSE); \
1164 width_remain -= num_pixels; \
1165 vx += num_pixels * unit_x; \
1166 dst += num_pixels; \
1168 if (flags & FLAG_HAVE_NON_SOLID_MASK) \
1169 mask += num_pixels; \
1173 else \
1175 scanline_func (dst, mask, src_first_line + src_stride * y1, \
1176 src_first_line + src_stride * y2, width, \
1177 weight1, weight2, vx, unit_x, max_vx, FALSE); \
1182 /* A workaround for old sun studio, see: https://bugs.freedesktop.org/show_bug.cgi?id=32764 */
1183 #define FAST_BILINEAR_MAINLOOP_COMMON(scale_func_name, scanline_func, src_type_t, mask_type_t, \
1184 dst_type_t, repeat_mode, flags) \
1185 FAST_BILINEAR_MAINLOOP_INT(_ ## scale_func_name, scanline_func, src_type_t, mask_type_t,\
1186 dst_type_t, repeat_mode, flags)
1188 #define SCALED_BILINEAR_FLAGS \
1189 (FAST_PATH_SCALE_TRANSFORM | \
1190 FAST_PATH_NO_ALPHA_MAP | \
1191 FAST_PATH_BILINEAR_FILTER | \
1192 FAST_PATH_NO_ACCESSORS | \
1193 FAST_PATH_NARROW_FORMAT)
1195 #define SIMPLE_BILINEAR_FAST_PATH_PAD(op,s,d,func) \
1196 { PIXMAN_OP_ ## op, \
1197 PIXMAN_ ## s, \
1198 (SCALED_BILINEAR_FLAGS | \
1199 FAST_PATH_PAD_REPEAT | \
1200 FAST_PATH_X_UNIT_POSITIVE), \
1201 PIXMAN_null, 0, \
1202 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1203 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
1206 #define SIMPLE_BILINEAR_FAST_PATH_NONE(op,s,d,func) \
1207 { PIXMAN_OP_ ## op, \
1208 PIXMAN_ ## s, \
1209 (SCALED_BILINEAR_FLAGS | \
1210 FAST_PATH_NONE_REPEAT | \
1211 FAST_PATH_X_UNIT_POSITIVE), \
1212 PIXMAN_null, 0, \
1213 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1214 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
1217 #define SIMPLE_BILINEAR_FAST_PATH_COVER(op,s,d,func) \
1218 { PIXMAN_OP_ ## op, \
1219 PIXMAN_ ## s, \
1220 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
1221 PIXMAN_null, 0, \
1222 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1223 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
1226 #define SIMPLE_BILINEAR_FAST_PATH_NORMAL(op,s,d,func) \
1227 { PIXMAN_OP_ ## op, \
1228 PIXMAN_ ## s, \
1229 (SCALED_BILINEAR_FLAGS | \
1230 FAST_PATH_NORMAL_REPEAT | \
1231 FAST_PATH_X_UNIT_POSITIVE), \
1232 PIXMAN_null, 0, \
1233 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1234 fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
1237 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD(op,s,d,func) \
1238 { PIXMAN_OP_ ## op, \
1239 PIXMAN_ ## s, \
1240 (SCALED_BILINEAR_FLAGS | \
1241 FAST_PATH_PAD_REPEAT | \
1242 FAST_PATH_X_UNIT_POSITIVE), \
1243 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
1244 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1245 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
1248 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE(op,s,d,func) \
1249 { PIXMAN_OP_ ## op, \
1250 PIXMAN_ ## s, \
1251 (SCALED_BILINEAR_FLAGS | \
1252 FAST_PATH_NONE_REPEAT | \
1253 FAST_PATH_X_UNIT_POSITIVE), \
1254 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
1255 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1256 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
1259 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER(op,s,d,func) \
1260 { PIXMAN_OP_ ## op, \
1261 PIXMAN_ ## s, \
1262 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
1263 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
1264 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1265 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
1268 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NORMAL(op,s,d,func) \
1269 { PIXMAN_OP_ ## op, \
1270 PIXMAN_ ## s, \
1271 (SCALED_BILINEAR_FLAGS | \
1272 FAST_PATH_NORMAL_REPEAT | \
1273 FAST_PATH_X_UNIT_POSITIVE), \
1274 PIXMAN_a8, MASK_FLAGS (a8, FAST_PATH_UNIFIED_ALPHA), \
1275 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1276 fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
1279 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD(op,s,d,func) \
1280 { PIXMAN_OP_ ## op, \
1281 PIXMAN_ ## s, \
1282 (SCALED_BILINEAR_FLAGS | \
1283 FAST_PATH_PAD_REPEAT | \
1284 FAST_PATH_X_UNIT_POSITIVE), \
1285 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
1286 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1287 fast_composite_scaled_bilinear_ ## func ## _pad ## _ ## op, \
1290 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE(op,s,d,func) \
1291 { PIXMAN_OP_ ## op, \
1292 PIXMAN_ ## s, \
1293 (SCALED_BILINEAR_FLAGS | \
1294 FAST_PATH_NONE_REPEAT | \
1295 FAST_PATH_X_UNIT_POSITIVE), \
1296 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
1297 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1298 fast_composite_scaled_bilinear_ ## func ## _none ## _ ## op, \
1301 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER(op,s,d,func) \
1302 { PIXMAN_OP_ ## op, \
1303 PIXMAN_ ## s, \
1304 SCALED_BILINEAR_FLAGS | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR, \
1305 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
1306 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1307 fast_composite_scaled_bilinear_ ## func ## _cover ## _ ## op, \
1310 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NORMAL(op,s,d,func) \
1311 { PIXMAN_OP_ ## op, \
1312 PIXMAN_ ## s, \
1313 (SCALED_BILINEAR_FLAGS | \
1314 FAST_PATH_NORMAL_REPEAT | \
1315 FAST_PATH_X_UNIT_POSITIVE), \
1316 PIXMAN_solid, MASK_FLAGS (solid, FAST_PATH_UNIFIED_ALPHA), \
1317 PIXMAN_ ## d, FAST_PATH_STD_DEST_FLAGS, \
1318 fast_composite_scaled_bilinear_ ## func ## _normal ## _ ## op, \
1321 /* Prefer the use of 'cover' variant, because it is faster */
1322 #define SIMPLE_BILINEAR_FAST_PATH(op,s,d,func) \
1323 SIMPLE_BILINEAR_FAST_PATH_COVER (op,s,d,func), \
1324 SIMPLE_BILINEAR_FAST_PATH_NONE (op,s,d,func), \
1325 SIMPLE_BILINEAR_FAST_PATH_PAD (op,s,d,func), \
1326 SIMPLE_BILINEAR_FAST_PATH_NORMAL (op,s,d,func)
1328 #define SIMPLE_BILINEAR_A8_MASK_FAST_PATH(op,s,d,func) \
1329 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_COVER (op,s,d,func), \
1330 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NONE (op,s,d,func), \
1331 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_PAD (op,s,d,func), \
1332 SIMPLE_BILINEAR_A8_MASK_FAST_PATH_NORMAL (op,s,d,func)
1334 #define SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH(op,s,d,func) \
1335 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_COVER (op,s,d,func), \
1336 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NONE (op,s,d,func), \
1337 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_PAD (op,s,d,func), \
1338 SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH_NORMAL (op,s,d,func)
1340 #endif