mesa: fix num_draw_buffers==0 in fixed-function fragment program generation
[mesa.git] / src / mesa / main / teximage.c
index 825f5e26bff7dc79c55fb3154323a3293343d843..47d509396a788857a4e2a4d3416b4053cb4229fb 100644 (file)
 #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"
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
+#include "mfeatures.h"
 #include "state.h"
 #include "texcompress.h"
-#include "texformat.h"
+#include "texfetch.h"
 #include "teximage.h"
 #include "texstate.h"
-#include "texstore.h"
+#include "texpal.h"
 #include "mtypes.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.
@@ -182,9 +124,11 @@ logbase2( int n )
  *
  * This is the format which is used during texture application (i.e. the
  * texture format and env mode determine the arithmetic used.
+ *
+ * XXX this could be static
  */
 GLint
-_mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
+_mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
 {
    switch (internalFormat) {
       case GL_ALPHA:
@@ -397,253 +341,166 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
          return GL_RGBA;
       case GL_SLUMINANCE_ALPHA_EXT:
       case GL_SLUMINANCE8_ALPHA8_EXT:
-      case GL_COMPRESSED_SLUMINANCE_EXT:
       case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
          return GL_LUMINANCE_ALPHA;
       case GL_SLUMINANCE_EXT:
       case GL_SLUMINANCE8_EXT:
+      case GL_COMPRESSED_SLUMINANCE_EXT:
          return GL_LUMINANCE;
       default:
-            ; /* fallthrough */
+         ; /* fallthrough */
       }
    }
-
 #endif /* FEATURE_EXT_texture_sRGB */
 
-   return -1; /* error */
-}
-
-
-/**
- * Test if the given image format is a color/RGBA format (i.e., not color
- * index, depth, stencil, etc).
- * \param format  the image format value (may by an internal texture format)
- * \return GL_TRUE if its a color/RGBA format, GL_FALSE otherwise.
- * XXX maybe move this func to image.c
- */
-GLboolean
-_mesa_is_color_format(GLenum format)
-{
-   switch (format) {
-      case GL_RED:
-      case GL_GREEN:
-      case GL_BLUE:
-      case GL_ALPHA:
-      case GL_ALPHA4:
-      case GL_ALPHA8:
-      case GL_ALPHA12:
-      case GL_ALPHA16:
-      case 1:
-      case GL_LUMINANCE:
-      case GL_LUMINANCE4:
-      case GL_LUMINANCE8:
-      case GL_LUMINANCE12:
-      case GL_LUMINANCE16:
-      case 2:
-      case GL_LUMINANCE_ALPHA:
-      case GL_LUMINANCE4_ALPHA4:
-      case GL_LUMINANCE6_ALPHA2:
-      case GL_LUMINANCE8_ALPHA8:
-      case GL_LUMINANCE12_ALPHA4:
-      case GL_LUMINANCE12_ALPHA12:
-      case GL_LUMINANCE16_ALPHA16:
-      case GL_INTENSITY:
-      case GL_INTENSITY4:
-      case GL_INTENSITY8:
-      case GL_INTENSITY12:
-      case GL_INTENSITY16:
-      case 3:
-      case GL_RGB:
-      case GL_BGR:
-      case GL_R3_G3_B2:
-      case GL_RGB4:
-      case GL_RGB5:
-      case GL_RGB8:
-      case GL_RGB10:
-      case GL_RGB12:
-      case GL_RGB16:
-      case 4:
-      case GL_ABGR_EXT:
-      case GL_RGBA:
-      case GL_BGRA:
-      case GL_RGBA2:
-      case GL_RGBA4:
-      case GL_RGB5_A1:
-      case GL_RGBA8:
-      case GL_RGB10_A2:
-      case GL_RGBA12:
-      case GL_RGBA16:
-      /* float texture formats */
-      case GL_ALPHA16F_ARB:
-      case GL_ALPHA32F_ARB:
-      case GL_LUMINANCE16F_ARB:
-      case GL_LUMINANCE32F_ARB:
-      case GL_LUMINANCE_ALPHA16F_ARB:
-      case GL_LUMINANCE_ALPHA32F_ARB:
-      case GL_INTENSITY16F_ARB:
-      case GL_INTENSITY32F_ARB:
-      case GL_RGB16F_ARB:
-      case GL_RGB32F_ARB:
-      case GL_RGBA16F_ARB:
-      case GL_RGBA32F_ARB:
-      /* compressed formats */
-      case GL_COMPRESSED_ALPHA:
-      case GL_COMPRESSED_LUMINANCE:
-      case GL_COMPRESSED_LUMINANCE_ALPHA:
-      case GL_COMPRESSED_INTENSITY:
-      case GL_COMPRESSED_RGB:
-      case GL_COMPRESSED_RGBA:
-      case GL_RGB_S3TC:
-      case GL_RGB4_S3TC:
-      case GL_RGBA_S3TC:
-      case GL_RGBA4_S3TC:
-      case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-      case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-      case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-      case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-      case GL_COMPRESSED_RGB_FXT1_3DFX:
-      case GL_COMPRESSED_RGBA_FXT1_3DFX:
-#if FEATURE_EXT_texture_sRGB
-      case GL_SRGB_EXT:
-      case GL_SRGB8_EXT:
-      case GL_SRGB_ALPHA_EXT:
-      case GL_SRGB8_ALPHA8_EXT:
-      case GL_SLUMINANCE_ALPHA_EXT:
-      case GL_SLUMINANCE8_ALPHA8_EXT:
-      case GL_SLUMINANCE_EXT:
-      case GL_SLUMINANCE8_EXT:
-      case GL_COMPRESSED_SRGB_EXT:
-      case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-      case GL_COMPRESSED_SRGB_ALPHA_EXT:
-      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-      case GL_COMPRESSED_SLUMINANCE_EXT:
-      case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
-#endif /* FEATURE_EXT_texture_sRGB */
-         return GL_TRUE;
-      /* signed texture formats */
-      case GL_RGBA_SNORM:
-      case GL_RGBA8_SNORM:
-         return GL_TRUE;
-      case GL_YCBCR_MESA:  /* not considered to be RGB */
-         /* fall-through */
+   if (ctx->Extensions.EXT_texture_integer) {
+      switch (internalFormat) {
+      case GL_RGBA8UI_EXT:
+      case GL_RGBA16UI_EXT:
+      case GL_RGBA32UI_EXT:
+      case GL_RGBA8I_EXT:
+      case GL_RGBA16I_EXT:
+      case GL_RGBA32I_EXT:
+         return GL_RGBA;
+      case GL_RGB8UI_EXT:
+      case GL_RGB16UI_EXT:
+      case GL_RGB32UI_EXT:
+      case GL_RGB8I_EXT:
+      case GL_RGB16I_EXT:
+      case GL_RGB32I_EXT:
+         return GL_RGB;
+      case GL_ALPHA8UI_EXT:
+      case GL_ALPHA16UI_EXT:
+      case GL_ALPHA32UI_EXT:
+      case GL_ALPHA8I_EXT:
+      case GL_ALPHA16I_EXT:
+      case GL_ALPHA32I_EXT:
+         return GL_ALPHA;
+      case GL_INTENSITY8UI_EXT:
+      case GL_INTENSITY16UI_EXT:
+      case GL_INTENSITY32UI_EXT:
+      case GL_INTENSITY8I_EXT:
+      case GL_INTENSITY16I_EXT:
+      case GL_INTENSITY32I_EXT:
+         return GL_INTENSITY;
+      case GL_LUMINANCE8UI_EXT:
+      case GL_LUMINANCE16UI_EXT:
+      case GL_LUMINANCE32UI_EXT:
+      case GL_LUMINANCE8I_EXT:
+      case GL_LUMINANCE16I_EXT:
+      case GL_LUMINANCE32I_EXT:
+         return GL_LUMINANCE;
+      case GL_LUMINANCE_ALPHA8UI_EXT:
+      case GL_LUMINANCE_ALPHA16UI_EXT:
+      case GL_LUMINANCE_ALPHA32UI_EXT:
+      case GL_LUMINANCE_ALPHA8I_EXT:
+      case GL_LUMINANCE_ALPHA16I_EXT:
+      case GL_LUMINANCE_ALPHA32I_EXT:
+         return GL_LUMINANCE_ALPHA;
       default:
-         return GL_FALSE;
+         ; /* fallthrough */
+      }
    }
-}
-
 
-/**
- * Test if the given image format is a color index format.
- */
-static GLboolean
-is_index_format(GLenum format)
-{
-   switch (format) {
-      case GL_COLOR_INDEX:
-      case GL_COLOR_INDEX1_EXT:
-      case GL_COLOR_INDEX2_EXT:
-      case GL_COLOR_INDEX4_EXT:
-      case GL_COLOR_INDEX8_EXT:
-      case GL_COLOR_INDEX12_EXT:
-      case GL_COLOR_INDEX16_EXT:
-         return GL_TRUE;
+   if (ctx->Extensions.ARB_texture_rg) {
+      switch (internalFormat) {
+      case GL_R16F:
+        /* R16F depends on both ARB_half_float_pixel and ARB_texture_float.
+         */
+        if (!ctx->Extensions.ARB_half_float_pixel)
+           break;
+        /* FALLTHROUGH */
+      case GL_R32F:
+        if (!ctx->Extensions.ARB_texture_float)
+           break;
+         return GL_RED;
+      case GL_R8I:
+      case GL_R8UI:
+      case GL_R16I:
+      case GL_R16UI:
+      case GL_R32I:
+      case GL_R32UI:
+        if (!ctx->Extensions.EXT_texture_integer)
+           break;
+        /* FALLTHROUGH */
+      case GL_R8:
+      case GL_R16:
+      case GL_RED:
+      case GL_COMPRESSED_RED:
+         return GL_RED;
+
+      case GL_RG16F:
+        /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float.
+         */
+        if (!ctx->Extensions.ARB_half_float_pixel)
+           break;
+        /* FALLTHROUGH */
+      case GL_RG32F:
+        if (!ctx->Extensions.ARB_texture_float)
+           break;
+         return GL_RG;
+      case GL_RG8I:
+      case GL_RG8UI:
+      case GL_RG16I:
+      case GL_RG16UI:
+      case GL_RG32I:
+      case GL_RG32UI:
+        if (!ctx->Extensions.EXT_texture_integer)
+           break;
+        /* FALLTHROUGH */
+      case GL_RG:
+      case GL_RG8:
+      case GL_RG16:
+      case GL_COMPRESSED_RG:
+         return GL_RG;
       default:
-         return GL_FALSE;
+         ; /* fallthrough */
+      }
    }
-}
 
-
-/**
- * Test if the given image format is a depth component format.
- */
-static GLboolean
-is_depth_format(GLenum format)
-{
-   switch (format) {
-      case GL_DEPTH_COMPONENT16:
-      case GL_DEPTH_COMPONENT24:
-      case GL_DEPTH_COMPONENT32:
-      case GL_DEPTH_COMPONENT:
-         return GL_TRUE;
+   if (ctx->Extensions.EXT_texture_shared_exponent) {
+      switch (internalFormat) {
+      case GL_RGB9_E5_EXT:
+         return GL_RGB;
       default:
-         return GL_FALSE;
+         ; /* fallthrough */
+      }
    }
-}
 
-
-/**
- * Test if the given image format is a YCbCr format.
- */
-static GLboolean
-is_ycbcr_format(GLenum format)
-{
-   switch (format) {
-      case GL_YCBCR_MESA:
-         return GL_TRUE;
+   if (ctx->Extensions.EXT_packed_float) {
+      switch (internalFormat) {
+      case GL_R11F_G11F_B10F_EXT:
+         return GL_RGB;
       default:
-         return GL_FALSE;
+         ; /* fallthrough */
+      }
    }
-}
 
-
-/**
- * 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;
+   if (ctx->Extensions.ARB_depth_buffer_float) {
+      switch (internalFormat) {
+      case GL_DEPTH_COMPONENT32F:
+         return GL_DEPTH_COMPONENT;
+      case GL_DEPTH32F_STENCIL8:
+         return GL_DEPTH_STENCIL;
       default:
-         return GL_FALSE;
+         ; /* fallthrough */
+      }
    }
-}
 
-/**
- * Test if the given image format is a dudv format.
- */
-static GLboolean
-is_dudv_format(GLenum format)
-{
-   switch (format) {
-      case GL_DUDV_ATI:
-      case GL_DU8DV8_ATI:
-         return GL_TRUE;
+   if (ctx->Extensions.ARB_texture_compression_rgtc) {
+      switch (internalFormat) {
+      case GL_COMPRESSED_RED_RGTC1:
+      case GL_COMPRESSED_SIGNED_RED_RGTC1:
+         return GL_RED;
+      case GL_COMPRESSED_RG_RGTC2:
+      case GL_COMPRESSED_SIGNED_RG_RGTC2:
+         return GL_RG;
       default:
-         return GL_FALSE;
-   }
-}
-
-
-/**
- * Test if it is a supported compressed format.
- * 
- * \param internalFormat the internal format token provided by the user.
- * 
- * \ret GL_TRUE if \p internalFormat is a supported compressed format, or
- * GL_FALSE otherwise.
- *
- * Currently only GL_COMPRESSED_RGB_FXT1_3DFX and GL_COMPRESSED_RGBA_FXT1_3DFX
- * are supported.
- */
-static GLboolean
-is_compressed_format(GLcontext *ctx, GLenum internalFormat)
-{
-   GLint supported[100]; /* 100 should be plenty */
-   GLuint i, n;
-
-   n = _mesa_get_compressed_formats(ctx, supported, GL_TRUE);
-   ASSERT(n < 100);
-   for (i = 0; i < n; i++) {
-      if ((GLint) internalFormat == supported[i]) {
-         return GL_TRUE;
+         ; /* fallthrough */
       }
    }
-   return GL_FALSE;
+
+   return -1; /* error */
 }
 
 
@@ -702,7 +559,7 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
  * zero.
  */
 struct gl_texture_image *
-_mesa_new_texture_image( GLcontext *ctx )
+_mesa_new_texture_image( struct gl_context *ctx )
 {
    (void) ctx;
    return CALLOC_STRUCT(gl_texture_image);
@@ -718,7 +575,7 @@ _mesa_new_texture_image( GLcontext *ctx )
  * Free the texture image data if it's not marked as client data.
  */
 void
-_mesa_free_texture_image_data(GLcontext *ctx,
+_mesa_free_texture_image_data(struct gl_context *ctx,
                               struct gl_texture_image *texImage)
 {
    (void) ctx;
@@ -740,7 +597,8 @@ _mesa_free_texture_image_data(GLcontext *ctx,
  * Free the texture image structure and the associated image data.
  */
 void
-_mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
+_mesa_delete_texture_image(struct gl_context *ctx,
+                           struct gl_texture_image *texImage)
 {
    /* Free texImage->Data and/or any other driver-specific texture
     * image storage.
@@ -750,8 +608,8 @@ _mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
 
    ASSERT(texImage->Data == NULL);
    if (texImage->ImageOffsets)
-      _mesa_free(texImage->ImageOffsets);
-   _mesa_free(texImage);
+      free(texImage->ImageOffsets);
+   free(texImage);
 }
 
 
@@ -765,6 +623,9 @@ _mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
 GLboolean
 _mesa_is_proxy_texture(GLenum target)
 {
+   /* NUM_TEXTURE_TARGETS should match number of terms below */
+   assert(NUM_TEXTURE_TARGETS == 7);
+
    return (target == GL_PROXY_TEXTURE_1D ||
            target == GL_PROXY_TEXTURE_2D ||
            target == GL_PROXY_TEXTURE_3D ||
@@ -776,19 +637,49 @@ _mesa_is_proxy_texture(GLenum target)
 
 
 /**
- * Return pointer to current texture unit.
- * This the texture unit set by glActiveTexture(), not glClientActiveTexture().
+ * Return the proxy target which corresponds to the given texture target
  */
-static INLINE struct gl_texture_unit *
-get_current_tex_unit(GLcontext *ctx)
+static GLenum
+get_proxy_target(GLenum target)
 {
-   ASSERT(ctx->Texture.CurrentUnit < Elements(ctx->Texture.Unit));
-   return &(ctx->Texture.Unit[ctx->Texture.CurrentUnit]);
+   switch (target) {
+   case GL_TEXTURE_1D:
+   case GL_PROXY_TEXTURE_1D:
+      return GL_PROXY_TEXTURE_1D;
+   case GL_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_2D:
+      return GL_PROXY_TEXTURE_2D;
+   case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
+      return GL_PROXY_TEXTURE_3D;
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
+   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:
+   case GL_TEXTURE_CUBE_MAP_ARB:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
+      return GL_PROXY_TEXTURE_CUBE_MAP_ARB;
+   case GL_TEXTURE_RECTANGLE_NV:
+   case GL_PROXY_TEXTURE_RECTANGLE_NV:
+      return GL_PROXY_TEXTURE_RECTANGLE_NV;
+   case GL_TEXTURE_1D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+      return GL_PROXY_TEXTURE_1D_ARRAY_EXT;
+   case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+      return GL_PROXY_TEXTURE_2D_ARRAY_EXT;
+   default:
+      _mesa_problem(NULL, "unexpected target in get_proxy_target()");
+      return 0;
+   }
 }
 
 
 /**
- * Get the texture object that corresponds to the target of the given texture unit.
+ * Get the texture object that corresponds to the target of the given
+ * texture unit.
  *
  * \param ctx GL context.
  * \param texUnit texture unit.
@@ -799,7 +690,8 @@ get_current_tex_unit(GLcontext *ctx)
  * \sa gl_texture_unit.
  */
 struct gl_texture_object *
-_mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
+_mesa_select_tex_object(struct gl_context *ctx,
+                        const struct gl_texture_unit *texUnit,
                         GLenum target)
 {
    switch (target) {
@@ -852,6 +744,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(struct gl_context *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
@@ -865,7 +768,8 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
  * \return pointer to the texture image structure, or NULL on failure.
  */
 struct gl_texture_image *
-_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
+_mesa_select_tex_image(struct gl_context *ctx,
+                       const struct gl_texture_object *texObj,
                       GLenum target, GLint level)
 {
    const GLuint face = _mesa_tex_target_to_face(target);
@@ -884,7 +788,7 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
  * out of memory.
  */
 struct gl_texture_image *
-_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj,
+_mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj,
                     GLenum target, GLint level)
 {
    struct gl_texture_image *texImage;
@@ -914,7 +818,7 @@ _mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj,
  *         level, or out of memory.
  */
 struct gl_texture_image *
-_mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level)
+_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
 {
    struct gl_texture_image *texImage;
    GLuint texIndex;
@@ -989,17 +893,13 @@ _mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level)
  * \sa gl_constants.
  */
 GLint
-_mesa_max_texture_levels(GLcontext *ctx, GLenum target)
+_mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
-   case GL_TEXTURE_1D_ARRAY_EXT:
-   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
-   case GL_TEXTURE_2D_ARRAY_EXT:
-   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return ctx->Const.MaxTextureLevels;
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
@@ -1012,16 +912,62 @@ _mesa_max_texture_levels(GLcontext *ctx, GLenum target)
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
    case GL_TEXTURE_CUBE_MAP_ARB:
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
-      return ctx->Const.MaxCubeTextureLevels;
+      return ctx->Extensions.ARB_texture_cube_map
+         ? ctx->Const.MaxCubeTextureLevels : 0;
    case GL_TEXTURE_RECTANGLE_NV:
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      return 1;
+      return ctx->Extensions.NV_texture_rectangle ? 1 : 0;
+   case GL_TEXTURE_1D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+   case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+      return ctx->Extensions.MESA_texture_array
+         ? ctx->Const.MaxTextureLevels : 0;
    default:
       return 0; /* bad target */
    }
 }
 
 
+/**
+ * Return number of dimensions per mipmap level for the given texture target.
+ */
+GLint
+_mesa_get_texture_dimensions(GLenum target)
+{
+   switch (target) {
+   case GL_TEXTURE_1D:
+   case GL_PROXY_TEXTURE_1D:
+      return 1;
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_PROXY_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_RECTANGLE:
+   case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_PROXY_TEXTURE_1D_ARRAY:
+      return 2;
+   case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_PROXY_TEXTURE_2D_ARRAY:
+      return 3;
+   default:
+      _mesa_problem(NULL, "invalid target 0x%x in get_texture_dimensions()",
+                    target);
+      return 2;
+   }
+}
+
+
+
 
 #if 000 /* not used anymore */
 /*
@@ -1100,7 +1046,7 @@ clear_teximage_fields(struct gl_texture_image *img)
    img->Depth = 0;
    img->RowStride = 0;
    if (img->ImageOffsets) {
-      _mesa_free(img->ImageOffsets);
+      free(img->ImageOffsets);
       img->ImageOffsets = NULL;
    }
    img->Width2 = 0;
@@ -1110,11 +1056,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;
 }
 
 
@@ -1129,17 +1073,19 @@ clear_teximage_fields(struct gl_texture_image *img)
  * \param depth image depth.
  * \param border image border.
  * \param internalFormat internal format.
+ * \param format  the actual hardware format (one of MESA_FORMAT_*)
  *
  * Fills in the fields of \p img with the given information.
  * Note: width, height and depth include the border.
  */
 void
-_mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
+_mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
                            struct gl_texture_image *img,
                            GLsizei width, GLsizei height, GLsizei depth,
-                           GLint border, GLenum internalFormat)
+                           GLint border, GLenum internalFormat,
+                           gl_format format)
 {
-   GLint i;
+   GLint i, dims;
 
    ASSERT(img);
    ASSERT(width >= 0);
@@ -1177,9 +1123,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)))
@@ -1194,8 +1137,8 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
     * case code in the texstore routines.
     */
    if (img->ImageOffsets)
-      _mesa_free(img->ImageOffsets);
-   img->ImageOffsets = (GLuint *) _mesa_malloc(depth * sizeof(GLuint));
+      free(img->ImageOffsets);
+   img->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint));
    for (i = 0; i < depth; i++) {
       img->ImageOffsets[i] = i * width * height;
    }
@@ -1212,17 +1155,41 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
       img->HeightScale = (GLfloat) img->Height;
       img->DepthScale = (GLfloat) img->Depth;
    }
+
+   img->TexFormat = format;
+
+   dims = _mesa_get_texture_dimensions(target);
+
+   _mesa_set_fetch_functions(img, dims);
 }
 
 
 /**
- * This is the fallback for Driver.TestProxyTexImage().  Test the texture
- * level, width, height and depth against the ctx->Const limits for textures.
+ * Free and clear fields of the gl_texture_image struct.
  *
- * A hardware driver might override this function if, for example, the
- * max 3D texture size is 512x512x64 (i.e. not a cube).
+ * \param ctx GL context.
+ * \param texImage texture image structure to be cleared.
  *
- * Note that width, height, depth == 0 is not an error.  However, a
+ * After the call, \p texImage will have no data associated with it.  Its
+ * fields are cleared so that its parent object will test incomplete.
+ */
+void
+_mesa_clear_texture_image(struct gl_context *ctx,
+                          struct gl_texture_image *texImage)
+{
+   ctx->Driver.FreeTexImageData(ctx, texImage);
+   clear_teximage_fields(texImage);
+}
+
+
+/**
+ * This is the fallback for Driver.TestProxyTexImage().  Test the texture
+ * level, width, height and depth against the ctx->Const limits for textures.
+ *
+ * A hardware driver might override this function if, for example, the
+ * max 3D texture size is 512x512x64 (i.e. not a cube).
+ *
+ * Note that width, height, depth == 0 is not an error.  However, a
  * texture with zero width/height/depth will be considered "incomplete"
  * and texturing will effectively be disabled.
  *
@@ -1240,7 +1207,7 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
  * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
  */
 GLboolean
-_mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
+_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
                           GLint internalFormat, GLenum format, GLenum type,
                           GLint width, GLint height, GLint depth, GLint border)
 {
@@ -1253,94 +1220,110 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    switch (target) {
    case GL_PROXY_TEXTURE_1D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width >0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or level */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_2D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or height or level */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_3D:
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          depth < 2 * border || depth > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           depth > 0 && !_mesa_is_pow_two(depth - 2 * border)) ||
-          level >= ctx->Const.Max3DTextureLevels) {
-         /* bad width or height or depth or level */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (depth < 2 * border || depth > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.Max3DTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
+         if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      if (width < 0 || width > ctx->Const.MaxTextureRectSize ||
-          height < 0 || height > ctx->Const.MaxTextureRectSize ||
-          level != 0) {
-         /* bad width or height or level */
+      maxSize = ctx->Const.MaxTextureRectSize;
+      if (width < 0 || width > maxSize)
+         return GL_FALSE;
+      if (height < 0 || height > maxSize)
+         return GL_FALSE;
+      if (level != 0)
          return GL_FALSE;
-      }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxCubeTextureLevels) {
-         /* bad width or height */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxCubeTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
-      }
-
-      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) {
+      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers)
          return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or height or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
-      }
-      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) {
+      if (height < 2 * border || height > 2 + maxSize)
          return GL_FALSE;
+      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    default:
       _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
       return GL_FALSE;
@@ -1349,19 +1332,154 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
 
 
 /**
- * Helper function to determine whether a target supports compressed textures
+ * Check if the memory used by the texture would exceed the driver's limit.
+ * This lets us support a max 3D texture size of 8K (for example) but
+ * prevents allocating a full 8K x 8K x 8K texture.
+ * XXX this could be rolled into the proxy texture size test (above) but
+ * we don't have the actual texture internal format at that point.
+ */
+static GLboolean
+legal_texture_size(struct gl_context *ctx, gl_format format,
+                   GLint width, GLint height, GLint depth)
+{
+   uint64_t bytes = _mesa_format_image_size64(format, width, height, depth);
+   uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */
+   return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes;
+}
+
+
+
+/**
+ * Helper function to determine whether a target and specific compression
+ * format are supported.
+ */
+static GLboolean
+target_can_be_compressed(const struct gl_context *ctx, GLenum target,
+                         GLenum intFormat)
+{
+   (void) intFormat;  /* not used yet */
+
+   switch (target) {
+   case GL_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_2D:
+      return GL_TRUE; /* true for any compressed format so far */
+   case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+      return ctx->Extensions.ARB_texture_cube_map;
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+   case GL_TEXTURE_2D_ARRAY_EXT:
+      return ctx->Extensions.MESA_texture_array;
+   default:
+      return GL_FALSE;
+   }      
+}
+
+
+/**
+ * Check if the given texture target value is legal for a
+ * glTexImage1/2/3D call.
+ */
+static GLboolean
+legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
+{
+   switch (dims) {
+   case 1:
+      switch (target) {
+      case GL_TEXTURE_1D:
+      case GL_PROXY_TEXTURE_1D:
+         return GL_TRUE;
+      default:
+         return GL_FALSE;
+      }
+   case 2:
+      switch (target) {
+      case GL_TEXTURE_2D:
+      case GL_PROXY_TEXTURE_2D:
+         return GL_TRUE;
+      case GL_PROXY_TEXTURE_CUBE_MAP:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+         return ctx->Extensions.ARB_texture_cube_map;
+      case GL_TEXTURE_RECTANGLE_NV:
+      case GL_PROXY_TEXTURE_RECTANGLE_NV:
+         return ctx->Extensions.NV_texture_rectangle;
+      case GL_TEXTURE_1D_ARRAY_EXT:
+      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array;
+      default:
+         return GL_FALSE;
+      }
+   case 3:
+      switch (target) {
+      case GL_TEXTURE_3D:
+      case GL_PROXY_TEXTURE_3D:
+         return GL_TRUE;
+      case GL_TEXTURE_2D_ARRAY_EXT:
+      case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array;
+      default:
+         return GL_FALSE;
+      }
+   default:
+      _mesa_problem(ctx, "invalid dims=%u in legal_teximage_target()", dims);
+      return GL_FALSE;
+   }
+}
+
+
+/**
+ * Check if the given texture target value is legal for a
+ * glTexSubImage, glCopyTexSubImage or glCopyTexImage call.
+ * The difference compared to legal_teximage_target() above is that
+ * proxy targets are not supported.
  */
 static GLboolean
-target_can_be_compressed(GLcontext *ctx, GLenum target)
+legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
 {
-   return (((target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D))
-           || ((ctx->Extensions.ARB_texture_cube_map &&
-                (target == GL_PROXY_TEXTURE_CUBE_MAP ||
-                 (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                  target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))))
-           || ((ctx->Extensions.MESA_texture_array &&
-                ((target == GL_PROXY_TEXTURE_2D_ARRAY_EXT) ||
-                 (target == GL_TEXTURE_2D_ARRAY_EXT)))));
+   switch (dims) {
+   case 1:
+      return target == GL_TEXTURE_1D;
+   case 2:
+      switch (target) {
+      case GL_TEXTURE_2D:
+         return GL_TRUE;
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+         return ctx->Extensions.ARB_texture_cube_map;
+      case GL_TEXTURE_RECTANGLE_NV:
+         return ctx->Extensions.NV_texture_rectangle;
+      case GL_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array;
+      default:
+         return GL_FALSE;
+      }
+   case 3:
+      switch (target) {
+      case GL_TEXTURE_3D:
+         return GL_TRUE;
+      case GL_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array;
+      default:
+         return GL_FALSE;
+      }
+   default:
+      _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()",
+                    dims);
+      return GL_FALSE;
+   }
 }
 
 
