diff --git a/cogl/cogl-bitmap-fallback.c b/cogl/cogl-bitmap-fallback.c index 71a7ba765..b74602b82 100644 --- a/cogl/cogl-bitmap-fallback.c +++ b/cogl/cogl-bitmap-fallback.c @@ -30,121 +30,25 @@ #include -/* TO rgba */ +#define component_type guint8 +/* We want to specially optimise the packing when we are converting + to/from an 8-bit type so that it won't do anything. That way for + example if we are just doing a swizzle conversion then the inner + loop for the conversion will be really simple */ +#define UNPACK_BYTE(b) (b) +#define PACK_BYTE(b) (b) +#include "cogl-bitmap-packing.h" +#undef PACK_BYTE +#undef UNPACK_BYTE +#undef component_type -inline static void -_cogl_g_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[0]; - dst[1] = src[0]; - dst[2] = src[0]; - dst[3] = 255; -} - -inline static void -_cogl_rgb_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = 255; -} - -inline static void -_cogl_bgr_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - dst[3] = 255; -} - -inline static void -_cogl_bgra_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - dst[3] = src[3]; -} - -inline static void -_cogl_argb_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[1]; - dst[1] = src[2]; - dst[2] = src[3]; - dst[3] = src[0]; -} - -inline static void -_cogl_abgr_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; -} - -inline static void -_cogl_rgba_to_rgba (const guint8 *src, guint8 *dst) -{ - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; -} - -/* FROM rgba */ - -inline static void -_cogl_rgba_to_g (const guint8 *src, guint8 *dst) -{ - dst[0] = (src[0] + src[1] + src[2]) / 3; -} - -inline static void -_cogl_rgba_to_rgb (const guint8 *src, guint8 *dst) -{ - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; -} - -inline static void -_cogl_rgba_to_bgr (const guint8 *src, guint8 *dst) -{ - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; -} - -inline static void -_cogl_rgba_to_bgra (const guint8 *src, guint8 *dst) -{ - dst[0] = src[2]; - dst[1] = src[1]; - dst[2] = src[0]; - dst[3] = src[3]; -} - -inline static void -_cogl_rgba_to_argb (const guint8 *src, guint8 *dst) -{ - dst[0] = src[3]; - dst[1] = src[0]; - dst[2] = src[1]; - dst[3] = src[2]; -} - -inline static void -_cogl_rgba_to_abgr (const guint8 *src, guint8 *dst) -{ - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; -} +#define component_type guint16 +#define UNPACK_BYTE(b) (((b) * 65535 + 127) / 255) +#define PACK_BYTE(b) (((b) * 255 + 32767) / 65535) +#include "cogl-bitmap-packing.h" +#undef PACK_BYTE +#undef UNPACK_BYTE +#undef component_type /* (Un)Premultiplication */ @@ -299,30 +203,6 @@ _cogl_premult_alpha_last_four_pixels_sse2 (guint8 *p) #endif /* COGL_USE_PREMULT_SSE2 */ -static gboolean -_cogl_bitmap_fallback_can_convert (CoglPixelFormat src, CoglPixelFormat dst) -{ - if (src == dst) - return FALSE; - - switch (src & ~COGL_PREMULT_BIT) - { - case COGL_PIXEL_FORMAT_G_8: - case COGL_PIXEL_FORMAT_RGB_888: - case COGL_PIXEL_FORMAT_BGR_888: - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ABGR_8888: - return TRUE; - - default: - return FALSE; - } - - return TRUE; -} - static gboolean _cogl_bitmap_fallback_can_premult (CoglPixelFormat format) { @@ -339,6 +219,54 @@ _cogl_bitmap_fallback_can_premult (CoglPixelFormat format) } } +static gboolean +_cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format) +{ + /* If the format is using more than 8 bits per component then we'll + unpack into a 16-bit per component buffer instead of 8-bit so we + won't lose as much precision. If we ever add support for formats + with more than 16 bits for at least one of the components then we + should probably do something else here, maybe convert to + floats */ + switch (format) + { + case COGL_PIXEL_FORMAT_ANY: + case COGL_PIXEL_FORMAT_YUV: + g_assert_not_reached (); + + case COGL_PIXEL_FORMAT_A_8: + case COGL_PIXEL_FORMAT_RGB_565: + case COGL_PIXEL_FORMAT_RGBA_4444: + case COGL_PIXEL_FORMAT_RGBA_5551: + case COGL_PIXEL_FORMAT_G_8: + case COGL_PIXEL_FORMAT_RGB_888: + case COGL_PIXEL_FORMAT_BGR_888: + case COGL_PIXEL_FORMAT_RGBA_8888: + case COGL_PIXEL_FORMAT_BGRA_8888: + case COGL_PIXEL_FORMAT_ARGB_8888: + case COGL_PIXEL_FORMAT_ABGR_8888: + case COGL_PIXEL_FORMAT_RGBA_8888_PRE: + case COGL_PIXEL_FORMAT_BGRA_8888_PRE: + case COGL_PIXEL_FORMAT_ARGB_8888_PRE: + case COGL_PIXEL_FORMAT_ABGR_8888_PRE: + case COGL_PIXEL_FORMAT_RGBA_4444_PRE: + case COGL_PIXEL_FORMAT_RGBA_5551_PRE: + return FALSE; + + case COGL_PIXEL_FORMAT_RGBA_1010102: + case COGL_PIXEL_FORMAT_BGRA_1010102: + case COGL_PIXEL_FORMAT_ARGB_2101010: + case COGL_PIXEL_FORMAT_ABGR_2101010: + case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: + case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: + case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: + case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: + return TRUE; + } + + g_assert_not_reached (); +} + CoglBitmap * _cogl_bitmap_fallback_convert (CoglBitmap *src_bmp, CoglPixelFormat dst_format) @@ -347,33 +275,30 @@ _cogl_bitmap_fallback_convert (CoglBitmap *src_bmp, guint8 *dst_data; guint8 *src; guint8 *dst; - int src_bpp; + void *tmp_row; int dst_bpp; int src_rowstride; int dst_rowstride; - int x,y; - guint8 temp_rgba[4] = {0,0,0,0}; + int y; int width, height; CoglPixelFormat src_format; + gboolean use_16; src_format = _cogl_bitmap_get_format (src_bmp); src_rowstride = _cogl_bitmap_get_rowstride (src_bmp); width = _cogl_bitmap_get_width (src_bmp); height = _cogl_bitmap_get_height (src_bmp); - /* Make sure conversion supported */ - if (!_cogl_bitmap_fallback_can_convert (src_format, dst_format)) - return NULL; - src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0); if (src_data == NULL) return NULL; - src_bpp = _cogl_pixel_format_get_bytes_per_pixel (src_format); + use_16 = _cogl_bitmap_needs_short_temp_buffer (dst_format); + dst_bpp = _cogl_pixel_format_get_bytes_per_pixel (dst_format); /* Initialize destination bitmap */ - dst_rowstride = sizeof(guint8) * dst_bpp * width; + dst_rowstride = (sizeof(guint8) * dst_bpp * width + 3) & ~3; /* Copy the premult bit if the new format has an alpha channel */ if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format)) dst_format = ((src_format & COGL_PREMULT_BIT) | @@ -381,6 +306,9 @@ _cogl_bitmap_fallback_convert (CoglBitmap *src_bmp, /* Allocate a new buffer to hold converted data */ dst_data = g_malloc (height * dst_rowstride); + /* and a buffer to hold a temporary RGBA row */ + tmp_row = g_malloc (width * + (use_16 ? sizeof (guint16) : sizeof (guint8)) * 4); /* FIXME: Optimize */ for (y = 0; y < height; y++) @@ -388,58 +316,21 @@ _cogl_bitmap_fallback_convert (CoglBitmap *src_bmp, src = src_data + y * src_rowstride; dst = dst_data + y * dst_rowstride; - for (x = 0; x < width; x++) - { - /* FIXME: Would be nice to at least remove this inner - * branching, but not sure it can be done without - * rewriting of the whole loop */ - switch (src_format & ~COGL_PREMULT_BIT) - { - case COGL_PIXEL_FORMAT_G_8: - _cogl_g_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_RGB_888: - _cogl_rgb_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_BGR_888: - _cogl_bgr_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_RGBA_8888: - _cogl_rgba_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_BGRA_8888: - _cogl_bgra_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_ARGB_8888: - _cogl_argb_to_rgba (src, temp_rgba); break; - case COGL_PIXEL_FORMAT_ABGR_8888: - _cogl_abgr_to_rgba (src, temp_rgba); break; - default: - break; - } + if (use_16) + _cogl_unpack_guint16 (src_format, src, tmp_row, width); + else + _cogl_unpack_guint8 (src_format, src, tmp_row, width); - switch (dst_format & ~COGL_PREMULT_BIT) - { - case COGL_PIXEL_FORMAT_G_8: - _cogl_rgba_to_g (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_RGB_888: - _cogl_rgba_to_rgb (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_BGR_888: - _cogl_rgba_to_bgr (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_RGBA_8888: - _cogl_rgba_to_rgba (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_BGRA_8888: - _cogl_rgba_to_bgra (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_ARGB_8888: - _cogl_rgba_to_argb (temp_rgba, dst); break; - case COGL_PIXEL_FORMAT_ABGR_8888: - _cogl_rgba_to_abgr (temp_rgba, dst); break; - default: - break; - } - - src += src_bpp; - dst += dst_bpp; - } + if (use_16) + _cogl_pack_guint16 (dst_format, tmp_row, dst, width); + else + _cogl_pack_guint8 (dst_format, tmp_row, dst, width); } _cogl_bitmap_unmap (src_bmp); + g_free (tmp_row); + return _cogl_bitmap_new_from_data (dst_data, dst_format, width, height, dst_rowstride, diff --git a/cogl/cogl-bitmap-packing.h b/cogl/cogl-bitmap-packing.h new file mode 100644 index 000000000..6c0a98588 --- /dev/null +++ b/cogl/cogl-bitmap-packing.h @@ -0,0 +1,718 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +/* This file is included multiple times with different definitions for + the component_type type (either guint8 or guint16). The code ends + up exactly the same for both but we only want to end up hitting the + 16-bit path when one of the types in the conversion is > 8 bits per + component. */ + +/* Unpacking to RGBA */ + +#define UNPACK_1(b) ((b) * ((1 << (sizeof (component_type) * 8)) - 1)) +#define UNPACK_2(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ + 1) / 3) +#define UNPACK_4(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ + 7) / 15) +#define UNPACK_5(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ + 15) / 31) +#define UNPACK_6(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ + 31) / 63) +#define UNPACK_10(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \ + 511) / 1023) + +inline static void +G_PASTE (_cogl_unpack_a_8_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + dst[3] = UNPACK_BYTE (*src); + dst += 4; + src++; + } +} + +inline static void +G_PASTE (_cogl_unpack_g_8_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + /* FIXME: I'm not sure if this is right. It looks like Nvidia and + Mesa handle luminance textures differently. Maybe we should + consider just removing luminance textures for Cogl 2.0 because + they have been removed in GL 3.0 */ + while (width-- > 0) + { + component_type v = UNPACK_BYTE (src[0]); + dst[0] = v; + dst[1] = v; + dst[2] = v; + dst[3] = UNPACK_BYTE (255); + dst += 4; + src++; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgb_888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[0]); + dst[1] = UNPACK_BYTE (src[1]); + dst[2] = UNPACK_BYTE (src[2]); + dst[3] = UNPACK_BYTE (255); + dst += 4; + src += 3; + } +} + +inline static void +G_PASTE (_cogl_unpack_bgr_888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[2]); + dst[1] = UNPACK_BYTE (src[1]); + dst[2] = UNPACK_BYTE (src[0]); + dst[3] = UNPACK_BYTE (255); + dst += 4; + src += 3; + } +} + +inline static void +G_PASTE (_cogl_unpack_bgra_8888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[2]); + dst[1] = UNPACK_BYTE (src[1]); + dst[2] = UNPACK_BYTE (src[0]); + dst[3] = UNPACK_BYTE (src[3]); + dst += 4; + src += 4; + } +} + +inline static void +G_PASTE (_cogl_unpack_argb_8888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[1]); + dst[1] = UNPACK_BYTE (src[2]); + dst[2] = UNPACK_BYTE (src[3]); + dst[3] = UNPACK_BYTE (src[0]); + dst += 4; + src += 4; + } +} + +inline static void +G_PASTE (_cogl_unpack_abgr_8888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[3]); + dst[1] = UNPACK_BYTE (src[2]); + dst[2] = UNPACK_BYTE (src[1]); + dst[3] = UNPACK_BYTE (src[0]); + dst += 4; + src += 4; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgba_8888_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[0]); + dst[1] = UNPACK_BYTE (src[1]); + dst[2] = UNPACK_BYTE (src[2]); + dst[3] = UNPACK_BYTE (src[3]); + dst += 4; + src += 4; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgb_565_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint16 v = *(const guint16 *) src; + + dst[0] = UNPACK_5 (v >> 11); + dst[1] = UNPACK_6 ((v >> 5) & 63); + dst[2] = UNPACK_5 (v & 31); + dst[3] = UNPACK_BYTE (255); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgba_4444_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint16 v = *(const guint16 *) src; + + dst[0] = UNPACK_4 (v >> 12); + dst[1] = UNPACK_4 ((v >> 8) & 15); + dst[2] = UNPACK_4 ((v >> 4) & 15); + dst[3] = UNPACK_4 (v & 15); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgba_5551_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint16 v = *(const guint16 *) src; + + dst[0] = UNPACK_5 (v >> 11); + dst[1] = UNPACK_5 ((v >> 6) & 31); + dst[2] = UNPACK_5 ((v >> 1) & 31); + dst[3] = UNPACK_1 (v & 1); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_rgba_1010102_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint32 v = *(const guint32 *) src; + + dst[0] = UNPACK_10 (v >> 22); + dst[1] = UNPACK_10 ((v >> 12) & 1023); + dst[2] = UNPACK_10 ((v >> 2) & 1023); + dst[3] = UNPACK_2 (v & 3); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_bgra_1010102_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint32 v = *(const guint32 *) src; + + dst[2] = UNPACK_10 (v >> 22); + dst[1] = UNPACK_10 ((v >> 12) & 1023); + dst[0] = UNPACK_10 ((v >> 2) & 1023); + dst[3] = UNPACK_2 (v & 3); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_argb_2101010_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint32 v = *(const guint32 *) src; + + dst[3] = UNPACK_2 (v >> 30); + dst[0] = UNPACK_10 ((v >> 20) & 1023); + dst[1] = UNPACK_10 ((v >> 10) & 1023); + dst[2] = UNPACK_10 (v & 1023); + dst += 4; + src += 2; + } +} + +inline static void +G_PASTE (_cogl_unpack_abgr_2101010_, component_type) (const guint8 *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + guint32 v = *(const guint32 *) src; + + dst[3] = UNPACK_2 (v >> 30); + dst[2] = UNPACK_10 ((v >> 20) & 1023); + dst[1] = UNPACK_10 ((v >> 10) & 1023); + dst[0] = UNPACK_10 (v & 1023); + dst += 4; + src += 2; + } +} + +#undef UNPACK_1 +#undef UNPACK_2 +#undef UNPACK_4 +#undef UNPACK_5 +#undef UNPACK_6 +#undef UNPACK_10 + +inline static void +G_PASTE (_cogl_unpack_, component_type) (CoglPixelFormat format, + const guint8 *src, + component_type *dst, + int width) +{ + switch (format) + { + case COGL_PIXEL_FORMAT_A_8: + G_PASTE (_cogl_unpack_a_8_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_G_8: + G_PASTE (_cogl_unpack_g_8_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGB_888: + G_PASTE (_cogl_unpack_rgb_888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGR_888: + G_PASTE (_cogl_unpack_bgr_888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_8888: + case COGL_PIXEL_FORMAT_RGBA_8888_PRE: + G_PASTE (_cogl_unpack_rgba_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGRA_8888: + case COGL_PIXEL_FORMAT_BGRA_8888_PRE: + G_PASTE (_cogl_unpack_bgra_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ARGB_8888: + case COGL_PIXEL_FORMAT_ARGB_8888_PRE: + G_PASTE (_cogl_unpack_argb_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ABGR_8888: + case COGL_PIXEL_FORMAT_ABGR_8888_PRE: + G_PASTE (_cogl_unpack_abgr_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGB_565: + G_PASTE (_cogl_unpack_rgb_565_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_4444: + case COGL_PIXEL_FORMAT_RGBA_4444_PRE: + G_PASTE (_cogl_unpack_rgba_4444_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_5551: + case COGL_PIXEL_FORMAT_RGBA_5551_PRE: + G_PASTE (_cogl_unpack_rgba_5551_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_1010102: + case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: + G_PASTE (_cogl_unpack_rgba_1010102_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGRA_1010102: + case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: + G_PASTE (_cogl_unpack_bgra_1010102_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ARGB_2101010: + case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: + G_PASTE (_cogl_unpack_argb_2101010_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ABGR_2101010: + case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: + G_PASTE (_cogl_unpack_abgr_2101010_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ANY: + case COGL_PIXEL_FORMAT_YUV: + g_assert_not_reached (); + } +} + +/* Packing from RGBA */ + +/* Pack and round to nearest */ +#define PACK_SIZE(b, max) \ + (((b) * (max) + (1 << (sizeof (component_type) * 8 - 1)) - 1) / \ + ((1 << (sizeof (component_type) * 8)) - 1)) + +#define PACK_1(b) PACK_SIZE (b, 1) +#define PACK_2(b) PACK_SIZE (b, 3) +#define PACK_4(b) PACK_SIZE (b, 15) +#define PACK_5(b) PACK_SIZE (b, 31) +#define PACK_6(b) PACK_SIZE (b, 63) +#define PACK_10(b) PACK_SIZE (b, 1023) + +inline static void +G_PASTE (_cogl_pack_a_8_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + *dst = PACK_BYTE (src[3]); + src += 4; + dst++; + } +} + +inline static void +G_PASTE (_cogl_pack_g_8_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + /* FIXME: I'm not sure if this is right. It looks like Nvidia and + Mesa handle luminance textures differently. Maybe we should + consider just removing luminance textures for Cogl 2.0 because + they have been removed in GL 3.0 */ + while (width-- > 0) + { + component_type v = (src[0] + src[1] + src[2]) / 3; + *dst = PACK_BYTE (v); + src += 4; + dst++; + } +} + +inline static void +G_PASTE (_cogl_pack_rgb_888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = PACK_BYTE (src[0]); + dst[1] = PACK_BYTE (src[1]); + dst[2] = PACK_BYTE (src[2]); + src += 4; + dst += 3; + } +} + +inline static void +G_PASTE (_cogl_pack_bgr_888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[2] = PACK_BYTE (src[0]); + dst[1] = PACK_BYTE (src[1]); + dst[0] = PACK_BYTE (src[2]); + src += 4; + dst += 3; + } +} + +inline static void +G_PASTE (_cogl_pack_bgra_8888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[2] = PACK_BYTE (src[0]); + dst[1] = PACK_BYTE (src[1]); + dst[0] = PACK_BYTE (src[2]); + dst[3] = PACK_BYTE (src[3]); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_argb_8888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[1] = PACK_BYTE (src[0]); + dst[2] = PACK_BYTE (src[1]); + dst[3] = PACK_BYTE (src[2]); + dst[0] = PACK_BYTE (src[3]); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_abgr_8888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[3] = PACK_BYTE (src[0]); + dst[2] = PACK_BYTE (src[1]); + dst[1] = PACK_BYTE (src[2]); + dst[0] = PACK_BYTE (src[3]); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_rgba_8888_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = PACK_BYTE (src[0]); + dst[1] = PACK_BYTE (src[1]); + dst[2] = PACK_BYTE (src[2]); + dst[3] = PACK_BYTE (src[3]); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_rgb_565_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint16 *v = (guint16 *) dst; + + *v = ((PACK_5 (src[0]) << 11) | + (PACK_6 (src[1]) << 5) | + PACK_5 (src[2])); + src += 4; + dst += 2; + } +} + +inline static void +G_PASTE (_cogl_pack_rgba_4444_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint16 *v = (guint16 *) dst; + + *v = ((PACK_4 (src[0]) << 12) | + (PACK_4 (src[1]) << 8) | + (PACK_4 (src[2]) << 4) | + PACK_4 (src[3])); + src += 4; + dst += 2; + } +} + +inline static void +G_PASTE (_cogl_pack_rgba_5551_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint16 *v = (guint16 *) dst; + + *v = ((PACK_5 (src[0]) << 11) | + (PACK_5 (src[1]) << 6) | + (PACK_5 (src[2]) << 1) | + PACK_1 (src[3])); + src += 4; + dst += 2; + } +} + +inline static void +G_PASTE (_cogl_pack_rgba_1010102_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint32 *v = (guint32 *) dst; + + *v = ((PACK_10 (src[0]) << 22) | + (PACK_10 (src[1]) << 12) | + (PACK_10 (src[2]) << 2) | + PACK_2 (src[3])); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_bgra_1010102_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint32 *v = (guint32 *) dst; + + *v = ((PACK_10 (src[2]) << 22) | + (PACK_10 (src[1]) << 12) | + (PACK_10 (src[0]) << 2) | + PACK_2 (src[3])); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_argb_2101010_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint32 *v = (guint32 *) dst; + + *v = ((PACK_2 (src[3]) << 30) | + (PACK_10 (src[0]) << 20) | + (PACK_10 (src[1]) << 10) | + PACK_10 (src[2])); + src += 4; + dst += 4; + } +} + +inline static void +G_PASTE (_cogl_pack_abgr_2101010_, component_type) (const component_type *src, + guint8 *dst, + int width) +{ + while (width-- > 0) + { + guint32 *v = (guint32 *) dst; + + *v = ((PACK_2 (src[3]) << 30) | + (PACK_10 (src[2]) << 20) | + (PACK_10 (src[1]) << 10) | + PACK_10 (src[0])); + src += 4; + dst += 4; + } +} + +#undef PACK_SIZE +#undef PACK_1 +#undef PACK_2 +#undef PACK_4 +#undef PACK_5 +#undef PACK_6 +#undef PACK_10 + +inline static void +G_PASTE (_cogl_pack_, component_type) (CoglPixelFormat format, + const component_type *src, + guint8 *dst, + int width) +{ + switch (format) + { + case COGL_PIXEL_FORMAT_A_8: + G_PASTE (_cogl_pack_a_8_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_G_8: + G_PASTE (_cogl_pack_g_8_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGB_888: + G_PASTE (_cogl_pack_rgb_888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGR_888: + G_PASTE (_cogl_pack_bgr_888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_8888: + case COGL_PIXEL_FORMAT_RGBA_8888_PRE: + G_PASTE (_cogl_pack_rgba_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGRA_8888: + case COGL_PIXEL_FORMAT_BGRA_8888_PRE: + G_PASTE (_cogl_pack_bgra_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ARGB_8888: + case COGL_PIXEL_FORMAT_ARGB_8888_PRE: + G_PASTE (_cogl_pack_argb_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ABGR_8888: + case COGL_PIXEL_FORMAT_ABGR_8888_PRE: + G_PASTE (_cogl_pack_abgr_8888_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGB_565: + G_PASTE (_cogl_pack_rgb_565_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_4444: + case COGL_PIXEL_FORMAT_RGBA_4444_PRE: + G_PASTE (_cogl_pack_rgba_4444_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_5551: + case COGL_PIXEL_FORMAT_RGBA_5551_PRE: + G_PASTE (_cogl_pack_rgba_5551_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_RGBA_1010102: + case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: + G_PASTE (_cogl_pack_rgba_1010102_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_BGRA_1010102: + case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: + G_PASTE (_cogl_pack_bgra_1010102_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ARGB_2101010: + case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: + G_PASTE (_cogl_pack_argb_2101010_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ABGR_2101010: + case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: + G_PASTE (_cogl_pack_abgr_2101010_, component_type) (src, dst, width); + break; + case COGL_PIXEL_FORMAT_ANY: + case COGL_PIXEL_FORMAT_YUV: + g_assert_not_reached (); + } +}