mesa: Make ARB_gpu_shader5 core-profile-only
[mesa.git] / src / mesa / main / teximage.c
index ce62248441dc9aa30a43f2068e355922a8c26d1c..5f8edff87c699847a1b64331ee393ccaab37364e 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 
@@ -28,7 +29,7 @@
  * Texture image-related functions.
  */
 
-
+#include <stdbool.h>
 #include "glheader.h"
 #include "bufferobj.h"
 #include "context.h"
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
-#include "mfeatures.h"
+#include "multisample.h"
 #include "state.h"
 #include "texcompress.h"
+#include "texcompress_cpal.h"
 #include "teximage.h"
+#include "texobj.h"
 #include "texstate.h"
-#include "texpal.h"
+#include "texstorage.h"
+#include "textureview.h"
 #include "mtypes.h"
+#include "glformats.h"
+#include "texstore.h"
 
 
 /**
@@ -69,8 +75,6 @@
  *
  * This is the format which is used during texture application (i.e. the
  * texture format and env mode determine the arithmetic used.
- *
- * XXX this could be static
  */
 GLint
 _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
@@ -81,14 +85,14 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_ALPHA8:
       case GL_ALPHA12:
       case GL_ALPHA16:
-         return GL_ALPHA;
+         return (ctx->API != API_OPENGL_CORE) ? GL_ALPHA : -1;
       case 1:
       case GL_LUMINANCE:
       case GL_LUMINANCE4:
       case GL_LUMINANCE8:
       case GL_LUMINANCE12:
       case GL_LUMINANCE16:
-         return GL_LUMINANCE;
+         return (ctx->API != API_OPENGL_CORE) ? GL_LUMINANCE : -1;
       case 2:
       case GL_LUMINANCE_ALPHA:
       case GL_LUMINANCE4_ALPHA4:
@@ -97,14 +101,15 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_LUMINANCE12_ALPHA4:
       case GL_LUMINANCE12_ALPHA12:
       case GL_LUMINANCE16_ALPHA16:
-         return GL_LUMINANCE_ALPHA;
+         return (ctx->API != API_OPENGL_CORE) ? GL_LUMINANCE_ALPHA : -1;
       case GL_INTENSITY:
       case GL_INTENSITY4:
       case GL_INTENSITY8:
       case GL_INTENSITY12:
       case GL_INTENSITY16:
-         return GL_INTENSITY;
+         return (ctx->API != API_OPENGL_CORE) ? GL_INTENSITY : -1;
       case 3:
+         return (ctx->API != API_OPENGL_CORE) ? GL_RGB : -1;
       case GL_RGB:
       case GL_R3_G3_B2:
       case GL_RGB4:
@@ -115,6 +120,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_RGB16:
          return GL_RGB;
       case 4:
+         return (ctx->API != API_OPENGL_CORE) ? GL_RGBA : -1;
       case GL_RGBA:
       case GL_RGBA2:
       case GL_RGBA4:
@@ -130,7 +136,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
 
    /* GL_BGRA can be an internal format *only* in OpenGL ES (1.x or 2.0).
     */
-   if (ctx->API != API_OPENGL) {
+   if (_mesa_is_gles(ctx)) {
       switch (internalFormat) {
          case GL_BGRA:
             return GL_RGBA;
@@ -139,6 +145,15 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
+   if (ctx->Extensions.ARB_ES2_compatibility) {
+      switch (internalFormat) {
+         case GL_RGB565:
+            return GL_RGB;
+         default:
+            ; /* fallthrough */
+      }
+   }
+
    if (ctx->Extensions.ARB_depth_texture) {
       switch (internalFormat) {
          case GL_DEPTH_COMPONENT:
@@ -146,6 +161,9 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
          case GL_DEPTH_COMPONENT24:
          case GL_DEPTH_COMPONENT32:
             return GL_DEPTH_COMPONENT;
+         case GL_DEPTH_STENCIL:
+         case GL_DEPTH24_STENCIL8:
+            return GL_DEPTH_STENCIL;
          default:
             ; /* fallthrough */
       }
@@ -167,7 +185,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
    default:
       ; /* fallthrough */
    }
-         
+
    if (ctx->Extensions.TDFX_texture_compression_FXT1) {
       switch (internalFormat) {
          case GL_COMPRESSED_RGB_FXT1_3DFX:
@@ -179,7 +197,9 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.EXT_texture_compression_s3tc) {
+   /* Assume that the ANGLE flag will always be set if the EXT flag is set.
+    */
+   if (ctx->Extensions.ANGLE_texture_compression_dxt) {
       switch (internalFormat) {
          case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
             return GL_RGB;
@@ -192,7 +212,8 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.S3_s3tc) {
+   if (_mesa_is_desktop_gl(ctx)
+       && ctx->Extensions.ANGLE_texture_compression_dxt) {
       switch (internalFormat) {
          case GL_RGB_S3TC:
          case GL_RGB4_S3TC:
@@ -235,16 +256,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
-   if (ctx->Extensions.ATI_envmap_bumpmap) {
-      switch (internalFormat) {
-         case GL_DUDV_ATI:
-         case GL_DU8DV8_ATI:
-            return GL_DUDV_ATI;
-         default:
-            ; /* fallthrough */
-      }
-   }
-
    if (ctx->Extensions.EXT_texture_snorm) {
       switch (internalFormat) {
          case GL_RED_SNORM:
@@ -284,31 +295,22 @@ _mesa_base_tex_format( struct gl_context *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_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+         return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGB : -1;
       case GL_SRGB_ALPHA_EXT:
       case GL_SRGB8_ALPHA8_EXT:
       case GL_COMPRESSED_SRGB_ALPHA_EXT:
+         return GL_RGBA;
       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;
+         return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGBA : -1;
       case GL_SLUMINANCE_ALPHA_EXT:
       case GL_SLUMINANCE8_ALPHA8_EXT:
       case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
@@ -321,9 +323,9 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
          ; /* fallthrough */
       }
    }
-#endif /* FEATURE_EXT_texture_sRGB */
 
-   if (ctx->Extensions.EXT_texture_integer) {
+   if (ctx->Version >= 30 ||
+       ctx->Extensions.EXT_texture_integer) {
       switch (internalFormat) {
       case GL_RGBA8UI_EXT:
       case GL_RGBA16UI_EXT:
@@ -340,6 +342,11 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_RGB16I_EXT:
       case GL_RGB32I_EXT:
          return GL_RGB;
+      }
+   }
+
+   if (ctx->Extensions.EXT_texture_integer) {
+      switch (internalFormat) {
       case GL_ALPHA8UI_EXT:
       case GL_ALPHA16UI_EXT:
       case GL_ALPHA32UI_EXT:
@@ -376,11 +383,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
    if (ctx->Extensions.ARB_texture_rg) {
       switch (internalFormat) {
       case GL_R16F:
-        /* R16F depends on both ARB_half_float_pixel and ARB_texture_float.
-         */
-        if (!ctx->Extensions.ARB_half_float_pixel)
-           break;
-        /* FALLTHROUGH */
       case GL_R32F:
         if (!ctx->Extensions.ARB_texture_float)
            break;
@@ -391,7 +393,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_R16UI:
       case GL_R32I:
       case GL_R32UI:
-        if (!ctx->Extensions.EXT_texture_integer)
+        if (ctx->Version < 30 && !ctx->Extensions.EXT_texture_integer)
            break;
         /* FALLTHROUGH */
       case GL_R8:
@@ -401,11 +403,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
          return GL_RED;
 
       case GL_RG16F:
-        /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float.
-         */
-        if (!ctx->Extensions.ARB_half_float_pixel)
-           break;
-        /* FALLTHROUGH */
       case GL_RG32F:
         if (!ctx->Extensions.ARB_texture_float)
            break;
@@ -416,7 +413,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       case GL_RG16UI:
       case GL_RG32I:
       case GL_RG32UI:
-        if (!ctx->Extensions.EXT_texture_integer)
+        if (ctx->Version < 30 && !ctx->Extensions.EXT_texture_integer)
            break;
         /* FALLTHROUGH */
       case GL_RG:
@@ -502,6 +499,41 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
       }
    }
 
+   if (_mesa_is_gles3(ctx) || ctx->Extensions.ARB_ES3_compatibility) {
+      switch (internalFormat) {
+      case GL_COMPRESSED_RGB8_ETC2:
+      case GL_COMPRESSED_SRGB8_ETC2:
+         return GL_RGB;
+      case GL_COMPRESSED_RGBA8_ETC2_EAC:
+      case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+      case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+      case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+         return GL_RGBA;
+      case GL_COMPRESSED_R11_EAC:
+      case GL_COMPRESSED_SIGNED_R11_EAC:
+         return GL_RED;
+      case GL_COMPRESSED_RG11_EAC:
+      case GL_COMPRESSED_SIGNED_RG11_EAC:
+         return GL_RG;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
+   if (_mesa_is_desktop_gl(ctx) &&
+       ctx->Extensions.ARB_texture_compression_bptc) {
+      switch (internalFormat) {
+      case GL_COMPRESSED_RGBA_BPTC_UNORM:
+      case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
+         return GL_RGBA;
+      case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
+      case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
+         return GL_RGB;
+      default:
+         ; /* fallthrough */
+      }
+   }
+
    if (ctx->API == API_OPENGLES) {
       switch (internalFormat) {
       case GL_PALETTE4_RGB8_OES:
@@ -572,7 +604,7 @@ set_tex_image(struct gl_texture_object *tObj,
 
 /**
  * Allocate a texture image structure.
- * 
+ *
  * Called via ctx->Driver.NewTextureImage() unless overriden by a device
  * driver.
  *
@@ -618,19 +650,29 @@ _mesa_delete_texture_image(struct gl_context *ctx,
 GLboolean
 _mesa_is_proxy_texture(GLenum target)
 {
+   unsigned i;
+   static const GLenum targets[] = {
+      GL_PROXY_TEXTURE_1D,
+      GL_PROXY_TEXTURE_2D,
+      GL_PROXY_TEXTURE_3D,
+      GL_PROXY_TEXTURE_CUBE_MAP,
+      GL_PROXY_TEXTURE_RECTANGLE,
+      GL_PROXY_TEXTURE_1D_ARRAY,
+      GL_PROXY_TEXTURE_2D_ARRAY,
+      GL_PROXY_TEXTURE_CUBE_MAP_ARRAY,
+      GL_PROXY_TEXTURE_2D_MULTISAMPLE,
+      GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY
+   };
    /*
-    * NUM_TEXTURE_TARGETS should match number of terms below, except there's no
+    * NUM_TEXTURE_TARGETS should match number of terms above, except there's no
     * proxy for GL_TEXTURE_BUFFER and GL_TEXTURE_EXTERNAL_OES.
     */
-   assert(NUM_TEXTURE_TARGETS == 7 + 2);
+   STATIC_ASSERT(NUM_TEXTURE_TARGETS == Elements(targets) + 2);
 
-   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_1D_ARRAY_EXT ||
-           target == GL_PROXY_TEXTURE_2D_ARRAY_EXT);
+   for (i = 0; i < Elements(targets); ++i)
+      if (target == targets[i])
+         return GL_TRUE;
+   return GL_FALSE;
 }
 
 
@@ -638,7 +680,7 @@ _mesa_is_proxy_texture(GLenum target)
  * Return the proxy target which corresponds to the given texture target
  */
 static GLenum
-get_proxy_target(GLenum target)
+proxy_target(GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
@@ -668,30 +710,32 @@ get_proxy_target(GLenum target)
    case GL_TEXTURE_2D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return GL_PROXY_TEXTURE_2D_ARRAY_EXT;
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      return GL_PROXY_TEXTURE_CUBE_MAP_ARRAY;
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+      return GL_PROXY_TEXTURE_2D_MULTISAMPLE;
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      return GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY;
    default:
-      _mesa_problem(NULL, "unexpected target in get_proxy_target()");
+      _mesa_problem(NULL, "unexpected target in proxy_target()");
       return 0;
    }
 }
 
 
 /**
- * Get the texture object that corresponds to the target of the given
- * texture unit.  The target should have already been checked for validity.
- *
- * \param ctx GL context.
- * \param texUnit texture unit.
- * \param target texture target.
- *
- * \return pointer to the texture object on success, or NULL on failure.
+ * Return a pointer to the current texture object for the given target
+ * on the current texture unit.
+ * Note: all <target> error checking should have been done by this point.
  */
 struct gl_texture_object *
-_mesa_select_tex_object(struct gl_context *ctx,
-                        const struct gl_texture_unit *texUnit,
-                        GLenum target)
+_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target)
 {
-   const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array ||
-                               ctx->Extensions.EXT_texture_array);
+   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+   const GLboolean arrayTex = ctx->Extensions.EXT_texture_array;
 
    switch (target) {
       case GL_TEXTURE_1D:
@@ -718,6 +762,12 @@ _mesa_select_tex_object(struct gl_context *ctx,
       case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
          return ctx->Extensions.ARB_texture_cube_map
                 ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL;
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+         return ctx->Extensions.ARB_texture_cube_map_array
+                ? texUnit->CurrentTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
+      case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+         return ctx->Extensions.ARB_texture_cube_map_array
+                ? ctx->Texture.ProxyTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
       case GL_TEXTURE_RECTANGLE_NV:
          return ctx->Extensions.NV_texture_rectangle
                 ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL;
@@ -733,28 +783,31 @@ _mesa_select_tex_object(struct gl_context *ctx,
       case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
          return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
       case GL_TEXTURE_BUFFER:
-         return ctx->Extensions.ARB_texture_buffer_object
-            ? texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
+         return ctx->API == API_OPENGL_CORE &&
+                ctx->Extensions.ARB_texture_buffer_object ?
+                texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
       case GL_TEXTURE_EXTERNAL_OES:
-         return ctx->Extensions.OES_EGL_image_external
+         return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
             ? texUnit->CurrentTex[TEXTURE_EXTERNAL_INDEX] : NULL;
+      case GL_TEXTURE_2D_MULTISAMPLE:
+         return ctx->Extensions.ARB_texture_multisample
+            ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
+      case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+         return ctx->Extensions.ARB_texture_multisample
+            ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
+      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+         return ctx->Extensions.ARB_texture_multisample
+            ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
+      case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+         return ctx->Extensions.ARB_texture_multisample
+            ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
       default:
-         _mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
+         _mesa_problem(NULL, "bad target in _mesa_get_current_tex_object()");
          return NULL;
    }
 }
 
 
-/**
- * Return pointer to texture object for given target on current texture unit.
- */
-struct gl_texture_object *
-_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target)
-{
-   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
-   return _mesa_select_tex_object(ctx, texUnit, target);
-}
-
 
 /**
  * Get a texture image pointer from a texture object, given a texture
@@ -796,7 +849,7 @@ _mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj,
 
    if (!texObj)
       return NULL;
-   
+
    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
    if (!texImage) {
       texImage = ctx->Driver.NewTextureImage(ctx);
@@ -818,13 +871,13 @@ _mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj,
  * \return pointer to texture image or NULL if invalid target, invalid
  *         level, or out of memory.
  */
-struct gl_texture_image *
-_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
+static struct gl_texture_image *
+get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
 {
    struct gl_texture_image *texImage;
    GLuint texIndex;
 
-   if (level < 0 )
+   if (level < 0)
       return NULL;
 
    switch (target) {
@@ -863,6 +916,21 @@ _mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
          return NULL;
       texIndex = TEXTURE_2D_ARRAY_INDEX;
       break;
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      if (level >= ctx->Const.MaxCubeTextureLevels)
+         return NULL;
+      texIndex = TEXTURE_CUBE_ARRAY_INDEX;
+      break;
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+      if (level > 0)
+         return 0;
+      texIndex = TEXTURE_2D_MULTISAMPLE_INDEX;
+      break;
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      if (level > 0)
+         return 0;
+      texIndex = TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX;
+      break;
    default:
       return NULL;
    }
@@ -887,7 +955,7 @@ _mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
  *
  * \param ctx GL context.
  * \param target texture target.
- * 
+ *
  * \return the maximum number of allowed mipmap levels for the given
  * texture target, or zero if passed a bad target.
  *
@@ -905,13 +973,13 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
       return ctx->Const.Max3DTextureLevels;
+   case GL_TEXTURE_CUBE_MAP:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
-   case GL_TEXTURE_CUBE_MAP_ARB:
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
       return ctx->Extensions.ARB_texture_cube_map
          ? ctx->Const.MaxCubeTextureLevels : 0;
@@ -922,10 +990,22 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
    case GL_TEXTURE_2D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
-      return (ctx->Extensions.MESA_texture_array ||
-              ctx->Extensions.EXT_texture_array)
+      return ctx->Extensions.EXT_texture_array
          ? ctx->Const.MaxTextureLevels : 0;
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      return ctx->Extensions.ARB_texture_cube_map_array
+         ? ctx->Const.MaxCubeTextureLevels : 0;
    case GL_TEXTURE_BUFFER:
+      return ctx->API == API_OPENGL_CORE &&
+             ctx->Extensions.ARB_texture_buffer_object ? 1 : 0;
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      return _mesa_is_desktop_gl(ctx)
+         && ctx->Extensions.ARB_texture_multisample
+         ? 1 : 0;
    case GL_TEXTURE_EXTERNAL_OES:
       /* fall-through */
    default:
@@ -959,11 +1039,17 @@ _mesa_get_texture_dimensions(GLenum target)
    case GL_TEXTURE_1D_ARRAY:
    case GL_PROXY_TEXTURE_1D_ARRAY:
    case GL_TEXTURE_EXTERNAL_OES:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
       return 2;
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
    case GL_TEXTURE_2D_ARRAY:
    case GL_PROXY_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
       return 3;
    case GL_TEXTURE_BUFFER:
       /* fall-through */
@@ -975,6 +1061,142 @@ _mesa_get_texture_dimensions(GLenum target)
 }
 
 
+/**
+ * Check if a texture target can have more than one layer.
+ */
+GLboolean
+_mesa_tex_target_is_layered(GLenum target)
+{
+   switch (target) {
+   case GL_TEXTURE_1D:
+   case GL_PROXY_TEXTURE_1D:
+   case GL_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_2D:
+   case GL_TEXTURE_RECTANGLE:
+   case GL_PROXY_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+   case GL_TEXTURE_BUFFER:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+   case GL_TEXTURE_EXTERNAL_OES:
+      return GL_FALSE;
+
+   case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_PROXY_TEXTURE_1D_ARRAY:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_PROXY_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      return GL_TRUE;
+
+   default:
+      assert(!"Invalid texture target.");
+      return GL_FALSE;
+   }
+}
+
+
+/**
+ * Return the number of layers present in the given level of an array,
+ * cubemap or 3D texture.  If the texture is not layered return zero.
+ */
+GLuint
+_mesa_get_texture_layers(const struct gl_texture_object *texObj, GLint level)
+{
+   assert(level >= 0 && level < MAX_TEXTURE_LEVELS);
+
+   switch (texObj->Target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_TEXTURE_BUFFER:
+   case GL_TEXTURE_EXTERNAL_OES:
+      return 0;
+
+   case GL_TEXTURE_CUBE_MAP:
+      return 6;
+
+   case GL_TEXTURE_1D_ARRAY: {
+      struct gl_texture_image *img = texObj->Image[0][level];
+      return img ? img->Height : 0;
+   }
+
+   case GL_TEXTURE_3D:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
+      struct gl_texture_image *img = texObj->Image[0][level];
+      return img ? img->Depth : 0;
+   }
+
+   default:
+      assert(!"Invalid texture target.");
+      return 0;
+   }
+}
+
+
+/**
+ * Return the maximum number of mipmap levels for the given target
+ * and the dimensions.
+ * The dimensions are expected not to include the border.
+ */
+GLsizei
+_mesa_get_tex_max_num_levels(GLenum target, GLsizei width, GLsizei height,
+                             GLsizei depth)
+{
+   GLsizei size;
+
+   switch (target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_PROXY_TEXTURE_1D:
+   case GL_PROXY_TEXTURE_1D_ARRAY:
+      size = width;
+      break;
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      size = width;
+      break;
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_PROXY_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_2D_ARRAY:
+      size = MAX2(width, height);
+      break;
+   case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
+      size = MAX3(width, height, depth);
+      break;
+   case GL_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_EXTERNAL_OES:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_RECTANGLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      return 1;
+   default:
+      assert(0);
+      return 1;
+   }
+
+   return _mesa_logbase2(size) + 1;
+}
 
 
 #if 000 /* not used anymore */
@@ -988,7 +1210,7 @@ make_null_texture(GLint width, GLint height, GLint depth, GLenum format)
 {
    const GLint components = _mesa_components_in_format(format);
    const GLint numPixels = width * height * depth;
-   GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte));
+   GLubyte *data = (GLubyte *) malloc(numPixels * components * sizeof(GLubyte));
 
 #ifdef DEBUG
    /*
@@ -1052,6 +1274,8 @@ clear_teximage_fields(struct gl_texture_image *img)
    img->HeightLog2 = 0;
    img->DepthLog2 = 0;
    img->TexFormat = MESA_FORMAT_NONE;
+   img->NumSamples = 0;
+   img->FixedSampleLocations = GL_TRUE;
 }
 
 
@@ -1066,22 +1290,27 @@ clear_teximage_fields(struct gl_texture_image *img)
  * \param border image border.
  * \param internalFormat internal format.
  * \param format  the actual hardware format (one of MESA_FORMAT_*)
+ * \param numSamples  number of samples per texel, or zero for non-MS.
+ * \param fixedSampleLocations  are sample locations fixed?
  *
  * Fills in the fields of \p img with the given information.
  * Note: width, height and depth include the border.
  */
-void
-_mesa_init_teximage_fields(struct gl_context *ctx,
-                           struct gl_texture_image *img,
-                           GLsizei width, GLsizei height, GLsizei depth,
-                           GLint border, GLenum internalFormat,
-                           gl_format format)
+static void
+init_teximage_fields_ms(struct gl_context *ctx,
+                        struct gl_texture_image *img,
+                        GLsizei width, GLsizei height, GLsizei depth,
+                        GLint border, GLenum internalFormat,
+                        mesa_format format,
+                        GLuint numSamples, GLboolean fixedSampleLocations)
 {
+   GLenum target;
    ASSERT(img);
    ASSERT(width >= 0);
    ASSERT(height >= 0);
    ASSERT(depth >= 0);
 
+   target = img->TexObject->Target;
    img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
    ASSERT(img->_BaseFormat > 0);
    img->InternalFormat = internalFormat;
@@ -1093,27 +1322,98 @@ _mesa_init_teximage_fields(struct gl_context *ctx,
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
    img->WidthLog2 = _mesa_logbase2(img->Width2);
 
-   if (height == 1) { /* 1-D texture */
-      img->Height2 = 1;
+   img->NumSamples = 0;
+   img->FixedSampleLocations = GL_TRUE;
+
+   switch(target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_BUFFER:
+   case GL_PROXY_TEXTURE_1D:
+      if (height == 0)
+         img->Height2 = 0;
+      else
+         img->Height2 = 1;
       img->HeightLog2 = 0;
-   }
-   else {
+      if (depth == 0)
+         img->Depth2 = 0;
+      else
+         img->Depth2 = 1;
+      img->DepthLog2 = 0;
+      break;
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_PROXY_TEXTURE_1D_ARRAY:
+      img->Height2 = height; /* no border */
+      img->HeightLog2 = 0; /* not used */
+      if (depth == 0)
+         img->Depth2 = 0;
+      else
+         img->Depth2 = 1;
+      img->DepthLog2 = 0;
+      break;
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_RECTANGLE:
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+   case GL_TEXTURE_EXTERNAL_OES:
+   case GL_PROXY_TEXTURE_2D:
+   case GL_PROXY_TEXTURE_RECTANGLE:
+   case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
       img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
       img->HeightLog2 = _mesa_logbase2(img->Height2);
-   }
-
-   if (depth == 1) {  /* 2-D texture */
-      img->Depth2 = 1;
+      if (depth == 0)
+         img->Depth2 = 0;
+      else
+         img->Depth2 = 1;
       img->DepthLog2 = 0;
-   }
-   else {
+      break;
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_PROXY_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
+      img->HeightLog2 = _mesa_logbase2(img->Height2);
+      img->Depth2 = depth; /* no border */
+      img->DepthLog2 = 0; /* not used */
+      break;
+   case GL_TEXTURE_3D:
+   case GL_PROXY_TEXTURE_3D:
+      img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
+      img->HeightLog2 = _mesa_logbase2(img->Height2);
       img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
       img->DepthLog2 = _mesa_logbase2(img->Depth2);
+      break;
+   default:
+      _mesa_problem(NULL, "invalid target 0x%x in _mesa_init_teximage_fields()",
+                    target);
    }
 
-   img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
-
+   img->MaxNumLevels =
+      _mesa_get_tex_max_num_levels(target,
+                                   img->Width2, img->Height2, img->Depth2);
    img->TexFormat = format;
+   img->NumSamples = numSamples;
+   img->FixedSampleLocations = fixedSampleLocations;
+}
+
+
+void
+_mesa_init_teximage_fields(struct gl_context *ctx,
+                           struct gl_texture_image *img,
+                           GLsizei width, GLsizei height, GLsizei depth,
+                           GLint border, GLenum internalFormat,
+                           mesa_format format)
+{
+   init_teximage_fields_ms(ctx, img, width, height, depth, border,
+                           internalFormat, format, 0, GL_TRUE);
 }
 
 
@@ -1136,46 +1436,25 @@ _mesa_clear_texture_image(struct gl_context *ctx,
 
 
 /**
- * This is the fallback for Driver.TestProxyTexImage().  Test the texture
- * level, width, height and depth against the ctx->Const limits for textures.
- *
- * A hardware driver might override this function if, for example, the
- * max 3D texture size is 512x512x64 (i.e. not a cube).
- *
- * Note that width, height, depth == 0 is not an error.  However, a
- * texture with zero width/height/depth will be considered "incomplete"
- * and texturing will effectively be disabled.
- *
- * \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.
- * \param level  as passed to glTexImage
- * \param internalFormat  as passed to glTexImage
- * \param format  as passed to glTexImage
- * \param type  as passed to glTexImage
- * \param width  as passed to glTexImage
- * \param height  as passed to glTexImage
- * \param depth  as passed to glTexImage
- * \param border  as passed to glTexImage
- * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
+ * Check the width, height, depth and border of a texture image are legal.
+ * Used by all the glTexImage, glCompressedTexImage and glCopyTexImage
+ * functions.
+ * The target and level parameters will have already been validated.
+ * \return GL_TRUE if size is OK, GL_FALSE otherwise.
  */
 GLboolean
-_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
-                          GLint internalFormat, GLenum format, GLenum type,
-                          GLint width, GLint height, GLint depth, GLint border)
+_mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
+                               GLint level, GLint width, GLint height,
+                               GLint depth, GLint border)
 {
    GLint maxSize;
 
-   (void) internalFormat;
-   (void) format;
-   (void) type;
-
    switch (target) {
+   case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
-      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
-         return GL_FALSE;
-      if (level >= ctx->Const.MaxTextureLevels)
+      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); /* level zero size */
+      maxSize >>= level;  /* level size */
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
@@ -1183,13 +1462,15 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
+      maxSize >>= level;
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
-      if (height < 2 * border || height > 2 + maxSize)
-         return GL_FALSE;
-      if (level >= ctx->Const.MaxTextureLevels)
+      if (height < 2 * border || height > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
@@ -1199,15 +1480,15 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
-         return GL_FALSE;
-      if (height < 2 * border || height > 2 + maxSize)
+      maxSize >>= level;
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
-      if (depth < 2 * border || depth > 2 + maxSize)
+      if (height < 2 * border || height > 2 * border + maxSize)
          return GL_FALSE;
-      if (level >= ctx->Const.Max3DTextureLevels)
+      if (depth < 2 * border || depth > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
@@ -1219,23 +1500,32 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_RECTANGLE_NV:
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
+      if (level != 0)
+         return GL_FALSE;
       maxSize = ctx->Const.MaxTextureRectSize;
       if (width < 0 || width > maxSize)
          return GL_FALSE;
       if (height < 0 || height > maxSize)
          return GL_FALSE;
-      if (level != 0)
-         return GL_FALSE;
       return GL_TRUE;
 
+   case GL_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
+      maxSize >>= level;
+      if (width != height)
          return GL_FALSE;
-      if (height < 2 * border || height > 2 + maxSize)
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
-      if (level >= ctx->Const.MaxCubeTextureLevels)
+      if (height < 2 * border || height > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
@@ -1245,29 +1535,31 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_1D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
+      maxSize >>= level;
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 1 || height > ctx->Const.MaxArrayTextureLayers)
          return GL_FALSE;
-      if (level >= ctx->Const.MaxTextureLevels)
-         return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
             return GL_FALSE;
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_2D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize)
+      maxSize >>= level;
+      if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
-      if (height < 2 * border || height > 2 + maxSize)
+      if (height < 2 * border || height > 2 * border + maxSize)
          return GL_FALSE;
-      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers)
-         return GL_FALSE;
-      if (level >= ctx->Const.MaxTextureLevels)
+      if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
          if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
@@ -1277,26 +1569,188 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
       }
       return GL_TRUE;
 
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+      maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
+      if (width < 2 * border || width > 2 * border + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 * border + maxSize)
+         return GL_FALSE;
+      if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers || depth % 6)
+         return GL_FALSE;
+      if (width != height)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxCubeTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
+      }
+      return GL_TRUE;
    default:
-      _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
+      _mesa_problem(ctx, "Invalid target in _mesa_legal_texture_dimensions()");
       return GL_FALSE;
    }
 }
 
 
 /**
- * Check if the memory used by the texture would exceed the driver's limit.
- * This lets us support a max 3D texture size of 8K (for example) but
- * prevents allocating a full 8K x 8K x 8K texture.
- * XXX this could be rolled into the proxy texture size test (above) but
- * we don't have the actual texture internal format at that point.
+ * Do error checking of xoffset, yoffset, zoffset, width, height and depth
+ * for glTexSubImage, glCopyTexSubImage and glCompressedTexSubImage.
+ * \param destImage  the destination texture image.
+ * \return GL_TRUE if error found, GL_FALSE otherwise.
  */
 static GLboolean
-legal_texture_size(struct gl_context *ctx, gl_format format,
-                   GLint width, GLint height, GLint depth)
+error_check_subtexture_dimensions(struct gl_context *ctx,
+                                  const char *function, GLuint dims,
+                                  const struct gl_texture_image *destImage,
+                                  GLint xoffset, GLint yoffset, GLint zoffset,
+                                  GLsizei subWidth, GLsizei subHeight,
+                                  GLsizei subDepth)
+{
+   const GLenum target = destImage->TexObject->Target;
+   GLuint bw, bh;
+
+   /* Check size */
+   if (subWidth < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s%dD(width=%d)", function, dims, subWidth);
+      return GL_TRUE;
+   }
+
+   if (dims > 1 && subHeight < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s%dD(height=%d)", function, dims, subHeight);
+      return GL_TRUE;
+   }
+
+   if (dims > 2 && subDepth < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s%dD(depth=%d)", function, dims, subDepth);
+      return GL_TRUE;
+   }
+
+   /* check xoffset and width */
+   if (xoffset < - (GLint) destImage->Border) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset)",
+                  function, dims);
+      return GL_TRUE;
+   }
+
+   if (xoffset + subWidth > (GLint) destImage->Width) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset+width)",
+                  function, dims);
+      return GL_TRUE;
+   }
+
+   /* check yoffset and height */
+   if (dims > 1) {
+      GLint yBorder = (target == GL_TEXTURE_1D_ARRAY) ? 0 : destImage->Border;
+      if (yoffset < -yBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset)",
+                     function, dims);
+         return GL_TRUE;
+      }
+      if (yoffset + subHeight > (GLint) destImage->Height) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset+height)",
+                     function, dims);
+         return GL_TRUE;
+      }
+   }
+
+   /* check zoffset and depth */
+   if (dims > 2) {
+      GLint zBorder = (target == GL_TEXTURE_2D_ARRAY ||
+                       target == GL_TEXTURE_CUBE_MAP_ARRAY) ?
+                         0 : destImage->Border;
+
+      if (zoffset < -zBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", function);
+         return GL_TRUE;
+      }
+      if (zoffset + subDepth  > (GLint) destImage->Depth) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset+depth)", function);
+         return GL_TRUE;
+      }
+   }
+
+   /*
+    * The OpenGL spec (and GL_ARB_texture_compression) says only whole
+    * compressed texture images can be updated.  But, that restriction may be
+    * relaxed for particular compressed formats.  At this time, all the
+    * compressed formats supported by Mesa allow sub-textures to be updated
+    * along compressed block boundaries.
+    */
+   _mesa_get_format_block_size(destImage->TexFormat, &bw, &bh);
+
+   if (bw != 1 || bh != 1) {
+      /* offset must be multiple of block size */
+      if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s%dD(xoffset = %d, yoffset = %d)",
+                     function, dims, xoffset, yoffset);
+         return GL_TRUE;
+      }
+
+      /* The size must be a multiple of bw x bh, or we must be using a
+       * offset+size that exactly hits the edge of the image.  This
+       * is important for small mipmap levels (1x1, 2x1, etc) and for
+       * NPOT textures.
+       */
+      if ((subWidth % bw != 0) &&
+          (xoffset + subWidth != (GLint) destImage->Width)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s%dD(width = %d)", function, dims, subWidth);
+         return GL_TRUE;
+      }
+
+      if ((subHeight % bh != 0) &&
+          (yoffset + subHeight != (GLint) destImage->Height)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s%dD(height = %d)", function, dims, subHeight);
+         return GL_TRUE;
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
+
+
+/**
+ * This is the fallback for Driver.TestProxyTexImage() for doing device-
+ * specific texture image size checks.
+ *
+ * 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  any texture target/type
+ * \param level  as passed to glTexImage
+ * \param format  the MESA_FORMAT_x for the tex image
+ * \param width  as passed to glTexImage
+ * \param height  as passed to glTexImage
+ * \param depth  as passed to glTexImage
+ * \param border  as passed to glTexImage
+ * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
+ */
+GLboolean
+_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
+                          mesa_format format,
+                          GLint width, GLint height, GLint depth, GLint border)
 {
+   /* We just check if the image size is less than MaxTextureMbytes.
+    * Some drivers may do more specific checks.
+    */
    uint64_t bytes = _mesa_format_image_size64(format, width, height, depth);
    uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */
+   mbytes *= _mesa_num_tex_faces(target);
    return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes;
 }
 
@@ -1309,6 +1763,16 @@ compressedteximage_only_format(const struct gl_context *ctx, GLenum format)
 {
    switch (format) {
    case GL_ETC1_RGB8_OES:
+   case GL_PALETTE4_RGB8_OES:
+   case GL_PALETTE4_RGBA8_OES:
+   case GL_PALETTE4_R5_G6_B5_OES:
+   case GL_PALETTE4_RGBA4_OES:
+   case GL_PALETTE4_RGB5_A1_OES:
+   case GL_PALETTE8_RGB8_OES:
+   case GL_PALETTE8_RGBA8_OES:
+   case GL_PALETTE8_R5_G6_B5_OES:
+   case GL_PALETTE8_RGBA4_OES:
+   case GL_PALETTE8_RGB5_A1_OES:
       return GL_TRUE;
    default:
       return GL_FALSE;
@@ -1320,9 +1784,9 @@ compressedteximage_only_format(const struct gl_context *ctx, GLenum format)
  * Helper function to determine whether a target and specific compression
  * format are supported.
  */
-static GLboolean
-target_can_be_compressed(const struct gl_context *ctx, GLenum target,
-                         GLenum intFormat)
+GLboolean
+_mesa_target_can_be_compressed(const struct gl_context *ctx, GLenum target,
+                               GLenum intFormat)
 {
    (void) intFormat;  /* not used yet */
 
@@ -1331,6 +1795,7 @@ target_can_be_compressed(const struct gl_context *ctx, GLenum target,
    case GL_PROXY_TEXTURE_2D:
       return GL_TRUE; /* true for any compressed format so far */
    case GL_PROXY_TEXTURE_CUBE_MAP:
+   case GL_TEXTURE_CUBE_MAP:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -1340,11 +1805,13 @@ target_can_be_compressed(const struct gl_context *ctx, GLenum target,
       return ctx->Extensions.ARB_texture_cube_map;
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
    case GL_TEXTURE_2D_ARRAY_EXT:
-      return (ctx->Extensions.MESA_texture_array ||
-              ctx->Extensions.EXT_texture_array);
+      return ctx->Extensions.EXT_texture_array;
+   case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+      return ctx->Extensions.ARB_texture_cube_map_array;
    default:
       return GL_FALSE;
-   }      
+   }
 }
 
 
@@ -1360,16 +1827,19 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
       switch (target) {
       case GL_TEXTURE_1D:
       case GL_PROXY_TEXTURE_1D:
-         return GL_TRUE;
+         return _mesa_is_desktop_gl(ctx);
       default:
          return GL_FALSE;
       }
    case 2:
       switch (target) {
       case GL_TEXTURE_2D:
-      case GL_PROXY_TEXTURE_2D:
          return GL_TRUE;
+      case GL_PROXY_TEXTURE_2D:
+         return _mesa_is_desktop_gl(ctx);
       case GL_PROXY_TEXTURE_CUBE_MAP:
+         return _mesa_is_desktop_gl(ctx)
+            && ctx->Extensions.ARB_texture_cube_map;
       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -1379,23 +1849,28 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
          return ctx->Extensions.ARB_texture_cube_map;
       case GL_TEXTURE_RECTANGLE_NV:
       case GL_PROXY_TEXTURE_RECTANGLE_NV:
-         return ctx->Extensions.NV_texture_rectangle;
+         return _mesa_is_desktop_gl(ctx)
+            && ctx->Extensions.NV_texture_rectangle;
       case GL_TEXTURE_1D_ARRAY_EXT:
       case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
-         return (ctx->Extensions.MESA_texture_array ||
-                 ctx->Extensions.EXT_texture_array);
+         return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array;
       default:
          return GL_FALSE;
       }
    case 3:
       switch (target) {
       case GL_TEXTURE_3D:
-      case GL_PROXY_TEXTURE_3D:
          return GL_TRUE;
+      case GL_PROXY_TEXTURE_3D:
+         return _mesa_is_desktop_gl(ctx);
       case GL_TEXTURE_2D_ARRAY_EXT:
+         return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array)
+            || _mesa_is_gles3(ctx);
       case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
-         return (ctx->Extensions.MESA_texture_array ||
-                 ctx->Extensions.EXT_texture_array);
+         return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array;
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+      case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+         return ctx->Extensions.ARB_texture_cube_map_array;
       default:
          return GL_FALSE;
       }
@@ -1417,7 +1892,7 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
 {
    switch (dims) {
    case 1:
-      return target == GL_TEXTURE_1D;
+      return _mesa_is_desktop_gl(ctx) && target == GL_TEXTURE_1D;
    case 2:
       switch (target) {
       case GL_TEXTURE_2D:
@@ -1430,10 +1905,10 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
          return ctx->Extensions.ARB_texture_cube_map;
       case GL_TEXTURE_RECTANGLE_NV:
-         return ctx->Extensions.NV_texture_rectangle;
+         return _mesa_is_desktop_gl(ctx)
+            && ctx->Extensions.NV_texture_rectangle;
       case GL_TEXTURE_1D_ARRAY_EXT:
-         return (ctx->Extensions.MESA_texture_array ||
-                 ctx->Extensions.EXT_texture_array);
+         return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array;
       default:
          return GL_FALSE;
       }
@@ -1442,8 +1917,11 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
       case GL_TEXTURE_3D:
          return GL_TRUE;
       case GL_TEXTURE_2D_ARRAY_EXT:
-         return (ctx->Extensions.MESA_texture_array ||
-                 ctx->Extensions.EXT_texture_array);
+         return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array)
+            || _mesa_is_gles3(ctx);
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+      case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+         return ctx->Extensions.ARB_texture_cube_map_array;
       default:
          return GL_FALSE;
       }
@@ -1462,22 +1940,135 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
 static GLboolean
 mutable_tex_object(struct gl_context *ctx, GLenum target)
 {
-   if (ctx->Extensions.ARB_texture_storage) {
-      struct gl_texture_object *texObj =
-         _mesa_get_current_tex_object(ctx, target);
-      return !texObj->Immutable;
+   struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target);
+   return !texObj->Immutable;
+}
+
+
+/**
+ * Return expected size of a compressed texture.
+ */
+static GLuint
+compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth,
+                    GLenum glformat)
+{
+   mesa_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
+   return _mesa_format_image_size(mesaFormat, width, height, depth);
+}
+
+/**
+ * Verify that a texture format is valid with a particular target
+ *
+ * In particular, textures with base format of \c GL_DEPTH_COMPONENT or
+ * \c GL_DEPTH_STENCIL are only valid with certain, context dependent texture
+ * targets.
+ *
+ * \param ctx             GL context
+ * \param target          Texture target
+ * \param internalFormat  Internal format of the texture image
+ * \param dimensions      Dimensionality at the caller.  This is \b not used
+ *                        in the validation.  It is only used when logging
+ *                        error messages.
+ * \param caller          Base name of the calling function (e.g.,
+ *                        "glTexImage" or "glTexStorage").
+ *
+ * \returns true if the combination is legal, false otherwise.
+ */
+bool
+_mesa_legal_texture_base_format_for_target(struct gl_context *ctx,
+                                           GLenum target, GLenum internalFormat,
+                                           unsigned dimensions,
+                                           const char *caller)
+{
+   if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT
+       || _mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_STENCIL) {
+      /* Section 3.8.3 (Texture Image Specification) of the OpenGL 3.3 Core
+       * Profile spec says:
+       *
+       *     "Textures with a base internal format of DEPTH_COMPONENT or
+       *     DEPTH_STENCIL are supported by texture image specification
+       *     commands only if target is TEXTURE_1D, TEXTURE_2D,
+       *     TEXTURE_1D_ARRAY, TEXTURE_2D_ARRAY, TEXTURE_RECTANGLE,
+       *     TEXTURE_CUBE_MAP, PROXY_TEXTURE_1D, PROXY_TEXTURE_2D,
+       *     PROXY_TEXTURE_1D_ARRAY, PROXY_TEXTURE_2D_ARRAY,
+       *     PROXY_TEXTURE_RECTANGLE, or PROXY_TEXTURE_CUBE_MAP. Using these
+       *     formats in conjunction with any other target will result in an
+       *     INVALID_OPERATION error."
+       *
+       * Cubemaps are only supported with desktop OpenGL version >= 3.0,
+       * EXT_gpu_shader4, or, on OpenGL ES 2.0+, OES_depth_texture_cube_map.
+       */
+      if (target != GL_TEXTURE_1D &&
+          target != GL_PROXY_TEXTURE_1D &&
+          target != GL_TEXTURE_2D &&
+          target != GL_PROXY_TEXTURE_2D &&
+          target != GL_TEXTURE_1D_ARRAY &&
+          target != GL_PROXY_TEXTURE_1D_ARRAY &&
+          target != GL_TEXTURE_2D_ARRAY &&
+          target != GL_PROXY_TEXTURE_2D_ARRAY &&
+          target != GL_TEXTURE_RECTANGLE_ARB &&
+          target != GL_PROXY_TEXTURE_RECTANGLE_ARB &&
+         !((_mesa_is_cube_face(target) ||
+            target == GL_TEXTURE_CUBE_MAP ||
+            target == GL_PROXY_TEXTURE_CUBE_MAP) &&
+           (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4
+            || (ctx->API == API_OPENGLES2 && ctx->Extensions.OES_depth_texture_cube_map))) &&
+          !((target == GL_TEXTURE_CUBE_MAP_ARRAY ||
+             target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) &&
+            ctx->Extensions.ARB_texture_cube_map_array)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s%dD(bad target for depth texture)",
+                     caller, dimensions);
+         return false;
+      }
    }
