mesa: Add a rebase_swizzle parameter to _mesa_format_convert
authorIago Toral Quiroga <itoral@igalia.com>
Wed, 26 Nov 2014 08:05:08 +0000 (09:05 +0100)
committerIago Toral Quiroga <itoral@igalia.com>
Mon, 12 Jan 2015 10:20:28 +0000 (11:20 +0100)
The new parameter allows callers to provide a rebase swizzle that
the function needs to use to match the requirements of the base
internal format involved. This is necessary when the source or
destination internal formats (depending on whether we are doing
the conversion for a pixel download or a pixel upload respectively)
do not match the base formats of the source or destination
formats of the conversion. This can happen when the driver does not
support the internal formats and uses a different format to store
pixel data internally.

For example, a texture upload from RGB to Luminance in a driver
that does not support textures with a Luminance format may decide
to store the Luminance data as RGBA. In this case we want to store
the RGBA values as (R,R,R,1). Following the same example, when we
download from that texture to RGBA we want to read (R,0,0,1). The
rebase_swizzle parameter allows these transforms to happen.

Reviewed-by: Jason Ekstrand <jason.ekstrand@intel.com>
src/mesa/main/format_utils.c
src/mesa/main/format_utils.h

index 6467307c653cba5397990d19dba3fe4d172fe7cf..2cbe80e77eb89283e24eccc7032356743e9c193c 100644 (file)
@@ -81,6 +81,75 @@ gl_type_for_array_format_datatype(enum mesa_array_format_datatype type)
    }
 }
 
+/* Takes a src to RGBA swizzle and applies a rebase swizzle to it. This
+ * is used when we need to rebase a format to match a different
+ * base internal format.
+ *
+ * The rebase swizzle can be NULL, which means that no rebase is necessary,
+ * in which case the src to RGBA swizzle is copied to the output without
+ * changes.
+ *
+ * The resulting rebased swizzle and well as the input swizzles are
+ * all 4-element swizzles, but the rebase swizzle can be NULL if no rebase
+ * is necessary.
+ */
+static void
+compute_rebased_rgba_component_mapping(uint8_t *src2rgba,
+                                       uint8_t *rebase_swizzle,
+                                       uint8_t *rebased_src2rgba)
+{
+   int i;
+
+   if (rebase_swizzle) {
+      for (i = 0; i < 4; i++) {
+         if (rebase_swizzle[i] > MESA_FORMAT_SWIZZLE_W)
+            rebased_src2rgba[i] = rebase_swizzle[i];
+         else
+            rebased_src2rgba[i] = src2rgba[rebase_swizzle[i]];
+      }
+   } else {
+      /* No rebase needed, so src2rgba is all that we need */
+      memcpy(rebased_src2rgba, src2rgba, 4 * sizeof(uint8_t));
+   }
+}
+
+/* Computes the final swizzle transform to apply from src to dst in a
+ * conversion that might involve a rebase swizzle.
+ *
+ * This is used to compute the swizzle transform to apply in conversions
+ * between array formats where we have a src2rgba swizzle, a rgba2dst swizzle
+ * and possibly, a rebase swizzle.
+ *
+ * The final swizzle transform to apply (src2dst) when a rebase swizzle is
+ * involved is: src -> rgba -> base -> rgba -> dst
+ */
+static void
+compute_src2dst_component_mapping(uint8_t *src2rgba, uint8_t *rgba2dst,
+                                  uint8_t *rebase_swizzle, uint8_t *src2dst)
+{
+   int i;
+
+   if (!rebase_swizzle) {
+      for (i = 0; i < 4; i++) {
+         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
+            src2dst[i] = rgba2dst[i];
+         } else {
+            src2dst[i] = src2rgba[rgba2dst[i]];
+         }
+      }
+   } else {
+      for (i = 0; i < 4; i++) {
+         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
+            src2dst[i] = rgba2dst[i];
+         } else if (rebase_swizzle[rgba2dst[i]] > MESA_FORMAT_SWIZZLE_W) {
+            src2dst[i] = rebase_swizzle[rgba2dst[i]];
+         } else {
+            src2dst[i] = src2rgba[rebase_swizzle[rgba2dst[i]]];
+         }
+      }
+   }
+}
+
 /**
  * This can be used to convert between most color formats.
  *
@@ -101,24 +170,31 @@ gl_type_for_array_format_datatype(enum mesa_array_format_datatype type)
  * \param src_stride  The stride of the source format in bytes.
  * \param width  The width, in pixels, of the source image to convert.
  * \param height  The height, in pixels, of the source image to convert.
+ * \param rebase_swizzle  A swizzle transform to apply during the conversion,
+ *                        typically used to match a different internal base
+ *                        format involved. NULL if no rebase transform is needed
+ *                        (i.e. the internal base format and the base format of
+ *                        the dst or the src -depending on whether we are doing
+ *                        an upload or a download respectively- are the same).
  */
 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)
