mesa: remove array size so the static assert can work
[mesa.git] / src / mesa / main / mipmap.c
index 46d71bb22181c1074bbca993c0f8ba0b2fba2c68..a2f3767a327177d3d8ac02d19e6f95661797b0c7 100644 (file)
 
 #include "imports.h"
 #include "formats.h"
+#include "glformats.h"
 #include "mipmap.h"
 #include "mtypes.h"
 #include "teximage.h"
+#include "texobj.h"
 #include "texstore.h"
 #include "image.h"
 #include "macros.h"
@@ -476,7 +478,7 @@ do_row(GLenum datatype, GLuint comps, GLint srcWidth,
       GLuint *dst = (GLuint *) dstRow;
       for (i = j = 0, k = k0; i < (GLuint) dstWidth;
            i++, j += colStride, k += colStride) {
-         dst[i] = (GLfloat)(rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4);
+         dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
       }
    }
 
@@ -991,7 +993,7 @@ do_row_3D(GLenum datatype, GLuint comps, GLint srcWidth,
       }
    }
    else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 3)) {
-      DECLARE_ROW_POINTERS(GLhalfARB, 4);
+      DECLARE_ROW_POINTERS(GLhalfARB, 3);
 
       for (i = j = 0, k = k0; i < (GLuint) dstWidth;
            i++, j += colStride, k += colStride) {
@@ -1001,7 +1003,7 @@ do_row_3D(GLenum datatype, GLuint comps, GLint srcWidth,
       }
    }
    else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 2)) {
-      DECLARE_ROW_POINTERS(GLhalfARB, 4);
+      DECLARE_ROW_POINTERS(GLhalfARB, 2);
 
       for (i = j = 0, k = k0; i < (GLuint) dstWidth;
            i++, j += colStride, k += colStride) {
@@ -1010,7 +1012,7 @@ do_row_3D(GLenum datatype, GLuint comps, GLint srcWidth,
       }
    }
    else if ((datatype == GL_HALF_FLOAT_ARB) && (comps == 1)) {
-      DECLARE_ROW_POINTERS(GLhalfARB, 4);
+      DECLARE_ROW_POINTERS(GLhalfARB, 1);
 
       for (i = j = 0, k = k0; i < (GLuint) dstWidth;
            i++, j += colStride, k += colStride) {
@@ -1751,6 +1753,7 @@ _mesa_generate_mipmap_level(GLenum target,
       }
       break;
    case GL_TEXTURE_RECTANGLE_NV:
+   case GL_TEXTURE_EXTERNAL_OES:
       /* no mipmaps, do nothing */
       break;
    default:
@@ -1802,6 +1805,80 @@ next_mipmap_level_size(GLenum target, GLint border,
    }
 }
 
+
+/**
+ * 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
+ */
+GLboolean
+_mesa_prepare_mipmap_level(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 = _mesa_num_tex_faces(texObj->Target);
+   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, dstImage,
+                                    width, height, depth,
+                                    border, intFormat, format);
+
+         ctx->Driver.AllocTextureImageBuffer(ctx, dstImage);
+
+         /* in case the mipmap level is part of an FBO: */
+         _mesa_update_fbo_texture(ctx, texObj, face, level);
+
+         ctx->NewState |= _NEW_TEXTURE;
+      }
+   }
+
+   return GL_TRUE;
+}
+
+
 static void
 generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
                             struct gl_texture_object *texObj,
@@ -1824,6 +1901,7 @@ generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
       GLint slice;
       GLboolean nextLevel;
       GLubyte **srcMaps, **dstMaps;
+      GLboolean success = GL_TRUE;
 
       /* get src image parameters */
       srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
@@ -1839,31 +1917,20 @@ generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
       if (!nextLevel)
          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");
+      if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
+                                      dstWidth, dstHeight, dstDepth,
+                                      border, srcImage->InternalFormat,
+                                      srcImage->TexFormat)) {
          return;
       }
 
-      /* Free old image data */
-      ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
-
-      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
-                                 dstDepth, border, srcImage->InternalFormat,
-                                 srcImage->TexFormat);
-
-      /* Alloc storage for new texture image */
-      if (!ctx->Driver.AllocTextureImageBuffer(ctx, dstImage,
-                                               dstImage->TexFormat,
-                                               dstWidth, dstHeight,
-                                               dstDepth)) {
+      /* 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;
       }
 
-      ASSERT(dstImage->TexFormat);
-
       if (target == GL_TEXTURE_1D_ARRAY) {
         srcDepth = srcHeight;
         dstDepth = dstHeight;
@@ -1872,42 +1939,74 @@ generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
       }
 
       /* Map src texture image slices */
-      srcMaps = (GLubyte **) malloc(srcDepth * sizeof(GLubyte *));
-      for (slice = 0; slice < srcDepth; slice++) {
-         ctx->Driver.MapTextureImage(ctx, srcImage, slice,
-                                     0, 0, srcWidth, srcHeight,
-                                     GL_MAP_READ_BIT,
-                                     &srcMaps[slice], &srcRowStride);
+      srcMaps = calloc(srcDepth, sizeof(GLubyte *));
+      if (srcMaps) {
+         for (slice = 0; slice < srcDepth; slice++) {
+            ctx->Driver.MapTextureImage(ctx, srcImage, slice,
+                                        0, 0, srcWidth, srcHeight,
+                                        GL_MAP_READ_BIT,
+                                        &srcMaps[slice], &srcRowStride);
+            if (!srcMaps[slice]) {
+               success = GL_FALSE;
+               break;
+            }
+         }
+      }
+      else {
+         success = GL_FALSE;
       }
 
       /* Map dst texture image slices */
-      dstMaps = (GLubyte **) malloc(dstDepth * sizeof(GLubyte *));
-      for (slice = 0; slice < dstDepth; slice++) {
-         ctx->Driver.MapTextureImage(ctx, dstImage, slice,
-                                     0, 0, dstWidth, dstHeight,
-                                     GL_MAP_WRITE_BIT,
-                                     &dstMaps[slice], &dstRowStride);
+      dstMaps = calloc(dstDepth, sizeof(GLubyte *));
+      if (dstMaps) {
+         for (slice = 0; slice < dstDepth; slice++) {
+            ctx->Driver.MapTextureImage(ctx, dstImage, slice,
+                                        0, 0, dstWidth, dstHeight,
+                                        GL_MAP_WRITE_BIT,
+                                        &dstMaps[slice], &dstRowStride);
+            if (!dstMaps[slice]) {
+               success = GL_FALSE;
+               break;
+            }
+         }
+      }
+      else {
+         success = GL_FALSE;
       }
 
-      /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
-      _mesa_generate_mipmap_level(target, datatype, comps, border,
-                                  srcWidth, srcHeight, srcDepth,
-                                  (const GLubyte **) srcMaps, srcRowStride,
-                                  dstWidth, dstHeight, dstDepth,
-                                  dstMaps, dstRowStride);
+      if (success) {
+         /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
+         _mesa_generate_mipmap_level(target, datatype, comps, border,
+                                     srcWidth, srcHeight, srcDepth,
+                                     (const GLubyte **) srcMaps, srcRowStride,
+                                     dstWidth, dstHeight, dstDepth,
+                                     dstMaps, dstRowStride);
+      }
 
       /* Unmap src image slices */
-      for (slice = 0; slice < srcDepth; slice++) {
-         ctx->Driver.UnmapTextureImage(ctx, srcImage, slice);
+      if (srcMaps) {
+         for (slice = 0; slice < srcDepth; slice++) {
+            if (srcMaps[slice]) {
+               ctx->Driver.UnmapTextureImage(ctx, srcImage, slice);
+            }
+         }
+         free(srcMaps);
       }
-      free(srcMaps);
 
       /* Unmap dst image slices */
-      for (slice = 0; slice < dstDepth; slice++) {
-         ctx->Driver.UnmapTextureImage(ctx, dstImage, slice);
+      if (dstMaps) {
+         for (slice = 0; slice < dstDepth; slice++) {
+            if (dstMaps[slice]) {
+               ctx->Driver.UnmapTextureImage(ctx, dstImage, slice);
+            }
+         }
+         free(dstMaps);
       }
-      free(dstMaps);
 
+      if (!success) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation");
+         break;
+      }
    } /* loop over mipmap levels */
 }
 
@@ -1954,7 +2053,7 @@ generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
    /* allocate storage for the temporary, uncompressed image */
    /* 20 extra bytes, just be safe when calling last FetchTexel */
    temp_src_stride = _mesa_format_row_stride(temp_format, srcImage->Width);
-   temp_src = (GLubyte *) malloc(temp_src_stride * srcImage->Height + 20);
+   temp_src = malloc(temp_src_stride * srcImage->Height + 20);
    if (!temp_src) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
       return;
@@ -2003,7 +2102,7 @@ generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
 
       temp_dst_stride = _mesa_format_row_stride(temp_format, dstWidth);
       if (!temp_dst) {
-        temp_dst = (GLubyte *) malloc(temp_dst_stride * dstHeight);
+        temp_dst = malloc(temp_dst_stride * dstHeight);
         if (!temp_dst) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
            break;
@@ -2014,12 +2113,11 @@ generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
       dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
       if (!dstImage) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
+         free(temp_dst);
          return;
       }
 
-      /* Free old image data */
-      ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
-
+      /* rescale src image to dest image */
       _mesa_generate_mipmap_level(target, temp_datatype, components, border,
                                   srcWidth, srcHeight, srcDepth,
                                   (const GLubyte **) &temp_src,
@@ -2027,19 +2125,19 @@ generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
                                   dstWidth, dstHeight, dstDepth,
                                   &temp_dst, temp_dst_stride);
 
-      /* initialize new image */
-      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
-                                 dstDepth, border, srcImage->InternalFormat,
-                                 srcImage->TexFormat);
-
-      /* Free old dest texture image buffer */
-      ctx->Driver.FreeTextureImageBuffer(ctx, dstImage);
+      if (!_mesa_prepare_mipmap_level(ctx, texObj, level + 1,
+                                      dstWidth, dstHeight, dstDepth,
+                                      border, srcImage->InternalFormat,
+                                      srcImage->TexFormat)) {
+         free(temp_dst);
+         return;
+      }
 
-      ctx->Driver.TexImage2D(ctx, target, level + 1,
-                            srcImage->InternalFormat,
-                            dstWidth, dstHeight, border,
-                            temp_base_format, temp_datatype,
-                            temp_dst, &ctx->DefaultPacking, texObj, dstImage);
+      /* The image space was allocated above so use glTexSubImage now */
+      ctx->Driver.TexSubImage(ctx, 2, dstImage,
+                              0, 0, 0, dstWidth, dstHeight, 1,
+                              temp_base_format, temp_datatype,
+                              temp_dst, &ctx->DefaultPacking);
 
       /* swap src and dest pointers */
       {