-   return GL_TRUE;
+
+   return true;
 }
 
+static bool
+texture_formats_agree(GLenum internalFormat,
+                      GLenum format)
+{
+   GLboolean colorFormat;
+   GLboolean is_format_depth_or_depthstencil;
+   GLboolean is_internalFormat_depth_or_depthstencil;
+
+   /* Even though there are no color-index textures, we still have to support
+    * uploading color-index data and remapping it to RGB via the
+    * GL_PIXEL_MAP_I_TO_[RGBA] tables.
+    */
+   const GLboolean indexFormat = (format == GL_COLOR_INDEX);
+
+   is_internalFormat_depth_or_depthstencil =
+      _mesa_is_depth_format(internalFormat) ||
+      _mesa_is_depthstencil_format(internalFormat);
+
+   is_format_depth_or_depthstencil =
+      _mesa_is_depth_format(format) ||
+      _mesa_is_depthstencil_format(format);
+
+   colorFormat = _mesa_is_color_format(format);
+
+   if (_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat)
+      return false;
+
+   if (is_internalFormat_depth_or_depthstencil !=
+       is_format_depth_or_depthstencil)
+      return false;
+
+   if (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format))
+      return false;
 
+   return true;
+}
 
 /**
  * Test the glTexImage[123]D() parameters for errors.
- * 
+ *
  * \param ctx GL context.
  * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
+ * \param target texture target given by the user (already validated).
  * \param level image level given by the user.
  * \param internalFormat internal format given by the user.
  * \param format pixel data format given by the user.
@@ -1486,12 +2077,16 @@ mutable_tex_object(struct gl_context *ctx, GLenum target)
  * \param height image height given by the user.
  * \param depth image depth given by the user.
  * \param border image border given by the user.
- * 
- * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
+ *
+ * \return GL_TRUE if a error is found, GL_FALSE otherwise
  *
  * Verifies each of the parameters against the constants specified in
  * __struct gl_contextRec::Const and the supported extensions, and according
  * to the OpenGL specification.
+ * Note that we don't fully error-check the width, height, depth values
+ * here.  That's done in _mesa_legal_texture_dimensions() which is used
+ * by several other GL entrypoints.  Plus, texture dims have a special
+ * interaction with proxy textures.
  */
 static GLboolean
 texture_error_check( struct gl_context *ctx,
@@ -1501,105 +2096,95 @@ texture_error_check( struct gl_context *ctx,
                      GLint width, GLint height,
                      GLint depth, GLint border )
 {
-   const GLenum proxyTarget = get_proxy_target(target);
-   const GLboolean isProxy = target == proxyTarget;
-   GLboolean sizeOK = GL_TRUE;
-   GLboolean colorFormat;
+   GLenum err;
 
-   /* Even though there are no color-index textures, we still have to support
-    * uploading color-index data and remapping it to RGB via the
-    * GL_PIXEL_MAP_I_TO_[RGBA] tables.
+   /* Note: for proxy textures, some error conditions immediately generate
+    * a GL error in the usual way.  But others do not generate a GL error.
+    * Instead, they cause the width, height, depth, format fields of the
+    * texture image to be zeroed-out.  The GL spec seems to indicate that the
+    * zero-out behaviour is only used in cases related to memory allocation.
     */
-   const GLboolean indexFormat = (format == GL_COLOR_INDEX);
 
-   /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
-   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(level=%d)", dimensions, level);
-      }
+   /* level check */
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glTexImage%dD(level=%d)", dimensions, level);
       return GL_TRUE;
    }
 
    /* Check border */
    if (border < 0 || border > 1 ||
-       ((target == GL_TEXTURE_RECTANGLE_NV ||
+       ((ctx->API != API_OPENGL_COMPAT ||
+         target == GL_TEXTURE_RECTANGLE_NV ||
          target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(border=%d)", dimensions, border);
-      }
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glTexImage%dD(border=%d)", dimensions, border);
       return GL_TRUE;
    }
 
    if (width < 0 || height < 0 || depth < 0) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(width, height or depth < 0)", dimensions);
-      }
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glTexImage%dD(width, height or depth < 0)", dimensions);
       return GL_TRUE;
    }
 
-   /* Do this simple check before calling the TestProxyTexImage() function */
-   if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
-      sizeOK = (width == height);
-   }
-
-   /*
-    * Use the proxy texture driver hook to see if the size/level/etc are
-    * legal.
+   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
+    * combinations of format, internalFormat, and type that can be used.
+    * Formats and types that require additional extensions (e.g., GL_FLOAT
+    * requires GL_OES_texture_float) are filtered elsewhere.
     */
-   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
-                                                    internalFormat, format,
-                                                    type, width, height,
-                                                    depth, border);
-   if (!sizeOK) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)",
-                     dimensions, level, width, height, depth);
+
+   if (_mesa_is_gles(ctx)) {
+      if (_mesa_is_gles3(ctx)) {
+         err = _mesa_es3_error_check_format_and_type(format, type,
+                                                     internalFormat);
+      } else {
+         if (format != internalFormat) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glTexImage%dD(format = %s, internalFormat = %s)",
+                        dimensions,
+                        _mesa_lookup_enum_by_nr(format),
+                        _mesa_lookup_enum_by_nr(internalFormat));
+            return GL_TRUE;
+         }
+
+         err = _mesa_es_error_check_format_and_type(format, type, dimensions);
+      }
+      if (err != GL_NO_ERROR) {
+         _mesa_error(ctx, err,
+                     "glTexImage%dD(format = %s, type = %s, internalFormat = %s)",
+                     dimensions,
+                     _mesa_lookup_enum_by_nr(format),
+                     _mesa_lookup_enum_by_nr(type),
+                     _mesa_lookup_enum_by_nr(internalFormat));
+         return GL_TRUE;
       }
-      return GL_TRUE;
    }
 
    /* Check internalFormat */
    if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glTexImage%dD(internalFormat=%s)",
-                     dimensions, _mesa_lookup_enum_by_nr(internalFormat));
-      }
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glTexImage%dD(internalFormat=%s)",
+                  dimensions, _mesa_lookup_enum_by_nr(internalFormat));
       return GL_TRUE;
    }
 
    /* Check incoming image format and type */
-   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
-      /* Normally, GL_INVALID_OPERATION is generated by a format/type
-       * mismatch (see the 1.2 spec page 94, sec 3.6.4.).  But with the
-       * GL_EXT_texture_integer extension, some combinations should generate
-       * GL_INVALID_ENUM instead (grr!).
-       */
-      if (!isProxy) {
-         GLenum error = _mesa_is_integer_format(format)
-            ? GL_INVALID_ENUM : GL_INVALID_OPERATION;
-         _mesa_error(ctx, error,
-                     "glTexImage%dD(incompatible format 0x%x, type 0x%x)",
-                     dimensions, format, type);
-      }
+   err = _mesa_error_check_format_and_type(ctx, format, type);
+   if (err != GL_NO_ERROR) {
+      _mesa_error(ctx, err,
+                  "glTexImage%dD(incompatible format = %s, type = %s)",
+                  dimensions, _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type));
       return GL_TRUE;
    }
 
    /* make sure internal format and format basically agree */
-   colorFormat = _mesa_is_color_format(format);
-   if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
-       (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) ||
-       (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) ||
-       (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) ||
-       (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) {
-      if (!isProxy)
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)",
-                     dimensions, internalFormat, format);
+   if (!texture_formats_agree(internalFormat, format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glTexImage%dD(incompatible internalFormat = %s, format = %s)",
+                  dimensions, _mesa_lookup_enum_by_nr(internalFormat),
+                  _mesa_lookup_enum_by_nr(format));
       return GL_TRUE;
    }
 
@@ -1610,7 +2195,8 @@ texture_error_check( struct gl_context *ctx,
           type != GL_UNSIGNED_SHORT_8_8_REV_MESA) {
          char message[100];
          _mesa_snprintf(message, sizeof(message),
-                        "glTexImage%dD(format/type YCBCR mismatch", dimensions);
+                        "glTexImage%dD(format/type YCBCR mismatch)",
+                        dimensions);
          _mesa_error(ctx, GL_INVALID_ENUM, "%s", message);
          return GL_TRUE; /* error */
       }
@@ -1618,76 +2204,52 @@ texture_error_check( struct gl_context *ctx,
           target != GL_PROXY_TEXTURE_2D &&
           target != GL_TEXTURE_RECTANGLE_NV &&
           target != GL_PROXY_TEXTURE_RECTANGLE_NV) {
-         if (!isProxy)
-            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)");
+         _mesa_error(ctx, GL_INVALID_ENUM,
+                     "glTexImage%dD(bad target for YCbCr texture)",
+                     dimensions);
          return GL_TRUE;
       }
       if (border != 0) {
-         if (!isProxy) {
-            char message[100];
-            _mesa_snprintf(message, sizeof(message),
-                           "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)",
-                           dimensions, border);
-            _mesa_error(ctx, GL_INVALID_VALUE, "%s", message);
-         }
+         char message[100];
+         _mesa_snprintf(message, sizeof(message),
+                        "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)",
+                        dimensions, border);
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s", message);
          return GL_TRUE;
       }
    }
 
    /* additional checks for depth textures */
-   if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
-      /* Only 1D, 2D, rect, array and cube textures supported, not 3D
-       * Cubemaps are only supported for GL version > 3.0 or with EXT_gpu_shader4 */
-      if (target != GL_TEXTURE_1D &&
-          target != GL_PROXY_TEXTURE_1D &&
-          target != GL_TEXTURE_2D &&
-          target != GL_PROXY_TEXTURE_2D &&
-          target != GL_TEXTURE_1D_ARRAY &&
-          target != GL_PROXY_TEXTURE_1D_ARRAY &&
-          target != GL_TEXTURE_2D_ARRAY &&
-          target != GL_PROXY_TEXTURE_2D_ARRAY &&
-          target != GL_TEXTURE_RECTANGLE_ARB &&
-          target != GL_PROXY_TEXTURE_RECTANGLE_ARB &&
-         !((_mesa_is_cube_face(target) || target == GL_PROXY_TEXTURE_CUBE_MAP) &&
-           (ctx->VersionMajor >= 3 || ctx->Extensions.EXT_gpu_shader4))) {
-         if (!isProxy)
-            _mesa_error(ctx, GL_INVALID_ENUM,
-                        "glTexImage(target/internalFormat)");
-         return GL_TRUE;
-      }
-   }
+   if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalFormat,
+                                                   dimensions, "glTexImage"))
+      return GL_TRUE;
 
    /* additional checks for compressed textures */
    if (_mesa_is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target, internalFormat)) {
-         if (!isProxy)
-            _mesa_error(ctx, GL_INVALID_ENUM,
-                        "glTexImage%dD(target)", dimensions);
+      if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) {
+         _mesa_error(ctx, GL_INVALID_ENUM,
+                     "glTexImage%dD(target can't be compressed)", dimensions);
          return GL_TRUE;
       }
       if (compressedteximage_only_format(ctx, internalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-               "glTexImage%dD(no compression for format)", dimensions);
+                     "glTexImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
       }
       if (border != 0) {
-         if (!isProxy) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glTexImage%dD(border!=0)", dimensions);
-         }
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glTexImage%dD(border!=0)", dimensions);
          return GL_TRUE;
       }
    }
 
    /* additional checks for integer textures */
-   if (ctx->Extensions.EXT_texture_integer &&
-       (_mesa_is_integer_format(format) !=
-        _mesa_is_integer_format(internalFormat))) {
-      if (!isProxy) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexImage%dD(integer/non-integer format mismatch)",
-                     dimensions);
-      }
+   if ((ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) &&
+       (_mesa_is_enum_format_integer(format) !=
+        _mesa_is_enum_format_integer(internalFormat))) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glTexImage%dD(integer/non-integer format mismatch)",
+                  dimensions);
       return GL_TRUE;
    }
 
@@ -1702,12 +2264,184 @@ texture_error_check( struct gl_context *ctx,
 }
 
 
+bool
+_mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx,
+                                             GLint dimensions,
+                                             struct gl_pixelstore_attrib *packing,
+                                             const char *caller)
+{
+   if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
+      return true;
+
+   if (packing->CompressedBlockWidth && packing->SkipPixels % packing->CompressedBlockWidth) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(skip-pixels %% block-width)", caller);
+      return false;
+   }
+
+   if (dimensions > 1 && packing->CompressedBlockHeight && packing->SkipRows % packing->CompressedBlockHeight) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(skip-rows %% block-height)", caller);
+      return false;
+   }
+
+   if (dimensions > 2 && packing->CompressedBlockDepth && packing->SkipImages % packing->CompressedBlockDepth) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(skip-images %% block-depth)", caller);
+      return false;
+   }
+
+   return true;
+}
+
+/**
+ * Error checking for glCompressedTexImage[123]D().
+ * Note that the width, height and depth values are not fully error checked
+ * here.
+ * \return GL_TRUE if a error is found, GL_FALSE otherwise
+ */
+static GLenum
+compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
+                               GLenum target, GLint level,
+                               GLenum internalFormat, GLsizei width,
+                               GLsizei height, GLsizei depth, GLint border,
+                               GLsizei imageSize)
+{
+   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
+   GLint expectedSize;
+   GLenum error = GL_NO_ERROR;
+   char *reason = ""; /* no error */
+
+   if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) {
+      reason = "target";
+      /* From section 3.8.6, page 146 of OpenGL ES 3.0 spec:
+       *
+       *    "The ETC2/EAC texture compression algorithm supports only
+       *     two-dimensional images. If internalformat is an ETC2/EAC format,
+       *     CompressedTexImage3D will generate an INVALID_OPERATION error if
+       *     target is not TEXTURE_2D_ARRAY."
+       */
+      error = _mesa_is_desktop_gl(ctx) ? GL_INVALID_ENUM : GL_INVALID_OPERATION;
+      goto error;
+   }
+
+   /* This will detect any invalid internalFormat value */
+   if (!_mesa_is_compressed_format(ctx, internalFormat)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glCompressedTexImage%dD(internalFormat=%s)",
+                  dimensions, _mesa_lookup_enum_by_nr(internalFormat));
+      return GL_TRUE;
+   }
+
+   switch (internalFormat) {
+   case GL_PALETTE4_RGB8_OES:
+   case GL_PALETTE4_RGBA8_OES:
+   case GL_PALETTE4_R5_G6_B5_OES:
+   case GL_PALETTE4_RGBA4_OES:
+   case GL_PALETTE4_RGB5_A1_OES:
+   case GL_PALETTE8_RGB8_OES:
+   case GL_PALETTE8_RGBA8_OES:
+   case GL_PALETTE8_R5_G6_B5_OES:
+   case GL_PALETTE8_RGBA4_OES:
+   case GL_PALETTE8_RGB5_A1_OES:
+      /* check level (note that level should be zero or less!) */
+      if (level > 0 || level < -maxLevels) {
+        reason = "level";
+        error = GL_INVALID_VALUE;
+         goto error;
+      }
+
+      if (dimensions != 2) {
+        reason = "compressed paletted textures must be 2D";
+        error = GL_INVALID_OPERATION;
+         goto error;
+      }
+
+      /* Figure out the expected texture size (in bytes).  This will be
+       * checked against the actual size later.
+       */
+      expectedSize = _mesa_cpal_compressed_size(level, internalFormat,
+                                               width, height);
+
+      /* This is for the benefit of the TestProxyTexImage below.  It expects
+       * level to be non-negative.  OES_compressed_paletted_texture uses a
+       * weird mechanism where the level specified to glCompressedTexImage2D
+       * is -(n-1) number of levels in the texture, and the data specifies the
+       * complete mipmap stack.  This is done to ensure the palette is the
+       * same for all levels.
+       */
+      level = -level;
+      break;
+
+   default:
+      /* check level */
+      if (level < 0 || level >= maxLevels) {
+        reason = "level";
+        error = GL_INVALID_VALUE;
+         goto error;
+      }
+
+      /* Figure out the expected texture size (in bytes).  This will be
+       * checked against the actual size later.
+       */
+      expectedSize = compressed_tex_size(width, height, depth, internalFormat);
+      break;
+   }
+
+   /* This should really never fail */
+   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
+      reason = "internalFormat";
+      error = GL_INVALID_ENUM;
+      goto error;
+   }
+
+   /* No compressed formats support borders at this time */
+   if (border != 0) {
+      reason = "border != 0";
+      error = GL_INVALID_VALUE;
+      goto error;
+   }
+
+   /* Check for invalid pixel storage modes */
+   if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dimensions,
+                                                           &ctx->Unpack,
+                                                           "glCompressedTexImage")) {
+      return GL_FALSE;
+   }
+
+   /* check image size in bytes */
+   if (expectedSize != imageSize) {
+      /* Per GL_ARB_texture_compression:  GL_INVALID_VALUE is generated [...]
+       * if <imageSize> is not consistent with the format, dimensions, and
+       * contents of the specified image.
+       */
+      reason = "imageSize inconsistant with width/height/format";
+      error = GL_INVALID_VALUE;
+      goto error;
+   }
+
+   if (!mutable_tex_object(ctx, target)) {
+      reason = "immutable texture";
+      error = GL_INVALID_OPERATION;
+      goto error;
+   }
+
+   return GL_FALSE;
+
+error:
+   /* Note: not all error paths exit through here. */
+   _mesa_error(ctx, error, "glCompressedTexImage%dD(%s)", dimensions, reason);
+   return GL_TRUE;
+}
+
+
+
 /**
  * Test glTexSubImage[123]D() parameters for errors.
- * 
+ *
  * \param ctx GL context.
  * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
+ * \param target texture target given by the user (already validated)
  * \param level image level given by the user.
  * \param xoffset sub-image x offset given by the user.
  * \param yoffset sub-image y offset given by the user.
@@ -1717,7 +2451,7 @@ texture_error_check( struct gl_context *ctx,
  * \param width image width given by the user.
  * \param height image height given by the user.
  * \param depth image depth given by the user.
- * 
+ *
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  *
  * Verifies each of the parameters against the constants specified in
@@ -1725,132 +2459,95 @@ texture_error_check( struct gl_context *ctx,
  * to the OpenGL specification.
  */
 static GLboolean
