mesa: Make condrender.[ch] prototypes match.
[mesa.git] / src / mesa / main / teximage.c
index 8228303040932feb47acb4b76a45c7481d5ca6d0..b946f3c69d7e846f9dc6c09ac60b377d4c82d62f 100644 (file)
@@ -33,9 +33,8 @@
 #include "glheader.h"
 #include "bufferobj.h"
 #include "context.h"
-#if FEATURE_convolve
 #include "convolve.h"
-#endif
+#include "enums.h"
 #include "fbobject.h"
 #include "framebuffer.h"
 #include "hash.h"
@@ -44,7 +43,7 @@
 #include "macros.h"
 #include "state.h"
 #include "texcompress.h"
-#include "texformat.h"
+#include "texfetch.h"
 #include "teximage.h"
 #include "texstate.h"
 #include "texstore.h"
@@ -83,63 +82,6 @@ _mesa_free_texmemory(void *m)
 }
 
 
-
-
-#if 0
-static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
-{
-#if CHAN_TYPE != GL_UNSIGNED_BYTE
-   _mesa_problem(NULL, "PrintTexture not supported");
-#else
-   GLuint i, j, c;
-   const GLubyte *data = (const GLubyte *) img->Data;
-
-   if (!data) {
-      _mesa_printf("No texture data\n");
-      return;
-   }
-
-   switch (img->Format) {
-      case GL_ALPHA:
-      case GL_LUMINANCE:
-      case GL_INTENSITY:
-      case GL_COLOR_INDEX:
-         c = 1;
-         break;
-      case GL_LUMINANCE_ALPHA:
-         c = 2;
-         break;
-      case GL_RGB:
-         c = 3;
-         break;
-      case GL_RGBA:
-         c = 4;
-         break;
-      default:
-         _mesa_problem(NULL, "error in PrintTexture\n");
-         return;
-   }
-
-   for (i = 0; i < img->Height; i++) {
-      for (j = 0; j < img->Width; j++) {
-         if (c==1)
-            _mesa_printf("%02x  ", data[0]);
-         else if (c==2)
-            _mesa_printf("%02x%02x  ", data[0], data[1]);
-         else if (c==3)
-            _mesa_printf("%02x%02x%02x  ", data[0], data[1], data[2]);
-         else if (c==4)
-            _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
-}
-#endif
-
-
 /*
  * Compute floor(log_base_2(n)).
  * If n < 0 return -1.
@@ -640,6 +582,17 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
 }
 
 
+/**
+ * Return pointer to texture object for given target on current texture unit.
+ */
+struct gl_texture_object *
+_mesa_get_current_tex_object(GLcontext *ctx, GLenum target)
+{
+   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+   return _mesa_select_tex_object(ctx, texUnit, target);
+}
+
+
 /**
  * Get a texture image pointer from a texture object, given a texture
  * target and mipmap level.  The target and level parameters should
@@ -901,11 +854,9 @@ clear_teximage_fields(struct gl_texture_image *img)
    img->HeightLog2 = 0;
    img->DepthLog2 = 0;
    img->Data = NULL;
-   img->TexFormat = &_mesa_null_texformat;
+   img->TexFormat = MESA_FORMAT_NONE;
    img->FetchTexelc = NULL;
    img->FetchTexelf = NULL;
-   img->IsCompressed = 0;
-   img->CompressedSize = 0;
 }
 
 
@@ -968,9 +919,6 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
 
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
 
-   img->IsCompressed = GL_FALSE;
-   img->CompressedSize = 0;
-
    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)))
@@ -1003,6 +951,9 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
       img->HeightScale = (GLfloat) img->Height;
       img->DepthScale = (GLfloat) img->Depth;
    }
+
+   img->FetchTexelc = NULL;
+   img->FetchTexelf = NULL;
 }
 
 
@@ -1316,8 +1267,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
    if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
       if (!isProxy) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(internalFormat=0x%x)",
-                     dimensions, internalFormat);
+                     "glTexImage%dD(internalFormat=%s)",
+                     dimensions, _mesa_lookup_enum_by_nr(internalFormat));
       }
       return GL_TRUE;
    }
@@ -1529,6 +1480,11 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
    return GL_FALSE;
 }
 
+
+/**
+ * Do second part of glTexSubImage which depends on the destination texture.
+ * \return GL_TRUE if error recorded, GL_FALSE otherwise
+ */
 static GLboolean
 subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
                         GLenum target, GLint level,
@@ -1576,41 +1532,35 @@ subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-#if FEATURE_EXT_texture_sRGB
-   if (destTex->InternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
-      if ((width & 0x3) || (height & 0x3) ||
-          (xoffset & 0x3) || (yoffset & 0x3))
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%dD(size or offset not multiple of 4)",
-                     dimensions);
-      return GL_TRUE;
-   }
-#endif
+   if (_mesa_is_format_compressed(destTex->TexFormat)) {
+      GLuint bw, bh;
 
-   if (destTex->IsCompressed) {
       if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexSubImage%D(target)", dimensions);
+                     "glTexSubImage%D(target=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(target));
          return GL_TRUE;
       }
-      /* offset must be multiple of 4 */
-      if ((xoffset & 3) || (yoffset & 3)) {
+
+      /* do tests which depend on compression block size */
+      _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
+
+      /* offset must be multiple of block size */
+      if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%D(xoffset or yoffset)", dimensions);
+                     "glTexSubImage%D(xoffset = %d, yoffset = %d)",
+                     dimensions, xoffset, yoffset);
          return GL_TRUE;
       }
-      /* size must be multiple of 4 or equal to whole texture size */
-      if ((width & 3) && (GLuint) width != destTex->Width) {
+      /* size must be multiple of bw by bh or equal to whole texture size */
+      if ((width % bw != 0) && (GLuint) width != destTex->Width) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%D(width)", dimensions);
+                     "glTexSubImage%D(width = %d)", dimensions, width);
          return GL_TRUE;
       }         
