[Mesa-dev] [PATCH 01/29] mesa: Add an implementation of a master convert function.

Iago Toral Quiroga itoral at igalia.com
Tue Nov 18 01:23:42 PST 2014


From: Jason Ekstrand <jason.ekstrand at intel.com>

v2 by Iago Toral <itoral at igalia.com>:

- When testing if we can directly pack we should use the src format to check
  if we are packing from an RGBA format. The original code used the dst format
  for the ubyte case by mistake.
- Fixed incorrect number of bits for dst, it was computed using the src format
  instead of the dst format.
- If the dst format is an array format, check if it is signed. We were only
  checking this for the case where it was not an array format, but we need
  to know this in both scenarios.
- Fixed incorrect swizzle transform for the cases where we convert between
  array formats.
- Compute is_signed and bits only once and for the dst format. We were
  computing these for the src format too but they were overwritten by the
  dst values immediately after.
- Be more careful when selecting the integer path. Specifically, check that
  both src and dst are integer types. Checking only one of them should suffice
  since OpenGL does not allow conversions between normalized and integer types,
  but putting extra care here makes sense and also makes the actual requirements
  for this path more clear.
- The format argument for pack functions is the destination format we are
  packing to, not the source format (which has to be RGBA).
- Expose RGBA8888_* to other files. These will come in handy when in need to
  test if a given array format is RGBA or in need to pass RGBA formats to
  mesa_format_convert.

v3 by Samuel Iglesias <siglesias at igalia.com>:

- Add an RGBA8888_INT definition.
---
 src/mesa/main/format_utils.c | 378 +++++++++++++++++++++++++++++++++++++++++++
 src/mesa/main/format_utils.h |  10 ++
 src/mesa/main/formats.h      |  15 +-
 3 files changed, 399 insertions(+), 4 deletions(-)

diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c
index fcbbba4..c3815cb 100644
--- a/src/mesa/main/format_utils.c
+++ b/src/mesa/main/format_utils.c
@@ -25,6 +25,384 @@
 #include "format_utils.h"
 #include "glformats.h"
 #include "macros.h"
