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 : */
25 :
26 : #ifndef PIXMAN_FAST_PATH_H__
27 : #define PIXMAN_FAST_PATH_H__
28 :
29 : #include "pixman-private.h"
30 :
31 : #define PIXMAN_REPEAT_COVER -1
32 :
33 : static force_inline pixman_bool_t
34 : repeat (pixman_repeat_t repeat, int *c, int size)
35 : {
36 0 : if (repeat == PIXMAN_REPEAT_NONE)
37 : {
38 0 : if (*c < 0 || *c >= size)
39 0 : return FALSE;
40 : }
41 0 : else if (repeat == PIXMAN_REPEAT_NORMAL)
42 : {
43 0 : while (*c >= size)
44 0 : *c -= size;
45 0 : while (*c < 0)
46 0 : *c += size;
47 : }
48 0 : else if (repeat == PIXMAN_REPEAT_PAD)
49 : {
50 0 : *c = CLIP (*c, 0, size - 1);
51 : }
52 : else /* REFLECT */
53 : {
54 0 : *c = MOD (*c, size * 2);
55 0 : if (*c >= size)
56 0 : *c = size * 2 - *c - 1;
57 : }
58 0 : return TRUE;
59 : }
60 :
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 8 : int64_t max_vx = (int64_t) source_image_width << 16;
82 : int64_t tmp;
83 8 : if (vx < 0)
84 : {
85 3 : tmp = ((int64_t) unit_x - 1 - vx) / unit_x;
86 3 : if (tmp > *width)
87 : {
88 0 : *left_pad = *width;
89 0 : *width = 0;
90 : }
91 : else
92 : {
93 3 : *left_pad = (int32_t) tmp;
94 3 : *width -= (int32_t) tmp;
95 : }
96 : }
97 : else
98 : {
99 5 : *left_pad = 0;
100 : }
101 8 : tmp = ((int64_t) unit_x - 1 - vx + max_vx) / unit_x - *left_pad;
102 8 : if (tmp < 0)
103 : {
104 0 : *right_pad = *width;
105 0 : *width = 0;
106 : }
107 8 : else if (tmp >= *width)
108 : {
109 5 : *right_pad = 0;
110 : }
111 : else
112 : {
113 3 : *right_pad = *width - (int32_t) tmp;
114 3 : *width = (int32_t) tmp;
115 : }
116 : }
117 :
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 : */
132 :
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
137 :
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 : }
251 :
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 : }
400 :
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)
406 :
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)
424 :
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)
429 :
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)
438 :
439 :
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)
446 :
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 : }
457 :
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 : }
468 :
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 : }
479 :
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 : }
488 :
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 : }
499 :
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 : }
510 :
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 : }
521 :
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 : }
530 :
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 : }
541 :
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 : }
552 :
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 : }
563 :
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 : }
572 :
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)
579 :
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)
584 :
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)
589 :
590 : /*****************************************************************************/
591 :
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 4 : int width1 = *width, left_pad1, right_pad1;
608 4 : int width2 = *width, left_pad2, right_pad2;
609 :
610 : pad_repeat_get_scanline_bounds (source_image_width, vx, unit_x,
611 : &width1, &left_pad1, &right_pad1);
612 4 : pad_repeat_get_scanline_bounds (source_image_width, vx + pixman_fixed_1,
613 : unit_x, &width2, &left_pad2, &right_pad2);
614 :
615 4 : *left_pad = left_pad2;
616 4 : *left_tz = left_pad1 - left_pad2;
617 4 : *right_tz = right_pad2 - right_pad1;
618 4 : *right_pad = right_pad1;
619 4 : *width -= *left_pad + *left_tz + *right_tz + *right_pad;
620 : }
621 :
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 : }
899 :
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)
905 :
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)
912 :
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 : }
923 :
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 : }
934 :
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 : }
943 :
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 : }
954 :
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 : }
965 :
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 : }
974 :
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 : }
985 :
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 : }
996 :
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 : }
1005 :
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)
1011 :
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)
1016 :
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)
1021 :
1022 : #endif
|