-subtexture_error_check( struct gl_context *ctx, GLuint dimensions,
+texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
                         GLenum target, GLint level,
                         GLint xoffset, GLint yoffset, GLint zoffset,
                         GLint width, GLint height, GLint depth,
-                        GLenum format, GLenum type )
+                        GLenum format, GLenum type)
 {
-   /* Basic level check */
-   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level);
-      return GL_TRUE;
-   }
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GLenum err;
 
-   /* Check for negative sizes */
-   if (width < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glTexSubImage%dD(width=%d)", dimensions, width);
+   /* check target (proxies not allowed) */
+   if (!legal_texsubimage_target(ctx, dimensions, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
+                  dimensions, _mesa_lookup_enum_by_nr(target));
       return GL_TRUE;
    }
-   if (height < 0 && dimensions > 1) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glTexSubImage%dD(height=%d)", dimensions, height);
+
+   /* level check */
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(level=%d)",
+                  dimensions, level);
       return GL_TRUE;
    }
-   if (depth < 0 && dimensions > 2) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glTexSubImage%dD(depth=%d)", dimensions, depth);
-      return GL_TRUE;
+
+   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
+    * combinations of format and type that can be used.  Formats and types
+    * that require additional extensions (e.g., GL_FLOAT requires
+    * GL_OES_texture_float) are filtered elsewhere.
+    */
+   if (_mesa_is_gles(ctx) && !_mesa_is_gles3(ctx)) {
+      err = _mesa_es_error_check_format_and_type(format, type, dimensions);
+      if (err != GL_NO_ERROR) {
+         _mesa_error(ctx, err,
+                     "glTexSubImage%dD(format = %s, type = %s)",
+                     dimensions,
+                     _mesa_lookup_enum_by_nr(format),
+                     _mesa_lookup_enum_by_nr(type));
+         return GL_TRUE;
+      }
    }
 
-   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
-      /* As with the glTexImage2D check above, the error code here
-       * depends on texture integer.
-       */
-      GLenum error = _mesa_is_integer_format(format)
-         ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
-      _mesa_error(ctx, error,
-                  "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)",
-                  dimensions, format, type);
+   err = _mesa_error_check_format_and_type(ctx, format, type);
+   if (err != GL_NO_ERROR) {
+      _mesa_error(ctx, err,
+                  "glTexSubImage%dD(incompatible format = %s, type = %s)",
+                  dimensions, _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type));
       return GL_TRUE;
    }
 
-   return GL_FALSE;
-}
-
-
-/**
- * Do second part of glTexSubImage which depends on the destination texture.
- * \return GL_TRUE if error recorded, GL_FALSE otherwise
- */
-static GLboolean
-subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
-                        GLenum target, GLint level,
-                        GLint xoffset, GLint yoffset, GLint zoffset,
-                        GLint width, GLint height, GLint depth,
-                        GLenum format, GLenum type,
-                        const struct gl_texture_image *destTex )
-{
-   if (!destTex) {
-      /* undefined image level */
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions);
+   /* Get dest texture object / image pointers */
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   if (!texObj) {
+      /* must be out of memory */
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage%dD()", dimensions);
       return GL_TRUE;
    }
 
-   if (xoffset < -((GLint)destTex->Border)) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)",
-                  dimensions);
+   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+   if (!texImage) {
+      /* non-existant texture level */
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glTexSubImage%dD(invalid texture image)", dimensions);
       return GL_TRUE;
    }
-   if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)",
-                  dimensions);
+
+   if (error_check_subtexture_dimensions(ctx, "glTexSubImage", dimensions,
+                                         texImage, xoffset, yoffset, 0,
+                                         width, height, 1)) {
       return GL_TRUE;
    }
-   if (dimensions > 1) {
-      if (yoffset < -((GLint)destTex->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)",
-                     dimensions);
-         return GL_TRUE;
-      }
-      if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)",
-                     dimensions);
-         return GL_TRUE;
-      }
-   }
-   if (dimensions > 2) {
-      if (zoffset < -((GLint)destTex->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)");
-         return GL_TRUE;
-      }
-      if (zoffset + depth  > (GLint) (destTex->Depth + destTex->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)");
-         return GL_TRUE;
-      }
-   }
-
-   if (_mesa_is_format_compressed(destTex->TexFormat)) {
-      GLuint bw, bh;
 
-      if (compressedteximage_only_format(ctx, destTex->InternalFormat)) {
+   if (_mesa_is_format_compressed(texImage->TexFormat)) {
+      if (compressedteximage_only_format(ctx, texImage->InternalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "glTexSubImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
       }
+   }
 
-      /* do tests which depend on compression block size */
-      _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
-
-      /* offset must be multiple of block size */
-      if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
+   if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) {
+      /* both source and dest must be integer-valued, or neither */
+      if (_mesa_is_format_integer_color(texImage->TexFormat) !=
+          _mesa_is_enum_format_integer(format)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%dD(xoffset = %d, yoffset = %d)",
-                     dimensions, xoffset, yoffset);
+                     "glTexSubImage%dD(integer/non-integer format mismatch)",
+                     dimensions);
          return GL_TRUE;
       }
-      /* size must be multiple of bw by bh or equal to whole texture size */
-      if ((width % bw != 0) && (GLuint) width != destTex->Width) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%dD(width = %d)", dimensions, width);
-         return GL_TRUE;
-      }         
-      if ((height % bh != 0) && (GLuint) height != destTex->Height) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glTexSubImage%dD(height = %d)", dimensions, height);
-         return GL_TRUE;
-      }         
    }
 
    return GL_FALSE;
@@ -1859,7 +2556,7 @@ subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
 
 /**
  * Test glCopyTexImage[12]D() parameters for errors.
- * 
+ *
  * \param ctx GL context.
  * \param dimensions texture image dimensions (must be 1, 2 or 3).
  * \param target texture target given by the user.
@@ -1868,9 +2565,9 @@ subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
  * \param width image width given by the user.
  * \param height image height given by the user.
  * \param border texture border.
- * 
+ *
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- * 
+ *
  * Verifies each of the parameters against the constants specified in
  * __struct gl_contextRec::Const and the supported extensions, and according
  * to the OpenGL specification.
@@ -1880,20 +2577,20 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
                          GLenum target, GLint level, GLint internalFormat,
                          GLint width, GLint height, GLint border )
 {
-   const GLenum proxyTarget = get_proxy_target(target);
-   const GLenum type = GL_FLOAT;
-   GLboolean sizeOK;
    GLint baseFormat;
+   GLint rb_base_format;
+   struct gl_renderbuffer *rb;
+   GLenum rb_internal_format;
 
    /* check target */
    if (!legal_texsubimage_target(ctx, dimensions, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
                   dimensions, _mesa_lookup_enum_by_nr(target));
       return GL_TRUE;
-   }       
+   }
 
-   /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
-   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+   /* level check */
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
       _mesa_error(ctx, GL_INVALID_VALUE,
                   "glCopyTexImage%dD(level=%d)", dimensions, level);
       return GL_TRUE;
@@ -1909,52 +2606,187 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
                      "glCopyTexImage%dD(invalid readbuffer)", dimensions);
          return GL_TRUE;
       }
+
+      if (ctx->ReadBuffer->Visual.samples > 0) {
+        _mesa_error(ctx, GL_INVALID_OPERATION,
+                    "glCopyTexImage%dD(multisample FBO)",
+                    dimensions);
+        return GL_TRUE;
+      }
    }
 
    /* Check border */
    if (border < 0 || border > 1 ||
-       ((target == GL_TEXTURE_RECTANGLE_NV ||
+       ((ctx->API != API_OPENGL_COMPAT ||
+         target == GL_TEXTURE_RECTANGLE_NV ||
          target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glCopyTexImage%dD(border=%d)", dimensions, border);
       return GL_TRUE;
    }
 
-   baseFormat = _mesa_base_tex_format(ctx, internalFormat);
-   if (baseFormat < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexImage%dD(internalFormat)", dimensions);
+   rb = _mesa_get_read_renderbuffer_for_format(ctx, internalFormat);
+   if (rb == NULL) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexImage%dD(read buffer)", dimensions);
       return GL_TRUE;
    }
 
-   if (!_mesa_source_buffer_exists(ctx, baseFormat)) {
+   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
+    * internalFormat.
+    */
+   if (_mesa_is_gles(ctx) && !_mesa_is_gles3(ctx)) {
+      switch (internalFormat) {
+      case GL_ALPHA:
+      case GL_RGB:
+      case GL_RGBA:
+      case GL_LUMINANCE:
+      case GL_LUMINANCE_ALPHA:
+         break;
+      default:
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCopyTexImage%dD(internalFormat=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(internalFormat));
+         return GL_TRUE;
+      }
+   }
+
+   baseFormat = _mesa_base_tex_format(ctx, internalFormat);
+   if (baseFormat < 0) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCopyTexImage%dD(missing readbuffer)", dimensions);
+                  "glCopyTexImage%dD(internalFormat=%s)", dimensions,
+                  _mesa_lookup_enum_by_nr(internalFormat));
       return GL_TRUE;
    }
 
-   /* Do size, level checking */
-   sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB)
-      ? (width == height) : 1;
+   rb_internal_format = rb->InternalFormat;
+   rb_base_format = _mesa_base_tex_format(ctx, rb->InternalFormat);
+   if (_mesa_is_color_format(internalFormat)) {
+      if (rb_base_format < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCopyTexImage%dD(internalFormat=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(internalFormat));
+         return GL_TRUE;
+      }
+   }
+
+   if (_mesa_is_gles(ctx)) {
+      bool valid = true;
+      if (_mesa_base_format_component_count(baseFormat) >
+          _mesa_base_format_component_count(rb_base_format)) {
+         valid = false;
+      }
+      if (baseFormat == GL_DEPTH_COMPONENT ||
+          baseFormat == GL_DEPTH_STENCIL ||
+          rb_base_format == GL_DEPTH_COMPONENT ||
+          rb_base_format == GL_DEPTH_STENCIL ||
+          ((baseFormat == GL_LUMINANCE_ALPHA ||
+            baseFormat == GL_ALPHA) &&
+           rb_base_format != GL_RGBA) ||
+          internalFormat == GL_RGB9_E5) {
+         valid = false;
+      }
+      if (internalFormat == GL_RGB9_E5) {
+         valid = false;
+      }
+      if (!valid) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%dD(internalFormat=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(internalFormat));
+         return GL_TRUE;
+      }
+   }
 
-   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
-                                                    internalFormat, baseFormat,
-                                                    type, width, height,
-                                                    1, border);
+   if (_mesa_is_gles3(ctx)) {
+      bool rb_is_srgb = false;
+      bool dst_is_srgb = false;
 
-   if (!sizeOK) {
-      if (dimensions == 1) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexImage1D(width=%d)", width);
+      if (ctx->Extensions.EXT_framebuffer_sRGB &&
+          _mesa_get_format_color_encoding(rb->Format) == GL_SRGB) {
+         rb_is_srgb = true;
       }
-      else {
-         ASSERT(dimensions == 2);
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexImage2D(width=%d, height=%d)", width, height);
+
+      if (_mesa_get_linear_internalformat(internalFormat) != internalFormat) {
+         dst_is_srgb = true;
+      }
+
+      if (rb_is_srgb != dst_is_srgb) {
+         /* Page 137 (page 149 of the PDF) in section 3.8.5 of the
+          * OpenGLES 3.0.0 spec says:
+          *
+          *     "The error INVALID_OPERATION is also generated if the
+          *     value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the
+          *     framebuffer attachment corresponding to the read buffer
+          *     is LINEAR (see section 6.1.13) and internalformat is
+          *     one of the sRGB formats described in section 3.8.16, or
+          *     if the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING is
+          *     SRGB and internalformat is not one of the sRGB formats."
+          */
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%dD(srgb usage mismatch)", dimensions);
+         return GL_TRUE;
+      }
+
+      /* Page 139, Table 3.15 of OpenGL ES 3.0 spec does not define ReadPixels
+       * types for SNORM formats. Also, conversion to SNORM formats is not
+       * allowed by Table 3.2 on Page 110.
+       */
+      if(_mesa_is_enum_format_snorm(internalFormat)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glCopyTexImage%dD(internalFormat=%s)", dimensions,
+                     _mesa_lookup_enum_by_nr(internalFormat));
+         return GL_TRUE;
       }
+   }
+
+   if (!_mesa_source_buffer_exists(ctx, baseFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexImage%dD(missing readbuffer)", dimensions);
       return GL_TRUE;
    }
 
+   /* From the EXT_texture_integer spec:
+    *
+    *     "INVALID_OPERATION is generated by CopyTexImage* and CopyTexSubImage*
+    *      if the texture internalformat is an integer format and the read color
+    *      buffer is not an integer format, or if the internalformat is not an
+    *      integer format and the read color buffer is an integer format."
+    */
+   if (_mesa_is_color_format(internalFormat)) {
+      bool is_int = _mesa_is_enum_format_integer(internalFormat);
+      bool is_rbint = _mesa_is_enum_format_integer(rb_internal_format);
+      bool is_unorm = _mesa_is_enum_format_unorm(internalFormat);
+      bool is_rbunorm = _mesa_is_enum_format_unorm(rb_internal_format);
+      if (is_int || is_rbint) {
+         if (is_int != is_rbint) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glCopyTexImage%dD(integer vs non-integer)", dimensions);
+            return GL_TRUE;
+         } else if (_mesa_is_gles(ctx) &&
+                    _mesa_is_enum_format_unsigned_int(internalFormat) !=
+                      _mesa_is_enum_format_unsigned_int(rb_internal_format)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glCopyTexImage%dD(signed vs unsigned integer)", dimensions);
+            return GL_TRUE;
+         }
+      }
+
+      /* From page 138 of OpenGL ES 3.0 spec:
+       *    "The error INVALID_OPERATION is generated if floating-point RGBA
+       *    data is required; if signed integer RGBA data is required and the
+       *    format of the current color buffer is not signed integer; if
+       *    unsigned integer RGBA data is required and the format of the
+       *    current color buffer is not unsigned integer; or if fixed-point
+       *    RGBA data is required and the format of the current color buffer
+       *    is not fixed-point.
+       */
+      if (_mesa_is_gles(ctx) && is_unorm != is_rbunorm)
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glCopyTexImage%dD(unorm vs non-unorm)", dimensions);
+   }
+
    if (_mesa_is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target, internalFormat)) {
+      if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glCopyTexImage%dD(target)", dimensions);
          return GL_TRUE;
@@ -1984,20 +2816,17 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
 
 /**
  * Test glCopyTexSubImage[12]D() parameters for errors.
- * Note that this is the first part of error checking.
- * See also copytexsubimage_error_check2() below for the second part.
- * 
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- * 
  * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
  */
 static GLboolean
-copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
-                              GLenum target, GLint level)
+copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
+                            GLenum target, GLint level,
+                            GLint xoffset, GLint yoffset, GLint zoffset,
+                            GLint width, GLint height)
 {
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
    /* Check that the source buffer is complete */
    if (_mesa_is_user_fbo(ctx->ReadBuffer)) {
       if (ctx->ReadBuffer->_Status == 0) {
@@ -2008,6 +2837,13 @@ copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
                      "glCopyTexImage%dD(invalid readbuffer)", dimensions);
          return GL_TRUE;
       }
+
+      if (ctx->ReadBuffer->Visual.samples > 0) {
+        _mesa_error(ctx, GL_INVALID_OPERATION,
+                    "glCopyTexSubImage%dD(multisample FBO)",
+                    dimensions);
+        return GL_TRUE;
+      }
    }
 
    /* check target (proxies not allowed) */
@@ -2018,137 +2854,69 @@ copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
    }
 
    /* Check level */
-   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
       _mesa_error(ctx, GL_INVALID_VALUE,
                   "glCopyTexSubImage%dD(level=%d)", dimensions, level);
       return GL_TRUE;
    }
 
-   return GL_FALSE;
-}
-
-
-/**
- * Second part of error checking for glCopyTexSubImage[12]D().
- * \param xoffset sub-image x offset given by the user.
- * \param yoffset sub-image y offset given by the user.
- * \param zoffset sub-image z offset given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- */
-static GLboolean
-copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions,
-                             GLenum target, GLint level,
-                             GLint xoffset, GLint yoffset, GLint zoffset,
-                             GLsizei width, GLsizei height,
-                             const struct gl_texture_image *teximage )
-{
-   /* check that dest tex image exists */
-   if (!teximage) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCopyTexSubImage%dD(undefined texture level: %d)",
-                  dimensions, level);
+   /* Get dest texture object / image pointers */
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   if (!texObj) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%dD()", dimensions);
       return GL_TRUE;
    }
 
-   /* Check size */
-   if (width < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexSubImage%dD(width=%d)", dimensions, width);
-      return GL_TRUE;
-   }
-   if (dimensions > 1 && height < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexSubImage%dD(height=%d)", dimensions, height);
+   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+   if (!texImage) {
+      /* destination image does not exist */
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCopyTexSubImage%dD(invalid texture image)", dimensions);
       return GL_TRUE;
    }
 
-   /* check x/y offsets */
-   if (xoffset < -((GLint)teximage->Border)) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset);
-      return GL_TRUE;
-   }
-   if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCopyTexSubImage%dD(xoffset+width)", dimensions);
+   if (error_check_subtexture_dimensions(ctx, "glCopyTexSubImage",
+                                         dimensions, texImage,
+                                         xoffset, yoffset, zoffset,
+                                         width, height, 1)) {
       return GL_TRUE;
    }
-   if (dimensions > 1) {
-      if (yoffset < -((GLint)teximage->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset);
-         return GL_TRUE;
-      }
-      /* NOTE: we're adding the border here, not subtracting! */
-      if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(yoffset+height)", dimensions);
-         return GL_TRUE;
-      }
-   }
-
-   /* check z offset */
-   if (dimensions > 2) {
-      if (zoffset < -((GLint)teximage->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(zoffset)", dimensions);
-         return GL_TRUE;
-      }
-      if (zoffset > (GLint) (teximage->Depth + teximage->Border)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(zoffset+depth)", dimensions);
-         return GL_TRUE;
-      }
-   }
 
-   if (_mesa_is_format_compressed(teximage->TexFormat)) {
-      if (compressedteximage_only_format(ctx, teximage->InternalFormat)) {
+   if (_mesa_is_format_compressed(texImage->TexFormat)) {
+      if (compressedteximage_only_format(ctx, texImage->InternalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "glCopyTexSubImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
       }
-      /* offset must be multiple of 4 */
-      if ((xoffset & 3) || (yoffset & 3)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions);
-         return GL_TRUE;
-      }
-      /* size must be multiple of 4 */
-      if ((width & 3) != 0 && (GLuint) width != teximage->Width) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(width)", dimensions);
-         return GL_TRUE;
-      }         
-      if ((height & 3) != 0 && (GLuint) height != teximage->Height) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCopyTexSubImage%dD(height)", dimensions);
-         return GL_TRUE;
-      }         
    }
 
-   if (teximage->InternalFormat == 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)) {
+   if (!_mesa_source_buffer_exists(ctx, texImage->_BaseFormat)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCopyTexSubImage%dD(missing readbuffer, format=0x%x)",
-                  dimensions, teximage->_BaseFormat);
+                  dimensions, texImage->_BaseFormat);
       return GL_TRUE;
    }
 
-   /* If copying into an integer texture, the source buffer must also be
-    * integer-valued.
+   /* From the EXT_texture_integer spec:
+    *
+    *     "INVALID_OPERATION is generated by CopyTexImage* and CopyTexSubImage*
+    *      if the texture internalformat is an integer format and the read color
+    *      buffer is not an integer format, or if the internalformat is not an
+    *      integer format and the read color buffer is an integer format."
     */
-   if (_mesa_is_format_integer_color(teximage->TexFormat)) {
+   if (_mesa_is_color_format(texImage->InternalFormat)) {
       struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
-      if (!_mesa_is_format_integer_color(rb->Format)) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glCopyTexSubImage%dD(source buffer is not integer format)",
-                  dimensions);
-         return GL_TRUE;
+
+      if (_mesa_is_format_integer_color(rb->Format) !=
+         _mesa_is_format_integer_color(texImage->TexFormat)) {
+        _mesa_error(ctx, GL_INVALID_OPERATION,
+                    "glCopyTexImage%dD(integer vs non-integer)", dimensions);
+        return GL_TRUE;
       }
    }
 
