1af69d88dSmrg/*
2af69d88dSmrg * Mesa 3-D graphics library
3af69d88dSmrg *
4af69d88dSmrg * Copyright (C) 2014  Intel Corporation  All Rights Reserved.
5af69d88dSmrg *
6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
7af69d88dSmrg * copy of this software and associated documentation files (the "Software"),
8af69d88dSmrg * to deal in the Software without restriction, including without limitation
9af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the
11af69d88dSmrg * Software is furnished to do so, subject to the following conditions:
12af69d88dSmrg *
13af69d88dSmrg * The above copyright notice and this permission notice shall be included
14af69d88dSmrg * in all copies or substantial portions of the Software.
15af69d88dSmrg *
16af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
23af69d88dSmrg */
24af69d88dSmrg
251463c08dSmrg#include <stdlib.h>
261463c08dSmrg
277e995a2eSmrg#include "errors.h"
28af69d88dSmrg#include "format_utils.h"
29af69d88dSmrg#include "glformats.h"
307e995a2eSmrg#include "format_pack.h"
317e995a2eSmrg#include "format_unpack.h"
327e995a2eSmrg
337e995a2eSmrgconst mesa_array_format RGBA32_FLOAT =
341463c08dSmrg   MESA_ARRAY_FORMAT(MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS,
351463c08dSmrg                     4, 1, 1, 1, 4, 0, 1, 2, 3);
367e995a2eSmrg
377e995a2eSmrgconst mesa_array_format RGBA8_UBYTE =
381463c08dSmrg   MESA_ARRAY_FORMAT(MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS,
391463c08dSmrg                     1, 0, 0, 1, 4, 0, 1, 2, 3);
401463c08dSmrg
411463c08dSmrgconst mesa_array_format BGRA8_UBYTE =
421463c08dSmrg   MESA_ARRAY_FORMAT(MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS,
431463c08dSmrg                     1, 0, 0, 1, 4, 2, 1, 0, 3);
447e995a2eSmrg
457e995a2eSmrgconst mesa_array_format RGBA32_UINT =
461463c08dSmrg   MESA_ARRAY_FORMAT(MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS,
471463c08dSmrg                     4, 0, 0, 0, 4, 0, 1, 2, 3);
487e995a2eSmrg
497e995a2eSmrgconst mesa_array_format RGBA32_INT =
501463c08dSmrg   MESA_ARRAY_FORMAT(MESA_ARRAY_FORMAT_BASE_FORMAT_RGBA_VARIANTS,
511463c08dSmrg                     4, 1, 0, 0, 4, 0, 1, 2, 3);
527e995a2eSmrg
537e995a2eSmrgstatic void
547e995a2eSmrginvert_swizzle(uint8_t dst[4], const uint8_t src[4])
557e995a2eSmrg{
567e995a2eSmrg   int i, j;
577e995a2eSmrg
587e995a2eSmrg   dst[0] = MESA_FORMAT_SWIZZLE_NONE;
597e995a2eSmrg   dst[1] = MESA_FORMAT_SWIZZLE_NONE;
607e995a2eSmrg   dst[2] = MESA_FORMAT_SWIZZLE_NONE;
617e995a2eSmrg   dst[3] = MESA_FORMAT_SWIZZLE_NONE;
627e995a2eSmrg
637e995a2eSmrg   for (i = 0; i < 4; ++i)
647e995a2eSmrg      for (j = 0; j < 4; ++j)
657e995a2eSmrg         if (src[j] == i && dst[i] == MESA_FORMAT_SWIZZLE_NONE)
667e995a2eSmrg            dst[i] = j;
677e995a2eSmrg}
687e995a2eSmrg
697e995a2eSmrg/* Takes a src to RGBA swizzle and applies a rebase swizzle to it. This
707e995a2eSmrg * is used when we need to rebase a format to match a different
717e995a2eSmrg * base internal format.
727e995a2eSmrg *
737e995a2eSmrg * The rebase swizzle can be NULL, which means that no rebase is necessary,
747e995a2eSmrg * in which case the src to RGBA swizzle is copied to the output without
757e995a2eSmrg * changes.
767e995a2eSmrg *
777e995a2eSmrg * The resulting rebased swizzle and well as the input swizzles are
787e995a2eSmrg * all 4-element swizzles, but the rebase swizzle can be NULL if no rebase
797e995a2eSmrg * is necessary.
807e995a2eSmrg */
817e995a2eSmrgstatic void
827e995a2eSmrgcompute_rebased_rgba_component_mapping(uint8_t *src2rgba,
837e995a2eSmrg                                       uint8_t *rebase_swizzle,
847e995a2eSmrg                                       uint8_t *rebased_src2rgba)
857e995a2eSmrg{
867e995a2eSmrg   int i;
877e995a2eSmrg
887e995a2eSmrg   if (rebase_swizzle) {
897e995a2eSmrg      for (i = 0; i < 4; i++) {
907e995a2eSmrg         if (rebase_swizzle[i] > MESA_FORMAT_SWIZZLE_W)
917e995a2eSmrg            rebased_src2rgba[i] = rebase_swizzle[i];
927e995a2eSmrg         else
937e995a2eSmrg            rebased_src2rgba[i] = src2rgba[rebase_swizzle[i]];
947e995a2eSmrg      }
957e995a2eSmrg   } else {
967e995a2eSmrg      /* No rebase needed, so src2rgba is all that we need */
977e995a2eSmrg      memcpy(rebased_src2rgba, src2rgba, 4 * sizeof(uint8_t));
987e995a2eSmrg   }
997e995a2eSmrg}
1007e995a2eSmrg
1017e995a2eSmrg/* Computes the final swizzle transform to apply from src to dst in a
1027e995a2eSmrg * conversion that might involve a rebase swizzle.
1037e995a2eSmrg *
1047e995a2eSmrg * This is used to compute the swizzle transform to apply in conversions
1057e995a2eSmrg * between array formats where we have a src2rgba swizzle, a rgba2dst swizzle
1067e995a2eSmrg * and possibly, a rebase swizzle.
1077e995a2eSmrg *
1087e995a2eSmrg * The final swizzle transform to apply (src2dst) when a rebase swizzle is
1097e995a2eSmrg * involved is: src -> rgba -> base -> rgba -> dst
1107e995a2eSmrg */
1117e995a2eSmrgstatic void
1127e995a2eSmrgcompute_src2dst_component_mapping(uint8_t *src2rgba, uint8_t *rgba2dst,
1137e995a2eSmrg                                  uint8_t *rebase_swizzle, uint8_t *src2dst)
1147e995a2eSmrg{
1157e995a2eSmrg   int i;
1167e995a2eSmrg
1177e995a2eSmrg   if (!rebase_swizzle) {
1187e995a2eSmrg      for (i = 0; i < 4; i++) {
1197e995a2eSmrg         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
1207e995a2eSmrg            src2dst[i] = rgba2dst[i];
1217e995a2eSmrg         } else {
1227e995a2eSmrg            src2dst[i] = src2rgba[rgba2dst[i]];
1237e995a2eSmrg         }
1247e995a2eSmrg      }
1257e995a2eSmrg   } else {
1267e995a2eSmrg      for (i = 0; i < 4; i++) {
1277e995a2eSmrg         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
1287e995a2eSmrg            src2dst[i] = rgba2dst[i];
1297e995a2eSmrg         } else if (rebase_swizzle[rgba2dst[i]] > MESA_FORMAT_SWIZZLE_W) {
1307e995a2eSmrg            src2dst[i] = rebase_swizzle[rgba2dst[i]];
1317e995a2eSmrg         } else {
1327e995a2eSmrg            src2dst[i] = src2rgba[rebase_swizzle[rgba2dst[i]]];
1337e995a2eSmrg         }
1347e995a2eSmrg      }
1357e995a2eSmrg   }
1367e995a2eSmrg}
1377e995a2eSmrg
1387e995a2eSmrg/**
1397e995a2eSmrg * This function is used by clients of _mesa_format_convert to obtain
1407e995a2eSmrg * the rebase swizzle to use in a format conversion based on the base
1417e995a2eSmrg * format involved.
1427e995a2eSmrg *
1437e995a2eSmrg * \param baseFormat  the base internal format involved in the conversion.
1447e995a2eSmrg * \param map  the rebase swizzle to consider
1457e995a2eSmrg *
1467e995a2eSmrg * This function computes 'map' as rgba -> baseformat -> rgba and returns true
1477e995a2eSmrg * if the resulting swizzle transform is not the identity transform (thus, a
1487e995a2eSmrg * rebase is needed). If the function returns false then a rebase swizzle
1497e995a2eSmrg * is not necessary and the value of 'map' is undefined. In this situation
1507e995a2eSmrg * clients of _mesa_format_convert should pass NULL in the 'rebase_swizzle'
1517e995a2eSmrg * parameter.
1527e995a2eSmrg */
1537e995a2eSmrgbool
1547e995a2eSmrg_mesa_compute_rgba2base2rgba_component_mapping(GLenum baseFormat, uint8_t *map)
1557e995a2eSmrg{
1567e995a2eSmrg   uint8_t rgba2base[6], base2rgba[6];
1577e995a2eSmrg   int i;
1587e995a2eSmrg
1597e995a2eSmrg   switch (baseFormat) {
1607e995a2eSmrg   case GL_ALPHA:
1617e995a2eSmrg   case GL_RED:
1627e995a2eSmrg   case GL_GREEN:
1637e995a2eSmrg   case GL_BLUE:
1647e995a2eSmrg   case GL_RG:
1657e995a2eSmrg   case GL_RGB:
1667e995a2eSmrg   case GL_BGR:
1677e995a2eSmrg   case GL_RGBA:
1687e995a2eSmrg   case GL_BGRA:
1697e995a2eSmrg   case GL_ABGR_EXT:
1707e995a2eSmrg   case GL_LUMINANCE:
1717e995a2eSmrg   case GL_INTENSITY:
1727e995a2eSmrg   case GL_LUMINANCE_ALPHA:
1737e995a2eSmrg      {
1747e995a2eSmrg         bool needRebase = false;
1757e995a2eSmrg         _mesa_compute_component_mapping(GL_RGBA, baseFormat, rgba2base);
1767e995a2eSmrg         _mesa_compute_component_mapping(baseFormat, GL_RGBA, base2rgba);
1777e995a2eSmrg         for (i = 0; i < 4; i++) {
1787e995a2eSmrg            if (base2rgba[i] > MESA_FORMAT_SWIZZLE_W) {
1797e995a2eSmrg               map[i] = base2rgba[i];
1807e995a2eSmrg            } else {
1817e995a2eSmrg               map[i] = rgba2base[base2rgba[i]];
1827e995a2eSmrg            }
1837e995a2eSmrg            if (map[i] != i)
1847e995a2eSmrg               needRebase = true;
1857e995a2eSmrg         }
1867e995a2eSmrg         return needRebase;
1877e995a2eSmrg      }
1887e995a2eSmrg   default:
1897e995a2eSmrg      unreachable("Unexpected base format");
1907e995a2eSmrg   }
1917e995a2eSmrg}
1927e995a2eSmrg
1937e995a2eSmrg
1947e995a2eSmrg/**
1957e995a2eSmrg * Special case conversion function to swap r/b channels from the source
1967e995a2eSmrg * image to the dest image.
1977e995a2eSmrg */
1987e995a2eSmrgstatic void
1997e995a2eSmrgconvert_ubyte_rgba_to_bgra(size_t width, size_t height,
2007e995a2eSmrg                           const uint8_t *src, size_t src_stride,
2017e995a2eSmrg                           uint8_t *dst, size_t dst_stride)
2027e995a2eSmrg{
2037e995a2eSmrg   int row;
2047e995a2eSmrg
2057e995a2eSmrg   if (sizeof(void *) == 8 &&
2067e995a2eSmrg       src_stride % 8 == 0 &&
2077e995a2eSmrg       dst_stride % 8 == 0 &&
2087e995a2eSmrg       (GLsizeiptr) src % 8 == 0 &&
2097e995a2eSmrg       (GLsizeiptr) dst % 8 == 0) {
2107e995a2eSmrg      /* use 64-bit word to swizzle two 32-bit pixels.  We need 8-byte
2117e995a2eSmrg       * alignment for src/dst addresses and strides.
2127e995a2eSmrg       */
2137e995a2eSmrg      for (row = 0; row < height; row++) {
2147e995a2eSmrg         const GLuint64 *s = (const GLuint64 *) src;
2157e995a2eSmrg         GLuint64 *d = (GLuint64 *) dst;
2167e995a2eSmrg         int i;
2177e995a2eSmrg         for (i = 0; i < width/2; i++) {
2187e995a2eSmrg            d[i] = ( (s[i] & 0xff00ff00ff00ff00) |
2197e995a2eSmrg                    ((s[i] &       0xff000000ff) << 16) |
2207e995a2eSmrg                    ((s[i] &   0xff000000ff0000) >> 16));
2217e995a2eSmrg         }
2227e995a2eSmrg         if (width & 1) {
2237e995a2eSmrg            /* handle the case of odd widths */
2247e995a2eSmrg            const GLuint s = ((const GLuint *) src)[width - 1];
2257e995a2eSmrg            GLuint *d = (GLuint *) dst + width - 1;
2267e995a2eSmrg            *d = ( (s & 0xff00ff00) |
2277e995a2eSmrg                  ((s &       0xff) << 16) |
2287e995a2eSmrg                  ((s &   0xff0000) >> 16));
2297e995a2eSmrg         }
2307e995a2eSmrg         src += src_stride;
2317e995a2eSmrg         dst += dst_stride;
2327e995a2eSmrg      }
2337e995a2eSmrg   } else {
2347e995a2eSmrg      for (row = 0; row < height; row++) {
2357e995a2eSmrg         const GLuint *s = (const GLuint *) src;
2367e995a2eSmrg         GLuint *d = (GLuint *) dst;
2377e995a2eSmrg         int i;
2387e995a2eSmrg         for (i = 0; i < width; i++) {
2397e995a2eSmrg            d[i] = ( (s[i] & 0xff00ff00) |
2407e995a2eSmrg                    ((s[i] &       0xff) << 16) |
2417e995a2eSmrg                    ((s[i] &   0xff0000) >> 16));
2427e995a2eSmrg         }
2437e995a2eSmrg         src += src_stride;
2447e995a2eSmrg         dst += dst_stride;
2457e995a2eSmrg      }
2467e995a2eSmrg   }
2477e995a2eSmrg}
2487e995a2eSmrg
2497e995a2eSmrg
2507e995a2eSmrg/**
2517e995a2eSmrg * This can be used to convert between most color formats.
2527e995a2eSmrg *
2537e995a2eSmrg * Limitations:
2547e995a2eSmrg * - This function doesn't handle GL_COLOR_INDEX or YCBCR formats.
2557e995a2eSmrg * - This function doesn't handle byte-swapping or transferOps, these should
2567e995a2eSmrg *   be handled by the caller.
2577e995a2eSmrg *
2587e995a2eSmrg * \param void_dst  The address where converted color data will be stored.
2597e995a2eSmrg *                  The caller must ensure that the buffer is large enough
2607e995a2eSmrg *                  to hold the converted pixel data.
2617e995a2eSmrg * \param dst_format  The destination color format. It can be a mesa_format
2627e995a2eSmrg *                    or a mesa_array_format represented as an uint32_t.
2637e995a2eSmrg * \param dst_stride  The stride of the destination format in bytes.
2647e995a2eSmrg * \param void_src  The address of the source color data to convert.
2657e995a2eSmrg * \param src_format  The source color format. It can be a mesa_format
2667e995a2eSmrg *                    or a mesa_array_format represented as an uint32_t.
2677e995a2eSmrg * \param src_stride  The stride of the source format in bytes.
2687e995a2eSmrg * \param width  The width, in pixels, of the source image to convert.
2697e995a2eSmrg * \param height  The height, in pixels, of the source image to convert.
2707e995a2eSmrg * \param rebase_swizzle  A swizzle transform to apply during the conversion,
2717e995a2eSmrg *                        typically used to match a different internal base
2727e995a2eSmrg *                        format involved. NULL if no rebase transform is needed
2737e995a2eSmrg *                        (i.e. the internal base format and the base format of
2747e995a2eSmrg *                        the dst or the src -depending on whether we are doing
2757e995a2eSmrg *                        an upload or a download respectively- are the same).
2767e995a2eSmrg */
2777e995a2eSmrgvoid
2787e995a2eSmrg_mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
2797e995a2eSmrg                     void *void_src, uint32_t src_format, size_t src_stride,
2807e995a2eSmrg                     size_t width, size_t height, uint8_t *rebase_swizzle)
2817e995a2eSmrg{
2827e995a2eSmrg   uint8_t *dst = (uint8_t *)void_dst;
2837e995a2eSmrg   uint8_t *src = (uint8_t *)void_src;
2847e995a2eSmrg   mesa_array_format src_array_format, dst_array_format;
2857e995a2eSmrg   bool src_format_is_mesa_array_format, dst_format_is_mesa_array_format;
2867e995a2eSmrg   uint8_t src2dst[4], src2rgba[4], rgba2dst[4], dst2rgba[4];
2877e995a2eSmrg   uint8_t rebased_src2rgba[4];
2887e995a2eSmrg   enum mesa_array_format_datatype src_type = 0, dst_type = 0, common_type;
2897e995a2eSmrg   bool normalized, dst_integer, src_integer, is_signed;
2907e995a2eSmrg   int src_num_channels = 0, dst_num_channels = 0;
2917e995a2eSmrg   uint8_t (*tmp_ubyte)[4];
2927e995a2eSmrg   float (*tmp_float)[4];
2937e995a2eSmrg   uint32_t (*tmp_uint)[4];
2947e995a2eSmrg   int bits;
2957e995a2eSmrg   size_t row;
2967e995a2eSmrg
2977e995a2eSmrg   if (_mesa_format_is_mesa_array_format(src_format)) {
2987e995a2eSmrg      src_format_is_mesa_array_format = true;
2997e995a2eSmrg      src_array_format = src_format;
3007e995a2eSmrg   } else {
3017e995a2eSmrg      assert(_mesa_is_format_color_format(src_format));
3027e995a2eSmrg      src_format_is_mesa_array_format = false;
3037e995a2eSmrg      src_array_format = _mesa_format_to_array_format(src_format);
3047e995a2eSmrg   }
3057e995a2eSmrg
3067e995a2eSmrg   if (_mesa_format_is_mesa_array_format(dst_format)) {
3077e995a2eSmrg      dst_format_is_mesa_array_format = true;
3087e995a2eSmrg      dst_array_format = dst_format;
3097e995a2eSmrg   } else {
3107e995a2eSmrg      assert(_mesa_is_format_color_format(dst_format));
3117e995a2eSmrg      dst_format_is_mesa_array_format = false;
3127e995a2eSmrg      dst_array_format = _mesa_format_to_array_format(dst_format);
3137e995a2eSmrg   }
3147e995a2eSmrg
3157e995a2eSmrg   /* First we see if we can implement the conversion with a direct pack
3167e995a2eSmrg    * or unpack.
3177e995a2eSmrg    *
3187e995a2eSmrg    * In this case we want to be careful when we need to apply a swizzle to
3197e995a2eSmrg    * match an internal base format, since in these cases a simple pack/unpack
3207e995a2eSmrg    * to the dst format from the src format may not match the requirements
3217e995a2eSmrg    * of the internal base format. For now we decide to be safe and
3227e995a2eSmrg    * avoid this path in these scenarios but in the future we may want to
3237e995a2eSmrg    * enable it for specific combinations that are known to work.
3247e995a2eSmrg    */
3257e995a2eSmrg   if (!rebase_swizzle) {
3267e995a2eSmrg      /* Do a direct memcpy where possible */
3277e995a2eSmrg      if ((dst_format_is_mesa_array_format &&
3287e995a2eSmrg           src_format_is_mesa_array_format &&
3297e995a2eSmrg           src_array_format == dst_array_format) ||
3307e995a2eSmrg          src_format == dst_format) {
3317e995a2eSmrg         int format_size = _mesa_get_format_bytes(src_format);
3327e995a2eSmrg         for (row = 0; row < height; row++) {
3337e995a2eSmrg            memcpy(dst, src, width * format_size);
3347e995a2eSmrg            src += src_stride;
3357e995a2eSmrg            dst += dst_stride;
3367e995a2eSmrg         }
3377e995a2eSmrg         return;
3387e995a2eSmrg      }
3397e995a2eSmrg
3407e995a2eSmrg      /* Handle the cases where we can directly unpack */
3417e995a2eSmrg      if (!src_format_is_mesa_array_format) {
3427e995a2eSmrg         if (dst_array_format == RGBA32_FLOAT) {
3437e995a2eSmrg            for (row = 0; row < height; ++row) {
3447e995a2eSmrg               _mesa_unpack_rgba_row(src_format, width,
3457e995a2eSmrg                                     src, (float (*)[4])dst);
3467e995a2eSmrg               src += src_stride;
3477e995a2eSmrg               dst += dst_stride;
3487e995a2eSmrg            }
3497e995a2eSmrg            return;
3507e995a2eSmrg         } else if (dst_array_format == RGBA8_UBYTE) {
3517e995a2eSmrg            assert(!_mesa_is_format_integer_color(src_format));
3527e995a2eSmrg            for (row = 0; row < height; ++row) {
3537e995a2eSmrg               _mesa_unpack_ubyte_rgba_row(src_format, width,
3547e995a2eSmrg                                           src, (uint8_t (*)[4])dst);
3557e995a2eSmrg               src += src_stride;
3567e995a2eSmrg               dst += dst_stride;
3577e995a2eSmrg            }
3587e995a2eSmrg            return;
3591463c08dSmrg         } else if (dst_array_format == BGRA8_UBYTE &&
3601463c08dSmrg                    src_format == MESA_FORMAT_R8G8B8A8_UNORM) {
3611463c08dSmrg             convert_ubyte_rgba_to_bgra(width, height, src, src_stride,
3621463c08dSmrg                                        dst, dst_stride);
3631463c08dSmrg             return;
3647e995a2eSmrg         } else if (dst_array_format == RGBA32_UINT &&
3657e995a2eSmrg                    _mesa_is_format_unsigned(src_format)) {
3667e995a2eSmrg            assert(_mesa_is_format_integer_color(src_format));
3677e995a2eSmrg            for (row = 0; row < height; ++row) {
3687e995a2eSmrg               _mesa_unpack_uint_rgba_row(src_format, width,
3697e995a2eSmrg                                          src, (uint32_t (*)[4])dst);
3707e995a2eSmrg               src += src_stride;
3717e995a2eSmrg               dst += dst_stride;
3727e995a2eSmrg            }
3737e995a2eSmrg            return;
3747e995a2eSmrg         }
3757e995a2eSmrg      }
3767e995a2eSmrg
3777e995a2eSmrg      /* Handle the cases where we can directly pack */
3787e995a2eSmrg      if (!dst_format_is_mesa_array_format) {
3797e995a2eSmrg         if (src_array_format == RGBA32_FLOAT) {
3807e995a2eSmrg            for (row = 0; row < height; ++row) {
3817e995a2eSmrg               _mesa_pack_float_rgba_row(dst_format, width,
3827e995a2eSmrg                                         (const float (*)[4])src, dst);
3837e995a2eSmrg               src += src_stride;
3847e995a2eSmrg               dst += dst_stride;
3857e995a2eSmrg            }
3867e995a2eSmrg            return;
3877e995a2eSmrg         } else if (src_array_format == RGBA8_UBYTE) {
3887e995a2eSmrg            assert(!_mesa_is_format_integer_color(dst_format));
3897e995a2eSmrg
3907e995a2eSmrg            if (dst_format == MESA_FORMAT_B8G8R8A8_UNORM) {
3917e995a2eSmrg               convert_ubyte_rgba_to_bgra(width, height, src, src_stride,
3927e995a2eSmrg                                          dst, dst_stride);
3937e995a2eSmrg            }
3947e995a2eSmrg            else {
3957e995a2eSmrg               for (row = 0; row < height; ++row) {
3961463c08dSmrg                  _mesa_pack_ubyte_rgba_row(dst_format, width, src, dst);
3977e995a2eSmrg                  src += src_stride;
3987e995a2eSmrg                  dst += dst_stride;
3997e995a2eSmrg               }
4007e995a2eSmrg            }
4017e995a2eSmrg            return;
4027e995a2eSmrg         } else if (src_array_format == RGBA32_UINT &&
4037e995a2eSmrg                    _mesa_is_format_unsigned(dst_format)) {
4047e995a2eSmrg            assert(_mesa_is_format_integer_color(dst_format));
4057e995a2eSmrg            for (row = 0; row < height; ++row) {
4067e995a2eSmrg               _mesa_pack_uint_rgba_row(dst_format, width,
4077e995a2eSmrg                                        (const uint32_t (*)[4])src, dst);
4087e995a2eSmrg               src += src_stride;
4097e995a2eSmrg               dst += dst_stride;
4107e995a2eSmrg            }
4117e995a2eSmrg            return;
4127e995a2eSmrg         }
4137e995a2eSmrg      }
4147e995a2eSmrg   }
4157e995a2eSmrg
4167e995a2eSmrg   /* Handle conversions between array formats */
4177e995a2eSmrg   normalized = false;
4187e995a2eSmrg   if (src_array_format) {
4197e995a2eSmrg      src_type = _mesa_array_format_get_datatype(src_array_format);
4207e995a2eSmrg
4217e995a2eSmrg      src_num_channels = _mesa_array_format_get_num_channels(src_array_format);
4227e995a2eSmrg
4237e995a2eSmrg      _mesa_array_format_get_swizzle(src_array_format, src2rgba);
4247e995a2eSmrg
4257e995a2eSmrg      normalized = _mesa_array_format_is_normalized(src_array_format);
4267e995a2eSmrg   }
4277e995a2eSmrg
4287e995a2eSmrg   if (dst_array_format) {
4297e995a2eSmrg      dst_type = _mesa_array_format_get_datatype(dst_array_format);
4307e995a2eSmrg
4317e995a2eSmrg      dst_num_channels = _mesa_array_format_get_num_channels(dst_array_format);
4327e995a2eSmrg
4337e995a2eSmrg      _mesa_array_format_get_swizzle(dst_array_format, dst2rgba);
4347e995a2eSmrg      invert_swizzle(rgba2dst, dst2rgba);
4357e995a2eSmrg
4367e995a2eSmrg      normalized |= _mesa_array_format_is_normalized(dst_array_format);
4377e995a2eSmrg   }
4387e995a2eSmrg
4397e995a2eSmrg   if (src_array_format && dst_array_format) {
4407e995a2eSmrg      assert(_mesa_array_format_is_normalized(src_array_format) ==
4417e995a2eSmrg             _mesa_array_format_is_normalized(dst_array_format));
4427e995a2eSmrg
4437e995a2eSmrg      compute_src2dst_component_mapping(src2rgba, rgba2dst, rebase_swizzle,
4447e995a2eSmrg                                        src2dst);
4457e995a2eSmrg
4467e995a2eSmrg      for (row = 0; row < height; ++row) {
4477e995a2eSmrg         _mesa_swizzle_and_convert(dst, dst_type, dst_num_channels,
4487e995a2eSmrg                                   src, src_type, src_num_channels,
4497e995a2eSmrg                                   src2dst, normalized, width);
4507e995a2eSmrg         src += src_stride;
4517e995a2eSmrg         dst += dst_stride;
4527e995a2eSmrg      }
4537e995a2eSmrg      return;
4547e995a2eSmrg   }
4557e995a2eSmrg
4567e995a2eSmrg   /* At this point, we're fresh out of fast-paths and we need to convert
4577e995a2eSmrg    * to float, uint32, or, if we're lucky, uint8.
4587e995a2eSmrg    */
4597e995a2eSmrg   dst_integer = false;
4607e995a2eSmrg   src_integer = false;
4617e995a2eSmrg
4627e995a2eSmrg   if (src_array_format) {
4637e995a2eSmrg      if (!_mesa_array_format_is_float(src_array_format) &&
4647e995a2eSmrg          !_mesa_array_format_is_normalized(src_array_format))
4657e995a2eSmrg         src_integer = true;
4667e995a2eSmrg   } else {
4677e995a2eSmrg      switch (_mesa_get_format_datatype(src_format)) {
4687e995a2eSmrg      case GL_UNSIGNED_INT:
4697e995a2eSmrg      case GL_INT:
4707e995a2eSmrg         src_integer = true;
4717e995a2eSmrg         break;
4727e995a2eSmrg      }
4737e995a2eSmrg   }
4747e995a2eSmrg
4757e995a2eSmrg   /* If the destination format is signed but the source is unsigned, then we
4767e995a2eSmrg    * don't loose any data by converting to a signed intermediate format above
4777e995a2eSmrg    * and beyond the precision that we loose in the conversion itself. If the
4787e995a2eSmrg    * destination is unsigned then, by using an unsigned intermediate format,
4797e995a2eSmrg    * we make the conversion function that converts from the source to the
4807e995a2eSmrg    * intermediate format take care of truncating at zero. The exception here
4817e995a2eSmrg    * is if the intermediate format is float, in which case the first
4827e995a2eSmrg    * conversion will leave it signed and the second conversion will truncate
4837e995a2eSmrg    * at zero.
4847e995a2eSmrg    */
4857e995a2eSmrg   is_signed = false;
4867e995a2eSmrg   if (dst_array_format) {
4877e995a2eSmrg      if (!_mesa_array_format_is_float(dst_array_format) &&
4887e995a2eSmrg          !_mesa_array_format_is_normalized(dst_array_format))
4897e995a2eSmrg         dst_integer = true;
4907e995a2eSmrg      is_signed = _mesa_array_format_is_signed(dst_array_format);
4917e995a2eSmrg      bits = 8 * _mesa_array_format_get_type_size(dst_array_format);
4927e995a2eSmrg   } else {
4937e995a2eSmrg      switch (_mesa_get_format_datatype(dst_format)) {
4947e995a2eSmrg      case GL_UNSIGNED_NORMALIZED:
4957e995a2eSmrg         is_signed = false;
4967e995a2eSmrg         break;
4977e995a2eSmrg      case GL_SIGNED_NORMALIZED:
4987e995a2eSmrg         is_signed = true;
4997e995a2eSmrg         break;
5007e995a2eSmrg      case GL_FLOAT:
5017e995a2eSmrg         is_signed = true;
5027e995a2eSmrg         break;
5037e995a2eSmrg      case GL_UNSIGNED_INT:
5047e995a2eSmrg         is_signed = false;
5057e995a2eSmrg         dst_integer = true;
5067e995a2eSmrg         break;
5077e995a2eSmrg      case GL_INT:
5087e995a2eSmrg         is_signed = true;
5097e995a2eSmrg         dst_integer = true;
5107e995a2eSmrg         break;
5117e995a2eSmrg      }
5127e995a2eSmrg      bits = _mesa_get_format_max_bits(dst_format);
5137e995a2eSmrg   }
5147e995a2eSmrg
5157e995a2eSmrg   assert(src_integer == dst_integer);
5167e995a2eSmrg
5177e995a2eSmrg   if (src_integer && dst_integer) {
5187e995a2eSmrg      tmp_uint = malloc(width * height * sizeof(*tmp_uint));
5197e995a2eSmrg
5207e995a2eSmrg      /* The [un]packing functions for unsigned datatypes treat the 32-bit
5217e995a2eSmrg       * integer array as signed for signed formats and as unsigned for
5227e995a2eSmrg       * unsigned formats. This is a bit of a problem if we ever convert from
5237e995a2eSmrg       * a signed to an unsigned format because the unsigned packing function
5247e995a2eSmrg       * doesn't know that the input is signed and will treat it as unsigned
5257e995a2eSmrg       * and not do the trunctation. The thing that saves us here is that all
5267e995a2eSmrg       * of the packed formats are unsigned, so we can just always use
5277e995a2eSmrg       * _mesa_swizzle_and_convert for signed formats, which is aware of the
5287e995a2eSmrg       * truncation problem.
5297e995a2eSmrg       */
5307e995a2eSmrg      common_type = is_signed ? MESA_ARRAY_FORMAT_TYPE_INT :
5317e995a2eSmrg                                MESA_ARRAY_FORMAT_TYPE_UINT;
5327e995a2eSmrg      if (src_array_format) {
5337e995a2eSmrg         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
5347e995a2eSmrg                                                rebased_src2rgba);
5357e995a2eSmrg         for (row = 0; row < height; ++row) {
5367e995a2eSmrg            _mesa_swizzle_and_convert(tmp_uint + row * width, common_type, 4,
5377e995a2eSmrg                                      src, src_type, src_num_channels,
5387e995a2eSmrg                                      rebased_src2rgba, normalized, width);
5397e995a2eSmrg            src += src_stride;
5407e995a2eSmrg         }
5417e995a2eSmrg      } else {
5427e995a2eSmrg         for (row = 0; row < height; ++row) {
5437e995a2eSmrg            _mesa_unpack_uint_rgba_row(src_format, width,
5447e995a2eSmrg                                       src, tmp_uint + row * width);
5457e995a2eSmrg            if (rebase_swizzle)
5467e995a2eSmrg               _mesa_swizzle_and_convert(tmp_uint + row * width, common_type, 4,
5477e995a2eSmrg                                         tmp_uint + row * width, common_type, 4,
5487e995a2eSmrg                                         rebase_swizzle, false, width);
5497e995a2eSmrg            src += src_stride;
5507e995a2eSmrg         }
5517e995a2eSmrg      }
5527e995a2eSmrg
5537e995a2eSmrg      /* At this point, we have already done the truncation if the source is
5547e995a2eSmrg       * signed but the destination is unsigned, so no need to force the
5557e995a2eSmrg       * _mesa_swizzle_and_convert path.
5567e995a2eSmrg       */
5577e995a2eSmrg      if (dst_format_is_mesa_array_format) {
5587e995a2eSmrg         for (row = 0; row < height; ++row) {
5597e995a2eSmrg            _mesa_swizzle_and_convert(dst, dst_type, dst_num_channels,
5607e995a2eSmrg                                      tmp_uint + row * width, common_type, 4,
5617e995a2eSmrg                                      rgba2dst, normalized, width);
5627e995a2eSmrg            dst += dst_stride;
5637e995a2eSmrg         }
5647e995a2eSmrg      } else {
5657e995a2eSmrg         for (row = 0; row < height; ++row) {
5667e995a2eSmrg            _mesa_pack_uint_rgba_row(dst_format, width,
5677e995a2eSmrg                                     (const uint32_t (*)[4])tmp_uint + row * width, dst);
5687e995a2eSmrg            dst += dst_stride;
5697e995a2eSmrg         }
5707e995a2eSmrg      }
5717e995a2eSmrg
5727e995a2eSmrg      free(tmp_uint);
5737e995a2eSmrg   } else if (is_signed || bits > 8) {
5747e995a2eSmrg      tmp_float = malloc(width * height * sizeof(*tmp_float));
5757e995a2eSmrg
5767e995a2eSmrg      if (src_format_is_mesa_array_format) {
5777e995a2eSmrg         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
5787e995a2eSmrg                                                rebased_src2rgba);
5797e995a2eSmrg         for (row = 0; row < height; ++row) {
5807e995a2eSmrg            _mesa_swizzle_and_convert(tmp_float + row * width,
5817e995a2eSmrg                                      MESA_ARRAY_FORMAT_TYPE_FLOAT, 4,
5827e995a2eSmrg                                      src, src_type, src_num_channels,
5837e995a2eSmrg                                      rebased_src2rgba, normalized, width);
5847e995a2eSmrg            src += src_stride;
5857e995a2eSmrg         }
5867e995a2eSmrg      } else {
5877e995a2eSmrg         for (row = 0; row < height; ++row) {
5887e995a2eSmrg            _mesa_unpack_rgba_row(src_format, width,
5897e995a2eSmrg                                  src, tmp_float + row * width);
5907e995a2eSmrg            if (rebase_swizzle)
5917e995a2eSmrg               _mesa_swizzle_and_convert(tmp_float + row * width,
5927e995a2eSmrg                                         MESA_ARRAY_FORMAT_TYPE_FLOAT, 4,
5937e995a2eSmrg                                         tmp_float + row * width,
5947e995a2eSmrg                                         MESA_ARRAY_FORMAT_TYPE_FLOAT, 4,
5957e995a2eSmrg                                         rebase_swizzle, normalized, width);
5967e995a2eSmrg            src += src_stride;
5977e995a2eSmrg         }
5987e995a2eSmrg      }
5997e995a2eSmrg
6007e995a2eSmrg      if (dst_format_is_mesa_array_format) {
6017e995a2eSmrg         for (row = 0; row < height; ++row) {
6027e995a2eSmrg            _mesa_swizzle_and_convert(dst, dst_type, dst_num_channels,
6037e995a2eSmrg                                      tmp_float + row * width,
6047e995a2eSmrg                                      MESA_ARRAY_FORMAT_TYPE_FLOAT, 4,
6057e995a2eSmrg                                      rgba2dst, normalized, width);
6067e995a2eSmrg            dst += dst_stride;
6077e995a2eSmrg         }
6087e995a2eSmrg      } else {
6097e995a2eSmrg         for (row = 0; row < height; ++row) {
6107e995a2eSmrg            _mesa_pack_float_rgba_row(dst_format, width,
6117e995a2eSmrg                                      (const float (*)[4])tmp_float + row * width, dst);
6127e995a2eSmrg            dst += dst_stride;
6137e995a2eSmrg         }
6147e995a2eSmrg      }
6157e995a2eSmrg
6167e995a2eSmrg      free(tmp_float);
6177e995a2eSmrg   } else {
6187e995a2eSmrg      tmp_ubyte = malloc(width * height * sizeof(*tmp_ubyte));
6197e995a2eSmrg
6207e995a2eSmrg      if (src_format_is_mesa_array_format) {
6217e995a2eSmrg         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
6227e995a2eSmrg                                                rebased_src2rgba);
6237e995a2eSmrg         for (row = 0; row < height; ++row) {
6247e995a2eSmrg            _mesa_swizzle_and_convert(tmp_ubyte + row * width,
6257e995a2eSmrg                                      MESA_ARRAY_FORMAT_TYPE_UBYTE, 4,
6267e995a2eSmrg                                      src, src_type, src_num_channels,
6277e995a2eSmrg                                      rebased_src2rgba, normalized, width);
6287e995a2eSmrg            src += src_stride;
6297e995a2eSmrg         }
6307e995a2eSmrg      } else {
6317e995a2eSmrg         for (row = 0; row < height; ++row) {
6327e995a2eSmrg            _mesa_unpack_ubyte_rgba_row(src_format, width,
6337e995a2eSmrg                                        src, tmp_ubyte + row * width);
6347e995a2eSmrg            if (rebase_swizzle)
6357e995a2eSmrg               _mesa_swizzle_and_convert(tmp_ubyte + row * width,
6367e995a2eSmrg                                         MESA_ARRAY_FORMAT_TYPE_UBYTE, 4,
6377e995a2eSmrg                                         tmp_ubyte + row * width,
6387e995a2eSmrg                                         MESA_ARRAY_FORMAT_TYPE_UBYTE, 4,
6397e995a2eSmrg                                         rebase_swizzle, normalized, width);
6407e995a2eSmrg            src += src_stride;
6417e995a2eSmrg         }
6427e995a2eSmrg      }
6437e995a2eSmrg
6447e995a2eSmrg      if (dst_format_is_mesa_array_format) {
6457e995a2eSmrg         for (row = 0; row < height; ++row) {
6467e995a2eSmrg            _mesa_swizzle_and_convert(dst, dst_type, dst_num_channels,
6477e995a2eSmrg                                      tmp_ubyte + row * width,
6487e995a2eSmrg                                      MESA_ARRAY_FORMAT_TYPE_UBYTE, 4,
6497e995a2eSmrg                                      rgba2dst, normalized, width);
6507e995a2eSmrg            dst += dst_stride;
6517e995a2eSmrg         }
6527e995a2eSmrg      } else {
6537e995a2eSmrg         for (row = 0; row < height; ++row) {
6547e995a2eSmrg            _mesa_pack_ubyte_rgba_row(dst_format, width,
6551463c08dSmrg                                      (const uint8_t *)(tmp_ubyte + row * width), dst);
6567e995a2eSmrg            dst += dst_stride;
6577e995a2eSmrg         }
6587e995a2eSmrg      }
6597e995a2eSmrg
6607e995a2eSmrg      free(tmp_ubyte);
6617e995a2eSmrg   }
6627e995a2eSmrg}
663af69d88dSmrg
664af69d88dSmrgstatic const uint8_t map_identity[7] = { 0, 1, 2, 3, 4, 5, 6 };
6651463c08dSmrg#if UTIL_ARCH_BIG_ENDIAN
666af69d88dSmrgstatic const uint8_t map_3210[7] = { 3, 2, 1, 0, 4, 5, 6 };
667af69d88dSmrgstatic const uint8_t map_1032[7] = { 1, 0, 3, 2, 4, 5, 6 };
6681463c08dSmrg#endif
669af69d88dSmrg
670af69d88dSmrg/**
671af69d88dSmrg * Describes a format as an array format, if possible
672af69d88dSmrg *
673af69d88dSmrg * A helper function for figuring out if a (possibly packed) format is
674af69d88dSmrg * actually an array format and, if so, what the array parameters are.
675af69d88dSmrg *
676af69d88dSmrg * \param[in]  format         the mesa format
677af69d88dSmrg * \param[out] type           the GL type of the array (GL_BYTE, etc.)
678af69d88dSmrg * \param[out] num_components the number of components in the array
679af69d88dSmrg * \param[out] swizzle        a swizzle describing how to get from the
680af69d88dSmrg *                            given format to RGBA
681af69d88dSmrg * \param[out] normalized     for integer formats, this represents whether
682af69d88dSmrg *                            the format is a normalized integer or a
683af69d88dSmrg *                            regular integer
684af69d88dSmrg * \return  true if this format is an array format, false otherwise
685af69d88dSmrg */
686af69d88dSmrgbool
687af69d88dSmrg_mesa_format_to_array(mesa_format format, GLenum *type, int *num_components,
688af69d88dSmrg                      uint8_t swizzle[4], bool *normalized)
689af69d88dSmrg{
690af69d88dSmrg   int i;
691af69d88dSmrg   GLuint format_components;
692af69d88dSmrg   uint8_t packed_swizzle[4];
693af69d88dSmrg   const uint8_t *endian;
694af69d88dSmrg
695af69d88dSmrg   if (_mesa_is_format_compressed(format))
696af69d88dSmrg      return false;
697af69d88dSmrg
698af69d88dSmrg   *normalized = !_mesa_is_format_integer(format);
699af69d88dSmrg
7007e995a2eSmrg   _mesa_uncompressed_format_to_type_and_comps(format, type, &format_components);
701af69d88dSmrg
702af69d88dSmrg   switch (_mesa_get_format_layout(format)) {
703af69d88dSmrg   case MESA_FORMAT_LAYOUT_ARRAY:
704af69d88dSmrg      *num_components = format_components;
705af69d88dSmrg      _mesa_get_format_swizzle(format, swizzle);
706af69d88dSmrg      return true;
707af69d88dSmrg   case MESA_FORMAT_LAYOUT_PACKED:
708af69d88dSmrg      switch (*type) {
709af69d88dSmrg      case GL_UNSIGNED_BYTE:
710af69d88dSmrg      case GL_BYTE:
711af69d88dSmrg         if (_mesa_get_format_max_bits(format) != 8)
712af69d88dSmrg            return false;
713af69d88dSmrg         *num_components = _mesa_get_format_bytes(format);
714af69d88dSmrg         switch (*num_components) {
715af69d88dSmrg         case 1:
716af69d88dSmrg            endian = map_identity;
717af69d88dSmrg            break;
718af69d88dSmrg         case 2:
7191463c08dSmrg#if UTIL_ARCH_LITTLE_ENDIAN
7201463c08dSmrg            endian = map_identity;
7211463c08dSmrg#else
7221463c08dSmrg            endian = map_1032;
7231463c08dSmrg#endif
724af69d88dSmrg            break;
725af69d88dSmrg         case 4:
7261463c08dSmrg#if UTIL_ARCH_LITTLE_ENDIAN
7271463c08dSmrg            endian = map_identity;
7281463c08dSmrg#else
7291463c08dSmrg            endian = map_3210;
7301463c08dSmrg#endif
731af69d88dSmrg            break;
732af69d88dSmrg         default:
733af69d88dSmrg            endian = map_identity;
734af69d88dSmrg            assert(!"Invalid number of components");
735af69d88dSmrg         }
736af69d88dSmrg         break;
737af69d88dSmrg      case GL_UNSIGNED_SHORT:
738af69d88dSmrg      case GL_SHORT:
739af69d88dSmrg      case GL_HALF_FLOAT:
740af69d88dSmrg         if (_mesa_get_format_max_bits(format) != 16)
741af69d88dSmrg            return false;
742af69d88dSmrg         *num_components = _mesa_get_format_bytes(format) / 2;
743af69d88dSmrg         switch (*num_components) {
744af69d88dSmrg         case 1:
745af69d88dSmrg            endian = map_identity;
746af69d88dSmrg            break;
747af69d88dSmrg         case 2:
7481463c08dSmrg#if UTIL_ARCH_LITTLE_ENDIAN
7491463c08dSmrg            endian = map_identity;
7501463c08dSmrg#else
7511463c08dSmrg            endian = map_1032;
7521463c08dSmrg#endif
753af69d88dSmrg            break;
754af69d88dSmrg         default:
755af69d88dSmrg            endian = map_identity;
756af69d88dSmrg            assert(!"Invalid number of components");
757af69d88dSmrg         }
758af69d88dSmrg         break;
759af69d88dSmrg      case GL_UNSIGNED_INT:
760af69d88dSmrg      case GL_INT:
761af69d88dSmrg      case GL_FLOAT:
762af69d88dSmrg         /* This isn't packed.  At least not really. */
763af69d88dSmrg         assert(format_components == 1);
764af69d88dSmrg         if (_mesa_get_format_max_bits(format) != 32)
765af69d88dSmrg            return false;
766af69d88dSmrg         *num_components = format_components;
767af69d88dSmrg         endian = map_identity;
768af69d88dSmrg         break;
769af69d88dSmrg      default:
770af69d88dSmrg         return false;
771af69d88dSmrg      }
772af69d88dSmrg
773af69d88dSmrg      _mesa_get_format_swizzle(format, packed_swizzle);
774af69d88dSmrg
775af69d88dSmrg      for (i = 0; i < 4; ++i)
776af69d88dSmrg         swizzle[i] = endian[packed_swizzle[i]];
777af69d88dSmrg
778af69d88dSmrg      return true;
779af69d88dSmrg   case MESA_FORMAT_LAYOUT_OTHER:
780af69d88dSmrg   default:
781af69d88dSmrg      return false;
782af69d88dSmrg   }
783af69d88dSmrg}
784af69d88dSmrg
785af69d88dSmrg/**
786af69d88dSmrg * Attempts to perform the given swizzle-and-convert operation with memcpy
787af69d88dSmrg *
788af69d88dSmrg * This function determines if the given swizzle-and-convert operation can
789af69d88dSmrg * be done with a simple memcpy and, if so, does the memcpy.  If not, it
790af69d88dSmrg * returns false and we fall back to the standard version below.
791af69d88dSmrg *
792af69d88dSmrg * The arguments are exactly the same as for _mesa_swizzle_and_convert
793af69d88dSmrg *
794af69d88dSmrg * \return  true if it successfully performed the swizzle-and-convert
795af69d88dSmrg *          operation with memcpy, false otherwise
796af69d88dSmrg */
797af69d88dSmrgstatic bool
7987e995a2eSmrgswizzle_convert_try_memcpy(void *dst,
7997e995a2eSmrg                           enum mesa_array_format_datatype dst_type,
8007e995a2eSmrg                           int num_dst_channels,
8017e995a2eSmrg                           const void *src,
8027e995a2eSmrg                           enum mesa_array_format_datatype src_type,
8037e995a2eSmrg                           int num_src_channels,
804af69d88dSmrg                           const uint8_t swizzle[4], bool normalized, int count)
805af69d88dSmrg{
806af69d88dSmrg   int i;
807af69d88dSmrg
808af69d88dSmrg   if (src_type != dst_type)
809af69d88dSmrg      return false;
810af69d88dSmrg   if (num_src_channels != num_dst_channels)
811af69d88dSmrg      return false;
812af69d88dSmrg
813af69d88dSmrg   for (i = 0; i < num_dst_channels; ++i)
814af69d88dSmrg      if (swizzle[i] != i && swizzle[i] != MESA_FORMAT_SWIZZLE_NONE)
815af69d88dSmrg         return false;
816af69d88dSmrg
8177e995a2eSmrg   memcpy(dst, src, count * num_src_channels *
8187e995a2eSmrg          _mesa_array_format_datatype_get_size(src_type));
819af69d88dSmrg
820af69d88dSmrg   return true;
821af69d88dSmrg}
822af69d88dSmrg
823af69d88dSmrg/**
824af69d88dSmrg * Represents a single instance of the standard swizzle-and-convert loop
825af69d88dSmrg *
826af69d88dSmrg * Any swizzle-and-convert operation simply loops through the pixels and
827af69d88dSmrg * performs the transformation operation one pixel at a time.  This macro
828af69d88dSmrg * embodies one instance of the conversion loop.  This way we can do all
829af69d88dSmrg * control flow outside of the loop and allow the compiler to unroll
830af69d88dSmrg * everything inside the loop.
831af69d88dSmrg *
832af69d88dSmrg * Note: This loop is carefully crafted for performance.  Be careful when
833af69d88dSmrg * changing it and run some benchmarks to ensure no performance regressions
834af69d88dSmrg * if you do.
835af69d88dSmrg *
836af69d88dSmrg * \param   DST_TYPE    the C datatype of the destination
837af69d88dSmrg * \param   DST_CHANS   the number of destination channels
838af69d88dSmrg * \param   SRC_TYPE    the C datatype of the source
839af69d88dSmrg * \param   SRC_CHANS   the number of source channels
840af69d88dSmrg * \param   CONV        an expression for converting from the source data,
841af69d88dSmrg *                      storred in the variable "src", to the destination
842af69d88dSmrg *                      format
843af69d88dSmrg */
844af69d88dSmrg#define SWIZZLE_CONVERT_LOOP(DST_TYPE, DST_CHANS, SRC_TYPE, SRC_CHANS, CONV) \
8457e995a2eSmrg   do {                                           \
8467e995a2eSmrg      int s, j;                                   \
8477e995a2eSmrg      for (s = 0; s < count; ++s) {               \
8487e995a2eSmrg         for (j = 0; j < SRC_CHANS; ++j) {        \
8497e995a2eSmrg            SRC_TYPE src = typed_src[j];          \
8507e995a2eSmrg            tmp[j] = CONV;                        \
8517e995a2eSmrg         }                                        \
8527e995a2eSmrg                                                  \
8537e995a2eSmrg         typed_dst[0] = tmp[swizzle_x];           \
8547e995a2eSmrg         if (DST_CHANS > 1) {                     \
8557e995a2eSmrg            typed_dst[1] = tmp[swizzle_y];        \
8567e995a2eSmrg            if (DST_CHANS > 2) {                  \
8577e995a2eSmrg               typed_dst[2] = tmp[swizzle_z];     \
8587e995a2eSmrg               if (DST_CHANS > 3) {               \
8597e995a2eSmrg                  typed_dst[3] = tmp[swizzle_w];  \
8607e995a2eSmrg               }                                  \
8617e995a2eSmrg            }                                     \
8627e995a2eSmrg         }                                        \
8637e995a2eSmrg         typed_src += SRC_CHANS;                  \
8647e995a2eSmrg         typed_dst += DST_CHANS;                  \
8657e995a2eSmrg      }                                           \
8667e995a2eSmrg   } while (0)
867af69d88dSmrg
868af69d88dSmrg/**
869af69d88dSmrg * Represents a single swizzle-and-convert operation
870af69d88dSmrg *
871af69d88dSmrg * This macro represents everything done in a single swizzle-and-convert
872af69d88dSmrg * operation.  The actual work is done by the SWIZZLE_CONVERT_LOOP macro.
873af69d88dSmrg * This macro acts as a wrapper that uses a nested switch to ensure that
874af69d88dSmrg * all looping parameters get unrolled.
875af69d88dSmrg *
876af69d88dSmrg * This macro makes assumptions about variables etc. in the calling
877af69d88dSmrg * function.  Changes to _mesa_swizzle_and_convert may require changes to
878af69d88dSmrg * this macro.
879af69d88dSmrg *
880af69d88dSmrg * \param   DST_TYPE    the C datatype of the destination
881af69d88dSmrg * \param   SRC_TYPE    the C datatype of the source
882af69d88dSmrg * \param   CONV        an expression for converting from the source data,
883af69d88dSmrg *                      storred in the variable "src", to the destination
884af69d88dSmrg *                      format
885af69d88dSmrg */
886af69d88dSmrg#define SWIZZLE_CONVERT(DST_TYPE, SRC_TYPE, CONV)                 \
887af69d88dSmrg   do {                                                           \
8887e995a2eSmrg      const uint8_t swizzle_x = swizzle[0];                       \
8897e995a2eSmrg      const uint8_t swizzle_y = swizzle[1];                       \
8907e995a2eSmrg      const uint8_t swizzle_z = swizzle[2];                       \
8917e995a2eSmrg      const uint8_t swizzle_w = swizzle[3];                       \
892af69d88dSmrg      const SRC_TYPE *typed_src = void_src;                       \
893af69d88dSmrg      DST_TYPE *typed_dst = void_dst;                             \
894af69d88dSmrg      DST_TYPE tmp[7];                                            \
895af69d88dSmrg      tmp[4] = 0;                                                 \
896af69d88dSmrg      tmp[5] = one;                                               \
897af69d88dSmrg      switch (num_dst_channels) {                                 \
898af69d88dSmrg      case 1:                                                     \
899af69d88dSmrg         switch (num_src_channels) {                              \
900af69d88dSmrg         case 1:                                                  \
9017e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 1, CONV); \
902af69d88dSmrg            break;                                                \
903af69d88dSmrg         case 2:                                                  \
9047e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 2, CONV); \
905af69d88dSmrg            break;                                                \
906af69d88dSmrg         case 3:                                                  \
9077e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 3, CONV); \
908af69d88dSmrg            break;                                                \
909af69d88dSmrg         case 4:                                                  \
9107e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 4, CONV); \
911af69d88dSmrg            break;                                                \
912af69d88dSmrg         }                                                        \
913af69d88dSmrg         break;                                                   \
914af69d88dSmrg      case 2:                                                     \
915af69d88dSmrg         switch (num_src_channels) {                              \
916af69d88dSmrg         case 1:                                                  \
9177e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 1, CONV); \
918af69d88dSmrg            break;                                                \
919af69d88dSmrg         case 2:                                                  \
9207e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 2, CONV); \
921af69d88dSmrg            break;                                                \
922af69d88dSmrg         case 3:                                                  \
9237e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 3, CONV); \
924af69d88dSmrg            break;                                                \
925af69d88dSmrg         case 4:                                                  \
9267e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 4, CONV); \
927af69d88dSmrg            break;                                                \
928af69d88dSmrg         }                                                        \
929af69d88dSmrg         break;                                                   \
930af69d88dSmrg      case 3:                                                     \
931af69d88dSmrg         switch (num_src_channels) {                              \
932af69d88dSmrg         case 1:                                                  \
9337e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 1, CONV); \
934af69d88dSmrg            break;                                                \
935af69d88dSmrg         case 2:                                                  \
9367e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 2, CONV); \
937af69d88dSmrg            break;                                                \
938af69d88dSmrg         case 3:                                                  \
9397e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 3, CONV); \
940af69d88dSmrg            break;                                                \
941af69d88dSmrg         case 4:                                                  \
9427e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 4, CONV); \
943af69d88dSmrg            break;                                                \
944af69d88dSmrg         }                                                        \
945af69d88dSmrg         break;                                                   \
946af69d88dSmrg      case 4:                                                     \
947af69d88dSmrg         switch (num_src_channels) {                              \
948af69d88dSmrg         case 1:                                                  \
9497e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 1, CONV); \
950af69d88dSmrg            break;                                                \
951af69d88dSmrg         case 2:                                                  \
9527e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 2, CONV); \
953af69d88dSmrg            break;                                                \
954af69d88dSmrg         case 3:                                                  \
9557e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 3, CONV); \
956af69d88dSmrg            break;                                                \
957af69d88dSmrg         case 4:                                                  \
9587e995a2eSmrg            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 4, CONV); \
959af69d88dSmrg            break;                                                \
960af69d88dSmrg         }                                                        \
961af69d88dSmrg         break;                                                   \
962af69d88dSmrg      }                                                           \
9637e995a2eSmrg   } while (0)
9647e995a2eSmrg
965af69d88dSmrg
966427dc834Schristosstatic void
9677e995a2eSmrgconvert_float(void *void_dst, int num_dst_channels,
9687e995a2eSmrg              const void *void_src, GLenum src_type, int num_src_channels,
9697e995a2eSmrg              const uint8_t swizzle[4], bool normalized, int count)
970af69d88dSmrg{
9717e995a2eSmrg   const float one = 1.0f;
972af69d88dSmrg
9737e995a2eSmrg   switch (src_type) {
9747e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
9757e995a2eSmrg      SWIZZLE_CONVERT(float, float, src);
9767e995a2eSmrg      break;
9777e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
9787e995a2eSmrg      SWIZZLE_CONVERT(float, uint16_t, _mesa_half_to_float(src));
9797e995a2eSmrg      break;
9807e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
9817e995a2eSmrg      if (normalized) {
9827e995a2eSmrg         SWIZZLE_CONVERT(float, uint8_t, _mesa_unorm_to_float(src, 8));
9837e995a2eSmrg      } else {
9847e995a2eSmrg         SWIZZLE_CONVERT(float, uint8_t, src);
9857e995a2eSmrg      }
9867e995a2eSmrg      break;
9877e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
9887e995a2eSmrg      if (normalized) {
9897e995a2eSmrg         SWIZZLE_CONVERT(float, int8_t, _mesa_snorm_to_float(src, 8));
9907e995a2eSmrg      } else {
9917e995a2eSmrg         SWIZZLE_CONVERT(float, int8_t, src);
992af69d88dSmrg      }
9937e995a2eSmrg      break;
9947e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
9957e995a2eSmrg      if (normalized) {
9967e995a2eSmrg         SWIZZLE_CONVERT(float, uint16_t, _mesa_unorm_to_float(src, 16));
9977e995a2eSmrg      } else {
9987e995a2eSmrg         SWIZZLE_CONVERT(float, uint16_t, src);
9997e995a2eSmrg      }
10007e995a2eSmrg      break;
10017e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
10027e995a2eSmrg      if (normalized) {
10037e995a2eSmrg         SWIZZLE_CONVERT(float, int16_t, _mesa_snorm_to_float(src, 16));
10047e995a2eSmrg      } else {
10057e995a2eSmrg         SWIZZLE_CONVERT(float, int16_t, src);
10067e995a2eSmrg      }
10077e995a2eSmrg      break;
10087e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
10097e995a2eSmrg      if (normalized) {
10107e995a2eSmrg         SWIZZLE_CONVERT(float, uint32_t, _mesa_unorm_to_float(src, 32));
10117e995a2eSmrg      } else {
10127e995a2eSmrg         SWIZZLE_CONVERT(float, uint32_t, src);
10137e995a2eSmrg      }
10147e995a2eSmrg      break;
10157e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
10167e995a2eSmrg      if (normalized) {
10177e995a2eSmrg         SWIZZLE_CONVERT(float, int32_t, _mesa_snorm_to_float(src, 32));
10187e995a2eSmrg      } else {
10197e995a2eSmrg         SWIZZLE_CONVERT(float, int32_t, src);
10207e995a2eSmrg      }
10217e995a2eSmrg      break;
10227e995a2eSmrg   default:
10237e995a2eSmrg      assert(!"Invalid channel type combination");
1024af69d88dSmrg   }
1025427dc834Schristos}
1026427dc834Schristos
10277e995a2eSmrg
1028427dc834Schristosstatic void
10297e995a2eSmrgconvert_half_float(void *void_dst, int num_dst_channels,
10307e995a2eSmrg                   const void *void_src, GLenum src_type, int num_src_channels,
10317e995a2eSmrg                   const uint8_t swizzle[4], bool normalized, int count)
1032427dc834Schristos{
10337e995a2eSmrg   const uint16_t one = _mesa_float_to_half(1.0f);
1034427dc834Schristos
10357e995a2eSmrg   switch (src_type) {
10367e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
10377e995a2eSmrg      SWIZZLE_CONVERT(uint16_t, float, _mesa_float_to_half(src));
10387e995a2eSmrg      break;
10397e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
10407e995a2eSmrg      SWIZZLE_CONVERT(uint16_t, uint16_t, src);
10417e995a2eSmrg      break;
10427e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
10437e995a2eSmrg      if (normalized) {
10447e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint8_t, _mesa_unorm_to_half(src, 8));
10457e995a2eSmrg      } else {
10467e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint8_t, _mesa_float_to_half(src));
10477e995a2eSmrg      }
10487e995a2eSmrg      break;
10497e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
10507e995a2eSmrg      if (normalized) {
10517e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int8_t, _mesa_snorm_to_half(src, 8));
10527e995a2eSmrg      } else {
10537e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int8_t, _mesa_float_to_half(src));
1054af69d88dSmrg      }
10557e995a2eSmrg      break;
10567e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
10577e995a2eSmrg      if (normalized) {
10587e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_unorm_to_half(src, 16));
10597e995a2eSmrg      } else {
10607e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_float_to_half(src));
10617e995a2eSmrg      }
10627e995a2eSmrg      break;
10637e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
10647e995a2eSmrg      if (normalized) {
10657e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int16_t, _mesa_snorm_to_half(src, 16));
10667e995a2eSmrg      } else {
10677e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int16_t, _mesa_float_to_half(src));
10687e995a2eSmrg      }
10697e995a2eSmrg      break;
10707e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
10717e995a2eSmrg      if (normalized) {
10727e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint32_t, _mesa_unorm_to_half(src, 32));
10737e995a2eSmrg      } else {
10747e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint32_t, _mesa_float_to_half(src));
10757e995a2eSmrg      }
10767e995a2eSmrg      break;
10777e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
10787e995a2eSmrg      if (normalized) {
10797e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int32_t, _mesa_snorm_to_half(src, 32));
10807e995a2eSmrg      } else {
10817e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int32_t, _mesa_float_to_half(src));
10827e995a2eSmrg      }
10837e995a2eSmrg      break;
10847e995a2eSmrg   default:
10857e995a2eSmrg      assert(!"Invalid channel type combination");
1086af69d88dSmrg   }
1087427dc834Schristos}
1088427dc834Schristos
1089427dc834Schristosstatic void
10907e995a2eSmrgconvert_ubyte(void *void_dst, int num_dst_channels,
10917e995a2eSmrg              const void *void_src, GLenum src_type, int num_src_channels,
10927e995a2eSmrg              const uint8_t swizzle[4], bool normalized, int count)
1093427dc834Schristos{
10947e995a2eSmrg   const uint8_t one = normalized ? UINT8_MAX : 1;
1095427dc834Schristos
10967e995a2eSmrg   switch (src_type) {
10977e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
10987e995a2eSmrg      if (normalized) {
10997e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, float, _mesa_float_to_unorm(src, 8));
11007e995a2eSmrg      } else {
11017e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, float, _mesa_float_to_unsigned(src, 8));
11027e995a2eSmrg      }
11037e995a2eSmrg      break;
11047e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
11057e995a2eSmrg      if (normalized) {
11067e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_half_to_unorm(src, 8));
11077e995a2eSmrg      } else {
11087e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_half_to_unsigned(src, 8));
11097e995a2eSmrg      }
11107e995a2eSmrg      break;
11117e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
11127e995a2eSmrg      SWIZZLE_CONVERT(uint8_t, uint8_t, src);
11137e995a2eSmrg      break;
11147e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
11157e995a2eSmrg      if (normalized) {
11167e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int8_t, _mesa_snorm_to_unorm(src, 8, 8));
11177e995a2eSmrg      } else {
11187e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int8_t, _mesa_signed_to_unsigned(src, 8));
11197e995a2eSmrg      }
11207e995a2eSmrg      break;
11217e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
11227e995a2eSmrg      if (normalized) {
11237e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_unorm_to_unorm(src, 16, 8));
11247e995a2eSmrg      } else {
11257e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_unsigned_to_unsigned(src, 8));
1126af69d88dSmrg      }
11277e995a2eSmrg      break;
11287e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
11297e995a2eSmrg      if (normalized) {
11307e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int16_t, _mesa_snorm_to_unorm(src, 16, 8));
11317e995a2eSmrg      } else {
11327e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int16_t, _mesa_signed_to_unsigned(src, 8));
11337e995a2eSmrg      }
11347e995a2eSmrg      break;
11357e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
11367e995a2eSmrg      if (normalized) {
11377e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint32_t, _mesa_unorm_to_unorm(src, 32, 8));
11387e995a2eSmrg      } else {
11397e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint32_t, _mesa_unsigned_to_unsigned(src, 8));
11407e995a2eSmrg      }
11417e995a2eSmrg      break;
11427e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
11437e995a2eSmrg      if (normalized) {
11447e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int32_t, _mesa_snorm_to_unorm(src, 32, 8));
11457e995a2eSmrg      } else {
11467e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, int32_t, _mesa_signed_to_unsigned(src, 8));
11477e995a2eSmrg      }
11487e995a2eSmrg      break;
11497e995a2eSmrg   default:
11507e995a2eSmrg      assert(!"Invalid channel type combination");
1151af69d88dSmrg   }
1152427dc834Schristos}
1153427dc834Schristos
11547e995a2eSmrg
1155427dc834Schristosstatic void
11567e995a2eSmrgconvert_byte(void *void_dst, int num_dst_channels,
11577e995a2eSmrg             const void *void_src, GLenum src_type, int num_src_channels,
11587e995a2eSmrg             const uint8_t swizzle[4], bool normalized, int count)
1159427dc834Schristos{
11607e995a2eSmrg   const int8_t one = normalized ? INT8_MAX : 1;
1161427dc834Schristos
11627e995a2eSmrg   switch (src_type) {
11637e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
11647e995a2eSmrg      if (normalized) {
11657e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, float, _mesa_float_to_snorm(src, 8));
11667e995a2eSmrg      } else {
11677e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, float, _mesa_float_to_signed(src, 8));
11687e995a2eSmrg      }
11697e995a2eSmrg      break;
11707e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
11717e995a2eSmrg      if (normalized) {
11727e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_half_to_snorm(src, 8));
11737e995a2eSmrg      } else {
11747e995a2eSmrg         SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_half_to_signed(src, 8));
11757e995a2eSmrg      }
11767e995a2eSmrg      break;
11777e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
11787e995a2eSmrg      if (normalized) {
11797e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint8_t, _mesa_unorm_to_snorm(src, 8, 8));
11807e995a2eSmrg      } else {
11817e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint8_t, _mesa_unsigned_to_signed(src, 8));
11827e995a2eSmrg      }
11837e995a2eSmrg      break;
11847e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
11857e995a2eSmrg      SWIZZLE_CONVERT(int8_t, int8_t, src);
11867e995a2eSmrg      break;
11877e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
11887e995a2eSmrg      if (normalized) {
11897e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint16_t, _mesa_unorm_to_snorm(src, 16, 8));
11907e995a2eSmrg      } else {
11917e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint16_t, _mesa_unsigned_to_signed(src, 8));
11927e995a2eSmrg      }
11937e995a2eSmrg      break;
11947e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
11957e995a2eSmrg      if (normalized) {
11967e995a2eSmrg         SWIZZLE_CONVERT(int8_t, int16_t, _mesa_snorm_to_snorm(src, 16, 8));
11977e995a2eSmrg      } else {
11987e995a2eSmrg         SWIZZLE_CONVERT(int8_t, int16_t, _mesa_signed_to_signed(src, 8));
1199af69d88dSmrg      }
12007e995a2eSmrg      break;
12017e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
12027e995a2eSmrg      if (normalized) {
12037e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint32_t, _mesa_unorm_to_snorm(src, 32, 8));
12047e995a2eSmrg      } else {
12057e995a2eSmrg         SWIZZLE_CONVERT(int8_t, uint32_t, _mesa_unsigned_to_signed(src, 8));
12067e995a2eSmrg      }
12077e995a2eSmrg      break;
12087e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
12097e995a2eSmrg      if (normalized) {
12107e995a2eSmrg         SWIZZLE_CONVERT(int8_t, int32_t, _mesa_snorm_to_snorm(src, 32, 8));
12117e995a2eSmrg      } else {
12127e995a2eSmrg         SWIZZLE_CONVERT(int8_t, int32_t, _mesa_signed_to_signed(src, 8));
12137e995a2eSmrg      }
12147e995a2eSmrg      break;
12157e995a2eSmrg   default:
12167e995a2eSmrg      assert(!"Invalid channel type combination");
1217af69d88dSmrg   }
1218427dc834Schristos}
1219427dc834Schristos
12207e995a2eSmrg
1221427dc834Schristosstatic void
12227e995a2eSmrgconvert_ushort(void *void_dst, int num_dst_channels,
12237e995a2eSmrg               const void *void_src, GLenum src_type, int num_src_channels,
12247e995a2eSmrg               const uint8_t swizzle[4], bool normalized, int count)
1225427dc834Schristos{
12267e995a2eSmrg   const uint16_t one = normalized ? UINT16_MAX : 1;
12277e995a2eSmrg
12287e995a2eSmrg   switch (src_type) {
12297e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
12307e995a2eSmrg      if (normalized) {
12317e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, float, _mesa_float_to_unorm(src, 16));
12327e995a2eSmrg      } else {
12337e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, float, _mesa_float_to_unsigned(src, 16));
12347e995a2eSmrg      }
12357e995a2eSmrg      break;
12367e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
12377e995a2eSmrg      if (normalized) {
12387e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_half_to_unorm(src, 16));
12397e995a2eSmrg      } else {
12407e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_half_to_unsigned(src, 16));
1241af69d88dSmrg      }
12427e995a2eSmrg      break;
12437e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
12447e995a2eSmrg      if (normalized) {
12457e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint8_t, _mesa_unorm_to_unorm(src, 8, 16));
12467e995a2eSmrg      } else {
12477e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint8_t, src);
12487e995a2eSmrg      }
12497e995a2eSmrg      break;
12507e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
12517e995a2eSmrg      if (normalized) {
12527e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int8_t, _mesa_snorm_to_unorm(src, 8, 16));
12537e995a2eSmrg      } else {
12547e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int8_t, _mesa_signed_to_unsigned(src, 16));
12557e995a2eSmrg      }
12567e995a2eSmrg      break;
12577e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
12587e995a2eSmrg      SWIZZLE_CONVERT(uint16_t, uint16_t, src);
12597e995a2eSmrg      break;
12607e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
12617e995a2eSmrg      if (normalized) {
12627e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int16_t, _mesa_snorm_to_unorm(src, 16, 16));
12637e995a2eSmrg      } else {
12647e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int16_t, _mesa_signed_to_unsigned(src, 16));
12657e995a2eSmrg      }
12667e995a2eSmrg      break;
12677e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
12687e995a2eSmrg      if (normalized) {
12697e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint32_t, _mesa_unorm_to_unorm(src, 32, 16));
12707e995a2eSmrg      } else {
12717e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint32_t, _mesa_unsigned_to_unsigned(src, 16));
12727e995a2eSmrg      }
12737e995a2eSmrg      break;
12747e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
12757e995a2eSmrg      if (normalized) {
12767e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int32_t, _mesa_snorm_to_unorm(src, 32, 16));
12777e995a2eSmrg      } else {
12787e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, int32_t, _mesa_signed_to_unsigned(src, 16));
12797e995a2eSmrg      }
12807e995a2eSmrg      break;
12817e995a2eSmrg   default:
12827e995a2eSmrg      assert(!"Invalid channel type combination");
1283af69d88dSmrg   }
1284427dc834Schristos}
1285427dc834Schristos
12867e995a2eSmrg
1287427dc834Schristosstatic void
12887e995a2eSmrgconvert_short(void *void_dst, int num_dst_channels,
12897e995a2eSmrg              const void *void_src, GLenum src_type, int num_src_channels,
12907e995a2eSmrg              const uint8_t swizzle[4], bool normalized, int count)
1291427dc834Schristos{
12927e995a2eSmrg   const int16_t one = normalized ? INT16_MAX : 1;
1293427dc834Schristos
12947e995a2eSmrg   switch (src_type) {
12957e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
12967e995a2eSmrg      if (normalized) {
12977e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, float, _mesa_float_to_snorm(src, 16));
12987e995a2eSmrg      } else {
12997e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, float, _mesa_float_to_signed(src, 16));
13007e995a2eSmrg      }
13017e995a2eSmrg      break;
13027e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
13037e995a2eSmrg      if (normalized) {
13047e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_half_to_snorm(src, 16));
13057e995a2eSmrg      } else {
13067e995a2eSmrg         SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_half_to_signed(src, 16));
13077e995a2eSmrg      }
13087e995a2eSmrg      break;
13097e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
13107e995a2eSmrg      if (normalized) {
13117e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint8_t, _mesa_unorm_to_snorm(src, 8, 16));
13127e995a2eSmrg      } else {
13137e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint8_t, src);
13147e995a2eSmrg      }
13157e995a2eSmrg      break;
13167e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
13177e995a2eSmrg      if (normalized) {
13187e995a2eSmrg         SWIZZLE_CONVERT(int16_t, int8_t, _mesa_snorm_to_snorm(src, 8, 16));
13197e995a2eSmrg      } else {
13207e995a2eSmrg         SWIZZLE_CONVERT(int16_t, int8_t, src);
13217e995a2eSmrg      }
13227e995a2eSmrg      break;
13237e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
13247e995a2eSmrg      if (normalized) {
13257e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint16_t, _mesa_unorm_to_snorm(src, 16, 16));
13267e995a2eSmrg      } else {
13277e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint16_t, _mesa_unsigned_to_signed(src, 16));
13287e995a2eSmrg      }
13297e995a2eSmrg      break;
13307e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
13317e995a2eSmrg      SWIZZLE_CONVERT(int16_t, int16_t, src);
13327e995a2eSmrg      break;
13337e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
13347e995a2eSmrg      if (normalized) {
13357e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint32_t, _mesa_unorm_to_snorm(src, 32, 16));
13367e995a2eSmrg      } else {
13377e995a2eSmrg         SWIZZLE_CONVERT(int16_t, uint32_t, _mesa_unsigned_to_signed(src, 16));
1338af69d88dSmrg      }
13397e995a2eSmrg      break;
13407e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
13417e995a2eSmrg      if (normalized) {
13427e995a2eSmrg         SWIZZLE_CONVERT(int16_t, int32_t, _mesa_snorm_to_snorm(src, 32, 16));
13437e995a2eSmrg      } else {
13447e995a2eSmrg         SWIZZLE_CONVERT(int16_t, int32_t, _mesa_signed_to_signed(src, 16));
13457e995a2eSmrg      }
13467e995a2eSmrg      break;
13477e995a2eSmrg   default:
13487e995a2eSmrg      assert(!"Invalid channel type combination");
1349af69d88dSmrg   }
1350427dc834Schristos}
1351427dc834Schristos
1352427dc834Schristosstatic void
13537e995a2eSmrgconvert_uint(void *void_dst, int num_dst_channels,
13547e995a2eSmrg             const void *void_src, GLenum src_type, int num_src_channels,
13557e995a2eSmrg             const uint8_t swizzle[4], bool normalized, int count)
1356427dc834Schristos{
13577e995a2eSmrg   const uint32_t one = normalized ? UINT32_MAX : 1;
13587e995a2eSmrg
13597e995a2eSmrg   switch (src_type) {
13607e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
13617e995a2eSmrg      if (normalized) {
13627e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, float, _mesa_float_to_unorm(src, 32));
13637e995a2eSmrg      } else {
13647e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, float, _mesa_float_to_unsigned(src, 32));
13657e995a2eSmrg      }
13667e995a2eSmrg      break;
13677e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
13687e995a2eSmrg      if (normalized) {
13697e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_half_to_unorm(src, 32));
13707e995a2eSmrg      } else {
13717e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_half_to_unsigned(src, 32));
13727e995a2eSmrg      }
13737e995a2eSmrg      break;
13747e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
13757e995a2eSmrg      if (normalized) {
13767e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint8_t, _mesa_unorm_to_unorm(src, 8, 32));
13777e995a2eSmrg      } else {
13787e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint8_t, src);
13797e995a2eSmrg      }
13807e995a2eSmrg      break;
13817e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
13827e995a2eSmrg      if (normalized) {
13837e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int8_t, _mesa_snorm_to_unorm(src, 8, 32));
13847e995a2eSmrg      } else {
13857e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int8_t, _mesa_signed_to_unsigned(src, 32));
13867e995a2eSmrg      }
13877e995a2eSmrg      break;
13887e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
13897e995a2eSmrg      if (normalized) {
13907e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_unorm_to_unorm(src, 16, 32));
13917e995a2eSmrg      } else {
13927e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, src);
1393af69d88dSmrg      }
13947e995a2eSmrg      break;
13957e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
13967e995a2eSmrg      if (normalized) {
13977e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int16_t, _mesa_snorm_to_unorm(src, 16, 32));
13987e995a2eSmrg      } else {
13997e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int16_t, _mesa_signed_to_unsigned(src, 32));
14007e995a2eSmrg      }
14017e995a2eSmrg      break;
14027e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
14037e995a2eSmrg      SWIZZLE_CONVERT(uint32_t, uint32_t, src);
14047e995a2eSmrg      break;
14057e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
14067e995a2eSmrg      if (normalized) {
14077e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int32_t, _mesa_snorm_to_unorm(src, 32, 32));
14087e995a2eSmrg      } else {
14097e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, int32_t, _mesa_signed_to_unsigned(src, 32));
14107e995a2eSmrg      }
14117e995a2eSmrg      break;
14127e995a2eSmrg   default:
14137e995a2eSmrg      assert(!"Invalid channel type combination");
1414af69d88dSmrg   }
1415427dc834Schristos}
1416427dc834Schristos
14177e995a2eSmrg
1418427dc834Schristosstatic void
14197e995a2eSmrgconvert_int(void *void_dst, int num_dst_channels,
14207e995a2eSmrg            const void *void_src, GLenum src_type, int num_src_channels,
14217e995a2eSmrg            const uint8_t swizzle[4], bool normalized, int count)
1422427dc834Schristos{
14237e995a2eSmrg   const int32_t one = normalized ? INT32_MAX : 1;
1424427dc834Schristos
14257e995a2eSmrg   switch (src_type) {
14267e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
14277e995a2eSmrg      if (normalized) {
14287e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, float, _mesa_float_to_snorm(src, 32));
14297e995a2eSmrg      } else {
14307e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, float, _mesa_float_to_signed(src, 32));
14317e995a2eSmrg      }
14327e995a2eSmrg      break;
14337e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
14347e995a2eSmrg      if (normalized) {
14357e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_half_to_snorm(src, 32));
14367e995a2eSmrg      } else {
14377e995a2eSmrg         SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_half_to_signed(src, 32));
14387e995a2eSmrg      }
14397e995a2eSmrg      break;
14407e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
14417e995a2eSmrg      if (normalized) {
14427e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint8_t, _mesa_unorm_to_snorm(src, 8, 32));
14437e995a2eSmrg      } else {
14447e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint8_t, src);
14457e995a2eSmrg      }
14467e995a2eSmrg      break;
14477e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
14487e995a2eSmrg      if (normalized) {
14497e995a2eSmrg         SWIZZLE_CONVERT(int32_t, int8_t, _mesa_snorm_to_snorm(src, 8, 32));
14507e995a2eSmrg      } else {
14517e995a2eSmrg         SWIZZLE_CONVERT(int32_t, int8_t, src);
1452af69d88dSmrg      }
14537e995a2eSmrg      break;
14547e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
14557e995a2eSmrg      if (normalized) {
14567e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint16_t, _mesa_unorm_to_snorm(src, 16, 32));
14577e995a2eSmrg      } else {
14587e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint16_t, src);
14597e995a2eSmrg      }
14607e995a2eSmrg      break;
14617e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
14627e995a2eSmrg      if (normalized) {
14637e995a2eSmrg         SWIZZLE_CONVERT(int32_t, int16_t, _mesa_snorm_to_snorm(src, 16, 32));
14647e995a2eSmrg      } else {
14657e995a2eSmrg         SWIZZLE_CONVERT(int32_t, int16_t, src);
14667e995a2eSmrg      }
14677e995a2eSmrg      break;
14687e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
14697e995a2eSmrg      if (normalized) {
14707e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint32_t, _mesa_unorm_to_snorm(src, 32, 32));
14717e995a2eSmrg      } else {
14727e995a2eSmrg         SWIZZLE_CONVERT(int32_t, uint32_t, _mesa_unsigned_to_signed(src, 32));
14737e995a2eSmrg      }
14747e995a2eSmrg      break;
14757e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
14767e995a2eSmrg      SWIZZLE_CONVERT(int32_t, int32_t, src);
14777e995a2eSmrg      break;
14787e995a2eSmrg   default:
14797e995a2eSmrg      assert(!"Invalid channel type combination");
1480af69d88dSmrg   }
1481427dc834Schristos}
1482427dc834Schristos
14837e995a2eSmrg
14847e995a2eSmrg/**
14857e995a2eSmrg * Convert between array-based color formats.
14867e995a2eSmrg *
14877e995a2eSmrg * Most format conversion operations required by GL can be performed by
14887e995a2eSmrg * converting one channel at a time, shuffling the channels around, and
14897e995a2eSmrg * optionally filling missing channels with zeros and ones.  This function
14907e995a2eSmrg * does just that in a general, yet efficient, way.
14917e995a2eSmrg *
14927e995a2eSmrg * The swizzle parameter is an array of 4 numbers (see
14937e995a2eSmrg * _mesa_get_format_swizzle) that describes where each channel in the
14947e995a2eSmrg * destination should come from in the source.  If swizzle[i] < 4 then it
14957e995a2eSmrg * means that dst[i] = CONVERT(src[swizzle[i]]).  If swizzle[i] is
14967e995a2eSmrg * MESA_FORMAT_SWIZZLE_ZERO or MESA_FORMAT_SWIZZLE_ONE, the corresponding
14977e995a2eSmrg * dst[i] will be filled with the appropreate representation of zero or one
14987e995a2eSmrg * respectively.
14997e995a2eSmrg *
15007e995a2eSmrg * Under most circumstances, the source and destination images must be
15017e995a2eSmrg * different as no care is taken not to clobber one with the other.
15027e995a2eSmrg * However, if they have the same number of bits per pixel, it is safe to
15037e995a2eSmrg * do an in-place conversion.
15047e995a2eSmrg *
15057e995a2eSmrg * \param[out] dst               pointer to where the converted data should
15067e995a2eSmrg *                               be stored
15077e995a2eSmrg *
15087e995a2eSmrg * \param[in]  dst_type          the destination GL type of the converted
15097e995a2eSmrg *                               data (GL_BYTE, etc.)
15107e995a2eSmrg *
15117e995a2eSmrg * \param[in]  num_dst_channels  the number of channels in the converted
15127e995a2eSmrg *                               data
15137e995a2eSmrg *
15147e995a2eSmrg * \param[in]  src               pointer to the source data
15157e995a2eSmrg *
15167e995a2eSmrg * \param[in]  src_type          the GL type of the source data (GL_BYTE,
15177e995a2eSmrg *                               etc.)
15187e995a2eSmrg *
15197e995a2eSmrg * \param[in]  num_src_channels  the number of channels in the source data
15207e995a2eSmrg *                               (the number of channels total, not just
15217e995a2eSmrg *                               the number used)
15227e995a2eSmrg *
15237e995a2eSmrg * \param[in]  swizzle           describes how to get the destination data
15247e995a2eSmrg *                               from the source data.
15257e995a2eSmrg *
15267e995a2eSmrg * \param[in]  normalized        for integer types, this indicates whether
15277e995a2eSmrg *                               the data should be considered as integers
15287e995a2eSmrg *                               or as normalized integers;
15297e995a2eSmrg *
15307e995a2eSmrg * \param[in]  count             the number of pixels to convert
15317e995a2eSmrg */
1532427dc834Schristosvoid
15337e995a2eSmrg_mesa_swizzle_and_convert(void *void_dst, enum mesa_array_format_datatype dst_type, int num_dst_channels,
15347e995a2eSmrg                          const void *void_src, enum mesa_array_format_datatype src_type, int num_src_channels,
1535427dc834Schristos                          const uint8_t swizzle[4], bool normalized, int count)
1536427dc834Schristos{
1537427dc834Schristos   if (swizzle_convert_try_memcpy(void_dst, dst_type, num_dst_channels,
1538427dc834Schristos                                  void_src, src_type, num_src_channels,
1539427dc834Schristos                                  swizzle, normalized, count))
1540427dc834Schristos      return;
1541427dc834Schristos
1542427dc834Schristos   switch (dst_type) {
15437e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
15447e995a2eSmrg      convert_float(void_dst, num_dst_channels, void_src, src_type,
15457e995a2eSmrg                    num_src_channels, swizzle, normalized, count);
15467e995a2eSmrg      break;
15477e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_HALF:
15487e995a2eSmrg      convert_half_float(void_dst, num_dst_channels, void_src, src_type,
15497e995a2eSmrg                    num_src_channels, swizzle, normalized, count);
15507e995a2eSmrg      break;
15517e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
15527e995a2eSmrg      convert_ubyte(void_dst, num_dst_channels, void_src, src_type,
15537e995a2eSmrg                    num_src_channels, swizzle, normalized, count);
15547e995a2eSmrg      break;
15557e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_BYTE:
15567e995a2eSmrg      convert_byte(void_dst, num_dst_channels, void_src, src_type,
15577e995a2eSmrg                   num_src_channels, swizzle, normalized, count);
15587e995a2eSmrg      break;
15597e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_USHORT:
15607e995a2eSmrg      convert_ushort(void_dst, num_dst_channels, void_src, src_type,
15617e995a2eSmrg                     num_src_channels, swizzle, normalized, count);
15627e995a2eSmrg      break;
15637e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_SHORT:
15647e995a2eSmrg      convert_short(void_dst, num_dst_channels, void_src, src_type,
15657e995a2eSmrg                    num_src_channels, swizzle, normalized, count);
15667e995a2eSmrg      break;
15677e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_UINT:
15687e995a2eSmrg      convert_uint(void_dst, num_dst_channels, void_src, src_type,
15697e995a2eSmrg                   num_src_channels, swizzle, normalized, count);
15707e995a2eSmrg      break;
15717e995a2eSmrg   case MESA_ARRAY_FORMAT_TYPE_INT:
15727e995a2eSmrg      convert_int(void_dst, num_dst_channels, void_src, src_type,
15737e995a2eSmrg                  num_src_channels, swizzle, normalized, count);
1574427dc834Schristos      break;
1575af69d88dSmrg   default:
1576af69d88dSmrg      assert(!"Invalid channel type");
1577af69d88dSmrg   }
1578af69d88dSmrg}
1579