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

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial