Take the source format into account in pixman_expand.
authorAaron Plattner <aplattner@nvidia.com>
Sat, 7 Jun 2008 02:40:25 +0000 (19:40 -0700)
committerSøren Sandmann Pedersen <sandmann@redhat.com>
Fri, 13 Jun 2008 04:11:37 +0000 (00:11 -0400)
Extract the original bits of the source image for each component and then
replicate up to 16 bits to fill the wide components.  Make sure to hard-code the
alpha value to 1 if the source format didn't have alpha.

Signed-off-by: Søren Sandmann Pedersen <sandmann@redhat.com>
pixman/pixman-access.c

index 29ddcb3..ec187d3 100644 (file)
@@ -1879,30 +1879,70 @@ storeProc64 ACCESS(pixman_storeProcForPicture64) (bits_image_t * pict)
 
 #ifndef PIXMAN_FB_ACCESSORS
 /*
+ * Helper routine to expand a color component from 0 < n <= 8 bits to 16 bits by
+ * replication.
+ */
+static inline uint64_t expand16(const uint8_t val, int nbits)
+{
+    // Start out with the high bit of val in the high bit of result.
+    uint16_t result = (uint16_t)val << (16 - nbits);
+
+    if (nbits == 0)
+        return 0;
+
+    // Copy the bits in result, doubling the number of bits each time, until we
+    // fill all 16 bits.
+    while (nbits < 16) {
+        result |= result >> nbits;
+        nbits *= 2;
+    }
+
+    return result;
+}
+
+/*
  * This function expands images from ARGB8 format to ARGB16.  To preserve
  * precision, it needs to know the original source format.  For example, if the
  * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
  * the expanded value is 12345123.  To correctly expand this to 16 bits, it
  * should be 1234512345123451 and not 1234512312345123.
- *
- * XXX[AGP]: For now, this just does naïve byte replication.
  */
 void pixman_expand(uint64_t *dst, const uint32_t *src,
                    pixman_format_code_t format, int width)
 {
+    /*
+     * Determine the sizes of each component and the masks and shifts required
+     * to extract them from the source pixel.
+     */
+    const int a_size = PIXMAN_FORMAT_A(format),
+              r_size = PIXMAN_FORMAT_R(format),
+              g_size = PIXMAN_FORMAT_G(format),
+              b_size = PIXMAN_FORMAT_B(format);
+    const int a_shift = 32 - a_size,
+              r_shift = 24 - r_size,
+              g_shift = 16 - g_size,
+              b_shift =  8 - b_size;
+    const uint8_t a_mask = ~(~0 << a_size),
+                  r_mask = ~(~0 << r_size),
+                  g_mask = ~(~0 << g_size),
+                  b_mask = ~(~0 << b_size);
     int i;
 
     /* Start at the end so that we can do the expansion in place when src == dst */
     for (i = width - 1; i >= 0; i--)
     {
-        const uint8_t a = src[i] >> 24,
-                      r = src[i] >> 16,
-                      g = src[i] >> 8,
-                      b = src[i];
-        dst[i] = (uint64_t)a << 56 | (uint64_t) a << 48 |
-                 (uint64_t)r << 40 | (uint64_t) r << 32 |
-                 (uint64_t)g << 24 | (uint64_t) g << 16 |
-                 (uint64_t)b << 8 | (uint64_t)b;
+        const uint32_t pixel = src[i];
+        // Extract the components.
+        const uint8_t a = (pixel >> a_shift) & a_mask,
+                      r = (pixel >> r_shift) & r_mask,
+                      g = (pixel >> g_shift) & g_mask,
+                      b = (pixel >> b_shift) & b_mask;
+        const uint64_t a16 = a_size ? expand16(a, a_size) : 0xffff,
+                       r16 = expand16(r, r_size),
+                       g16 = expand16(g, g_size),
+                       b16 = expand16(b, b_size);
+
+        dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
     }
 }