Fix a number of texture compression issues.
[mesa.git] / src / mesa / main / teximage.c
index f0b3ac1f13dff4e18907731ea9d0c01d9e53b367..4b9b1b8728d27a3e7dd5debd941b1d4f0a51c251 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.3
+ * Version:  6.5
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 
 /**
  * \file teximage.c
- * Texture images manipulation functions.
- *
- * \note Mesa's native texture data type is GLchan.  Native formats are
- * GL_ALPHA, GL_LUMINANCE, GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, GL_RGBA, and
- * GL_COLOR_INDEX.
- *
- * \note Device drivers are free to implement any internal format they want.
+ * Texture image-related functions.
  */
 
 
@@ -39,6 +33,8 @@
 #include "bufferobj.h"
 #include "context.h"
 #include "convolve.h"
+#include "fbobject.h"
+#include "framebuffer.h"
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
 #include "mtypes.h"
 
 
+/**
+ * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE
+ * elsewhere.
+ */
+void *
+_mesa_alloc_texmemory(GLsizei bytes)
+{
+   return _mesa_align_malloc(bytes, 512);
+}
+
+
+/**
+ * Free texture memory allocated with _mesa_alloc_texmemory()
+ */
+void
+_mesa_free_texmemory(void *m)
+{
+   _mesa_align_free(m);
+}
+
+
+
+
 #if 0
 static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
 {
@@ -98,6 +117,7 @@ static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
             _mesa_printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
          data += (img->RowStride - img->Width) * c;
       }
+      /* XXX use img->ImageStride here */
       _mesa_printf("\n");
    }
 #endif
@@ -219,7 +239,8 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.SGIX_depth_texture) {
+   if (ctx->Extensions.SGIX_depth_texture ||
+       ctx->Extensions.ARB_depth_texture) {
       switch (internalFormat) {
          case GL_DEPTH_COMPONENT:
          case GL_DEPTH_COMPONENT16_SGIX:
@@ -317,6 +338,16 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
       }
    }
 
+   if (ctx->Extensions.EXT_packed_depth_stencil) {
+      switch (internalFormat) {
+         case GL_DEPTH_STENCIL_EXT:
+         case GL_DEPTH24_STENCIL8_EXT:
+            return GL_DEPTH_STENCIL_EXT;
+         default:
+            ; /* fallthrough */
+      }
+   }
+
    return -1; /* error */
 }
 
@@ -471,6 +502,23 @@ is_ycbcr_format(GLenum format)
 }
 
 
+/**
+ * Test if the given image format is a Depth/Stencil format.
+ */
+static GLboolean
+is_depthstencil_format(GLenum format)
+{
+   switch (format) {
+      case GL_DEPTH24_STENCIL8_EXT:
+      case GL_DEPTH_STENCIL_EXT:
+         return GL_TRUE;
+      default:
+         return GL_FALSE;
+   }
+}
+
+
+
 /**
  * Test if it is a supported compressed format.
  * 
@@ -504,6 +552,18 @@ is_compressed_format(GLcontext *ctx, GLenum internalFormat)
 }
 
 
+static GLuint
+texture_face(GLenum target)
+{
+   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
+       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)
+      return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+   else
+      return 0;
+}
+
+
+
 /**
  * Store a gl_texture_image pointer in a gl_texture_object structure
  * according to the target and level parameters.
@@ -533,12 +593,13 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: {
-        GLuint face = ((GLuint) target - 
-                       (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
-         tObj->Image[face][level] = texImage;
-        break;
-      }
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+         {
+            GLuint face = ((GLuint) target - 
+                           (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
+            tObj->Image[face][level] = texImage;
+         }
+         break;
       case GL_TEXTURE_RECTANGLE_NV:
          ASSERT(level == 0);
          tObj->Image[0][level] = texImage;
@@ -569,22 +630,42 @@ _mesa_new_texture_image( GLcontext *ctx )
 }
 
 
+/**
+ * Free texture image data.
+ * This function is a fallback called via ctx->Driver.FreeTexImageData().
+ *
+ * \param teximage texture image.
+ *
+ * Free the texture image data if it's not marked as client data.
+ */
+void
+_mesa_free_texture_image_data(GLcontext *ctx,
+                              struct gl_texture_image *texImage)
+{
+   if (texImage->Data && !texImage->IsClientData) {
+      /* free the old texture data */
+      _mesa_free_texmemory(texImage->Data);
+   }
+
+   texImage->Data = NULL;
+}
+
+
 /**
  * Free texture image.
  *
  * \param teximage texture image.
  *
- * Free the texture image structure and the associated image data if it's not
- * marked as client data.
+ * Free the texture image structure and the associated image data.
  */
 void
