Use a macro to generate some {a,x}8r8g8b8, a8, and r5g6b5 bilinear fetchers.
authorSøren Sandmann Pedersen <ssp@redhat.com>
Sun, 23 May 2010 08:44:33 +0000 (04:44 -0400)
committerSøren Sandmann Pedersen <ssp@redhat.com>
Tue, 21 Sep 2010 12:50:16 +0000 (08:50 -0400)
There are versions for all combinations of x8r8g8b8/a8r8g8b8 and
pad/repeat/none/normal repeat modes. The bulk of each scaler is an
inline function that takes a format and a repeat mode as parameters.

The new scalers are all commented out, but the next commits will
enable them one at a time to facilitate bisecting.

pixman/pixman-bits-image.c
test/composite-test.c

index a32ebcc..98dc28a 100644 (file)
@@ -637,7 +637,7 @@ bits_image_fetch_affine_no_alpha (pixman_image_t * image,
            buffer[i] = bits_image_fetch_pixel_filtered (
                &image->bits, x, y, fetch_pixel_no_alpha);
        }
-       
+
        x += ux;
        y += uy;
     }
@@ -749,6 +749,222 @@ bits_image_fetch_general (pixman_image_t * image,
     }
 }
 
+static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+typedef uint32_t (* convert_pixel_t) (const uint8_t *row, int x);
+
+static force_inline void
+bits_image_fetch_bilinear_affine (pixman_image_t * image,
+                                 int              offset,
+                                 int              line,
+                                 int              width,
+                                 uint32_t *       buffer,
+                                 const uint32_t * mask,
+
+                                 convert_pixel_t       convert_pixel,
+                                 pixman_format_code_t  format,
+                                 pixman_repeat_t       repeat_mode)
+{
+    pixman_fixed_t x, y;
+    pixman_fixed_t ux, uy;
+    pixman_vector_t v;
+    bits_image_t *bits = &image->bits;
+    int i;
+
+    /* reference point is the center of the pixel */
+    v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
+    v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
+    v.vector[2] = pixman_fixed_1;
+
+    if (!pixman_transform_point_3d (image->common.transform, &v))
+       return;
+
+    ux = image->common.transform->matrix[0][0];
+    uy = image->common.transform->matrix[1][0];
+
+    x = v.vector[0];
+    y = v.vector[1];
+
+    for (i = 0; i < width; ++i)
+    {
+       int x1, y1, x2, y2;
+       uint32_t tl, tr, bl, br;
+       int32_t distx, disty;
+       int width = image->bits.width;
+       int height = image->bits.height;
+       const uint8_t *row1;
+       const uint8_t *row2;
+
+       if (mask && !mask[i])
+           goto next;
+
+       x1 = x - pixman_fixed_1 / 2;
+       y1 = y - pixman_fixed_1 / 2;
+
+       distx = (x1 >> 8) & 0xff;
+       disty = (y1 >> 8) & 0xff;
+
+       y1 = pixman_fixed_to_int (y1);
+       y2 = y1 + 1;
+       x1 = pixman_fixed_to_int (x1);
+       x2 = x1 + 1;
+
+       if (repeat_mode != PIXMAN_REPEAT_NONE)
+       {
+           uint32_t mask;
+
+           mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
+
+           repeat (repeat_mode, width, &x1);
+           repeat (repeat_mode, height, &y1);
+           repeat (repeat_mode, width, &x2);
+           repeat (repeat_mode, height, &y2);
+
+           row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
+           row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
+
+           tl = convert_pixel (row1, x1) | mask;
+           tr = convert_pixel (row1, x2) | mask;
+           bl = convert_pixel (row2, x1) | mask;
+           br = convert_pixel (row2, x2) | mask;
+       }
+       else
+       {
+           uint32_t mask1, mask2;
+           int bpp;
+
+           /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value,
+            * which means if you use it in expressions, those
+            * expressions become unsigned themselves. Since
+            * the variables below can be negative in some cases,
+            * that will lead to crashes on 64 bit architectures.
+            *
+            * So this line makes sure bpp is signed
+            */
+           bpp = PIXMAN_FORMAT_BPP (format);
+
+           if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0)
+           {
+               buffer[i] = 0;
+               goto next;
+           }
+
+           if (y2 == 0)
+           {
+               row1 = zero;
+               mask1 = 0;
+           }
+           else
+           {
+               row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
+               row1 += bpp / 8 * x1;
+
+               mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
+           }
+
+           if (y1 == height - 1)
+           {
+               row2 = zero;
+               mask2 = 0;
+           }
+           else
+           {
+               row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
+               row2 += bpp / 8 * x1;
+
+               mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
+           }
+
+           if (x2 == 0)
+           {
+               tl = 0;
+               bl = 0;
+           }
+           else
+           {
+               tl = convert_pixel (row1, 0) | mask1;
+               bl = convert_pixel (row2, 0) | mask2;
+           }
+
+           if (x1 == width - 1)
+           {
+               tr = 0;
+               br = 0;
+           }
+           else
+           {
+               tr = convert_pixel (row1, 1) | mask1;
+               br = convert_pixel (row2, 1) | mask2;
+           }
+       }
+
+       buffer[i] = bilinear_interpolation (
+           tl, tr, bl, br, distx, disty);
+
+    next:
+       x += ux;
+       y += uy;
+    }
+}
+
+static force_inline uint32_t
+convert_a8r8g8b8 (const uint8_t *row, int x)
+{
+    return *(((uint32_t *)row) + x);
+}
+
+static force_inline uint32_t
+convert_x8r8g8b8 (const uint8_t *row, int x)
+{
+    return *(((uint32_t *)row) + x);
+}
+
+static force_inline uint32_t
+convert_a8 (const uint8_t *row, int x)
+{
+    return *(row + x) << 24;
+}
+
+static force_inline uint32_t
+convert_r5g6b5 (const uint8_t *row, int x)
+{
+    return CONVERT_0565_TO_0888 (*((uint16_t *)row + x));
+}
+
+#define MAKE_BILINEAR_FETCHER(name, format, repeat_mode)               \
+    static void                                                                \
+    bits_image_fetch_bilinear_affine_ ## name (pixman_image_t *image,  \
+                                              int              offset, \
+                                              int              line,   \
+                                              int              width,  \
+                                              uint32_t *       buffer, \
+                                              const uint32_t * mask)   \
+    {                                                                  \
+       bits_image_fetch_bilinear_affine (image, offset, line, width, buffer, mask, \
+                                         convert_ ## format,           \
+                                         PIXMAN_ ## format,            \
+                                         repeat_mode);                 \
+    }
+
+#if 0
+MAKE_BILINEAR_FETCHER (pad_a8r8g8b8,     a8r8g8b8, PIXMAN_REPEAT_PAD);
+MAKE_BILINEAR_FETCHER (none_a8r8g8b8,    a8r8g8b8, PIXMAN_REPEAT_NONE);
+MAKE_BILINEAR_FETCHER (reflect_a8r8g8b8, a8r8g8b8, PIXMAN_REPEAT_REFLECT);
+MAKE_BILINEAR_FETCHER (normal_a8r8g8b8,  a8r8g8b8, PIXMAN_REPEAT_NORMAL);
+MAKE_BILINEAR_FETCHER (pad_x8r8g8b8,     x8r8g8b8, PIXMAN_REPEAT_PAD);
+MAKE_BILINEAR_FETCHER (none_x8r8g8b8,    x8r8g8b8, PIXMAN_REPEAT_NONE);
+MAKE_BILINEAR_FETCHER (reflect_x8r8g8b8, x8r8g8b8, PIXMAN_REPEAT_REFLECT);
+MAKE_BILINEAR_FETCHER (normal_x8r8g8b8,  x8r8g8b8, PIXMAN_REPEAT_NORMAL);
+MAKE_BILINEAR_FETCHER (pad_a8,           a8,       PIXMAN_REPEAT_PAD);
+MAKE_BILINEAR_FETCHER (none_a8,          a8,       PIXMAN_REPEAT_NONE);
+MAKE_BILINEAR_FETCHER (reflect_a8,      a8,       PIXMAN_REPEAT_REFLECT);
+MAKE_BILINEAR_FETCHER (normal_a8,       a8,       PIXMAN_REPEAT_NORMAL);
+MAKE_BILINEAR_FETCHER (pad_r5g6b5,       r5g6b5,   PIXMAN_REPEAT_PAD);
+MAKE_BILINEAR_FETCHER (none_r5g6b5,      r5g6b5,   PIXMAN_REPEAT_NONE);
+MAKE_BILINEAR_FETCHER (reflect_r5g6b5,   r5g6b5,   PIXMAN_REPEAT_REFLECT);
+MAKE_BILINEAR_FETCHER (normal_r5g6b5,    r5g6b5,   PIXMAN_REPEAT_NORMAL);
+#endif
+
 static void
 bits_image_fetch_solid_32 (pixman_image_t * image,
                            int              x,
@@ -954,14 +1170,47 @@ static const fetcher_info_t fetcher_info[] =
       _pixman_image_get_scanline_generic_64
     },
 
+#define GENERAL_BILINEAR_FLAGS                                         \
+    (FAST_PATH_NO_ALPHA_MAP            |                               \
+     FAST_PATH_NO_ACCESSORS            |                               \
+     FAST_PATH_HAS_TRANSFORM           |                               \
+     FAST_PATH_AFFINE_TRANSFORM                |                               \
+     FAST_PATH_BILINEAR_FILTER)
+
+#define BILINEAR_AFFINE_FAST_PATH(name, format, repeat)                        \
+    { PIXMAN_ ## format,                                               \
+      GENERAL_BILINEAR_FLAGS | FAST_PATH_ ## repeat ## _REPEAT,                \
+      bits_image_fetch_bilinear_affine_ ## name,                       \
+      _pixman_image_get_scanline_generic_64                            \
+    },
+
+#if 0
+    BILINEAR_AFFINE_FAST_PATH (pad_a8r8g8b8, a8r8g8b8, PAD)
+    BILINEAR_AFFINE_FAST_PATH (none_a8r8g8b8, a8r8g8b8, NONE)
+    BILINEAR_AFFINE_FAST_PATH (reflect_a8r8g8b8, a8r8g8b8, REFLECT)
+    BILINEAR_AFFINE_FAST_PATH (normal_a8r8g8b8, a8r8g8b8, NORMAL)
+    BILINEAR_AFFINE_FAST_PATH (pad_x8r8g8b8, x8r8g8b8, PAD)
+    BILINEAR_AFFINE_FAST_PATH (none_x8r8g8b8, x8r8g8b8, NONE)
+    BILINEAR_AFFINE_FAST_PATH (reflect_x8r8g8b8, x8r8g8b8, REFLECT)
+    BILINEAR_AFFINE_FAST_PATH (normal_x8r8g8b8, x8r8g8b8, NORMAL)
+    BILINEAR_AFFINE_FAST_PATH (pad_a8, a8, PAD)
+    BILINEAR_AFFINE_FAST_PATH (none_a8, a8, NONE)
+    BILINEAR_AFFINE_FAST_PATH (reflect_a8, a8, REFLECT)
+    BILINEAR_AFFINE_FAST_PATH (normal_a8, a8, NORMAL)
+    BILINEAR_AFFINE_FAST_PATH (pad_r5g6b5, r5g6b5, PAD)
+    BILINEAR_AFFINE_FAST_PATH (none_r5g6b5, r5g6b5, NONE)
+    BILINEAR_AFFINE_FAST_PATH (reflect_r5g6b5, r5g6b5, REFLECT)
+    BILINEAR_AFFINE_FAST_PATH (normal_r5g6b5, r5g6b5, NORMAL)
+#endif
+
+    /* Affine, no alpha */
     { PIXMAN_any,
-      (FAST_PATH_NO_ALPHA_MAP |
-       FAST_PATH_HAS_TRANSFORM |
-       FAST_PATH_AFFINE_TRANSFORM),
+      (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM),
       bits_image_fetch_affine_no_alpha,
       _pixman_image_get_scanline_generic_64
     },
 
+    /* General */
     { PIXMAN_any, 0, bits_image_fetch_general, _pixman_image_get_scanline_generic_64 },
 
     { PIXMAN_null },
index 5401abf..f5f352f 100644 (file)
@@ -104,12 +104,11 @@ main (int argc, char **argv)
        { d2f (0.0), { full, low, low, alpha } },
        { d2f (0.25), { full, full, low, alpha } },
        { d2f (0.4), { low, full, low, alpha } },
-       { d2f (0.5), { low, full, full, alpha } },
+       { d2f (0.6), { low, full, full, alpha } },
        { d2f (0.8), { low, low, full, alpha } },
        { d2f (1.0), { full, low, full, alpha } },
     };
-       
-           
+
     int i;
 
     gtk_init (&argc, &argv);