-      if ((height & 3) && (GLuint) height != destTex->Height) {
+      if ((height % bh != 0) && (GLuint) height != destTex->Height) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%D(width)", dimensions);
+                     "glTexSubImage%D(height = %d)", dimensions, height);
          return GL_TRUE;
       }         
    }
@@ -1952,7 +1902,7 @@ copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-   if (teximage->IsCompressed) {
+   if (_mesa_is_format_compressed(teximage->TexFormat)) {
       if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glCopyTexSubImage%d(target)", dimensions);
@@ -2075,6 +2025,25 @@ update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
 }
 
 
+/**
+ * If the texture object's GenerateMipmap flag is set and we've
+ * changed the texture base level image, regenerate the rest of the
+ * mipmap levels now.
+ */
+static INLINE void
+check_gen_mipmap(GLcontext *ctx, GLenum target,
+                 struct gl_texture_object *texObj, GLint level)
+{
+   ASSERT(target != GL_TEXTURE_CUBE_MAP);
+   if (texObj->GenerateMipmap &&
+       level == texObj->BaseLevel &&
+       level < texObj->MaxLevel) {
+      ASSERT(ctx->Driver.GenerateMipmap);
+      ctx->Driver.GenerateMipmap(ctx, target, texObj);
+   }
+}
+
+
 /** Debug helper: override the user-requested internal format */
 static GLenum
 override_internal_format(GLenum internalFormat, GLint width, GLint height)
@@ -2131,6 +2100,13 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexImage1D %s %d %s %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat), width, border,
+                  _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    internalFormat = override_internal_format(internalFormat, width, 1);
 
 #if FEATURE_convolve
@@ -2141,7 +2117,6 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
 
    if (target == GL_TEXTURE_1D) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       const GLuint face = _mesa_tex_target_to_face(target);
@@ -2154,43 +2129,50 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
-           goto out;
-        }
-      
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
         }
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+
+            ASSERT(texImage->Data == NULL);
+
+            clear_teximage_fields(texImage); /* not really needed, but helpful */
+            _mesa_init_teximage_fields(ctx, target, texImage,
+                                       postConvWidth, 1, 1,
+                                       border, internalFormat);
 
-        ASSERT(texImage->Data == NULL);
-
-        clear_teximage_fields(texImage); /* not really needed, but helpful */
-        _mesa_init_teximage_fields(ctx, target, texImage,
-                                   postConvWidth, 1, 1,
-                                   border, internalFormat);
-        
-        ASSERT(ctx->Driver.TexImage1D);
-
-        /* Give the texture to the driver!  <pixels> may be null! */
-        (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat,
-                                  width, border, format, type, pixels,
-                                  &ctx->Unpack, texObj, texImage);
-        
-        ASSERT(texImage->TexFormat);
-
-        update_fbo_texture(ctx, texObj, face, level);
-        
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
-      }
-   out:
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            /* Give the texture to the driver.  <pixels> may be null. */
+            ASSERT(ctx->Driver.TexImage1D);
+            ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+                                   width, border, format, type, pixels,
+                                   &ctx->Unpack, texObj, texImage);
+
+            ASSERT(texImage->TexFormat);
+
+            _mesa_set_fetch_functions(texImage, 1);
+
+            check_gen_mipmap(ctx, target, texObj, level);
+
+            update_fbo_texture(ctx, texObj, face, level);
+
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_1D) {
@@ -2209,8 +2191,8 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
          _mesa_init_teximage_fields(ctx, target, texImage,
                                     postConvWidth, 1, 1,
                                     border, internalFormat);
-         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
-                                          internalFormat, format, type);
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
       }
    }
    else {
@@ -2230,6 +2212,13 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexImage2D %s %d %s %d %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat), width, height,
+                  border, _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    internalFormat = override_internal_format(internalFormat, width, height);
 
 #if FEATURE_convolve
@@ -2248,7 +2237,6 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
        (ctx->Extensions.MESA_texture_array &&
         target == GL_TEXTURE_1D_ARRAY_EXT)) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       const GLuint face = _mesa_tex_target_to_face(target);
@@ -2262,42 +2250,49 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
-           goto out;
         }