+#include "format_pack.h"
+#include "format_unpack.h"
+
+mesa_array_format RGBA8888_FLOAT = {{
+   MESA_ARRAY_FORMAT_TYPE_FLOAT,
+   0,
+   4,
+   0, 1, 2, 3,
+   0, 1
+}};
+
+mesa_array_format RGBA8888_UBYTE = {{
+   MESA_ARRAY_FORMAT_TYPE_UBYTE,
+   1,
+   4,
+   0, 1, 2, 3,
+   0, 1
+}};
+
+mesa_array_format RGBA8888_UINT = {{
+   MESA_ARRAY_FORMAT_TYPE_UINT,
+   0,
+   4,
+   0, 1, 2, 3,
+   0, 1
+}};
+
+mesa_array_format RGBA8888_INT = {{
+   MESA_ARRAY_FORMAT_TYPE_INT,
+   0,
+   4,
+   0, 1, 2, 3,
+   0, 1
+}};
+
+static void
+invert_swizzle(uint8_t dst[4], const uint8_t src[4])
+{
+   int i, j;
+
+   dst[0] = MESA_FORMAT_SWIZZLE_NONE;
+   dst[1] = MESA_FORMAT_SWIZZLE_NONE;
+   dst[2] = MESA_FORMAT_SWIZZLE_NONE;
+   dst[3] = MESA_FORMAT_SWIZZLE_NONE;
+
+   for (i = 0; i < 4; ++i)
+      for (j = 0; j < 4; ++j)
+         if (src[j] == i && dst[i] == MESA_FORMAT_SWIZZLE_NONE)
+            dst[i] = j;
+}
+
+static GLenum
+gl_type_for_array_format_datatype(enum mesa_array_format_datatype type)
+{
+   switch (type) {
+   case MESA_ARRAY_FORMAT_TYPE_UBYTE:
+      return GL_UNSIGNED_BYTE;
+   case MESA_ARRAY_FORMAT_TYPE_USHORT:
+      return GL_UNSIGNED_SHORT;
+   case MESA_ARRAY_FORMAT_TYPE_UINT:
+      return GL_UNSIGNED_INT;
+   case MESA_ARRAY_FORMAT_TYPE_BYTE:
+      return GL_BYTE;
+   case MESA_ARRAY_FORMAT_TYPE_SHORT:
+      return GL_SHORT;
+   case MESA_ARRAY_FORMAT_TYPE_INT:
+      return GL_INT;
+   case MESA_ARRAY_FORMAT_TYPE_HALF:
+      return GL_HALF_FLOAT;
+   case MESA_ARRAY_FORMAT_TYPE_FLOAT:
+      return GL_FLOAT;
+   default:
+      assert(!"Invalid datatype");
+      return GL_NONE;
+   }
+}
+
+void
+_mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
+                     void *void_src, uint32_t src_format, size_t src_stride,
+                     size_t width, size_t height)
+{
+   uint8_t *dst = (uint8_t *)void_dst;
+   uint8_t *src = (uint8_t *)void_src;
+   mesa_array_format src_array_format, dst_array_format;
+   uint8_t src2dst[4], src2rgba[4], rgba2dst[4], dst2rgba[4];
+   GLenum src_gl_type, dst_gl_type, common_gl_type;
+   bool normalized, dst_integer, src_integer, is_signed;
+   uint8_t (*tmp_ubyte)[4];
+   float (*tmp_float)[4];
+   uint32_t (*tmp_uint)[4];
+   int i, bits;
+   size_t row;
+
+   if (src_format & MESA_ARRAY_FORMAT_BIT) {
+      src_array_format.as_uint = src_format;
+   } else {
+      assert(_mesa_is_format_color_format(src_format));
+      src_array_format.as_uint = _mesa_format_to_array_format(src_format);
+   }
+
+   if (dst_format & MESA_ARRAY_FORMAT_BIT) {
+      dst_array_format.as_uint = dst_format;
+   } else {
+      assert(_mesa_is_format_color_format(dst_format));
+      dst_array_format.as_uint = _mesa_format_to_array_format(dst_format);
+   }
+
+   /* Handle the cases where we can directly unpack */
+   if (!(src_format & MESA_ARRAY_FORMAT_BIT)) {
+      if (dst_array_format.as_uint == RGBA8888_FLOAT.as_uint) {
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_rgba_row(src_format, width,
+                                  src, (float (*)[4])dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      } else if (dst_array_format.as_uint == RGBA8888_UBYTE.as_uint) {
+         assert(!_mesa_is_format_integer_color(src_format));
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_ubyte_rgba_row(src_format, width,
+                                        src, (uint8_t (*)[4])dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      } else if (dst_array_format.as_uint == RGBA8888_UINT.as_uint) {
+         assert(_mesa_is_format_integer_color(src_format));
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_uint_rgba_row(src_format, width,
+                                       src, (uint32_t (*)[4])dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      }
+   }
+
+   /* Handle the cases where we can directly pack */
+   if (!(dst_format & MESA_ARRAY_FORMAT_BIT)) {
+      if (src_array_format.as_uint == RGBA8888_FLOAT.as_uint) {
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_float_rgba_row(dst_format, width,
+                                      (const float (*)[4])src, dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      } else if (src_array_format.as_uint == RGBA8888_UBYTE.as_uint) {
+         assert(!_mesa_is_format_integer_color(dst_format));
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_ubyte_rgba_row(dst_format, width,
+                                      (const uint8_t (*)[4])src, dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      } else if (src_array_format.as_uint == RGBA8888_UINT.as_uint) {
+         assert(_mesa_is_format_integer_color(dst_format));
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_uint_rgba_row(dst_format, width,
+                                     (const uint32_t (*)[4])src, dst);
+            src += src_stride;
+            dst += dst_stride;
+         }
+         return;
+      }
+   }
+
+   /* Handle conversions between array formats */
+   normalized = false;
+   if (src_array_format.as_uint) {
+      src_gl_type = gl_type_for_array_format_datatype(src_array_format.type);
+
+      src2rgba[0] = src_array_format.swizzle_x;
+      src2rgba[1] = src_array_format.swizzle_y;
+      src2rgba[2] = src_array_format.swizzle_z;
+      src2rgba[3] = src_array_format.swizzle_w;
+
+      normalized = src_array_format.normalized;
+   }
+
+   if (dst_array_format.as_uint) {
+      dst_gl_type = gl_type_for_array_format_datatype(dst_array_format.type);
+
+      dst2rgba[0] = dst_array_format.swizzle_x;
+      dst2rgba[1] = dst_array_format.swizzle_y;
+      dst2rgba[2] = dst_array_format.swizzle_z;
+      dst2rgba[3] = dst_array_format.swizzle_w;
+
+      invert_swizzle(rgba2dst, dst2rgba);
+
+      normalized |= dst_array_format.normalized;
+   }
+
+   if (src_array_format.as_uint && dst_array_format.as_uint) {
+      assert(src_array_format.normalized == dst_array_format.normalized);
+
+      for (i = 0; i < 4; i++) {
+         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
+            src2dst[i] = rgba2dst[i];
+         } else {
+            src2dst[i] = src2rgba[rgba2dst[i]];
+         }
+      }
+
+      for (row = 0; row < height; ++row) {
+         _mesa_swizzle_and_convert(dst, dst_gl_type, dst_array_format.num_channels,
+                                   src, src_gl_type, src_array_format.num_channels,
+                                   src2dst, normalized, width);
+         src += src_stride;
+         dst += dst_stride;
+      }
+      return;
+   }
+
+   /* At this point, we're fresh out of fast-paths and we need to convert
+    * to float, uint32, or, if we're lucky, uint8.
+    */
+   dst_integer = false;
+   src_integer = false;
+
+   if (src_array_format.array_format_bit) {
+      if (!(src_array_format.type & MESA_ARRAY_FORMAT_TYPE_IS_FLOAT) &&
+          !src_array_format.normalized)
+         src_integer = true;
+   } else {
+      switch (_mesa_get_format_datatype(src_format)) {
+      case GL_UNSIGNED_INT:
+      case GL_INT:
+         src_integer = true;
+         break;
+      }
+   }
+
+   if (dst_array_format.array_format_bit) {
+      if (!(dst_array_format.type & MESA_ARRAY_FORMAT_TYPE_IS_FLOAT) &&
+          !dst_array_format.normalized)
+         dst_integer = true;
+      is_signed = dst_array_format.as_uint & MESA_ARRAY_FORMAT_TYPE_IS_SIGNED;
+      bits = 8 * _mesa_array_format_datatype_size(dst_array_format.type);
+   } else {
+      switch (_mesa_get_format_datatype(dst_format)) {
+      case GL_UNSIGNED_NORMALIZED:
+         is_signed = false;
+         break;
+      case GL_SIGNED_NORMALIZED:
+         is_signed = true;
+         break;
+      case GL_FLOAT:
+         is_signed = true;
+         break;
+      case GL_UNSIGNED_INT:
+         is_signed = false;
+         dst_integer = true;
+         break;
+      case GL_INT:
+         is_signed = true;
+         dst_integer = true;
+         break;
+      }
+      bits = _mesa_get_format_max_bits(dst_format);
+   }
+
+   assert((src_integer && dst_integer) || (!src_integer && !dst_integer));
+
+   if (src_integer && dst_integer) {
+      tmp_uint = malloc(width * height * sizeof(*tmp_uint));
+      common_gl_type = is_signed ? GL_INT : GL_UNSIGNED_INT;
+
+      if (src_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(tmp_uint + row * width, common_gl_type, 4,
+                                      src, src_gl_type,
+                                      src_array_format.num_channels,
+                                      src2rgba, normalized, width);
+            src += src_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_uint_rgba_row(src_format, width,
+                                       src, tmp_uint + row * width);
+            src += src_stride;
+         }
+      }
+
+      if (dst_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(dst, dst_gl_type,
+                                      dst_array_format.num_channels,
+                                      tmp_uint + row * width, common_gl_type, 4,
+                                      rgba2dst, normalized, width);
+            dst += dst_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_uint_rgba_row(dst_format, width,
+                                     (const uint32_t (*)[4])tmp_uint + row * width, dst);
+            dst += dst_stride;
+         }
+      }
+
+      free(tmp_uint);
+   } else if (is_signed || bits > 8) {
+      tmp_float = malloc(width * height * sizeof(*tmp_float));
+
+      if (src_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4,
+                                      src, src_gl_type,
+                                      src_array_format.num_channels,
+                                      src2rgba, normalized, width);
+            src += src_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_rgba_row(src_format, width,
+                                  src, tmp_float + row * width);
+            src += src_stride;
+         }
+      }
+
+      if (dst_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(dst, dst_gl_type,
+                                      dst_array_format.num_channels,
+                                      tmp_float + row * width, GL_FLOAT, 4,
+                                      rgba2dst, normalized, width);
+            dst += dst_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_float_rgba_row(dst_format, width,
+                                      (const float (*)[4])tmp_float + row * width, dst);
+            dst += dst_stride;
+         }
+      }
+
+      free(tmp_float);
+   } else {
+      tmp_ubyte = malloc(width * height * sizeof(*tmp_ubyte));
+
+      if (src_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4,
+                                      src, src_gl_type,
+                                      src_array_format.num_channels,
+                                      src2rgba, normalized, width);
+            src += src_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_unpack_ubyte_rgba_row(src_format, width,
+                                        src, tmp_ubyte + row * width);
+            src += src_stride;
+         }
+      }
+
+      if (dst_format & MESA_ARRAY_FORMAT_BIT) {
+         for (row = 0; row < height; ++row) {
+            _mesa_swizzle_and_convert(dst, dst_gl_type,
+                                      dst_array_format.num_channels,
+                                      tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4,
+                                      rgba2dst, normalized, width);
+            dst += dst_stride;
+         }
+      } else {
+         for (row = 0; row < height; ++row) {
+            _mesa_pack_ubyte_rgba_row(dst_format, width,
+                                      (const uint8_t (*)[4])tmp_ubyte + row * width, dst);
+            dst += dst_stride;
+         }
+      }
+
+      free(tmp_ubyte);
+   }
+}
 
 static const uint8_t map_identity[7] = { 0, 1, 2, 3, 4, 5, 6 };
 static const uint8_t map_3210[7] = { 3, 2, 1, 0, 4, 5, 6 };
diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h
index 010d137..4d348cc 100644
--- a/src/mesa/main/format_utils.h
+++ b/src/mesa/main/format_utils.h
@@ -33,6 +33,11 @@
 
 #include "imports.h"
 
+extern mesa_array_format RGBA8888_FLOAT;
+extern mesa_array_format RGBA8888_UBYTE;
+extern mesa_array_format RGBA8888_UINT;
+extern mesa_array_format RGBA8888_INT;
+
 /* 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))
@@ -147,4 +152,9 @@ _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);
 
+void
+_mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
+                     void *void_src, uint32_t src_format, size_t src_stride,
+                     size_t width, size_t height);
+
 #endif
diff --git a/src/mesa/main/formats.h b/src/mesa/main/formats.h
index bba5bae..7a792d4 100644
--- a/src/mesa/main/formats.h
+++ b/src/mesa/main/formats.h
@@ -81,7 +81,7 @@ enum {
    MESA_FORMAT_SWIZZLE_NONE = 6,
 };
 
-enum  mesa_array_format_datatype {
+enum mesa_array_format_datatype {
    MESA_ARRAY_FORMAT_TYPE_UBYTE = 0x0,
    MESA_ARRAY_FORMAT_TYPE_USHORT = 0x1,
    MESA_ARRAY_FORMAT_TYPE_UINT = 0x2,
@@ -90,11 +90,12 @@ enum  mesa_array_format_datatype {
    MESA_ARRAY_FORMAT_TYPE_INT = 0x6,
    MESA_ARRAY_FORMAT_TYPE_HALF = 0xd,
    MESA_ARRAY_FORMAT_TYPE_FLOAT = 0xe,
-
-   MESA_ARRAY_FORMAT_TYPE_IS_SIGNED = 0x4,
-   MESA_ARRAY_FORMAT_TYPE_IS_FLOAT = 0x8,
 };
 
+#define MESA_ARRAY_FORMAT_TYPE_IS_SIGNED 0x4
+#define MESA_ARRAY_FORMAT_TYPE_IS_FLOAT 0x8
+#define MESA_ARRAY_FORMAT_BIT 0x80000000
+
 typedef union {
    struct {
       enum mesa_array_format_datatype type:4;
@@ -130,6 +131,12 @@ _mesa_ilog2(unsigned x)
    (((SIGNED)    << 2 ) & MESA_ARRAY_FORMAT_TYPE_IS_SIGNED) |      \
    (((IS_FLOAT)  << 3 ) & MESA_ARRAY_FORMAT_TYPE_IS_FLOAT)
 
+static inline int
+_mesa_array_format_datatype_size(enum mesa_array_format_datatype type)
+{
+   return 1 << (type & 0x3);
+}
+
 /**
  * Mesa texture/renderbuffer image formats.
  */
-- 
1.9.1



More information about the mesa-dev mailing list