Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 |