[Mesa-dev] [PATCH 06/12] main/format_utils: Add a general format conversion function

Jason Ekstrand jason at jlekstrand.net
Thu Jul 17 11:04:28 PDT 2014


Most format conversion operations required by GL can be performed by
converting one channel at a time, shuffling the channels around, and
optionally filling missing channels with zeros and ones.  This adds a
function to do just that in a general, yet efficient, way.

Signed-off-by: Jason Ekstrand <jason.ekstrand at intel.com>
---
 src/mesa/main/format_utils.c | 566 +++++++++++++++++++++++++++++++++++++++++++
 src/mesa/main/format_utils.h |  18 ++
 2 files changed, 584 insertions(+)

diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c
index 241c158..0cb3eae 100644
--- a/src/mesa/main/format_utils.c
+++ b/src/mesa/main/format_utils.c
@@ -54,3 +54,569 @@ _mesa_srgb_ubyte_to_linear_float(uint8_t cl)
 
    return lut[cl];
 }
+
+static bool
+swizzle_convert_try_memcpy(void *dst, GLenum dst_type, int num_dst_channels,
+                           const void *src, GLenum src_type, int num_src_channels,
+                           const uint8_t swizzle[4], bool normalized, int count)
+{
+   int i;
+
+   if (src_type != dst_type)
+      return false;
+   if (num_src_channels != num_dst_channels)
+      return false;
+
+   for (i = 0; i < num_dst_channels; ++i)
+      if (swizzle[i] != i && swizzle[i] != MESA_FORMAT_SWIZZLE_NONE)
+         return false;
+
+   memcpy(dst, src, count * num_src_channels * _mesa_sizeof_type(src_type));
+
+   return true;
+}
+
+/* Note: This loop is carefully crafted for performance.  Be careful when
+ * changing it and run some benchmarks to ensure no performance regressions
+ * if you do.
+ */
+#define SWIZZLE_CONVERT_LOOP(DST_TYPE, SRC_TYPE, CONV)   \
+   do {                                                  \
+      const SRC_TYPE *typed_src = void_src;              \
+      DST_TYPE *typed_dst = void_dst;                    \
+      DST_TYPE tmp[7];                                   \
+      tmp[4] = 0;                                        \
+      tmp[5] = one;                                      \
+      for (s = 0; s < count; ++s) {                      \
+         for (j = 0; j < num_src_channels; ++j) {        \
+            SRC_TYPE src = typed_src[j];                 \
+            tmp[j] = CONV;                               \
+         }                                               \
+                                                         \
+         typed_dst[0] = tmp[swizzle_x];                  \
+         if (num_dst_channels > 1) {                     \
+            typed_dst[1] = tmp[swizzle_y];               \
+            if (num_dst_channels > 2) {                  \
+               typed_dst[2] = tmp[swizzle_z];            \
+               if (num_dst_channels > 3) {               \
+                  typed_dst[3] = tmp[swizzle_w];         \
+               }                                         \
+            }                                            \
+         }                                               \
+         typed_src += num_src_channels;                  \
+         typed_dst += num_dst_channels;                  \
+      }                                                  \
+   } while (0);
+
+/**
+ * Convert between array-based color formats.
+ *
+ * Most format conversion operations required by GL can be performed by
+ * converting one channel at a time, shuffling the channels around, and
+ * optionally filling missing channels with zeros and ones.  This function
+ * does just that in a general, yet efficient, way.
+ *
+ * Most of the parameters are self-explanitory.  The swizzle parameter is
+ * an array of 4 numbers (see _mesa_get_format_swizzle) that describes
+ * where each channel in the destination should come from in the source.
+ *
+ * Under most circumstances, the source and destination images must be
+ * different as no care is taken not to clobber one with the other.
+ * However, if they have the same number of bits per pixel, it is safe to
+ * do an in-place conversion.
+ */
+void
+_mesa_swizzle_and_convert(void *void_dst, GLenum dst_type, int num_dst_channels,
+                          const void *void_src, GLenum src_type, int num_src_channels,
+                          const uint8_t swizzle[4], bool normalized, int count)
+{
+   int s, j;
+   register uint8_t swizzle_x, swizzle_y, swizzle_z, swizzle_w;
+
+   if (swizzle_convert_try_memcpy(void_dst, dst_type, num_dst_channels,
+                                  void_src, src_type, num_src_channels,
+                                  swizzle, normalized, count))
+      return;
+
+   swizzle_x = swizzle[0];
+   swizzle_y = swizzle[1];
+   swizzle_z = swizzle[2];
+   swizzle_w = swizzle[3];
+
+   switch (dst_type) {
+   case GL_FLOAT:
+   {
+      const float one = 1.0f;
+      switch (src_type) {
+      case GL_FLOAT:
+         SWIZZLE_CONVERT_LOOP(float, float, src)
+         break;
+      case GL_HALF_FLOAT:
+         SWIZZLE_CONVERT_LOOP(float, uint16_t, _mesa_half_to_float(src))
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, uint8_t, UBYTE_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, int8_t, BYTE_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, uint16_t, USHORT_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, int16_t, SHORT_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, uint32_t, UINT_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(float, int32_t, INT_TO_FLOAT(src))
+         } else {
+            SWIZZLE_CONVERT_LOOP(float, int32_t, src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_HALF_FLOAT:
+   {
+      const uint16_t one = _mesa_float_to_half(1.0f);
+      switch (src_type) {
+      case GL_FLOAT:
+         SWIZZLE_CONVERT_LOOP(uint16_t, float, _mesa_float_to_half(src))
+         break;
+      case GL_HALF_FLOAT:
+         SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(UBYTE_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(BYTE_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(USHORT_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(SHORT_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(UINT_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(INT_TO_FLOAT(src)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(src))
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_UNSIGNED_BYTE:
+   {
+      const uint8_t one = normalized ? UINT8_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_UBYTE(CLAMP(src, 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_UBYTE(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         SWIZZLE_CONVERT_LOOP(uint8_t, uint8_t, src)
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : ((uint8_t)src * 2) + ((uint8_t)src >> 6))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src >> 8)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : (uint16_t)src >> 7)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src >> 24)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 23)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_BYTE:
+   {
+      const int8_t one = normalized ? INT8_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_BYTE(CLAMP(src, -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_BYTE(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src >> 1)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         SWIZZLE_CONVERT_LOOP(int8_t, int8_t, src)
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src >> 9)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src >> 8)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src >> 25)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src >> 24)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_UNSIGNED_SHORT:
+   {
+      const uint16_t one = normalized ? UINT16_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_USHORT(CLAMP(src, 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_USHORT(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, EXTEND_NORMALIZED_UINT((uint16_t)src, 8, 16))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint16_t)src, 7, 16))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint16_t)src, 15, 16))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src >> 16)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 15)
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_SHORT:
+   {
+      const int16_t one = normalized ? INT16_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_SHORT(CLAMP(src, -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_SHORT(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, EXTEND_NORMALIZED_UINT((int16_t)src, 8, 15))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int16_t, int8_t, EXTEND_NORMALIZED_INT((int16_t)src, 7, 15))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int16_t, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src >> 1)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         SWIZZLE_CONVERT_LOOP(int16_t, int16_t, src)
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src >> 17)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src >> 16)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_UNSIGNED_INT:
+   {
+      const uint32_t one = normalized ? UINT32_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_UINT(CLAMP(src, 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_UINT(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, EXTEND_NORMALIZED_UINT((uint32_t)src, 8, 32))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 7, 32))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, EXTEND_NORMALIZED_UINT((uint32_t)src, 16, 32))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 15, 32))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         SWIZZLE_CONVERT_LOOP(uint32_t, uint32_t, src)
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 31, 32))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : src)
+         }
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   case GL_INT:
+   {
+      const int32_t one = normalized ? INT32_MAX : 1;
+      switch (src_type) {
+      case GL_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_INT(CLAMP(src, -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_INT(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
+         } else {
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, EXTEND_NORMALIZED_UINT((int32_t)src, 8, 31))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int32_t, int8_t, EXTEND_NORMALIZED_INT((int32_t)src, 7, 31))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int32_t, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, EXTEND_NORMALIZED_UINT((int32_t)src, 16, 31))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int32_t, int16_t, EXTEND_NORMALIZED_INT((int32_t)src, 15, 31))
+         } else {
+            SWIZZLE_CONVERT_LOOP(int32_t, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src >> 1)
+         } else {
+            SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         SWIZZLE_CONVERT_LOOP(int32_t, int32_t, src)
+         break;
+      default:
+         assert(!"Invalid channel type combination");
+      }
+   } break;
+   default:
+      assert(!"Invalid channel type");
+   }
+}
diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h
index 6af3aa5..c5dab7b 100644
--- a/src/mesa/main/format_utils.h
+++ b/src/mesa/main/format_utils.h
@@ -33,6 +33,19 @@
 
 #include "macros.h"
 
