add a number of PBO validate/map/unmap functions
[mesa.git] / src / mesa / main / teximage.c
index b9625dc247b0f06248406a9b6d52e258483e5a00..384e1455203c3185d79a7c3ec0c869ca9bbcdcc5 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.3
+ * Version:  7.1
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 
 /**
  * \file teximage.c
- * Texture images manipulation functions.
- *
- * \note Mesa's native texture data type is GLchan.  Native formats are
- * GL_ALPHA, GL_LUMINANCE, GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, GL_RGBA, and
- * GL_COLOR_INDEX.
- *
- * \note Device drivers are free to implement any internal format they want.
+ * Texture image-related functions.
  */
 
 
@@ -39,6 +33,8 @@
 #include "bufferobj.h"
 #include "context.h"
 #include "convolve.h"
+#include "fbobject.h"
+#include "framebuffer.h"
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
 #include "mtypes.h"
 
 
+/**
+ * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE
+ * elsewhere.
+ */
+void *
+_mesa_alloc_texmemory(GLsizei bytes)
+{
+   return _mesa_align_malloc(bytes, 512);
+}
+
+
+/**
+ * Free texture memory allocated with _mesa_alloc_texmemory()
+ */
+void
+_mesa_free_texmemory(void *m)
+{
+   _mesa_align_free(m);
+}
+
+
+
+
 #if 0
 static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
 {
-#if CHAN_TYPE == GL_FLOAT
-   _mesa_problem(NULL, "PrintTexture doesn't support float channels");
+#if CHAN_TYPE != GL_UNSIGNED_BYTE
+   _mesa_problem(NULL, "PrintTexture not supported");
 #else
    GLuint i, j, c;
-   const GLchan *data = (const GLchan *) img->Data;
+   const GLubyte *data = (const GLubyte *) img->Data;
 
    if (!data) {
       _mesa_printf("No texture data\n");
@@ -98,6 +117,7 @@ static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
             _mesa_printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
          data += (img->RowStride - img->Width) * c;
       }
+      /* XXX use img->ImageStride here */
       _mesa_printf("\n");
    }
 #endif
@@ -219,7 +239,8 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.SGIX_depth_texture) {
+   if (ctx->Extensions.SGIX_depth_texture ||
+       ctx->Extensions.ARB_depth_texture) {
       switch (internalFormat) {
          case GL_DEPTH_COMPONENT:
          case GL_DEPTH_COMPONENT16_SGIX:
@@ -317,6 +338,46 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
       }
    }
 
+   if (ctx->Extensions.EXT_packed_depth_stencil) {
+      switch (internalFormat) {
+         case GL_DEPTH_STENCIL_EXT:
+         case GL_DEPTH24_STENCIL8_EXT:
+            return GL_DEPTH_STENCIL_EXT;
+         default:
+            ; /* fallthrough */
+      }
+   }
+
+#if FEATURE_EXT_texture_sRGB
+   if (ctx->Extensions.EXT_texture_sRGB) {
+      switch (internalFormat) {
+      case GL_SRGB_EXT:
+      case GL_SRGB8_EXT:
+      case GL_COMPRESSED_SRGB_EXT:
+      case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+         return GL_RGB;
+      case GL_SRGB_ALPHA_EXT:
+      case GL_SRGB8_ALPHA8_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:
+         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:
+         return GL_LUMINANCE;
+      default:
+            ; /* fallthrough */
+      }
+   }
+
+#endif /* FEATURE_EXT_texture_sRGB */
+
    return -1; /* error */
 }
 
@@ -409,6 +470,24 @@ is_color_format(GLenum format)
       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;
       case GL_YCBCR_MESA:  /* not considered to be RGB */
       default:
@@ -471,6 +550,23 @@ is_ycbcr_format(GLenum format)
 }
 
 
