mesa: Allow querying the system FBO in GetFramebufferAttachmentParameteriv
[mesa.git] / src / mesa / main / teximage.c
index 4fbfeb8582680176bdbefb741ba317890e1ddc4e..ff752155ea9a3ff374104da02903dcce04d5395a 100644 (file)
@@ -46,7 +46,7 @@
 #include "texfetch.h"
 #include "teximage.h"
 #include "texstate.h"
-#include "texstore.h"
+#include "texpal.h"
 #include "mtypes.h"
 
 
@@ -82,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.
@@ -415,34 +358,6 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
 }
 
 
-/**
- * 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;
-      }
-   }
-   return GL_FALSE;
-}
-
-
 /**
  * For cube map faces, return a face index in [0,5].
  * For other targets return 0;
@@ -546,8 +461,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);
 }
 
 
@@ -639,6 +554,17 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
 }
 
 
+/**
+ * Return pointer to texture object for given target on current texture unit.
+ */
+struct gl_texture_object *
+_mesa_get_current_tex_object(GLcontext *ctx, GLenum target)
+{
+   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+   return _mesa_select_tex_object(ctx, texUnit, target);
+}
+
+
 /**
  * Get a texture image pointer from a texture object, given a texture
  * target and mipmap level.  The target and level parameters should
@@ -890,7 +816,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;
@@ -979,8 +905,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;
    }
@@ -1313,8 +1239,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
    if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
       if (!isProxy) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(internalFormat=0x%x)",
-                     dimensions, internalFormat);
+                     "glTexImage%dD(internalFormat=%s)",
+                     dimensions, _mesa_lookup_enum_by_nr(internalFormat));
       }
       return GL_TRUE;
    }
@@ -1354,8 +1280,8 @@ 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_snprintf(message, sizeof(message),
+                        "glTexImage%dD(format/type YCBCR mismatch", dimensions);
          _mesa_error(ctx, GL_INVALID_ENUM, message);
          return GL_TRUE; /* error */
       }
@@ -1370,9 +1296,9 @@ 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_snprintf(message, sizeof(message),
+                           "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)",
+                           dimensions, border);
             _mesa_error(ctx, GL_INVALID_VALUE, message);
          }
          return GL_TRUE;
@@ -1396,16 +1322,16 @@ texture_error_check( GLcontext *ctx, GLenum target,
    }
 
    /* additional checks for compressed textures */
-   if (is_compressed_format(ctx, internalFormat)) {
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
       if (!target_can_be_compressed(ctx, target) && !isProxy) {
          _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexImage%d(target)", dimensions);
+                     "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;
       }
@@ -1526,6 +1452,11 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
    return GL_FALSE;
 }
 
+
+/**
+ * Do second part of glTexSubImage which depends on the destination texture.
+ * \return GL_TRUE if error recorded, GL_FALSE otherwise
+ */
 static GLboolean
 subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
                         GLenum target, GLint level,
@@ -1573,41 +1504,35 @@ subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-#if FEATURE_EXT_texture_sRGB
-   if (destTex->InternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ||
-       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
-      if ((width & 0x3) || (height & 0x3) ||
-          (xoffset & 0x3) || (yoffset & 0x3))
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%dD(size or offset not multiple of 4)",
-                     dimensions);
-      return GL_TRUE;
-   }
-#endif
-
    if (_mesa_is_format_compressed(destTex->TexFormat)) {
+      GLuint bw, bh;
+
       if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexSubImage%D(target)", dimensions);
+                     "glTexSubImage%dD(target=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(target));
          return GL_TRUE;
       }
-      /* offset must be multiple of 4 */
-      if ((xoffset & 3) || (yoffset & 3)) {
+
+      /* do tests which depend on compression block size */
+      _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
+
+      /* offset must be multiple of block size */
+      if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%D(xoffset or yoffset)", dimensions);
+                     "glTexSubImage%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;
       }         
    }
@@ -1763,15 +1688,15 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   if (is_compressed_format(ctx, internalFormat)) {
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
       if (!target_can_be_compressed(ctx, target)) {
          _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;
       }
    }