+/* Only guaranteed to work for BITS <= 32 */
+#define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << BITS) - 1))
+
+/* Extends an integer of size Sb to one of size Db in a linear way */
+#define EXTEND_NORMALIZED_UINT(X, Sb, Db) \
+      (((X) * (__typeof__(X))(MAX_UINT(Db) / MAX_UINT(Sb))) + \
+       ((Db % Sb) ? ((X) >> (Sb - Db % Sb)) : (__typeof__(X))0))
+
+/* This is almost the same as extending unsigned int except that we have to
+ * handle the case of -MAX(Sb) */
+#define EXTEND_NORMALIZED_INT(X, Sb, Db) (((X) < -(__typeof__(X))MAX_UINT(Sb)) \
+      ? -(__typeof__(X))MAX_UINT(Db) : EXTEND_NORMALIZED_UINT(X, Sb, Db))
+
 /* RGB to sRGB conversion functions */
 
 static inline float
@@ -65,4 +78,9 @@ _mesa_srgb_to_linear(float cs)
 
 float _mesa_srgb_ubyte_to_linear_float(uint8_t cl);
 
+void
+_mesa_swizzle_and_convert(void *dst, GLenum dst_type, int num_dst_channels,
+                          const void *src, GLenum src_type, int num_src_channels,
+                          const uint8_t swizzle[4], bool normalized, int count);
+
 #endif
-- 
2.0.1



More information about the mesa-dev mailing list