-        
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
-        }
-        
-        ASSERT(texImage->Data == NULL);
-        clear_teximage_fields(texImage); /* not really needed, but helpful */
-        _mesa_init_teximage_fields(ctx, target, texImage,
-                                   postConvWidth, postConvHeight, 1,
-                                   border, internalFormat);
-        
-        ASSERT(ctx->Driver.TexImage2D);
-
-        /* Give the texture to the driver!  <pixels> may be null! */
-        (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat,
-                                  width, height, border, format, type, pixels,
-                                  &ctx->Unpack, texObj, texImage);
-        
-        ASSERT(texImage->TexFormat);
-
-        update_fbo_texture(ctx, texObj, face, level);
-
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
-      }
-   out:
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+
+            ASSERT(texImage->Data == NULL);
+            clear_teximage_fields(texImage); /* not really needed, but helpful */
+            _mesa_init_teximage_fields(ctx, target, texImage,
+                                       postConvWidth, postConvHeight, 1,
+                                       border, internalFormat);
+
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            /* Give the texture to the driver.  <pixels> may be null. */
+            ASSERT(ctx->Driver.TexImage2D);
+            ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+                                   width, height, border, format, type,
+                                   pixels, &ctx->Unpack, texObj, texImage);
+
+            ASSERT(texImage->TexFormat);
+
+            _mesa_set_fetch_functions(texImage, 2);
+
+            check_gen_mipmap(ctx, target, texObj, level);
+
+            update_fbo_texture(ctx, texObj, face, level);
+
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_2D ||
@@ -2322,8 +2317,8 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
          _mesa_init_teximage_fields(ctx, target, texImage,
                                     postConvWidth, postConvHeight, 1,
                                     border, internalFormat);
-         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
-                                          internalFormat, format, type);
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
       }
    }
    else {
@@ -2346,13 +2341,19 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexImage3D %s %d %s %d %d %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat), width, height,
+                  depth, border, _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    internalFormat = override_internal_format(internalFormat, width, height);
 
    if (target == GL_TEXTURE_3D ||
        (ctx->Extensions.MESA_texture_array &&
         target == GL_TEXTURE_2D_ARRAY_EXT)) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       const GLuint face = _mesa_tex_target_to_face(target);
@@ -2365,42 +2366,49 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
-           goto out;
-        }
-        
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
         }
-        
-        ASSERT(texImage->Data == NULL);
-        clear_teximage_fields(texImage); /* not really needed, but helpful */
-        _mesa_init_teximage_fields(ctx, target, texImage,
-                                   width, height, depth,
-                                   border, internalFormat);
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+
+            ASSERT(texImage->Data == NULL);
+            clear_teximage_fields(texImage); /* not really needed, but helpful */
+            _mesa_init_teximage_fields(ctx, target, texImage,
+                                       width, height, depth,
+                                       border, internalFormat);
+
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            /* Give the texture to the driver.  <pixels> may be null. */
+            ASSERT(ctx->Driver.TexImage3D);
+            ctx->Driver.TexImage3D(ctx, target, level, internalFormat,
+                                   width, height, depth, border, format, type,
+                                   pixels, &ctx->Unpack, texObj, texImage);
 
-        ASSERT(ctx->Driver.TexImage3D);
+            ASSERT(texImage->TexFormat);
 
-        /* Give the texture to the driver!  <pixels> may be null! */
-        (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat,
-                                  width, height, depth, border, format, type,
-                                  pixels, &ctx->Unpack, texObj, texImage);
+            _mesa_set_fetch_functions(texImage, 3);
 
-        ASSERT(texImage->TexFormat);
+            check_gen_mipmap(ctx, target, texObj, level);
 
-        update_fbo_texture(ctx, texObj, face, level);
+            update_fbo_texture(ctx, texObj, face, level);
 
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
       }
-   out:
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_3D ||
@@ -2419,8 +2427,8 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
          /* no error, set the tex image parameters */
          _mesa_init_teximage_fields(ctx, target, texImage, width, height,
                                     depth, border, internalFormat);
-         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
-                                          internalFormat, format, type);
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
       }
    }
    else {
@@ -2449,12 +2457,17 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GLsizei postConvWidth = width;
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage = NULL;
+   struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexSubImage1D %s %d %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  xoffset, width, _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
       _mesa_update_state(ctx);
 
@@ -2471,8 +2484,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    }
 
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
    assert(texObj);
 
    _mesa_lock_texture(ctx, texObj);
@@ -2480,23 +2492,24 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
       if (subtexture_error_check2(ctx, 1, target, level, xoffset, 0, 0,
-                                 postConvWidth, 1, 1, format, type, texImage)) {
-        goto out;   /* error was detected */
+                                 postConvWidth, 1, 1,
+                                  format, type, texImage)) {
+         /* error was recorded */
       }