@@ -1369,12 +1487,12 @@ target_can_be_compressed(GLcontext *ctx, GLenum target)
  * Test the glTexImage[123]D() parameters for errors.
  * 
  * \param ctx GL context.
+ * \param dimensions texture image dimensions (must be 1, 2 or 3).
  * \param target texture target given by the user.
  * \param level image level given by the user.
  * \param internalFormat internal format given by the user.
  * \param format pixel data format given by the user.
  * \param type pixel data type given by the user.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
  * \param width image width given by the user.
  * \param height image height given by the user.
  * \param depth image depth given by the user.
@@ -1383,21 +1501,21 @@ target_can_be_compressed(GLcontext *ctx, GLenum target)
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  *
  * Verifies each of the parameters against the constants specified in
- * __GLcontextRec::Const and the supported extensions, and according to the
- * OpenGL specification.
+ * __struct gl_contextRec::Const and the supported extensions, and according
+ * to the OpenGL specification.
  */
 static GLboolean
-texture_error_check( GLcontext *ctx, GLenum target,
+texture_error_check( struct gl_context *ctx,
+                     GLuint dimensions, GLenum target,
                      GLint level, GLint internalFormat,
                      GLenum format, GLenum type,
-                     GLuint dimensions,
                      GLint width, GLint height,
                      GLint depth, GLint border )
 {
-   const GLboolean isProxy = _mesa_is_proxy_texture(target);
+   const GLenum proxyTarget = get_proxy_target(target);
+   const GLboolean isProxy = target == proxyTarget;
    GLboolean sizeOK = GL_TRUE;
    GLboolean colorFormat, indexFormat;
-   GLenum proxy_target;
 
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
@@ -1427,71 +1545,16 @@ texture_error_check( GLcontext *ctx, GLenum target,
       return GL_TRUE;
    }
 
-   /* Check target and call ctx->Driver.TestProxyTexImage() to check the
-    * level, width, height and depth.
-    */
-   if (dimensions == 1) {
-      if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) {
-         proxy_target = GL_PROXY_TEXTURE_1D;
-         height = 1;
-         depth = 1;
-      }
-      else {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 2) {
-      depth = 1;
-      if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) {
-         proxy_target = GL_PROXY_TEXTURE_2D;
-      }
-      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
-               (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-                target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
-         if (!ctx->Extensions.ARB_texture_cube_map) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
-            return GL_TRUE;
-         }
-         proxy_target = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
-         sizeOK = (width == height);
-      }
-      else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
-               target == GL_TEXTURE_RECTANGLE_NV) {
-         if (!ctx->Extensions.NV_texture_rectangle) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
-            return GL_TRUE;
-         }
-         proxy_target = GL_PROXY_TEXTURE_RECTANGLE_NV;
-      }
-      else if (target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
-               target == GL_TEXTURE_1D_ARRAY_EXT) {
-         proxy_target = GL_PROXY_TEXTURE_1D_ARRAY_EXT;
-      }
-      else {
-         _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 3) {
-      if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) {
-         proxy_target = GL_PROXY_TEXTURE_3D;
-      }
-      else if (target == GL_PROXY_TEXTURE_2D_ARRAY_EXT ||
-               target == GL_TEXTURE_2D_ARRAY_EXT) {
-         proxy_target = GL_PROXY_TEXTURE_2D_ARRAY_EXT;
-      }
-      else {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else {
-      _mesa_problem( ctx, "bad dims in texture_error_check" );
-      return GL_TRUE;
+   /* Do this simple check before calling the TestProxyTexImage() function */
+   if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
+      sizeOK = (width == height);
    }
 
-   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxy_target, level,
+   /*
+    * Use the proxy texture driver hook to see if the size/level/etc are
+    * legal.
+    */
+   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
                                                     internalFormat, format,
                                                     type, width, height,
                                                     depth, border);
@@ -1508,19 +1571,23 @@ 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;
    }
 
    /* Check incoming image format and type */
    if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
-      /* Yes, generate GL_INVALID_OPERATION, not GL_INVALID_ENUM, if there
-       * is a type/format mismatch.  See 1.2 spec page 94, sec 3.6.4.
+      /* Normally, GL_INVALID_OPERATION is generated by a format/type
+       * mismatch (see the 1.2 spec page 94, sec 3.6.4.).  But with the
+       * GL_EXT_texture_integer extension, some combinations should generate
+       * GL_INVALID_ENUM instead (grr!).
        */
       if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
+         GLenum error = _mesa_is_integer_format(format)
+            ? GL_INVALID_ENUM : GL_INVALID_OPERATION;
+         _mesa_error(ctx, error,
                      "glTexImage%dD(incompatible format 0x%x, type 0x%x)",
                      dimensions, format, type);
       }
@@ -1529,13 +1596,13 @@ texture_error_check( GLcontext *ctx, GLenum target,
 
    /* make sure internal format and format basically agree */
    colorFormat = _mesa_is_color_format(format);
-   indexFormat = is_index_format(format);
+   indexFormat = _mesa_is_index_format(format);
    if ((_mesa_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_depthstencil_format(internalFormat) != is_depthstencil_format(format)) ||
-       (is_dudv_format(internalFormat) != is_dudv_format(format))) {
+       (_mesa_is_index_format(internalFormat) && !indexFormat) ||
+       (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) ||
+       (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) ||
+       (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) ||
+       (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) {
       if (!isProxy)
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)",
@@ -1549,9 +1616,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
       if (type != GL_UNSIGNED_SHORT_8_8_MESA &&
           type != GL_UNSIGNED_SHORT_8_8_REV_MESA) {
          char message[100];
-         _mesa_sprintf(message,
-                 "glTexImage%d(format/type YCBCR mismatch", dimensions);
-         _mesa_error(ctx, GL_INVALID_ENUM, message);
+         _mesa_snprintf(message, sizeof(message),
+                        "glTexImage%dD(format/type YCBCR mismatch", dimensions);
+         _mesa_error(ctx, GL_INVALID_ENUM, "%s", message);
          return GL_TRUE; /* error */
       }
       if (target != GL_TEXTURE_2D &&
@@ -1565,10 +1632,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
       if (border != 0) {
          if (!isProxy) {
             char message[100];
-            _mesa_sprintf(message,
-                    "glTexImage%d(format=GL_YCBCR_MESA and border=%d)",
-                    dimensions, border);
-            _mesa_error(ctx, GL_INVALID_VALUE, message);
+            _mesa_snprintf(message, sizeof(message),
+                           "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)",
+                           dimensions, border);
+            _mesa_error(ctx, GL_INVALID_VALUE, "%s", message);
          }
          return GL_TRUE;
       }
@@ -1591,21 +1658,34 @@ texture_error_check( GLcontext *ctx, GLenum target,
    }
 
    /* additional checks for compressed textures */
-   if (is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target) && !isProxy) {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexImage%d(target)", dimensions);
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
+      if (!target_can_be_compressed(ctx, target, internalFormat)) {
+         if (!isProxy)
+            _mesa_error(ctx, GL_INVALID_ENUM,
+                        "glTexImage%dD(target)", dimensions);
          return GL_TRUE;
       }
       if (border != 0) {
          if (!isProxy) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glTexImage%D(border!=0)", dimensions);
+                        "glTexImage%dD(border!=0)", dimensions);
          }
          return GL_TRUE;
       }
    }
 
+   /* additional checks for integer textures */
+   if (ctx->Extensions.EXT_texture_integer &&
+       (_mesa_is_integer_format(format) !=
+        _mesa_is_integer_format(internalFormat))) {
+      if (!isProxy) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glTexImage%dD(integer/non-integer format mismatch)",
+                     dimensions);
+      }
+      return GL_TRUE;
+   }
+
    /* if we get here, the parameters are OK */
    return GL_FALSE;
 }
@@ -1630,71 +1710,23 @@ texture_error_check( GLcontext *ctx, GLenum target,
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  *
  * Verifies each of the parameters against the constants specified in
- * __GLcontextRec::Const and the supported extensions, and according to the
- * OpenGL specification.
+ * __struct gl_contextRec::Const and the supported extensions, and according
+ * to the OpenGL specification.
  */
 static GLboolean
-subtexture_error_check( GLcontext *ctx, GLuint dimensions,
+subtexture_error_check( struct gl_context *ctx, GLuint dimensions,
                         GLenum target, GLint level,
                         GLint xoffset, GLint yoffset, GLint zoffset,
                         GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type )
 {
-   /* Check target */
-   if (dimensions == 1) {
-      if (target != GL_TEXTURE_1D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 2) {
-      if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target == GL_TEXTURE_RECTANGLE_NV) {
-         if (!ctx->Extensions.NV_texture_rectangle) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
-        if (!ctx->Extensions.MESA_texture_array) {
-           _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
-           return GL_TRUE;
-        }
-      }
-      else if (target != GL_TEXTURE_2D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 3) {
-      if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-         if (!ctx->Extensions.MESA_texture_array) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target != GL_TEXTURE_3D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else {
-      _mesa_problem( ctx, "invalid dims in texture_error_check" );
-      return GL_TRUE;
-   }
-
    /* Basic level check */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level);
       return GL_TRUE;
    }
 
+   /* Check for negative sizes */
    if (width < 0) {
       _mesa_error(ctx, GL_INVALID_VALUE,
                   "glTexSubImage%dD(width=%d)", dimensions, width);
@@ -1712,7 +1744,12 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
    }
 
    if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
+      /* As with the glTexImage2D check above, the error code here
+       * depends on texture integer.
+       */
+      GLenum error = _mesa_is_integer_format(format)
+         ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
+      _mesa_error(ctx, error,
                   "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)",
                   dimensions, format, type);
       return GL_TRUE;
@@ -1721,8 +1758,13 @@ 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,
+subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
                         GLenum target, GLint level,
                         GLint xoffset, GLint yoffset, GLint zoffset,
                         GLint width, GLint height, GLint depth,
@@ -1768,41 +1810,28 @@ 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);
-         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%dD(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%dD(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%dD(height = %d)", dimensions, height);
          return GL_TRUE;
       }         
    }
@@ -1826,18 +1855,26 @@ subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  * 
  * Verifies each of the parameters against the constants specified in
- * __GLcontextRec::Const and the supported extensions, and according to the
- * OpenGL specification.
+ * __struct gl_contextRec::Const and the supported extensions, and according
+ * to the OpenGL specification.
  */
 static GLboolean
-copytexture_error_check( GLcontext *ctx, GLuint dimensions,
+copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
                          GLenum target, GLint level, GLint internalFormat,
                          GLint width, GLint height, GLint border )
 {
-   GLenum type;
+   const GLenum proxyTarget = get_proxy_target(target);
+   const GLenum type = GL_FLOAT;
    GLboolean sizeOK;
    GLint format;
 
+   /* check target */
+   if (!legal_texsubimage_target(ctx, dimensions, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
+                  dimensions, _mesa_lookup_enum_by_nr(target));
+      return GL_TRUE;
+   }       
+
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
       _mesa_error(ctx, GL_INVALID_VALUE,
@@ -1875,75 +1912,14 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   /* NOTE: the format and type aren't really significant for
-    * TestProxyTexImage().  Only the internalformat really matters.
-    */
-   type = GL_FLOAT;
+   /* Do size, level checking */
+   sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB)
+      ? (width == height) : 1;
 
-   /* Check target and call ctx->Driver.TestProxyTexImage() to check the
-    * level, width, height and depth.
-    */
-   if (dimensions == 1) {
-      if (target == GL_TEXTURE_1D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_1D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, 1, 1, border);
-      }
-      else {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage1D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 2) {
-      if (target == GL_TEXTURE_2D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_2D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
-      }
-      else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-               target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
-            return GL_TRUE;
-         }
-         sizeOK = (width == height) &&
-            ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_CUBE_MAP_ARB,
-                                          level, internalFormat, format, type,
-                                          width, height, 1, border);
-      }
-      else if (target == GL_TEXTURE_RECTANGLE_NV) {
-         if (!ctx->Extensions.NV_texture_rectangle) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
-            return GL_TRUE;
-         }
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
-                                                GL_PROXY_TEXTURE_RECTANGLE_NV,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
-      }
-      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
-         if (!ctx->Extensions.MESA_texture_array) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)");
-            return GL_TRUE;
-         }
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
-                                                GL_PROXY_TEXTURE_1D_ARRAY_EXT,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
-      }
-      else {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else {
-      _mesa_problem(ctx, "invalid dimensions in copytexture_error_check");
-      return GL_TRUE;
-   }
+   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
+                                                    internalFormat, format,
+                                                    type, width, height,
+                                                    1, border);
 
    if (!sizeOK) {
       if (dimensions == 1) {
@@ -1958,31 +1934,31 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   if (is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target)) {
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
+      if (!target_can_be_compressed(ctx, target, internalFormat)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glCopyTexImage%d(target)", dimensions);
+                     "glCopyTexImage%dD(target)", dimensions);
          return GL_TRUE;
       }
       if (border != 0) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glCopyTexImage%D(border!=0)", dimensions);
+                     "glCopyTexImage%dD(border!=0)", dimensions);
          return GL_TRUE;
       }
    }
-   else if (is_depth_format(internalFormat)) {
+   else if (_mesa_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);
+                     "glCopyTexImage%dD(no depth)", dimensions);
          return GL_TRUE;
       }
    }
-   else if (is_depthstencil_format(internalFormat)) {
+   else if (_mesa_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);
+                     "glCopyTexImage%dD(no depth/stencil buffer)", dimensions);
          return GL_TRUE;
       }
    }
@@ -2005,7 +1981,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  */
 static GLboolean
-copytexsubimage_error_check1( GLcontext *ctx, GLuint dimensions,
+copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
                               GLenum target, GLint level)
 {
    /* Check that the source buffer is complete */
@@ -2018,45 +1994,11 @@ copytexsubimage_error_check1( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-   /* Check target */
-   if (dimensions == 1) {
-      if (target != GL_TEXTURE_1D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 2) {
-      if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target == GL_TEXTURE_RECTANGLE_NV) {
-         if (!ctx->Extensions.NV_texture_rectangle) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
-         if (!ctx->Extensions.MESA_texture_array) {
-            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
-            return GL_TRUE;
-         }
-      }
-      else if (target != GL_TEXTURE_2D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
-         return GL_TRUE;
-      }
-   }
-   else if (dimensions == 3) {
-      if (((target != GL_TEXTURE_2D_ARRAY_EXT) ||
-          (!ctx->Extensions.MESA_texture_array))
-         && (target != GL_TEXTURE_3D)) {
-        _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
-        return GL_TRUE;
-      }
+   /* check target (proxies not allowed) */
+   if (!legal_texsubimage_target(ctx, dimensions, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)",
+                  dimensions, _mesa_lookup_enum_by_nr(target));
+      return GL_TRUE;
    }
 
    /* Check level */
@@ -2079,7 +2021,7 @@ copytexsubimage_error_check1( GLcontext *ctx, GLuint dimensions,
  * \param height image height given by the user.
  */
 static GLboolean
-copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
+copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions,
                              GLenum target, GLint level,
                              GLint xoffset, GLint yoffset, GLint zoffset,
                              GLsizei width, GLsizei height,
@@ -2144,27 +2086,22 @@ copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-   if (teximage->IsCompressed) {
-      if (!target_can_be_compressed(ctx, target)) {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glCopyTexSubImage%d(target)", dimensions);
-         return GL_TRUE;
-      }
+   if (_mesa_is_format_compressed(teximage->TexFormat)) {
       /* offset must be multiple of 4 */
       if ((xoffset & 3) || (yoffset & 3)) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%D(xoffset or yoffset)", dimensions);
+                     "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions);
          return GL_TRUE;
       }
       /* size must be multiple of 4 */
       if ((width & 3) != 0 && (GLuint) width != teximage->Width) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%D(width)", dimensions);
+                     "glCopyTexSubImage%dD(width)", dimensions);
          return GL_TRUE;
       }         
       if ((height & 3) != 0 && (GLuint) height != teximage->Height) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%D(height)", dimensions);
+                     "glCopyTexSubImage%dD(height)", dimensions);
          return GL_TRUE;
       }         
    }
@@ -2184,7 +2121,7 @@ copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
    if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) {
       if (!ctx->ReadBuffer->_DepthBuffer) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glCopyTexSubImage%D(no depth buffer)",
+                     "glCopyTexSubImage%dD(no depth buffer)",
                      dimensions);
          return GL_TRUE;
       }
@@ -2192,184 +2129,34 @@ copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
    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)",
+                     "glCopyTexSubImage%dD(no depth/stencil buffer)",
                      dimensions);
          return GL_TRUE;
       }
    }
 
+   /* If copying into an integer texture, the source buffer must also be
+    * integer-valued.
+    */
+   if (_mesa_is_format_integer_color(teximage->TexFormat)) {
+      struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
+      if (!_mesa_is_format_integer_color(rb->Format)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexSubImage%dD(source buffer is not integer format)",
+                  dimensions);
+         return GL_TRUE;
+      }
+   }
+
    /* if we get here, the parameters are OK */
    return GL_FALSE;
 }
 
 
-/**
- * Do error checking for a glGetTexImage() call.
- * \return GL_TRUE if any error, GL_FALSE if no errors.
- */
-static GLboolean
-getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
-                        GLenum format, GLenum type, GLvoid *pixels )
-{
-   const struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
-
-   ASSERT(maxLevels > 0);  /* 0 indicates bad target, caught above */
-
-   if (level < 0 || level >= maxLevels) {
-      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
-      return GL_TRUE;
-   }
-
-   if (_mesa_sizeof_packed_type(type) <= 0) {
-      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
-      return GL_TRUE;
-   }
-
-   if (_mesa_components_in_format(format) <= 0 ||
-       format == GL_STENCIL_INDEX) {
-      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
-      return GL_TRUE;
-   }
-
-   if (!ctx->Extensions.EXT_paletted_texture && is_index_format(format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-      return GL_TRUE;
-   }
-
-   if (!ctx->Extensions.ARB_depth_texture && is_depth_format(format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-      return GL_TRUE;
-   }
-
-   if (!ctx->Extensions.MESA_ycbcr_texture && is_ycbcr_format(format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-      return GL_TRUE;
-   }
-
-   if (!ctx->Extensions.EXT_packed_depth_stencil
-       && is_depthstencil_format(format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-      return GL_TRUE;
-   }
-
-   if (!ctx->Extensions.ATI_envmap_bumpmap
-       && is_dudv_format(format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-      return GL_TRUE;
-   }
-
-
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-   if (!texImage) {
-      /* out of memory */
-      return GL_TRUE;
-   }
-      
-   /* Make sure the requested image format is compatible with the
-    * texture's format.  Note that a color index texture can be converted
-    * to RGBA so that combo is allowed.
-    */
-   if (_mesa_is_color_format(format)
-       && !_mesa_is_color_format(texImage->TexFormat->BaseFormat)
-       && !is_index_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-   else if (is_index_format(format)
-            && !is_index_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-   else if (is_depth_format(format)
-            && !is_depth_format(texImage->TexFormat->BaseFormat)
-            && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-   else if (is_ycbcr_format(format)
-            && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-   else if (is_depthstencil_format(format)
-            && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-   else if (is_dudv_format(format)
-            && !is_dudv_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return GL_TRUE;
-   }
-
-   if (ctx->Pack.BufferObj->Name) {
-      /* packing texture image into a PBO */
-      const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
-      if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
-                                     texImage->Height, texImage->Depth,
-                                     format, type, pixels)) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glGetTexImage(invalid PBO access)");
-         return GL_TRUE;
-      }
-   }
-
-   return GL_FALSE;
-}
-
-
-
-/**
- * Get texture image.  Called by glGetTexImage.
- *
- * \param target texture target.
- * \param level image level.
- * \param format pixel data format for returned image.
- * \param type pixel data type for returned image.
- * \param pixels returned pixel data.
- */
-void GLAPIENTRY
-_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
-                   GLenum type, GLvoid *pixels )
-{
-   const struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   if (!texObj || _mesa_is_proxy_texture(target)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
-      return;
-   }
-
-   if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
-      return;
-   }
-
-   _mesa_lock_texture(ctx, texObj);
-   {
-      struct gl_texture_image *texImage =
-         _mesa_select_tex_image(ctx, texObj, target, level);
-
-      /* typically, this will call _mesa_get_teximage() */
-      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
-                              texObj, texImage);
-   }
-   _mesa_unlock_texture(ctx, texObj);
-}
-
-
 /** Callback info for walking over FBO hash table */
 struct cb_info
 {
-   GLcontext *ctx;
+   struct gl_context *ctx;
    struct gl_texture_object *texObj;
    GLuint level, face;
 };
@@ -2383,7 +2170,7 @@ check_rtt_cb(GLuint key, void *data, void *userData)
 {
    struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
    const struct cb_info *info = (struct cb_info *) userData;
-   GLcontext *ctx = info->ctx;
+   struct gl_context *ctx = info->ctx;
    const struct gl_texture_object *texObj = info->texObj;
    const GLuint level = info->level, face = info->face;
 
@@ -2415,7 +2202,7 @@ check_rtt_cb(GLuint key, void *data, void *userData)
  * Any FBOs rendering into the texture must be re-validated.
  */
 static void
-update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
+update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj,
                    GLuint face, GLuint level)
 {
    /* Only check this texture if it's been marked as RenderToTexture */
@@ -2430,6 +2217,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(struct gl_context *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)
@@ -2474,217 +2280,215 @@ override_internal_format(GLenum internalFormat, GLint width, GLint height)
 }
 
 
-/*
- * Called from the API.  Note that width includes the border.
+/**
+ * Choose the actual hardware format for a texture image.
+ * Try to use the same format as the previous image level when possible.
+ * Otherwise, ask the driver for the best format.
+ * It's important to try to choose a consistant format for all levels
+ * for efficient texture memory layout/allocation.  In particular, this
+ * comes up during automatic mipmap generation.
  */
-void GLAPIENTRY
-_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
-                  GLsizei width, GLint border, GLenum format,
-                  GLenum type, const GLvoid *pixels )
+gl_format
+_mesa_choose_texture_format(struct gl_context *ctx,
+                            struct gl_texture_object *texObj,
+                            GLenum target, GLint level,
+                            GLenum internalFormat, GLenum format, GLenum type)
 {
-   GLsizei postConvWidth = width;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+   gl_format f;
+
+   /* see if we've already chosen a format for the previous level */
+   if (level > 0) {
+      struct gl_texture_image *prevImage =
+        _mesa_select_tex_image(ctx, texObj, target, level - 1);
+      /* See if the prev level is defined and has an internal format which
+       * matches the new internal format.
+       */
+      if (prevImage &&
+          prevImage->Width > 0 &&
+          prevImage->InternalFormat == internalFormat) {
+         /* use the same format */
+         ASSERT(prevImage->TexFormat != MESA_FORMAT_NONE);
+         return prevImage->TexFormat;
+      }
+   }
 
-   internalFormat = override_internal_format(internalFormat, width, 1);
+   /* choose format from scratch */
+   f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
+   ASSERT(f != MESA_FORMAT_NONE);
+   return f;
+}
 
-#if FEATURE_convolve
-   if (_mesa_is_color_format(internalFormat)) {
-      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
-   }
-#endif
 
-   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);
+/**
+ * Common code to implement all the glTexImage1D/2D/3D functions.
+ */
+static void
+teximage(struct gl_context *ctx, GLuint dims,
+         GLenum target, GLint level, GLint internalFormat,
+         GLsizei width, GLsizei height, GLsizei depth,
+         GLint border, GLenum format, GLenum type,
+         const GLvoid *pixels)
+{
+   GLboolean error;
 
-      if (texture_error_check(ctx, target, level, internalFormat,
-                              format, type, 1, postConvWidth, 1, 1, border)) {
-         return;   /* error was recorded */
-      }
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-      if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
-        _mesa_update_state(ctx);
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n",
+                  dims,
+                  _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);
 
-      texUnit = get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, 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 );
-        }
+   internalFormat = override_internal_format(internalFormat, width, height);
 
-        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:
-      _mesa_unlock_texture(ctx, texObj);
+   /* target error checking */
+   if (!legal_teximage_target(ctx, dims, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)",
+                  dims, _mesa_lookup_enum_by_nr(target));
+      return;
    }
-   else if (target == GL_PROXY_TEXTURE_1D) {
-      /* Proxy texture: check for errors and update proxy state */
-      struct gl_texture_image *texImage;
-      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-      if (texture_error_check(ctx, target, level, internalFormat,
-                              format, type, 1, postConvWidth, 1, 1, border)) {
+
+   /* general error checking */
+   error = texture_error_check(ctx, dims, target, level, internalFormat,
+                               format, type, width, height, depth, border);
+
+   if (_mesa_is_proxy_texture(target)) {
+      /* Proxy texture: just clear or set state depending on error checking */
+      struct gl_texture_image *texImage =
+         _mesa_get_proxy_tex_image(ctx, target, level);
+
+      if (error) {
          /* when error, clear all proxy texture image parameters */
          if (texImage)
             clear_teximage_fields(texImage);
       }
       else {
          /* no error, set the tex image parameters */
-         ASSERT(texImage);
-         _mesa_init_teximage_fields(ctx, target, texImage,
-                                    postConvWidth, 1, 1,
-                                    border, internalFormat);
-         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
-                                          internalFormat, format, type);
+         struct gl_texture_object *texObj =
+            _mesa_get_current_tex_object(ctx, target);
+         gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
+                                                           target, level,
+                                                           internalFormat,
+                                                           format, type);
+
+         if (legal_texture_size(ctx, texFormat, width, height, depth)) {
+            _mesa_init_teximage_fields(ctx, target, texImage, width, height,
+                                       depth, border, internalFormat,
+                                       texFormat);
+         }
+         else if (texImage) {
+            clear_teximage_fields(texImage);
+         }
       }
    }
    else {
-      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
-      return;
-   }
-}
-
-
-void GLAPIENTRY
-_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
-                  GLsizei width, GLsizei height, GLint border,
-                  GLenum format, GLenum type,
-                  const GLvoid *pixels )
-{
-   GLsizei postConvWidth = width, postConvHeight = height;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   internalFormat = override_internal_format(internalFormat, width, height);
-
-#if FEATURE_convolve
-   if (_mesa_is_color_format(internalFormat)) {
-      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
-                                        &postConvHeight);
-   }
-#endif
-
-   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) ||
-       (ctx->Extensions.NV_texture_rectangle &&
-        target == GL_TEXTURE_RECTANGLE_NV) ||
-       (ctx->Extensions.MESA_texture_array &&
-        target == GL_TEXTURE_1D_ARRAY_EXT)) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
+      const GLuint face = _mesa_tex_target_to_face(target);
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      const GLuint face = _mesa_tex_target_to_face(target);
 
-      if (texture_error_check(ctx, target, level, internalFormat,
-                              format, type, 2, postConvWidth, postConvHeight,
-                              1, border)) {
+      if (error) {
          return;   /* error was recorded */
       }
 
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = 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;
+           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
         }
-        
-        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:
-      _mesa_unlock_texture(ctx, texObj);
-   }
-   else if (target == GL_PROXY_TEXTURE_2D ||
-            (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB &&
-             ctx->Extensions.ARB_texture_cube_map) ||
-            (target == GL_PROXY_TEXTURE_RECTANGLE_NV &&
-             ctx->Extensions.NV_texture_rectangle) ||
-            (ctx->Extensions.MESA_texture_array &&
-             target == GL_PROXY_TEXTURE_1D_ARRAY_EXT)) {
-      /* Proxy texture: check for errors and update proxy state */
-      struct gl_texture_image *texImage;
-      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-      if (texture_error_check(ctx, target, level, internalFormat,
-                              format, type, 2, postConvWidth, postConvHeight,
-                              1, border)) {
-         /* when error, clear all proxy texture image parameters */
-         if (texImage)
-            clear_teximage_fields(texImage);
-      }
-      else {
-         /* no error, set the tex image parameters */
-         _mesa_init_teximage_fields(ctx, target, texImage,
-                                    postConvWidth, postConvHeight, 1,
-                                    border, internalFormat);
-         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
-                                          internalFormat, format, type);
+         else {
+            gl_format texFormat;
+
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+
+            ASSERT(texImage->Data == NULL);
+            texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+                                                    internalFormat, format,
+                                                    type);
+
+            if (legal_texture_size(ctx, texFormat, width, height, depth)) {
+               _mesa_init_teximage_fields(ctx, target, texImage,
+                                          width, height, depth,
+                                          border, internalFormat, texFormat);
+
+               /* Give the texture to the driver.  <pixels> may be null. */
+               ASSERT(ctx->Driver.TexImage3D);
+               switch (dims) {
+               case 1:
+                  ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+                                         width, border, format,
+                                         type, pixels, &ctx->Unpack, texObj,
+                                         texImage);
+                  break;
+               case 2:
+                  ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+                                         width, height, border, format,
+                                         type, pixels, &ctx->Unpack, texObj,
+                                         texImage);
+                  break;
+               case 3:
+                  ctx->Driver.TexImage3D(ctx, target, level, internalFormat,
+                                         width, height, depth, border, format,
+                                         type, pixels, &ctx->Unpack, texObj,
+                                         texImage);
+                  break;
+               default:
+                  _mesa_problem(ctx, "invalid dims=%u in teximage()", dims);
+               }
+
+               check_gen_mipmap(ctx, target, texObj, level);
+
+               update_fbo_texture(ctx, texObj, face, level);
+
+               /* state update */
+               texObj->_Complete = GL_FALSE;
+               ctx->NewState |= _NEW_TEXTURE;
+            }
+            else {
+               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
+            }
+         }
       }
