[Mesa-dev] [PATCH 16/29] mesa: use master conversion function to implement get_tex_rgba_uncompressed()

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


From: Samuel Iglesias Gonsalvez <siglesias at igalia.com>

This covers glGetTexImage for uncompressed color formats.

Signed-off-by: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
Signed-off-by: Eduardo Lima Mitev <elima at igalia.com>
---
 src/mesa/main/texgetimage.c | 170 ++++++++++++++++++++++++++++++--------------
 1 file changed, 117 insertions(+), 53 deletions(-)

diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c
index cb5f793..84cd53e 100644
--- a/src/mesa/main/texgetimage.c
+++ b/src/mesa/main/texgetimage.c
@@ -45,7 +45,8 @@
 #include "texgetimage.h"
 #include "teximage.h"
 #include "texstore.h"
-
+#include "format_utils.h"
+#include "pixeltransfer.h"
 
 
 /**
@@ -380,20 +381,10 @@ get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
    GLenum rebaseFormat = GL_NONE;
    GLuint height = texImage->Height;
    GLuint depth = texImage->Depth;
-   GLuint img, row;
-   GLfloat (*rgba)[4];
-   GLuint (*rgba_uint)[4];
-   GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
-   GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat);
+   GLuint img;
    GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat);
 
-   /* Allocate buffer for one row of texels */
-   rgba = malloc(4 * width * sizeof(GLfloat));
-   rgba_uint = (GLuint (*)[4]) rgba;
-   if (!rgba) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
-      return;
-   }
+   assert (depth <= 1 || dimensions > 2);
 
    if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
       depth = height;
@@ -413,9 +404,7 @@ get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
              texImage->_BaseFormat == GL_RGB ||
              texImage->_BaseFormat == GL_RG) &&
             (destBaseFormat == GL_LUMINANCE ||
-             destBaseFormat == GL_LUMINANCE_ALPHA ||
-             destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
-             destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) {
+             destBaseFormat == GL_LUMINANCE_ALPHA)) {
       /* If we're reading back an RGB(A) texture as luminance then we need
        * to return L=tex(R).  Note, that's different from glReadPixels which
        * returns L=R+G+B.
@@ -467,6 +456,22 @@ get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
       }
    }
 
+   /* Describe the dst format */
+   GLboolean dst_is_integer = _mesa_is_enum_format_integer(format);
+   uint32_t dst_format = _mesa_format_from_format_and_type(format, type);
+   int dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
+
+   /* Since _mesa_format_convert does not handle transferOps we need to handle
+    * them before we call the function. This requires to convert to RGBA float
+    * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is
+    * integer we can ignore transferOps.
+    *
+    * Some source formats (Luminance) will also require to be rebased to obtain
+    * the expected results and this also requires to convert to RGBA first.
+    */
+   assert(!transferOps || (transferOps && !dst_is_integer));
+   bool needs_rgba = (transferOps || rebaseFormat != GL_NONE);
+
    for (img = 0; img < depth; img++) {
       GLubyte *srcMap;
       GLint rowstride;
@@ -475,46 +480,105 @@ get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
       ctx->Driver.MapTextureImage(ctx, texImage, img,
                                   0, 0, width, height, GL_MAP_READ_BIT,
                                   &srcMap, &rowstride);
-      if (srcMap) {
-         for (row = 0; row < height; row++) {
-            const GLubyte *src = srcMap + row * rowstride;
-            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
-                                             width, height, format, type,
-                                             img, row, 0);
-
-	    if (tex_is_integer) {
-	       _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
-               if (rebaseFormat)
-                  _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat);
-               if (tex_is_uint) {
-                  _mesa_pack_rgba_span_from_uints(ctx, width,
-                                                  (GLuint (*)[4]) rgba_uint,
-                                                  format, type, dest);
-               } else {
-                  _mesa_pack_rgba_span_from_ints(ctx, width,
-                                                 (GLint (*)[4]) rgba_uint,
-                                                 format, type, dest);
-               }
-	    } else {
-	       _mesa_unpack_rgba_row(texFormat, width, src, rgba);
-               if (rebaseFormat)
-                  _mesa_rebase_rgba_float(width, rgba, rebaseFormat);
-	       _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
-					  format, type, dest,
-					  &ctx->Pack, transferOps);
-	    }
-	 }
-
-         /* Unmap the src texture buffer */
-         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
-      }
-      else {
+      if (!srcMap) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
-         break;
+         return;
       }
-   }
 
-   free(rgba);
+      GLubyte *img_src = srcMap;
+      void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
+                                       width, height, format, type,
+                                       img, 0, 0);
+
+      void *rgba = NULL;
+      void *src;
+      int src_stride;
+      uint32_t src_format;
+      if (needs_rgba) {
+         uint32_t rgba_format;
+         int rgba_stride;
+
+         /* Convert to RGBA float or (u)int depending on the type of the dst */
+         if (dst_is_integer) {
+            /* To avoid losing information because of clamping when converting
+             * from source to RGBA, check if source's format is signed or not.
+             */
+            GLboolean src_is_uint = _mesa_is_format_unsigned(texImage->TexFormat);
+
+            if (src_is_uint) {
+               rgba_format = RGBA8888_UINT.as_uint;
+               rgba_stride = width * 4 * sizeof(GLuint);
+            } else {
+               rgba_format = RGBA8888_INT.as_uint;
+               rgba_stride = width * 4 * sizeof(GLint);
+            }
+         } else {
+            rgba_format = RGBA8888_FLOAT.as_uint;
+            rgba_stride = width * 4 * sizeof(GLfloat);
+         }
+
+         /* If we are lucky and the dst format matches the RGBA format we need to
+          * convert to, then we can convert directly into the dst buffer and avoid
+          * the final conversion/copy from the rgba buffer to the dst buffer.
+          */
+         bool need_convert;
+         if (format == rgba_format) {
+            need_convert = false;
+            rgba = dest;
+         } else {
+            need_convert = true;
+            rgba = malloc(height * rgba_stride);
+            if (!rgba) {
+               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
+               ctx->Driver.UnmapTextureImage(ctx, texImage, img);
+               return;
+            }
+         }
+
+         /* Convert to RGBA now */
+         _mesa_format_convert(rgba, rgba_format, rgba_stride,
+                              img_src, texFormat, rowstride,
+                              width, height, GL_RGBA);
+
+         /* Rebase and handle transfer ops as necessary */
+         if (dst_is_integer) {
+            _mesa_rebase_rgba_uint(width * height, (GLuint (*)[4]) rgba, rebaseFormat);
+         } else {
+            _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) rgba, rebaseFormat);
+            if (transferOps)
+               _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba);
+         }
+
+         /* If we were lucky and our RGBA conversion matches the dst format, then
+          * we are done.
+          */
+         if (!need_convert)
+            goto done;
+
+         /* Otherwise, we need to convert from RGBA to dst next */
+         src = rgba;
+         src_format = rgba_format;
+         src_stride = rgba_stride;
+      } else {
+         /* No RGBA conversion needed, convert directly to dst */
+         src = img_src;
+         src_format = texFormat;
+         src_stride = rowstride;
+      }
+
+      /* Do the conversion to destination format */
+      _mesa_format_convert(dest, dst_format, dst_stride,
+                           src, src_format, src_stride,
+                           width, height,
+                           _mesa_get_format_base_format(dst_format));
+
+      if (rgba)
+         free(rgba);
+
+   done:
+      /* Unmap the src texture buffer */
+      ctx->Driver.UnmapTextureImage(ctx, texImage, img);
+   }
 }
 
 
-- 
1.9.1



More information about the mesa-dev mailing list