+/**
+ * Test if the given image format is a Depth/Stencil format.
+ */
+static GLboolean
+is_depthstencil_format(GLenum format)
+{
+   switch (format) {
+      case GL_DEPTH24_STENCIL8_EXT:
+      case GL_DEPTH_STENCIL_EXT:
+         return GL_TRUE;
+      default:
+         return GL_FALSE;
+   }
+}
+
+
+
 /**
  * Test if it is a supported compressed format.
  * 
@@ -485,25 +581,36 @@ is_ycbcr_format(GLenum format)
 static GLboolean
 is_compressed_format(GLcontext *ctx, GLenum internalFormat)
 {
-   (void) ctx;
-   switch (internalFormat) {
-      case GL_COMPRESSED_RGB_FXT1_3DFX:
-      case GL_COMPRESSED_RGBA_FXT1_3DFX:
-      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_RGB_S3TC:
-      case GL_RGB4_S3TC:
-      case GL_RGBA_S3TC:
-      case GL_RGBA4_S3TC:
+   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;
-      default:
-         return GL_FALSE;
+      }
    }
+   return GL_FALSE;
 }
 
 
+/**
+ * For cube map faces, return a face index in [0,5].
+ * For other targets return 0;
+ */
+GLuint
+_mesa_tex_target_to_face(GLenum target)
+{
+   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
+       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)
+      return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+   else
+      return 0;
+}
+
+
+
 /**
  * Store a gl_texture_image pointer in a gl_texture_object structure
  * according to the target and level parameters.
@@ -522,10 +629,13 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
 {
    ASSERT(tObj);
    ASSERT(texImage);
+   /* XXX simplify this with _mesa_tex_target_to_face() */
    switch (target) {
       case GL_TEXTURE_1D:
       case GL_TEXTURE_2D:
       case GL_TEXTURE_3D:
+      case GL_TEXTURE_1D_ARRAY_EXT:
+      case GL_TEXTURE_2D_ARRAY_EXT:
          tObj->Image[0][level] = texImage;
          break;
       case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
@@ -533,12 +643,13 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: {
-        GLuint face = ((GLuint) target - 
-                       (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
-         tObj->Image[face][level] = texImage;
-        break;
-      }
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+         {
+            GLuint face = ((GLuint) target - 
+                           (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
+            tObj->Image[face][level] = texImage;
+         }
+         break;
       case GL_TEXTURE_RECTANGLE_NV:
          ASSERT(level == 0);
          tObj->Image[0][level] = texImage;
@@ -570,21 +681,48 @@ _mesa_new_texture_image( GLcontext *ctx )
 
 
 /**
- * Free texture image.
+ * Free texture image data.
+ * This function is a fallback called via ctx->Driver.FreeTexImageData().
  *
  * \param teximage texture image.
  *
- * Free the texture image structure and the associated image data if it's not
- * marked as client data.
+ * Free the texture image data if it's not marked as client data.
  */
 void
-_mesa_delete_texture_image( struct gl_texture_image *teximage )
+_mesa_free_texture_image_data(GLcontext *ctx,
+                              struct gl_texture_image *texImage)
 {
-   if (teximage->Data && !teximage->IsClientData) {
-      MESA_PBUFFER_FREE( teximage->Data );
-      teximage->Data = NULL;
+   (void) ctx;
+
+   if (texImage->Data && !texImage->IsClientData) {
+      /* free the old texture data */
+      _mesa_free_texmemory(texImage->Data);
    }
-   FREE( teximage );
+
+   texImage->Data = NULL;
+}
+
+
+/**
+ * Free texture image.
+ *
+ * \param teximage texture image.
+ *
+ * Free the texture image structure and the associated image data.
+ */
+void
+_mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
+{
+   /* Free texImage->Data and/or any other driver-specific texture
+    * image storage.
+    */
+   ASSERT(ctx->Driver.FreeTexImageData);
+   ctx->Driver.FreeTexImageData( ctx, texImage );
+
+   ASSERT(texImage->Data == NULL);
+   if (texImage->ImageOffsets)
+      _mesa_free(texImage->ImageOffsets);
+   _mesa_free(texImage);
 }
 
 
@@ -595,14 +733,16 @@ _mesa_delete_texture_image( struct gl_texture_image *teximage )
  *
  * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise.
  */
-static GLboolean
-is_proxy_target(GLenum target)
+GLboolean
+_mesa_is_proxy_texture(GLenum target)
 {
    return (target == GL_PROXY_TEXTURE_1D ||
            target == GL_PROXY_TEXTURE_2D ||
            target == GL_PROXY_TEXTURE_3D ||
            target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
-           target == GL_PROXY_TEXTURE_RECTANGLE_NV);
+           target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
+           target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
+           target == GL_PROXY_TEXTURE_2D_ARRAY_EXT);
 }
 
 
@@ -652,6 +792,18 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
       case GL_PROXY_TEXTURE_RECTANGLE_NV:
          return ctx->Extensions.NV_texture_rectangle
                 ? ctx->Texture.ProxyRect : NULL;
+      case GL_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? texUnit->Current1DArray : NULL;
+      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? ctx->Texture.Proxy1DArray : NULL;
+      case GL_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? texUnit->Current2DArray : NULL;
+      case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? ctx->Texture.Proxy2DArray : NULL;
       default:
          _mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
          return NULL;
@@ -673,24 +825,24 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
  * \sa gl_texture_unit.
  */
 struct gl_texture_image *
-_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit,
-                       GLenum target, GLint level)
+_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
+                      GLenum target, GLint level)
 {
-   ASSERT(texUnit);
-   ASSERT(level < MAX_TEXTURE_LEVELS);
+   ASSERT(texObj);
+
+   if (level < 0 || level >= MAX_TEXTURE_LEVELS) 
+      return NULL;
+
+   /* XXX simplify this with _mesa_tex_target_to_face() */
    switch (target) {
       case GL_TEXTURE_1D:
-         return texUnit->Current1D->Image[0][level];
       case GL_PROXY_TEXTURE_1D:
-         return ctx->Texture.Proxy1D->Image[0][level];
       case GL_TEXTURE_2D:
-         return texUnit->Current2D->Image[0][level];
       case GL_PROXY_TEXTURE_2D:
-         return ctx->Texture.Proxy2D->Image[0][level];
       case GL_TEXTURE_3D:
-         return texUnit->Current3D->Image[0][level];
       case GL_PROXY_TEXTURE_3D:
-         return ctx->Texture.Proxy3D->Image[0][level];
+         return texObj->Image[0][level];
+
       case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
@@ -700,33 +852,32 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit,
          if (ctx->Extensions.ARB_texture_cube_map) {
            GLuint face = ((GLuint) target - 
                           (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
-            return texUnit->CurrentCubeMap->Image[face][level];
+            return texObj->Image[face][level];
         }
          else
             return NULL;
+
       case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
          if (ctx->Extensions.ARB_texture_cube_map)
-            return ctx->Texture.ProxyCubeMap->Image[0][level];
+            return texObj->Image[0][level];
          else
             return NULL;
+
       case GL_TEXTURE_RECTANGLE_NV:
-         if (ctx->Extensions.NV_texture_rectangle) {
-            ASSERT(level == 0);
-            return texUnit->CurrentRect->Image[0][level];
-         }
-         else {
-            return NULL;
-         }
       case GL_PROXY_TEXTURE_RECTANGLE_NV:
-         if (ctx->Extensions.NV_texture_rectangle) {
-            ASSERT(level == 0);
-            return ctx->Texture.ProxyRect->Image[0][level];
-         }
-         else {
+         if (ctx->Extensions.NV_texture_rectangle && level == 0) 
+            return texObj->Image[0][level];
+         else 
             return NULL;
-         }
+
+      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)
+            ? texObj->Image[0][level] : NULL;
+
       default:
-         _mesa_problem(ctx, "bad target in _mesa_select_tex_image()");
          return NULL;
    }
 }
@@ -738,22 +889,25 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit,
  * out of memory.
  */
 struct gl_texture_image *
-_mesa_get_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit,
+_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj,
                     GLenum target, GLint level)
 {
    struct gl_texture_image *texImage;
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
+
+   if (!texObj)
+      return NULL;
+   
+   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
    if (!texImage) {
-      struct gl_texture_object *texObj;
       texImage = ctx->Driver.NewTextureImage(ctx);
       if (!texImage) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation");
          return NULL;
       }
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      ASSERT(texObj);
+
       _mesa_set_tex_image(texObj, target, level, texImage);
    }
+
    return texImage;
 }
 
@@ -848,6 +1002,36 @@ _mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level)
          texImage->TexObject = ctx->Texture.ProxyRect;
       }
       return texImage;
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+      if (level >= ctx->Const.MaxTextureLevels)
+         return NULL;
+      texImage = ctx->Texture.Proxy1DArray->Image[0][level];
+      if (!texImage) {
+         texImage = ctx->Driver.NewTextureImage(ctx);
+         if (!texImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
+            return NULL;
+         }
+         ctx->Texture.Proxy1DArray->Image[0][level] = texImage;
+         /* Set the 'back' pointer */
+         texImage->TexObject = ctx->Texture.Proxy1DArray;
+      }
+      return texImage;
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+      if (level >= ctx->Const.MaxTextureLevels)
+         return NULL;
+      texImage = ctx->Texture.Proxy2DArray->Image[0][level];
+      if (!texImage) {
+         texImage = ctx->Driver.NewTextureImage(ctx);
+         if (!texImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
+            return NULL;
+         }
+         ctx->Texture.Proxy2DArray->Image[0][level] = texImage;
+         /* Set the 'back' pointer */
+         texImage->TexObject = ctx->Texture.Proxy2DArray;
+      }
+      return texImage;
    default:
       return NULL;
    }
