mesa: Split _mesa_generate_mipmap along compressed/uncompressed lines.
authorEric Anholt <eric@anholt.net>
Fri, 10 Jun 2011 19:00:23 +0000 (12:00 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 14 Jun 2011 18:17:39 +0000 (11:17 -0700)
The path taken is wildly different based on this (do we generate from
a temporary image, or from level-1's data), and we appear to have
stride bugs in the compressed case that are tough to disentangle.

This just duplicates the code for the moment, the followon commit will
do the actual changes.  Only real code change here is handling
maxLevel in one common place.

src/mesa/main/mipmap.c

index e9fcb545a1e9dbb2a9ede08ff16c00414c054e7e..2bdb111181390c6f13dd4b9ba91e9fcdf4003791 100644 (file)
@@ -1885,38 +1885,208 @@ next_mipmap_level_size(GLenum target, GLint border,
    }
 }
 
+static void
+generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
+                            struct gl_texture_object *texObj,
+                            const struct gl_texture_image *srcImage,
+                            GLuint maxLevel)
+{
+   GLint level;
+   gl_format convertFormat;
+   const GLubyte *srcData = NULL;
+   GLubyte *dstData = NULL;
+   GLenum datatype;
+   GLuint comps;
 
+   /* Find convertFormat - the format that do_row() will process */
+   if (_mesa_is_format_compressed(srcImage->TexFormat)) {
+      /* setup for compressed textures - need to allocate temporary
+       * image buffers to hold uncompressed images.
+       */
+      GLuint row;
+      GLint  components, size;
+      GLchan *dst;
 
+      assert(texObj->Target == GL_TEXTURE_2D ||
+             texObj->Target == GL_TEXTURE_CUBE_MAP_ARB);
 
-/**
- * Automatic mipmap generation.
- * This is the fallback/default function for ctx->Driver.GenerateMipmap().
- * Generate a complete set of mipmaps from texObj's BaseLevel image.
- * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
- * For cube maps, target will be one of
- * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP.
- */
-void
-_mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
-                      struct gl_texture_object *texObj)
+      if (srcImage->_BaseFormat == GL_RGB) {
+         convertFormat = MESA_FORMAT_RGB888;
+         components = 3;
+      } else if (srcImage->_BaseFormat == GL_RED) {
+         convertFormat = MESA_FORMAT_R8;
+         components = 1;
+      } else if (srcImage->_BaseFormat == GL_RG) {
+         convertFormat = MESA_FORMAT_RG88;
+         components = 2;
+      } else if (srcImage->_BaseFormat == GL_RGBA) {
+         convertFormat = MESA_FORMAT_RGBA8888;
+         components = 4;
+      } else if (srcImage->_BaseFormat == GL_LUMINANCE) {
+         convertFormat = MESA_FORMAT_L8;
+         components = 1;
+      } else if (srcImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
+         convertFormat = MESA_FORMAT_AL88;
+         components = 2;
+      } else {
+         _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
+         return;
+      }
+
+      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
+      size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
+         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
+      /* 20 extra bytes, just be safe when calling last FetchTexel */
+      srcData = (GLubyte *) malloc(size);
+      if (!srcData) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+         return;
+      }
+      dstData = (GLubyte *) malloc(size / 2);  /* 1/4 would probably be OK */
+      if (!dstData) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
+         free((void *) srcData);
+         return;
+      }
+
+      /* decompress base image here */
+      dst = (GLchan *) srcData;
+      for (row = 0; row < srcImage->Height; row++) {
+         GLuint col;
+         for (col = 0; col < srcImage->Width; col++) {
+            srcImage->FetchTexelc(srcImage, col, row, 0, dst);
+            dst += components;
+         }
+      }
+   }
+   else {
+      /* uncompressed */
+      convertFormat = srcImage->TexFormat;
+   }
+
+   _mesa_format_to_type_and_comps(convertFormat, &datatype, &comps);
+
+   for (level = texObj->BaseLevel; level < maxLevel; level++) {
+      /* generate image[level+1] from image[level] */
+      const struct gl_texture_image *srcImage;
+      struct gl_texture_image *dstImage;
+      GLint srcWidth, srcHeight, srcDepth;
+      GLint dstWidth, dstHeight, dstDepth;
+      GLint border;
+      GLboolean nextLevel;
+
+      /* get src image parameters */
+      srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      ASSERT(srcImage);
+      srcWidth = srcImage->Width;
+      srcHeight = srcImage->Height;
+      srcDepth = srcImage->Depth;
+      border = srcImage->Border;
+
+      nextLevel = next_mipmap_level_size(target, border,
+                                         srcWidth, srcHeight, srcDepth,
+                                         &dstWidth, &dstHeight, &dstDepth);
+      if (!nextLevel) {
+         /* all done */
+         if (_mesa_is_format_compressed(srcImage->TexFormat)) {
+            free((void *) srcData);
+            free(dstData);
+         }
+         return;
+      }
+
+      /* get dest gl_texture_image */
+      dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
+      if (!dstImage) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+         return;
+      }
+
+      /* Free old image data */
+      if (dstImage->Data)
+         ctx->Driver.FreeTexImageData(ctx, dstImage);
+
+      /* initialize new image */
+      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
+                                 dstDepth, border, srcImage->InternalFormat,
+                                 srcImage->TexFormat);
+      dstImage->DriverData = NULL;
+      dstImage->FetchTexelc = srcImage->FetchTexelc;
+      dstImage->FetchTexelf = srcImage->FetchTexelf;
+
+      /* Alloc new teximage data buffer */
+      {
+         GLuint size = _mesa_format_image_size(dstImage->TexFormat,
+                                               dstWidth, dstHeight, dstDepth);
+         dstImage->Data = _mesa_alloc_texmemory(size);
+         if (!dstImage->Data) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+            return;
+         }
+      }
+
+      /* Setup src and dest data pointers */
+      if (_mesa_is_format_compressed(dstImage->TexFormat)) {
+         /* srcData and dstData are already set */
+         ASSERT(srcData);
+         ASSERT(dstData);
+      }
+      else {
+         srcData = (const GLubyte *) srcImage->Data;
+         dstData = (GLubyte *) dstImage->Data;
+      }
+
+      ASSERT(dstImage->TexFormat);
+      ASSERT(dstImage->FetchTexelc);
+      ASSERT(dstImage->FetchTexelf);
+
+      _mesa_generate_mipmap_level(target, datatype, comps, border,
+                                  srcWidth, srcHeight, srcDepth,
+                                  srcData, srcImage->RowStride,
+                                  dstWidth, dstHeight, dstDepth,
+                                  dstData, dstImage->RowStride);
+
+
+      if (_mesa_is_format_compressed(dstImage->TexFormat)) {
+         GLubyte *temp;
+         /* compress image from dstData into dstImage->Data */
+         const GLenum srcFormat = _mesa_get_format_base_format(convertFormat);
+         GLint dstRowStride
+            = _mesa_format_row_stride(dstImage->TexFormat, dstWidth);
+
+         _mesa_texstore(ctx, 2, dstImage->_BaseFormat,
+                        dstImage->TexFormat,
+                        dstImage->Data,
+                        0, 0, 0, /* dstX/Y/Zoffset */
+                        dstRowStride, 0, /* strides */
+                        dstWidth, dstHeight, 1, /* size */
+                        srcFormat, CHAN_TYPE,
+                        dstData, /* src data, actually */
+                        &ctx->DefaultPacking);
+
+         /* swap src and dest pointers */
+         temp = (GLubyte *) srcData;
+         srcData = dstData;
+         dstData = temp;
+      }
+
+   } /* loop over mipmap levels */
+}
+
+static void
+generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
+                          struct gl_texture_object *texObj,
+                          const struct gl_texture_image *srcImage,
+                          GLuint maxLevel)
 {
-   const struct gl_texture_image *srcImage;
+   GLint level;
    gl_format convertFormat;
    const GLubyte *srcData = NULL;
    GLubyte *dstData = NULL;
-   GLint level, maxLevels;
    GLenum datatype;
    GLuint comps;
 
-   ASSERT(texObj);
-   srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
-   ASSERT(srcImage);
-
-   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
-   ASSERT(maxLevels > 0);  /* bad target */
-
    /* Find convertFormat - the format that do_row() will process */
-
    if (_mesa_is_format_compressed(srcImage->TexFormat)) {
       /* setup for compressed textures - need to allocate temporary
        * image buffers to hold uncompressed images.
@@ -1984,8 +2154,7 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
 
    _mesa_format_to_type_and_comps(convertFormat, &datatype, &comps);
 
-   for (level = texObj->BaseLevel; level < texObj->MaxLevel
-           && level < maxLevels - 1; level++) {
+   for (level = texObj->BaseLevel; level < maxLevel; level++) {
       /* generate image[level+1] from image[level] */
       const struct gl_texture_image *srcImage;
       struct gl_texture_image *dstImage;
@@ -2060,12 +2229,11 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
       ASSERT(dstImage->FetchTexelf);
 
       _mesa_generate_mipmap_level(target, datatype, comps, border,
-                                  srcWidth, srcHeight, srcDepth, 
+                                  srcWidth, srcHeight, srcDepth,
                                   srcData, srcImage->RowStride,
-                                  dstWidth, dstHeight, dstDepth, 
+                                  dstWidth, dstHeight, dstDepth,
                                   dstData, dstImage->RowStride);
 
-
       if (_mesa_is_format_compressed(dstImage->TexFormat)) {
          GLubyte *temp;
          /* compress image from dstData into dstImage->Data */
@@ -2092,6 +2260,37 @@ _mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
    } /* loop over mipmap levels */
 }
 
+/**
+ * Automatic mipmap generation.
+ * This is the fallback/default function for ctx->Driver.GenerateMipmap().
+ * Generate a complete set of mipmaps from texObj's BaseLevel image.
+ * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
+ * For cube maps, target will be one of
+ * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP.
+ */
+void
+_mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
+                      struct gl_texture_object *texObj)
+{
+   const struct gl_texture_image *srcImage;
+   GLint maxLevel;
+
+   ASSERT(texObj);
+   srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
+   ASSERT(srcImage);
+
+   maxLevel = _mesa_max_texture_levels(ctx, texObj->Target) - 1;
+   ASSERT(maxLevel >= 0);  /* bad target */
+
+   maxLevel = MIN2(maxLevel, texObj->MaxLevel);
+
+   if (_mesa_is_format_compressed(srcImage->TexFormat)) {
+      generate_mipmap_compressed(ctx, target, texObj, srcImage, maxLevel);
+   } else {
+      generate_mipmap_uncompressed(ctx, target, texObj, srcImage, maxLevel);
+   }
+}
+
 
 /**
  * Helper function for drivers which need to rescale texture images to