+                     size_t width, size_t height, uint8_t *rebase_swizzle)
 {
    uint8_t *dst = (uint8_t *)void_dst;
    uint8_t *src = (uint8_t *)void_src;
    mesa_array_format src_array_format, dst_array_format;
    bool src_format_is_mesa_array_format, dst_format_is_mesa_array_format;
    uint8_t src2dst[4], src2rgba[4], rgba2dst[4], dst2rgba[4];
+   uint8_t rebased_src2rgba[4];
    GLenum src_gl_type, dst_gl_type, common_gl_type;
    bool normalized, dst_integer, src_integer, is_signed;
    int src_num_channels = 0, dst_num_channels = 0;
    uint8_t (*tmp_ubyte)[4];
    float (*tmp_float)[4];
    uint32_t (*tmp_uint)[4];
-   int i, bits;
+   int bits;
    size_t row;
 
    if (_mesa_format_is_mesa_array_format(src_format)) {
@@ -139,67 +215,79 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
       dst_array_format = _mesa_format_to_array_format(dst_format);
    }
 
-   /* Handle the cases where we can directly unpack */
-   if (!src_format_is_mesa_array_format) {
-      if (dst_array_format == RGBA8888_FLOAT) {
-         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 == RGBA8888_UBYTE) {
-         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 == RGBA8888_UINT &&
-                 _mesa_is_format_unsigned(src_format)) {
-         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;
+   /* First we see if we can implement the conversion with a direct pack
+    * or unpack.
+    *
+    * In this case we want to be careful when we need to apply a swizzle to
+    * match an internal base format, since in these cases a simple pack/unpack
+    * to the dst format from the src format may not match the requirements
+    * of the internal base format. For now we decide to be safe and
+    * avoid this path in these scenarios but in the future we may want to
+    * enable it for specific combinations that are known to work.
+    */
+   if (!rebase_swizzle) {
+      /* Handle the cases where we can directly unpack */
+      if (!src_format_is_mesa_array_format) {
+         if (dst_array_format == RGBA8888_FLOAT) {
+            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 == RGBA8888_UBYTE) {
+            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 == RGBA8888_UINT &&
+                    _mesa_is_format_unsigned(src_format)) {
+            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;
          }
-         return;
       }
-   }
 
-   /* Handle the cases where we can directly pack */
-   if (!dst_format_is_mesa_array_format) {
-      if (src_array_format == RGBA8888_FLOAT) {
-         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 == RGBA8888_UBYTE) {
-         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 == RGBA8888_UINT &&
-                 _mesa_is_format_unsigned(dst_format)) {
-         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;
+      /* Handle the cases where we can directly pack */
+      if (!dst_format_is_mesa_array_format) {
+         if (src_array_format == RGBA8888_FLOAT) {
+            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 == RGBA8888_UBYTE) {
+            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 == RGBA8888_UINT &&
+                    _mesa_is_format_unsigned(dst_format)) {
+            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;
          }
-         return;
       }
    }
 
@@ -234,13 +322,8 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
       assert(_mesa_array_format_is_normalized(src_array_format) ==
              _mesa_array_format_is_normalized(dst_array_format));
 
-      for (i = 0; i < 4; i++) {
-         if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
-            src2dst[i] = rgba2dst[i];
-         } else {
-            src2dst[i] = src2rgba[rgba2dst[i]];
-         }
-      }
+      compute_src2dst_component_mapping(src2rgba, rgba2dst, rebase_swizzle,
+                                        src2dst);
 
       for (row = 0; row < height; ++row) {
          _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels,
@@ -328,16 +411,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
        */
       common_gl_type = is_signed ? GL_INT : GL_UNSIGNED_INT;
       if (src_array_format) {
+         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
+                                                rebased_src2rgba);
          for (row = 0; row < height; ++row) {
             _mesa_swizzle_and_convert(tmp_uint + row * width, common_gl_type, 4,
                                       src, src_gl_type, src_num_channels,
-                                      src2rgba, normalized, width);
+                                      rebased_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);
+            if (rebase_swizzle)
+               _mesa_swizzle_and_convert(tmp_uint + row * width, common_gl_type, 4,
+                                         tmp_uint + row * width, common_gl_type, 4,
+                                         rebase_swizzle, false, width);
             src += src_stride;
          }
       }
@@ -366,16 +455,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
       tmp_float = malloc(width * height * sizeof(*tmp_float));
 
       if (src_format_is_mesa_array_format) {
+         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
+                                                rebased_src2rgba);
          for (row = 0; row < height; ++row) {
             _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4,
                                       src, src_gl_type, src_num_channels,
-                                      src2rgba, normalized, width);
+                                      rebased_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);
+            if (rebase_swizzle)
+               _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4,
+                                         tmp_float + row * width, GL_FLOAT, 4,
+                                         rebase_swizzle, false, width);
             src += src_stride;
          }
       }
@@ -400,16 +495,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
       tmp_ubyte = malloc(width * height * sizeof(*tmp_ubyte));
 
       if (src_format_is_mesa_array_format) {
+         compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle,
+                                                rebased_src2rgba);
          for (row = 0; row < height; ++row) {
             _mesa_swizzle_and_convert(tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4,
                                       src, src_gl_type, src_num_channels,
-                                      src2rgba, normalized, width);
+                                      rebased_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);
+            if (rebase_swizzle)
+               _mesa_swizzle_and_convert(tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4,
+                                         tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4,
+                                         rebase_swizzle, false, width);
             src += src_stride;
          }
       }
index f006e18d78523b37b359533ac3cdd32dc39fc796..ae7926e0c7515400b6c14c0da53c7130f32abf02 100644 (file)
@@ -215,6 +215,6 @@ _mesa_swizzle_and_convert(void *dst, GLenum dst_type, int num_dst_channels,
 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);
+                     size_t width, size_t height, uint8_t *rebase_swizzle);
 
 #endif