@@ -873,6 +1057,10 @@ _mesa_max_texture_levels(GLcontext *ctx, GLenum target)
    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:
@@ -965,13 +1153,17 @@ static void
 clear_teximage_fields(struct gl_texture_image *img)
 {
    ASSERT(img);
-   img->Format = 0;
-   img->IntFormat = 0;
+   img->_BaseFormat = 0;
+   img->InternalFormat = 0;
    img->Border = 0;
    img->Width = 0;
    img->Height = 0;
    img->Depth = 0;
    img->RowStride = 0;
+   if (img->ImageOffsets) {
+      _mesa_free(img->ImageOffsets);
+      img->ImageOffsets = NULL;
+   }
    img->Width2 = 0;
    img->Height2 = 0;
    img->Depth2 = 0;
@@ -991,7 +1183,7 @@ clear_teximage_fields(struct gl_texture_image *img)
  * Initialize basic fields of the gl_texture_image struct.
  *
  * \param ctx GL context.
- * \param target texture target.
+ * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc).
  * \param img texture image structure to be initialized.
  * \param width image width.
  * \param height image height.
@@ -1008,42 +1200,65 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
                            GLsizei width, GLsizei height, GLsizei depth,
                            GLint border, GLenum internalFormat)
 {
+   GLint i;
+
    ASSERT(img);
-   img->Format = _mesa_base_tex_format( ctx, internalFormat );
-   ASSERT(img->Format > 0);
-   img->IntFormat = internalFormat;
+   ASSERT(width >= 0);
+   ASSERT(height >= 0);
+   ASSERT(depth >= 0);
+
+   img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
+   ASSERT(img->_BaseFormat > 0);
+   img->InternalFormat = internalFormat;
    img->Border = border;
    img->Width = width;
    img->Height = height;
    img->Depth = depth;
-   img->RowStride = width;
-   img->WidthLog2 = logbase2(width - 2 * border);
-   if (height == 1)  /* 1-D texture */
+
+   img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
+   img->WidthLog2 = logbase2(img->Width2);
+
+   if (height == 1) { /* 1-D texture */
+      img->Height2 = 1;
       img->HeightLog2 = 0;
-   else
-      img->HeightLog2 = logbase2(height - 2 * border);
-   if (depth == 1)   /* 2-D texture */
+   }
+   else {
+      img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
+      img->HeightLog2 = logbase2(img->Height2);
+   }
+
+   if (depth == 1) {  /* 2-D texture */
+      img->Depth2 = 1;
       img->DepthLog2 = 0;
-   else
-      img->DepthLog2 = logbase2(depth - 2 * border);
-   img->Width2 = width - 2 * border; /*1 << img->WidthLog2;*/
-   img->Height2 = height - 2 * border; /*1 << img->HeightLog2;*/
-   img->Depth2 = depth - 2 * border; /*1 << img->DepthLog2;*/
+   }
+   else {
+      img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
+      img->DepthLog2 = logbase2(img->Depth2);
+   }
+
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
-   img->IsCompressed = is_compressed_format(ctx, internalFormat);
-   if (img->IsCompressed)
-      img->CompressedSize = ctx->Driver.CompressedTextureSize(ctx, width,
-                                               height, depth, internalFormat);
-   else
-      img->CompressedSize = 0;
 
-   if ((width == 1 || _mesa_bitcount(width - 2 * border) == 1) &&
-       (height == 1 || _mesa_bitcount(height - 2 * border) == 1) &&
-       (depth == 1 || _mesa_bitcount(depth - 2 * border) == 1))
+   img->IsCompressed = GL_FALSE;
+   img->CompressedSize = 0;
+
+   if ((width == 1 || _mesa_bitcount(img->Width2) == 1) &&
+       (height == 1 || _mesa_bitcount(img->Height2) == 1) &&
+       (depth == 1 || _mesa_bitcount(img->Depth2) == 1))
       img->_IsPowerOfTwo = GL_TRUE;
    else
       img->_IsPowerOfTwo = GL_FALSE;
 
+   /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
+   img->RowStride = width;
+   /* Allocate the ImageOffsets array and initialize to typical values.
+    * We allocate the array for 1D/2D textures too in order to avoid special-
+    * case code in the texstore routines.
+    */
+   img->ImageOffsets = (GLuint *) _mesa_malloc(depth * sizeof(GLuint));
+   for (i = 0; i < depth; i++) {
+      img->ImageOffsets[i] = i * width * height;
+   }
+
    /* Compute Width/Height/DepthScale for mipmap lod computation */
    if (target == GL_TEXTURE_RECTANGLE_NV) {
       /* scale = 1.0 since texture coords directly map to texels */
@@ -1066,6 +1281,10 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
  * 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.
+ *
  * \param target  one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D,
  *                GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV,
  *                GL_PROXY_TEXTURE_CUBE_MAP_ARB.
@@ -1095,7 +1314,7 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width >0 && _mesa_bitcount(width - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or level */
          return GL_FALSE;
@@ -1105,10 +1324,10 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or height or level */
          return GL_FALSE;
@@ -1118,21 +1337,21 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           depth < 2 * border || depth > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(depth - 2 * border) != 1) ||
+           depth > 0 && _mesa_bitcount(depth - 2 * border) != 1) ||
           level >= ctx->Const.Max3DTextureLevels) {
          /* bad width or height or depth or level */
          return GL_FALSE;
       }
       return GL_TRUE;
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      if (width < 1 || width > ctx->Const.MaxTextureRectSize ||
-          height < 1 || height > ctx->Const.MaxTextureRectSize ||
+      if (width < 0 || width > ctx->Const.MaxTextureRectSize ||
+          height < 0 || height > ctx->Const.MaxTextureRectSize ||
           level != 0) {
          /* bad width or height or level */
          return GL_FALSE;
@@ -1142,15 +1361,45 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxCubeTextureLevels) {
          /* bad width or height */
          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_bitcount(width - 2 * border) != 1) ||
+          level >= ctx->Const.MaxTextureLevels) {
+         /* bad width or level */
+         return GL_FALSE;
+      }
+
+      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) {
+         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_bitcount(width - 2 * border) != 1) ||
+          height < 2 * border || height > 2 + maxSize ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
+          level >= ctx->Const.MaxTextureLevels) {
+         /* bad width or height or level */
+         return GL_FALSE;
+      }
+      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) {
+         return GL_FALSE;
+      }
+      return GL_TRUE;
    default:
       _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
       return GL_FALSE;
@@ -1158,6 +1407,23 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
 }
 
 