+      else if (width > 0) {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
 
-      if (width == 0)
-        goto out;  /* no-op, not an error */
+         ASSERT(ctx->Driver.TexSubImage1D);
+         ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width,
+                                   format, type, pixels, &ctx->Unpack,
+                                   texObj, texImage);
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      ASSERT(ctx->Driver.TexSubImage1D);
-      (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
-                                  format, type, pixels, &ctx->Unpack,
-                                  texObj, texImage);
-      ctx->NewState |= _NEW_TEXTURE;
+         ctx->NewState |= _NEW_TEXTURE;
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2509,12 +2522,18 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GLsizei postConvWidth = width, postConvHeight = height;
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexSubImage2D %s %d %d %d %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  xoffset, yoffset, width, height,
+                  _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
       _mesa_update_state(ctx);
 
@@ -2531,32 +2550,32 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
       return;   /* error was detected */
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
+
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
       if (subtexture_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
-                                 postConvWidth, postConvHeight, 1, format, type, 
-                                 texImage)) {
-        goto out;   /* error was detected */
+                                 postConvWidth, postConvHeight, 1,
+                                  format, type, texImage)) {
+        /* error was recorded */
       }
+      else if (width > 0 && height >= 0) {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
+         yoffset += texImage->Border;
+
+         ASSERT(ctx->Driver.TexSubImage2D);
+         ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset,
+                                   width, height, format, type, pixels,
+                                   &ctx->Unpack, texObj, texImage);
 
-      if (width == 0 || height == 0)
-        goto out;  /* no-op, not an error */
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
-      yoffset += texImage->Border;
-      
-      ASSERT(ctx->Driver.TexSubImage2D);
-      (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset,
-                                  width, height, format, type, pixels,
-                                  &ctx->Unpack, texObj, texImage);
-      ctx->NewState |= _NEW_TEXTURE;
+         ctx->NewState |= _NEW_TEXTURE;
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2569,12 +2588,18 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
                      GLenum format, GLenum type,
                      const GLvoid *pixels )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexSubImage3D %s %d %d %d %d %d %d %d %s %s %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  xoffset, yoffset, zoffset, width, height, depth,
+                  _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type), pixels);
+
    if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
       _mesa_update_state(ctx);
 
@@ -2583,35 +2608,36 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
       return;   /* error was detected */
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-      if (subtexture_error_check2(ctx, 3, target, level, xoffset, yoffset, zoffset,
-                                 width, height, depth, format, type, texImage)) {
-        goto out;   /* error was detected */
+      if (subtexture_error_check2(ctx, 3, target, level,
+                                  xoffset, yoffset, zoffset,
+                                 width, height, depth,
+                                  format, type, texImage)) {
+         /* error was recorded */
       }
+      else if (width > 0 && height > 0 && height > 0) {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
+         yoffset += texImage->Border;
+         zoffset += texImage->Border;
 
-      if (width == 0 || height == 0 || height == 0)
-        goto out;  /* no-op, not an error */
+         ASSERT(ctx->Driver.TexSubImage3D);
+         ctx->Driver.TexSubImage3D(ctx, target, level,
+                                   xoffset, yoffset, zoffset,
+                                   width, height, depth,
+                                   format, type, pixels,
+                                   &ctx->Unpack, texObj, texImage );
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
-      yoffset += texImage->Border;
-      zoffset += texImage->Border;
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      ASSERT(ctx->Driver.TexSubImage3D);
-      (*ctx->Driver.TexSubImage3D)(ctx, target, level,
-                                  xoffset, yoffset, zoffset,
-                                  width, height, depth,
-                                  format, type, pixels,
-                                  &ctx->Unpack, texObj, texImage );
-      ctx->NewState |= _NEW_TEXTURE;
+         ctx->NewState |= _NEW_TEXTURE;
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2623,7 +2649,6 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
                       GLint x, GLint y,
                       GLsizei width, GLint border )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
@@ -2631,6 +2656,12 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexImage1D %s %d %s %d %d %d %d\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  x, y, width, border);
+
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
@@ -2644,40 +2675,48 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
                                postConvWidth, 1, border))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
+
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_get_tex_image(ctx, texObj, target, level);
       if (!texImage) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
-        goto out;
       }
+      else {
+         if (texImage->Data) {
+            ctx->Driver.FreeTexImageData( ctx, texImage );
+         }
 
-      if (texImage->Data) {
-        ctx->Driver.FreeTexImageData( ctx, texImage );
-      }
-      
-      ASSERT(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,
+                                    border, internalFormat);
+
+         /* Choose actual texture format */
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                            GL_NONE, GL_NONE);
+         ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
 
-      clear_teximage_fields(texImage); /* not really needed, but helpful */
-      _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
-                                border, internalFormat);
+         ASSERT(ctx->Driver.CopyTexImage1D);
+         ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
+                                    x, y, width, border);
 
+         ASSERT(texImage->TexFormat);
 
-      ASSERT(ctx->Driver.CopyTexImage1D);
-      (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat,
-                                   x, y, width, border);
+         _mesa_set_fetch_functions(texImage, 1);
 
-      ASSERT(texImage->TexFormat);
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      update_fbo_texture(ctx, texObj, face, level);
+         update_fbo_texture(ctx, texObj, face, level);
 
