mesa/texstore: Use _mesa_swizzle_and_convert when possible
authorJason Ekstrand <jason.ekstrand@intel.com>
Fri, 11 Jul 2014 15:55:47 +0000 (08:55 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 5 Aug 2014 17:56:17 +0000 (10:56 -0700)
This should be both faster and more accurate than our general slow-path of
converting everything to float.

v2: Add a comment to top of the texstore_swizzle function

Signed-off-by: Jason Ekstrand <jason.ekstrand@intel.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
src/mesa/main/texstore.c

index d70497668b2cd753ca5f75fdb88fd59e1b8bee32..c30ef1f74a2de066f5858746c9ac685919abe410 100644 (file)
@@ -55,6 +55,7 @@
 #include "bufferobj.h"
 #include "colormac.h"
 #include "format_pack.h"
+#include "format_utils.h"
 #include "image.h"
 #include "macros.h"
 #include "mipmap.h"
@@ -233,21 +234,44 @@ static int
 get_map_idx(GLenum value)
 {
    switch (value) {
-   case GL_LUMINANCE: return IDX_LUMINANCE;
-   case GL_ALPHA: return IDX_ALPHA;
-   case GL_INTENSITY: return IDX_INTENSITY;
-   case GL_LUMINANCE_ALPHA: return IDX_LUMINANCE_ALPHA;
-   case GL_RGB: return IDX_RGB;
-   case GL_RGBA: return IDX_RGBA;
-   case GL_RED: return IDX_RED;
-   case GL_GREEN: return IDX_GREEN;
-   case GL_BLUE: return IDX_BLUE;
-   case GL_BGR: return IDX_BGR;
-   case GL_BGRA: return IDX_BGRA;
-   case GL_ABGR_EXT: return IDX_ABGR;
-   case GL_RG: return IDX_RG;
+   case GL_LUMINANCE:
+   case GL_LUMINANCE_INTEGER_EXT:
+      return IDX_LUMINANCE;
+   case GL_ALPHA:
+   case GL_ALPHA_INTEGER:
+      return IDX_ALPHA;
+   case GL_INTENSITY:
+      return IDX_INTENSITY;
+   case GL_LUMINANCE_ALPHA:
+   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
+      return IDX_LUMINANCE_ALPHA;
+   case GL_RGB:
+   case GL_RGB_INTEGER:
+      return IDX_RGB;
+   case GL_RGBA:
+   case GL_RGBA_INTEGER:
+      return IDX_RGBA;
+   case GL_RED:
+   case GL_RED_INTEGER:
+      return IDX_RED;
+   case GL_GREEN:
+      return IDX_GREEN;
+   case GL_BLUE:
+      return IDX_BLUE;
+   case GL_BGR:
+   case GL_BGR_INTEGER:
+      return IDX_BGR;
+   case GL_BGRA:
+   case GL_BGRA_INTEGER:
+      return IDX_BGRA;
+   case GL_ABGR_EXT:
+      return IDX_ABGR;
+   case GL_RG:
+   case GL_RG_INTEGER:
+      return IDX_RG;
    default:
-      _mesa_problem(NULL, "Unexpected inFormat");
+      _mesa_problem(NULL, "Unexpected inFormat %s",
+                    _mesa_lookup_enum_by_nr(value));
       return 0;
    }
 }   
@@ -789,6 +813,7 @@ swizzle_copy(GLubyte *dst, GLuint dstComponents, const GLubyte *src,
 
 static const GLubyte map_identity[6] = { 0, 1, 2, 3, ZERO, ONE };
 static const GLubyte map_3210[6] = { 3, 2, 1, 0, ZERO, ONE };
+static const GLubyte map_1032[6] = { 1, 0, 3, 2, ZERO, ONE };
 
 
 /**
@@ -826,6 +851,12 @@ byteswap_mapping( GLboolean swapBytes,
    switch (srcType) {
    case GL_BYTE:
    case GL_UNSIGNED_BYTE:
+   case GL_SHORT:
+   case GL_UNSIGNED_SHORT:
+   case GL_INT:
+   case GL_UNSIGNED_INT:
+   case GL_FLOAT:
+   case GL_HALF_FLOAT:
       return map_identity;
    case GL_UNSIGNED_INT_8_8_8_8:
    case GL_UNSIGNED_INT_8_8_8_8_REV:
@@ -3621,6 +3652,124 @@ texstore_compressed(TEXSTORE_PARAMS)
                            srcFormat, srcType, srcAddr, srcPacking);
 }
 
+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;
+}
+
+/** Store a texture by per-channel conversions and swizzling.
+ *
+ * This function attempts to perform a texstore operation by doing simple
+ * per-channel conversions and swizzling.  This covers a huge chunk of the
+ * texture storage operations that anyone cares about.  If this function is
+ * incapable of performing the operation, it bails and returns GL_FALSE.
+ */
+static GLboolean
+texstore_swizzle(TEXSTORE_PARAMS)
+{
+   const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth,
+                                                     srcFormat, srcType);
+   const GLint srcImageStride = _mesa_image_image_stride(srcPacking,
+                                      srcWidth, srcHeight, srcFormat, srcType);
+   const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dims,
+        srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0);
+   const int src_components = _mesa_components_in_format(srcFormat);
+
+   GLubyte swizzle[4], rgba2base[6], base2src[6], rgba2dst[4], dst2rgba[4];
+   const GLubyte *swap;
+   GLenum dst_type;
+   int dst_components;
+   bool is_array, normalized, need_swap;
+   GLint i, img, row;
+   const GLubyte *src_row;
+   GLubyte *dst_row;
+
+   is_array = _mesa_format_to_array(dstFormat, &dst_type, &dst_components,
+                                    rgba2dst, &normalized);
+
+   if (!is_array)
+      return GL_FALSE;
+
+   switch (srcType) {
+   case GL_FLOAT:
+   case GL_UNSIGNED_BYTE:
+   case GL_BYTE:
+   case GL_UNSIGNED_SHORT:
+   case GL_SHORT:
+   case GL_UNSIGNED_INT:
+   case GL_INT:
+      /* If wa have to swap bytes in a multi-byte datatype, that means
+       * we're not doing an array conversion anymore */
+      if (srcPacking->SwapBytes)
+         return GL_FALSE;
+      need_swap = false;
+      break;
+   case GL_UNSIGNED_INT_8_8_8_8:
+      need_swap = srcPacking->SwapBytes;
+      if (_mesa_little_endian())
+         need_swap = !need_swap;
+      srcType = GL_UNSIGNED_BYTE;
+      break;
+   case GL_UNSIGNED_INT_8_8_8_8_REV:
+      need_swap = srcPacking->SwapBytes;
+      if (!_mesa_little_endian())
+         need_swap = !need_swap;
+      srcType = GL_UNSIGNED_BYTE;
+      break;
+   default:
+      return GL_FALSE;
+   }
+   swap = need_swap ? map_3210 : map_identity;
+
+   compute_component_mapping(srcFormat, baseInternalFormat, base2src);
+   compute_component_mapping(baseInternalFormat, GL_RGBA, rgba2base);
+   invert_swizzle(dst2rgba, rgba2dst);
+
+   for (i = 0; i < 4; i++) {
+      if (dst2rgba[i] == MESA_FORMAT_SWIZZLE_NONE)
+         swizzle[i] = MESA_FORMAT_SWIZZLE_NONE;
+      else
+         swizzle[i] = swap[base2src[rgba2base[dst2rgba[i]]]];
+   }
+
+   /* Is it normalized? */
+   normalized |= !_mesa_is_enum_format_integer(srcFormat);
+
+   for (img = 0; img < srcDepth; img++) {
+      if (dstRowStride == srcWidth * dst_components &&
+          srcRowStride == srcWidth * src_components) {
+         _mesa_swizzle_and_convert(dstSlices[img], dst_type, dst_components,
+                                   srcImage, srcType, src_components,
+                                   swizzle, normalized, srcWidth * srcHeight);
+      } else {
+         src_row = srcImage;
+         dst_row = dstSlices[img];
+         for (row = 0; row < srcHeight; row++) {
+            _mesa_swizzle_and_convert(dst_row, dst_type, dst_components,
+                                      src_row, srcType, src_components,
+                                      swizzle, normalized, srcWidth);
+            dst_row += dstRowStride;
+            src_row += srcRowStride;
+         }
+      }
+      srcImage += srcImageStride;
+   }
+
+   return GL_TRUE;
+}
+
+
 static GLboolean
 texstore_rgba(TEXSTORE_PARAMS)
 {
@@ -3796,6 +3945,14 @@ texstore_rgba(TEXSTORE_PARAMS)
       initialized = GL_TRUE;
    }
 
+   if (texstore_swizzle(ctx, dims, baseInternalFormat,
+                        dstFormat,
+                        dstRowStride, dstSlices,
+                        srcWidth, srcHeight, srcDepth,
+                        srcFormat, srcType, srcAddr, srcPacking)) {
+      return GL_TRUE;
+   }
+
    ASSERT(table[dstFormat]);
    return table[dstFormat](ctx, dims, baseInternalFormat,
                            dstFormat, dstRowStride, dstSlices,
@@ -3888,7 +4045,6 @@ _mesa_texstore_memcpy(TEXSTORE_PARAMS)
    return GL_TRUE;
 }
 
-
 /**
  * Store user data into texture memory.
  * Called via glTex[Sub]Image1/2/3D()