[Mesa-dev] [PATCH 05/29] mesa: Consider internal base format in _mesa_format_convert

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


Add a dst_internal_format parameter to _mesa_format_convert, that represents
the base internal format for texture/pixel uploads, so we can do the right
thing when the driver has selected a different internal format for the target
dst format.
---
 src/mesa/main/format_utils.c | 65 +++++++++++++++++++++++++++++++++++++++++++-
 src/mesa/main/format_utils.h |  2 +-
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c
index fc59e86..5964689 100644
--- a/src/mesa/main/format_utils.c
+++ b/src/mesa/main/format_utils.c
@@ -303,7 +303,7 @@ _mesa_compute_component_mapping(GLenum inFormat, GLenum outFormat, GLubyte *map)
 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, GLenum dst_internal_format)
 {
    uint8_t *dst = (uint8_t *)void_dst;
    uint8_t *src = (uint8_t *)void_src;
@@ -422,6 +422,36 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
    if (src_array_format.as_uint && dst_array_format.as_uint) {
       assert(src_array_format.normalized == dst_array_format.normalized);
 
+      /* If the base format of our dst is not the same as the provided base
+       * format it means that we are converting to a different format
+       * than the one originally requested by the client. This can happen when
+       * the internal base format requested is not supported by the driver.
+       * In this case we need to consider the requested internal base format to
+       * compute the correct swizzle operation from src to dst. We will do this
+       * by computing the swizzle transform src->rgba->base->rgba->dst instead
+       * of src->rgba->dst.
+       */
+      mesa_format dst_mesa_format;
+      if (dst_format & MESA_ARRAY_FORMAT_BIT)
+         dst_mesa_format = _mesa_format_from_array_format(dst_format);
+      else
+         dst_mesa_format = dst_format;
+      if (dst_internal_format != _mesa_get_format_base_format(dst_mesa_format)) {
+         /* Compute src2rgba as src->rgba->base->rgba */
+         uint8_t rgba2base[4], base2rgba[4], swizzle[4];
+         _mesa_compute_component_mapping(GL_RGBA, dst_internal_format, rgba2base);
+         _mesa_compute_component_mapping(dst_internal_format, GL_RGBA, base2rgba);
+
+         for (i = 0; i < 4; i++) {
+            if (base2rgba[i] > MESA_FORMAT_SWIZZLE_W)
+               swizzle[i] = base2rgba[i];
+            else
+               swizzle[i] = src2rgba[rgba2base[base2rgba[i]]];
+         }
+         memcpy(src2rgba, swizzle, sizeof(src2rgba));
+      }
+
+      /* Compute src2dst from src2rgba */
       for (i = 0; i < 4; i++) {
          if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) {
             src2dst[i] = rgba2dst[i];
@@ -539,9 +569,42 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride,
             src += src_stride;
          }
       } else {
+         /* For some conversions, doing src->rgba->dst is not enough and we
+          * need to consider the base internal format. In these cases a
+          * swizzle operation is required to match the semantics of the base
+          * internal format requested: src->rgba->swizzle->rgba->dst.
+          *
+          * We can detect these cases by checking if the swizzle transform
+          * for base->rgba->base is 0123. If it is not, then we need
+          * to do the swizzle operation (need_convert = true).
+          */
+         GLubyte rgba2base[4], base2rgba[4], map[4];
+         bool need_convert = false;
+         mesa_format dst_mesa_format;
+         if (dst_format & MESA_ARRAY_FORMAT_BIT)
+            dst_mesa_format = _mesa_format_from_array_format(dst_format);
+         else
+            dst_mesa_format = dst_format;
+         if (dst_internal_format !=
+             _mesa_get_format_base_format(dst_mesa_format)) {
+            _mesa_compute_component_mapping(GL_RGBA, dst_internal_format,
+                                            base2rgba);
+            _mesa_compute_component_mapping(dst_internal_format, GL_RGBA,
+                                            rgba2base);
+            for (i = 0; i < 4; ++i) {
+               map[i] = base2rgba[rgba2base[i]];
+               if (map[i] != i)
+                  need_convert = true;
+            }
+         }
+
          for (row = 0; row < height; ++row) {
             _mesa_unpack_rgba_row(src_format, width,
                                   src, tmp_float + row * width);
+            if (need_convert)
+               _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4,
+                                         tmp_float + row * width, GL_FLOAT, 4,
+                                         map, false, width);
             src += src_stride;
          }
       }
diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h
index 4237ad3..29ab4a0 100644
--- a/src/mesa/main/format_utils.h
+++ b/src/mesa/main/format_utils.h
@@ -158,6 +158,6 @@ _mesa_compute_component_mapping(GLenum inFormat, GLenum outFormat, GLubyte *map)
 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, GLenum dst_internal_format);
 
 #endif
-- 
1.9.1



More information about the mesa-dev mailing list