@@ -2188,9 +2956,8 @@ check_rtt_cb(GLuint key, void *data, void *userData)
              att->Texture == texObj &&
              att->TextureLevel == level &&
              att->CubeMapFace == face) {
-            ASSERT(_mesa_get_attachment_teximage(att));
-            /* Tell driver about the new renderbuffer texture */
-            ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+            _mesa_update_texture_renderbuffer(ctx, ctx->DrawBuffer, att);
+            ASSERT(att->Renderbuffer->TexImage);
             /* Mark fb status as indeterminate to force re-validation */
             fb->_Status = 0;
          }
@@ -2293,13 +3060,13 @@ override_internal_format(GLenum internalFormat, GLint width, GLint height)
  * for efficient texture memory layout/allocation.  In particular, this
  * comes up during automatic mipmap generation.
  */
-gl_format
+mesa_format
 _mesa_choose_texture_format(struct gl_context *ctx,
                             struct gl_texture_object *texObj,
                             GLenum target, GLint level,
                             GLenum internalFormat, GLenum format, GLenum type)
 {
-   gl_format f;
+   mesa_format f;
 
    /* see if we've already chosen a format for the previous level */
    if (level > 0) {
@@ -2317,15 +3084,48 @@ _mesa_choose_texture_format(struct gl_context *ctx,
       }
    }
 
+   /* If the application requested compression to an S3TC format but we don't
+    * have the DXTn library, force a generic compressed format instead.
+    */
+   if (internalFormat != format && format != GL_NONE) {
+      const GLenum before = internalFormat;
+
+      switch (internalFormat) {
+      case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+         if (!ctx->Mesa_DXTn)
+            internalFormat = GL_COMPRESSED_RGB;
+         break;
+      case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+      case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+      case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+         if (!ctx->Mesa_DXTn)
+            internalFormat = GL_COMPRESSED_RGBA;
+         break;
+      default:
+         break;
+      }
+
+      if (before != internalFormat) {
+         _mesa_warning(ctx,
+                       "DXT compression requested (%s), "
+                       "but libtxc_dxtn library not installed.  Using %s "
+                       "instead.",
+                       _mesa_lookup_enum_by_nr(before),
+                       _mesa_lookup_enum_by_nr(internalFormat));
+      }
+   }
+
    /* choose format from scratch */
-   f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
+   f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat,
+                                       format, type);
    ASSERT(f != MESA_FORMAT_NONE);
    return f;
 }
 
+
 /**
  * Adjust pixel unpack params and image dimensions to strip off the
- * texture border.
+ * one-pixel texture border.
  *
  * Gallium and intel don't support texture borders.  They've seldem been used
  * and seldom been implemented correctly anyway.
@@ -2333,111 +3133,188 @@ _mesa_choose_texture_format(struct gl_context *ctx,
  * \param unpackNew returns the new pixel unpack parameters
  */
 static void
-strip_texture_border(GLint *border,
+strip_texture_border(GLenum target,
                      GLint *width, GLint *height, GLint *depth,
                      const struct gl_pixelstore_attrib *unpack,
                      struct gl_pixelstore_attrib *unpackNew)
 {
-   assert(*border > 0);  /* sanity check */
+   assert(width);
+   assert(height);
+   assert(depth);
 
    *unpackNew = *unpack;
 
    if (unpackNew->RowLength == 0)
       unpackNew->RowLength = *width;
 
-   if (depth && unpackNew->ImageHeight == 0)
+   if (unpackNew->ImageHeight == 0)
       unpackNew->ImageHeight = *height;
 
-   unpackNew->SkipPixels += *border;
-   if (height)
-      unpackNew->SkipRows += *border;
-   if (depth)
-      unpackNew->SkipImages += *border;
-
    assert(*width >= 3);
-   *width = *width - 2 * *border;
-   if (height && *height >= 3)
-      *height = *height - 2 * *border;
-   if (depth && *depth >= 3)
-      *depth = *depth - 2 * *border;
-   *border = 0;
+   unpackNew->SkipPixels++;  /* skip the border */
+   *width = *width - 2;      /* reduce the width by two border pixels */
+
+   /* The min height of a texture with a border is 3 */
+   if (*height >= 3 && target != GL_TEXTURE_1D_ARRAY) {
+      unpackNew->SkipRows++;  /* skip the border */
+      *height = *height - 2;  /* reduce the height by two border pixels */
+   }
+
+   if (*depth >= 3 &&
+       target != GL_TEXTURE_2D_ARRAY &&
+       target != GL_TEXTURE_CUBE_MAP_ARRAY) {
+      unpackNew->SkipImages++;  /* skip the border */
+      *depth = *depth - 2;      /* reduce the depth by two border pixels */
+   }
 }
 
+
 /**
- * Common code to implement all the glTexImage1D/2D/3D functions.
+ * Common code to implement all the glTexImage1D/2D/3D functions
+ * as well as glCompressedTexImage1D/2D/3D.
+ * \param compressed  only GL_TRUE for glCompressedTexImage1D/2D/3D calls.
+ * \param format  the user's image format (only used if !compressed)
+ * \param type  the user's image type (only used if !compressed)
+ * \param imageSize  only used for glCompressedTexImage1D/2D/3D calls.
  */
 static void
-teximage(struct gl_context *ctx, GLuint dims,
+teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
          GLenum target, GLint level, GLint internalFormat,
          GLsizei width, GLsizei height, GLsizei depth,
          GLint border, GLenum format, GLenum type,
-         const GLvoid *pixels)
+         GLsizei imageSize, const GLvoid *pixels)
 {
-   GLboolean error;
+   const char *func = compressed ? "glCompressedTexImage" : "glTexImage";
    struct gl_pixelstore_attrib unpack_no_border;
    const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
-
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n",
-                  dims,
-                  _mesa_lookup_enum_by_nr(target), level,
-                  _mesa_lookup_enum_by_nr(internalFormat),
-                  width, height, depth, border,
-                  _mesa_lookup_enum_by_nr(format),
-                  _mesa_lookup_enum_by_nr(type), pixels);
+   struct gl_texture_object *texObj;
+   mesa_format texFormat;
+   GLboolean dimensionsOK, sizeOK;
+
+   FLUSH_VERTICES(ctx, 0);
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) {
+      if (compressed)
+         _mesa_debug(ctx,
+                     "glCompressedTexImage%uD %s %d %s %d %d %d %d %p\n",
+                     dims,
+                     _mesa_lookup_enum_by_nr(target), level,
+                     _mesa_lookup_enum_by_nr(internalFormat),
+                     width, height, depth, border, pixels);
+      else
+         _mesa_debug(ctx,
+                     "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n",
+                     dims,
+                     _mesa_lookup_enum_by_nr(target), level,
+                     _mesa_lookup_enum_by_nr(internalFormat),
+                     width, height, depth, border,
+                     _mesa_lookup_enum_by_nr(format),
+                     _mesa_lookup_enum_by_nr(type), pixels);
+   }
 
    internalFormat = override_internal_format(internalFormat, width, height);
 
    /* target error checking */
    if (!legal_teximage_target(ctx, dims, target)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)",
-                  dims, _mesa_lookup_enum_by_nr(target));
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s%uD(target=%s)",
+                  func, dims, _mesa_lookup_enum_by_nr(target));
       return;
    }
 
    /* general error checking */
-   error = texture_error_check(ctx, dims, target, level, internalFormat,
-                               format, type, width, height, depth, border);
+   if (compressed) {
+      if (compressed_texture_error_check(ctx, dims, target, level,
+                                         internalFormat,
+                                         width, height, depth,
+                                         border, imageSize))
+         return;
+   }
+   else {
+      if (texture_error_check(ctx, dims, target, level, internalFormat,
+                              format, type, width, height, depth, border))
+         return;
+   }
+
+   /* Here we convert a cpal compressed image into a regular glTexImage2D
+    * call by decompressing the texture.  If we really want to support cpal
+    * textures in any driver this would have to be changed.
+    */
+   if (ctx->API == API_OPENGLES && compressed && dims == 2) {
+      switch (internalFormat) {
+      case GL_PALETTE4_RGB8_OES:
+      case GL_PALETTE4_RGBA8_OES:
+      case GL_PALETTE4_R5_G6_B5_OES:
+      case GL_PALETTE4_RGBA4_OES:
+      case GL_PALETTE4_RGB5_A1_OES:
+      case GL_PALETTE8_RGB8_OES:
+      case GL_PALETTE8_RGBA8_OES:
+      case GL_PALETTE8_R5_G6_B5_OES:
+      case GL_PALETTE8_RGBA4_OES:
+      case GL_PALETTE8_RGB5_A1_OES:
+         _mesa_cpal_compressed_teximage2d(target, level, internalFormat,
+                                          width, height, imageSize, pixels);
+         return;
+      }
+   }
+
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   assert(texObj);
+
+   if (compressed) {
+      /* For glCompressedTexImage() the driver has no choice about the
+       * texture format since we'll never transcode the user's compressed
+       * image data.  The internalFormat was error checked earlier.
+       */
+      texFormat = _mesa_glenum_to_compressed_format(internalFormat);
+   }
+   else {
+      texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+                                              internalFormat, format, type);
+   }
+
+   assert(texFormat != MESA_FORMAT_NONE);
+
+   /* check that width, height, depth are legal for the mipmap level */
+   dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, level, width,
+                                                 height, depth, border);
+
+   /* check that the texture won't take too much memory, etc */
+   sizeOK = ctx->Driver.TestProxyTexImage(ctx, proxy_target(target),
+                                          level, texFormat,
+                                          width, height, depth, border);
 
    if (_mesa_is_proxy_texture(target)) {
       /* Proxy texture: just clear or set state depending on error checking */
       struct gl_texture_image *texImage =
-         _mesa_get_proxy_tex_image(ctx, target, level);
+         get_proxy_tex_image(ctx, target, level);
+
+      if (!texImage)
+         return;  /* GL_OUT_OF_MEMORY already recorded */
 
-      if (error) {
-         /* when error, clear all proxy texture image parameters */
-         if (texImage)
-            clear_teximage_fields(texImage);
+      if (dimensionsOK && sizeOK) {
+         _mesa_init_teximage_fields(ctx, texImage, width, height, depth,
+                                    border, internalFormat, texFormat);
       }
       else {
-         /* no error, set the tex image parameters */
-         struct gl_texture_object *texObj =
-            _mesa_get_current_tex_object(ctx, target);
-         gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
-                                                           target, level,
-                                                           internalFormat,
-                                                           format, type);
-
-         if (legal_texture_size(ctx, texFormat, width, height, depth)) {
-            _mesa_init_teximage_fields(ctx, texImage, width, height,
-                                       depth, border, internalFormat,
-                                       texFormat);
-         }
-         else if (texImage) {
-            clear_teximage_fields(texImage);
-         }
+         clear_teximage_fields(texImage);
       }
    }
    else {
       /* non-proxy target */
       const GLuint face = _mesa_tex_target_to_face(target);
-      struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
 
-      if (error) {
-         return;   /* error was recorded */
+      if (!dimensionsOK) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glTexImage%uD(invalid width or height or depth)",
+                     dims);
+         return;
+      }
+
+      if (!sizeOK) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                     "glTexImage%uD(image too large)", dims);
+         return;
       }
 
       /* Allow a hardware driver to just strip out the border, to provide
@@ -2445,70 +3322,46 @@ teximage(struct gl_context *ctx, GLuint dims,
        * rarely-tested software fallback rendering.
        */
       if (border && ctx->Const.StripTextureBorder) {
-        strip_texture_border(&border, &width, &height, &depth, unpack,
+        strip_texture_border(target, &width, &height, &depth, unpack,
                              &unpack_no_border);
+         border = 0;
         unpack = &unpack_no_border;
       }
 
       if (ctx->NewState & _NEW_PIXEL)
         _mesa_update_state(ctx);
 
-      texObj = _mesa_get_current_tex_object(ctx, target);
-
       _mesa_lock_texture(ctx, texObj);
       {
         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
         if (!texImage) {
-           _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
+           _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
         }
          else {
-            gl_format texFormat;
-
             ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
-            texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
-                                                    internalFormat, format,
-                                                    type);
-
-            if (legal_texture_size(ctx, texFormat, width, height, depth)) {
-               _mesa_init_teximage_fields(ctx, texImage,
-                                          width, height, depth,
-                                          border, internalFormat, texFormat);
-
-               /* Give the texture to the driver.  <pixels> may be null. */
-               ASSERT(ctx->Driver.TexImage3D);
-               switch (dims) {
-               case 1:
-                  ctx->Driver.TexImage1D(ctx, texImage, internalFormat,
-                                         width, border, format,
-                                         type, pixels, unpack);
-                  break;
-               case 2:
-                  ctx->Driver.TexImage2D(ctx, texImage, internalFormat,
-                                         width, height, border, format,
-                                         type, pixels, unpack);
-                  break;
-               case 3:
-                  ctx->Driver.TexImage3D(ctx, texImage, internalFormat,
-                                         width, height, depth, border, format,
-                                         type, pixels, unpack);
-                  break;
-               default:
-                  _mesa_problem(ctx, "invalid dims=%u in teximage()", dims);
+            _mesa_init_teximage_fields(ctx, texImage,
+                                       width, height, depth,
+                                       border, internalFormat, texFormat);
+
+            /* Give the texture to the driver.  <pixels> may be null. */
+            if (width > 0 && height > 0 && depth > 0) {
+               if (compressed) {
+                  ctx->Driver.CompressedTexImage(ctx, dims, texImage,
+                                                 imageSize, pixels);
+               }
+               else {
+                  ctx->Driver.TexImage(ctx, dims, texImage, format,
+                                       type, pixels, unpack);
                }
+            }
 
-               check_gen_mipmap(ctx, target, texObj, level);
+            check_gen_mipmap(ctx, target, texObj, level);
 
-               _mesa_update_fbo_texture(ctx, texObj, face, level);
+            _mesa_update_fbo_texture(ctx, texObj, face, level);
 
-               /* state update */
-               texObj->_Complete = GL_FALSE;
-               ctx->NewState |= _NEW_TEXTURE;
-            }
-            else {
-               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
-            }
+            _mesa_dirty_texobj(ctx, texObj);
          }
       }
       _mesa_unlock_texture(ctx, texObj);
@@ -2516,6 +3369,7 @@ teximage(struct gl_context *ctx, GLuint dims,
 }
 
 
+
 /*
  * Called from the API.  Note that width includes the border.
  */
@@ -2525,8 +3379,8 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
                   GLenum type, const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, 1, target, level, internalFormat, width, 1, 1,
-            border, format, type, pixels);
+   teximage(ctx, GL_FALSE, 1, target, level, internalFormat, width, 1, 1,
+            border, format, type, 0, pixels);
 }
 
 
@@ -2537,8 +3391,8 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, 2, target, level, internalFormat, width, height, 1,
-            border, format, type, pixels);
+   teximage(ctx, GL_FALSE, 2, target, level, internalFormat, width, height, 1,
+            border, format, type, 0, pixels);
 }
 
 
@@ -2553,8 +3407,9 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, 3, target, level, internalFormat, width, height, depth,
-            border, format, type, pixels);
+   teximage(ctx, GL_FALSE, 3, target, level, internalFormat,
+            width, height, depth,
+            border, format, type, 0, pixels);
 }
 
 
@@ -2569,30 +3424,53 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
 }
 
 
-#if FEATURE_OES_EGL_image
 void GLAPIENTRY
 _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
 {
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
+   bool valid_target;
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+   FLUSH_VERTICES(ctx, 0);
+
+   switch (target) {
+   case GL_TEXTURE_2D:
+      valid_target = ctx->Extensions.OES_EGL_image;
+      break;
+   case GL_TEXTURE_EXTERNAL_OES:
+      valid_target =
+         _mesa_is_gles(ctx) ? ctx->Extensions.OES_EGL_image_external : false;
+      break;
+   default:
+      valid_target = false;
+      break;
+   }
 
-   if ((target == GL_TEXTURE_2D &&
-        !ctx->Extensions.OES_EGL_image) ||
-       (target == GL_TEXTURE_EXTERNAL_OES &&
-        !ctx->Extensions.OES_EGL_image_external)) {
+   if (!valid_target) {
       _mesa_error(ctx, GL_INVALID_ENUM,
                  "glEGLImageTargetTexture2D(target=%d)", target);
       return;
    }
 
+   if (!image) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                 "glEGLImageTargetTexture2D(image=%p)", image);
+      return;
+   }
+
    if (ctx->NewState & _NEW_PIXEL)
       _mesa_update_state(ctx);
 
    texObj = _mesa_get_current_tex_object(ctx, target);
    _mesa_lock_texture(ctx, texObj);
 
+   if (texObj->Immutable) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                 "glEGLImageTargetTexture2D(texture is immutable)");
+      _mesa_unlock_texture(ctx, texObj);
+      return;
+   }
+
    texImage = _mesa_get_tex_image(ctx, texObj, target, 0);
    if (!texImage) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D");
@@ -2602,14 +3480,11 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
       ctx->Driver.EGLImageTargetTexture2D(ctx, target,
                                          texObj, texImage, image);
 
-      /* state update */
-      texObj->_Complete = GL_FALSE;
-      ctx->NewState |= _NEW_TEXTURE;
+      _mesa_dirty_texobj(ctx, texObj);
    }
    _mesa_unlock_texture(ctx, texObj);
 
 }
-#endif
 
 
 
@@ -2625,7 +3500,7 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
 
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+   FLUSH_VERTICES(ctx, 0);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n",
@@ -2640,13 +3515,14 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
       _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
                   dims, _mesa_lookup_enum_by_nr(target));
       return;
-   }       
+   }
 
    if (ctx->NewState & _NEW_PIXEL)
       _mesa_update_state(ctx);
 
-   if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset,
-                              width, height, depth, format, type)) {
+   if (texsubimage_error_check(ctx, dims, target, level,
+                               xoffset, yoffset, zoffset,
+                               width, height, depth, format, type)) {
       return;   /* error was detected */
    }
 
@@ -2656,49 +3532,31 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-      if (subtexture_error_check2(ctx, dims, target, level,
-                                  xoffset, yoffset, zoffset,
-                                 width, height, depth,
-                                  format, type, texImage)) {
-         /* error was recorded */
-      }
-      else if (width > 0 && height > 0 && depth > 0) {
+      if (width > 0 && height > 0 && depth > 0) {
          /* If we have a border, offset=-1 is legal.  Bias by border width. */
          switch (dims) {
          case 3:
-            zoffset += texImage->Border;
+            if (target != GL_TEXTURE_2D_ARRAY)
+               zoffset += texImage->Border;
             /* fall-through */
          case 2:
-            yoffset += texImage->Border;
+            if (target != GL_TEXTURE_1D_ARRAY)
+               yoffset += texImage->Border;
             /* fall-through */
          case 1:
             xoffset += texImage->Border;
          }
 
-         switch (dims) {
-         case 1:
-            ctx->Driver.TexSubImage1D(ctx, texImage,
-                                      xoffset, width,
-                                      format, type, pixels, &ctx->Unpack);
-            break;
-         case 2:
-            ctx->Driver.TexSubImage2D(ctx, texImage,
-                                      xoffset, yoffset, width, height,
-                                      format, type, pixels, &ctx->Unpack);
-            break;
-         case 3:
-            ctx->Driver.TexSubImage3D(ctx, texImage,
-                                      xoffset, yoffset, zoffset,
-                                      width, height, depth,
-                                      format, type, pixels, &ctx->Unpack);
-            break;
-         default:
-            _mesa_problem(ctx, "unexpected dims in subteximage()");
-         }
+         ctx->Driver.TexSubImage(ctx, dims, texImage,
+                                 xoffset, yoffset, zoffset,
+                                 width, height, depth,
+                                 format, type, pixels, &ctx->Unpack);
 
          check_gen_mipmap(ctx, target, texObj, level);
 
-         ctx->NewState |= _NEW_TEXTURE;
+         /* NOTE: Don't signal _NEW_TEXTURE since we've only changed
+          * the texel data, not the texture format, size, etc.
+          */
       }
    }
    _mesa_unlock_texture(ctx, texObj);
@@ -2756,7 +3614,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
  * from.  This depends on whether the texture contains color or depth values.
  */
 static struct gl_renderbuffer *
-get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat)
+get_copy_tex_image_source(struct gl_context *ctx, mesa_format texFormat)
 {
    if (_mesa_get_format_bits(texFormat, GL_DEPTH_BITS) > 0) {
       /* reading from depth/stencil buffer */
@@ -2768,7 +3626,58 @@ get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat)
    }
 }
 