+      _mesa_unlock_texture(ctx, texObj);
    }
-   else {
-      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" );
-      return;
-   }
+}
+
+
+/*
+ * Called from the API.  Note that width includes the border.
+ */
+void GLAPIENTRY
+_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
+                  GLsizei width, GLint border, GLenum format,
+                  GLenum type, const GLvoid *pixels )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage(ctx, 1, target, level, internalFormat, width, 1, 1,
+            border, format, type, pixels);
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
+                  GLsizei width, GLsizei height, GLint border,
+                  GLenum format, GLenum type,
+                  const GLvoid *pixels )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage(ctx, 2, target, level, internalFormat, width, height, 1,
+            border, format, type, pixels);
 }
 
 
@@ -2699,89 +2503,8 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   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);
-
-      if (texture_error_check(ctx, target, level, (GLint) internalFormat,
-                              format, type, 3, width, height, depth, border)) {
-         return;   /* error was recorded */
-      }
-
-      if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
-        _mesa_update_state(ctx);
-
-      texUnit = get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, 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);
-
-        ASSERT(ctx->Driver.TexImage3D);
-
-        /* 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);
-
-        ASSERT(texImage->TexFormat);
-
-        update_fbo_texture(ctx, texObj, face, level);
-
-        /* state update */
-        texObj->_Complete = GL_FALSE;
-        ctx->NewState |= _NEW_TEXTURE;
-      }
-   out:
-      _mesa_unlock_texture(ctx, texObj);
-   }
-   else if (target == GL_PROXY_TEXTURE_3D ||
-       (ctx->Extensions.MESA_texture_array &&
-        target == GL_PROXY_TEXTURE_2D_ARRAY_EXT)) {
-      /* Proxy texture: check for errors and update proxy state */
-      struct gl_texture_image *texImage;
-      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-      if (texture_error_check(ctx, target, level, internalFormat,
-                              format, type, 3, width, height, depth, border)) {
-         /* when error, clear all proxy texture image parameters */
-         if (texImage)
-            clear_teximage_fields(texImage);
-      }
-      else {
-         /* 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);
-      }
-   }
-   else {
-      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
-      return;
-   }
+   teximage(ctx, 3, target, level, internalFormat, width, height, depth,
+            border, format, type, pixels);
 }
 
 
@@ -2796,423 +2519,397 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
 }
 
 
-
+#if FEATURE_OES_EGL_image
 void GLAPIENTRY
-_mesa_TexSubImage1D( GLenum target, GLint level,
-                     GLint xoffset, GLsizei width,
-                     GLenum format, GLenum type,
-                     const GLvoid *pixels )
+_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
 {
-   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 (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
-      _mesa_update_state(ctx);
-
-#if FEATURE_convolve
-   /* XXX should test internal format */
-   if (_mesa_is_color_format(format)) {
-      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
+   if (!ctx->Extensions.OES_EGL_image) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glEGLImageTargetTexture2DOES(unsupported)");
+      return;
    }
-#endif
 
-   if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0,
-                              postConvWidth, 1, 1, format, type)) {
-      return;   /* error was detected */
+   if (target != GL_TEXTURE_2D) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                 "glEGLImageTargetTexture2D(target=%d)", target);
+      return;
    }
 
+   if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
+      _mesa_update_state(ctx);
 
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   assert(texObj);
-
+   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, 1, target, level, xoffset, 0, 0,
-                                 postConvWidth, 1, 1, format, type, texImage)) {
-        goto out;   /* error was detected */
-      }
 
-      if (width == 0)
-        goto out;  /* no-op, not an error */
+   texImage = _mesa_get_tex_image(ctx, texObj, target, 0);
+   if (!texImage) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D");
+   } else {
+      if (texImage->Data)
+        ctx->Driver.FreeTexImageData( ctx, texImage );
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
+      ASSERT(texImage->Data == NULL);
+      ctx->Driver.EGLImageTargetTexture2D(ctx, target,
+                                         texObj, texImage, image);
 
-      ASSERT(ctx->Driver.TexSubImage1D);
-      (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
-                                  format, type, pixels, &ctx->Unpack,
-                                  texObj, texImage);
+      /* state update */
+      texObj->_Complete = GL_FALSE;
       ctx->NewState |= _NEW_TEXTURE;
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
+
 }
+#endif
 
 
-void GLAPIENTRY
-_mesa_TexSubImage2D( GLenum target, GLint level,
-                     GLint xoffset, GLint yoffset,
-                     GLsizei width, GLsizei height,
-                     GLenum format, GLenum type,
-                     const GLvoid *pixels )
+
+/**
+ * Implement all the glTexSubImage1/2/3D() functions.
+ */
+static void
+texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
+            GLint xoffset, GLint yoffset, GLint zoffset,
+            GLsizei width, GLsizei height, GLsizei depth,
+            GLenum format, GLenum type, 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, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n",
+                  dims,
+                  _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);
+
+   /* check target (proxies not allowed) */
+   if (!legal_texsubimage_target(ctx, dims, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
+                  dims, _mesa_lookup_enum_by_nr(target));
+      return;
+   }       
+
    if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
       _mesa_update_state(ctx);
 
-#if FEATURE_convolve
-   /* XXX should test internal format */
-   if (_mesa_is_color_format(format)) {
-      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
-                                         &postConvHeight);
-   }
-#endif
-
-   if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
-                             postConvWidth, postConvHeight, 1, format, type)) {
+   if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset,
+                              width, height, depth, format, type)) {
       return;   /* error was detected */
    }
 
-   texUnit = 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 */
-      }
+      if (subtexture_error_check2(ctx, dims, 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, offset=-1 is legal.  Bias by border width. */
+         switch (dims) {
+         case 3:
+            zoffset += texImage->Border;
+            /* fall-through */
+         case 2:
+            yoffset += texImage->Border;
+            /* fall-through */
+         case 1:
+            xoffset += texImage->Border;
+         }
+
+         switch (dims) {
+         case 1:
+            ctx->Driver.TexSubImage1D(ctx, target, level,
+                                      xoffset, width,
+                                      format, type, pixels,
+                                      &ctx->Unpack, texObj, texImage );
+            break;
+         case 2:
+            ctx->Driver.TexSubImage2D(ctx, target, level,
+                                      xoffset, yoffset, width, height,
+                                      format, type, pixels,
+                                      &ctx->Unpack, texObj, texImage );
+            break;
+         case 3:
+            ctx->Driver.TexSubImage3D(ctx, target, level,
+                                      xoffset, yoffset, zoffset,
+                                      width, height, depth,
+                                      format, type, pixels,
+                                      &ctx->Unpack, texObj, texImage );
+            break;
+         default:
+            _mesa_problem(ctx, "unexpected dims in subteximage()");
+         }
 
-      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);
 }
 
 
-
 void GLAPIENTRY
-_mesa_TexSubImage3D( GLenum target, GLint level,
-                     GLint xoffset, GLint yoffset, GLint zoffset,
-                     GLsizei width, GLsizei height, GLsizei depth,
+_mesa_TexSubImage1D( GLenum target, GLint level,
+                     GLint xoffset, GLsizei width,
                      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 (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
-      _mesa_update_state(ctx);
-
-   if (subtexture_error_check(ctx, 3, target, level, xoffset, yoffset, zoffset,
-                              width, height, depth, format, type)) {
-      return;   /* error was detected */
-   }
-
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texsubimage(ctx, 1, target, level,
+               xoffset, 0, 0,
+               width, 1, 1,
+               format, type, pixels);
+}
 
-   _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 */
-      }
+void GLAPIENTRY
+_mesa_TexSubImage2D( GLenum target, GLint level,
+                     GLint xoffset, GLint yoffset,
+                     GLsizei width, GLsizei height,
+                     GLenum format, GLenum type,
+                     const GLvoid *pixels )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texsubimage(ctx, 2, target, level,
+               xoffset, yoffset, 0,
+               width, height, 1,
+               format, type, pixels);
+}
 
-      if (width == 0 || height == 0 || height == 0)
-        goto out;  /* no-op, not an error */
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
-      yoffset += texImage->Border;
-      zoffset += texImage->Border;
 
-      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;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+void GLAPIENTRY
+_mesa_TexSubImage3D( GLenum target, GLint level,
+                     GLint xoffset, GLint yoffset, GLint zoffset,
+                     GLsizei width, GLsizei height, GLsizei depth,
+                     GLenum format, GLenum type,
+                     const GLvoid *pixels )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texsubimage(ctx, 3, target, level,
+               xoffset, yoffset, zoffset,
+               width, height, depth,
+               format, type, pixels);
 }
 
 
 
-void GLAPIENTRY
-_mesa_CopyTexImage1D( GLenum target, GLint level,
-                      GLenum internalFormat,
-                      GLint x, GLint y,
-                      GLsizei width, GLint border )
+/**
+ * Implement the glCopyTexImage1/2D() functions.
+ */
+static void
+copyteximage(struct gl_context *ctx, GLuint dims,
+             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;
    const GLuint face = _mesa_tex_target_to_face(target);
-   GET_CURRENT_CONTEXT(ctx);
+
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n",
+                  dims,
+                  _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);
 
-#if FEATURE_convolve
-   if (_mesa_is_color_format(internalFormat)) {
-      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
-   }
-#endif
-
-   if (copytexture_error_check(ctx, 1, target, level, internalFormat,
-                               postConvWidth, 1, border))
+   if (copytexture_error_check(ctx, dims, target, level, internalFormat,
+                               width, height, border))
       return;
 
-   texUnit = 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;
+        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
       }
+      else {
+         gl_format texFormat;
 
-      if (texImage->Data) {
-        ctx->Driver.FreeTexImageData( ctx, texImage );
-      }
-      
-      ASSERT(texImage->Data == NULL);
+         if (texImage->Data) {
+            ctx->Driver.FreeTexImageData( ctx, texImage );
+         }
 
-      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);
 
+         texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+                                                 internalFormat, GL_NONE,
+                                                 GL_NONE);
 
-      ASSERT(ctx->Driver.CopyTexImage1D);
-      (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat,
-                                   x, y, width, border);
+         if (legal_texture_size(ctx, texFormat, width, height, 1)) {
+            _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
+                                       border, internalFormat, texFormat);
 
-      ASSERT(texImage->TexFormat);
+            ASSERT(ctx->Driver.CopyTexImage2D);
+            if (dims == 1)
+               ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
+                                          x, y, width, border);
+            else
+               ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
+                                          x, y, width, height, border);
 
-      update_fbo_texture(ctx, texObj, face, level);
+            check_gen_mipmap(ctx, target, texObj, level);
 
-      /* state update */
-      texObj->_Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+            update_fbo_texture(ctx, texObj, face, level);
+
+            /* state update */
+            texObj->_Complete = GL_FALSE;
+            ctx->NewState |= _NEW_TEXTURE;
+         }
+         else {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
+         }
+      }
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
 
 
 void GLAPIENTRY
