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

Brian Paul brian.e.paul at gmail.com
Tue Dec 13 17:07:05 PST 2011


From: Brian Paul <brianp at vmware.com>

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.  Now we only make the call
   when necessary.

v2: use _mesa_TexImage() in prepare_dest_image() to make sure side-effects
of changing a texture image are observed (like FBO completeness).
---
 src/mesa/drivers/common/meta.c |  129 +++++++++++++++++++++++++++++-----------
 1 files changed, 94 insertions(+), 35 deletions(-)

diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index 259041f..976640b 100644
--- a/src/mesa/drivers/common/meta.c
+++ b/src/mesa/drivers/common/meta.c
@@ -2789,6 +2789,90 @@ 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 */
+         switch (target) {
+         case GL_TEXTURE_1D:
+            _mesa_TexImage1D(target, level, intFormat, width, border,
+                             GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+            break;
+         case GL_TEXTURE_2D:
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+            _mesa_TexImage2D(target, level, intFormat, width, height, border,
+                             GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+            break;
+         case GL_TEXTURE_3D:
+            _mesa_TexImage3D(target, level, intFormat, width, height, depth,
+                             border, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+            break;
+         default:
+            _mesa_problem(ctx, "bad texture target in prepare_dest_image()");
+            return GL_FALSE;
+         }
+      }
+   }
+
+   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 +3027,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