-      /* state update */
-      texObj->_Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+         /* state update */
+         texObj->_Complete = GL_FALSE;
+         ctx->NewState |= _NEW_TEXTURE;
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2688,7 +2727,6 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                       GLint x, GLint y, GLsizei width, GLsizei height,
                       GLint border )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
@@ -2696,6 +2734,12 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexImage2D %s %d %s %d %d %d %d %d\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  x, y, width, height, border);
+
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
@@ -2710,8 +2754,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                                postConvWidth, postConvHeight, border))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2719,33 +2762,42 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
 
       if (!texImage) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
-        goto out;
-      }
-      
-      if (texImage->Data) {
-        ctx->Driver.FreeTexImageData( ctx, texImage );
       }
-      
-      ASSERT(texImage->Data == NULL);
+      else {
+         if (texImage->Data) {
+            ctx->Driver.FreeTexImageData( ctx, texImage );
+         }
+
+         ASSERT(texImage->Data == NULL);
+
+         clear_teximage_fields(texImage); /* not really needed, but helpful */
+         _mesa_init_teximage_fields(ctx, target, texImage,
+                                    postConvWidth, postConvHeight, 1,
+                                    border, internalFormat);
+
+         /* Choose actual texture format */
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                            GL_NONE, GL_NONE);
+         ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+         ASSERT(ctx->Driver.CopyTexImage2D);
+         ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
+                                    x, y, width, height, border);
+
+         ASSERT(texImage->TexFormat);
+
+         _mesa_set_fetch_functions(texImage, 2);
 
-      clear_teximage_fields(texImage); /* not really needed, but helpful */
-      _mesa_init_teximage_fields(ctx, target, texImage,
-                                postConvWidth, postConvHeight, 1,
-                                border, internalFormat);
-      
-      ASSERT(ctx->Driver.CopyTexImage2D);
-      (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat,
-                                   x, y, width, height, border);
-      
-      ASSERT(texImage->TexFormat);
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      update_fbo_texture(ctx, texObj, face, level);
+         update_fbo_texture(ctx, texObj, face, level);
 
-      /* state update */
-      texObj->_Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+         /* state update */
+         texObj->_Complete = GL_FALSE;
+         ctx->NewState |= _NEW_TEXTURE;
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2754,7 +2806,6 @@ void GLAPIENTRY
 _mesa_CopyTexSubImage1D( GLenum target, GLint level,
                          GLint xoffset, GLint x, GLint y, GLsizei width )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
@@ -2764,14 +2815,18 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexSubImage1D %s %d %d %d %d %d\n",
+                  _mesa_lookup_enum_by_nr(target),
+                  level, xoffset, x, y, width);
+
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
    if (copytexsubimage_error_check1(ctx, 1, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2785,23 +2840,25 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
 
       if (copytexsubimage_error_check2(ctx, 1, target, level,
                                       xoffset, 0, 0, postConvWidth, 1,
-                                      texImage))
-        goto out;
-      
+                                      texImage)) {
+         /* error was recorded */
+      }
+      else {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
+         if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                        &width, &height)) {
+            ASSERT(ctx->Driver.CopyTexSubImage1D);
+            ctx->Driver.CopyTexSubImage1D(ctx, target, level,
+                                          xoffset, x, y, width);
 
-      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
-                                     &width, &height)) {
-         ASSERT(ctx->Driver.CopyTexSubImage1D);
-         ctx->Driver.CopyTexSubImage1D(ctx, target, level,
-                                       xoffset, x, y, width);
-      }
+            check_gen_mipmap(ctx, target, texObj, level);
 
-      ctx->NewState |= _NEW_TEXTURE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2812,21 +2869,24 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
                          GLint xoffset, GLint yoffset,
                          GLint x, GLint y, GLsizei width, GLsizei height )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexSubImage2D %s %d %d %d %d %d %d %d\n",
+                  _mesa_lookup_enum_by_nr(target),
+                  level, xoffset, yoffset, x, y, width, height);
+
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
    if (copytexsubimage_error_check1(ctx, 2, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2839,24 +2899,29 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
       }
 #endif
 
-      if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
-                                      postConvWidth, postConvHeight, texImage))
-        goto out;
+      if (copytexsubimage_error_check2(ctx, 2, target, level,
+                                       xoffset, yoffset, 0,
+                                      postConvWidth, postConvHeight,
+                                       texImage)) {
+         /* error was recorded */
+      }
+      else {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
+         yoffset += texImage->Border;
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
-      yoffset += texImage->Border;
+         if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                        &width, &height)) {
+            ASSERT(ctx->Driver.CopyTexSubImage2D);
+            ctx->Driver.CopyTexSubImage2D(ctx, target, level, xoffset, yoffset,
+                                          x, y, width, height);
 
-      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
-                                     &width, &height)) {
-         ASSERT(ctx->Driver.CopyTexSubImage2D);
-         ctx->Driver.CopyTexSubImage2D(ctx, target, level,
-                                      xoffset, yoffset, x, y, width, height);
-      }
+            check_gen_mipmap(ctx, target, texObj, level);
 