-_mesa_delete_texture_image( struct gl_texture_image *teximage )
+_mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
 {
-   if (teximage->Data && !teximage->IsClientData) {
-      MESA_PBUFFER_FREE( teximage->Data );
-      teximage->Data = NULL;
+   if (texImage->Data) {
+      ctx->Driver.FreeTexImageData( ctx, texImage );
    }
-   FREE( teximage );
+   ASSERT(texImage->Data == NULL);
+   FREE( texImage );
 }
 
 
@@ -595,8 +676,8 @@ _mesa_delete_texture_image( struct gl_texture_image *teximage )
  *
  * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise.
  */
-static GLboolean
-is_proxy_target(GLenum target)
+GLboolean
+_mesa_is_proxy_texture(GLenum target)
 {
    return (target == GL_PROXY_TEXTURE_1D ||
            target == GL_PROXY_TEXTURE_2D ||
@@ -965,13 +1046,14 @@ static void
 clear_teximage_fields(struct gl_texture_image *img)
 {
    ASSERT(img);
-   img->Format = 0;
-   img->IntFormat = 0;
+   img->_BaseFormat = 0;
+   img->InternalFormat = 0;
    img->Border = 0;
    img->Width = 0;
    img->Height = 0;
    img->Depth = 0;
    img->RowStride = 0;
+   img->ImageStride = 0;
    img->Width2 = 0;
    img->Height2 = 0;
    img->Depth2 = 0;
@@ -1009,37 +1091,34 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
                            GLint border, GLenum internalFormat)
 {
    ASSERT(img);
-   img->Format = _mesa_base_tex_format( ctx, internalFormat );
-   ASSERT(img->Format > 0);
-   img->IntFormat = internalFormat;
+   img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
+   ASSERT(img->_BaseFormat > 0);
+   img->InternalFormat = internalFormat;
    img->Border = border;
    img->Width = width;
    img->Height = height;
    img->Depth = depth;
    img->RowStride = width;
-   img->WidthLog2 = logbase2(width - 2 * border);
+   img->ImageStride = width * height;
+   img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
+   img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
+   img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
+   img->WidthLog2 = logbase2(img->Width2);
    if (height == 1)  /* 1-D texture */
       img->HeightLog2 = 0;
    else
-      img->HeightLog2 = logbase2(height - 2 * border);
+      img->HeightLog2 = logbase2(img->Height2);
    if (depth == 1)   /* 2-D texture */
       img->DepthLog2 = 0;
    else
-      img->DepthLog2 = logbase2(depth - 2 * border);
-   img->Width2 = width - 2 * border; /*1 << img->WidthLog2;*/
-   img->Height2 = height - 2 * border; /*1 << img->HeightLog2;*/
-   img->Depth2 = depth - 2 * border; /*1 << img->DepthLog2;*/
+      img->DepthLog2 = logbase2(img->Depth2);
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
-   img->IsCompressed = is_compressed_format(ctx, internalFormat);
-   if (img->IsCompressed)
-      img->CompressedSize = ctx->Driver.CompressedTextureSize(ctx, width,
-                                               height, depth, internalFormat);
-   else
-      img->CompressedSize = 0;
+   img->IsCompressed = GL_FALSE;
+   img->CompressedSize = 0;
 
-   if ((width == 1 || _mesa_bitcount(width - 2 * border) == 1) &&
-       (height == 1 || _mesa_bitcount(height - 2 * border) == 1) &&
-       (depth == 1 || _mesa_bitcount(depth - 2 * border) == 1))
+   if ((width == 1 || _mesa_bitcount(img->Width2) == 1) &&
+       (height == 1 || _mesa_bitcount(img->Height2) == 1) &&
+       (depth == 1 || _mesa_bitcount(img->Depth2) == 1))
       img->_IsPowerOfTwo = GL_TRUE;
    else
       img->_IsPowerOfTwo = GL_FALSE;
@@ -1187,7 +1266,7 @@ texture_error_check( GLcontext *ctx, GLenum target,
                      GLint width, GLint height,
                      GLint depth, GLint border )
 {
-   const GLboolean isProxy = is_proxy_target(target);
+   const GLboolean isProxy = _mesa_is_proxy_texture(target);
    GLboolean sizeOK;
    GLboolean colorFormat, indexFormat;
 
@@ -1324,7 +1403,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
    if ((is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
        (is_index_format(internalFormat) && !indexFormat) ||
        (is_depth_format(internalFormat) != is_depth_format(format)) ||
-       (is_ycbcr_format(internalFormat) != is_ycbcr_format(format))) {
+       (is_ycbcr_format(internalFormat) != is_ycbcr_format(format)) ||
+       (is_depthstencil_format(internalFormat) != is_depthstencil_format(format))) {
       if (!isProxy)
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage(internalFormat/format)");
@@ -1614,11 +1694,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
                          GLenum target, GLint level, GLint internalFormat,
                          GLint width, GLint height, GLint border )
 {
-   GLenum format, type;
+   GLenum type;
    GLboolean sizeOK;
+   GLint format;
 
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+   /* Check that the source buffer is complete */
+   if (ctx->ReadBuffer->Name) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
+      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
+
       _mesa_error(ctx, GL_INVALID_VALUE,
                   "glCopyTexImage%dD(level=%d)", dimensions, level);
       return GL_TRUE;
@@ -1631,10 +1722,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   /* The format and type aren't really significant here, but we need to pass
-    * something to TestProxyTexImage().
-    */
    format = _mesa_base_tex_format(ctx, internalFormat);
+   if (format < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glCopyTexImage%dD(internalFormat)", dimensions);
+      return GL_TRUE;
+   }
+
+   /* NOTE: the format and type aren't really significant for
+    * TestProxyTexImage().  Only the internalformat really matters.
+   if (!_mesa_source_buffer_exists(ctx, format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexImage%dD(missing readbuffer)", dimensions);
+      return GL_TRUE;
+   }
+
+    */
    type = GL_FLOAT;
 
    /* Check target and call ctx->Driver.TestProxyTexImage() to check the
@@ -1704,12 +1807,6 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexImage%dD(internalFormat)", dimensions);
-      return GL_TRUE;
-   }
-
    if (is_compressed_format(ctx, internalFormat)) {
       if (target != GL_TEXTURE_2D) {
          _mesa_error(ctx, GL_INVALID_ENUM,
@@ -1722,6 +1819,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
          return GL_TRUE;
       }
    }
+   else if (is_depth_format(internalFormat)) {
+      /* make sure we have depth/stencil buffers */
+      if (!ctx->ReadBuffer->_DepthBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%D(no depth)", dimensions);
+         return GL_TRUE;
+      }
+   }
+   else if (is_depthstencil_format(internalFormat)) {
+      /* make sure we have depth/stencil buffers */
+      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%D(no depth/stencil buffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
 
    /* if we get here, the parameters are OK */
    return GL_FALSE;
@@ -1729,7 +1842,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
 
 
 /**
- * Test glCopyTexImage[12]D() parameters for errors.
+ * Test glCopyTexSubImage[12]D() parameters for errors.
  * 
  * \param ctx GL context.
  * \param dimensions texture image dimensions (must be 1, 2 or 3).
@@ -1757,6 +1870,16 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
    struct gl_texture_image *teximage;
 
    /* Check target */
+   /* Check that the source buffer is complete */
+   if (ctx->ReadBuffer->Name) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
+      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
+
    if (dimensions == 1) {
       if (target != GL_TEXTURE_1D) {
          _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
@@ -1854,6 +1977,12 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
    }
 
    if (teximage->IsCompressed) {
+   if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexSubImage%dD(missing readbuffer)", dimensions);
+      return GL_TRUE;
+   }
+
       if (target != GL_TEXTURE_2D) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glCopyTexSubImage%d(target)", dimensions);
@@ -1878,11 +2007,28 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
       }         
    }
 
-   if (teximage->IntFormat == GL_YCBCR_MESA) {
+   if (teximage->InternalFormat == GL_YCBCR_MESA) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D");
       return GL_TRUE;
    }
 
+   if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) {
+      if (!ctx->ReadBuffer->_DepthBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexSubImage%D(no depth buffer)",
+                     dimensions);
+         return GL_TRUE;
+      }
+   }
+   else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexSubImage%D(no depth/stencil buffer)",
+                     dimensions);
+         return GL_TRUE;
+      }
+   }
+
    /* if we get here, the parameters are OK */
    return GL_FALSE;
 }
@@ -1902,15 +2048,15 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
                    GLenum type, GLvoid *pixels )
 {
    const struct gl_texture_unit *texUnit;
-   const struct gl_texture_object *texObj;
-   const struct gl_texture_image *texImage;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
    GLint maxLevels = 0;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    texUnit = &(ctx->Texture.Unit[ctx->Texture.CurrentUnit]);
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   if (!texObj || is_proxy_target(target)) {
+   if (!texObj || _mesa_is_proxy_texture(target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
       return;
    }
@@ -1938,7 +2084,8 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
    }
 
-   if (!ctx->Extensions.SGIX_depth_texture && is_depth_format(format)) {
+   if (!ctx->Extensions.SGIX_depth_texture &&
+       !ctx->Extensions.ARB_depth_texture && is_depth_format(format)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
    }
 
@@ -1946,6 +2093,11 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
    }
 
+   if (!ctx->Extensions.EXT_packed_depth_stencil
+       && is_depthstencil_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+   }
+
    if (!pixels)
       return;
 
@@ -1956,8 +2108,8 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
    }
 
    /* Make sure the requested image format is compatible with the
-    * texture's format. We let the colorformat-indexformat go through,
-    * because the texelfetcher will dequantize to full rgba.
+    * texture's format.  Note that a color index texture can be converted
+    * to RGBA so that combo is allowed.
     */
    if (is_color_format(format)
        && !is_color_format(texImage->TexFormat->BaseFormat)
@@ -1971,7 +2123,8 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       return;
    }
    else if (is_depth_format(format)
-       && !is_depth_format(texImage->TexFormat->BaseFormat)) {
+       && !is_depth_format(texImage->TexFormat->BaseFormat)
+       && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
       return;
    }
@@ -1980,6 +2133,11 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
       return;
    }