+/**
+ * Helper function to determine whether a target supports compressed textures
+ */
+static GLboolean
+target_can_be_compressed(GLcontext *ctx, 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)))));
+}
+
+
 /**
  * Test the glTexImage[123]D() parameters for errors.
  * 
@@ -1187,9 +1453,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
                      GLint width, GLint height,
                      GLint depth, GLint border )
 {
-   const GLboolean isProxy = is_proxy_target(target);
-   GLboolean sizeOK;
+   const GLboolean isProxy = _mesa_is_proxy_texture(target);
+   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) {
@@ -1224,10 +1491,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
     */
    if (dimensions == 1) {
       if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_1D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, 1, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_1D;
+         height = 1;
+         depth = 1;
       }
       else {
          _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
@@ -1235,11 +1501,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
       }
    }
    else if (dimensions == 2) {
+      depth = 1;
       if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_2D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_2D;
       }
       else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
                (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
@@ -1248,10 +1512,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
             _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(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);
+         proxy_target = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
+         sizeOK = (width == height);
       }
       else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
                target == GL_TEXTURE_RECTANGLE_NV) {
@@ -1259,11 +1521,11 @@ texture_error_check( GLcontext *ctx, GLenum target,
             _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
             return GL_TRUE;
          }
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
-                                                GL_PROXY_TEXTURE_RECTANGLE_NV,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
+         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)");
@@ -1272,10 +1534,11 @@ texture_error_check( GLcontext *ctx, GLenum target,
    }
    else if (dimensions == 3) {
       if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_3D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, depth, border);
+         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)" );
@@ -1287,6 +1550,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
       return GL_TRUE;
    }
 
+   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxy_target, level,
+                                                    internalFormat, format,
+                                                    type, width, height,
+                                                    depth, border);
    if (!sizeOK) {
       if (!isProxy) {
          _mesa_error(ctx, GL_INVALID_VALUE,
@@ -1324,7 +1591,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
    if ((is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
        (is_index_format(internalFormat) && !indexFormat) ||
        (is_depth_format(internalFormat) != is_depth_format(format)) ||
-       (is_ycbcr_format(internalFormat) != is_ycbcr_format(format))) {
+       (is_ycbcr_format(internalFormat) != is_ycbcr_format(format)) ||
+       (is_depthstencil_format(internalFormat) != is_depthstencil_format(format))) {
       if (!isProxy)
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage(internalFormat/format)");
@@ -1364,11 +1632,13 @@ texture_error_check( GLcontext *ctx, GLenum target,
 
    /* additional checks for depth textures */
    if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
-      /* Only 1D and 2D textures supported */
+      /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */
       if (target != GL_TEXTURE_1D &&
           target != GL_PROXY_TEXTURE_1D &&
           target != GL_TEXTURE_2D &&
-          target != GL_PROXY_TEXTURE_2D) {
+          target != GL_PROXY_TEXTURE_2D &&
+          target != GL_TEXTURE_RECTANGLE_ARB &&
+          target != GL_PROXY_TEXTURE_RECTANGLE_ARB) {
          if (!isProxy)
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glTexImage(target/internalFormat)");
@@ -1378,21 +1648,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
 
    /* additional checks for compressed textures */
    if (is_compressed_format(ctx, internalFormat)) {
-      if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
-         /* OK */
-      }
-      else if (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))) {
-         /* OK */
-      }
-      else {
-         if (!isProxy) {
-            _mesa_error(ctx, GL_INVALID_ENUM,
-                        "glTexImage%d(target)", dimensions);
-            return GL_TRUE;
-         }
+      if (!target_can_be_compressed(ctx, target) && !isProxy) {
+         _mesa_error(ctx, GL_INVALID_ENUM,
+                     "glTexImage%d(target)", dimensions);
+         return GL_TRUE;
       }
       if (border != 0) {
          if (!isProxy) {
@@ -1437,9 +1696,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
                         GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type )
 {
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   struct gl_texture_image *destTex;
-
    /* Check target */
    if (dimensions == 1) {
       if (target != GL_TEXTURE_1D) {
@@ -1449,26 +1705,37 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
    }
    else if (dimensions == 2) {
       if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
-          target <=GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_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 (ctx->Extensions.NV_texture_rectangle &&
-               target == GL_TEXTURE_RECTANGLE_NV) {
+      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_3D) {
+      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;
       }
@@ -1500,8 +1767,23 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   destTex = _mesa_select_tex_image(ctx, texUnit, target, level);
+   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glTexSubImage%dD(format or type)", dimensions);
+      return GL_TRUE;
+   }
+
+   return GL_FALSE;
+}
 
+static GLboolean
+subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
+                        GLenum target, GLint level,
+                        GLint xoffset, GLint yoffset, GLint zoffset,
+                        GLint width, GLint height, GLint depth,
+                        GLenum format, GLenum type,
+                        const struct gl_texture_image *destTex )
+{
    if (!destTex) {
       /* undefined image level */
       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions);
@@ -1541,28 +1823,22 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
       }
    }
 
-   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "glTexSubImage%dD(format or type)", 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 (destTex->IsCompressed) {
-      const struct gl_texture_unit *texUnit;
-      const struct gl_texture_image *texImage;
-      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-      texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-
-      if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
-         /* OK */
-      }
-      else if (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))) {
-         /* OK */
-      }
-      else {
+      if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glTexSubImage%D(target)", dimensions);
          return GL_TRUE;
@@ -1574,12 +1850,12 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
          return GL_TRUE;
       }
       /* size must be multiple of 4 or equal to whole texture size */
-      if ((width & 3) && (GLuint) width != texImage->Width) {
+      if ((width & 3) && (GLuint) width != destTex->Width) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexSubImage%D(width)", dimensions);
          return GL_TRUE;
       }         
-      if ((height & 3) && (GLuint) height != texImage->Height) {
+      if ((height & 3) && (GLuint) height != destTex->Height) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexSubImage%D(width)", dimensions);
          return GL_TRUE;
@@ -1614,8 +1890,9 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
                          GLenum target, GLint level, GLint internalFormat,
                          GLint width, GLint height, GLint border )
 {
-   GLenum format, type;
+   GLenum type;
    GLboolean sizeOK;
+   GLint format;
 
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
@@ -1624,6 +1901,16 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
+   /* Check that the source buffer is complete */
+   if (ctx->ReadBuffer->Name) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
+      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
+
    /* Check border */
    if (border < 0 || border > 1 ||
        ((target == GL_TEXTURE_RECTANGLE_NV ||
@@ -1631,10 +1918,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   /* The format and type aren't really significant here, but we need to pass
-    * something to TestProxyTexImage().
-    */
    format = _mesa_base_tex_format(ctx, internalFormat);
+   if (format < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glCopyTexImage%dD(internalFormat)", dimensions);
+      return GL_TRUE;
+   }
+
+   /* NOTE: the format and type aren't really significant for
+    * TestProxyTexImage().  Only the internalformat really matters.
+   if (!_mesa_source_buffer_exists(ctx, format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexImage%dD(missing readbuffer)", dimensions);
+      return GL_TRUE;
+   }
+
+    */
    type = GL_FLOAT;
 
    /* Check target and call ctx->Driver.TestProxyTexImage() to check the
@@ -1681,6 +1980,17 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
                                                 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;
@@ -1704,12 +2014,6 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexImage%dD(internalFormat)", dimensions);
-      return GL_TRUE;
-   }
-
    if (is_compressed_format(ctx, internalFormat)) {
       if (target != GL_TEXTURE_2D) {
          _mesa_error(ctx, GL_INVALID_ENUM,
@@ -1722,6 +2026,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
          return GL_TRUE;
       }
    }
+   else if (is_depth_format(internalFormat)) {
+      /* make sure we have depth/stencil buffers */
+      if (!ctx->ReadBuffer->_DepthBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%D(no depth)", dimensions);
+         return GL_TRUE;
+      }
+   }
+   else if (is_depthstencil_format(internalFormat)) {
+      /* make sure we have depth/stencil buffers */
+      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%D(no depth/stencil buffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
 
    /* if we get here, the parameters are OK */
    return GL_FALSE;
@@ -1729,7 +2049,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
 
 
 /**
- * Test glCopyTexImage[12]D() parameters for errors.
+ * Test glCopyTexSubImage[12]D() parameters for errors.
  * 
  * \param ctx GL context.
  * \param dimensions texture image dimensions (must be 1, 2 or 3).
@@ -1751,12 +2071,19 @@ static GLboolean
 copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
                              GLenum target, GLint level,
                              GLint xoffset, GLint yoffset, GLint zoffset,
-                             GLsizei width, GLsizei height )
+                             GLsizei width, GLsizei height)
 {
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   struct gl_texture_image *teximage;
-
    /* Check target */
+   /* Check that the source buffer is complete */
+   if (ctx->ReadBuffer->Name) {
+      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
+      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
+         return GL_TRUE;
+      }
+   }
+
    if (dimensions == 1) {
       if (target != GL_TEXTURE_1D) {
          _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
@@ -1777,15 +2104,23 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
             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_3D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
-         return GL_TRUE;
+      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;
       }
    }
 
@@ -1808,7 +2143,16 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
-   teximage = _mesa_select_tex_image(ctx, texUnit, target, level);
+   return GL_FALSE;
+}
+
+static GLboolean
+copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
+                             GLenum target, GLint level,
+                             GLint xoffset, GLint yoffset, GLint zoffset,
+                             GLsizei width, GLsizei height,
+                             const struct gl_texture_image *teximage )
+{
    if (!teximage) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCopyTexSubImage%dD(undefined texture level: %d)",
@@ -1878,11 +2222,34 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
       }         
    }
 
-   if (teximage->IntFormat == GL_YCBCR_MESA) {
+   if (teximage->InternalFormat == GL_YCBCR_MESA) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D");
       return GL_TRUE;
    }
 
+   if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glCopyTexSubImage%dD(missing readbuffer)", dimensions);
+      return GL_TRUE;
+   }
+
+   if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) {
+      if (!ctx->ReadBuffer->_DepthBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexSubImage%D(no depth buffer)",
+                     dimensions);
+         return GL_TRUE;
+      }
+   }
+   else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexSubImage%D(no depth/stencil buffer)",
+                     dimensions);
+         return GL_TRUE;
+      }
+   }
+
    /* if we get here, the parameters are OK */
    return GL_FALSE;
 }