+static void
+copytexsubimage_by_slice(struct gl_context *ctx,
+                         struct gl_texture_image *texImage,
+                         GLuint dims,
+                         GLint xoffset, GLint yoffset, GLint zoffset,
+                         struct gl_renderbuffer *rb,
+                         GLint x, GLint y,
+                         GLsizei width, GLsizei height)
+{
+   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+      int slice;
+
+      /* For 1D arrays, we copy each scanline of the source rectangle into the
+       * next array slice.
+       */
+      assert(zoffset == 0);
+
+      for (slice = 0; slice < height; slice++) {
+         assert(yoffset + slice < texImage->Height);
+         ctx->Driver.CopyTexSubImage(ctx, 2, texImage,
+                                     xoffset, 0, yoffset + slice,
+                                     rb, x, y + slice, width, 1);
+      }
+   } else {
+      ctx->Driver.CopyTexSubImage(ctx, dims, texImage,
+                                  xoffset, yoffset, zoffset,
+                                  rb, x, y, width, height);
+   }
+}
+
+static GLboolean
+formats_differ_in_component_sizes (mesa_format f1,
+                                   mesa_format f2)
+{
+   GLint f1_r_bits = _mesa_get_format_bits(f1, GL_RED_BITS);
+   GLint f1_g_bits = _mesa_get_format_bits(f1, GL_GREEN_BITS);
+   GLint f1_b_bits = _mesa_get_format_bits(f1, GL_BLUE_BITS);
+   GLint f1_a_bits = _mesa_get_format_bits(f1, GL_ALPHA_BITS);
+
+   GLint f2_r_bits = _mesa_get_format_bits(f2, GL_RED_BITS);
+   GLint f2_g_bits = _mesa_get_format_bits(f2, GL_GREEN_BITS);
+   GLint f2_b_bits = _mesa_get_format_bits(f2, GL_BLUE_BITS);
+   GLint f2_a_bits = _mesa_get_format_bits(f2, GL_ALPHA_BITS);
+
+   if ((f1_r_bits && f2_r_bits && f1_r_bits != f2_r_bits)
+       || (f1_g_bits && f2_g_bits && f1_g_bits != f2_g_bits)
+       || (f1_b_bits && f2_b_bits && f1_b_bits != f2_b_bits)
+       || (f1_a_bits && f2_a_bits && f1_a_bits != f2_a_bits))
+      return GL_TRUE;
 
+   return GL_FALSE;
+}
 
 /**
  * Implement the glCopyTexImage1/2D() functions.
@@ -2781,8 +3690,10 @@ copyteximage(struct gl_context *ctx, GLuint dims,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    const GLuint face = _mesa_tex_target_to_face(target);
+   mesa_format texFormat;
+   struct gl_renderbuffer *rb;
 
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+   FLUSH_VERTICES(ctx, 0);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n",
@@ -2798,7 +3709,61 @@ copyteximage(struct gl_context *ctx, GLuint dims,
                                width, height, border))
       return;
 
+   if (!_mesa_legal_texture_dimensions(ctx, target, level, width, height,
+                                       1, border)) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glCopyTexImage%uD(invalid width or height)", dims);
+      return;
+   }
+
    texObj = _mesa_get_current_tex_object(ctx, target);
+   assert(texObj);
+
+   texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+                                           internalFormat, GL_NONE, GL_NONE);
+
+   rb = _mesa_get_read_renderbuffer_for_format(ctx, internalFormat);
+
+   if (_mesa_is_gles3(ctx)) {
+      if (_mesa_is_enum_format_unsized(internalFormat)) {
+      /* Conversion from GL_RGB10_A2 source buffer format is not allowed in
+       * OpenGL ES 3.0. Khronos bug# 9807.
+       */
+         if (rb->InternalFormat == GL_RGB10_A2) {
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glCopyTexImage%uD(Reading from GL_RGB10_A2 buffer and"
+                           " writing to unsized internal format)", dims);
+               return;
+         }
+      }
+      /* From Page 139 of OpenGL ES 3.0 spec:
+       *    "If internalformat is sized, the internal format of the new texel
+       *    array is internalformat, and this is also the new texel array’s
+       *    effective internal format. If the component sizes of internalformat
+       *    do not exactly match the corresponding component sizes of the source
+       *    buffer’s effective internal format, described below, an
+       *    INVALID_OPERATION error is generated. If internalformat is unsized,
+       *    the internal format of the new texel array is the effective internal
+       *    format of the source buffer, and this is also the new texel array’s
+       *    effective internal format.
+       */
+      else if (formats_differ_in_component_sizes (texFormat, rb->Format)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glCopyTexImage%uD(componenet size changed in"
+                        " internal format)", dims);
+            return;
+      }
+   }
+
+   assert(texFormat != MESA_FORMAT_NONE);
+
+   if (!ctx->Driver.TestProxyTexImage(ctx, proxy_target(target),
+                                      level, texFormat,
+                                      width, height, 1, border)) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                  "glCopyTexImage%uD(image too large)", dims);
+      return;
+   }
 
    if (border && ctx->Const.StripTextureBorder) {
       x += border;
@@ -2818,59 +3783,34 @@ copyteximage(struct gl_context *ctx, GLuint dims,
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
       }
       else {
-         /* choose actual hw format */
-         gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
-                                                           target, level,
-                                                           internalFormat,
-                                                           GL_NONE, GL_NONE);
+         GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
 
-         if (legal_texture_size(ctx, texFormat, width, height, 1)) {
-            GLint srcX = x, srcY = y, dstX = 0, dstY = 0;
-
-            /* Free old texture image */
-            ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
+         /* Free old texture image */
+         ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
-            _mesa_init_teximage_fields(ctx, texImage, width, height, 1,
-                                       border, internalFormat, texFormat);
+         _mesa_init_teximage_fields(ctx, texImage, width, height, 1,
+                                    border, internalFormat, texFormat);
 
+         if (width && height) {
             /* Allocate texture memory (no pixel data yet) */
-            if (dims == 1) {
-               ctx->Driver.TexImage1D(ctx, texImage, internalFormat,
-                                      width, border, GL_NONE, GL_NONE, NULL,
-                                      &ctx->Unpack);
-            }
-            else {
-               ctx->Driver.TexImage2D(ctx, texImage, internalFormat,
-                                      width, height, border, GL_NONE, GL_NONE,
-                                      NULL, &ctx->Unpack);
-            }
+            ctx->Driver.AllocTextureImageBuffer(ctx, texImage);
 
             if (_mesa_clip_copytexsubimage(ctx, &dstX, &dstY, &srcX, &srcY,
                                            &width, &height)) {
                struct gl_renderbuffer *srcRb =
                   get_copy_tex_image_source(ctx, texImage->TexFormat);
 
-               if (dims == 1)
-                  ctx->Driver.CopyTexSubImage1D(ctx, texImage, dstX,
-                                                srcRb, srcX, srcY, width);
-                                                
-               else
-                  ctx->Driver.CopyTexSubImage2D(ctx, texImage, dstX, dstY,
-                                                srcRb, srcX, srcY, width, height);
+               copytexsubimage_by_slice(ctx, texImage, dims,
+                                        dstX, dstY, dstZ,
+                                        srcRb, srcX, srcY, width, height);
             }
 
             check_gen_mipmap(ctx, target, texObj, level);
+         }
 
-            _mesa_update_fbo_texture(ctx, texObj, face, level);
+         _mesa_update_fbo_texture(ctx, texObj, face, level);
 
-            /* state update */
-            texObj->_Complete = GL_FALSE;
-            ctx->NewState |= _NEW_TEXTURE;
-         }
-         else {
-            /* probably too large of image */
-            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
-         }
+         _mesa_dirty_texobj(ctx, texObj);
       }
    }
    _mesa_unlock_texture(ctx, texObj);
@@ -2913,7 +3853,7 @@ copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
 
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+   FLUSH_VERTICES(ctx, 0);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n",
@@ -2924,8 +3864,10 @@ copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
-   if (copytexsubimage_error_check1(ctx, dims, target, level))
+   if (copytexsubimage_error_check(ctx, dims, target, level,
+                                   xoffset, yoffset, zoffset, width, height)) {
       return;
+   }
 
    texObj = _mesa_get_current_tex_object(ctx, target);
 
@@ -2933,50 +3875,34 @@ copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
 
-      if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset,
-                                      zoffset, width, height, texImage)) {
-         /* error was recored */
-      }
-      else {
-         /* If we have a border, offset=-1 is legal.  Bias by border width. */
-         switch (dims) {
-         case 3:
+      /* If we have a border, offset=-1 is legal.  Bias by border width. */
+      switch (dims) {
+      case 3:
+         if (target != GL_TEXTURE_2D_ARRAY)
             zoffset += texImage->Border;
-            /* fall-through */
-         case 2:
+         /* fall-through */
+      case 2:
+         if (target != GL_TEXTURE_1D_ARRAY)
             yoffset += texImage->Border;
-            /* fall-through */
-         case 1:
-            xoffset += texImage->Border;
-         }
+         /* fall-through */
+      case 1:
+         xoffset += texImage->Border;
+      }
 
-         if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
-                                        &width, &height)) {
-            struct gl_renderbuffer *srcRb =
-               get_copy_tex_image_source(ctx, texImage->TexFormat);
-
-            switch (dims) {
-            case 1:
-               ctx->Driver.CopyTexSubImage1D(ctx, texImage, xoffset,
-                                             srcRb, x, y, width);
-               break;
-            case 2:
-               ctx->Driver.CopyTexSubImage2D(ctx, texImage, xoffset, yoffset,
-                                             srcRb, x, y, width, height);
-               break;
-            case 3:
-               ctx->Driver.CopyTexSubImage3D(ctx, texImage,
-                                             xoffset, yoffset, zoffset,
-                                             srcRb, x, y, width, height);
-               break;
-            default:
-               _mesa_problem(ctx, "bad dims in copytexsubimage()");
-            }
+      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                     &width, &height)) {
+         struct gl_renderbuffer *srcRb =
+            get_copy_tex_image_source(ctx, texImage->TexFormat);
 
-            check_gen_mipmap(ctx, target, texObj, level);
+         copytexsubimage_by_slice(ctx, texImage, dims,
+                                  xoffset, yoffset, zoffset,
+                                  srcRb, x, y, width, height);
 
-            ctx->NewState |= _NEW_TEXTURE;
-         }
+         check_gen_mipmap(ctx, target, texObj, level);
+
+         /* NOTE: Don't signal _NEW_TEXTURE since we've only changed
+          * the texel data, not the texture format, size, etc.
+          */
       }
    }
    _mesa_unlock_texture(ctx, texObj);
@@ -3015,294 +3941,364 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
                    x, y, width, height);
 }
 
+static bool
+check_clear_tex_image(struct gl_context *ctx,
+                      const char *function,
+                      struct gl_texture_image *texImage,
+                      GLenum format, GLenum type,
+                      const void *data,
+                      GLubyte *clearValue)
+{
+   struct gl_texture_object *texObj = texImage->TexObject;
+   static const GLubyte zeroData[MAX_PIXEL_BYTES];
+   GLenum internalFormat = texImage->InternalFormat;
+   GLenum err;
 
+   if (texObj->Target == GL_TEXTURE_BUFFER) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(buffer texture)", function);
+      return false;
+   }
 
+   if (_mesa_is_compressed_format(ctx, internalFormat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(compressed texture)", function);
+      return false;
+   }
 
-/**********************************************************************/
-/******                   Compressed Textures                    ******/
-/**********************************************************************/
+   err = _mesa_error_check_format_and_type(ctx, format, type);
+   if (err != GL_NO_ERROR) {
+      _mesa_error(ctx, err,
+                  "%s(incompatible format = %s, type = %s)",
+                  function,
+                  _mesa_lookup_enum_by_nr(format),
+                  _mesa_lookup_enum_by_nr(type));
+      return false;
+   }
 
+   /* make sure internal format and format basically agree */
+   if (!texture_formats_agree(internalFormat, format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(incompatible internalFormat = %s, format = %s)",
+                  function,
+                  _mesa_lookup_enum_by_nr(internalFormat),
+                  _mesa_lookup_enum_by_nr(format));
+      return false;
+   }
 
-/**
- * Return expected size of a compressed texture.
- */
-static GLuint
-compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth,
-                    GLenum glformat)
-{
-   gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
-   return _mesa_format_image_size(mesaFormat, width, height, depth);
-}
+   if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) {
+      /* both source and dest must be integer-valued, or neither */
+      if (_mesa_is_format_integer_color(texImage->TexFormat) !=
+          _mesa_is_enum_format_integer(format)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(integer/non-integer format mismatch)",
+                     function);
+         return false;
+      }
+   }
 
+   if (!_mesa_texstore(ctx,
+                       1, /* dims */
+                       texImage->_BaseFormat,
+                       texImage->TexFormat,
+                       0, /* dstRowStride */
+                       &clearValue,
+                       1, 1, 1, /* srcWidth/Height/Depth */
+                       format, type,
+                       data ? data : zeroData,
+                       &ctx->DefaultPacking)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function);
+      return false;
+   }
 
-/*
- * Return compressed texture block size, in pixels.
- */
-static void
-get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
-{
-   gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
-   _mesa_get_format_block_size(mesaFormat, bw, bh);
+   return true;
 }
 
-
-/**
- * Error checking for glCompressedTexImage[123]D().
- * \param reason  returns reason for error, if any
- * \return error code or GL_NO_ERROR.
- */
-static GLenum
-compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
-                               GLenum target, GLint level,
-                               GLenum internalFormat, GLsizei width,
-                               GLsizei height, GLsizei depth, GLint border,
-                               GLsizei imageSize, char **reason)
+static struct gl_texture_object *
+get_tex_obj_for_clear(struct gl_context *ctx,
+                      const char *function,
+                      GLuint texture)
 {
-   const GLenum proxyTarget = get_proxy_target(target);
-   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
-   GLint expectedSize;
-   GLenum choose_format;
-   GLenum choose_type;
-   GLenum proxy_format;
-
-   *reason = ""; /* no error */
+   struct gl_texture_object *texObj;
 
-   if (!target_can_be_compressed(ctx, target, internalFormat)) {
-      *reason = "target";
-      return GL_INVALID_ENUM;
+   if (texture == 0) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
+      return NULL;
    }
 
-   /* This will detect any invalid internalFormat value */
-   if (!_mesa_is_compressed_format(ctx, internalFormat)) {
-      *reason = "internalFormat";
-      return GL_INVALID_ENUM;
-   }
+   texObj = _mesa_lookup_texture(ctx, texture);
 
-   switch (internalFormat) {
-#if FEATURE_ES
-   case GL_PALETTE4_RGB8_OES:
-   case GL_PALETTE4_RGBA8_OES:
-   case GL_PALETTE4_R5_G6_B5_OES:
-   case GL_PALETTE4_RGBA4_OES:
-   case GL_PALETTE4_RGB5_A1_OES:
-   case GL_PALETTE8_RGB8_OES:
-   case GL_PALETTE8_RGBA8_OES:
-   case GL_PALETTE8_R5_G6_B5_OES:
-   case GL_PALETTE8_RGBA4_OES:
-   case GL_PALETTE8_RGB5_A1_OES:
-      _mesa_cpal_compressed_format_type(internalFormat, &choose_format,
-                                       &choose_type);
-      proxy_format = choose_format;
+   if (texObj == NULL) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
+      return NULL;
+   }
 
-      /* check level */
-      if (level > 0 || level < -maxLevels) {
-        *reason = "level";
-        return GL_INVALID_VALUE;
-      }
+   if (texObj->Target == 0) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
+      return NULL;
+   }
 
-      if (dimensions != 2) {
-        *reason = "compressed paletted textures must be 2D";
-        return GL_INVALID_OPERATION;
-      }
+   return texObj;
+}
 
-      /* Figure out the expected texture size (in bytes).  This will be
-       * checked against the actual size later.
-       */
-      expectedSize = _mesa_cpal_compressed_size(level, internalFormat,
-                                               width, height);
+static int
+get_tex_images_for_clear(struct gl_context *ctx,
+                         const char *function,
+                         struct gl_texture_object *texObj,
+                         GLint level,
+                         struct gl_texture_image **texImages)
+{
+   GLenum target;
+   int i;
 
-      /* This is for the benefit of the TestProxyTexImage below.  It expects
-       * level to be non-negative.  OES_compressed_paletted_texture uses a
-       * weird mechanism where the level specified to glCompressedTexImage2D
-       * is -(n-1) number of levels in the texture, and the data specifies the
-       * complete mipmap stack.  This is done to ensure the palette is the
-       * same for all levels.
-       */
-      level = -level;
-      break;
-#endif
+   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
+      return 0;
+   }
 
-   default:
-      choose_format = GL_NONE;
-      choose_type = GL_NONE;
-      proxy_format = internalFormat;
+   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+      for (i = 0; i < MAX_FACES; i++) {
+         target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
 
-      /* check level */
-      if (level < 0 || level >= maxLevels) {
-        *reason = "level";
-        return GL_INVALID_VALUE;
+         texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level);
+         if (texImages[i] == NULL) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(invalid level)", function);
+            return 0;
+         }
       }
 
-      /* Figure out the expected texture size (in bytes).  This will be
-       * checked against the actual size later.
-       */
-      expectedSize = compressed_tex_size(width, height, depth, internalFormat);
-      break;
+      return MAX_FACES;
    }
 
-   /* This should really never fail */
-   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
-      *reason = "internalFormat";
-      return GL_INVALID_ENUM;
-   }
+   texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level);
 
-   /* No compressed formats support borders at this time */
-   if (border != 0) {
-      *reason = "border != 0";
-      return GL_INVALID_VALUE;
+   if (texImages[0] == NULL) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
+      return 0;
    }
 
-   /* For cube map, width must equal height */
-   if (_mesa_is_cube_face(target) && width != height) {
-      *reason = "width != height";
-      return GL_INVALID_VALUE;
+   return 1;
+}
+
+void GLAPIENTRY
+_mesa_ClearTexSubImage( GLuint texture, GLint level,
+                        GLint xoffset, GLint yoffset, GLint zoffset,
+                        GLsizei width, GLsizei height, GLsizei depth,
+                        GLenum format, GLenum type, const void *data )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImages[MAX_FACES];
+   GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
+   int i, numImages;
+   int minDepth, maxDepth;
+
+   texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture);
+
+   if (texObj == NULL)
+      return;
+
+   _mesa_lock_texture(ctx, texObj);
+
+   numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage",
+                                        texObj, level, texImages);
+   if (numImages == 0)
+      goto out;
+
+   if (numImages == 1) {
+      minDepth = -(int) texImages[0]->Border;
+      maxDepth = texImages[0]->Depth;
+   } else {
+      minDepth = 0;
+      maxDepth = numImages;
+   }
+
+   if (xoffset < -(GLint) texImages[0]->Border ||
+       yoffset < -(GLint) texImages[0]->Border ||
+       zoffset < minDepth ||
+       width < 0 ||
+       height < 0 ||
+       depth < 0 ||
+       xoffset + width > texImages[0]->Width ||
+       yoffset + height > texImages[0]->Height ||
+       zoffset + depth > maxDepth) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glClearSubTexImage(invalid dimensions)");
+      goto out;
    }
 
-   /* check image size against compression block size */
-   {
-      gl_format texFormat =
-         ctx->Driver.ChooseTextureFormat(ctx, proxy_format,
-                                        choose_format, choose_type);
-      GLuint bw, bh;
-
-      _mesa_get_format_block_size(texFormat, &bw, &bh);
-      if ((width > bw && width % bw > 0) ||
-          (height > bh && height % bh > 0)) {
-         /*
-          * Per GL_ARB_texture_compression:  GL_INVALID_OPERATION is
-          * generated [...] if any parameter combinations are not
-          * supported by the specific compressed internal format. 
-          */
-         *reason = "invalid width or height for compression format";
-         return GL_INVALID_OPERATION;
+   if (numImages == 1) {
+      if (check_clear_tex_image(ctx, "glClearTexSubImage",
+                                texImages[0],
+                                format, type, data, clearValue[0])) {
+         ctx->Driver.ClearTexSubImage(ctx,
+                                      texImages[0],
+                                      xoffset, yoffset, zoffset,
+                                      width, height, depth,
+                                      data ? clearValue[0] : NULL);
+      }
+   } else {
+      for (i = zoffset; i < zoffset + depth; i++) {
+         if (!check_clear_tex_image(ctx, "glClearTexSubImage",
+                                    texImages[i],
+                                    format, type, data, clearValue[i]))
+            goto out;
+      }
+      for (i = zoffset; i < zoffset + depth; i++) {
+         ctx->Driver.ClearTexSubImage(ctx,
+                                      texImages[i],
+                                      xoffset, yoffset, 0,
+                                      width, height, 1,
+                                      data ? clearValue[i] : NULL);
       }
    }
 
-   /* check image sizes */
-   if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
-                                     proxy_format, choose_format,
-                                     choose_type,
-                                     width, height, depth, border)) {
-      /* See error comment above */
-      *reason = "invalid width, height or format";
-      return GL_INVALID_OPERATION;
-   }
+ out:
+   _mesa_unlock_texture(ctx, texObj);
+}
 
