[Mesa-dev] [PATCH] meta: rework dest image allocation in mipmap generation code

Brian Paul brianp at vmware.com
Sat Dec 10 11:00:27 PST 2011


This fixes two things:
1. If the texture object was created with glTexStorage2D, the call
   to _mesa_TexImage2D() would generate INVALID_OPERATION since the
   texture is marked as immutable.
2. _mesa_TexImage2D() always frees any existing texture image memory
   before allocating new memory.  That's inefficient since the existing
   image is usually the right size already.
---
 src/mesa/drivers/common/meta.c |  114 +++++++++++++++++++++++++++------------
 1 files changed, 79 insertions(+), 35 deletions(-)

diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index 259041f..3ec8828 100644
--- a/src/mesa/drivers/common/meta.c
+++ b/src/mesa/drivers/common/meta.c
@@ -2789,6 +2789,75 @@ setup_texture_coords(GLenum faceTarget,
 
 
 /**
+ * Helper function for mipmap generation.
+ * Make sure the specified destination mipmap level is the right size/format
+ * for mipmap generation.  If not, (re) allocate it.
+ * \return GL_TRUE if successful, GL_FALSE if mipmap generation should stop
+ */
+static GLboolean
+prepare_dest_image(struct gl_context *ctx,
+                   struct gl_texture_object *texObj, GLuint level,
+                   GLsizei width, GLsizei height, GLsizei depth,
+                   GLsizei border, GLenum intFormat, gl_format format)
+{
+   const GLuint numFaces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
+   GLuint face;
+
+   if (texObj->Immutable) {
+      /* The texture was created with glTexStorage() so the number/size of
+       * mipmap levels is fixed and the storage for all images is already
+       * allocated.
+       */
+      if (!texObj->Image[0][level]) {
+         /* No more levels to create - we're done */
+         return GL_FALSE;
+      }
+      else {
+         /* Nothing to do - the texture memory must have already been
+          * allocated to the right size so we're all set.
+          */
+         return GL_TRUE;
+      }
+   }
+
+   for (face = 0; face < numFaces; face++) {
+      struct gl_texture_image *dstImage;
+      GLenum target;
+
+      if (numFaces == 1)
+         target = texObj->Target;
+      else
+         target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+
+      dstImage = _mesa_get_tex_image(ctx, texObj, target, level);
+      if (!dstImage) {
+         /* out of memory */
+         return GL_FALSE;
+      }
+
+      if (dstImage->Width != width ||
+          dstImage->Height != height ||
+          dstImage->Depth != depth ||
+          dstImage->Border != border ||
+          dstImage->InternalFormat != intFormat ||
+          dstImage->TexFormat != format) {
+         /* need to (re)allocate image */
+         ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
+
+         _mesa_init_teximage_fields(ctx, target, dstImage,
+                                    width, height, depth,
+                                    border, intFormat, format);
+
+         ctx->Driver.AllocTextureImageBuffer(ctx, dstImage,
+                                             format, width, height, depth);
+      }
+   }
+
+   return GL_TRUE;
+}
+
+
+/**
  * Called via ctx->Driver.GenerateMipmap()
  * Note: We don't yet support 3D textures, 1D/2D array textures or texture
  * borders.
@@ -2943,43 +3012,18 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
          break;
       }
 
-      /* Set MaxLevel large enough to hold the new level when we allocate it  */
+      /* Allocate storage for the destination mipmap image(s) */
+
+      /* Set MaxLevel large enough to hold the new level when we allocate it */
       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel);
 
-      /* Create empty dest image */
-      if (target == GL_TEXTURE_1D) {
-         _mesa_TexImage1D(target, dstLevel, srcImage->InternalFormat,
-                          dstWidth, border,
-                          GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-      }
-      else if (target == GL_TEXTURE_3D) {
-         _mesa_TexImage3D(target, dstLevel, srcImage->InternalFormat,
-                          dstWidth, dstHeight, dstDepth, border,
-                          GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-      }
-      else {
-         /* 2D or cube */
-         _mesa_TexImage2D(faceTarget, dstLevel, srcImage->InternalFormat,
-                          dstWidth, dstHeight, border,
-                          GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
-         if (target == GL_TEXTURE_CUBE_MAP) {
-            /* If texturing from a cube, we need to make sure all src faces
-             * have been defined (even if we're not sampling from them.)
-             * Otherwise the texture object will be 'incomplete' and
-             * texturing from it will not be allowed.
-             */
-            GLuint face;
-            for (face = 0; face < 6; face++) {
-               if (!texObj->Image[face][srcLevel] ||
-                   texObj->Image[face][srcLevel]->Width != srcWidth) {
-                  _mesa_TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
-                                   srcLevel, srcImage->InternalFormat,
-                                   srcWidth, srcHeight, border,
-                                   GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-               }
-            }
-         }
+      if (!prepare_dest_image(ctx, texObj, dstLevel,
+                              dstWidth, dstHeight, dstDepth, srcImage->Border,
+                              srcImage->InternalFormat, srcImage->TexFormat)) {
+         /* All done.  We either ran out of memory or we would go beyond the
+          * last valid level of an immutable texture if we continued.
+          */
+         break;
       }
 
       /* limit minification to src level */
-- 
1.7.3.4



More information about the mesa-dev mailing list