@@ -1902,15 +2269,15 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
                    GLenum type, GLvoid *pixels )
 {
    const struct gl_texture_unit *texUnit;
-   const struct gl_texture_object *texObj;
-   const struct gl_texture_image *texImage;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
    GLint maxLevels = 0;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    texUnit = &(ctx->Texture.Unit[ctx->Texture.CurrentUnit]);
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   if (!texObj || is_proxy_target(target)) {
+   if (!texObj || _mesa_is_proxy_texture(target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
       return;
    }
@@ -1936,54 +2303,116 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
 
    if (!ctx->Extensions.EXT_paletted_texture && is_index_format(format)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return;
    }
 
-   if (!ctx->Extensions.SGIX_depth_texture && is_depth_format(format)) {
+   if (!ctx->Extensions.SGIX_depth_texture &&
+       !ctx->Extensions.ARB_depth_texture && is_depth_format(format)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
+      return;
    }
 
    if (!ctx->Extensions.MESA_ycbcr_texture && is_ycbcr_format(format)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
-   }
-
-   if (!pixels)
-      return;
-
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   if (!texImage) {
-      /* invalid mipmap level, not an error */
       return;
    }
 
-   /* Make sure the requested image format is compatible with the
-    * texture's format. We let the colorformat-indexformat go through,
-    * because the texelfetcher will dequantize to full rgba.
-    */
-   if (is_color_format(format)
-       && !is_color_format(texImage->TexFormat->BaseFormat)
-       && !is_index_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return;
-   }
-   else if (is_index_format(format)
-       && !is_index_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return;
-   }
-   else if (is_depth_format(format)
-       && !is_depth_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+   if (!ctx->Extensions.EXT_packed_depth_stencil
+       && is_depthstencil_format(format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
       return;
    }
-   else if (is_ycbcr_format(format)
-       && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
-      return;
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      if (!texImage) {
+        /* invalid mipmap level, not an error */
+        goto out;
+      }
+
+
+      /* 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 (is_color_format(format)
+         && !is_color_format(texImage->TexFormat->BaseFormat)
+         && !is_index_format(texImage->TexFormat->BaseFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+        goto out;
+      }
+      else if (is_index_format(format)
+              && !is_index_format(texImage->TexFormat->BaseFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+        goto out;
+      }
+      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)");
+        goto out;
+      }
+      else if (is_ycbcr_format(format)
+              && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+        goto out;
+      }
+      else if (is_depthstencil_format(format)
+              && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
+        goto out;
+      }
+
+      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)");
+           goto out;
+        }
+      }
+
+      /* typically, this will call _mesa_get_teximage() */
+      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
+                             texObj, texImage);
+
    }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
+}
+
+
 
-   /* typically, this will call _mesa_get_teximage() */
-   ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
-                           texObj, texImage);
+/**
+ * Check if the given texture image is bound to any framebuffer objects
+ * and update/invalidate them.
+ * XXX We're only checking the currently bound framebuffer object for now.
+ * In the future, perhaps struct gl_texture_image should have a pointer (or
+ * list of pointers (yikes)) to the gl_framebuffer(s) which it's bound to.
+ */
+static void
+update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
+                   GLuint face, GLuint level)
+{
+   if (ctx->DrawBuffer->Name) {
+      GLuint i;
+      for (i = 0; i < BUFFER_COUNT; i++) {
+         struct gl_renderbuffer_attachment *att = 
+            ctx->DrawBuffer->Attachment + i;
+         if (att->Type == GL_TEXTURE &&
+             att->Texture == texObj &&
+             att->TextureLevel == level &&
+             att->CubeMapFace == face) {
+            ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]);
+            /* Tell driver about the new renderbuffer texture */
+            ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+         }
+      }
+   }
 }
 
 