-      ctx->NewState |= _NEW_TEXTURE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2867,21 +2932,24 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
                          GLint xoffset, GLint yoffset, GLint zoffset,
                          GLint x, GLint y, GLsizei width, GLsizei height )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexSubImage3D %s %d %d %d %d %d %d %d %d\n",
+                  _mesa_lookup_enum_by_nr(target),
+                  level, xoffset, yoffset, zoffset, x, y, width, height);
+
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
    if (copytexsubimage_error_check1(ctx, 3, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2896,25 +2964,28 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
 
       if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset,
                                       zoffset, postConvWidth, postConvHeight,
-                                      texImage))
-        goto out;
-
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
-      yoffset += texImage->Border;
-      zoffset += texImage->Border;
-      
-      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
-                                     &width, &height)) {
-         ASSERT(ctx->Driver.CopyTexSubImage3D);
-         ctx->Driver.CopyTexSubImage3D(ctx, target, level,
-                                      xoffset, yoffset, zoffset,
-                                      x, y, width, height);
+                                      texImage)) {
+         /* error was recored */
       }
+      else {
+         /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+         xoffset += texImage->Border;
+         yoffset += texImage->Border;
+         zoffset += texImage->Border;
+
+         if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                        &width, &height)) {
+            ASSERT(ctx->Driver.CopyTexSubImage3D);
+            ctx->Driver.CopyTexSubImage3D(ctx, target, level,
+                                          xoffset, yoffset, zoffset,
+                                          x, y, width, height);
+
+            check_gen_mipmap(ctx, target, texObj, level);
 
-      ctx->NewState |= _NEW_TEXTURE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
@@ -2926,6 +2997,29 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
 /**********************************************************************/
 
 
+/**
+ * Return expected size of a compressed texture.
+ */
+static GLuint
+compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth,
+                    GLenum glformat)
+{
+   gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
+   return _mesa_format_image_size(mesaFormat, width, height, depth);
+}
+
+
+/*
+ * Return compressed texture block size, in pixels.
+ */
+static void
+get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
+{
+   gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
+   _mesa_get_format_block_size(mesaFormat, bw, bh);
+}
+
+
 /**
  * Error checking for glCompressedTexImage[123]D().
  * \return error code or GL_NO_ERROR.
@@ -3008,8 +3102,7 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
    if (level < 0 || level >= maxLevels)
       return GL_INVALID_VALUE;
 
-   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
-                                                       depth, internalFormat);
+   expectedSize = compressed_tex_size(width, height, depth, internalFormat);
    if (expectedSize != imageSize)
       return GL_INVALID_VALUE;
 
@@ -3042,6 +3135,7 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
                                   GLenum format, GLsizei imageSize)
 {
    GLint expectedSize, maxLevels = 0, maxTextureSize;
+   GLuint bw, bh;
    (void) zoffset;
 
    if (dimensions == 1) {
@@ -3091,20 +3185,21 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
    if (level < 0 || level >= maxLevels)
       return GL_INVALID_VALUE;
 
-   /* XXX these tests are specific to the compressed format.
-    * this code should be generalized in some way.
+   /*
+    * do checks which depend on compression block size
     */
-   if ((xoffset & 3) != 0 || (yoffset & 3) != 0)
+   get_compressed_block_size(format, &bw, &bh);
+
+   if ((xoffset % bw != 0) || (yoffset % bh != 0))
       return GL_INVALID_VALUE;
 
-   if ((width & 3) != 0 && width != 2 && width != 1)
+   if ((width % bw != 0) && width != 2 && width != 1)
       return GL_INVALID_VALUE;
 
-   if ((height & 3) != 0 && height != 2 && height != 1)
+   if ((height % bh != 0) && height != 2 && height != 1)
       return GL_INVALID_VALUE;
 
-   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
-                                                       depth, format);
+   expectedSize = compressed_tex_size(width, height, depth, format);
    if (expectedSize != imageSize)
       return GL_INVALID_VALUE;
 
@@ -3112,6 +3207,55 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
 }
 
 
+/**
+ * Do second part of glCompressedTexSubImage error checking.
+ * \return GL_TRUE if error found, GL_FALSE otherwise.
+ */
+static GLboolean
+compressed_subtexture_error_check2(GLcontext *ctx, GLuint dims,
+                                   GLsizei width, GLsizei height,
+                                   GLsizei depth, GLenum format,
+                                   struct gl_texture_image *texImage)
+{
+
+   if ((GLint) format != texImage->InternalFormat) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCompressedTexSubImage%uD(format=0x%x)", dims, format);
+      return GL_TRUE;
+   }
+
+   if (((width == 1 || width == 2) &&
+        (GLuint) width != texImage->Width) ||
+       (width > texImage->Width)) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glCompressedTexSubImage%uD(width=%d)", dims, width);
+      return GL_TRUE;
+   }
+
+   if (dims >= 2) {
+      if (((height == 1 || height == 2) &&
+           (GLuint) height != texImage->Height) ||
+          (height > texImage->Height)) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCompressedTexSubImage%uD(height=%d)", dims, height);
+         return GL_TRUE;
+      }
+   }
+
+   if (dims >= 3) {
+      if (((depth == 1 || depth == 2) &&
+           (GLuint) depth != texImage->Depth) ||
+          (depth > texImage->Depth)) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCompressedTexSubImage%uD(depth=%d)", dims, depth);
+         return GL_TRUE;
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
 
 void GLAPIENTRY
 _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
@@ -3122,9 +3266,14 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCompressedTexImage1DARB %s %d %s %d %d %d %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  width, border, imageSize, data);
+
    if (target == GL_TEXTURE_1D) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       GLenum error = compressed_texture_error_check(ctx, 1, target, level,
@@ -3134,36 +3283,44 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
 
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D");
-           goto out;
-        }
-        
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
         }