-   /* check image size in bytes */
-   if (expectedSize != imageSize) {
-      /* Per GL_ARB_texture_compression:  GL_INVALID_VALUE is generated [...]
-       * if <imageSize> is not consistent with the format, dimensions, and
-       * contents of the specified image.
-       */
-      *reason = "imageSize inconsistant with width/height/format";
-      return GL_INVALID_VALUE;
+void GLAPIENTRY
+_mesa_ClearTexImage( GLuint texture, GLint level,
+                     GLenum format, GLenum type, const void *data )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImages[MAX_FACES];
+   GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
+   int i, numImages;
+
+   texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture);
+
+   if (texObj == NULL)
+      return;
+
+   _mesa_lock_texture(ctx, texObj);
+
+   numImages = get_tex_images_for_clear(ctx, "glClearTexImage",
+                                        texObj, level, texImages);
+
+   for (i = 0; i < numImages; i++) {
+      if (!check_clear_tex_image(ctx, "glClearTexImage",
+                                 texImages[i],
+                                 format, type, data,
+                                 clearValue[i]))
+         goto out;
    }
 
-   if (!mutable_tex_object(ctx, target)) {
-      *reason = "immutable texture";
-      return GL_INVALID_OPERATION;
+   for (i = 0; i < numImages; i++) {
+      ctx->Driver.ClearTexSubImage(ctx, texImages[i],
+                                   -(GLint) texImages[i]->Border, /* xoffset */
+                                   -(GLint) texImages[i]->Border, /* yoffset */
+                                   -(GLint) texImages[i]->Border, /* zoffset */
+                                   texImages[i]->Width,
+                                   texImages[i]->Height,
+                                   texImages[i]->Depth,
+                                   data ? clearValue[i] : NULL);
    }
 
-   return GL_NO_ERROR;
+out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
+
+
+/**********************************************************************/
+/******                   Compressed Textures                    ******/
+/**********************************************************************/
+
+
 /**
  * Error checking for glCompressedTexSubImage[123]D().
- * \warning  There are some bad assumptions here about the size of compressed
- *           texture tiles (multiple of 4) used to test the validity of the
- *           offset and size parameters.
  * \return error code or GL_NO_ERROR.
  */
 static GLenum
-compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions,
+compressed_subtexture_error_check(struct gl_context *ctx, GLint dims,
                                   GLenum target, GLint level,
                                   GLint xoffset, GLint yoffset, GLint zoffset,
                                   GLsizei width, GLsizei height, GLsizei depth,
                                   GLenum format, GLsizei imageSize)
 {
-   GLint expectedSize, maxLevels = 0, maxTextureSize;
-   GLuint bw, bh;
-   (void) zoffset;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GLint expectedSize;
+   GLboolean targetOK;
 
-   if (dimensions == 1) {
-      /* 1D compressed textures not allowed */
-      return GL_INVALID_ENUM;
-   }
-   else if (dimensions == 2) {
-      if (target == GL_PROXY_TEXTURE_2D) {
-         maxLevels = ctx->Const.MaxTextureLevels;
-      }
-      else if (target == GL_TEXTURE_2D) {
-         maxLevels = ctx->Const.MaxTextureLevels;
-      }
-      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
-         if (!ctx->Extensions.ARB_texture_cube_map)
-            return GL_INVALID_ENUM; /*target*/
-         maxLevels = ctx->Const.MaxCubeTextureLevels;
-      }
-      else if (_mesa_is_cube_face(target)) {
-         if (!ctx->Extensions.ARB_texture_cube_map)
-            return GL_INVALID_ENUM; /*target*/
-         maxLevels = ctx->Const.MaxCubeTextureLevels;
-      }
-      else {
-         return GL_INVALID_ENUM; /*target*/
+   switch (dims) {
+   case 2:
+      switch (target) {
+      case GL_TEXTURE_2D:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+         targetOK = GL_TRUE;
+         break;
+      default:
+         targetOK = GL_FALSE;
+         break;
       }
-   }
-   else if (dimensions == 3) {
-      /* 3D compressed textures not allowed */
-      return GL_INVALID_ENUM;
+      break;
+   case 3:
+      targetOK = (target == GL_TEXTURE_2D_ARRAY);
+      break;
+   default:
+      assert(dims == 1);
+      /* no 1D compressed textures at this time */
+      targetOK = GL_FALSE;
+      break;
    }
 
-   maxTextureSize = 1 << (maxLevels - 1);
+   if (!targetOK) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexSubImage%uD(target)",
+                  dims);
+      return GL_TRUE;
+   }
 
    /* this will catch any invalid compressed format token */
-   if (!_mesa_is_compressed_format(ctx, format))
-      return GL_INVALID_ENUM;
-
-   if (width < 1 || width > maxTextureSize)
-      return GL_INVALID_VALUE;
-
-   if ((height < 1 || height > maxTextureSize)
-       && dimensions > 1)
-      return GL_INVALID_VALUE;
-
-   if (level < 0 || level >= maxLevels)
-      return GL_INVALID_VALUE;
-
-   /*
-    * do checks which depend on compression block size
-    */
-   get_compressed_block_size(format, &bw, &bh);
+   if (!_mesa_is_compressed_format(ctx, format)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(format)",
+                  dims);
+      return GL_TRUE;
+   }
 
-   if ((xoffset % bw != 0) || (yoffset % bh != 0))
-      return GL_INVALID_VALUE;
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(level=%d)",
+                  dims, level);
+      return GL_TRUE;
+   }
 
-   if ((width % bw != 0) && width != 2 && width != 1)
-      return GL_INVALID_VALUE;
+   /* Check for invalid pixel storage modes */
+   if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dims,
+                                                           &ctx->Unpack,
+                                                           "glCompressedTexSubImage")) {
+      return GL_FALSE;
+   }
 
-   if ((height % bh != 0) && height != 2 && height != 1)
-      return GL_INVALID_VALUE;
 
    expectedSize = compressed_tex_size(width, height, depth, format);
-   if (expectedSize != imageSize)
-      return GL_INVALID_VALUE;
-
-   return GL_NO_ERROR;
-}
+   if (expectedSize != imageSize) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(size=%d)",
+                  dims, imageSize);
+      return GL_TRUE;
+   }
 
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   if (!texObj) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY,
+                  "glCompressedTexSubImage%uD()", dims);
+      return GL_TRUE;
+   }
 
-/**
- * Do second part of glCompressedTexSubImage error checking.
- * \return GL_TRUE if error found, GL_FALSE otherwise.
- */
-static GLboolean
-compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims,
-                                   GLsizei width, GLsizei height,
-                                   GLsizei depth, GLenum format,
-                                   struct gl_texture_image *texImage)
-{
+   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+   if (!texImage) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glCompressedTexSubImage%uD(invalid texture image)", dims);
+      return GL_TRUE;
+   }
 
    if ((GLint) format != texImage->InternalFormat) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -3317,301 +4313,91 @@ compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims,
       return GL_TRUE;
    }
 
-   if (((width == 1 || width == 2) &&
-        width != (GLsizei) texImage->Width) ||
-       (width > (GLsizei) texImage->Width)) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "glCompressedTexSubImage%uD(width=%d)", dims, width);
+   if (error_check_subtexture_dimensions(ctx, "glCompressedTexSubImage", dims,
+                                         texImage, xoffset, yoffset, zoffset,
+                                         width, height, depth)) {
       return GL_TRUE;
    }
 
-   if (dims >= 2) {
-      if (((height == 1 || height == 2) &&
-           height != (GLsizei) texImage->Height) ||
-          (height > (GLsizei) texImage->Height)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCompressedTexSubImage%uD(height=%d)", dims, height);
-         return GL_TRUE;
-      }
-   }
+   return GL_FALSE;
+}
 
-   if (dims >= 3) {
-      if (((depth == 1 || depth == 2) &&
-           depth != (GLsizei) texImage->Depth) ||
-          (depth > (GLsizei) texImage->Depth)) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glCompressedTexSubImage%uD(depth=%d)", dims, depth);
-         return GL_TRUE;
-      }
-   }
 
-   return GL_FALSE;
+void GLAPIENTRY
+_mesa_CompressedTexImage1D(GLenum target, GLint level,
+                              GLenum internalFormat, GLsizei width,
+                              GLint border, GLsizei imageSize,
+                              const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage(ctx, GL_TRUE, 1, target, level, internalFormat,
+            width, 1, 1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTexImage2D(GLenum target, GLint level,
+                              GLenum internalFormat, GLsizei width,
+                              GLsizei height, GLint border, GLsizei imageSize,
+                              const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage(ctx, GL_TRUE, 2, target, level, internalFormat,
+            width, height, 1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTexImage3D(GLenum target, GLint level,
+                              GLenum internalFormat, GLsizei width,
+                              GLsizei height, GLsizei depth, GLint border,
+                              GLsizei imageSize, const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage(ctx, GL_TRUE, 3, target, level, internalFormat,
+            width, height, depth, border, GL_NONE, GL_NONE, imageSize, data);
 }
 
 
 /**
- * Implementation of the glCompressedTexImage1/2/3D() functions.
+ * Common helper for glCompressedTexSubImage1/2/3D().
  */
 static void
-compressedteximage(struct gl_context *ctx, GLuint dims,
-                   GLenum target, GLint level,
-                   GLenum internalFormat, GLsizei width,
-                   GLsizei height, GLsizei depth, GLint border,
-                   GLsizei imageSize, const GLvoid *data)
+compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
+                         GLint xoffset, GLint yoffset, GLint zoffset,
+                         GLsizei width, GLsizei height, GLsizei depth,
+                         GLenum format, GLsizei imageSize, const GLvoid *data)
 {
-   GLenum error;
-   char *reason = "";
-
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx,
-                  "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n",
-                  dims,
-                  _mesa_lookup_enum_by_nr(target), level,
-                  _mesa_lookup_enum_by_nr(internalFormat),
-                  width, height, depth, border, imageSize, data);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GET_CURRENT_CONTEXT(ctx);
+   FLUSH_VERTICES(ctx, 0);
 
-   /* check target */
-   if (!legal_teximage_target(ctx, dims, target)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)",
-                  dims, _mesa_lookup_enum_by_nr(target));
+   if (compressed_subtexture_error_check(ctx, dims, target, level,
+                                         xoffset, yoffset, zoffset,
+                                         width, height, depth,
+                                         format, imageSize)) {
       return;
    }
 
-   error = compressed_texture_error_check(ctx, dims, target, level,
-                                          internalFormat, width, height, depth,
-                                          border, imageSize, &reason);
-
-#if FEATURE_ES
-   /* XXX this is kind of a hack */
-   if (!error && dims == 2) {
-      switch (internalFormat) {
-      case GL_PALETTE4_RGB8_OES:
-      case GL_PALETTE4_RGBA8_OES:
-      case GL_PALETTE4_R5_G6_B5_OES:
-      case GL_PALETTE4_RGBA4_OES:
-      case GL_PALETTE4_RGB5_A1_OES:
-      case GL_PALETTE8_RGB8_OES:
-      case GL_PALETTE8_RGBA8_OES:
-      case GL_PALETTE8_R5_G6_B5_OES:
-      case GL_PALETTE8_RGBA4_OES:
-      case GL_PALETTE8_RGB5_A1_OES:
-         _mesa_cpal_compressed_teximage2d(target, level, internalFormat,
-                                          width, height, imageSize, data);
-         return;
-      }
-   }
-#endif
-
-   if (_mesa_is_proxy_texture(target)) {
-      /* Proxy texture: just check for errors and update proxy state */
-      struct gl_texture_image *texImage;
-
-      if (!error) {
-         struct gl_texture_object *texObj =
-            _mesa_get_current_tex_object(ctx, target);
-         gl_format texFormat =
-            _mesa_choose_texture_format(ctx, texObj, target, level,
-                                        internalFormat, GL_NONE, GL_NONE);
-         if (!legal_texture_size(ctx, texFormat, width, height, depth)) {
-            error = GL_OUT_OF_MEMORY;
-         }
-      }
-
-      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
-      if (texImage) {
-         if (error) {
-            /* if error, clear all proxy texture image parameters */
-            clear_teximage_fields(texImage);
-         }
-         else {
-            /* no error: store the teximage parameters */
-            _mesa_init_teximage_fields(ctx, texImage, width, height,
-                                       depth, border, internalFormat,
-                                       MESA_FORMAT_NONE);
-         }
-      }
-   }
-   else {
-      /* non-proxy target */
-      struct gl_texture_object *texObj;
-      struct gl_texture_image *texImage;
-
-      if (error) {
-         _mesa_error(ctx, error, "glCompressedTexImage%uD(%s)", dims, reason);
-         return;
-      }
-
-      texObj = _mesa_get_current_tex_object(ctx, target);
-
-      _mesa_lock_texture(ctx, texObj);
-      {
-        texImage = _mesa_get_tex_image(ctx, texObj, target, level);
-        if (!texImage) {
-           _mesa_error(ctx, GL_OUT_OF_MEMORY,
-                        "glCompressedTexImage%uD", dims);
-        }
-         else {
-            gl_format texFormat;
-
-            ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
-
-            texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
-                                                    internalFormat, GL_NONE,
-                                                    GL_NONE);
-
-            if (legal_texture_size(ctx, texFormat, width, height, depth)) {
-               _mesa_init_teximage_fields(ctx, texImage,
-                                          width, height, depth,
-                                          border, internalFormat, texFormat);
-
-               switch (dims) {
-               case 1:
-                  ASSERT(ctx->Driver.CompressedTexImage1D);
-                  ctx->Driver.CompressedTexImage1D(ctx, texImage,
-                                                   internalFormat,
-                                                   width,
-                                                   border, imageSize, data);
-                  break;
-               case 2:
-                  ASSERT(ctx->Driver.CompressedTexImage2D);
-                  ctx->Driver.CompressedTexImage2D(ctx, texImage,
-                                                   internalFormat,
-                                                   width, height,
-                                                   border, imageSize, data);
-                  break;
-               case 3:
-                  ASSERT(ctx->Driver.CompressedTexImage3D);
-                  ctx->Driver.CompressedTexImage3D(ctx, texImage,
-                                                   internalFormat,
-                                                   width, height, depth,
-                                                   border, imageSize, data);
-                  break;
-               default:
-                  _mesa_problem(ctx, "bad dims in compressedteximage");
-               }
-
-               check_gen_mipmap(ctx, target, texObj, level);
-
-               /* state update */
-               texObj->_Complete = GL_FALSE;
-               ctx->NewState |= _NEW_TEXTURE;
-            }
-            else {
-               _mesa_error(ctx, GL_OUT_OF_MEMORY,
-                           "glCompressedTexImage%uD", dims);
-            }
-         }
-      }
-      _mesa_unlock_texture(ctx, texObj);
-   }
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
-                              GLenum internalFormat, GLsizei width,
-                              GLint border, GLsizei imageSize,
-                              const GLvoid *data)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   compressedteximage(ctx, 1, target, level, internalFormat,
-                      width, 1, 1, border, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
-                              GLenum internalFormat, GLsizei width,
-                              GLsizei height, GLint border, GLsizei imageSize,
-                              const GLvoid *data)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   compressedteximage(ctx, 2, target, level, internalFormat,
-                      width, height, 1, border, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage3DARB(GLenum target, GLint level,
-                              GLenum internalFormat, GLsizei width,
-                              GLsizei height, GLsizei depth, GLint border,
-                              GLsizei imageSize, const GLvoid *data)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   compressedteximage(ctx, 3, target, level, internalFormat,
-                      width, height, depth, border, imageSize, data);
-}
-
-
-/**
- * Common helper for glCompressedTexSubImage1/2/3D().
- */
-static void
-compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
-                         GLint xoffset, GLint yoffset, GLint zoffset,
-                         GLsizei width, GLsizei height, GLsizei depth,
-                         GLenum format, GLsizei imageSize, const GLvoid *data)
-{
-   struct gl_texture_object *texObj;
-   struct gl_texture_image *texImage;
-   GLenum error;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
-   error = compressed_subtexture_error_check(ctx, dims, target, level,
-                                             xoffset, 0, 0, /* pos */
-                                             width, height, depth,   /* size */
-                                             format, imageSize);
-   if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims);
-      return;
-   }
-
-   texObj = _mesa_get_current_tex_object(ctx, target);
+   texObj = _mesa_get_current_tex_object(ctx, target);
 
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
       assert(texImage);
 
-      if (compressed_subtexture_error_check2(ctx, dims, width, height, depth,
-                                             format, texImage)) {
-         /* error was recorded */
-      }
-      else if (width > 0 && height > 0 && depth > 0) {
-         switch (dims) {
-         case 1:
-            if (ctx->Driver.CompressedTexSubImage1D) {
-               ctx->Driver.CompressedTexSubImage1D(ctx, texImage,
-                                                   xoffset, width,
-                                                   format, imageSize, data);
-            }
-            break;
-         case 2:
-            if (ctx->Driver.CompressedTexSubImage2D) {
-               ctx->Driver.CompressedTexSubImage2D(ctx, texImage,
-                                                   xoffset, yoffset,
-                                                   width, height,
-                                                   format, imageSize, data);
-            }
-            break;
-         case 3:
-            if (ctx->Driver.CompressedTexSubImage3D) {
-               ctx->Driver.CompressedTexSubImage3D(ctx, texImage,
-                                                   xoffset, yoffset, zoffset,
-                                                   width, height, depth,
-                                                   format, imageSize, data);
-            }
-            break;
-         default:
-            ;
-         }
+      if (width > 0 && height > 0 && depth > 0) {
+         ctx->Driver.CompressedTexSubImage(ctx, dims, texImage,
+                                           xoffset, yoffset, zoffset,
+                                           width, height, depth,
+                                           format, imageSize, data);
 
          check_gen_mipmap(ctx, target, texObj, level);
 
-         ctx->NewState |= _NEW_TEXTURE;
+         /* NOTE: Don't signal _NEW_TEXTURE since we've only changed
+          * the texel data, not the texture format, size, etc.
+          */
       }
    }
    _mesa_unlock_texture(ctx, texObj);
@@ -3619,7 +4405,7 @@ compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
 
 
 void GLAPIENTRY
-_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset,
                                  GLsizei width, GLenum format,
                                  GLsizei imageSize, const GLvoid *data)
 {
@@ -3629,7 +4415,7 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
 
 
 void GLAPIENTRY
-_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
                                  GLint yoffset, GLsizei width, GLsizei height,
                                  GLenum format, GLsizei imageSize,
                                  const GLvoid *data)
@@ -3640,7 +4426,7 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
 
 
 void GLAPIENTRY
-_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset,
                                  GLint yoffset, GLint zoffset, GLsizei width,
                                  GLsizei height, GLsizei depth, GLenum format,
                                  GLsizei imageSize, const GLvoid *data)
@@ -3649,228 +4435,253 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
                             width, height, depth, format, imageSize, data);
 }
 