+   else if (is_depthstencil_format(format)
+       && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+      return;
+   }
 
    /* typically, this will call _mesa_get_teximage() */
    ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
@@ -1988,6 +2146,36 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
 
 
 
+/**
+ * Check if the given texture image is bound to any framebuffer objects
+ * and update/invalidate them.
+ * XXX We're only checking the currently bound framebuffer object for now.
+ * In the future, perhaps struct gl_texture_image should have a pointer (or
+ * list of pointers (yikes)) to the gl_framebuffer(s) which it's bound to.
+ */
+static void
+update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
+                   GLuint face, GLuint level)
+{
+   if (ctx->DrawBuffer->Name) {
+      GLuint i;
+      for (i = 0; i < BUFFER_COUNT; i++) {
+         struct gl_renderbuffer_attachment *att = 
+            ctx->DrawBuffer->Attachment + i;
+         if (att->Type == GL_TEXTURE &&
+             att->Texture == texObj &&
+             att->TextureLevel == level &&
+             att->CubeMapFace == face) {
+            ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]);
+            /* Tell driver about the new renderbuffer texture */
+            ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+         }
+      }
+   }
+}
+
+
+
 /*
  * Called from the API.  Note that width includes the border.
  */
@@ -2009,6 +2197,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
+      const GLuint face = texture_face(target);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 1, postConvWidth, 1, 1, border)) {
@@ -2023,11 +2212,10 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         /* free the old texture data */
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
       clear_teximage_fields(texImage); /* not really needed, but helpful */
       _mesa_init_teximage_fields(ctx, target, texImage,
                                  postConvWidth, 1, 1,
@@ -2045,13 +2233,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
 
       ASSERT(texImage->TexFormat);
 
-      /* If driver didn't explicitly set this, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
+      update_fbo_texture(ctx, texObj, face, level);
 
       /* state update */
       texObj->Complete = GL_FALSE;
@@ -2109,6 +2291,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
+      const GLuint face = texture_face(target);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 2, postConvWidth, postConvHeight,
@@ -2123,11 +2306,10 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         /* free the old texture data */
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
       clear_teximage_fields(texImage); /* not really needed, but helpful */
       _mesa_init_teximage_fields(ctx, target, texImage,
                                  postConvWidth, postConvHeight, 1,
@@ -2145,13 +2327,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
 
       ASSERT(texImage->TexFormat);
 
-      /* If driver didn't explicitly set these, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
+      update_fbo_texture(ctx, texObj, face, level);
 
       /* state update */
       texObj->Complete = GL_FALSE;
@@ -2202,10 +2378,11 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    if (target == GL_TEXTURE_3D) {
+      /* non-proxy target */
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      /* non-proxy target */
+      const GLuint face = texture_face(target);
 
       if (texture_error_check(ctx, target, level, (GLint) internalFormat,
                               format, type, 3, width, height, depth, border)) {
@@ -2219,10 +2396,10 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
       clear_teximage_fields(texImage); /* not really needed, but helpful */
       _mesa_init_teximage_fields(ctx, target, texImage,
                                  width, height, depth,
@@ -2240,13 +2417,7 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
 
       ASSERT(texImage->TexFormat);
 
-      /* If driver didn't explicitly set these, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
+      update_fbo_texture(ctx, texObj, face, level);
 
       /* state update */
       texObj->Complete = GL_FALSE;
@@ -2438,6 +2609,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
+   const GLuint face = texture_face(target);
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2459,11 +2631,10 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
       return;
    }
-   else if (texImage->Data && !texImage->IsClientData) {
-      /* free the old texture data */
-      MESA_PBUFFER_FREE(texImage->Data);
+   else if (texImage->Data) {
+      ctx->Driver.FreeTexImageData( ctx, texImage );
    }
-   texImage->Data = NULL;
+   ASSERT(texImage->Data == NULL);
 
    clear_teximage_fields(texImage); /* not really needed, but helpful */
    _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
@@ -2476,13 +2647,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
 
    ASSERT(texImage->TexFormat);
 
-   /* If driver didn't explicitly set these, use the defaults */
-   if (!texImage->FetchTexelc)
-      texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
-   if (!texImage->FetchTexelf)
-      texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
-   ASSERT(texImage->FetchTexelc);
-   ASSERT(texImage->FetchTexelf);
+   update_fbo_texture(ctx, texObj, face, level);
 
    /* state update */
    texObj->Complete = GL_FALSE;
@@ -2500,6 +2665,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
+   const GLuint face = texture_face(target);
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2522,11 +2688,10 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
       return;
    }
-   else if (texImage->Data && !texImage->IsClientData) {
-      /* free the old texture data */
-      MESA_PBUFFER_FREE(texImage->Data);
+   else if (texImage->Data) {
+      ctx->Driver.FreeTexImageData( ctx, texImage );
    }
-   texImage->Data = NULL;
+   ASSERT(texImage->Data == NULL);
 
    clear_teximage_fields(texImage); /* not really needed, but helpful */
    _mesa_init_teximage_fields(ctx, target, texImage,
@@ -2539,13 +2704,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
 
    ASSERT(texImage->TexFormat);
 
-   /* If driver didn't explicitly set these, use the defaults */
-   if (!texImage->FetchTexelc)
-      texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
-   if (!texImage->FetchTexelf)
-      texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
-   ASSERT(texImage->FetchTexelc);
-   ASSERT(texImage->FetchTexelf);
+   update_fbo_texture(ctx, texObj, face, level);
 
    /* state update */
    texObj->Complete = GL_FALSE;
@@ -2681,7 +2840,7 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
                                GLsizei height, GLsizei depth, GLint border,
                                GLsizei imageSize)
 {
-   GLint expectedSize, maxLevels = 0, maxTextureSize;
+   GLint /**expectedSize,**/ maxLevels = 0, maxTextureSize;
 
    if (dimensions == 1) {
       /* 1D compressed textures not allowed */
@@ -2750,10 +2909,13 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
    if (level < 0 || level >= maxLevels)
       return GL_INVALID_VALUE;
 
+#if 0
+   /* XXX need to renable this code someday! */
    expectedSize = ctx->Driver.CompressedTextureSize(ctx, width, height, depth,
                                                     internalFormat);
    if (expectedSize != imageSize)
       return GL_INVALID_VALUE;
+#endif
 
    return GL_NO_ERROR;
 }
@@ -2872,10 +3034,10 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
 
       _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
                                  border, internalFormat);
@@ -2955,10 +3117,10 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
 
       _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
                                  border, internalFormat);
@@ -3037,10 +3199,10 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D");
          return;
       }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
+      else if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      texImage->Data = NULL;
+      ASSERT(texImage->Data == NULL);
 
       _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth,
                                  border, internalFormat);
@@ -3114,7 +3276,7 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
    texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
    assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
+   if ((GLint) format != texImage->InternalFormat) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCompressedTexSubImage1D(format)");
       return;
@@ -3164,7 +3326,7 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
    texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
    assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
+   if ((GLint) format != texImage->InternalFormat) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCompressedTexSubImage2D(format)");
       return;
@@ -3214,7 +3376,7 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
    texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
    assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
+   if ((GLint) format != texImage->InternalFormat) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCompressedTexSubImage3D(format)");
       return;
@@ -3266,7 +3428,7 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
       return;
    }
 
-   if (is_proxy_target(target)) {
+   if (_mesa_is_proxy_texture(target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
       return;
    }