mesa: rewrite glTexStorage() code
authorBrian Paul <brianp@vmware.com>
Sat, 15 Sep 2012 16:30:20 +0000 (10:30 -0600)
committerBrian Paul <brianp@vmware.com>
Tue, 18 Sep 2012 01:49:26 +0000 (19:49 -0600)
Simplify the code and make it more like the other glTexImage commands.
Call _mesa_legal_texture_dimensions() to validate width, height, depth.
Call ctx->Driver.TestProxyTexImage() to make sure texture is not too large.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/mesa/main/texstorage.c

index 10e5f8df35eaa133db586e8fb8b985a09fa1f7d6..0a4cafe450a0cf2ffd2ed4fb6e762cbf92a2d89b 100644 (file)
@@ -118,39 +118,42 @@ next_mipmap_level_size(GLenum target,
 }
 
 
-/**
- * Do actual memory allocation for glTexStorage1/2/3D().
- */
-static void
-setup_texstorage(struct gl_context *ctx,
-                 struct gl_texture_object *texObj,
-                 GLuint dims,
-                 gl_format texFormat,
-                 GLsizei levels, GLenum internalFormat,
-                 GLsizei width, GLsizei height, GLsizei depth)
+/** Helper to get a particular texture image in a texture object */
+static struct gl_texture_image *
+get_tex_image(struct gl_context *ctx, 
+              struct gl_texture_object *texObj,
+              GLuint face, GLuint level)
+{
+   const GLenum faceTarget =
+      (texObj->Target == GL_TEXTURE_CUBE_MAP ||
+       texObj->Target == GL_PROXY_TEXTURE_CUBE_MAP)
+      ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : texObj->Target;
+   return _mesa_get_tex_image(ctx, texObj, faceTarget, level);
+}
+
+
+
+static GLboolean
+initialize_texture_fields(struct gl_context *ctx,
+                          struct gl_texture_object *texObj,
+                          GLint levels,
+                          GLsizei width, GLsizei height, GLsizei depth,
+                          GLenum internalFormat, gl_format texFormat)
 {
    const GLenum target = texObj->Target;
    const GLuint numFaces = _mesa_num_tex_faces(target);
    GLint level, levelWidth = width, levelHeight = height, levelDepth = depth;
    GLuint face;
 
-   assert(levels > 0);
-   assert(width > 0);
-   assert(height > 0);
-   assert(depth > 0);
-
    /* Set up all the texture object's gl_texture_images */
    for (level = 0; level < levels; level++) {
       for (face = 0; face < numFaces; face++) {
-         const GLenum faceTarget =
-            (target == GL_TEXTURE_CUBE_MAP)
-            ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target;
          struct gl_texture_image *texImage =
-            _mesa_get_tex_image(ctx, texObj, faceTarget, level);
+            get_tex_image(ctx, texObj, face, level);
 
         if (!texImage) {
-           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
-            return;
+           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage");
+            return GL_FALSE;
         }
 
          _mesa_init_teximage_fields(ctx, texImage,
@@ -160,49 +163,18 @@ setup_texstorage(struct gl_context *ctx,
 
       next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth);
    }
-
-   assert(levelWidth > 0);
-   assert(levelHeight > 0);
-   assert(levelDepth > 0);
-
-   if (!_mesa_is_proxy_texture(texObj->Target)) {
-      /* Do actual texture memory allocation */
-      if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
-                                           width, height, depth)) {
-         /* Reset the texture images' info to zeros.
-          * Strictly speaking, we probably don't have to do this since
-          * generating GL_OUT_OF_MEMORY can leave things in an undefined
-          * state but this puts things in a consistent state.
-          */
-         for (level = 0; level < levels; level++) {
-            for (face = 0; face < numFaces; face++) {
-               struct gl_texture_image *texImage = texObj->Image[face][level];
-               if (texImage) {
-                  _mesa_init_teximage_fields(ctx, texImage,
-                                             0, 0, 0, 0,
-                                             GL_NONE, MESA_FORMAT_NONE);
-               }
-            }
-         }
-
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
-
-         return;
-      }
-
-      /* Only set this field for non-proxy texture objects */
-      texObj->Immutable = GL_TRUE;
-   }
+   return GL_TRUE;
 }
 
 
 /**
  * Clear all fields of texture object to zeros.  Used for proxy texture tests.
+ * Used for proxy texture tests (and to clean up when a texture memory
+ * allocation fails).
  */
 static void
