Mesa (master): mesa/format_utils: Add a general format conversion function

Jason Ekstrand jekstrand at kemper.freedesktop.org
Tue Aug 5 18:08:22 UTC 2014


Module: Mesa
Branch: master
Commit: d55f77b503ab7b59ecdd8f31c4f7dc498710e75b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=d55f77b503ab7b59ecdd8f31c4f7dc498710e75b

Author: Jason Ekstrand <jason.ekstrand at intel.com>
Date:   Fri Jul 11 08:41:49 2014 -0700

mesa/format_utils: Add a general format conversion function

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.

v2:
 * Add better comments including full docs for functions
 * Don't use __typeof__
 * Use inline helpers instead of writing out conversions by hand,
 * Force full loop unrolling for better performance

v3: Add another set of parens around the MAX_INT macro

Signed-off-by: Jason Ekstrand <jason.ekstrand at intel.com>
Reviewed-by: Brian Paul <brianp at vmware.com>

---

 src/mesa/Makefile.sources    |    1 +
 src/mesa/main/format_utils.c |  870 ++++++++++++++++++++++++++++++++++++++++++
 src/mesa/main/format_utils.h |   41 ++
 3 files changed, 912 insertions(+)

diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
index 5ccce54..45c53ca 100644
--- a/src/mesa/Makefile.sources
+++ b/src/mesa/Makefile.sources
@@ -51,6 +51,7 @@ MAIN_FILES = \
 	$(SRCDIR)main/formats.c \
 	$(SRCDIR)main/format_pack.c \
 	$(SRCDIR)main/format_unpack.c \
+	$(SRCDIR)main/format_utils.c \
 	$(SRCDIR)main/framebuffer.c \
 	$(SRCDIR)main/get.c \
 	$(SRCDIR)main/genmipmap.c \
diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c
new file mode 100644
index 0000000..8625969
--- /dev/null
+++ b/src/mesa/main/format_utils.c
@@ -0,0 +1,870 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2014  Intel Corporation  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "format_utils.h"
+#include "glformats.h"
+
+/* A bunch of format conversion macros and helper functions used below */
+
+/* Only guaranteed to work for BITS <= 32 */
+#define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << (BITS)) - 1))
+#define MAX_INT(BITS) ((int)MAX_UINT((BITS) - 1))
+
+/* Extends an integer of size SRC_BITS to one of size DST_BITS linearly */
+#define EXTEND_NORMALIZED_INT(X, SRC_BITS, DST_BITS) \
+      (((X) * (int)(MAX_UINT(DST_BITS) / MAX_UINT(SRC_BITS))) + \
+       ((DST_BITS % SRC_BITS) ? ((X) >> (SRC_BITS - DST_BITS % SRC_BITS)) : 0))
+
+static inline float
+unorm_to_float(unsigned x, unsigned src_bits)
+{
+   return x * (1.0f / (float)MAX_UINT(src_bits));
+}
+
+static inline float
+snorm_to_float(int x, unsigned src_bits)
+{
+   if (x == -MAX_INT(src_bits))
+      return -1.0f;
+   else
+      return x * (1.0f / (float)MAX_INT(src_bits));
+}
+
+static inline uint16_t
+unorm_to_half(unsigned x, unsigned src_bits)
+{
+   return _mesa_float_to_half(unorm_to_float(x, src_bits));
+}
+
+static inline uint16_t
+snorm_to_half(int x, unsigned src_bits)
+{
+   return _mesa_float_to_half(snorm_to_float(x, src_bits));
+}
+
+static inline unsigned
+float_to_unorm(float x, unsigned dst_bits)
+{
+   if (x < 0.0f)
+      return 0;
+   else if (x > 1.0f)
+      return MAX_UINT(dst_bits);
+   else
+      return F_TO_I(x * MAX_UINT(dst_bits));
+}
+
+static inline unsigned
+half_to_unorm(uint16_t x, unsigned dst_bits)
+{
+   return float_to_unorm(_mesa_half_to_float(x), dst_bits);
+}
+
+static inline unsigned
+unorm_to_unorm(unsigned x, unsigned src_bits, unsigned dst_bits)
+{
+   if (src_bits < dst_bits)
+      return EXTEND_NORMALIZED_INT(x, src_bits, dst_bits);
+   else
+      return x >> (src_bits - dst_bits);
+}
+
+static inline unsigned
+snorm_to_unorm(int x, unsigned src_bits, unsigned dst_bits)
+{
+   if (x < 0)
+      return 0;
+   else
+      return unorm_to_unorm(x, src_bits - 1, dst_bits);
+}
+
+static inline int
+float_to_snorm(float x, unsigned dst_bits)
+{
+   if (x < -1.0f)
+      return -MAX_INT(dst_bits);
+   else if (x > 1.0f)
+      return MAX_INT(dst_bits);
+   else
+      return F_TO_I(x * MAX_INT(dst_bits));
+}
+
+static inline int
+half_to_snorm(uint16_t x, unsigned dst_bits)
+{
+   return float_to_snorm(_mesa_half_to_float(x), dst_bits);
+}
+
+static inline int
+unorm_to_snorm(unsigned x, unsigned src_bits, unsigned dst_bits)
+{
+   return unorm_to_unorm(x, src_bits, dst_bits - 1);
+}
+
+static inline int
+snorm_to_snorm(int x, unsigned src_bits, unsigned dst_bits)
+{
+   if (x < -MAX_INT(src_bits))
+      return -MAX_INT(dst_bits);
+   else if (src_bits < dst_bits)
+      return EXTEND_NORMALIZED_INT(x, src_bits - 1, dst_bits - 1);
+   else
+      return x >> (src_bits - dst_bits);
+}
+
+static inline unsigned
+float_to_uint(float x)
+{
+   if (x < 0.0f)
+      return 0;
+   else
+      return x;
+}
+
+static inline unsigned
+half_to_uint(uint16_t x)
+{
+   if (_mesa_half_is_negative(x))
+      return 0;
+   else
+      return _mesa_float_to_half(x);
+}
+
+/**
+ * Attempts to perform the given swizzle-and-convert operation with memcpy
+ *
+ * This function determines if the given swizzle-and-convert operation can
+ * be done with a simple memcpy and, if so, does the memcpy.  If not, it
+ * returns false and we fall back to the standard version below.
+ *
+ * The arguments are exactly the same as for _mesa_swizzle_and_convert
+ *
+ * \return  true if it successfully performed the swizzle-and-convert
+ *          operation with memcpy, false otherwise
+ */
+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;
+}
+
+/**
+ * Represents a single instance of the standard swizzle-and-convert loop
+ *
+ * Any swizzle-and-convert operation simply loops through the pixels and
+ * performs the transformation operation one pixel at a time.  This macro
+ * embodies one instance of the conversion loop.  This way we can do all
+ * control flow outside of the loop and allow the compiler to unroll
+ * everything inside the loop.
+ *
+ * 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.
+ *
+ * \param   DST_TYPE    the C datatype of the destination
+ * \param   DST_CHANS   the number of destination channels
+ * \param   SRC_TYPE    the C datatype of the source
+ * \param   SRC_CHANS   the number of source channels
+ * \param   CONV        an expression for converting from the source data,
+ *                      storred in the variable "src", to the destination
+ *                      format
+ */
+#define SWIZZLE_CONVERT_LOOP(DST_TYPE, DST_CHANS, SRC_TYPE, SRC_CHANS, CONV) \
+   for (s = 0; s < count; ++s) {                                  \
+      for (j = 0; j < SRC_CHANS; ++j) {                           \
+         SRC_TYPE src = typed_src[j];                             \
+         tmp[j] = CONV;                                           \
+      }                                                           \
+                                                                  \
+      typed_dst[0] = tmp[swizzle_x];                              \
+      if (DST_CHANS > 1) {                                        \
+         typed_dst[1] = tmp[swizzle_y];                           \
+         if (DST_CHANS > 2) {                                     \
+            typed_dst[2] = tmp[swizzle_z];                        \
+            if (DST_CHANS > 3) {                                  \
+               typed_dst[3] = tmp[swizzle_w];                     \
+            }                                                     \
+         }                                                        \
+      }                                                           \
+      typed_src += SRC_CHANS;                                     \
+      typed_dst += DST_CHANS;                                     \
+   }                                                              \
+
+/**
+ * Represents a single swizzle-and-convert operation
+ *
+ * This macro represents everything done in a single swizzle-and-convert
+ * operation.  The actual work is done by the SWIZZLE_CONVERT_LOOP macro.
+ * This macro acts as a wrapper that uses a nested switch to ensure that
+ * all looping parameters get unrolled.
+ *
+ * This macro makes assumptions about variables etc. in the calling
+ * function.  Changes to _mesa_swizzle_and_convert may require changes to
+ * this macro.
+ *
+ * \param   DST_TYPE    the C datatype of the destination
+ * \param   SRC_TYPE    the C datatype of the source
+ * \param   CONV        an expression for converting from the source data,
+ *                      storred in the variable "src", to the destination
+ *                      format
+ */
+#define SWIZZLE_CONVERT(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;                                               \
+      switch (num_dst_channels) {                                 \
+      case 1:                                                     \
+         switch (num_src_channels) {                              \
+         case 1:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 1, CONV)  \
+            break;                                                \
+         case 2:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 2, CONV)  \
+            break;                                                \
+         case 3:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 3, CONV)  \
+            break;                                                \
+         case 4:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 1, SRC_TYPE, 4, CONV)  \
+            break;                                                \
+         }                                                        \
+         break;                                                   \
+      case 2:                                                     \
+         switch (num_src_channels) {                              \
+         case 1:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 1, CONV)  \
+            break;                                                \
+         case 2:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 2, CONV)  \
+            break;                                                \
+         case 3:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 3, CONV)  \
+            break;                                                \
+         case 4:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 2, SRC_TYPE, 4, CONV)  \
+            break;                                                \
+         }                                                        \
+         break;                                                   \
+      case 3:                                                     \
+         switch (num_src_channels) {                              \
+         case 1:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 1, CONV)  \
+            break;                                                \
+         case 2:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 2, CONV)  \
+            break;                                                \
+         case 3:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 3, CONV)  \
+            break;                                                \
+         case 4:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 3, SRC_TYPE, 4, CONV)  \
+            break;                                                \
+         }                                                        \
+         break;                                                   \
+      case 4:                                                     \
+         switch (num_src_channels) {                              \
+         case 1:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 1, CONV)  \
+            break;                                                \
+         case 2:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 2, CONV)  \
+            break;                                                \
+         case 3:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 3, CONV)  \
+            break;                                                \
+         case 4:                                                  \
+            SWIZZLE_CONVERT_LOOP(DST_TYPE, 4, SRC_TYPE, 4, CONV)  \
+            break;                                                \
+         }                                                        \
+         break;                                                   \
+      }                                                           \
+   } 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.
+ *
+ * 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.  If swizzle[i] < 4 then it
+ * means that dst[i] = CONVERT(src[swizzle[i]]).  If swizzle[i] is
+ * MESA_FORMAT_SWIZZLE_ZERO or MESA_FORMAT_SWIZZLE_ONE, the corresponding
+ * dst[i] will be filled with the appropreate representation of zero or one
+ * respectively.
+ *
+ * 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.
+ *
+ * \param[out] dst               pointer to where the converted data should
+ *                               be stored
+ *
+ * \param[in]  dst_type          the destination GL type of the converted
+ *                               data (GL_BYTE, etc.)
+ *
+ * \param[in]  num_dst_channels  the number of channels in the converted
+ *                               data
+ *
+ * \param[in]  src               pointer to the source data
+ *
+ * \param[in]  src_type          the GL type of the source data (GL_BYTE,
+ *                               etc.)
+ *
+ * \param[in]  num_src_channels  the number of channels in the source data
+ *                               (the number of channels total, not just
+ *                               the number used)
+ *
+ * \param[in]  swizzle           describes how to get the destination data
+ *                               from the source data.
+ *
+ * \param[in]  normalized        for integer types, this indicates whether
+ *                               the data should be considered as integers
+ *                               or as normalized integers;
+ *
+ * \param[in]  count             the number of pixels to convert
+ */
+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(float, float, src)
+         break;
+      case GL_HALF_FLOAT:
+         SWIZZLE_CONVERT(float, uint16_t, _mesa_half_to_float(src))
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, uint8_t, unorm_to_float(src, 8))
+         } else {
+            SWIZZLE_CONVERT(float, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, int8_t, snorm_to_float(src, 8))
+         } else {
+            SWIZZLE_CONVERT(float, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, uint16_t, unorm_to_float(src, 16))
+         } else {
+            SWIZZLE_CONVERT(float, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, int16_t, snorm_to_float(src, 16))
+         } else {
+            SWIZZLE_CONVERT(float, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, uint32_t, unorm_to_float(src, 32))
+         } else {
+            SWIZZLE_CONVERT(float, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(float, int32_t, snorm_to_float(src, 32))
+         } else {
+            SWIZZLE_CONVERT(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(uint16_t, float, _mesa_float_to_half(src))
+         break;
+      case GL_HALF_FLOAT:
+         SWIZZLE_CONVERT(uint16_t, uint16_t, src)
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint8_t, unorm_to_half(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint8_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int8_t, snorm_to_half(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, int8_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, unorm_to_half(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int16_t, snorm_to_half(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, int16_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint32_t, unorm_to_half(src, 32))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint32_t, _mesa_float_to_half(src))
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int32_t, snorm_to_half(src, 32))
+         } else {
+            SWIZZLE_CONVERT(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(uint8_t, float, float_to_unorm(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, half_to_unorm(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, half_to_uint(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         SWIZZLE_CONVERT(uint8_t, uint8_t, src)
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, int8_t, snorm_to_unorm(src, 8, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, unorm_to_unorm(src, 16, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, int16_t, snorm_to_unorm(src, 16, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, uint32_t, unorm_to_unorm(src, 32, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, int32_t, snorm_to_unorm(src, 32, 8))
+         } else {
+            SWIZZLE_CONVERT(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(uint8_t, float, float_to_snorm(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, half_to_snorm(src, 8))
+         } else {
+            SWIZZLE_CONVERT(uint8_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(int8_t, uint8_t, unorm_to_snorm(src, 8, 8))
+         } else {
+            SWIZZLE_CONVERT(int8_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         SWIZZLE_CONVERT(int8_t, int8_t, src)
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int8_t, uint16_t, unorm_to_snorm(src, 16, 8))
+         } else {
+            SWIZZLE_CONVERT(int8_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int8_t, int16_t, snorm_to_snorm(src, 16, 8))
+         } else {
+            SWIZZLE_CONVERT(int8_t, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int8_t, uint32_t, unorm_to_snorm(src, 32, 8))
+         } else {
+            SWIZZLE_CONVERT(int8_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int8_t, int32_t, snorm_to_snorm(src, 32, 8))
+         } else {
+            SWIZZLE_CONVERT(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(uint16_t, float, float_to_unorm(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, half_to_unorm(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, half_to_uint(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint8_t, unorm_to_unorm(src, 8, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int8_t, snorm_to_unorm(src, 8, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         SWIZZLE_CONVERT(uint16_t, uint16_t, src)
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int16_t, snorm_to_unorm(src, 16, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint32_t, unorm_to_unorm(src, 32, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, int32_t, snorm_to_unorm(src, 32, 16))
+         } else {
+            SWIZZLE_CONVERT(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(uint16_t, float, float_to_snorm(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, half_to_snorm(src, 16))
+         } else {
+            SWIZZLE_CONVERT(uint16_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(int16_t, uint8_t, unorm_to_snorm(src, 8, 16))
+         } else {
+            SWIZZLE_CONVERT(int16_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(int16_t, int8_t, snorm_to_snorm(src, 8, 16))
+         } else {
+            SWIZZLE_CONVERT(int16_t, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int16_t, uint16_t, unorm_to_snorm(src, 16, 16))
+         } else {
+            SWIZZLE_CONVERT(int16_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         SWIZZLE_CONVERT(int16_t, int16_t, src)
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int16_t, uint32_t, unorm_to_snorm(src, 32, 16))
+         } else {
+            SWIZZLE_CONVERT(int16_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int16_t, int32_t, snorm_to_snorm(src, 32, 16))
+         } else {
+            SWIZZLE_CONVERT(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(uint32_t, float, float_to_unorm(src, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, float, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, half_to_unorm(src, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, half_to_uint(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, uint8_t, unorm_to_unorm(src, 8, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, int8_t, snorm_to_unorm(src, 8, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, int8_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, unorm_to_unorm(src, 16, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, int16_t, snorm_to_unorm(src, 16, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, int16_t, (src < 0) ? 0 : src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         SWIZZLE_CONVERT(uint32_t, uint32_t, src)
+         break;
+      case GL_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, int32_t, snorm_to_unorm(src, 32, 32))
+         } else {
+            SWIZZLE_CONVERT(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(uint32_t, float, float_to_snorm(src, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, float, src)
+         }
+         break;
+      case GL_HALF_FLOAT:
+         if (normalized) {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, half_to_snorm(src, 32))
+         } else {
+            SWIZZLE_CONVERT(uint32_t, uint16_t, _mesa_half_to_float(src))
+         }
+         break;
+      case GL_UNSIGNED_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(int32_t, uint8_t, unorm_to_snorm(src, 8, 32))
+         } else {
+            SWIZZLE_CONVERT(int32_t, uint8_t, src)
+         }
+         break;
+      case GL_BYTE:
+         if (normalized) {
+            SWIZZLE_CONVERT(int32_t, int8_t, snorm_to_snorm(src, 8, 32))
+         } else {
+            SWIZZLE_CONVERT(int32_t, int8_t, src)
+         }
+         break;
+      case GL_UNSIGNED_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int32_t, uint16_t, unorm_to_snorm(src, 16, 32))
+         } else {
+            SWIZZLE_CONVERT(int32_t, uint16_t, src)
+         }
+         break;
+      case GL_SHORT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int32_t, int16_t, snorm_to_snorm(src, 16, 32))
+         } else {
+            SWIZZLE_CONVERT(int32_t, int16_t, src)
+         }
+         break;
+      case GL_UNSIGNED_INT:
+         if (normalized) {
+            SWIZZLE_CONVERT(int32_t, uint32_t, unorm_to_snorm(src, 32, 32))
+         } else {
+            SWIZZLE_CONVERT(int32_t, uint32_t, src)
+         }
+         break;
+      case GL_INT:
+         SWIZZLE_CONVERT(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
new file mode 100644
index 0000000..11546aa
--- /dev/null
+++ b/src/mesa/main/format_utils.h
@@ -0,0 +1,41 @@
+/**
+ * \file format_utils.h
+ * A collection of format conversion utility functions.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006  Brian Paul  All Rights Reserved.
+ * Copyright (C) 2014  Intel Corporation  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef FORMAT_UTILS_H
+#define FORMAT_UTILS_H
+
+#include "imports.h"
+
+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




More information about the mesa-commit mailing list