-
-/**
- * Helper for glTexBuffer().  Check if internalFormat is legal.  If so,
- * return the basic data type and number of components for the format.
- * \param return  GL_TRUE if internalFormat is legal, GL_FALSE otherwise
- */
-static GLboolean
-get_sized_format_info(const struct gl_context *ctx, GLenum internalFormat,
-                      GLenum *datatype, GLuint *components)
+static mesa_format
+get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
 {
+   if (ctx->API != API_OPENGL_CORE) {
+      switch (internalFormat) {
+      case GL_ALPHA8:
+         return MESA_FORMAT_A_UNORM8;
+      case GL_ALPHA16:
+         return MESA_FORMAT_A_UNORM16;
+      case GL_ALPHA16F_ARB:
+         return MESA_FORMAT_A_FLOAT16;
+      case GL_ALPHA32F_ARB:
+         return MESA_FORMAT_A_FLOAT32;
+      case GL_ALPHA8I_EXT:
+         return MESA_FORMAT_A_SINT8;
+      case GL_ALPHA16I_EXT:
+         return MESA_FORMAT_A_SINT16;
+      case GL_ALPHA32I_EXT:
+         return MESA_FORMAT_A_SINT32;
+      case GL_ALPHA8UI_EXT:
+         return MESA_FORMAT_A_UINT8;
+      case GL_ALPHA16UI_EXT:
+         return MESA_FORMAT_A_UINT16;
+      case GL_ALPHA32UI_EXT:
+         return MESA_FORMAT_A_UINT32;
+      case GL_LUMINANCE8:
+         return MESA_FORMAT_L_UNORM8;
+      case GL_LUMINANCE16:
+         return MESA_FORMAT_L_UNORM16;
+      case GL_LUMINANCE16F_ARB:
+         return MESA_FORMAT_L_FLOAT16;
+      case GL_LUMINANCE32F_ARB:
+         return MESA_FORMAT_L_FLOAT32;
+      case GL_LUMINANCE8I_EXT:
+         return MESA_FORMAT_L_SINT8;
+      case GL_LUMINANCE16I_EXT:
+         return MESA_FORMAT_L_SINT16;
+      case GL_LUMINANCE32I_EXT:
+         return MESA_FORMAT_L_SINT32;
+      case GL_LUMINANCE8UI_EXT:
+         return MESA_FORMAT_L_UINT8;
+      case GL_LUMINANCE16UI_EXT:
+         return MESA_FORMAT_L_UINT16;
+      case GL_LUMINANCE32UI_EXT:
+         return MESA_FORMAT_L_UINT32;
+      case GL_LUMINANCE8_ALPHA8:
+         return MESA_FORMAT_L8A8_UNORM;
+      case GL_LUMINANCE16_ALPHA16:
+         return MESA_FORMAT_L16A16_UNORM;
+      case GL_LUMINANCE_ALPHA16F_ARB:
+         return MESA_FORMAT_LA_FLOAT16;
+      case GL_LUMINANCE_ALPHA32F_ARB:
+         return MESA_FORMAT_LA_FLOAT32;
+      case GL_LUMINANCE_ALPHA8I_EXT:
+         return MESA_FORMAT_LA_SINT8;
+      case GL_LUMINANCE_ALPHA16I_EXT:
+         return MESA_FORMAT_LA_SINT8;
+      case GL_LUMINANCE_ALPHA32I_EXT:
+         return MESA_FORMAT_LA_SINT16;
+      case GL_LUMINANCE_ALPHA8UI_EXT:
+         return MESA_FORMAT_LA_UINT8;
+      case GL_LUMINANCE_ALPHA16UI_EXT:
+         return MESA_FORMAT_LA_UINT16;
+      case GL_LUMINANCE_ALPHA32UI_EXT:
+         return MESA_FORMAT_LA_UINT32;
+      case GL_INTENSITY8:
+         return MESA_FORMAT_I_UNORM8;
+      case GL_INTENSITY16:
+         return MESA_FORMAT_I_UNORM16;
+      case GL_INTENSITY16F_ARB:
+         return MESA_FORMAT_I_FLOAT16;
+      case GL_INTENSITY32F_ARB:
+         return MESA_FORMAT_I_FLOAT32;
+      case GL_INTENSITY8I_EXT:
+         return MESA_FORMAT_I_SINT8;
+      case GL_INTENSITY16I_EXT:
+         return MESA_FORMAT_I_SINT16;
+      case GL_INTENSITY32I_EXT:
+         return MESA_FORMAT_I_SINT32;
+      case GL_INTENSITY8UI_EXT:
+         return MESA_FORMAT_I_UINT8;
+      case GL_INTENSITY16UI_EXT:
+         return MESA_FORMAT_I_UINT16;
+      case GL_INTENSITY32UI_EXT:
+         return MESA_FORMAT_I_UINT32;
+      default:
+         break;
+      }
+   }
+
+   if (ctx->API == API_OPENGL_CORE &&
+       ctx->Extensions.ARB_texture_buffer_object_rgb32) {
+      switch (internalFormat) {
+      case GL_RGB32F:
+         return MESA_FORMAT_RGB_FLOAT32;
+      case GL_RGB32UI:
+         return MESA_FORMAT_RGB_UINT32;
+      case GL_RGB32I:
+         return MESA_FORMAT_RGB_SINT32;
+      default:
+         break;
+      }
+   }
+
    switch (internalFormat) {
-   case GL_ALPHA8:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_ALPHA16:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_ALPHA16F_ARB:
-      *datatype = GL_HALF_FLOAT;
-      *components = 1;
-      break;
-   case GL_ALPHA32F_ARB:
-      *datatype = GL_FLOAT;
-      *components = 1;
-      break;
-   case GL_ALPHA8I_EXT:
-      *datatype = GL_BYTE;
-      *components = 1;
-      break;
-   case GL_ALPHA16I_EXT:
-      *datatype = GL_SHORT;
-      *components = 1;
-      break;
-   case GL_ALPHA32I_EXT:
-      *datatype = GL_INT;
-      *components = 1;
-      break;
-   case GL_ALPHA8UI_EXT:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_ALPHA16UI_EXT:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_ALPHA32UI_EXT:
-      *datatype = GL_UNSIGNED_INT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE8:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_LUMINANCE16:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE16F_ARB:
-      *datatype = GL_HALF_FLOAT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE32F_ARB:
-      *datatype = GL_FLOAT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE8I_EXT:
-      *datatype = GL_BYTE;
-      *components = 1;
-      break;
-   case GL_LUMINANCE16I_EXT:
-      *datatype = GL_SHORT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE32I_EXT:
-      *datatype = GL_INT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE8UI_EXT:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_LUMINANCE16UI_EXT:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE32UI_EXT:
-      *datatype = GL_UNSIGNED_INT;
-      *components = 1;
-      break;
-   case GL_LUMINANCE8_ALPHA8:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 2;
-      break;
-   case GL_LUMINANCE16_ALPHA16:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA16F_ARB:
-      *datatype = GL_HALF_FLOAT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA32F_ARB:
-      *datatype = GL_FLOAT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA8I_EXT:
-      *datatype = GL_BYTE;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA16I_EXT:
-      *datatype = GL_SHORT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA32I_EXT:
-      *datatype = GL_INT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA8UI_EXT:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA16UI_EXT:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 2;
-      break;
-   case GL_LUMINANCE_ALPHA32UI_EXT:
-      *datatype = GL_UNSIGNED_INT;
-      *components = 2;
-      break;
-   case GL_INTENSITY8:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_INTENSITY16:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_INTENSITY16F_ARB:
-      *datatype = GL_HALF_FLOAT;
-      *components = 1;
-      break;
-   case GL_INTENSITY32F_ARB:
-      *datatype = GL_FLOAT;
-      *components = 1;
-      break;
-   case GL_INTENSITY8I_EXT:
-      *datatype = GL_BYTE;
-      *components = 1;
-      break;
-   case GL_INTENSITY16I_EXT:
-      *datatype = GL_SHORT;
-      *components = 1;
-      break;
-   case GL_INTENSITY32I_EXT:
-      *datatype = GL_INT;
-      *components = 1;
-      break;
-   case GL_INTENSITY8UI_EXT:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 1;
-      break;
-   case GL_INTENSITY16UI_EXT:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 1;
-      break;
-   case GL_INTENSITY32UI_EXT:
-      *datatype = GL_UNSIGNED_INT;
-      *components = 1;
-      break;
    case GL_RGBA8:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 4;
-      break;
+      return MESA_FORMAT_R8G8B8A8_UNORM;
    case GL_RGBA16:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_UNORM16;
    case GL_RGBA16F_ARB:
-      *datatype = GL_HALF_FLOAT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_FLOAT16;
    case GL_RGBA32F_ARB:
-      *datatype = GL_FLOAT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_FLOAT32;
    case GL_RGBA8I_EXT:
-      *datatype = GL_BYTE;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_SINT8;
    case GL_RGBA16I_EXT:
-      *datatype = GL_SHORT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_SINT16;
    case GL_RGBA32I_EXT:
-      *datatype = GL_INT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_SINT32;
    case GL_RGBA8UI_EXT:
-      *datatype = GL_UNSIGNED_BYTE;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_UINT8;
    case GL_RGBA16UI_EXT:
-      *datatype = GL_UNSIGNED_SHORT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_UINT16;
    case GL_RGBA32UI_EXT:
-      *datatype = GL_UNSIGNED_INT;
-      *components = 4;
-      break;
+      return MESA_FORMAT_RGBA_UINT32;
+
+   case GL_RG8:
+      return MESA_FORMAT_R8G8_UNORM;
+   case GL_RG16:
+      return MESA_FORMAT_R16G16_UNORM;
+   case GL_RG16F:
+      return MESA_FORMAT_RG_FLOAT16;
+   case GL_RG32F:
+      return MESA_FORMAT_RG_FLOAT32;
+   case GL_RG8I:
+      return MESA_FORMAT_RG_SINT8;
+   case GL_RG16I:
+      return MESA_FORMAT_RG_SINT16;
+   case GL_RG32I:
+      return MESA_FORMAT_RG_SINT32;
+   case GL_RG8UI:
+      return MESA_FORMAT_RG_UINT8;
+   case GL_RG16UI:
+      return MESA_FORMAT_RG_UINT16;
+   case GL_RG32UI:
+      return MESA_FORMAT_RG_UINT32;
+
+   case GL_R8:
+      return MESA_FORMAT_R_UNORM8;
+   case GL_R16:
+      return MESA_FORMAT_R_UNORM16;
+   case GL_R16F:
+      return MESA_FORMAT_R_FLOAT16;
+   case GL_R32F:
+      return MESA_FORMAT_R_FLOAT32;
+   case GL_R8I:
+      return MESA_FORMAT_R_SINT8;
+   case GL_R16I:
+      return MESA_FORMAT_R_SINT16;
+   case GL_R32I:
+      return MESA_FORMAT_R_SINT32;
+   case GL_R8UI:
+      return MESA_FORMAT_R_UINT8;
+   case GL_R16UI:
+      return MESA_FORMAT_R_UINT16;
+   case GL_R32UI:
+      return MESA_FORMAT_R_UINT32;
+
    default:
-      return GL_FALSE;
+      return MESA_FORMAT_NONE;
    }
+}
 
-   if (*datatype == GL_FLOAT && !ctx->Extensions.ARB_texture_float)
-      return GL_FALSE;
 
-   if (*datatype == GL_HALF_FLOAT && !ctx->Extensions.ARB_half_float_pixel)
-      return GL_FALSE;
+mesa_format
+_mesa_validate_texbuffer_format(const struct gl_context *ctx,
+                                GLenum internalFormat)
+{
+   mesa_format format = get_texbuffer_format(ctx, internalFormat);
+   GLenum datatype;
+
+   if (format == MESA_FORMAT_NONE)
+      return MESA_FORMAT_NONE;
+
+   datatype = _mesa_get_format_datatype(format);
+
+   /* The GL_ARB_texture_buffer_object spec says:
+    *
+    *     "If ARB_texture_float is not supported, references to the
+    *     floating-point internal formats provided by that extension should be
+    *     removed, and such formats may not be passed to TexBufferARB."
+    *
+    * As a result, GL_HALF_FLOAT internal format depends on both
+    * GL_ARB_texture_float and GL_ARB_half_float_pixel.
+    */
+   if ((datatype == GL_FLOAT || datatype == GL_HALF_FLOAT) &&
+       !ctx->Extensions.ARB_texture_float)
+      return MESA_FORMAT_NONE;
 
-   return GL_TRUE;
+   if (!ctx->Extensions.ARB_texture_rg) {
+      GLenum base_format = _mesa_get_format_base_format(format);
+      if (base_format == GL_R || base_format == GL_RG)
+         return MESA_FORMAT_NONE;
+   }
+
+   if (!ctx->Extensions.ARB_texture_buffer_object_rgb32) {
+      GLenum base_format = _mesa_get_format_base_format(format);
+      if (base_format == GL_RGB)
+         return MESA_FORMAT_NONE;
+   }
+   return format;
+}
+
+
+static void
+texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat,
+               struct gl_buffer_object *bufObj,
+               GLintptr offset, GLsizeiptr size)
+{
+   struct gl_texture_object *texObj;
+   mesa_format format;
+
+   FLUSH_VERTICES(ctx, 0);
+
+   if (target != GL_TEXTURE_BUFFER_ARB) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(target)");
+      return;
+   }
+
+   format = _mesa_validate_texbuffer_format(ctx, internalFormat);
+   if (format == MESA_FORMAT_NONE) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(internalFormat 0x%x)",
+                  internalFormat);
+      return;
+   }
+
+   texObj = _mesa_get_current_tex_object(ctx, target);
+
+   _mesa_lock_texture(ctx, texObj);
+   {
+      _mesa_reference_buffer_object(ctx, &texObj->BufferObject, bufObj);
+      texObj->BufferObjectFormat = internalFormat;
+      texObj->_BufferObjectFormat = format;
+      texObj->BufferOffset = offset;
+      texObj->BufferSize = size;
+   }
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -3878,42 +4689,285 @@ get_sized_format_info(const struct gl_context *ctx, GLenum internalFormat,
 void GLAPIENTRY
 _mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
 {
-   struct gl_texture_object *texObj;
    struct gl_buffer_object *bufObj;
-   GLenum dataType;
-   GLuint comps;
 
    GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (!ctx->Extensions.ARB_texture_buffer_object) {
+   /* NOTE: ARB_texture_buffer_object has interactions with
+    * the compatibility profile that are not implemented.
+    */
+   if (!(ctx->API == API_OPENGL_CORE &&
+         ctx->Extensions.ARB_texture_buffer_object)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer");
       return;
    }
 
-   if (target != GL_TEXTURE_BUFFER_ARB) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(target)");
+   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+   if (!bufObj && buffer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer);
       return;
    }
 
-   if (!get_sized_format_info(ctx, internalFormat, &dataType, &comps)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(internalFormat 0x%x)",
-                  internalFormat);
+   texbufferrange(ctx, target, internalFormat, bufObj, 0, buffer ? -1 : 0);
+}
+
+
+/** GL_ARB_texture_buffer_range */
+void GLAPIENTRY
+_mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer,
+                     GLintptr offset, GLsizeiptr size)
+{
+   struct gl_buffer_object *bufObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!(ctx->API == API_OPENGL_CORE &&
+         ctx->Extensions.ARB_texture_buffer_range)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange");
       return;
    }
 
    bufObj = _mesa_lookup_bufferobj(ctx, buffer);
-   if (buffer && !bufObj) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer);
+   if (bufObj) {
+      if (offset < 0 ||
+          size <= 0 ||
+          (offset + size) > bufObj->Size) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glTexBufferRange");
+         return;
+      }
+      if (offset % ctx->Const.TextureBufferOffsetAlignment) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glTexBufferRange(invalid offset alignment)");
+         return;
+      }
+   } else if (buffer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange(buffer %u)",
+                  buffer);
+      return;
+   } else {
+      offset = 0;
+      size = 0;
+   }
+
+   texbufferrange(ctx, target, internalFormat, bufObj, offset, size);
+}
+
+
+static GLboolean
+is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat)
+{
+   /* Everything that is allowed for renderbuffers,
+    * except for a base format of GL_STENCIL_INDEX.
+    */
+   GLenum baseFormat = _mesa_base_fbo_format(ctx, internalformat);
+   return baseFormat != 0 && baseFormat != GL_STENCIL_INDEX;
+}
+
+
+/** GL_ARB_texture_multisample */
+static GLboolean
+check_multisample_target(GLuint dims, GLenum target)
+{
+   switch(target) {
+   case GL_TEXTURE_2D_MULTISAMPLE:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+      return dims == 2;
+
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      return dims == 3;
+
+   default:
+      return GL_FALSE;
+   }
+}
+
+
+static void
+teximagemultisample(GLuint dims, GLenum target, GLsizei samples,
+                    GLint internalformat, GLsizei width, GLsizei height,
+                    GLsizei depth, GLboolean fixedsamplelocations,
+                    GLboolean immutable, const char *func)
+{
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+   GLboolean sizeOK, dimensionsOK, samplesOK;
+   mesa_format texFormat;
+   GLenum sample_count_error;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!(ctx->Extensions.ARB_texture_multisample
+      && _mesa_is_desktop_gl(ctx))) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
+      return;
+   }
+
+   if (!check_multisample_target(dims, target)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
+      return;
+   }
+
+   /* check that the specified internalformat is color/depth/stencil-renderable;
+    * refer GL3.1 spec 4.4.4
+    */
+
+   if (immutable && !_mesa_is_legal_tex_storage_format(ctx, internalformat)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+            "%s(internalformat=%s not legal for immutable-format)",
+            func, _mesa_lookup_enum_by_nr(internalformat));
+      return;
+   }
+
+   if (!is_renderable_texture_format(ctx, internalformat)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+            "%s(internalformat=%s)",
+            func, _mesa_lookup_enum_by_nr(internalformat));
+      return;
+   }
+
+   sample_count_error = _mesa_check_sample_count(ctx, target,
+         internalformat, samples);
+   samplesOK = sample_count_error == GL_NO_ERROR;
+
+   /* Page 254 of OpenGL 4.4 spec says:
+    *   "Proxy arrays for two-dimensional multisample and two-dimensional
+    *    multisample array textures are operated on in the same way when
+    *    TexImage2DMultisample is called with target specified as
+    *    PROXY_TEXTURE_2D_MULTISAMPLE, or TexImage3DMultisample is called
+    *    with target specified as PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY.
+    *    However, if samples is not supported, then no error is generated.
+    */
+   if (!samplesOK && !_mesa_is_proxy_texture(target)) {
+      _mesa_error(ctx, sample_count_error, "%s(samples)", func);
       return;
    }
 
    texObj = _mesa_get_current_tex_object(ctx, target);
 
-   _mesa_lock_texture(ctx, texObj);
-   {
-      _mesa_reference_buffer_object(ctx, &texObj->BufferObject, bufObj);
-      texObj->BufferObjectFormat = internalFormat;
+   if (immutable && (!texObj || (texObj->Name == 0))) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+            "%s(texture object 0)",
+            func);
+      return;
    }
-   _mesa_unlock_texture(ctx, texObj);
+
+   texImage = _mesa_get_tex_image(ctx, texObj, 0, 0);
+
+   if (texImage == NULL) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", func);
+      return;
+   }
+
+   texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
+         internalformat, GL_NONE, GL_NONE);
+   assert(texFormat != MESA_FORMAT_NONE);
+
+   dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
+         width, height, depth, 0);
+
+   sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
+         width, height, depth, 0);
+
+   if (_mesa_is_proxy_texture(target)) {
+      if (samplesOK && dimensionsOK && sizeOK) {
+         init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
+                                 internalformat, texFormat,
+                                 samples, fixedsamplelocations);
+      }
+      else {
+         /* clear all image fields */
+         clear_teximage_fields(texImage);
+      }
+   }
+   else {
+      if (!dimensionsOK) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+               "%s(invalid width or height)", func);
+         return;
+      }
+
+      if (!sizeOK) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY,
+               "%s(texture too large)", func);
+         return;
+      }
+
+      /* Check if texObj->Immutable is set */
+      if (texObj->Immutable) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
+         return;
+      }
+
+      ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
+
+      init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
+                              internalformat, texFormat,
+                              samples, fixedsamplelocations);
+
+      if (width > 0 && height > 0 && depth > 0) {
+         if (!ctx->Driver.AllocTextureStorage(ctx, texObj, 1,
+                  width, height, depth)) {
+            /* tidy up the texture image state. strictly speaking,
+             * we're allowed to just leave this in whatever state we
+             * like, but being tidy is good.
+             */
+            _mesa_init_teximage_fields(ctx, texImage,
+                  0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE);
+         }
+      }
+
+      texObj->Immutable = immutable;
+
+      if (immutable) {
+         _mesa_set_texture_view_state(ctx, texObj, target, 1);
+      }
+
+      _mesa_update_fbo_texture(ctx, texObj, 0, 0);
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage2DMultisample(GLenum target, GLsizei samples,
+                            GLenum internalformat, GLsizei width,
+                            GLsizei height, GLboolean fixedsamplelocations)
+{
+   teximagemultisample(2, target, samples, internalformat,
+                       width, height, 1, fixedsamplelocations, GL_FALSE,
+                       "glTexImage2DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage3DMultisample(GLenum target, GLsizei samples,
+                            GLenum internalformat, GLsizei width,
+                            GLsizei height, GLsizei depth,
+                            GLboolean fixedsamplelocations)
+{
+   teximagemultisample(3, target, samples, internalformat,
+                       width, height, depth, fixedsamplelocations, GL_FALSE,
+                       "glTexImage3DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
+                              GLenum internalformat, GLsizei width,
+                              GLsizei height, GLboolean fixedsamplelocations)
+{
+   teximagemultisample(2, target, samples, internalformat,
+                       width, height, 1, fixedsamplelocations, GL_TRUE,
+                       "glTexStorage2DMultisample");
+}
+
+void GLAPIENTRY
+_mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
+                              GLenum internalformat, GLsizei width,
+                              GLsizei height, GLsizei depth,
+                              GLboolean fixedsamplelocations)
+{
+   teximagemultisample(3, target, samples, internalformat,
+                       width, height, depth, fixedsamplelocations, GL_TRUE,
+                       "glTexStorage3DMultisample");
 }