-clear_image_fields(struct gl_context *ctx,
-                   GLuint dims,
-                   struct gl_texture_object *texObj)
+clear_texture_fields(struct gl_context *ctx,
+                     struct gl_texture_object *texObj)
 {
    const GLenum target = texObj->Target;
    const GLuint numFaces = _mesa_num_tex_faces(target);
@@ -211,19 +183,17 @@ clear_image_fields(struct gl_context *ctx,
 
    for (level = 0; level < Elements(texObj->Image[0]); level++) {
       for (face = 0; face < numFaces; face++) {
-         const GLenum faceTarget =
-            (target == GL_TEXTURE_CUBE_MAP)
-            ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target;
          struct gl_texture_image *texImage =
-            _mesa_get_tex_image(ctx, texObj, faceTarget, level);
+            get_tex_image(ctx, texObj, face, level);
 
         if (!texImage) {
-           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
+           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage");
             return;
         }
 
          _mesa_init_teximage_fields(ctx, texImage,
-                                    0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE);
+                                    0, 0, 0, 0, /* w, h, d, border */
+                                    GL_NONE, MESA_FORMAT_NONE);
       }
    }
 }
@@ -356,7 +326,7 @@ texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat,
            GLsizei width, GLsizei height, GLsizei depth)
 {
    struct gl_texture_object *texObj;
-   GLboolean sizeOK;
+   GLboolean sizeOK, dimensionsOK;
    gl_format texFormat;
 
    GET_CURRENT_CONTEXT(ctx);
@@ -373,24 +343,59 @@ texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat,
                                            internalformat, GL_NONE, GL_NONE);
    assert(texFormat != MESA_FORMAT_NONE);
 
+   /* check that width, height, depth are legal for the mipmap level */
+   dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
+                                                  width, height, depth, 0);
+
    sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
                                           width, height, depth, 0);
 
-   if (!sizeOK) {
-      if (_mesa_is_proxy_texture(texObj->Target)) {
-         /* clear all image fields for [levels] */
-         clear_image_fields(ctx, dims, texObj);
+   if (_mesa_is_proxy_texture(texObj->Target)) {
+      if (dimensionsOK && sizeOK) {
+         initialize_texture_fields(ctx, texObj, levels, width, height, depth,
+                                   internalformat, texFormat);
       }
       else {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexStorage%uD(invalid width, height or depth)",
-                     dims);
-         return;
+         /* clear all image fields for [levels] */
+         clear_texture_fields(ctx, texObj);
       }
    }
    else {
-      setup_texstorage(ctx, texObj, dims, texFormat, levels, internalformat,
-                       width, height, depth);
+      if (!dimensionsOK) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glTexStorage%uD(invalid width, height or depth)", dims);
+         return;
+      }
+
+      if (!sizeOK) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                     "glTexStorage%uD(texture too large)", dims);
+      }
+
+      assert(levels > 0);
+      assert(width > 0);
+      assert(height > 0);
+      assert(depth > 0);
+
+      if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth,
+                                     internalformat, texFormat)) {
+         return;
+      }
+
+      /* Do actual texture memory allocation */
+      if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
+                                           width, height, depth)) {
+         /* Reset the texture images' info to zeros.
+          * Strictly speaking, we probably don't have to do this since
+          * generating GL_OUT_OF_MEMORY can leave things in an undefined
+          * state but this puts things in a consistent state.
+          */
+         clear_texture_fields(ctx, texObj);
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims);
+         return;
+      }
+
+      texObj->Immutable = GL_TRUE;
    }
 }