#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;
}
}