-_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
-                      GLint x, GLint y, GLsizei width, GLsizei height,
-                      GLint border )
+_mesa_CopyTexImage1D( GLenum target, GLint level,
+                      GLenum internalFormat,
+                      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, postConvHeight = height;
-   const GLuint face = _mesa_tex_target_to_face(target);
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   if (ctx->NewState & NEW_COPY_TEX_STATE)
-      _mesa_update_state(ctx);
-
-#if FEATURE_convolve
-   if (_mesa_is_color_format(internalFormat)) {
-      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
-                                         &postConvHeight);
-   }
-#endif
-
-   if (copytexture_error_check(ctx, 2, target, level, internalFormat,
-                               postConvWidth, postConvHeight, border))
-      return;
-
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_get_tex_image(ctx, texObj, target, level);
-
-      if (!texImage) {
-        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
-        goto out;
-      }
-      
-      if (texImage->Data) {
-        ctx->Driver.FreeTexImageData( ctx, texImage );
-      }
-      
-      ASSERT(texImage->Data == NULL);
+   copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border);
+}
 
-      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);
 
-      update_fbo_texture(ctx, texObj, face, level);
 
-      /* state update */
-      texObj->_Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+void GLAPIENTRY
+_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
+                      GLint x, GLint y, GLsizei width, GLsizei height,
+                      GLint border )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   copyteximage(ctx, 2, target, level, internalFormat,
+                x, y, width, height, border);
 }
 
 
-void GLAPIENTRY
-_mesa_CopyTexSubImage1D( GLenum target, GLint level,
-                         GLint xoffset, GLint x, GLint y, GLsizei width )
+
+/**
+ * Implementation for glCopyTexSubImage1/2/3D() functions.
+ */
+static void
+copytexsubimage(struct gl_context *ctx, GLuint dims, 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;
-   GLint yoffset = 0;
-   GLsizei height = 1;
 
-   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n",
+                  dims,
+                  _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, 1, target, level))
+   if (copytexsubimage_error_check1(ctx, dims, target, level))
       return;
 
-   texUnit = 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 FEATURE_convolve
-      if (texImage && _mesa_is_color_format(texImage->InternalFormat)) {
-         _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
+      if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset,
+                                      zoffset, width, height, texImage)) {
+         /* error was recored */
       }
-#endif
+      else {
+         /* If we have a border, offset=-1 is legal.  Bias by border width. */
+         switch (dims) {
+         case 3:
+            zoffset += texImage->Border;
+            /* fall-through */
+         case 2:
+            yoffset += texImage->Border;
+            /* fall-through */
+         case 1:
+            xoffset += texImage->Border;
+         }
 
-      if (copytexsubimage_error_check2(ctx, 1, target, level,
-                                      xoffset, 0, 0, postConvWidth, 1,
-                                      texImage))
-        goto out;
-      
+         if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                        &width, &height)) {
+            switch (dims) {
+            case 1:
+               ctx->Driver.CopyTexSubImage1D(ctx, target, level,
+                                             xoffset, x, y, width);
+               break;
+            case 2:
+               ctx->Driver.CopyTexSubImage2D(ctx, target, level,
+                                             xoffset, yoffset,
+                                             x, y, width, height);
+               break;
+            case 3:
+               ctx->Driver.CopyTexSubImage3D(ctx, target, level,
+                                             xoffset, yoffset, zoffset,
+                                             x, y, width, height);
+               break;
+            default:
+               _mesa_problem(ctx, "bad dims in copytexsubimage()");
+            }
 
-      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-      xoffset += texImage->Border;
+            check_gen_mipmap(ctx, target, texObj, level);
 
-      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);
+            ctx->NewState |= _NEW_TEXTURE;
+         }
       }
-
-      ctx->NewState |= _NEW_TEXTURE;
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }
 
 
+void GLAPIENTRY
+_mesa_CopyTexSubImage1D( GLenum target, GLint level,
+                         GLint xoffset, GLint x, GLint y, GLsizei width )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   copytexsubimage(ctx, 1, target, level, xoffset, 0, 0, x, y, width, 1);
+}
+
+
 
 void GLAPIENTRY
 _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 (ctx->NewState & NEW_COPY_TEX_STATE)
-      _mesa_update_state(ctx);
-
-   if (copytexsubimage_error_check1(ctx, 2, target, level))
-      return;
-
-   texUnit = 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);
-
-#if FEATURE_convolve
-      if (texImage && _mesa_is_color_format(texImage->InternalFormat)) {
-         _mesa_adjust_image_for_convolution(ctx, 2,
-                                            &postConvWidth, &postConvHeight);
-      }
-#endif
-
-      if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
-                                      postConvWidth, postConvHeight, texImage))
-        goto out;
-
-      /* 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);
-      }
-
-      ctx->NewState |= _NEW_TEXTURE;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+   copytexsubimage(ctx, 2, target, level, xoffset, yoffset, 0, x, y,
+                   width, height);
 }
 
 
@@ -3222,63 +2919,40 @@ _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 (ctx->NewState & NEW_COPY_TEX_STATE)
-      _mesa_update_state(ctx);
-
-   if (copytexsubimage_error_check1(ctx, 3, target, level))
-      return;
+   copytexsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset,
+                   x, y, width, height);
+}
 
-   texUnit = 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);
 
-#if FEATURE_convolve
-      if (texImage && _mesa_is_color_format(texImage->InternalFormat)) {
-         _mesa_adjust_image_for_convolution(ctx, 2,
-                                            &postConvWidth, &postConvHeight);
-      }
-#endif
 
-      if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset,
-                                      zoffset, postConvWidth, postConvHeight,
-                                      texImage))
-        goto out;
+/**********************************************************************/
+/******                   Compressed Textures                    ******/
+/**********************************************************************/
 
-      /* 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);
-      }
 
-      ctx->NewState |= _NEW_TEXTURE;
-   }
- out:
-   _mesa_unlock_texture(ctx, texObj);
+/**
+ * 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);
 }
 
 
-
-
-/**********************************************************************/
-/******                   Compressed Textures                    ******/
-/**********************************************************************/
+/*
+ * 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);
+}
 
 
 /**
@@ -3286,97 +2960,77 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
  * \return error code or GL_NO_ERROR.
  */
 static GLenum
-compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
+compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
                                GLenum target, GLint level,
                                GLenum internalFormat, GLsizei width,
                                GLsizei height, GLsizei depth, GLint border,
                                GLsizei imageSize)
 {
-   GLint expectedSize, maxLevels = 0, maxTextureSize;
+   const GLenum proxyTarget = get_proxy_target(target);
+   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
+   GLint expectedSize;
 
-   if (dimensions == 1) {
-      /* 1D compressed textures not allowed */
+   /* check level */
+   if (level < 0 || level >= maxLevels)
+      return GL_INVALID_VALUE;
+
+   if (!target_can_be_compressed(ctx, target, internalFormat)) {
       return GL_INVALID_ENUM;
    }
-   else if (dimensions == 2) {
-      if (target == GL_PROXY_TEXTURE_2D) {
-         maxLevels = ctx->Const.MaxTextureLevels;
-      }
-      else if (target == GL_TEXTURE_2D) {
-         maxLevels = ctx->Const.MaxTextureLevels;
-      }
-      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map)
-            return GL_INVALID_ENUM; /*target*/
-         maxLevels = ctx->Const.MaxCubeTextureLevels;
-      }
-      else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-               target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map)
-            return GL_INVALID_ENUM; /*target*/
-         maxLevels = ctx->Const.MaxCubeTextureLevels;
-      }
-      else {
-         return GL_INVALID_ENUM; /*target*/
-      }
-   }
-   else if (dimensions == 3) {
-      /* 3D compressed textures not allowed */
-      return GL_INVALID_ENUM;
-   }
-
-   maxTextureSize = 1 << (maxLevels - 1);
 
    /* This will detect any invalid internalFormat value */
-   if (!is_compressed_format(ctx, internalFormat))
+   if (!_mesa_is_compressed_format(ctx, internalFormat))
       return GL_INVALID_ENUM;
 
    /* This should really never fail */
    if (_mesa_base_tex_format(ctx, internalFormat) < 0)
       return GL_INVALID_ENUM;
 
+   /* No compressed formats support borders at this time */
    if (border != 0)
       return GL_INVALID_VALUE;
 
-   /*
-    * XXX We should probably use the proxy texture error check function here.
-    */
-   if (width < 1 || width > maxTextureSize ||
-       (!ctx->Extensions.ARB_texture_non_power_of_two && !_mesa_is_pow_two(width)))
-      return GL_INVALID_VALUE;
-
-   if ((height < 1 || height > maxTextureSize ||
-       (!ctx->Extensions.ARB_texture_non_power_of_two && !_mesa_is_pow_two(height)))
-       && dimensions > 1)
-      return GL_INVALID_VALUE;
-
-   if ((depth < 1 || depth > maxTextureSize ||
-       (!ctx->Extensions.ARB_texture_non_power_of_two && !_mesa_is_pow_two(depth)))
-       && dimensions > 2)
-      return GL_INVALID_VALUE;
-
    /* For cube map, width must equal height */
    if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height)
       return GL_INVALID_VALUE;
 
-   if (level < 0 || level >= maxLevels)
-      return GL_INVALID_VALUE;
+   /* check image size against compression block size */
+   {
+      gl_format texFormat =
+         ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                         GL_NONE, GL_NONE);
+      GLuint bw, bh;
+
+      _mesa_get_format_block_size(texFormat, &bw, &bh);
+      if ((width > bw && width % bw > 0) ||
+          (height > bh && height % bh > 0)) {
+         /*
+          * Per GL_ARB_texture_compression:  GL_INVALID_OPERATION is
+          * generated [...] if any parameter combinations are not
+          * supported by the specific compressed internal format. 
+          */
+         return GL_INVALID_OPERATION;
+      }
+   }
+
+   /* check image sizes */
+   if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
+                                      internalFormat, GL_NONE, GL_NONE,
+                                      width, height, depth, border)) {
+      /* See error comment above */
+      return GL_INVALID_OPERATION;
+   }
 
-   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
-                                                       depth, internalFormat);
-   if (expectedSize != imageSize)
+   /* check image size in bytes */
+   expectedSize = compressed_tex_size(width, height, depth, internalFormat);
+   if (expectedSize != imageSize) {
+      /* Per GL_ARB_texture_compression:  GL_INVALID_VALUE is generated [...]
+       * if <imageSize> is not consistent with the format, dimensions, and
+       * contents of the specified image.
+       */
       return GL_INVALID_VALUE;
-
-#if FEATURE_EXT_texture_sRGB
-   if ((internalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ||
-        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ||
-        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ||
-        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT)
-       && border != 0) {
-      return GL_INVALID_OPERATION;
    }
-#endif
 
    return GL_NO_ERROR;
 }
@@ -3390,13 +3044,14 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
  * \return error code or GL_NO_ERROR.
  */
 static GLenum
-compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
+compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions,
                                   GLenum target, GLint level,
                                   GLint xoffset, GLint yoffset, GLint zoffset,
                                   GLsizei width, GLsizei height, GLsizei depth,
                                   GLenum format, GLsizei imageSize)
 {
    GLint expectedSize, maxLevels = 0, maxTextureSize;
+   GLuint bw, bh;
    (void) zoffset;
 
    if (dimensions == 1) {
@@ -3433,7 +3088,7 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
    maxTextureSize = 1 << (maxLevels - 1);
 
    /* this will catch any invalid compressed format token */
-   if (!is_compressed_format(ctx, format))
+   if (!_mesa_is_compressed_format(ctx, format))
       return GL_INVALID_ENUM;
 
    if (width < 1 || width > maxTextureSize)
@@ -3446,20 +3101,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;
 
@@ -3467,197 +3123,246 @@ 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(struct gl_context *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;
+   }
 
-void GLAPIENTRY
-_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
-                              GLenum internalFormat, GLsizei width,
-                              GLint border, GLsizei imageSize,
-                              const GLvoid *data)
+   if (((width == 1 || width == 2) &&
+        width != (GLsizei) texImage->Width) ||
+       (width > (GLsizei) 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) &&
+           height != (GLsizei) texImage->Height) ||
+          (height > (GLsizei) 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) &&
+           depth != (GLsizei) texImage->Depth) ||
+          (depth > (GLsizei) texImage->Depth)) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCompressedTexSubImage%uD(depth=%d)", dims, depth);
+         return GL_TRUE;
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
+/**
+ * Implementation of the glCompressedTexImage1/2/3D() functions.
+ */
+static void
+compressedteximage(struct gl_context *ctx, GLuint dims,
+                   GLenum target, GLint level,
+                   GLenum internalFormat, GLsizei width,
+                   GLsizei height, GLsizei depth, GLint border,
+                   GLsizei imageSize, const GLvoid *data)
 {
-   GET_CURRENT_CONTEXT(ctx);
+   GLenum error;
+
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (target == GL_TEXTURE_1D) {
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx,
+                  "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n",
+                  dims,
+                  _mesa_lookup_enum_by_nr(target), level,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  width, height, depth, border, imageSize, data);
+
+   /* check target */
+   if (!legal_teximage_target(ctx, dims, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)",
+                  dims, _mesa_lookup_enum_by_nr(target));
+      return;
+   }
+
+   error = compressed_texture_error_check(ctx, dims, target, level,
+                                          internalFormat, width, height, depth,
+                                          border, imageSize);
+
+#if FEATURE_ES
+   /* XXX this is kind of a hack */
+   if (error) {
+      _mesa_error(ctx, error, "glTexImage2D");
+      return;
+   }
+
+   if (dims == 2) {
+      switch (internalFormat) {
+      case GL_PALETTE4_RGB8_OES:
+      case GL_PALETTE4_RGBA8_OES:
+      case GL_PALETTE4_R5_G6_B5_OES:
+      case GL_PALETTE4_RGBA4_OES:
+      case GL_PALETTE4_RGB5_A1_OES:
+      case GL_PALETTE8_RGB8_OES:
+      case GL_PALETTE8_RGBA8_OES:
+      case GL_PALETTE8_R5_G6_B5_OES:
+      case GL_PALETTE8_RGBA4_OES:
+      case GL_PALETTE8_RGB5_A1_OES:
+         _mesa_cpal_compressed_teximage2d(target, level, internalFormat,
+                                          width, height, imageSize, data);
+         return;
+      }
+   }
+#endif
+
+   if (_mesa_is_proxy_texture(target)) {
+      /* Proxy texture: just check for errors and update proxy state */
+      struct gl_texture_image *texImage;
+
+      if (!error) {
+         struct gl_texture_object *texObj =
+            _mesa_get_current_tex_object(ctx, target);
+         gl_format texFormat =
+            _mesa_choose_texture_format(ctx, texObj, target, level,
+                                        internalFormat, GL_NONE, GL_NONE);
+         if (!legal_texture_size(ctx, texFormat, width, height, depth)) {
+            error = GL_OUT_OF_MEMORY;
+         }
+      }
+
+      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
+      if (texImage) {
+         if (error) {
+            /* if error, clear all proxy texture image parameters */
+            clear_teximage_fields(texImage);
+         }
+         else {
+            /* no error: store the teximage parameters */
+            _mesa_init_teximage_fields(ctx, target, texImage, width, height,
+                                       depth, border, internalFormat,
+                                       MESA_FORMAT_NONE);
+         }
+      }
+   }
+   else {
       /* 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,
-                               internalFormat, width, 1, 1, border, imageSize);
+
       if (error) {
-         _mesa_error(ctx, error, "glCompressedTexImage1D");
+         _mesa_error(ctx, error, "glCompressedTexImage%uD", dims);
          return;
       }
 
-      texUnit = 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 );
+           _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                        "glCompressedTexImage%uD", dims);
         }
-        ASSERT(texImage->Data == NULL);
+         else {
+            gl_format texFormat;
 
-        _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
-                                   border, internalFormat);
+            if (texImage->Data) {
+               ctx->Driver.FreeTexImageData( ctx, texImage );
+            }
+            ASSERT(texImage->Data == NULL);
+
+            texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+                                                    internalFormat, GL_NONE,
+                                                    GL_NONE);
+
+            if (legal_texture_size(ctx, texFormat, width, height, depth)) {
+               _mesa_init_teximage_fields(ctx, target, texImage,
+                                          width, height, depth,
+                                          border, internalFormat, texFormat);
+
+               switch (dims) {
+               case 1:
+                  ASSERT(ctx->Driver.CompressedTexImage1D);
+                  ctx->Driver.CompressedTexImage1D(ctx, target, level,
+                                                   internalFormat,
+                                                   width,
+                                                   border, imageSize, data,
+                                                   texObj, texImage);
+                  break;
+               case 2:
+                  ASSERT(ctx->Driver.CompressedTexImage2D);
+                  ctx->Driver.CompressedTexImage2D(ctx, target, level,
+                                                   internalFormat,
+                                                   width, height,
+                                                   border, imageSize, data,
+                                                   texObj, texImage);
+                  break;
+               case 3:
+                  ASSERT(ctx->Driver.CompressedTexImage3D);
+                  ctx->Driver.CompressedTexImage3D(ctx, target, level,
+                                                   internalFormat,
+                                                   width, height, depth,
+                                                   border, imageSize, data,
+                                                   texObj, texImage);
+                  break;
+               default:
+                  _mesa_problem(ctx, "bad dims in compressedteximage");
+               }
 
-        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;
+            }
+            else {
+               _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                           "glCompressedTexImage%uD", dims);
+            }
+         }
       }
-   out:
       _mesa_unlock_texture(ctx, texObj);
    }
-   else if (target == GL_PROXY_TEXTURE_1D) {
-      /* Proxy texture: check for errors and update proxy state */
-      GLenum error = compressed_texture_error_check(ctx, 1, target, level,
-                               internalFormat, width, 1, 1, border, imageSize);
-      if (!error) {
-         ASSERT(ctx->Driver.TestProxyTexImage);
-         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
-                                             internalFormat, GL_NONE, GL_NONE,
-                                             width, 1, 1, border);
-      }
-      if (error) {
-         /* if error, clear all proxy texture image parameters */
-         struct gl_texture_image *texImage;
-         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-         if (texImage)
-            clear_teximage_fields(texImage);
-      }
-      else {
-         /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
-         struct gl_texture_object *texObj;
-         struct gl_texture_image *texImage;
-         texUnit = 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);
-           _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
-                                      border, internalFormat);
-        }
-        _mesa_unlock_texture(ctx, texObj);
-      }
-   }
-   else {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage1D(target)");
-      return;
-   }
 }
 
 
 void GLAPIENTRY
-_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
+_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
                               GLenum internalFormat, GLsizei width,
-                              GLsizei height, GLint border, GLsizei imageSize,
+                              GLint border, GLsizei imageSize,
                               const GLvoid *data)
 {
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   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) {
-         _mesa_error(ctx, error, "glCompressedTexImage2D");
-         return;
-      }
+   compressedteximage(ctx, 1, target, level, internalFormat,
+                      width, 1, 1, border, imageSize, data);
+}
 
-      texUnit = get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, 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:
-      _mesa_unlock_texture(ctx, texObj);
-   }
-   else if (target == GL_PROXY_TEXTURE_2D ||
-            (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB &&
-             ctx->Extensions.ARB_texture_cube_map)) {
-      /* Proxy texture: check for errors and update proxy state */
-      GLenum error = compressed_texture_error_check(ctx, 2, target, level,
-                          internalFormat, width, height, 1, border, imageSize);
-      if (!error) {
-         ASSERT(ctx->Driver.TestProxyTexImage);
-         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
-                                              internalFormat, GL_NONE, GL_NONE,
-                                              width, height, 1, border);
-      }
-      if (error) {
-         /* if error, clear all proxy texture image parameters */
-         struct gl_texture_image *texImage;
-         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-         if (texImage)
-            clear_teximage_fields(texImage);
-      }
-      else {
-         /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
-         struct gl_texture_object *texObj;
-         struct gl_texture_image *texImage;
-         texUnit = 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);
-           _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
-                                      border, internalFormat);
-        }
-        _mesa_unlock_texture(ctx, texObj);
-      }
-   }
-   else {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2D(target)");
-      return;
-   }
+void GLAPIENTRY
+_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
+                              GLenum internalFormat, GLsizei width,
+                              GLsizei height, GLint border, GLsizei imageSize,
+                              const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   compressedteximage(ctx, 2, target, level, internalFormat,
+                      width, height, 1, border, imageSize, data);
 }
 
 
@@ -3668,202 +3373,105 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
                               GLsizei imageSize, const GLvoid *data)
 {
    GET_CURRENT_CONTEXT(ctx);
-   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;
-      GLenum error = compressed_texture_error_check(ctx, 3, target, level,
-                      internalFormat, width, height, depth, border, imageSize);
-      if (error) {
-         _mesa_error(ctx, error, "glCompressedTexImage3D");
-         return;
-      }
-
-      texUnit = get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, 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:
-      _mesa_unlock_texture(ctx, texObj);
-   }
-   else if (target == GL_PROXY_TEXTURE_3D) {
-      /* Proxy texture: check for errors and update proxy state */
-      GLenum error = compressed_texture_error_check(ctx, 3, target, level,
-                      internalFormat, width, height, depth, border, imageSize);
-      if (!error) {
-         ASSERT(ctx->Driver.TestProxyTexImage);
-         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
-                                             internalFormat, GL_NONE, GL_NONE,
-                                             width, height, depth, border);
-      }
-      if (error) {
-         /* if error, clear all proxy texture image parameters */
-         struct gl_texture_image *texImage;
-         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-         if (texImage)
-            clear_teximage_fields(texImage);
-      }
-      else {
-         /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
-         struct gl_texture_object *texObj;
-         struct gl_texture_image *texImage;
-         texUnit = 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);
-           _mesa_init_teximage_fields(ctx, target, texImage, width, height,
-                                      depth, border, internalFormat);
-        }
-        _mesa_unlock_texture(ctx, texObj);
-      }
-   }
-   else {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage3D(target)");
-      return;
-   }
+   compressedteximage(ctx, 3, target, level, internalFormat,
+                      width, height, depth, border, imageSize, data);
 }
 
 
-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 = 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 = 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);
 }
 
 
@@ -3873,108 +3481,6 @@ _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 = 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);
-}
-
-
-void GLAPIENTRY
-_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
-{
-   const struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLint maxLevels;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   texUnit = get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   if (!texObj) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB");
-      return;
-   }
-
-   maxLevels = _mesa_max_texture_levels(ctx, target);
-   ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */
-
-   if (level < 0 || level >= maxLevels) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
-      return;
-   }
-
-   if (_mesa_is_proxy_texture(target)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
-      return;
-   }
-
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      if (texImage) {
-         if (texImage->IsCompressed) {
-            /* this typically calls _mesa_get_compressed_teximage() */
-            ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
-                                              texObj, texImage);
-         }
-         else {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glGetCompressedTexImageARB");
-         }
-      }
-      else {
-         /* probably invalid mipmap level */
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glGetCompressedTexImageARB(level)");
-      }
-   }
-   _mesa_unlock_texture(ctx, texObj);
+   compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset,
+                            width, height, depth, format, imageSize, data);
 }