@@ -1779,7 +1704,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       /* 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;
       }
    }
@@ -1787,7 +1712,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       /* 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;
       }
    }
@@ -1952,24 +1877,24 @@ copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
    if (_mesa_is_format_compressed(teximage->TexFormat)) {
       if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glCopyTexSubImage%d(target)", dimensions);
+                     "glCopyTexSubImage%dD(target)", dimensions);
          return GL_TRUE;
       }
       /* 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;
       }         
    }
@@ -1989,7 +1914,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;
       }
@@ -1997,7 +1922,7 @@ 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;
       }
@@ -2082,7 +2007,9 @@ check_gen_mipmap(GLcontext *ctx, GLenum target,
                  struct gl_texture_object *texObj, GLint level)
 {
    ASSERT(target != GL_TEXTURE_CUBE_MAP);
-   if (texObj->GenerateMipmap && level == texObj->BaseLevel) {
+   if (texObj->GenerateMipmap &&
+       level == texObj->BaseLevel &&
+       level < texObj->MaxLevel) {
       ASSERT(ctx->Driver.GenerateMipmap);
       ctx->Driver.GenerateMipmap(ctx, target, texObj);
    }
@@ -2162,7 +2089,6 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
 
    if (target == GL_TEXTURE_1D) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       const GLuint face = _mesa_tex_target_to_face(target);
@@ -2175,8 +2101,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
@@ -2195,6 +2120,12 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
                                        postConvWidth, 1, 1,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             /* Give the texture to the driver.  <pixels> may be null. */
             ASSERT(ctx->Driver.TexImage1D);
             ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
@@ -2278,7 +2209,6 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
        (ctx->Extensions.MESA_texture_array &&
         target == GL_TEXTURE_1D_ARRAY_EXT)) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       const GLuint face = _mesa_tex_target_to_face(target);
@@ -2292,8 +2222,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
@@ -2311,6 +2240,12 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
                                        postConvWidth, postConvHeight, 1,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             /* Give the texture to the driver.  <pixels> may be null. */
             ASSERT(ctx->Driver.TexImage2D);
             ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
@@ -2391,7 +2326,6 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
        (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);
@@ -2404,8 +2338,7 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
       if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
         _mesa_update_state(ctx);
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
@@ -2423,6 +2356,12 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
                                        width, height, depth,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               format, type);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             /* Give the texture to the driver.  <pixels> may be null. */
             ASSERT(ctx->Driver.TexImage3D);
             ctx->Driver.TexImage3D(ctx, target, level, internalFormat,
@@ -2482,6 +2421,53 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
 }
 
 
+#if FEATURE_OES_EGL_image
+void GLAPIENTRY
+_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
+{
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+   if (!ctx->Extensions.OES_EGL_image) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glEGLImageTargetTexture2DOES(unsupported)");
+      return;
+   }
+
+   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);
+
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   _mesa_lock_texture(ctx, texObj);
+
+   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 );
+
+      ASSERT(texImage->Data == NULL);
+      ctx->Driver.EGLImageTargetTexture2D(ctx, target,
+                                         texObj, texImage, image);
+
+      /* state update */
+      texObj->_Complete = GL_FALSE;
+      ctx->NewState |= _NEW_TEXTURE;
+   }
+   _mesa_unlock_texture(ctx, texObj);
+
+}
+#endif
+
 
 void GLAPIENTRY
 _mesa_TexSubImage1D( GLenum target, GLint level,
@@ -2490,9 +2476,8 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GLsizei postConvWidth = width;
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage = NULL;
+   struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2518,8 +2503,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    }
 
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
    assert(texObj);
 
    _mesa_lock_texture(ctx, texObj);
@@ -2557,7 +2541,6 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GLsizei postConvWidth = width, postConvHeight = height;
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
@@ -2586,8 +2569,7 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
       return;   /* error was detected */
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2625,7 +2607,6 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
                      GLenum format, GLenum type,
                      const GLvoid *pixels )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GET_CURRENT_CONTEXT(ctx);
@@ -2646,8 +2627,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
       return;   /* error was detected */
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2688,7 +2668,6 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
                       GLint x, GLint y,
                       GLsizei width, GLint border )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
@@ -2715,8 +2694,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
                                postConvWidth, 1, border))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2735,6 +2713,12 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
          _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
                                     border, internalFormat);
 
+         /* Choose actual texture format */
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                            GL_NONE, GL_NONE);
+         ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
          ASSERT(ctx->Driver.CopyTexImage1D);
          ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
                                     x, y, width, border);
@@ -2762,7 +2746,6 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                       GLint x, GLint y, GLsizei width, GLsizei height,
                       GLint border )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
@@ -2790,8 +2773,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                                postConvWidth, postConvHeight, border))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2812,6 +2794,12 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                                     postConvWidth, postConvHeight, 1,
                                     border, internalFormat);
 
+         /* Choose actual texture format */
+         texImage->TexFormat =
+            ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                            GL_NONE, GL_NONE);
+         ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
          ASSERT(ctx->Driver.CopyTexImage2D);
          ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
                                     x, y, width, height, border);