-        ASSERT(texImage->Data == NULL);
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+            ASSERT(texImage->Data == NULL);
+
+            _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
+                                       border, internalFormat);
+
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            ASSERT(ctx->Driver.CompressedTexImage1D);
+            ctx->Driver.CompressedTexImage1D(ctx, target, level,
+                                             internalFormat, width, border,
+                                             imageSize, data,
+                                             texObj, texImage);
 
-        _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
-                                   border, internalFormat);
+            _mesa_set_fetch_functions(texImage, 1);
 
-        ASSERT(ctx->Driver.CompressedTexImage1D);
-        (*ctx->Driver.CompressedTexImage1D)(ctx, target, level,
-                                            internalFormat, width, border,
-                                            imageSize, data,
-                                            texObj, texImage);
+            check_gen_mipmap(ctx, target, texObj, level);
 
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
       }
-   out:
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_1D) {
@@ -3185,11 +3342,10 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
 
         _mesa_lock_texture(ctx, texObj);
         {
@@ -3216,14 +3372,20 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCompressedTexImage2DARB %s %d %s %d %d %d %d %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  width, height, border, imageSize, data);
+
    if (target == GL_TEXTURE_2D ||
        (ctx->Extensions.ARB_texture_cube_map &&
         target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
         target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
+
       GLenum error = compressed_texture_error_check(ctx, 2, target, level,
                           internalFormat, width, height, 1, border, imageSize);
       if (error) {
@@ -3231,36 +3393,44 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
 
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
-           goto out;
-        }
-        
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
         }
-        ASSERT(texImage->Data == NULL);
-
-        _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
-                                   border, internalFormat);
-
-        ASSERT(ctx->Driver.CompressedTexImage2D);
-        (*ctx->Driver.CompressedTexImage2D)(ctx, target, level,
-                                            internalFormat, width, height,
-                                            border, imageSize, data,
-                                            texObj, texImage);
-        
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
-      }
-   out:
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+            ASSERT(texImage->Data == NULL);
+
+            _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
+                                       border, internalFormat);
+
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            ASSERT(ctx->Driver.CompressedTexImage2D);
+            ctx->Driver.CompressedTexImage2D(ctx, target, level,
+                                             internalFormat, width, height,
+                                             border, imageSize, data,
+                                             texObj, texImage);
+
+            _mesa_set_fetch_functions(texImage, 2);
+
+            check_gen_mipmap(ctx, target, texObj, level);
+
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_2D ||
@@ -3284,11 +3454,10 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
 
         _mesa_lock_texture(ctx, texObj);
         {
@@ -3315,9 +3484,14 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCompressedTexImage3DARB %s %d %s %d %d %d %d %d %p\n",
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  width, height, depth, border, imageSize, data);
+
    if (target == GL_TEXTURE_3D) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       GLenum error = compressed_texture_error_check(ctx, 3, target, level,
@@ -3327,36 +3501,46 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
+
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
         if (!texImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D");
-           goto out;
-        }
-        
-        if (texImage->Data) {
-           ctx->Driver.FreeTexImageData( ctx, texImage );
         }
-        ASSERT(texImage->Data == NULL);
-
-        _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth,
-                                   border, internalFormat);
-
-        ASSERT(ctx->Driver.CompressedTexImage3D);
-        (*ctx->Driver.CompressedTexImage3D)(ctx, target, level,
-                                            internalFormat,
-                                            width, height, depth,
-                                            border, imageSize, data,
-                                            texObj, texImage);
-        
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
-      }
-   out:
+         else {
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+            ASSERT(texImage->Data == NULL);
+
+            _mesa_init_teximage_fields(ctx, target, texImage,
+                                       width, height, depth,
+                                       border, internalFormat);
+
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
+            ASSERT(ctx->Driver.CompressedTexImage3D);
+            ctx->Driver.CompressedTexImage3D(ctx, target, level,
+                                             internalFormat,
+                                             width, height, depth,
+                                             border, imageSize, data,
+                                             texObj, texImage);
+
+            _mesa_set_fetch_functions(texImage, 3);
+
+            check_gen_mipmap(ctx, target, texObj, level);
+
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+      }
       _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_3D) {
@@ -3378,11 +3562,11 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
+
         _mesa_lock_texture(ctx, texObj);
         {
            texImage = _mesa_select_tex_image(ctx, texObj, target, level);
@@ -3399,116 +3583,100 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
 }
 
 
-void GLAPIENTRY
-_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
-                                 GLsizei width, GLenum format,
-                                 GLsizei imageSize, const GLvoid *data)
+/**
+ * Common helper for glCompressedTexSubImage1/2/3D().
+ */
+static void
+compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
+                         GLint xoffset, GLint yoffset, GLint zoffset,
+                         GLsizei width, GLsizei height, GLsizei depth,
+                         GLenum format, GLsizei imageSize, const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLenum error;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   error = compressed_subtexture_error_check(ctx, 1, target, level,
+   error = compressed_subtexture_error_check(ctx, dims, target, level,
                                              xoffset, 0, 0, /* pos */
-                                             width, 1, 1,   /* size */
+                                             width, height, depth,   /* size */
                                              format, imageSize);
    if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage1D");
+      _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims);
       return;
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
+
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
       assert(texImage);
 
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage1D(format)");
-        goto out;
-      }
+      if (compressed_subtexture_error_check2(ctx, dims, width, height, depth,
+                                             format, texImage)) {
+         /* error was recorded */
+      }
+      else if (width > 0 && height > 0 && depth > 0) {
+         switch (dims) {
+         case 1:
+            if (ctx->Driver.CompressedTexSubImage1D) {
+               ctx->Driver.CompressedTexSubImage1D(ctx, target, level,
+                                                   xoffset, width,
+                                                   format, imageSize, data,
+                                                   texObj, texImage);
+            }
+            break;
+         case 2:
+            if (ctx->Driver.CompressedTexSubImage2D) {
+               ctx->Driver.CompressedTexSubImage2D(ctx, target, level,
+                                                   xoffset, yoffset,
+                                                   width, height,
+                                                   format, imageSize, data,
+                                                   texObj, texImage);
+            }
+            break;
+         case 3:
+            if (ctx->Driver.CompressedTexSubImage3D) {
+               ctx->Driver.CompressedTexSubImage3D(ctx, target, level,
+                                                   xoffset, yoffset, zoffset,
+                                                   width, height, depth,
+                                                   format, imageSize, data,
+                                                   texObj, texImage);
+            }
+            break;
+         default:
+            ;
+         }
 
-      if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) {
-        _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)");
-        goto out;
-      }
-      
-      if (width == 0)
-        goto out;  /* no-op, not an error */
+         check_gen_mipmap(ctx, target, texObj, level);
 
-      if (ctx->Driver.CompressedTexSubImage1D) {
-        (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level,
-                                               xoffset, width,
-                                               format, imageSize, data,
-                                               texObj, texImage);
+         ctx->NewState |= _NEW_TEXTURE;
       }
-      ctx->NewState |= _NEW_TEXTURE;
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
 
+void GLAPIENTRY
+_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
+                                 GLsizei width, GLenum format,
+                                 GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1,
+                            format, imageSize, data);
+}
+
+
 void GLAPIENTRY
 _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
                                  GLint yoffset, GLsizei width, GLsizei height,
                                  GLenum format, GLsizei imageSize,
                                  const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLenum error;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   error = compressed_subtexture_error_check(ctx, 2, target, level,
-                                             xoffset, yoffset, 0, /* pos */
-                                             width, height, 1,    /* size */
-                                             format, imageSize);
-   if (error) {
-      /* XXX proxy target? */
-      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
-      return;
-   }
-
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      assert(texImage);
-
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage2D(format)");
-        goto out;
-      }
-
-      if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) ||
-         ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) {
-        _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)");
-        goto out;
-      }
-      
-      if (width == 0 || height == 0)
-        goto out;  /* no-op, not an error */
-
-      if (ctx->Driver.CompressedTexSubImage2D) {
-        (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level,
-                                               xoffset, yoffset, width, height,
-                                               format, imageSize, data,
-                                               texObj, texImage);
-      }
-      ctx->NewState |= _NEW_TEXTURE;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+   compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data);
 }
 
 
@@ -3518,56 +3686,8 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
                                  GLsizei height, GLsizei depth, GLenum format,
                                  GLsizei imageSize, const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLenum error;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   error = compressed_subtexture_error_check(ctx, 3, target, level,
-                                             xoffset, yoffset, zoffset,/*pos*/
-                                             width, height, depth, /*size*/
-                                             format, imageSize);
-   if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage3D");
-      return;
-   }
-
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      assert(texImage);
-
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage3D(format)");
-        goto out;
-      }
-
-      if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) ||
-         ((height == 1 || height == 2) && (GLuint) height != texImage->Height) ||
-         ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) {
-        _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)");
-        goto out;
-      }
-      
-      if (width == 0 || height == 0 || depth == 0)
-        goto out;  /* no-op, not an error */
-
-      if (ctx->Driver.CompressedTexSubImage3D) {
-        (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level,
-                                               xoffset, yoffset, zoffset,
-                                               width, height, depth,
-                                               format, imageSize, data,
-                                               texObj, texImage);
-      }
-      ctx->NewState |= _NEW_TEXTURE;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+   compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset,
+                            width, height, depth, format, imageSize, data);
 }