@@ -2005,56 +2434,58 @@ _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);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 1, postConvWidth, 1, 1, border)) {
          return;   /* error was recorded */
       }
 
-      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         /* free the old texture data */
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
-      clear_teximage_fields(texImage); /* not really needed, but helpful */
-      _mesa_init_teximage_fields(ctx, target, texImage,
-                                 postConvWidth, 1, 1,
-                                 border, internalFormat);
-
       if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
-         _mesa_update_state(ctx);
+        _mesa_update_state(ctx);
 
-      ASSERT(ctx->Driver.TexImage1D);
+      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+      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 );
+        }
 
-      /* 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->Data == NULL);
 
-      ASSERT(texImage->TexFormat);
+        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);
 
-      /* If driver didn't explicitly set this, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
+        /* 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);
 
-      /* 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;
+      }
+   out:
+      _mesa_unlock_texture(ctx, texObj);
    }
    else if (target == GL_PROXY_TEXTURE_1D) {
       /* Proxy texture: check for errors and update proxy state */
@@ -2103,11 +2534,14 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
         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)) {
+        target == GL_TEXTURE_RECTANGLE_NV) ||
+       (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);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 2, postConvWidth, postConvHeight,
@@ -2115,52 +2549,54 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
          return;   /* error was recorded */
       }
 
-      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-      texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         /* free the old texture data */
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
-      clear_teximage_fields(texImage); /* not really needed, but helpful */
-      _mesa_init_teximage_fields(ctx, target, texImage,
-                                 postConvWidth, postConvHeight, 1,
-                                 border, internalFormat);
-
       if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
-         _mesa_update_state(ctx);
-
-      ASSERT(ctx->Driver.TexImage2D);
+        _mesa_update_state(ctx);
 
-      /* 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);
-
-      /* If driver didn't explicitly set these, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
-
-      /* state update */
-      texObj->Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+      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, "glTexImage2D");
+           goto out;
+        }
+        
+        if (texImage->Data) {
+           ctx->Driver.FreeTexImageData( ctx, texImage );
+        }
+        
+        ASSERT(texImage->Data == NULL);
+        clear_teximage_fields(texImage); /* not really needed, but helpful */
+        _mesa_init_teximage_fields(ctx, target, texImage,
+                                   postConvWidth, postConvHeight, 1,
+                                   border, internalFormat);
+        
+        ASSERT(ctx->Driver.TexImage2D);
+
+        /* Give the texture to the driver!  <pixels> may be null! */
+        (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat,
+                                  width, height, border, format, type, pixels,
+                                  &ctx->Unpack, texObj, texImage);
+        
+        ASSERT(texImage->TexFormat);
+
+        update_fbo_texture(ctx, texObj, face, level);
+
+        /* state update */
+        texObj->_Complete = GL_FALSE;
+        ctx->NewState |= _NEW_TEXTURE;
+      }
+   out:
+      _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.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);
@@ -2200,57 +2636,64 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (target == GL_TEXTURE_3D) {
+   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 & _IMAGE_NEW_TRANSFER_STATE)
+        _mesa_update_state(ctx);
+
       texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
       texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
-      clear_teximage_fields(texImage); /* not really needed, but helpful */
-      _mesa_init_teximage_fields(ctx, target, texImage,
-                                 width, height, depth,
-                                 border, internalFormat);
-
-      if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
-         _mesa_update_state(ctx);
+      _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);
+        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);
+        /* 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);
+        ASSERT(texImage->TexFormat);
 
-      /* If driver didn't explicitly set these, use the defaults */
-      if (!texImage->FetchTexelc)
-         texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D;
-      if (!texImage->FetchTexelf)
-         texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df;
-      ASSERT(texImage->FetchTexelc);
-      ASSERT(texImage->FetchTexelf);
+        update_fbo_texture(ctx, texObj, face, level);
 
-      /* state update */
-      texObj->Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+        /* state update */
+        texObj->_Complete = GL_FALSE;
+        ctx->NewState |= _NEW_TEXTURE;
+      }
+   out:
+      _mesa_unlock_texture(ctx, texObj);
    }
-   else if (target == GL_PROXY_TEXTURE_3D) {
+   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);
@@ -2296,7 +2739,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    GLsizei postConvWidth = width;
    struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
+   struct gl_texture_image *texImage = NULL;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2309,26 +2752,38 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    }
 
    if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0,
-                              postConvWidth, 1, 1, format, type)) {
+                              postConvWidth, 1, 1, format, type)) {
       return;   /* error was detected */
    }
 
+
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
+   assert(texObj);
 
-   if (width == 0)
-      return;  /* no-op, not an error */
+   _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 we have a border, xoffset=-1 is legal.  Bias by border width */
-   xoffset += texImage->Border;
+      if (width == 0)
+        goto out;  /* no-op, not an error */
 
-   ASSERT(ctx->Driver.TexSubImage1D);
-   (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
-                                format, type, pixels, &ctx->Unpack,
-                                texObj, texImage);
-   ctx->NewState |= _NEW_TEXTURE;
+      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+      xoffset += texImage->Border;
+
+      ASSERT(ctx->Driver.TexSubImage1D);
+      (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
+                                  format, type, pixels, &ctx->Unpack,
+                                  texObj, texImage);
+      ctx->NewState |= _NEW_TEXTURE;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2356,27 +2811,37 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
    }
 
    if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
-                             postConvWidth, postConvHeight, 1, format, type)) {
+                             postConvWidth, postConvHeight, 1, format, type)) {
       return;   /* error was detected */
    }
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-   if (width == 0 || height == 0)
-      return;  /* no-op, not an error */
+      if (subtexture_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
+                                 postConvWidth, postConvHeight, 1, format, type, 
+                                 texImage)) {
+        goto out;   /* error was detected */
+      }
 
-   /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-   xoffset += texImage->Border;
-   yoffset += texImage->Border;
+      if (width == 0 || height == 0)
+        goto out;  /* no-op, not an error */
 