@@ -2837,7 +2825,6 @@ void GLAPIENTRY
 _mesa_CopyTexSubImage1D( GLenum target, GLint level,
                          GLint xoffset, GLint x, GLint y, GLsizei width )
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
@@ -2858,8 +2845,7 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
    if (copytexsubimage_error_check1(ctx, 1, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2902,7 +2888,6 @@ _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;
@@ -2920,8 +2905,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
    if (copytexsubimage_error_check1(ctx, 2, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -2967,7 +2951,6 @@ _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;
@@ -2985,8 +2968,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
    if (copytexsubimage_error_check1(ctx, 3, target, level))
       return;
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
@@ -3046,6 +3028,15 @@ compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth,
 }
 
 
+/*
+ * Return compressed texture block size, in pixels.
+ */
+static void
+get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
+{
+   gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
+   _mesa_get_format_block_size(mesaFormat, bw, bh);
+}
 
 
 /**
@@ -3095,7 +3086,7 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
    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 */
@@ -3163,6 +3154,7 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
                                   GLenum format, GLsizei imageSize)
 {
    GLint expectedSize, maxLevels = 0, maxTextureSize;
+   GLuint bw, bh;
    (void) zoffset;
 
    if (dimensions == 1) {
@@ -3199,7 +3191,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)
@@ -3212,16 +3204,18 @@ 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 = compressed_tex_size(width, height, depth, format);
@@ -3232,6 +3226,55 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
 }
 
 
+/**
+ * Do second part of glCompressedTexSubImage error checking.
+ * \return GL_TRUE if error found, GL_FALSE otherwise.
+ */
+static GLboolean
+compressed_subtexture_error_check2(GLcontext *ctx, GLuint dims,
+                                   GLsizei width, GLsizei height,
+                                   GLsizei depth, GLenum format,
+                                   struct gl_texture_image *texImage)
+{
+
+   if ((GLint) format != texImage->InternalFormat) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCompressedTexSubImage%uD(format=0x%x)", dims, format);
+      return GL_TRUE;
+   }
+
+   if (((width == 1 || width == 2) &&
+        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;
+}
+
+
 
 void GLAPIENTRY
 _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
@@ -3250,7 +3293,6 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
 
    if (target == GL_TEXTURE_1D) {
       /* non-proxy target */
-      struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       GLenum error = compressed_texture_error_check(ctx, 1, target, level,
@@ -3260,8 +3302,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
 
       _mesa_lock_texture(ctx, texObj);
       {
@@ -3278,6 +3319,12 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
             _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             ASSERT(ctx->Driver.CompressedTexImage1D);
             ctx->Driver.CompressedTexImage1D(ctx, target, level,
                                              internalFormat, width, border,
@@ -3314,11 +3361,10 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
 
         _mesa_lock_texture(ctx, texObj);
         {
@@ -3335,7 +3381,6 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
    }
 }
 
-
 void GLAPIENTRY
 _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
                               GLenum internalFormat, GLsizei width,
@@ -3351,14 +3396,32 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
                   _mesa_lookup_enum_by_nr(internalFormat),
                   width, height, border, imageSize, data);
 
+#if FEATURE_ES
+   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 (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) {
@@ -3366,8 +3429,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
 
       _mesa_lock_texture(ctx, texObj);
       {
@@ -3384,6 +3446,12 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
             _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             ASSERT(ctx->Driver.CompressedTexImage2D);
             ctx->Driver.CompressedTexImage2D(ctx, target, level,
                                              internalFormat, width, height,
@@ -3422,11 +3490,10 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
 
         _mesa_lock_texture(ctx, texObj);
         {
@@ -3461,7 +3528,6 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
 
    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,
@@ -3471,8 +3537,8 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
          return;
       }
 
-      texUnit = _mesa_get_current_tex_unit(ctx);
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
+      texObj = _mesa_get_current_tex_object(ctx, target);
+
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
@@ -3489,6 +3555,12 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
                                        width, height, depth,
                                        border, internalFormat);
 
+            /* Choose actual texture format */
+            texImage->TexFormat =
+               ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                               GL_NONE, GL_NONE);
+            ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+
             ASSERT(ctx->Driver.CompressedTexImage3D);
             ctx->Driver.CompressedTexImage3D(ctx, target, level,
                                              internalFormat,
@@ -3526,11 +3598,11 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
       }
       else {
          /* store the teximage parameters */
-         struct gl_texture_unit *texUnit;
          struct gl_texture_object *texObj;
          struct gl_texture_image *texImage;
-         texUnit = _mesa_get_current_tex_unit(ctx);
-        texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+         texObj = _mesa_get_current_tex_object(ctx, target);
+
         _mesa_lock_texture(ctx, texObj);
         {
            texImage = _mesa_select_tex_image(ctx, texObj, target, level);
@@ -3547,50 +3619,71 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
 }
 
 
-void GLAPIENTRY
-_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
-                                 GLsizei width, GLenum format,
-                                 GLsizei imageSize, const GLvoid *data)
+/**
+ * Common helper for glCompressedTexSubImage1/2/3D().
+ */
+static void
+compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
+                         GLint xoffset, GLint yoffset, GLint zoffset,
+                         GLsizei width, GLsizei height, GLsizei depth,
+                         GLenum format, GLsizei imageSize, const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLenum error;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   error = compressed_subtexture_error_check(ctx, 1, target, level,
+   error = compressed_subtexture_error_check(ctx, dims, target, level,
                                              xoffset, 0, 0, /* pos */
-                                             width, 1, 1,   /* size */
+                                             width, height, depth,   /* size */
                                              format, imageSize);
    if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage1D");
+      _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims);
       return;
    }
 
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
       assert(texImage);
 
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage1D(format)");
-      }
-      else if ((width == 1 || width == 2) &&
-               (GLuint) width != texImage->Width) {
-        _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCompressedTexSubImage1D(width)");
+      if (compressed_subtexture_error_check2(ctx, dims, width, height, depth,
+                                             format, texImage)) {
+         /* error was recorded */
       }
-      else if (width > 0) {
-         if (ctx->Driver.CompressedTexSubImage1D) {
-            ctx->Driver.CompressedTexSubImage1D(ctx, target, level,
-                                                xoffset, width,
-                                                format, imageSize, data,
-                                                texObj, texImage);
+      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:
+            ;
          }
 
          check_gen_mipmap(ctx, target, texObj, level);
@@ -3602,61 +3695,24 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
 }
 
 
+void GLAPIENTRY
+_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
+                                 GLsizei width, GLenum format,
+                                 GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1,
+                            format, imageSize, data);
+}
+
+
 void GLAPIENTRY
 _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
                                  GLint yoffset, GLsizei width, GLsizei height,
                                  GLenum format, GLsizei imageSize,
                                  const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLenum error;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   error = compressed_subtexture_error_check(ctx, 2, target, level,
-                                             xoffset, yoffset, 0, /* pos */
-                                             width, height, 1,    /* size */
-                                             format, imageSize);
-   if (error) {
-      /* XXX proxy target? */
-      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
-      return;
-   }
-
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      assert(texImage);
-
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage2D(format)");
-      }
-      else 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)");
-      }
-      else if (width > 0 && height > 0) {
-         if (ctx->Driver.CompressedTexSubImage2D) {
-            ctx->Driver.CompressedTexSubImage2D(ctx, target, level,
-                                               xoffset, yoffset, width, height,
-                                               format, imageSize, data,
-                                               texObj, texImage);
-         }
-
-         check_gen_mipmap(ctx, target, texObj, level);
-
-         ctx->NewState |= _NEW_TEXTURE;
-      }
-   }
-   _mesa_unlock_texture(ctx, texObj);
+   compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data);
 }
 
 
@@ -3666,57 +3722,8 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
                                  GLsizei height, GLsizei depth, GLenum format,
                                  GLsizei imageSize, const GLvoid *data)
 {
-   struct gl_texture_unit *texUnit;
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLenum error;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   error = compressed_subtexture_error_check(ctx, 3, target, level,
-                                             xoffset, yoffset, zoffset,/*pos*/
-                                             width, height, depth, /*size*/
-                                             format, imageSize);
-   if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage3D");
-      return;
-   }
-
-   texUnit = _mesa_get_current_tex_unit(ctx);
-   texObj = _mesa_select_tex_object(ctx, texUnit, target);
-
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      assert(texImage);
-
-      if ((GLint) format != texImage->InternalFormat) {
-        _mesa_error(ctx, GL_INVALID_OPERATION,
-                    "glCompressedTexSubImage3D(format)");
-      }
-      else 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)");
-      }
-      else if (width > 0 && height > 0 && depth > 0) {
-         if (ctx->Driver.CompressedTexSubImage3D) {
-            ctx->Driver.CompressedTexSubImage3D(ctx, target, level,
-                                               xoffset, yoffset, zoffset,
-                                               width, height, depth,
-                                               format, imageSize, data,
-                                               texObj, texImage);
-         }
-
-         check_gen_mipmap(ctx, target, texObj, level);
-
-         ctx->NewState |= _NEW_TEXTURE;
-      }
-   }
-   _mesa_unlock_texture(ctx, texObj);
+   compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset,
+                            width, height, depth, format, imageSize, data);
 }