gfx/cairo/libpixman/src/pixman-fast-path.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial