mesa: move gl_texture_image::Width/Height/DepthScale fields to swrast
[mesa.git] / src / mesa / main / teximage.c
index af0b9c7518758ab35240cb8be682c25b7d20734b..4f7f2ed60de36ec5b1fd9316f2937fcfd42c80cd 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * mesa 3-D graphics library
- * Version:  7.6
+ * Mesa 3-D graphics library
  *
  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
@@ -43,7 +42,6 @@
 #include "mfeatures.h"
 #include "state.h"
 #include "texcompress.h"
-#include "texfetch.h"
 #include "teximage.h"
 #include "texstate.h"
 #include "texpal.h"
@@ -80,36 +78,6 @@ _mesa_free_texmemory(void *m)
 }
 
 
-/*
- * Compute floor(log_base_2(n)).
- * If n < 0 return -1.
- */
-static int
-logbase2( int n )
-{
-   GLint i = 1;
-   GLint log2 = 0;
-
-   if (n < 0)
-      return -1;
-
-   if (n == 0)
-      return 0;
-
-   while ( n > i ) {
-      i *= 2;
-      log2++;
-   }
-   if (i != n) {
-      return log2 - 1;
-   }
-   else {
-      return log2;
-   }
-}
-
-
-
 /**
  * Return the simple base format for a given internal texture format.
  * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA.
@@ -190,21 +158,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.EXT_paletted_texture) {
-      switch (internalFormat) {
-         case GL_COLOR_INDEX:
-         case GL_COLOR_INDEX1_EXT:
-         case GL_COLOR_INDEX2_EXT:
-         case GL_COLOR_INDEX4_EXT:
-         case GL_COLOR_INDEX8_EXT:
-         case GL_COLOR_INDEX12_EXT:
-         case GL_COLOR_INDEX16_EXT:
-            return GL_COLOR_INDEX;
-         default:
-            ; /* fallthrough */
-      }
-   }
-
    if (ctx->Extensions.ARB_depth_texture) {
       switch (internalFormat) {
          case GL_DEPTH_COMPONENT:
@@ -558,6 +511,25 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
+   if (ctx->API == API_OPENGLES) {
+      switch (internalFormat) {
+      case GL_PALETTE4_RGB8_OES:
+      case GL_PALETTE4_R5_G6_B5_OES:
+      case GL_PALETTE8_RGB8_OES:
+      case GL_PALETTE8_R5_G6_B5_OES:
+        return GL_RGB;
+      case GL_PALETTE4_RGBA8_OES:
+      case GL_PALETTE8_RGB5_A1_OES:
+      case GL_PALETTE4_RGBA4_OES:
+      case GL_PALETTE4_RGB5_A1_OES:
+      case GL_PALETTE8_RGBA8_OES:
+      case GL_PALETTE8_RGBA4_OES:
+        return GL_RGBA;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
    return -1; /* error */
 }
 
@@ -586,8 +558,6 @@ _mesa_tex_target_to_face(GLenum target)
  * \param target texture target.
  * \param level image level.
  * \param texImage texture image.
- * 
- * This was basically prompted by the introduction of cube maps.
  */
 void
 _mesa_set_tex_image(struct gl_texture_object *tObj,
@@ -604,6 +574,8 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
 
    /* Set the 'back' pointer */
    texImage->TexObject = tObj;
+   texImage->Level = level;
+   texImage->Face = face;
 }
 
 
@@ -626,7 +598,7 @@ _mesa_new_texture_image( struct gl_context *ctx )
 
 /**
  * Free texture image data.
- * This function is a fallback called via ctx->Driver.FreeTexImageData().
+ * This function is a fallback called via ctx->Driver.FreeTextureImageBuffer().
  *
  * \param texImage texture image.
  *
@@ -648,7 +620,8 @@ _mesa_free_texture_image_data(struct gl_context *ctx,
 
 
 /**
- * Free texture image.
+ * Free a gl_texture_image and associated data.
+ * This function is a fallback called via ctx->Driver.DeleteTextureImage().
  *
  * \param texImage texture image.
  *
@@ -661,8 +634,8 @@ _mesa_delete_texture_image(struct gl_context *ctx,
    /* Free texImage->Data and/or any other driver-specific texture
     * image storage.
     */
-   ASSERT(ctx->Driver.FreeTexImageData);
-   ctx->Driver.FreeTexImageData( ctx, texImage );
+   ASSERT(ctx->Driver.FreeTextureImageBuffer);
+   ctx->Driver.FreeTextureImageBuffer( ctx, texImage );
 
    ASSERT(texImage->Data == NULL);
    if (texImage->ImageOffsets)
@@ -739,15 +712,13 @@ get_proxy_target(GLenum target)
 
 /**
  * Get the texture object that corresponds to the target of the given
- * texture unit.
+ * texture unit.  The target should have already been checked for validity.
  *
  * \param ctx GL context.
  * \param texUnit texture unit.
  * \param target texture target.
  *
  * \return pointer to the texture object on success, or NULL on failure.
- * 
- * \sa gl_texture_unit.
  */
 struct gl_texture_object *
 _mesa_select_tex_object(struct gl_context *ctx,
@@ -1124,8 +1095,6 @@ clear_teximage_fields(struct gl_texture_image *img)
    img->DepthLog2 = 0;
    img->Data = NULL;
    img->TexFormat = MESA_FORMAT_NONE;
-   img->FetchTexelc = NULL;
-   img->FetchTexelf = NULL;
 }
 
 
@@ -1152,7 +1121,7 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
                            GLint border, GLenum internalFormat,
                            gl_format format)
 {
-   GLint i, dims;
+   GLint i;
 
    ASSERT(img);
    ASSERT(width >= 0);
@@ -1168,7 +1137,7 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
    img->Depth = depth;
 
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
-   img->WidthLog2 = logbase2(img->Width2);
+   img->WidthLog2 = _mesa_logbase2(img->Width2);
 
    if (height == 1) { /* 1-D texture */
       img->Height2 = 1;
@@ -1176,7 +1145,7 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
    }
    else {
       img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
-      img->HeightLog2 = logbase2(img->Height2);
+      img->HeightLog2 = _mesa_logbase2(img->Height2);
    }
 
    if (depth == 1) {  /* 2-D texture */
@@ -1185,18 +1154,11 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
    }
    else {
       img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
-      img->DepthLog2 = logbase2(img->Depth2);
+      img->DepthLog2 = _mesa_logbase2(img->Depth2);
    }
 
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
 
-   if ((width == 1 || _mesa_is_pow_two(img->Width2)) &&
-       (height == 1 || _mesa_is_pow_two(img->Height2)) &&
-       (depth == 1 || _mesa_is_pow_two(img->Depth2)))
-      img->_IsPowerOfTwo = GL_TRUE;
-   else
-      img->_IsPowerOfTwo = GL_FALSE;
-
    /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
    img->RowStride = width;
    /* Allocate the ImageOffsets array and initialize to typical values.
@@ -1210,24 +1172,7 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
       img->ImageOffsets[i] = i * width * height;
    }
 
-   /* Compute Width/Height/DepthScale for mipmap lod computation */
-   if (target == GL_TEXTURE_RECTANGLE_NV) {
-      /* scale = 1.0 since texture coords directly map to texels */
-      img->WidthScale = 1.0;
-      img->HeightScale = 1.0;
-      img->DepthScale = 1.0;
-   }
-   else {
-      img->WidthScale = (GLfloat) img->Width;
-      img->HeightScale = (GLfloat) img->Height;
-      img->DepthScale = (GLfloat) img->Depth;
-   }
-
    img->TexFormat = format;
-
-   dims = _mesa_get_texture_dimensions(target);
-
-   _mesa_set_fetch_functions(img, dims);
 }
 
 
@@ -1244,7 +1189,7 @@ void
 _mesa_clear_texture_image(struct gl_context *ctx,
                           struct gl_texture_image *texImage)
 {
-   ctx->Driver.FreeTexImageData(ctx, texImage);
+   ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
    clear_teximage_fields(texImage);
 }
 
@@ -1587,7 +1532,13 @@ texture_error_check( struct gl_context *ctx,
    const GLenum proxyTarget = get_proxy_target(target);
    const GLboolean isProxy = target == proxyTarget;
    GLboolean sizeOK = GL_TRUE;
-   GLboolean colorFormat, indexFormat;
+   GLboolean colorFormat;
+
+   /* Even though there are no color-index textures, we still have to support
+    * uploading color-index data and remapping it to RGB via the
+    * GL_PIXEL_MAP_I_TO_[RGBA] tables.
+    */
+   const GLboolean indexFormat = (format == GL_COLOR_INDEX);
 
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
@@ -1668,9 +1619,7 @@ texture_error_check( struct gl_context *ctx,
 
    /* make sure internal format and format basically agree */
    colorFormat = _mesa_is_color_format(format);
-   indexFormat = _mesa_is_index_format(format);
    if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
-       (_mesa_is_index_format(internalFormat) && !indexFormat) ||
        (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) ||
        (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) ||
        (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) ||
@@ -1715,11 +1664,15 @@ texture_error_check( struct gl_context *ctx,
 
    /* additional checks for depth textures */
    if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
-      /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */
+      /* Only 1D, 2D, rect and array textures supported, not 3D or cubes */
       if (target != GL_TEXTURE_1D &&
           target != GL_PROXY_TEXTURE_1D &&
           target != GL_TEXTURE_2D &&
           target != GL_PROXY_TEXTURE_2D &&
+          target != GL_TEXTURE_1D_ARRAY &&
+          target != GL_PROXY_TEXTURE_1D_ARRAY &&
+          target != GL_TEXTURE_2D_ARRAY &&
+          target != GL_PROXY_TEXTURE_2D_ARRAY &&
           target != GL_TEXTURE_RECTANGLE_ARB &&
           target != GL_PROXY_TEXTURE_RECTANGLE_ARB) {
          if (!isProxy)
@@ -2485,9 +2438,7 @@ teximage(struct gl_context *ctx, GLuint dims,
          else {
             gl_format texFormat;
 
-            if (texImage->Data) {
-               ctx->Driver.FreeTexImageData( ctx, texImage );
-            }
+            ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
             ASSERT(texImage->Data == NULL);
             texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
@@ -2626,8 +2577,7 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
    if (!texImage) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D");
    } else {
-      if (texImage->Data)
-        ctx->Driver.FreeTexImageData( ctx, texImage );
+      ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
       ASSERT(texImage->Data == NULL);
       ctx->Driver.EGLImageTargetTexture2D(ctx, target,
@@ -2693,7 +2643,7 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
                                   format, type, texImage)) {
          /* error was recorded */
       }
-      else if (width > 0 && height > 0 && height > 0) {
+      else if (width > 0 && height > 0 && depth > 0) {
          /* If we have a border, offset=-1 is legal.  Bias by border width. */
          switch (dims) {
          case 3:
@@ -2823,29 +2773,43 @@ copyteximage(struct gl_context *ctx, GLuint dims,
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
       }
       else {
-         gl_format texFormat;
-
-         if (texImage->Data) {
-            ctx->Driver.FreeTexImageData( ctx, texImage );
-         }
+         /* choose actual hw format */
+         gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
+                                                           target, level,
+                                                           internalFormat,
+                                                           GL_NONE, GL_NONE);
 
-         ASSERT(texImage->Data == NULL);
+         if (legal_texture_size(ctx, texFormat, width, height, 1)) {
+            GLint srcX = x, srcY = y, dstX = 0, dstY = 0;
 
-         texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
-                                                 internalFormat, GL_NONE,
-                                                 GL_NONE);
+            /* Free old texture image */
+            ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
-         if (legal_texture_size(ctx, texFormat, width, height, 1)) {
             _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
                                        border, internalFormat, texFormat);
 
-            ASSERT(ctx->Driver.CopyTexImage2D);
-            if (dims == 1)
-               ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
-                                          x, y, width, border);
-            else
-               ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
-                                          x, y, width, height, border);
+            /* Allocate texture memory (no pixel data yet) */
+            if (dims == 1) {
+               ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+                                      width, border, GL_NONE, GL_NONE, NULL,
+                                      &ctx->Unpack, texObj, texImage);
+            }
+            else {
+               ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+                                      width, height, border, GL_NONE, GL_NONE,
+                                      NULL, &ctx->Unpack, texObj, texImage);
+            }
+
+            if (_mesa_clip_copytexsubimage(ctx, &dstX, &dstY, &srcX, &srcY,
+                                           &width, &height)) {
+               if (dims == 1)
+                  ctx->Driver.CopyTexSubImage1D(ctx, target, level, dstX,
+                                                srcX, srcY, width);
+                                                
+               else
+                  ctx->Driver.CopyTexSubImage2D(ctx, target, level, dstX, dstY,
+                                                srcX, srcY, width, height);
+            }
 
             check_gen_mipmap(ctx, target, texObj, level);
 
@@ -2856,6 +2820,7 @@ copyteximage(struct gl_context *ctx, GLuint dims,
             ctx->NewState |= _NEW_TEXTURE;
          }
          else {
+            /* probably too large of image */
             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
          }
       }
@@ -3033,6 +2998,7 @@ get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
 
 /**
  * Error checking for glCompressedTexImage[123]D().
+ * \param reason  returns reason for error, if any
  * \return error code or GL_NO_ERROR.
  */
 static GLenum
@@ -3040,42 +3006,114 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
                                GLenum target, GLint level,
                                GLenum internalFormat, GLsizei width,
                                GLsizei height, GLsizei depth, GLint border,
-                               GLsizei imageSize)
+                               GLsizei imageSize, char **reason)
 {
    const GLenum proxyTarget = get_proxy_target(target);
    const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
    GLint expectedSize;
+   GLenum choose_format;
+   GLenum choose_type;
+   GLenum proxy_format;
 
-   /* check level */
-   if (level < 0 || level >= maxLevels)
-      return GL_INVALID_VALUE;
+   *reason = ""; /* no error */
 
    if (!target_can_be_compressed(ctx, target, internalFormat)) {
+      *reason = "target";
       return GL_INVALID_ENUM;
    }
 
    /* This will detect any invalid internalFormat value */
-   if (!_mesa_is_compressed_format(ctx, internalFormat))
+   if (!_mesa_is_compressed_format(ctx, internalFormat)) {
+      *reason = "internalFormat";
       return GL_INVALID_ENUM;
+   }
+
+   switch (internalFormat) {
+#if FEATURE_ES
+   case GL_PALETTE4_RGB8_OES:
+   case GL_PALETTE4_RGBA8_OES:
+   case GL_PALETTE4_R5_G6_B5_OES:
+   case GL_PALETTE4_RGBA4_OES:
+   case GL_PALETTE4_RGB5_A1_OES:
+   case GL_PALETTE8_RGB8_OES:
+   case GL_PALETTE8_RGBA8_OES:
+   case GL_PALETTE8_R5_G6_B5_OES:
+   case GL_PALETTE8_RGBA4_OES:
+   case GL_PALETTE8_RGB5_A1_OES:
+      _mesa_cpal_compressed_format_type(internalFormat, &choose_format,
+                                       &choose_type);
+      proxy_format = choose_format;
+
+      /* check level */
+      if (level > 0 || level < -maxLevels) {
+        *reason = "level";
+        return GL_INVALID_VALUE;
+      }
+
+      if (dimensions != 2) {
+        *reason = "compressed paletted textures must be 2D";
+        return GL_INVALID_OPERATION;
+      }
+
+      /* Figure out the expected texture size (in bytes).  This will be
+       * checked against the actual size later.
+       */
+      expectedSize = _mesa_cpal_compressed_size(level, internalFormat,
+                                               width, height);
+
+      /* This is for the benefit of the TestProxyTexImage below.  It expects
+       * level to be non-negative.  OES_compressed_paletted_texture uses a
+       * weird mechanism where the level specified to glCompressedTexImage2D
+       * is -(n-1) number of levels in the texture, and the data specifies the
+       * complete mipmap stack.  This is done to ensure the palette is the
+       * same for all levels.
+       */
+      level = -level;
+      break;
+#endif
+
+   default:
+      choose_format = GL_NONE;
+      choose_type = GL_NONE;
+      proxy_format = internalFormat;
+
+      /* check level */
+      if (level < 0 || level >= maxLevels) {
+        *reason = "level";
+        return GL_INVALID_VALUE;
+      }
+
+      /* Figure out the expected texture size (in bytes).  This will be
+       * checked against the actual size later.
+       */
+      expectedSize = compressed_tex_size(width, height, depth, internalFormat);
+      break;
+   }
 
    /* This should really never fail */
-   if (_mesa_base_tex_format(ctx, internalFormat) < 0)
+   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
+      *reason = "internalFormat";
       return GL_INVALID_ENUM;
+   }
 
    /* No compressed formats support borders at this time */
-   if (border != 0)
+   if (border != 0) {
+      *reason = "border != 0";
       return GL_INVALID_VALUE;
+   }
 
    /* For cube map, width must equal height */
    if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height)
+       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height) {
+      *reason = "width != height";
       return GL_INVALID_VALUE;
+   }
 
    /* check image size against compression block size */
    {
       gl_format texFormat =
-         ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
-                                         GL_NONE, GL_NONE);
+         ctx->Driver.ChooseTextureFormat(ctx, proxy_format,
+                                        choose_format, choose_type);
       GLuint bw, bh;
 
       _mesa_get_format_block_size(texFormat, &bw, &bh);
@@ -3086,25 +3124,28 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
           * generated [...] if any parameter combinations are not
           * supported by the specific compressed internal format. 
           */
+         *reason = "invalid width or height for compression format";
          return GL_INVALID_OPERATION;
       }
    }
 
    /* check image sizes */
    if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
-                                      internalFormat, GL_NONE, GL_NONE,
-                                      width, height, depth, border)) {
+                                     proxy_format, choose_format,
+                                     choose_type,
+                                     width, height, depth, border)) {
       /* See error comment above */
+      *reason = "invalid width, height or format";
       return GL_INVALID_OPERATION;
    }
 
    /* check image size in bytes */
-   expectedSize = compressed_tex_size(width, height, depth, internalFormat);
    if (expectedSize != imageSize) {
       /* Per GL_ARB_texture_compression:  GL_INVALID_VALUE is generated [...]
        * if <imageSize> is not consistent with the format, dimensions, and
        * contents of the specified image.
        */
+      *reason = "imageSize inconsistant with width/height/format";
       return GL_INVALID_VALUE;
    }
 
@@ -3259,6 +3300,7 @@ compressedteximage(struct gl_context *ctx, GLuint dims,
                    GLsizei imageSize, const GLvoid *data)
 {
    GLenum error;
+   char *reason = "";
 
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -3279,10 +3321,10 @@ compressedteximage(struct gl_context *ctx, GLuint dims,
 
    error = compressed_texture_error_check(ctx, dims, target, level,
                                           internalFormat, width, height, depth,
-                                          border, imageSize);
+                                          border, imageSize, &reason);
 
    if (error) {
-      _mesa_error(ctx, error, "glTexImage2D");
+      _mesa_error(ctx, error, "glCompressedTexImage%uD(%s)", dims, reason);
       return;
    }
 
@@ -3358,9 +3400,7 @@ compressedteximage(struct gl_context *ctx, GLuint dims,
          else {
             gl_format texFormat;
 
-            if (texImage->Data) {
-               ctx->Driver.FreeTexImageData( ctx, texImage );
-            }
+            ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
             ASSERT(texImage->Data == NULL);
 
             texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,