-   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;
+      /* 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;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2404,24 +2869,34 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
-
-   if (width == 0 || height == 0 || height == 0)
-      return;  /* 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;
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+
+      if (subtexture_error_check2(ctx, 3, target, level, xoffset, yoffset, zoffset,
+                                 width, height, depth, format, type, texImage)) {
+        goto out;   /* error was detected */
+      }
+
+      if (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);
 }
 
 
@@ -2436,6 +2911,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
    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);
 
@@ -2452,39 +2928,39 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-   if (!texImage) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
-      return;
-   }
-   else if (texImage->Data && !texImage->IsClientData) {
-      /* free the old texture data */
-      MESA_PBUFFER_FREE(texImage->Data);
-   }
-   texImage->Data = NULL;
+   _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;
+      }
 
-   clear_teximage_fields(texImage); /* not really needed, but helpful */
-   _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
-                              border, internalFormat);
+      if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
+      }
+      
+      ASSERT(texImage->Data == NULL);
 
+      clear_teximage_fields(texImage); /* not really needed, but helpful */
+      _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
+                                border, internalFormat);
 
-   ASSERT(ctx->Driver.CopyTexImage1D);
-   (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat,
-                                 x, y, width, border);
 
-   ASSERT(texImage->TexFormat);
+      ASSERT(ctx->Driver.CopyTexImage1D);
+      (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat,
+                                   x, y, width, border);
 
-   /* If driver didn't explicitly set these, use the defaults */
-   if (!texImage->FetchTexelc)
-      texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
-   if (!texImage->FetchTexelf)
-      texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
-   ASSERT(texImage->FetchTexelc);
-   ASSERT(texImage->FetchTexelf);
+      ASSERT(texImage->TexFormat);
 
-   /* 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;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2498,6 +2974,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
+   const GLuint face = _mesa_tex_target_to_face(target);
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2515,50 +2992,55 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-   if (!texImage) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
-      return;
-   }
-   else if (texImage->Data && !texImage->IsClientData) {
-      /* free the old texture data */
-      MESA_PBUFFER_FREE(texImage->Data);
-   }
-   texImage->Data = NULL;
 
-   clear_teximage_fields(texImage); /* not really needed, but helpful */
-   _mesa_init_teximage_fields(ctx, target, texImage,
-                              postConvWidth, postConvHeight, 1,
-                              border, internalFormat);
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
-   ASSERT(ctx->Driver.CopyTexImage2D);
-   (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat,
-                                 x, y, width, height, border);
+      if (!texImage) {
+        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
+        goto out;
+      }
+      
+      if (texImage->Data) {
+        ctx->Driver.FreeTexImageData( ctx, texImage );
+      }
+      
+      ASSERT(texImage->Data == NULL);
 
-   ASSERT(texImage->TexFormat);
+      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);
 
-   /* If driver didn't explicitly set these, use the defaults */
-   if (!texImage->FetchTexelc)
-      texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
-   if (!texImage->FetchTexelf)
-      texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
-   ASSERT(texImage->FetchTexelc);
-   ASSERT(texImage->FetchTexelf);
+      update_fbo_texture(ctx, texObj, face, level);
 
-   /* state update */
-   texObj->Complete = GL_FALSE;
-   ctx->NewState |= _NEW_TEXTURE;
+      /* state update */
+      texObj->_Complete = GL_FALSE;
+      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 )
 {
    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);
 
@@ -2573,15 +3055,32 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
       return;
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   ASSERT(texImage);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+
+      if (copytexsubimage_error_check2(ctx, 1, target, level,
+                                      xoffset, 0, 0, postConvWidth, 1,
+                                      texImage))
+        goto out;
+      
 
-   /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-   xoffset += texImage->Border;
+      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+      xoffset += texImage->Border;
 
-   ASSERT(ctx->Driver.CopyTexSubImage1D);
-   (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width);
-   ctx->NewState |= _NEW_TEXTURE;
+      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;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2592,6 +3091,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
                          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);
@@ -2608,17 +3108,31 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
       return;
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   ASSERT(texImage);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-   /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-   xoffset += texImage->Border;
-   yoffset += texImage->Border;
+      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);
+      }
 
-   ASSERT(ctx->Driver.CopyTexSubImage2D);
-   (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level,
-                                    xoffset, yoffset, x, y, width, height);
-   ctx->NewState |= _NEW_TEXTURE;
+      ctx->NewState |= _NEW_TEXTURE;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2629,6 +3143,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
                          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);
@@ -2645,19 +3160,34 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
       return;
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   ASSERT(texImage);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
 
-   /* If we have a border, xoffset=-1 is legal.  Bias by border width */
-   xoffset += texImage->Border;
-   yoffset += texImage->Border;
-   zoffset += texImage->Border;
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-   ASSERT(ctx->Driver.CopyTexSubImage3D);
-   (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level,
-                                    xoffset, yoffset, zoffset,
-                                    x, y, width, height);
-   ctx->NewState |= _NEW_TEXTURE;
+      if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset,
+                                      zoffset, postConvWidth, postConvHeight,
+                                      texImage))
+        goto out;
+
+      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
+      xoffset += texImage->Border;
+      yoffset += texImage->Border;
+      zoffset += texImage->Border;
+      
+      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                     &width, &height)) {
+         ASSERT(ctx->Driver.CopyTexSubImage3D);
+         ctx->Driver.CopyTexSubImage3D(ctx, target, level,
+                                      xoffset, yoffset, zoffset,
+                                      x, y, width, height);
+      }
+
+      ctx->NewState |= _NEW_TEXTURE;
+   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -2714,9 +3244,11 @@ 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))
       return GL_INVALID_ENUM;
 
+   /* This should really never fail */
    if (_mesa_base_tex_format(ctx, internalFormat) < 0)
       return GL_INVALID_ENUM;
 
@@ -2748,11 +3280,21 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
    if (level < 0 || level >= maxLevels)
       return GL_INVALID_VALUE;
 
-   expectedSize = ctx->Driver.CompressedTextureSize(ctx, width, height, depth,
-                                                    internalFormat);
+   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
+                                                       depth, internalFormat);
    if (expectedSize != imageSize)
       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;
 }
 
@@ -2807,6 +3349,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))
       return GL_INVALID_ENUM;
 
@@ -2832,8 +3375,8 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
    if ((height & 3) != 0 && height != 2 && height != 1)
       return GL_INVALID_VALUE;
 
-   expectedSize = ctx->Driver.CompressedTextureSize(ctx, width, height, depth,
-                                                    format);
+   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
+                                                       depth, format);
    if (expectedSize != imageSize)
       return GL_INVALID_VALUE;
 
@@ -2852,6 +3395,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    if (target == GL_TEXTURE_1D) {
+      /* non-proxy target */
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
@@ -2864,28 +3408,35 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
 
       texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
       texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
 
-      _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
-                                 border, internalFormat);
+      _mesa_lock_texture(ctx, texObj);
+      {
+        texImage = _mesa_get_tex_image(ctx, texObj, target, level);
+        if (!texImage) {
+           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D");
+           goto out;
+        }
+        
+        if (texImage->Data) {
+           ctx->Driver.FreeTexImageData( ctx, texImage );
+        }
+        ASSERT(texImage->Data == NULL);
 
-      ASSERT(ctx->Driver.CompressedTexImage1D);
-      (*ctx->Driver.CompressedTexImage1D)(ctx, target, level,
-                                          internalFormat, width, border,
-                                          imageSize, data,
-                                          texObj, texImage);
+        _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
+                                   border, internalFormat);
 
-      /* state update */
-      texObj->Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+        ASSERT(ctx->Driver.CompressedTexImage1D);
+        (*ctx->Driver.CompressedTexImage1D)(ctx, target, level,
+                                            internalFormat, width, 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_1D) {
       /* Proxy texture: check for errors and update proxy state */
@@ -2907,11 +3458,18 @@ _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 = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-         texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-         _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
-                                    border, internalFormat);
+        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 {
@@ -2934,6 +3492,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
        (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;
@@ -2946,28 +3505,35 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
 
       texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
       texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
 
-      _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
-                                 border, internalFormat);
+      _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);
 
-      ASSERT(ctx->Driver.CompressedTexImage2D);
-      (*ctx->Driver.CompressedTexImage2D)(ctx, target, level,
-                                          internalFormat, width, height,
-                                          border, imageSize, data,
-                                          texObj, texImage);
+        _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
+                                   border, internalFormat);
 
-      /* state update */
-      texObj->Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+        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 &&
@@ -2991,11 +3557,18 @@ _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 = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-         texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-         _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
-                                    border, internalFormat);
+        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 {
@@ -3015,6 +3588,7 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
    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;
@@ -3027,29 +3601,35 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
 
       texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
       texObj = _mesa_select_tex_object(ctx, texUnit, target);
-      texImage = _mesa_get_tex_image(ctx, texUnit, target, level);
-      if (!texImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D");
-         return;
-      }
-      else if (texImage->Data && !texImage->IsClientData) {
-         MESA_PBUFFER_FREE(texImage->Data);
-      }
-      texImage->Data = NULL;
-
-      _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth,
-                                 border, internalFormat);
+      _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);
 
-      ASSERT(ctx->Driver.CompressedTexImage3D);
-      (*ctx->Driver.CompressedTexImage3D)(ctx, target, level,
-                                          internalFormat,
-                                          width, height, depth,
-                                          border, imageSize, data,
-                                          texObj, texImage);
+        _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth,
+                                   border, internalFormat);
 
-      /* state update */
-      texObj->Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+        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 */
@@ -3071,11 +3651,17 @@ _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 = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-         texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-         _mesa_init_teximage_fields(ctx, target, texImage, width, height,
-                                    depth, border, internalFormat);
+        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 {
@@ -3098,7 +3684,9 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    error = compressed_subtexture_error_check(ctx, 1, target, level,
-                                xoffset, 0, 0, width, 1, 1, format, imageSize);
+                                             xoffset, 0, 0, /* pos */
+                                             width, 1, 1,   /* size */
+                                             format, imageSize);
    if (error) {
       _mesa_error(ctx, error, "glCompressedTexSubImage1D");
       return;
@@ -3106,30 +3694,35 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCompressedTexSubImage1D(format)");
-      return;
-   }
+      if ((GLint) format != texImage->InternalFormat) {
+        _mesa_error(ctx, GL_INVALID_OPERATION,
+                    "glCompressedTexSubImage1D(format)");
+        goto out;
+      }
 
-   if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)");
-      return;
-   }
+      if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) {
+        _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)");
+        goto out;
+      }
       
-   if (width == 0)
-      return;  /* no-op, not an error */
+      if (width == 0)
+        goto out;  /* no-op, not an error */
 
-   if (ctx->Driver.CompressedTexSubImage1D) {
-      (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level,
-                                             xoffset, width,
-                                             format, imageSize, data,
-                                             texObj, texImage);
+      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);
 }
 
 
@@ -3147,7 +3740,9 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    error = compressed_subtexture_error_check(ctx, 2, target, level,
-                     xoffset, yoffset, 0, width, height, 1, format, imageSize);
+                                             xoffset, yoffset, 0, /* pos */
+                                             width, height, 1,    /* size */
+                                             format, imageSize);
    if (error) {
       /* XXX proxy target? */
       _mesa_error(ctx, error, "glCompressedTexSubImage2D");
@@ -3156,31 +3751,36 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCompressedTexSubImage2D(format)");
-      return;
-   }
+      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)");
-      return;
-   }
+      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)
-      return;  /* no-op, not an error */
+      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);
+      if (ctx->Driver.CompressedTexSubImage2D) {
+        (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level,
+                                               xoffset, yoffset, width, height,
+                                               format, imageSize, data,
+                                               texObj, texImage);
+      }
+      ctx->NewState |= _NEW_TEXTURE;
    }
-   ctx->NewState |= _NEW_TEXTURE;
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -3198,41 +3798,48 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
    error = compressed_subtexture_error_check(ctx, 3, target, level,
-           xoffset, yoffset, zoffset, width, height, depth, format, imageSize);
+                                             xoffset, yoffset, zoffset,/*pos*/
+                                             width, height, depth, /*size*/
+                                             format, imageSize);
    if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
+      _mesa_error(ctx, error, "glCompressedTexSubImage3D");
       return;
    }
 
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   assert(texImage);
+   _mesa_lock_texture(ctx, texObj);
+   {
+      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+      assert(texImage);
 
-   if ((GLint) format != texImage->IntFormat) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCompressedTexSubImage3D(format)");
-      return;
-   }
+      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)");
-      return;
-   }
+      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)
-      return;  /* no-op, not an error */
+      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);
+      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;
    }
-   ctx->NewState |= _NEW_TEXTURE;
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -3240,7 +3847,7 @@ void GLAPIENTRY
 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
 {
    const struct gl_texture_unit *texUnit;
-   const struct gl_texture_object *texObj;
+   struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLint maxLevels;
    GET_CURRENT_CONTEXT(ctx);
@@ -3261,23 +3868,30 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
       return;
    }
 
-   if (is_proxy_target(target)) {
+   if (_mesa_is_proxy_texture(target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
       return;
    }
 
-   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
-   if (!texImage) {
-      /* probably invalid mipmap level */
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
-      return;
-   }
-
-   if (!texImage->IsCompressed) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB");
-      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)");
+      }
    }
-
-   /* this typically calls _mesa_get_compressed_teximage() */
-   ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage);
+   _mesa_unlock_texture(ctx, texObj);
 }