mesa: fix invalid target error handling for teximage
[mesa.git] / src / mesa / main / teximage.c
index fed1dad2621094372e0be40885018059b0b481a7..b80d5a9b675f98375113653daf3d192b0f3b9830 100644 (file)
@@ -122,11 +122,61 @@ adjust_for_oes_float_texture(const struct gl_context *ctx,
    return format;
 }
 
    return format;
 }
 
+/**
+ * Returns a corresponding base format for a given internal floating point
+ * format as specifed by OES_texture_float.
+ */
+static GLenum
+oes_float_internal_format(const struct gl_context *ctx,
+                          GLenum format, GLenum type)
+{
+   switch (type) {
+   case GL_FLOAT:
+      if (ctx->Extensions.OES_texture_float) {
+         switch (format) {
+         case GL_RGBA32F:
+            return GL_RGBA;
+         case GL_RGB32F:
+            return GL_RGB;
+         case GL_ALPHA32F_ARB:
+            return GL_ALPHA;
+         case GL_LUMINANCE32F_ARB:
+            return GL_LUMINANCE;
+         case GL_LUMINANCE_ALPHA32F_ARB:
+            return GL_LUMINANCE_ALPHA;
+         default:
+            break;
+         }
+      }
+      break;
+
+   case GL_HALF_FLOAT_OES:
+      if (ctx->Extensions.OES_texture_half_float) {
+         switch (format) {
+         case GL_RGBA16F:
+            return GL_RGBA;
+         case GL_RGB16F:
+            return GL_RGB;
+         case GL_ALPHA16F_ARB:
+            return GL_ALPHA;
+         case GL_LUMINANCE16F_ARB:
+            return GL_LUMINANCE;
+         case GL_LUMINANCE_ALPHA16F_ARB:
+            return GL_LUMINANCE_ALPHA;
+         default:
+            break;
+         }
+      }
+      break;
+   }
+   return format;
+}
+
 
 /**
  * Install gl_texture_image in a gl_texture_object according to the target
  * and level parameters.
 
 /**
  * Install gl_texture_image in a gl_texture_object according to the target
  * and level parameters.
- * 
+ *
  * \param tObj texture object.
  * \param target texture target.
  * \param level image level.
  * \param tObj texture object.
  * \param target texture target.
  * \param level image level.
@@ -373,23 +423,15 @@ get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
 
    switch (target) {
    case GL_PROXY_TEXTURE_1D:
 
    switch (target) {
    case GL_PROXY_TEXTURE_1D:
-      if (level >= ctx->Const.MaxTextureLevels)
-         return NULL;
       texIndex = TEXTURE_1D_INDEX;
       break;
    case GL_PROXY_TEXTURE_2D:
       texIndex = TEXTURE_1D_INDEX;
       break;
    case GL_PROXY_TEXTURE_2D:
-      if (level >= ctx->Const.MaxTextureLevels)
-         return NULL;
       texIndex = TEXTURE_2D_INDEX;
       break;
    case GL_PROXY_TEXTURE_3D:
       texIndex = TEXTURE_2D_INDEX;
       break;
    case GL_PROXY_TEXTURE_3D:
-      if (level >= ctx->Const.Max3DTextureLevels)
-         return NULL;
       texIndex = TEXTURE_3D_INDEX;
       break;
    case GL_PROXY_TEXTURE_CUBE_MAP:
       texIndex = TEXTURE_3D_INDEX;
       break;
    case GL_PROXY_TEXTURE_CUBE_MAP:
-      if (level >= ctx->Const.MaxCubeTextureLevels)
-         return NULL;
       texIndex = TEXTURE_CUBE_INDEX;
       break;
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
       texIndex = TEXTURE_CUBE_INDEX;
       break;
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
@@ -398,28 +440,18 @@ get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
       texIndex = TEXTURE_RECT_INDEX;
       break;
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
       texIndex = TEXTURE_RECT_INDEX;
       break;
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
-      if (level >= ctx->Const.MaxTextureLevels)
-         return NULL;
       texIndex = TEXTURE_1D_ARRAY_INDEX;
       break;
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       texIndex = TEXTURE_1D_ARRAY_INDEX;
       break;
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
-      if (level >= ctx->Const.MaxTextureLevels)
-         return NULL;
       texIndex = TEXTURE_2D_ARRAY_INDEX;
       break;
    case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
       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:
       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:
       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:
       texIndex = TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX;
       break;
    default:
@@ -453,14 +485,14 @@ get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
  * \sa gl_constants.
  */
 GLint
  * \sa gl_constants.
  */
 GLint
-_mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
+_mesa_max_texture_levels(const struct gl_context *ctx, GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
 {
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
-      return ctx->Const.MaxTextureLevels;
+      return ffs(util_next_power_of_two(ctx->Const.MaxTextureSize));
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
       return ctx->Const.Max3DTextureLevels;
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
       return ctx->Const.Max3DTextureLevels;
@@ -482,7 +514,7 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
    case GL_TEXTURE_2D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return ctx->Extensions.EXT_texture_array
    case GL_TEXTURE_2D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return ctx->Extensions.EXT_texture_array
-         ? ctx->Const.MaxTextureLevels : 0;
+         ? ffs(util_next_power_of_two(ctx->Const.MaxTextureSize)) : 0;
    case GL_TEXTURE_CUBE_MAP_ARRAY:
    case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
       return _mesa_has_texture_cube_map_array(ctx)
    case GL_TEXTURE_CUBE_MAP_ARRAY:
    case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
       return _mesa_has_texture_cube_map_array(ctx)
@@ -498,7 +530,7 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
          && ctx->Extensions.ARB_texture_multisample
          ? 1 : 0;
    case GL_TEXTURE_EXTERNAL_OES:
          && ctx->Extensions.ARB_texture_multisample
          ? 1 : 0;
    case GL_TEXTURE_EXTERNAL_OES:
-      /* fall-through */
+      return _mesa_has_OES_EGL_image_external(ctx) ? 1 : 0;
    default:
       return 0; /* bad target */
    }
    default:
       return 0; /* bad target */
    }
@@ -787,14 +819,15 @@ clear_teximage_fields(struct gl_texture_image *img)
  * Fills in the fields of \p img with the given information.
  * Note: width, height and depth include the border.
  */
  * Fills in the fields of \p img with the given information.
  * Note: width, height and depth include the border.
  */
-static void
-init_teximage_fields_ms(struct gl_context *ctx,
+void
+_mesa_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)
 {
                         struct gl_texture_image *img,
                         GLsizei width, GLsizei height, GLsizei depth,
                         GLint border, GLenum internalFormat,
                         mesa_format format,
                         GLuint numSamples, GLboolean fixedSampleLocations)
 {
+   const GLint base_format =_mesa_base_tex_format(ctx, internalFormat);
    GLenum target;
    assert(img);
    assert(width >= 0);
    GLenum target;
    assert(img);
    assert(width >= 0);
@@ -802,8 +835,8 @@ init_teximage_fields_ms(struct gl_context *ctx,
    assert(depth >= 0);
 
    target = img->TexObject->Target;
    assert(depth >= 0);
 
    target = img->TexObject->Target;
-   img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
-   assert(img->_BaseFormat != -1);
+   assert(base_format != -1);
+   img->_BaseFormat = (GLenum16)base_format;
    img->InternalFormat = internalFormat;
    img->Border = border;
    img->Width = width;
    img->InternalFormat = internalFormat;
    img->Border = border;
    img->Width = width;
@@ -813,9 +846,6 @@ init_teximage_fields_ms(struct gl_context *ctx,
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
    img->WidthLog2 = _mesa_logbase2(img->Width2);
 
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
    img->WidthLog2 = _mesa_logbase2(img->Width2);
 
-   img->NumSamples = 0;
-   img->FixedSampleLocations = GL_TRUE;
-
    switch(target) {
    case GL_TEXTURE_1D:
    case GL_TEXTURE_BUFFER:
    switch(target) {
    case GL_TEXTURE_1D:
    case GL_TEXTURE_BUFFER:
@@ -903,8 +933,8 @@ _mesa_init_teximage_fields(struct gl_context *ctx,
                            GLint border, GLenum internalFormat,
                            mesa_format format)
 {
                            GLint border, GLenum internalFormat,
                            mesa_format format)
 {
-   init_teximage_fields_ms(ctx, img, width, height, depth, border,
-                           internalFormat, format, 0, GL_TRUE);
+   _mesa_init_teximage_fields_ms(ctx, img, width, height, depth, border,
+                                 internalFormat, format, 0, GL_TRUE);
 }
 
 
 }
 
 
@@ -943,8 +973,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_PROXY_TEXTURE_1D:
-      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); /* level zero size */
-      maxSize >>= level;  /* level size */
+      maxSize = ctx->Const.MaxTextureSize >> level;
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (!ctx->Extensions.ARB_texture_non_power_of_two) {
@@ -957,8 +986,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
    case GL_PROXY_TEXTURE_2D:
    case GL_TEXTURE_2D_MULTISAMPLE:
    case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
    case GL_PROXY_TEXTURE_2D:
    case GL_TEXTURE_2D_MULTISAMPLE:
    case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
-      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      maxSize >>= level;
+      maxSize = ctx->Const.MaxTextureSize >> level;
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 2 * border || height > 2 * border + maxSize)
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 2 * border || height > 2 * border + maxSize)
@@ -1028,8 +1056,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
 
    case GL_TEXTURE_1D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
 
    case GL_TEXTURE_1D_ARRAY_EXT:
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
-      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      maxSize >>= level;
+      maxSize = ctx->Const.MaxTextureSize >> level;
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 0 || height > ctx->Const.MaxArrayTextureLayers)
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 0 || height > ctx->Const.MaxArrayTextureLayers)
@@ -1044,8 +1071,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
    case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
    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);
-      maxSize >>= level;
+      maxSize = ctx->Const.MaxTextureSize >> level;
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 2 * border || height > 2 * border + maxSize)
       if (width < 2 * border || width > 2 * border + maxSize)
          return GL_FALSE;
       if (height < 2 * border || height > 2 * border + maxSize)
@@ -1136,7 +1162,8 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims,
    }
 
    if (xoffset + subWidth > (GLint) destImage->Width) {
    }
 
    if (xoffset + subWidth > (GLint) destImage->Width) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset+width)", func);
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset %d + width %d > %u)", func,
+                  xoffset, subWidth, destImage->Width);
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -1148,7 +1175,8 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims,
          return GL_TRUE;
       }
       if (yoffset + subHeight > (GLint) destImage->Height) {
          return GL_TRUE;
       }
       if (yoffset + subHeight > (GLint) destImage->Height) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset+height)", func);
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset %d + height %d > %u)",
+                     func, yoffset, subHeight, destImage->Height);
          return GL_TRUE;
       }
    }
          return GL_TRUE;
       }
    }
@@ -1169,7 +1197,8 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims,
       if (target == GL_TEXTURE_CUBE_MAP)
          depth = 6;
       if (zoffset + subDepth  > depth) {
       if (target == GL_TEXTURE_CUBE_MAP)
          depth = 6;
       if (zoffset + subDepth  > depth) {
-         _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset+depth)", func);
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset %d + depth %d > %u)",
+                     func, zoffset, subDepth, depth);
          return GL_TRUE;
       }
    }
          return GL_TRUE;
       }
    }
@@ -1248,7 +1277,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, GLuint dims,
  */
 GLboolean
 _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target,
  */
 GLboolean
 _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target,
-                          GLuint numLevels, GLint level,
+                          GLuint numLevels, ASSERTED GLint level,
                           mesa_format format, GLuint numSamples,
                           GLint width, GLint height, GLint depth)
 {
                           mesa_format format, GLuint numSamples,
                           GLint width, GLint height, GLint depth)
 {
@@ -1302,7 +1331,7 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target,
  * Return true if the format is only valid for glCompressedTexImage.
  */
 static bool
  * Return true if the format is only valid for glCompressedTexImage.
  */
 static bool
-compressedteximage_only_format(const struct gl_context *ctx, GLenum format)
+compressedteximage_only_format(GLenum format)
 {
    switch (format) {
    case GL_PALETTE4_RGB8_OES:
 {
    switch (format) {
    case GL_PALETTE4_RGB8_OES:
@@ -1315,6 +1344,9 @@ compressedteximage_only_format(const struct gl_context *ctx, GLenum format)
    case GL_PALETTE8_R5_G6_B5_OES:
    case GL_PALETTE8_RGBA4_OES:
    case GL_PALETTE8_RGB5_A1_OES:
    case GL_PALETTE8_R5_G6_B5_OES:
    case GL_PALETTE8_RGBA4_OES:
    case GL_PALETTE8_RGB5_A1_OES:
+   case GL_ATC_RGB_AMD:
+   case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+   case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
       return true;
    default:
       return false;
       return true;
    default:
       return false;
@@ -1325,11 +1357,11 @@ compressedteximage_only_format(const struct gl_context *ctx, GLenum format)
  * Return true if the format doesn't support online compression.
  */
 bool
  * Return true if the format doesn't support online compression.
  */
 bool
-_mesa_format_no_online_compression(const struct gl_context *ctx, GLenum format)
+_mesa_format_no_online_compression(GLenum format)
 {
    return _mesa_is_astc_format(format) ||
           _mesa_is_etc2_format(format) ||
 {
    return _mesa_is_astc_format(format) ||
           _mesa_is_etc2_format(format) ||
-          compressedteximage_only_format(ctx, format);
+          compressedteximage_only_format(format);
 }
 
 /* Writes to an GL error pointer if non-null and returns whether or not the
 }
 
 /* Writes to an GL error pointer if non-null and returns whether or not the
@@ -1412,8 +1444,26 @@ _mesa_target_can_be_compressed(const struct gl_context *ctx, GLenum target,
        *
        * This should also be applicable for glTexStorage3D(). Other available
        * targets for these functions are: TEXTURE_3D and TEXTURE_CUBE_MAP_ARRAY.
        *
        * This should also be applicable for glTexStorage3D(). Other available
        * targets for these functions are: TEXTURE_3D and TEXTURE_CUBE_MAP_ARRAY.
+       *
+       * Section 8.7, page 179 of OpenGL ES 3.2 adds:
+       *
+       *      An INVALID_OPERATION error is generated by CompressedTexImage3D
+       *      if internalformat is one of the the formats in table 8.17 and target is
+       *      not TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY or TEXTURE_3D.
+       *
+       *      An INVALID_OPERATION error is generated by CompressedTexImage3D
+       *      if internalformat is TEXTURE_CUBE_MAP_ARRAY and the “Cube Map
+       *      Array” column of table 8.17 is not checked, or if internalformat
+       *      is TEXTURE_- 3D and the “3D Tex.” column of table 8.17 is not
+       *      checked.
+       *
+       * The instances of <internalformat> above should say <target>.
+       *
+       * Such table 8.17 has checked "Cube Map Array" column for all the
+       * cases. So in practice, TEXTURE_CUBE_MAP_ARRAY is now valid for OpenGL ES 3.2
        */
        */
-      if (layout == MESA_FORMAT_LAYOUT_ETC2 && _mesa_is_gles3(ctx))
+      if (layout == MESA_FORMAT_LAYOUT_ETC2 && _mesa_is_gles3(ctx) &&
+          !_mesa_is_gles32(ctx))
             return write_error(error, GL_INVALID_OPERATION);
       target_can_be_compresed = _mesa_has_texture_cube_map_array(ctx);
       break;
             return write_error(error, GL_INVALID_OPERATION);
       target_can_be_compresed = _mesa_has_texture_cube_map_array(ctx);
       break;
@@ -1578,15 +1628,25 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target,
 
 /**
  * Helper function to determine if a texture object is mutable (in terms
 
 /**
  * Helper function to determine if a texture object is mutable (in terms
- * of GL_ARB_texture_storage).
+ * of GL_ARB_texture_storage/GL_ARB_bindless_texture).
  */
 static GLboolean
  */
 static GLboolean
-mutable_tex_object(struct gl_context *ctx, GLenum target)
+mutable_tex_object(struct gl_texture_object *texObj)
 {
 {
-   struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target);
    if (!texObj)
       return GL_FALSE;
 
    if (!texObj)
       return GL_FALSE;
 
+   if (texObj->HandleAllocated) {
+      /* The ARB_bindless_texture spec says:
+       *
+       * "The error INVALID_OPERATION is generated by TexImage*, CopyTexImage*,
+       *  CompressedTexImage*, TexBuffer*, TexParameter*, as well as other
+       *  functions defined in terms of these, if the texture object to be
+       *  modified is referenced by one or more texture or image handles."
+       */
+      return GL_FALSE;
+   }
+
    return !texObj->Immutable;
 }
 
    return !texObj->Immutable;
 }
 
@@ -1708,7 +1768,6 @@ texture_formats_agree(GLenum internalFormat,
  * \param format pixel data format given by the user.
  * \param type pixel data type given by the user.
  * \param internalFormat internal format given by the user.
  * \param format pixel data format given by the user.
  * \param type pixel data type given by the user.
  * \param internalFormat internal format given by the user.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
  * \param callerName name of the caller function to print in the error message
  *
  * \return true if a error is found, false otherwise
  * \param callerName name of the caller function to print in the error message
  *
  * \return true if a error is found, false otherwise
@@ -1717,31 +1776,17 @@ texture_formats_agree(GLenum internalFormat,
  */
 static bool
 texture_format_error_check_gles(struct gl_context *ctx, GLenum format,
  */
 static bool
 texture_format_error_check_gles(struct gl_context *ctx, GLenum format,
-                                GLenum type, GLenum internalFormat,
-                                GLuint dimensions, const char *callerName)
+                                GLenum type, GLenum internalFormat, const char *callerName)
 {
 {
-   GLenum err;
-
-   if (_mesa_is_gles3(ctx)) {
-      err = _mesa_es3_error_check_format_and_type(ctx, format, type,
-                                                  internalFormat);
-      if (err != GL_NO_ERROR) {
-         _mesa_error(ctx, err,
-                     "%s(format = %s, type = %s, internalformat = %s)",
-                     callerName, _mesa_enum_to_string(format),
-                     _mesa_enum_to_string(type),
-                     _mesa_enum_to_string(internalFormat));
-         return true;
-      }
-   }
-   else {
-      err = _mesa_es_error_check_format_and_type(ctx, format, type, dimensions);
-      if (err != GL_NO_ERROR) {
-         _mesa_error(ctx, err, "%s(format = %s, type = %s)",
-                     callerName, _mesa_enum_to_string(format),
-                     _mesa_enum_to_string(type));
-         return true;
-      }
+   GLenum err = _mesa_gles_error_check_format_and_type(ctx, format, type,
+                                                       internalFormat);
+   if (err != GL_NO_ERROR) {
+      _mesa_error(ctx, err,
+                  "%s(format = %s, type = %s, internalformat = %s)",
+                  callerName, _mesa_enum_to_string(format),
+                  _mesa_enum_to_string(type),
+                  _mesa_enum_to_string(internalFormat));
+      return true;
    }
 
    return false;
    }
 
    return false;
@@ -1775,6 +1820,7 @@ texture_format_error_check_gles(struct gl_context *ctx, GLenum format,
 static GLboolean
 texture_error_check( struct gl_context *ctx,
                      GLuint dimensions, GLenum target,
 static GLboolean
 texture_error_check( struct gl_context *ctx,
                      GLuint dimensions, GLenum target,
+                     struct gl_texture_object* texObj,
                      GLint level, GLint internalFormat,
                      GLenum format, GLenum type,
                      GLint width, GLint height,
                      GLint level, GLint internalFormat,
                      GLenum format, GLenum type,
                      GLint width, GLint height,
@@ -1845,9 +1891,11 @@ texture_error_check( struct gl_context *ctx,
     * Formats and types that require additional extensions (e.g., GL_FLOAT
     * requires GL_OES_texture_float) are filtered elsewhere.
     */
     * Formats and types that require additional extensions (e.g., GL_FLOAT
     * requires GL_OES_texture_float) are filtered elsewhere.
     */
+   char bufCallerName[20];
+   _mesa_snprintf(bufCallerName, 20, "glTexImage%dD", dimensions);
    if (_mesa_is_gles(ctx) &&
    if (_mesa_is_gles(ctx) &&
-       texture_format_error_check_gles(ctx, format, type, internalFormat,
-                                       dimensions, "glTexImage%dD")) {
+       texture_format_error_check_gles(ctx, format, type,
+                                       internalFormat, bufCallerName)) {
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -1913,7 +1961,7 @@ texture_error_check( struct gl_context *ctx,
                      "glTexImage%dD(target can't be compressed)", dimensions);
          return GL_TRUE;
       }
                      "glTexImage%dD(target can't be compressed)", dimensions);
          return GL_TRUE;
       }
-      if (_mesa_format_no_online_compression(ctx, internalFormat)) {
+      if (_mesa_format_no_online_compression(internalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTexImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
@@ -1935,7 +1983,7 @@ texture_error_check( struct gl_context *ctx,
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
-   if (!mutable_tex_object(ctx, target)) {
+   if (!mutable_tex_object(texObj)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glTexImage%dD(immutable texture)", dimensions);
       return GL_TRUE;
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glTexImage%dD(immutable texture)", dimensions);
       return GL_TRUE;
@@ -1954,8 +2002,8 @@ texture_error_check( struct gl_context *ctx,
  */
 static GLenum
 compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
  */
 static GLenum
 compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
-                               GLenum target, GLint level,
-                               GLenum internalFormat, GLsizei width,
+                               GLenum target, struct gl_texture_object* texObj,
+                               GLint level, GLenum internalFormat, GLsizei width,
                                GLsizei height, GLsizei depth, GLint border,
                                GLsizei imageSize, const GLvoid *data)
 {
                                GLsizei height, GLsizei depth, GLint border,
                                GLsizei imageSize, const GLvoid *data)
 {
@@ -2071,7 +2119,7 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
       goto error;
    }
 
       goto error;
    }
 
-   if (!mutable_tex_object(ctx, target)) {
+   if (!mutable_tex_object(texObj)) {
       reason = "immutable texture";
       error = GL_INVALID_OPERATION;
       goto error;
       reason = "immutable texture";
       error = GL_INVALID_OPERATION;
       goto error;
@@ -2117,7 +2165,7 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
                         GLint xoffset, GLint yoffset, GLint zoffset,
                         GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type, const GLvoid *pixels,
                         GLint xoffset, GLint yoffset, GLint zoffset,
                         GLint width, GLint height, GLint depth,
                         GLenum format, GLenum type, const GLvoid *pixels,
-                        bool dsa, const char *callerName)
+                        const char *callerName)
 {
    struct gl_texture_image *texImage;
    GLenum err;
 {
    struct gl_texture_image *texImage;
    GLenum err;
@@ -2143,8 +2191,8 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
       /* non-existant texture level */
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
       /* non-existant texture level */
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture image)",
-                  callerName);
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture level %d)",
+                  callerName, level);
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -2157,6 +2205,19 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
+   if (!texture_formats_agree(texImage->InternalFormat, format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(incompatible internalFormat = %s, format = %s)",
+                  callerName,
+                  _mesa_enum_to_string(texImage->InternalFormat),
+                  _mesa_enum_to_string(format));
+      return GL_TRUE;
+   }
+
+   GLenum internalFormat = _mesa_is_gles(ctx) ?
+      oes_float_internal_format(ctx, texImage->InternalFormat, type) :
+      texImage->InternalFormat;
+
    /* 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
    /* 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
@@ -2164,8 +2225,7 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
     */
    if (_mesa_is_gles(ctx) &&
        texture_format_error_check_gles(ctx, format, type,
     */
    if (_mesa_is_gles(ctx) &&
        texture_format_error_check_gles(ctx, format, type,
-                                       texImage->InternalFormat,
-                                       dimensions, callerName)) {
+                                       internalFormat, callerName)) {
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -2183,7 +2243,7 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
    }
 
    if (_mesa_is_format_compressed(texImage->TexFormat)) {
    }
 
    if (_mesa_is_format_compressed(texImage->TexFormat)) {
-      if (_mesa_format_no_online_compression(ctx, texImage->InternalFormat)) {
+      if (_mesa_format_no_online_compression(texImage->InternalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "%s(no compression for format)", callerName);
          return GL_TRUE;
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "%s(no compression for format)", callerName);
          return GL_TRUE;
@@ -2224,8 +2284,8 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
  */
 static GLboolean
 copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
  */
 static GLboolean
 copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
-                         GLenum target, GLint level, GLint internalFormat,
-                         GLint width, GLint height, GLint border )
+                         GLenum target, struct gl_texture_object* texObj,
+                         GLint level, GLint internalFormat, GLint border )
 {
    GLint baseFormat;
    GLint rb_base_format;
 {
    GLint baseFormat;
    GLint rb_base_format;
@@ -2337,8 +2397,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
 
    if (_mesa_is_gles(ctx)) {
       bool valid = true;
 
    if (_mesa_is_gles(ctx)) {
       bool valid = true;
-      if (_mesa_base_format_component_count(baseFormat) >
-          _mesa_base_format_component_count(rb_base_format)) {
+      if (_mesa_components_in_format(baseFormat) >
+          _mesa_components_in_format(rb_base_format)) {
          valid = false;
       }
       if (baseFormat == GL_DEPTH_COMPONENT ||
          valid = false;
       }
       if (baseFormat == GL_DEPTH_COMPONENT ||
@@ -2365,14 +2425,10 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
    }
 
    if (_mesa_is_gles3(ctx)) {
    }
 
    if (_mesa_is_gles3(ctx)) {
-      bool rb_is_srgb = false;
+      bool rb_is_srgb = (ctx->Extensions.EXT_sRGB &&
+                         _mesa_is_format_srgb(rb->Format));
       bool dst_is_srgb = false;
 
       bool dst_is_srgb = false;
 
-      if (ctx->Extensions.EXT_framebuffer_sRGB &&
-          _mesa_get_format_color_encoding(rb->Format) == GL_SRGB) {
-         rb_is_srgb = true;
-      }
-
       if (_mesa_get_linear_internalformat(internalFormat) != internalFormat) {
          dst_is_srgb = true;
       }
       if (_mesa_get_linear_internalformat(internalFormat) != internalFormat) {
          dst_is_srgb = true;
       }
@@ -2398,7 +2454,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
        * types for SNORM formats. Also, conversion to SNORM formats is not
        * allowed by Table 3.2 on Page 110.
        */
        * 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)) {
+      if (!_mesa_has_EXT_render_snorm(ctx) &&
+          _mesa_is_enum_format_snorm(internalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glCopyTexImage%dD(internalFormat=%s)", dimensions,
                      _mesa_enum_to_string(internalFormat));
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glCopyTexImage%dD(internalFormat=%s)", dimensions,
                      _mesa_enum_to_string(internalFormat));
@@ -2433,7 +2490,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
                     _mesa_is_enum_format_unsigned_int(internalFormat) !=
                       _mesa_is_enum_format_unsigned_int(rb_internal_format)) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
                     _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);
+                        "glCopyTexImage%dD(signed vs unsigned integer)",
+                        dimensions);
             return GL_TRUE;
          }
       }
             return GL_TRUE;
          }
       }
@@ -2459,7 +2517,7 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
                      "glCopyTexImage%dD(target can't be compressed)", dimensions);
          return GL_TRUE;
       }
                      "glCopyTexImage%dD(target can't be compressed)", dimensions);
          return GL_TRUE;
       }
-      if (_mesa_format_no_online_compression(ctx, internalFormat)) {
+      if (_mesa_format_no_online_compression(internalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "glCopyTexImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "glCopyTexImage%dD(no compression for format)", dimensions);
          return GL_TRUE;
@@ -2471,7 +2529,7 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
       }
    }
 
       }
    }
 
-   if (!mutable_tex_object(ctx, target)) {
+   if (!mutable_tex_object(texObj)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCopyTexImage%dD(immutable texture)", dimensions);
       return GL_TRUE;
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glCopyTexImage%dD(immutable texture)", dimensions);
       return GL_TRUE;
@@ -2493,6 +2551,8 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
                             GLint xoffset, GLint yoffset, GLint zoffset,
                             GLint width, GLint height, const char *caller)
 {
                             GLint xoffset, GLint yoffset, GLint zoffset,
                             GLint width, GLint height, const char *caller)
 {
+   assert(texObj);
+
    struct gl_texture_image *texImage;
 
    /* Check that the source buffer is complete */
    struct gl_texture_image *texImage;
 
    /* Check that the source buffer is complete */
@@ -2519,17 +2579,11 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
-   /* Get dest image pointers */
-   if (!texObj) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", caller);
-      return GL_TRUE;
-   }
-
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
       /* destination image does not exist */
       _mesa_error(ctx, GL_INVALID_OPERATION,
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
       /* destination image does not exist */
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(invalid texture image)", caller);
+                  "%s(invalid texture level %d)", caller, level);
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -2545,7 +2599,7 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
    }
 
    if (_mesa_is_format_compressed(texImage->TexFormat)) {
    }
 
    if (_mesa_is_format_compressed(texImage->TexFormat)) {
-      if (_mesa_format_no_online_compression(ctx, texImage->InternalFormat)) {
+      if (_mesa_format_no_online_compression(texImage->InternalFormat)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "%s(no compression for format)", caller);
          return GL_TRUE;
          _mesa_error(ctx, GL_INVALID_OPERATION,
                "%s(no compression for format)", caller);
          return GL_TRUE;
@@ -2557,6 +2611,20 @@ copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
+   /* From OpenGL ES 3.2 spec, section 8.6:
+    *
+    *     "An INVALID_OPERATION error is generated by CopyTexSubImage3D,
+    *      CopyTexImage2D, or CopyTexSubImage2D if the internalformat of the
+    *      texture image being (re)specified is RGB9_E5"
+    */
+   if (texImage->InternalFormat == GL_RGB9_E5 &&
+       !_mesa_is_desktop_gl(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "%s(invalid internal format %s)", caller,
+                  _mesa_enum_to_string(texImage->InternalFormat));
+      return GL_TRUE;
+   }
+
    if (!_mesa_source_buffer_exists(ctx, texImage->_BaseFormat)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "%s(missing readbuffer, format=%s)", caller,
    if (!_mesa_source_buffer_exists(ctx, texImage->_BaseFormat)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "%s(missing readbuffer, format=%s)", caller,
@@ -2610,7 +2678,7 @@ struct cb_info
  * Check render to texture callback.  Called from _mesa_HashWalk().
  */
 static void
  * Check render to texture callback.  Called from _mesa_HashWalk().
  */
 static void
-check_rtt_cb(GLuint key, void *data, void *userData)
+check_rtt_cb(UNUSED GLuint key, void *data, void *userData)
 {
    struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
    const struct cb_info *info = (struct cb_info *) userData;
 {
    struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
    const struct cb_info *info = (struct cb_info *) userData;
@@ -2687,7 +2755,8 @@ check_gen_mipmap(struct gl_context *ctx, GLenum target,
 
 /** Debug helper: override the user-requested internal format */
 static GLenum
 
 /** Debug helper: override the user-requested internal format */
 static GLenum
-override_internal_format(GLenum internalFormat, GLint width, GLint height)
+override_internal_format(GLenum internalFormat, UNUSED GLint width,
+                         UNUSED GLint height)
 {
 #if 0
    if (internalFormat == GL_RGBA16F_ARB ||
 {
 #if 0
    if (internalFormat == GL_RGBA16F_ARB ||
@@ -2748,7 +2817,7 @@ _mesa_choose_texture_format(struct gl_context *ctx,
    /* see if we've already chosen a format for the previous level */
    if (level > 0) {
       struct gl_texture_image *prevImage =
    /* see if we've already chosen a format for the previous level */
    if (level > 0) {
       struct gl_texture_image *prevImage =
-        _mesa_select_tex_image(texObj, target, level - 1);
+         _mesa_select_tex_image(texObj, target, level - 1);
       /* See if the prev level is defined and has an internal format which
        * matches the new internal format.
        */
       /* See if the prev level is defined and has an internal format which
        * matches the new internal format.
        */
@@ -2761,38 +2830,6 @@ _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_enum_to_string(before),
-                       _mesa_enum_to_string(internalFormat));
-      }
-   }
-
-   /* choose format from scratch */
    f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat,
                                        format, type);
    assert(f != MESA_FORMAT_NONE);
    f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat,
                                        format, type);
    assert(f != MESA_FORMAT_NONE);
@@ -2845,28 +2882,88 @@ strip_texture_border(GLenum target,
    }
 }
 
    }
 }
 
+static struct gl_texture_object *
+lookup_texture_ext_dsa(struct gl_context *ctx, GLenum target, GLuint texture,
+                       const char *caller)
+{
+   GLenum boundTarget;
+   switch (target) {
+   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:
+      boundTarget = GL_TEXTURE_CUBE_MAP;
+      break;
+   default:
+      boundTarget = target;
+      break;
+   }
+
+   int targetIndex = _mesa_tex_target_to_index(ctx, boundTarget);
+   if (targetIndex < 0) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target = %s)", caller,
+                  _mesa_enum_to_string(target));
+            return NULL;
+   }
+   assert(targetIndex < NUM_TEXTURE_TARGETS);
+
+   struct gl_texture_object *texObj;
+   if (texture == 0) {
+      /* Use a default texture object */
+      texObj = ctx->Shared->DefaultTex[targetIndex];
+      assert(texObj);
+   } else {
+      texObj = _mesa_lookup_texture(ctx, texture);
+      if (!texObj && ctx->API == API_OPENGL_CORE) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
+         return NULL;
+      }
+
+      if (!texObj) {
+         texObj = ctx->Driver.NewTextureObject(ctx, texture, boundTarget);
+         if (!texObj) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
+            return NULL;
+         }
+
+         /* insert into hash table */
+         _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
+      }
+
+      if (texObj->Target != boundTarget) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s != %s)",
+                     caller, _mesa_enum_to_string(texObj->Target),
+                     _mesa_enum_to_string(target));
+         return NULL;
+      }
+   }
+
+   return texObj;
+}
 
 /**
 
 /**
- * Common code to implement all the glTexImage1D/2D/3D functions
- * as well as glCompressedTexImage1D/2D/3D.
+ * Common code to implement all the glTexImage1D/2D/3D functions,
+ * glCompressedTexImage1D/2D/3D and glTextureImage1D/2D/3DEXT
  * \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.
  */
  * \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
+static ALWAYS_INLINE void
 teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
 teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
+         struct gl_texture_object *texObj,
          GLenum target, GLint level, GLint internalFormat,
          GLsizei width, GLsizei height, GLsizei depth,
          GLint border, GLenum format, GLenum type,
          GLenum target, GLint level, GLint internalFormat,
          GLsizei width, GLsizei height, GLsizei depth,
          GLint border, GLenum format, GLenum type,
-         GLsizei imageSize, const GLvoid *pixels)
+         GLsizei imageSize, const GLvoid *pixels, bool no_error)
 {
    const char *func = compressed ? "glCompressedTexImage" : "glTexImage";
    struct gl_pixelstore_attrib unpack_no_border;
    const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
 {
    const char *func = compressed ? "glCompressedTexImage" : "glTexImage";
    struct gl_pixelstore_attrib unpack_no_border;
    const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
-   struct gl_texture_object *texObj;
    mesa_format texFormat;
    mesa_format texFormat;
-   GLboolean dimensionsOK, sizeOK;
+   bool dimensionsOK = true, sizeOK = true;
 
    FLUSH_VERTICES(ctx, 0);
 
 
    FLUSH_VERTICES(ctx, 0);
 
@@ -2891,27 +2988,33 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
 
    internalFormat = override_internal_format(internalFormat, width, height);
 
 
    internalFormat = override_internal_format(internalFormat, width, height);
 
-   /* target error checking */
-   if (!legal_teximage_target(ctx, dims, target)) {
+   if (!no_error &&
+       /* target error checking */
+       !legal_teximage_target(ctx, dims, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "%s%uD(target=%s)",
                   func, dims, _mesa_enum_to_string(target));
       return;
    }
 
       _mesa_error(ctx, GL_INVALID_ENUM, "%s%uD(target=%s)",
                   func, dims, _mesa_enum_to_string(target));
       return;
    }
 
-   /* general error checking */
-   if (compressed) {
-      if (compressed_texture_error_check(ctx, dims, target, level,
-                                         internalFormat,
-                                         width, height, depth,
-                                         border, imageSize, pixels))
-         return;
-   }
-   else {
-      if (texture_error_check(ctx, dims, target, level, internalFormat,
-                              format, type, width, height, depth, border,
-                              pixels))
-         return;
+   if (!texObj)
+      texObj = _mesa_get_current_tex_object(ctx, target);
+
+   if (!no_error) {
+      /* general error checking */
+      if (compressed) {
+         if (compressed_texture_error_check(ctx, dims, target, texObj,
+                                            level, internalFormat,
+                                            width, height, depth,
+                                            border, imageSize, pixels))
+            return;
+      } else {
+         if (texture_error_check(ctx, dims, target, texObj, level, internalFormat,
+                                 format, type, width, height, depth, border,
+                                 pixels))
+            return;
+      }
    }
    }
+   assert(texObj);
 
    /* Here we convert a cpal compressed image into a regular glTexImage2D
     * call by decompressing the texture.  If we really want to support cpal
 
    /* Here we convert a cpal compressed image into a regular glTexImage2D
     * call by decompressing the texture.  If we really want to support cpal
@@ -2935,9 +3038,6 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
       }
    }
 
       }
    }
 
-   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
    if (compressed) {
       /* For glCompressedTexImage() the driver has no choice about the
        * texture format since we'll never transcode the user's compressed
@@ -2965,14 +3065,16 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
 
    assert(texFormat != MESA_FORMAT_NONE);
 
 
    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);
+   if (!no_error) {
+      /* 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),
-                                          0, level, texFormat, 1,
-                                          width, height, depth);
+      /* check that the texture won't take too much memory, etc */
+      sizeOK = ctx->Driver.TestProxyTexImage(ctx, proxy_target(target),
+                                             0, level, texFormat, 1,
+                                             width, height, depth);
+   }
 
    if (_mesa_is_proxy_texture(target)) {
       /* Proxy texture: just clear or set state depending on error checking */
 
    if (_mesa_is_proxy_texture(target)) {
       /* Proxy texture: just clear or set state depending on error checking */
@@ -2997,8 +3099,8 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
 
       if (!dimensionsOK) {
          _mesa_error(ctx, GL_INVALID_VALUE,
 
       if (!dimensionsOK) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "%s%uD(invalid width or height or depth)",
-                     func, dims);
+                     "%s%uD(invalid width=%d or height=%d or depth=%d)",
+                     func, dims, width, height, depth);
          return;
       }
 
          return;
       }
 
@@ -3015,22 +3117,22 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
        * rarely-tested software fallback rendering.
        */
       if (border && ctx->Const.StripTextureBorder) {
        * rarely-tested software fallback rendering.
        */
       if (border && ctx->Const.StripTextureBorder) {
-        strip_texture_border(target, &width, &height, &depth, unpack,
-                             &unpack_no_border);
+         strip_texture_border(target, &width, &height, &depth, unpack,
+                              &unpack_no_border);
          border = 0;
          border = 0;
-        unpack = &unpack_no_border;
+         unpack = &unpack_no_border;
       }
 
       if (ctx->NewState & _NEW_PIXEL)
       }
 
       if (ctx->NewState & _NEW_PIXEL)
-        _mesa_update_state(ctx);
+         _mesa_update_state(ctx);
 
       _mesa_lock_texture(ctx, texObj);
       {
 
       _mesa_lock_texture(ctx, texObj);
       {
-        texImage = _mesa_get_tex_image(ctx, texObj, target, level);
+         texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
 
-        if (!texImage) {
-           _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
-        }
+         if (!texImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
+         }
          else {
             ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
          else {
             ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
@@ -3062,6 +3164,32 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims,
 }
 
 
 }
 
 
+/* This is a wrapper around teximage() so that we can force the KHR_no_error
+ * logic to be inlined without inlining the function into all the callers.
+ */
+static void
+teximage_err(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,
+             GLsizei imageSize, const GLvoid *pixels)
+{
+   teximage(ctx, compressed, dims, NULL, target, level, internalFormat, width, height,
+            depth, border, format, type, imageSize, pixels, false);
+}
+
+
+static void
+teximage_no_error(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,
+                  GLsizei imageSize, const GLvoid *pixels)
+{
+   teximage(ctx, compressed, dims, NULL, target, level, internalFormat, width, height,
+            depth, border, format, type, imageSize, pixels, true);
+}
+
 
 /*
  * Called from the API.  Note that width includes the border.
 
 /*
  * Called from the API.  Note that width includes the border.
@@ -3072,10 +3200,43 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
                   GLenum type, const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                   GLenum type, const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, GL_FALSE, 1, target, level, internalFormat, width, 1, 1,
-            border, format, type, 0, pixels);
+   teximage_err(ctx, GL_FALSE, 1, target, level, internalFormat, width, 1, 1,
+                border, format, type, 0, pixels);
+}
+
+void GLAPIENTRY
+_mesa_TextureImage1DEXT(GLuint texture, GLenum target, GLint level,
+                      GLint internalFormat, GLsizei width, GLint border,
+                      GLenum format, GLenum type, const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glTextureImage1DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 1, texObj, target, level, internalFormat,
+            width, 1, 1, border, format, type, 0, pixels, false);
 }
 
 }
 
+void GLAPIENTRY
+_mesa_MultiTexImage1DEXT(GLenum texunit, GLenum target, GLint level,
+                         GLint internalFormat, GLsizei width, GLint border,
+                         GLenum format, GLenum type, const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glMultiTexImage1DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 1, texObj, target, level, internalFormat, width, 1, 1,
+                border, format, type, 0, pixels, false);
+}
 
 void GLAPIENTRY
 _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
 
 void GLAPIENTRY
 _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
@@ -3084,10 +3245,45 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, GL_FALSE, 2, target, level, internalFormat, width, height, 1,
-            border, format, type, 0, pixels);
+   teximage_err(ctx, GL_FALSE, 2, target, level, internalFormat, width, height, 1,
+                border, format, type, 0, pixels);
+}
+
+void GLAPIENTRY
+_mesa_TextureImage2DEXT(GLuint texture, GLenum target, GLint level,
+                      GLint internalFormat, GLsizei width, GLsizei height,
+                      GLint border,
+                      GLenum format, GLenum type, const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glTextureImage2DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 2, texObj, target, level, internalFormat,
+            width, height, 1, border, format, type, 0, pixels, false);
 }
 
 }
 
+void GLAPIENTRY
+_mesa_MultiTexImage2DEXT(GLenum texunit, GLenum target, GLint level,
+                         GLint internalFormat, GLsizei width, GLsizei height,
+                         GLint border,
+                         GLenum format, GLenum type, const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glMultiTexImage2DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 2, texObj, target, level, internalFormat, width, height, 1,
+                border, format, type, 0, pixels, false);
+}
 
 /*
  * Called by the API or display list executor.
 
 /*
  * Called by the API or display list executor.
@@ -3100,9 +3296,45 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                   const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   teximage(ctx, GL_FALSE, 3, target, level, internalFormat,
-            width, height, depth,
-            border, format, type, 0, pixels);
+   teximage_err(ctx, GL_FALSE, 3, target, level, internalFormat,
+                width, height, depth, border, format, type, 0, pixels);
+}
+
+void GLAPIENTRY
+_mesa_TextureImage3DEXT(GLuint texture, GLenum target, GLint level,
+                      GLint internalFormat, GLsizei width, GLsizei height,
+                      GLsizei depth, GLint border,
+                      GLenum format, GLenum type, const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glTextureImage3DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 3, texObj, target, level, internalFormat,
+            width, height, depth, border, format, type, 0, pixels, false);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiTexImage3DEXT(GLenum texunit, GLenum target, GLint level,
+                         GLint internalFormat, GLsizei width, GLsizei height,
+                         GLsizei depth, GLint border, GLenum format, GLenum type,
+                         const GLvoid *pixels )
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glMultiTexImage3DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_FALSE, 3, texObj, target, level, internalFormat,
+                width, height, depth, border, format, type, 0, pixels, false);
 }
 
 
 }
 
 
@@ -3117,6 +3349,40 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
 }
 
 
 }
 
 
+void GLAPIENTRY
+_mesa_TexImage1D_no_error(GLenum target, GLint level, GLint internalFormat,
+                          GLsizei width, GLint border, GLenum format,
+                          GLenum type, const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_FALSE, 1, target, level, internalFormat, width, 1,
+                     1, border, format, type, 0, pixels);
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage2D_no_error(GLenum target, GLint level, GLint internalFormat,
+                          GLsizei width, GLsizei height, GLint border,
+                          GLenum format, GLenum type, const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_FALSE, 2, target, level, internalFormat, width,
+                     height, 1, border, format, type, 0, pixels);
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage3D_no_error(GLenum target, GLint level, GLint internalFormat,
+                          GLsizei width, GLsizei height, GLsizei depth,
+                          GLint border, GLenum format, GLenum type,
+                          const GLvoid *pixels )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_FALSE, 3, target, level, internalFormat,
+                     width, height, depth, border, format, type, 0, pixels);
+}
+
+
 void GLAPIENTRY
 _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
 {
 void GLAPIENTRY
 _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
 {
@@ -3174,27 +3440,25 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
       ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
       ctx->Driver.EGLImageTargetTexture2D(ctx, target,
       ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
       ctx->Driver.EGLImageTargetTexture2D(ctx, target,
-                                         texObj, texImage, image);
+                                          texObj, texImage, image);
 
       _mesa_dirty_texobj(ctx, texObj);
    }
    _mesa_unlock_texture(ctx, texObj);
 }
 
 
       _mesa_dirty_texobj(ctx, texObj);
    }
    _mesa_unlock_texture(ctx, texObj);
 }
 
-
 /**
  * Helper that implements the glTexSubImage1/2/3D()
  * and glTextureSubImage1/2/3D() functions.
  */
 /**
  * Helper that implements the glTexSubImage1/2/3D()
  * and glTextureSubImage1/2/3D() functions.
  */
-void
-_mesa_texture_sub_image(struct gl_context *ctx, GLuint dims,
-                        struct gl_texture_object *texObj,
-                        struct gl_texture_image *texImage,
-                        GLenum target, GLint level,
-                        GLint xoffset, GLint yoffset, GLint zoffset,
-                        GLsizei width, GLsizei height, GLsizei depth,
-                        GLenum format, GLenum type, const GLvoid *pixels,
-                        bool dsa)
+static void
+texture_sub_image(struct gl_context *ctx, GLuint dims,
+                  struct gl_texture_object *texObj,
+                  struct gl_texture_image *texImage,
+                  GLenum target, GLint level,
+                  GLint xoffset, GLint yoffset, GLint zoffset,
+                  GLsizei width, GLsizei height, GLsizei depth,
+                  GLenum format, GLenum type, const GLvoid *pixels)
 {
    FLUSH_VERTICES(ctx, 0);
 
 {
    FLUSH_VERTICES(ctx, 0);
 
@@ -3238,12 +3502,12 @@ _mesa_texture_sub_image(struct gl_context *ctx, GLuint dims,
  * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
  */
 static void
  * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
  */
 static void
-texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
-            GLint xoffset, GLint yoffset, GLint zoffset,
-            GLsizei width, GLsizei height, GLsizei depth,
-            GLenum format, GLenum type, const GLvoid *pixels,
-            const char *callerName)
-{
+texsubimage_err(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
+                GLint xoffset, GLint yoffset, GLint zoffset,
+                GLsizei width, GLsizei height, GLsizei depth,
+                GLenum format, GLenum type, const GLvoid *pixels,
+                const char *callerName)
+{
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
 
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
 
@@ -3261,7 +3525,7 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    if (texsubimage_error_check(ctx, dims, texObj, target, level,
                                xoffset, yoffset, zoffset,
                                width, height, depth, format, type,
    if (texsubimage_error_check(ctx, dims, texObj, target, level,
                                xoffset, yoffset, zoffset,
                                width, height, depth, format, type,
-                               pixels, false, callerName)) {
+                               pixels, callerName)) {
       return;   /* error was detected */
    }
 
       return;   /* error was detected */
    }
 
@@ -3276,9 +3540,27 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
                   _mesa_enum_to_string(format),
                   _mesa_enum_to_string(type), pixels);
 
                   _mesa_enum_to_string(format),
                   _mesa_enum_to_string(type), pixels);
 
-   _mesa_texture_sub_image(ctx, dims, texObj, texImage, target, level,
-                           xoffset, yoffset, zoffset, width, height, depth,
-                           format, type, pixels, false);
+   texture_sub_image(ctx, dims, texObj, texImage, target, level,
+                     xoffset, yoffset, zoffset, width, height, depth,
+                     format, type, pixels);
+}
+
+
+static void
+texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
+            GLint xoffset, GLint yoffset, GLint zoffset,
+            GLsizei width, GLsizei height, GLsizei depth,
+            GLenum format, GLenum type, const GLvoid *pixels)
+{
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
+   texObj = _mesa_get_current_tex_object(ctx, target);
+   texImage = _mesa_select_tex_image(texObj, target, level);
+
+   texture_sub_image(ctx, dims, texObj, texImage, target, level,
+                     xoffset, yoffset, zoffset, width, height, depth,
+                     format, type, pixels);
 }
 
 
 }
 
 
@@ -3286,13 +3568,13 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
  * Implement all the glTextureSubImage1/2/3D() functions.
  * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
  */
  * Implement all the glTextureSubImage1/2/3D() functions.
  * Must split this out this way because of GL_TEXTURE_CUBE_MAP.
  */
-static void
+static ALWAYS_INLINE void
 texturesubimage(struct gl_context *ctx, GLuint dims,
 texturesubimage(struct gl_context *ctx, GLuint dims,
-                GLuint texture, GLint level,
+                GLuint texture, GLenum target, GLint level,
                 GLint xoffset, GLint yoffset, GLint zoffset,
                 GLsizei width, GLsizei height, GLsizei depth,
                 GLenum format, GLenum type, const GLvoid *pixels,
                 GLint xoffset, GLint yoffset, GLint zoffset,
                 GLsizei width, GLsizei height, GLsizei depth,
                 GLenum format, GLenum type, const GLvoid *pixels,
-                const char *callerName)
+                const char *callerName, bool no_error, bool ext_dsa)
 {
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
 {
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
@@ -3307,28 +3589,34 @@ texturesubimage(struct gl_context *ctx, GLuint dims,
                   _mesa_enum_to_string(type), pixels);
 
    /* Get the texture object by Name. */
                   _mesa_enum_to_string(type), pixels);
 
    /* Get the texture object by Name. */
-   texObj = _mesa_lookup_texture(ctx, texture);
-   if (!texObj) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureSubImage%uD(texture)",
-                  dims);
-      return;
+   if (!no_error) {
+      if (!ext_dsa) {
+         texObj = _mesa_lookup_texture_err(ctx, texture, callerName);
+      } else {
+         texObj = lookup_texture_ext_dsa(ctx, target, texture, callerName);
+      }
+      if (!texObj)
+         return;
+   } else {
+      texObj = _mesa_lookup_texture(ctx, texture);
    }
 
    }
 
-   /* check target (proxies not allowed) */
-   if (!legal_texsubimage_target(ctx, dims, texObj->Target, true)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)",
-                  callerName, _mesa_enum_to_string(texObj->Target));
-      return;
-   }
+   if (!no_error) {
+      /* check target (proxies not allowed) */
+      if (!legal_texsubimage_target(ctx, dims, texObj->Target, true)) {
+         _mesa_error(ctx, GL_INVALID_ENUM, "%s(target=%s)",
+                     callerName, _mesa_enum_to_string(texObj->Target));
+         return;
+      }
 
 
-   if (texsubimage_error_check(ctx, dims, texObj, texObj->Target, level,
-                               xoffset, yoffset, zoffset,
-                               width, height, depth, format, type,
-                               pixels, true, callerName)) {
-      return;   /* error was detected */
+      if (texsubimage_error_check(ctx, dims, texObj, texObj->Target, level,
+                                  xoffset, yoffset, zoffset,
+                                  width, height, depth, format, type,
+                                  pixels, callerName)) {
+         return;   /* error was detected */
+      }
    }
 
    }
 
-
    /* Must handle special case GL_TEXTURE_CUBE_MAP. */
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
       GLint imageStride;
    /* Must handle special case GL_TEXTURE_CUBE_MAP. */
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
       GLint imageStride;
@@ -3362,7 +3650,7 @@ texturesubimage(struct gl_context *ctx, GLuint dims,
        * It seems reasonable to check for cube completeness of an arbitrary
        * level here so that the image data has a consistent format and size.
        */
        * It seems reasonable to check for cube completeness of an arbitrary
        * level here so that the image data has a consistent format and size.
        */
-      if (!_mesa_cube_level_complete(texObj, level)) {
+      if (!no_error && !_mesa_cube_level_complete(texObj, level)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTextureSubImage%uD(cube map incomplete)",
                      dims);
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glTextureSubImage%uD(cube map incomplete)",
                      dims);
@@ -3376,10 +3664,10 @@ texturesubimage(struct gl_context *ctx, GLuint dims,
          texImage = texObj->Image[i][level];
          assert(texImage);
 
          texImage = texObj->Image[i][level];
          assert(texImage);
 
-         _mesa_texture_sub_image(ctx, 3, texObj, texImage, texObj->Target,
-                                 level, xoffset, yoffset, 0,
-                                 width, height, 1, format,
-                                 type, pixels, true);
+         texture_sub_image(ctx, 3, texObj, texImage, texObj->Target,
+                           level, xoffset, yoffset, 0,
+                           width, height, 1, format,
+                           type, pixels);
          pixels = (GLubyte *) pixels + imageStride;
       }
    }
          pixels = (GLubyte *) pixels + imageStride;
       }
    }
@@ -3387,14 +3675,56 @@ texturesubimage(struct gl_context *ctx, GLuint dims,
       texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
       assert(texImage);
 
       texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
       assert(texImage);
 
-      _mesa_texture_sub_image(ctx, dims, texObj, texImage, texObj->Target,
-                              level, xoffset, yoffset, zoffset,
-                              width, height, depth, format,
-                              type, pixels, true);
+      texture_sub_image(ctx, dims, texObj, texImage, texObj->Target,
+                        level, xoffset, yoffset, zoffset,
+                        width, height, depth, format,
+                        type, pixels);
    }
 }
 
 
    }
 }
 
 
+static void
+texturesubimage_error(struct gl_context *ctx, GLuint dims,
+                      GLuint texture, GLenum target, GLint level,
+                      GLint xoffset, GLint yoffset, GLint zoffset,
+                      GLsizei width, GLsizei height, GLsizei depth,
+                      GLenum format, GLenum type, const GLvoid *pixels,
+                      const char *callerName, bool ext_dsa)
+{
+   texturesubimage(ctx, dims, texture, target, level, xoffset, yoffset,
+                   zoffset, width, height, depth, format, type, pixels,
+                   callerName, false, ext_dsa);
+}
+
+
+static void
+texturesubimage_no_error(struct gl_context *ctx, GLuint dims,
+                         GLuint texture, GLenum target, GLint level,
+                         GLint xoffset, GLint yoffset, GLint zoffset,
+                         GLsizei width, GLsizei height, GLsizei depth,
+                         GLenum format, GLenum type, const GLvoid *pixels,
+                         const char *callerName, bool ext_dsa)
+{
+   texturesubimage(ctx, dims, texture, target, level, xoffset, yoffset,
+                   zoffset, width, height, depth, format, type, pixels,
+                   callerName, true, ext_dsa);
+}
+
+
+void GLAPIENTRY
+_mesa_TexSubImage1D_no_error(GLenum target, GLint level,
+                             GLint xoffset, GLsizei width,
+                             GLenum format, GLenum type,
+                             const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texsubimage(ctx, 1, target, level,
+               xoffset, 0, 0,
+               width, 1, 1,
+               format, type, pixels);
+}
+
+
 void GLAPIENTRY
 _mesa_TexSubImage1D( GLenum target, GLint level,
                      GLint xoffset, GLsizei width,
 void GLAPIENTRY
 _mesa_TexSubImage1D( GLenum target, GLint level,
                      GLint xoffset, GLsizei width,
@@ -3402,10 +3732,25 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   texsubimage(ctx, 1, target, level,
-               xoffset, 0, 0,
-               width, 1, 1,
-               format, type, pixels, "glTexSubImage1D");
+   texsubimage_err(ctx, 1, target, level,
+                   xoffset, 0, 0,
+                   width, 1, 1,
+                   format, type, pixels, "glTexSubImage1D");
+}
+
+
+void GLAPIENTRY
+_mesa_TexSubImage2D_no_error(GLenum target, GLint level,
+                             GLint xoffset, GLint yoffset,
+                             GLsizei width, GLsizei height,
+                             GLenum format, GLenum type,
+                             const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texsubimage(ctx, 2, target, level,
+               xoffset, yoffset, 0,
+               width, height, 1,
+               format, type, pixels);
 }
 
 
 }
 
 
@@ -3417,13 +3762,27 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   texsubimage(ctx, 2, target, level,
-               xoffset, yoffset, 0,
-               width, height, 1,
-               format, type, pixels, "glTexSubImage2D");
+   texsubimage_err(ctx, 2, target, level,
+                   xoffset, yoffset, 0,
+                   width, height, 1,
+                   format, type, pixels, "glTexSubImage2D");
 }
 
 
 }
 
 
+void GLAPIENTRY
+_mesa_TexSubImage3D_no_error(GLenum target, GLint level,
+                             GLint xoffset, GLint yoffset, GLint zoffset,
+                             GLsizei width, GLsizei height, GLsizei depth,
+                             GLenum format, GLenum type,
+                             const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texsubimage(ctx, 3, target, level,
+               xoffset, yoffset, zoffset,
+               width, height, depth,
+               format, type, pixels);
+}
+
 
 void GLAPIENTRY
 _mesa_TexSubImage3D( GLenum target, GLint level,
 
 void GLAPIENTRY
 _mesa_TexSubImage3D( GLenum target, GLint level,
@@ -3433,12 +3792,60 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
                      const GLvoid *pixels )
 {
    GET_CURRENT_CONTEXT(ctx);
-   texsubimage(ctx, 3, target, level,
-               xoffset, yoffset, zoffset,
-               width, height, depth,
-               format, type, pixels, "glTexSubImage3D");
+   texsubimage_err(ctx, 3, target, level,
+                   xoffset, yoffset, zoffset,
+                   width, height, depth,
+                   format, type, pixels, "glTexSubImage3D");
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage1D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                 GLsizei width, GLenum format, GLenum type,
+                                 const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_no_error(ctx, 1, texture, 0, level, xoffset, 0, 0, width,
+                            1, 1, format, type, pixels, "glTextureSubImage1D",
+                            false);
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage1DEXT(GLuint texture, GLenum target, GLint level,
+                        GLint xoffset, GLsizei width,
+                        GLenum format, GLenum type,
+                        const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_error(ctx, 1, texture, target, level, xoffset, 0, 0, width, 1,
+                         1, format, type, pixels, "glTextureSubImage1DEXT",
+                         false);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiTexSubImage1DEXT(GLenum texunit, GLenum target, GLint level,
+                            GLint xoffset, GLsizei width,
+                            GLenum format, GLenum type,
+                            const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false,
+                                                   "glMultiTexImage1DEXT");
+   texImage = _mesa_select_tex_image(texObj, target, level);
+
+   texture_sub_image(ctx, 1, texObj, texImage, target, level,
+                     xoffset, 0, 0, width, 1, 1,
+                     format, type, pixels);
 }
 
 }
 
+
 void GLAPIENTRY
 _mesa_TextureSubImage1D(GLuint texture, GLint level,
                         GLint xoffset, GLsizei width,
 void GLAPIENTRY
 _mesa_TextureSubImage1D(GLuint texture, GLint level,
                         GLint xoffset, GLsizei width,
@@ -3446,10 +3853,57 @@ _mesa_TextureSubImage1D(GLuint texture, GLint level,
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
-   texturesubimage(ctx, 1, texture, level,
-                   xoffset, 0, 0,
-                   width, 1, 1,
-                   format, type, pixels, "glTextureSubImage1D");
+   texturesubimage_error(ctx, 1, texture, 0, level, xoffset, 0, 0, width, 1,
+                         1, format, type, pixels, "glTextureSubImage1D",
+                         false);
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage2D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                 GLint yoffset, GLsizei width, GLsizei height,
+                                 GLenum format, GLenum type,
+                                 const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_no_error(ctx, 2, texture, 0, level, xoffset, yoffset, 0,
+                            width, height, 1, format, type, pixels,
+                            "glTextureSubImage2D", false);
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset, GLsizei width,
+                           GLsizei height, GLenum format, GLenum type,
+                           const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_error(ctx, 2, texture, target, level, xoffset, yoffset, 0,
+                         width, height, 1, format, type, pixels,
+                         "glTextureSubImage2DEXT", true);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiTexSubImage2DEXT(GLenum texunit, GLenum target, GLint level,
+                            GLint xoffset, GLint yoffset, GLsizei width,
+                            GLsizei height, GLenum format, GLenum type,
+                            const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false,
+                                                   "glMultiTexImage2DEXT");
+   texImage = _mesa_select_tex_image(texObj, target, level);
+
+   texture_sub_image(ctx, 2, texObj, texImage, target, level,
+                     xoffset, yoffset, 0, width, height, 1,
+                     format, type, pixels);
 }
 
 
 }
 
 
@@ -3461,10 +3915,57 @@ _mesa_TextureSubImage2D(GLuint texture, GLint level,
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
-   texturesubimage(ctx, 2, texture, level,
-                   xoffset, yoffset, 0,
-                   width, height, 1,
-                   format, type, pixels, "glTextureSubImage2D");
+   texturesubimage_error(ctx, 2, texture, 0, level, xoffset, yoffset, 0,
+                         width, height, 1, format, type, pixels,
+                         "glTextureSubImage2D", false);
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage3D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                 GLint yoffset, GLint zoffset, GLsizei width,
+                                 GLsizei height, GLsizei depth, GLenum format,
+                                 GLenum type, const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_no_error(ctx, 3, texture, 0, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format, type,
+                            pixels, "glTextureSubImage3D", false);
+}
+
+
+void GLAPIENTRY
+_mesa_TextureSubImage3DEXT(GLuint texture, GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset, GLint zoffset,
+                           GLsizei width, GLsizei height, GLsizei depth,
+                           GLenum format, GLenum type, const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   texturesubimage_error(ctx, 3, texture, target, level, xoffset, yoffset,
+                         zoffset, width, height, depth, format, type,
+                         pixels, "glTextureSubImage3DEXT", true);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiTexSubImage3DEXT(GLenum texunit, GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset, GLint zoffset,
+                           GLsizei width, GLsizei height, GLsizei depth,
+                           GLenum format, GLenum type, const GLvoid *pixels)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false,
+                                                   "glMultiTexImage3DEXT");
+   texImage = _mesa_select_tex_image(texObj, target, level);
+
+   texture_sub_image(ctx, 3, texObj, texImage, target, level,
+                     xoffset, yoffset, zoffset, width, height, depth,
+                     format, type, pixels);
 }
 
 
 }
 
 
@@ -3476,10 +3977,9 @@ _mesa_TextureSubImage3D(GLuint texture, GLint level,
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
                         const GLvoid *pixels)
 {
    GET_CURRENT_CONTEXT(ctx);
-   texturesubimage(ctx, 3, texture, level,
-                   xoffset, yoffset, zoffset,
-                   width, height, depth,
-                   format, type, pixels, "glTextureSubImage3D");
+   texturesubimage_error(ctx, 3, texture, 0, level, xoffset, yoffset, zoffset,
+                         width, height, depth, format, type, pixels,
+                         "glTextureSubImage3D", false);
 }
 
 
 }
 
 
@@ -3501,6 +4001,7 @@ get_copy_tex_image_source(struct gl_context *ctx, mesa_format texFormat)
    }
 }
 
    }
 }
 
+
 static void
 copytexsubimage_by_slice(struct gl_context *ctx,
                          struct gl_texture_image *texImage,
 static void
 copytexsubimage_by_slice(struct gl_context *ctx,
                          struct gl_texture_image *texImage,
@@ -3531,6 +4032,7 @@ copytexsubimage_by_slice(struct gl_context *ctx,
    }
 }
 
    }
 }
 
+
 static GLboolean
 formats_differ_in_component_sizes(mesa_format f1, mesa_format f2)
 {
 static GLboolean
 formats_differ_in_component_sizes(mesa_format f1, mesa_format f2)
 {
@@ -3562,7 +4064,7 @@ formats_differ_in_component_sizes(mesa_format f1, mesa_format f2)
 static bool
 can_avoid_reallocation(const struct gl_texture_image *texImage,
                        GLenum internalFormat,
 static bool
 can_avoid_reallocation(const struct gl_texture_image *texImage,
                        GLenum internalFormat,
-                       mesa_format texFormat, GLint x, GLint y, GLsizei width,
+                       mesa_format texFormat, GLsizei width,
                        GLsizei height, GLint border)
 {
    if (texImage->InternalFormat != internalFormat)
                        GLsizei height, GLint border)
 {
    if (texImage->InternalFormat != internalFormat)
@@ -3578,19 +4080,113 @@ can_avoid_reallocation(const struct gl_texture_image *texImage,
    return true;
 }
 
    return true;
 }
 
+
 /**
 /**
- * Implement the glCopyTexImage1/2D() functions.
+ * Implementation for glCopyTex(ture)SubImage1/2/3D() functions.
  */
 static void
  */
 static void
-copyteximage(struct gl_context *ctx, GLuint dims,
+copy_texture_sub_image(struct gl_context *ctx, GLuint dims,
+                       struct gl_texture_object *texObj,
+                       GLenum target, GLint level,
+                       GLint xoffset, GLint yoffset, GLint zoffset,
+                       GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_image *texImage;
+
+   _mesa_lock_texture(ctx, texObj);
+
+   texImage = _mesa_select_tex_image(texObj, target, level);
+
+   /* 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:
+      if (target != GL_TEXTURE_1D_ARRAY)
+         yoffset += 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);
+
+      copytexsubimage_by_slice(ctx, texImage, dims, xoffset, yoffset, zoffset,
+                               srcRb, x, y, width, height);
+
+      check_gen_mipmap(ctx, target, texObj, level);
+
+      /* NOTE: Don't signal _NEW_TEXTURE_OBJECT since we've only changed
+       * the texel data, not the texture format, size, etc.
+       */
+   }
+
+   _mesa_unlock_texture(ctx, texObj);
+}
+
+
+static void
+copy_texture_sub_image_err(struct gl_context *ctx, GLuint dims,
+                           struct gl_texture_object *texObj,
+                           GLenum target, GLint level,
+                           GLint xoffset, GLint yoffset, GLint zoffset,
+                           GLint x, GLint y, GLsizei width, GLsizei height,
+                           const char *caller)
+{
+   FLUSH_VERTICES(ctx, 0);
+
+   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
+      _mesa_debug(ctx, "%s %s %d %d %d %d %d %d %d %d\n", caller,
+                  _mesa_enum_to_string(target),
+                  level, xoffset, yoffset, zoffset, x, y, width, height);
+
+   if (ctx->NewState & NEW_COPY_TEX_STATE)
+      _mesa_update_state(ctx);
+
+   if (copytexsubimage_error_check(ctx, dims, texObj, target, level,
+                                   xoffset, yoffset, zoffset,
+                                   width, height, caller)) {
+      return;
+   }
+
+   copy_texture_sub_image(ctx, dims, texObj, target, level, xoffset, yoffset,
+                          zoffset, x, y, width, height);
+}
+
+
+static void
+copy_texture_sub_image_no_error(struct gl_context *ctx, GLuint dims,
+                                struct gl_texture_object *texObj,
+                                GLenum target, GLint level,
+                                GLint xoffset, GLint yoffset, GLint zoffset,
+                                GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   FLUSH_VERTICES(ctx, 0);
+
+   if (ctx->NewState & NEW_COPY_TEX_STATE)
+      _mesa_update_state(ctx);
+
+   copy_texture_sub_image(ctx, dims, texObj, target, level, xoffset, yoffset,
+                          zoffset, x, y, width, height);
+}
+
+
+/**
+ * Implement the glCopyTexImage1/2D() functions.
+ */
+static ALWAYS_INLINE void
+copyteximage(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj,
              GLenum target, GLint level, GLenum internalFormat,
              GLenum target, GLint level, GLenum internalFormat,
-             GLint x, GLint y, GLsizei width, GLsizei height, GLint border )
+             GLint x, GLint y, GLsizei width, GLsizei height, GLint border,
+             bool no_error)
 {
 {
-   struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    struct gl_texture_image *texImage;
-   const GLuint face = _mesa_tex_target_to_face(target);
    mesa_format texFormat;
    mesa_format texFormat;
-   struct gl_renderbuffer *rb;
 
    FLUSH_VERTICES(ctx, 0);
 
 
    FLUSH_VERTICES(ctx, 0);
 
@@ -3604,18 +4200,20 @@ copyteximage(struct gl_context *ctx, GLuint dims,
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
    if (ctx->NewState & NEW_COPY_TEX_STATE)
       _mesa_update_state(ctx);
 
-   if (copytexture_error_check(ctx, dims, target, level, internalFormat,
-                               width, height, border))
-      return;
+   if (!no_error) {
+      if (copytexture_error_check(ctx, dims, target, texObj, level,
+                                  internalFormat, 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;
+      if (!_mesa_legal_texture_dimensions(ctx, target, level, width, height,
+                                          1, border)) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glCopyTexImage%uD(invalid width=%d or height=%d)",
+                     dims, width, height);
+         return;
+      }
    }
 
    }
 
-   texObj = _mesa_get_current_tex_object(ctx, target);
    assert(texObj);
 
    texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
    assert(texObj);
 
    texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
@@ -3628,11 +4226,15 @@ copyteximage(struct gl_context *ctx, GLuint dims,
    {
       texImage = _mesa_select_tex_image(texObj, target, level);
       if (texImage && can_avoid_reallocation(texImage, internalFormat, texFormat,
    {
       texImage = _mesa_select_tex_image(texObj, target, level);
       if (texImage && can_avoid_reallocation(texImage, internalFormat, texFormat,
-                                             x, y, width, height, border)) {
+                                             width, height, border)) {
          _mesa_unlock_texture(ctx, texObj);
          _mesa_unlock_texture(ctx, texObj);
-         _mesa_copy_texture_sub_image(ctx, dims, texObj, target, level,
-                                      0, 0, 0, x, y, width, height,
-                                      "CopyTexImage");
+         if (no_error) {
+            copy_texture_sub_image_no_error(ctx, dims, texObj, target, level, 0,
+                                            0, 0, x, y, width, height);
+         } else {
+            copy_texture_sub_image_err(ctx, dims, texObj, target, level, 0, 0,
+                                       0, x, y, width, height,"CopyTexImage");
+         }
          return;
       }
    }
          return;
       }
    }
@@ -3640,9 +4242,10 @@ copyteximage(struct gl_context *ctx, GLuint dims,
    _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_LOW, "glCopyTexImage "
                     "can't avoid reallocating texture storage\n");
 
    _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_LOW, "glCopyTexImage "
                     "can't avoid reallocating texture storage\n");
 
-   rb = _mesa_get_read_renderbuffer_for_format(ctx, internalFormat);
+   if (!no_error && _mesa_is_gles3(ctx)) {
+      struct gl_renderbuffer *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 (_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.
@@ -3667,7 +4270,7 @@ copyteximage(struct gl_context *ctx, GLuint dims,
        */
       else if (formats_differ_in_component_sizes (texFormat, rb->Format)) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
        */
       else if (formats_differ_in_component_sizes (texFormat, rb->Format)) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glCopyTexImage%uD(componenet size changed in"
+                        "glCopyTexImage%uD(component size changed in"
                         " internal format)", dims);
             return;
       }
                         " internal format)", dims);
             return;
       }
@@ -3687,8 +4290,8 @@ copyteximage(struct gl_context *ctx, GLuint dims,
       x += border;
       width -= border * 2;
       if (dims == 2) {
       x += border;
       width -= border * 2;
       if (dims == 2) {
-        y += border;
-        height -= border * 2;
+         y += border;
+         height -= border * 2;
       }
       border = 0;
    }
       }
       border = 0;
    }
@@ -3698,10 +4301,11 @@ copyteximage(struct gl_context *ctx, GLuint dims,
       texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
       if (!texImage) {
       texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
       if (!texImage) {
-        _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
       }
       else {
          GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
       }
       else {
          GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
+         const GLuint face = _mesa_tex_target_to_face(target);
 
          /* Free old texture image */
          ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
          /* Free old texture image */
          ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
@@ -3735,6 +4339,28 @@ copyteximage(struct gl_context *ctx, GLuint dims,
 }
 
 
 }
 
 
+static void
+copyteximage_err(struct gl_context *ctx, GLuint dims,
+                 GLenum target,
+                 GLint level, GLenum internalFormat, GLint x, GLint y,
+                 GLsizei width, GLsizei height, GLint border)
+{
+   struct gl_texture_object* texObj = _mesa_get_current_tex_object(ctx, target);
+   copyteximage(ctx, dims, texObj, target, level, internalFormat, x, y, width, height,
+                border, false);
+}
+
+
+static void
+copyteximage_no_error(struct gl_context *ctx, GLuint dims, GLenum target,
+                      GLint level, GLenum internalFormat, GLint x, GLint y,
+                      GLsizei width, GLsizei height, GLint border)
+{
+   struct gl_texture_object* texObj = _mesa_get_current_tex_object(ctx, target);
+   copyteximage(ctx, dims, texObj, target, level, internalFormat, x, y, width, height,
+                border, true);
+}
+
 
 void GLAPIENTRY
 _mesa_CopyTexImage1D( GLenum target, GLint level,
 
 void GLAPIENTRY
 _mesa_CopyTexImage1D( GLenum target, GLint level,
@@ -3743,10 +4369,46 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
                       GLsizei width, GLint border )
 {
    GET_CURRENT_CONTEXT(ctx);
                       GLsizei width, GLint border )
 {
    GET_CURRENT_CONTEXT(ctx);
-   copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border);
+   copyteximage_err(ctx, 1, target, level, internalFormat, x, y, width, 1,
+                    border);
 }
 
 
 }
 
 
+void GLAPIENTRY
+_mesa_CopyTextureImage1DEXT( GLuint texture, GLenum target, GLint level,
+                             GLenum internalFormat,
+                             GLint x, GLint y,
+                             GLsizei width, GLint border )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object* texObj =
+      _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                     "glCopyTextureImage1DEXT");
+   if (!texObj)
+      return;
+   copyteximage(ctx, 1, texObj, target, level, internalFormat, x, y, width, 1,
+                border, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyMultiTexImage1DEXT( GLenum texunit, GLenum target, GLint level,
+                              GLenum internalFormat,
+                              GLint x, GLint y,
+                              GLsizei width, GLint border )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object* texObj =
+      _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                             texunit - GL_TEXTURE0,
+                                             false,
+                                             "glCopyMultiTexImage1DEXT");
+   if (!texObj)
+      return;
+   copyteximage(ctx, 1, texObj, target, level, internalFormat, x, y, width, 1,
+                border, false);
+}
+
 
 void GLAPIENTRY
 _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
 
 void GLAPIENTRY
 _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
@@ -3754,80 +4416,72 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
                       GLint border )
 {
    GET_CURRENT_CONTEXT(ctx);
                       GLint border )
 {
    GET_CURRENT_CONTEXT(ctx);
-   copyteximage(ctx, 2, target, level, internalFormat,
-                x, y, width, height, border);
+   copyteximage_err(ctx, 2, target, level, internalFormat,
+                    x, y, width, height, border);
 }
 
 }
 
-/**
- * Implementation for glCopyTex(ture)SubImage1/2/3D() functions.
- */
-void
-_mesa_copy_texture_sub_image(struct gl_context *ctx, GLuint dims,
-                             struct gl_texture_object *texObj,
-                             GLenum target, GLint level,
-                             GLint xoffset, GLint yoffset, GLint zoffset,
+
+void GLAPIENTRY
+_mesa_CopyTextureImage2DEXT( GLuint texture, GLenum target, GLint level,
+                             GLenum internalFormat,
                              GLint x, GLint y,
                              GLsizei width, GLsizei height,
                              GLint x, GLint y,
                              GLsizei width, GLsizei height,
-                             const char *caller)
+                             GLint border )
 {
 {
-   struct gl_texture_image *texImage;
-
-   FLUSH_VERTICES(ctx, 0);
-
-   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
-      _mesa_debug(ctx, "%s %s %d %d %d %d %d %d %d %d\n", caller,
-                  _mesa_enum_to_string(target),
-                  level, xoffset, yoffset, zoffset, x, y, width, height);
-
-   if (ctx->NewState & NEW_COPY_TEX_STATE)
-      _mesa_update_state(ctx);
-
-   if (copytexsubimage_error_check(ctx, dims, texObj, target, level,
-                                   xoffset, yoffset, zoffset,
-                                   width, height, caller)) {
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object* texObj =
+      _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                     "glCopyTextureImage2DEXT");
+   if (!texObj)
       return;
       return;
-   }
+   copyteximage(ctx, 2, texObj, target, level, internalFormat, x, y, width, height,
+                border, false);
+}
 
 
-   _mesa_lock_texture(ctx, texObj);
-   {
-      texImage = _mesa_select_tex_image(texObj, target, level);
 
 
-      /* 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:
-         if (target != GL_TEXTURE_1D_ARRAY)
-            yoffset += texImage->Border;
-         /* fall-through */
-      case 1:
-         xoffset += texImage->Border;
-      }
+void GLAPIENTRY
+_mesa_CopyMultiTexImage2DEXT( GLenum texunit, GLenum target, GLint level,
+                              GLenum internalFormat,
+                              GLint x, GLint y,
+                              GLsizei width, GLsizei height, GLint border )
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_texture_object* texObj =
+      _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                             texunit - GL_TEXTURE0,
+                                             false,
+                                             "glCopyMultiTexImage2DEXT");
+   if (!texObj)
+      return;
+   copyteximage(ctx, 2, texObj, target, level, internalFormat, x, y, width, height,
+                border, false);
+}
 
 
-      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
-                                     &width, &height)) {
-         struct gl_renderbuffer *srcRb =
-            get_copy_tex_image_source(ctx, texImage->TexFormat);
 
 
-         copytexsubimage_by_slice(ctx, texImage, dims,
-                                  xoffset, yoffset, zoffset,
-                                  srcRb, x, y, width, height);
+void GLAPIENTRY
+_mesa_CopyTexImage1D_no_error(GLenum target, GLint level, GLenum internalFormat,
+                              GLint x, GLint y, GLsizei width, GLint border)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   copyteximage_no_error(ctx, 1, target, level, internalFormat, x, y, width, 1,
+                         border);
+}
 
 
-         check_gen_mipmap(ctx, target, texObj, level);
 
 
-         /* NOTE: Don't signal _NEW_TEXTURE_OBJECT since we've only changed
-          * the texel data, not the texture format, size, etc.
-          */
-      }
-   }
-   _mesa_unlock_texture(ctx, texObj);
+void GLAPIENTRY
+_mesa_CopyTexImage2D_no_error(GLenum target, GLint level, GLenum internalFormat,
+                              GLint x, GLint y, GLsizei width, GLsizei height,
+                              GLint border)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   copyteximage_no_error(ctx, 2, target, level, internalFormat,
+                         x, y, width, height, border);
 }
 
 }
 
+
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTexSubImage1D( GLenum target, GLint level,
-                         GLint xoffset, GLint x, GLint y, GLsizei width )
+_mesa_CopyTexSubImage1D(GLenum target, GLint level,
+                        GLint xoffset, GLint x, GLint y, GLsizei width)
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage1D";
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage1D";
@@ -3846,16 +4500,15 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   _mesa_copy_texture_sub_image(ctx, 1, texObj, target, level, xoffset, 0, 0,
-                                x, y, width, 1, self);
+   copy_texture_sub_image_err(ctx, 1, texObj, target, level, xoffset, 0, 0,
+                              x, y, width, 1, self);
 }
 
 
 }
 
 
-
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTexSubImage2D( GLenum target, GLint level,
-                         GLint xoffset, GLint yoffset,
-                         GLint x, GLint y, GLsizei width, GLsizei height )
+_mesa_CopyTexSubImage2D(GLenum target, GLint level,
+                        GLint xoffset, GLint yoffset,
+                        GLint x, GLint y, GLsizei width, GLsizei height)
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage2D";
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage2D";
@@ -3874,17 +4527,15 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   _mesa_copy_texture_sub_image(ctx, 2, texObj, target, level,
-                                xoffset, yoffset, 0,
-                                x, y, width, height, self);
+   copy_texture_sub_image_err(ctx, 2, texObj, target, level, xoffset, yoffset,
+                              0, x, y, width, height, self);
 }
 
 
 }
 
 
-
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTexSubImage3D( GLenum target, GLint level,
-                         GLint xoffset, GLint yoffset, GLint zoffset,
-                         GLint x, GLint y, GLsizei width, GLsizei height )
+_mesa_CopyTexSubImage3D(GLenum target, GLint level,
+                        GLint xoffset, GLint yoffset, GLint zoffset,
+                        GLint x, GLint y, GLsizei width, GLsizei height)
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage3D";
 {
    struct gl_texture_object* texObj;
    const char *self = "glCopyTexSubImage3D";
@@ -3903,94 +4554,327 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   _mesa_copy_texture_sub_image(ctx, 3, texObj, target, level,
-                                xoffset, yoffset, zoffset,
-                                x, y, width, height, self);
+   copy_texture_sub_image_err(ctx, 3, texObj, target, level, xoffset, yoffset,
+                              zoffset, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage1D(GLuint texture, GLint level,
+                            GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage1D";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_texture_err(ctx, texture, self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 1, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   copy_texture_sub_image_err(ctx, 1, texObj, texObj->Target, level, xoffset, 0,
+                              0, x, y, width, 1, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage1DEXT(GLuint texture, GLenum target, GLint level,
+                               GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage1DEXT";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 1, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   copy_texture_sub_image_err(ctx, 1, texObj, texObj->Target, level, xoffset, 0,
+                              0, x, y, width, 1, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyMultiTexSubImage1DEXT(GLenum texunit, GLenum target, GLint level,
+                                GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyMultiTexSubImage1DEXT";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false, self);
+   if (!texObj)
+      return;
+
+   copy_texture_sub_image_err(ctx, 1, texObj, texObj->Target, level, xoffset, 0,
+                              0, x, y, width, 1, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage2D(GLuint texture, GLint level,
+                            GLint xoffset, GLint yoffset,
+                            GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage2D";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_texture_err(ctx, texture, self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 2, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   copy_texture_sub_image_err(ctx, 2, texObj, texObj->Target, level, xoffset,
+                              yoffset, 0, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
+                               GLint xoffset, GLint yoffset,
+                               GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage2DEXT";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true, self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 2, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   copy_texture_sub_image_err(ctx, 2, texObj, texObj->Target, level, xoffset,
+                              yoffset, 0, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyMultiTexSubImage2DEXT(GLenum texunit, GLenum target, GLint level,
+                               GLint xoffset, GLint yoffset,
+                               GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyMultiTexSubImage2DEXT";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false, self);
+   if (!texObj)
+      return;
+
+   copy_texture_sub_image_err(ctx, 2, texObj, texObj->Target, level, xoffset,
+                              yoffset, 0, x, y, width, height, self);
+}
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage3D(GLuint texture, GLint level,
+                            GLint xoffset, GLint yoffset, GLint zoffset,
+                            GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage3D";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_texture_err(ctx, texture, self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 3, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+      /* Act like CopyTexSubImage2D */
+      copy_texture_sub_image_err(ctx, 2, texObj,
+                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset,
+                                level, xoffset, yoffset, 0, x, y, width, height,
+                                self);
+   }
+   else
+      copy_texture_sub_image_err(ctx, 3, texObj, texObj->Target, level, xoffset,
+                                 yoffset, zoffset, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTextureSubImage3DEXT(GLuint texture, GLenum target, GLint level,
+                               GLint xoffset, GLint yoffset, GLint zoffset,
+                               GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyTextureSubImage3D";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true, self);
+   if (!texObj)
+      return;
+
+   /* Check target (proxies not allowed). */
+   if (!legal_texsubimage_target(ctx, 3, texObj->Target, true)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
+                  _mesa_enum_to_string(texObj->Target));
+      return;
+   }
+
+   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+      /* Act like CopyTexSubImage2D */
+      copy_texture_sub_image_err(ctx, 2, texObj,
+                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset,
+                                level, xoffset, yoffset, 0, x, y, width, height,
+                                self);
+   }
+   else
+      copy_texture_sub_image_err(ctx, 3, texObj, texObj->Target, level, xoffset,
+                                 yoffset, zoffset, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyMultiTexSubImage3DEXT(GLenum texunit, GLenum target, GLint level,
+                                GLint xoffset, GLint yoffset, GLint zoffset,
+                                GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   struct gl_texture_object* texObj;
+   const char *self = "glCopyMultiTexSubImage3D";
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   false, self);
+   if (!texObj)
+      return;
+
+   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+      /* Act like CopyTexSubImage2D */
+      copy_texture_sub_image_err(ctx, 2, texObj,
+                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset,
+                                level, xoffset, yoffset, 0, x, y, width, height,
+                                self);
+   }
+   else
+      copy_texture_sub_image_err(ctx, 3, texObj, texObj->Target, level, xoffset,
+                                 yoffset, zoffset, x, y, width, height, self);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTexSubImage1D_no_error(GLenum target, GLint level, GLint xoffset,
+                                 GLint x, GLint y, GLsizei width)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_texture_object* texObj = _mesa_get_current_tex_object(ctx, target);
+   copy_texture_sub_image_no_error(ctx, 1, texObj, target, level, xoffset, 0, 0,
+                                   x, y, width, 1);
+}
+
+
+void GLAPIENTRY
+_mesa_CopyTexSubImage2D_no_error(GLenum target, GLint level, GLint xoffset,
+                                 GLint yoffset, GLint x, GLint y, GLsizei width,
+                                 GLsizei height)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_texture_object* texObj = _mesa_get_current_tex_object(ctx, target);
+   copy_texture_sub_image_no_error(ctx, 2, texObj, target, level, xoffset,
+                                   yoffset, 0, x, y, width, height);
 }
 
 }
 
+
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTextureSubImage1D(GLuint texture, GLint level,
-                            GLint xoffset, GLint x, GLint y, GLsizei width)
+_mesa_CopyTexSubImage3D_no_error(GLenum target, GLint level, GLint xoffset,
+                                 GLint yoffset, GLint zoffset, GLint x, GLint y,
+                                 GLsizei width, GLsizei height)
 {
 {
-   struct gl_texture_object* texObj;
-   const char *self = "glCopyTextureSubImage1D";
    GET_CURRENT_CONTEXT(ctx);
 
    GET_CURRENT_CONTEXT(ctx);
 
-   texObj = _mesa_lookup_texture_err(ctx, texture, self);
-   if (!texObj)
-      return;
-
-   /* Check target (proxies not allowed). */
-   if (!legal_texsubimage_target(ctx, 1, texObj->Target, true)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
-                  _mesa_enum_to_string(texObj->Target));
-      return;
-   }
-
-   _mesa_copy_texture_sub_image(ctx, 1, texObj, texObj->Target, level,
-                                xoffset, 0, 0, x, y, width, 1, self);
+   struct gl_texture_object* texObj = _mesa_get_current_tex_object(ctx, target);
+   copy_texture_sub_image_no_error(ctx, 3, texObj, target, level, xoffset,
+                                   yoffset, zoffset, x, y, width, height);
 }
 
 }
 
+
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTextureSubImage2D(GLuint texture, GLint level,
-                            GLint xoffset, GLint yoffset,
-                            GLint x, GLint y, GLsizei width, GLsizei height)
+_mesa_CopyTextureSubImage1D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                     GLint x, GLint y, GLsizei width)
 {
 {
-   struct gl_texture_object* texObj;
-   const char *self = "glCopyTextureSubImage2D";
    GET_CURRENT_CONTEXT(ctx);
 
    GET_CURRENT_CONTEXT(ctx);
 
-   texObj = _mesa_lookup_texture_err(ctx, texture, self);
-   if (!texObj)
-      return;
-
-   /* Check target (proxies not allowed). */
-   if (!legal_texsubimage_target(ctx, 2, texObj->Target, true)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
-                  _mesa_enum_to_string(texObj->Target));
-      return;
-   }
-
-   _mesa_copy_texture_sub_image(ctx, 2, texObj, texObj->Target, level,
-                                xoffset, yoffset, 0,
-                                x, y, width, height, self);
+   struct gl_texture_object* texObj = _mesa_lookup_texture(ctx, texture);
+   copy_texture_sub_image_no_error(ctx, 1, texObj, texObj->Target, level,
+                                   xoffset, 0, 0, x, y, width, 1);
 }
 
 
 }
 
 
-
 void GLAPIENTRY
 void GLAPIENTRY
-_mesa_CopyTextureSubImage3D(GLuint texture, GLint level,
-                            GLint xoffset, GLint yoffset, GLint zoffset,
-                            GLint x, GLint y, GLsizei width, GLsizei height)
+_mesa_CopyTextureSubImage2D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                     GLint yoffset, GLint x, GLint y,
+                                     GLsizei width, GLsizei height)
 {
 {
-   struct gl_texture_object* texObj;
-   const char *self = "glCopyTextureSubImage3D";
    GET_CURRENT_CONTEXT(ctx);
 
    GET_CURRENT_CONTEXT(ctx);
 
-   texObj = _mesa_lookup_texture_err(ctx, texture, self);
-   if (!texObj)
-      return;
+   struct gl_texture_object* texObj = _mesa_lookup_texture(ctx, texture);
+   copy_texture_sub_image_no_error(ctx, 2, texObj, texObj->Target, level,
+                                   xoffset, yoffset, 0, x, y, width, height);
+}
 
 
-   /* Check target (proxies not allowed). */
-   if (!legal_texsubimage_target(ctx, 3, texObj->Target, true)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", self,
-                  _mesa_enum_to_string(texObj->Target));
-      return;
-   }
 
 
+void GLAPIENTRY
+_mesa_CopyTextureSubImage3D_no_error(GLuint texture, GLint level, GLint xoffset,
+                                     GLint yoffset, GLint zoffset, GLint x,
+                                     GLint y, GLsizei width, GLsizei height)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   struct gl_texture_object* texObj = _mesa_lookup_texture(ctx, texture);
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
       /* Act like CopyTexSubImage2D */
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
       /* Act like CopyTexSubImage2D */
-      _mesa_copy_texture_sub_image(ctx, 2, texObj,
-                                   GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset,
-                                   level, xoffset, yoffset, 0,
-                                   x, y, width, height, self);
+      copy_texture_sub_image_no_error(ctx, 2, texObj,
+                                      GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset,
+                                      level, xoffset, yoffset, 0, x, y, width,
+                                      height);
    }
    else
    }
    else
-      _mesa_copy_texture_sub_image(ctx, 3, texObj, texObj->Target, level,
-                                   xoffset, yoffset, zoffset,
-                                   x, y, width, height, self);
+      copy_texture_sub_image_no_error(ctx, 3, texObj, texObj->Target, level,
+                                      xoffset, yoffset, zoffset, x, y, width,
+                                      height);
 }
 
 }
 
+
 static bool
 check_clear_tex_image(struct gl_context *ctx,
                       const char *function,
 static bool
 check_clear_tex_image(struct gl_context *ctx,
                       const char *function,
@@ -4064,6 +4948,7 @@ check_clear_tex_image(struct gl_context *ctx,
    return true;
 }
 
    return true;
 }
 
+
 static struct gl_texture_object *
 get_tex_obj_for_clear(struct gl_context *ctx,
                       const char *function,
 static struct gl_texture_object *
 get_tex_obj_for_clear(struct gl_context *ctx,
                       const char *function,
@@ -4071,17 +4956,9 @@ get_tex_obj_for_clear(struct gl_context *ctx,
 {
    struct gl_texture_object *texObj;
 
 {
    struct gl_texture_object *texObj;
 
-   if (texture == 0) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
-      return NULL;
-   }
-
-   texObj = _mesa_lookup_texture(ctx, texture);
-
-   if (texObj == NULL) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
+   texObj = _mesa_lookup_texture_err(ctx, texture, function);
+   if (!texObj)
       return NULL;
       return NULL;
-   }
 
    if (texObj->Target == 0) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
 
    if (texObj->Target == 0) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
@@ -4091,6 +4968,15 @@ get_tex_obj_for_clear(struct gl_context *ctx,
    return texObj;
 }
 
    return texObj;
 }
 
+
+/**
+ * For clearing cube textures, the zoffset and depth parameters indicate
+ * which cube map faces are to be cleared.  This is the one case where we
+ * need to be concerned with multiple gl_texture_images.  This function
+ * returns the array of texture images to clear for cube maps, or one
+ * texture image otherwise.
+ * \return number of texture images, 0 for error, 6 for cube, 1 otherwise.
+ */
 static int
 get_tex_images_for_clear(struct gl_context *ctx,
                          const char *function,
 static int
 get_tex_images_for_clear(struct gl_context *ctx,
                          const char *function,
@@ -4099,7 +4985,7 @@ get_tex_images_for_clear(struct gl_context *ctx,
                          struct gl_texture_image **texImages)
 {
    GLenum target;
                          struct gl_texture_image **texImages)
 {
    GLenum target;
-   int i;
+   int numFaces, i;
 
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
 
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
@@ -4107,35 +4993,31 @@ get_tex_images_for_clear(struct gl_context *ctx,
    }
 
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
    }
 
    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
-      for (i = 0; i < MAX_FACES; i++) {
-         target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
-
-         texImages[i] = _mesa_select_tex_image(texObj, target, level);
-         if (texImages[i] == NULL) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "%s(invalid level)", function);
-            return 0;
-         }
-      }
-
-      return MAX_FACES;
+      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+      numFaces = MAX_FACES;
+   }
+   else {
+      target = texObj->Target;
+      numFaces = 1;
    }
 
    }
 
-   texImages[0] = _mesa_select_tex_image(texObj, texObj->Target, level);
-
-   if (texImages[0] == NULL) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
-      return 0;
+   for (i = 0; i < numFaces; i++) {
+      texImages[i] = _mesa_select_tex_image(texObj, target + i, level);
+      if (texImages[i] == NULL) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
+         return 0;
+      }
    }
 
    }
 
-   return 1;
+   return numFaces;
 }
 
 }
 
+
 void GLAPIENTRY
 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 )
+_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;
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_texture_object *texObj;
@@ -4160,6 +5042,7 @@ _mesa_ClearTexSubImage( GLuint texture, GLint level,
       minDepth = -(int) texImages[0]->Border;
       maxDepth = texImages[0]->Depth;
    } else {
       minDepth = -(int) texImages[0]->Border;
       maxDepth = texImages[0]->Depth;
    } else {
+      assert(numImages == MAX_FACES);
       minDepth = 0;
       maxDepth = numImages;
    }
       minDepth = 0;
       maxDepth = numImages;
    }
@@ -4179,8 +5062,7 @@ _mesa_ClearTexSubImage( GLuint texture, GLint level,
    }
 
    if (numImages == 1) {
    }
 
    if (numImages == 1) {
-      if (check_clear_tex_image(ctx, "glClearTexSubImage",
-                                texImages[0],
+      if (check_clear_tex_image(ctx, "glClearTexSubImage", texImages[0],
                                 format, type, data, clearValue[0])) {
          ctx->Driver.ClearTexSubImage(ctx,
                                       texImages[0],
                                 format, type, data, clearValue[0])) {
          ctx->Driver.ClearTexSubImage(ctx,
                                       texImages[0],
@@ -4189,9 +5071,10 @@ _mesa_ClearTexSubImage( GLuint texture, GLint level,
                                       data ? clearValue[0] : NULL);
       }
    } else {
                                       data ? clearValue[0] : NULL);
       }
    } else {
+      /* loop over cube face images */
       for (i = zoffset; i < zoffset + depth; i++) {
       for (i = zoffset; i < zoffset + depth; i++) {
-         if (!check_clear_tex_image(ctx, "glClearTexSubImage",
-                                    texImages[i],
+         assert(i < MAX_FACES);
+         if (!check_clear_tex_image(ctx, "glClearTexSubImage", texImages[i],
                                     format, type, data, clearValue[i]))
             goto out;
       }
                                     format, type, data, clearValue[i]))
             goto out;
       }
@@ -4208,6 +5091,7 @@ _mesa_ClearTexSubImage( GLuint texture, GLint level,
    _mesa_unlock_texture(ctx, texObj);
 }
 
    _mesa_unlock_texture(ctx, texObj);
 }
 
+
 void GLAPIENTRY
 _mesa_ClearTexImage( GLuint texture, GLint level,
                      GLenum format, GLenum type, const void *data )
 void GLAPIENTRY
 _mesa_ClearTexImage( GLuint texture, GLint level,
                      GLenum format, GLenum type, const void *data )
@@ -4229,10 +5113,8 @@ _mesa_ClearTexImage( GLuint texture, GLint level,
                                         texObj, level, texImages);
 
    for (i = 0; i < numImages; i++) {
                                         texObj, level, texImages);
 
    for (i = 0; i < numImages; i++) {
-      if (!check_clear_tex_image(ctx, "glClearTexImage",
-                                 texImages[i],
-                                 format, type, data,
-                                 clearValue[i]))
+      if (!check_clear_tex_image(ctx, "glClearTexImage", texImages[i], format,
+                                 type, data, clearValue[i]))
          goto out;
    }
 
          goto out;
    }
 
@@ -4267,10 +5149,12 @@ out:
  */
 static GLboolean
 compressed_subtexture_target_check(struct gl_context *ctx, GLenum target,
  */
 static GLboolean
 compressed_subtexture_target_check(struct gl_context *ctx, GLenum target,
-                                   GLint dims, GLenum format, bool dsa,
+                                   GLint dims, GLenum intFormat, bool dsa,
                                    const char *caller)
 {
    GLboolean targetOK;
                                    const char *caller)
 {
    GLboolean targetOK;
+   mesa_format format;
+   enum mesa_format_layout layout;
 
    if (dsa && target == GL_TEXTURE_RECTANGLE) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", caller,
 
    if (dsa && target == GL_TEXTURE_RECTANGLE) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid target %s)", caller,
@@ -4331,21 +5215,44 @@ compressed_subtexture_target_check(struct gl_context *ctx, GLenum target,
           * which is (at this time) only bptc. Otherwise we'd say s3tc (and
           * more) are valid here, which they are not, but of course not
           * mentioned by core spec.
           * which is (at this time) only bptc. Otherwise we'd say s3tc (and
           * more) are valid here, which they are not, but of course not
           * mentioned by core spec.
+          *
+          * Also, from GL_KHR_texture_compression_astc_{hdr,ldr}:
+          *
+          *    "Add a second new column "3D Tex." which is empty for all non-ASTC
+          *     formats. If only the LDR profile is supported by the implementation,
+          *     this column is also empty for all ASTC formats. If both the LDR and HDR
+          *     profiles are supported, this column is checked for all ASTC formats."
+          *
+          *    "An INVALID_OPERATION error is generated by CompressedTexSubImage3D if
+          *     <format> is one of the formats in table 8.19 and <target> is not
+          *     TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, or TEXTURE_3D.
+          *
+          *     An INVALID_OPERATION error is generated by CompressedTexSubImage3D if
+          *     <format> is TEXTURE_CUBE_MAP_ARRAY and the "Cube Map Array" column of
+          *     table 8.19 is *not* checked, or if <format> is TEXTURE_3D and the "3D
+          *     Tex." column of table 8.19 is *not* checked"
+          *
+          * And from GL_KHR_texture_compression_astc_sliced_3d:
+          *
+          *    "Modify the "3D Tex." column to be checked for all ASTC formats."
           */
           */
-         switch (format) {
-         /* These are the only 3D compression formats supported at this time */
-         case GL_COMPRESSED_RGBA_BPTC_UNORM:
-         case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
-         case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
-         case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
+         format = _mesa_glenum_to_compressed_format(intFormat);
+         layout = _mesa_get_format_layout(format);
+         switch (layout) {
+         case MESA_FORMAT_LAYOUT_BPTC:
             /* valid format */
             break;
             /* valid format */
             break;
+         case MESA_FORMAT_LAYOUT_ASTC:
+            targetOK =
+               ctx->Extensions.KHR_texture_compression_astc_hdr ||
+               ctx->Extensions.KHR_texture_compression_astc_sliced_3d;
+            break;
          default:
             /* invalid format */
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "%s(invalid target %s for format %s)", caller,
                         _mesa_enum_to_string(target),
          default:
             /* invalid format */
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "%s(invalid target %s for format %s)", caller,
                         _mesa_enum_to_string(target),
-                        _mesa_enum_to_string(format));
+                        _mesa_enum_to_string(intFormat));
             return GL_TRUE;
          }
          break;
             return GL_TRUE;
          }
          break;
@@ -4388,15 +5295,12 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims,
 
    /* this will catch any invalid compressed format token */
    if (!_mesa_is_compressed_format(ctx, format)) {
 
    /* this will catch any invalid compressed format token */
    if (!_mesa_is_compressed_format(ctx, format)) {
-      _mesa_error(ctx, GL_INVALID_ENUM,
-                  "%s(format)", callerName);
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(format)", callerName);
       return GL_TRUE;
    }
 
    if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
       return GL_TRUE;
    }
 
    if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "%s(level=%d)",
-                  callerName, level);
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level=%d)", callerName, level);
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
@@ -4414,43 +5318,36 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims,
 
    expectedSize = compressed_tex_size(width, height, depth, format);
    if (expectedSize != imageSize) {
 
    expectedSize = compressed_tex_size(width, height, depth, format);
    if (expectedSize != imageSize) {
-      _mesa_error(ctx, GL_INVALID_VALUE,
-                  "%s(size=%d)",
-                  callerName, imageSize);
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", callerName, imageSize);
       return GL_TRUE;
    }
 
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
       return GL_TRUE;
    }
 
    texImage = _mesa_select_tex_image(texObj, target, level);
    if (!texImage) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(invalid texture image)",
-                  callerName);
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture level %d)",
+                  callerName, level);
       return GL_TRUE;
    }
 
    if ((GLint) format != texImage->InternalFormat) {
       return GL_TRUE;
    }
 
    if ((GLint) format != texImage->InternalFormat) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(format=%s)",
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format=%s)",
                   callerName, _mesa_enum_to_string(format));
       return GL_TRUE;
    }
 
                   callerName, _mesa_enum_to_string(format));
       return GL_TRUE;
    }
 
-   if (compressedteximage_only_format(ctx, format)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "%s(format=%s cannot be updated)",
+   if (compressedteximage_only_format(format)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format=%s cannot be updated)",
                   callerName, _mesa_enum_to_string(format));
       return GL_TRUE;
    }
 
                   callerName, _mesa_enum_to_string(format));
       return GL_TRUE;
    }
 
-   if (error_check_subtexture_negative_dimensions(ctx, dims,
-                                                  width, height, depth,
-                                                  callerName)) {
+   if (error_check_subtexture_negative_dimensions(ctx, dims, width, height,
+                                                  depth, callerName)) {
       return GL_TRUE;
    }
 
       return GL_TRUE;
    }
 
-   if (error_check_subtexture_dimensions(ctx, dims,
-                                         texImage, xoffset, yoffset, zoffset,
-                                         width, height, depth,
+   if (error_check_subtexture_dimensions(ctx, dims, texImage, xoffset, yoffset,
+                                         zoffset, width, height, depth,
                                          callerName)) {
       return GL_TRUE;
    }
                                          callerName)) {
       return GL_TRUE;
    }
@@ -4466,8 +5363,46 @@ _mesa_CompressedTexImage1D(GLenum target, GLint level,
                               const GLvoid *data)
 {
    GET_CURRENT_CONTEXT(ctx);
                               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);
+   teximage_err(ctx, GL_TRUE, 1, target, level, internalFormat,
+                width, 1, 1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTextureImage1DEXT(GLuint texture, GLenum target, GLint level,
+                                  GLenum internalFormat, GLsizei width,
+                                  GLint border, GLsizei imageSize,
+                                  const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glCompressedTextureImage1DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 1, texObj, target, level, internalFormat,
+            width, 1, 1, border, GL_NONE, GL_NONE, imageSize, pixels, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexImage1DEXT(GLenum texunit, GLenum target, GLint level,
+                                   GLenum internalFormat, GLsizei width,
+                                   GLint border, GLsizei imageSize,
+                                   const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glCompressedMultiTexImage1DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 1, texObj, target, level, internalFormat,
+            width, 1, 1, border, GL_NONE, GL_NONE, imageSize, pixels, false);
 }
 
 
 }
 
 
@@ -4478,8 +5413,46 @@ _mesa_CompressedTexImage2D(GLenum target, GLint level,
                               const GLvoid *data)
 {
    GET_CURRENT_CONTEXT(ctx);
                               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);
+   teximage_err(ctx, GL_TRUE, 2, target, level, internalFormat,
+                width, height, 1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level,
+                                  GLenum internalFormat, GLsizei width,
+                                  GLsizei height, GLint border, GLsizei imageSize,
+                                  const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glCompressedTextureImage2DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 2, texObj, target, level, internalFormat,
+            width, height, 1, border, GL_NONE, GL_NONE, imageSize, pixels, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexImage2DEXT(GLenum texunit, GLenum target, GLint level,
+                                   GLenum internalFormat, GLsizei width,
+                                   GLsizei height, GLint border, GLsizei imageSize,
+                                   const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glCompressedMultiTexImage2DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 2, texObj, target, level, internalFormat,
+            width, height, 1, border, GL_NONE, GL_NONE, imageSize, pixels, false);
 }
 
 
 }
 
 
@@ -4490,8 +5463,82 @@ _mesa_CompressedTexImage3D(GLenum target, GLint level,
                               GLsizei imageSize, const GLvoid *data)
 {
    GET_CURRENT_CONTEXT(ctx);
                               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);
+   teximage_err(ctx, GL_TRUE, 3, target, level, internalFormat, width, height,
+                depth, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTextureImage3DEXT(GLuint texture, GLenum target, GLint level,
+                                  GLenum internalFormat, GLsizei width,
+                                  GLsizei height, GLsizei depth, GLint border,
+                                  GLsizei imageSize, const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_lookup_or_create_texture(ctx, target, texture, false, true,
+                                           "glCompressedTextureImage3DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 3, texObj, target, level, internalFormat,
+            width, height, depth, border, GL_NONE, GL_NONE, imageSize, pixels, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexImage3DEXT(GLenum texunit, GLenum target, GLint level,
+                                   GLenum internalFormat, GLsizei width,
+                                   GLsizei height, GLsizei depth, GLint border,
+                                   GLsizei imageSize, const GLvoid *pixels)
+{
+   struct gl_texture_object*  texObj;
+   GET_CURRENT_CONTEXT(ctx);
+
+   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                   texunit - GL_TEXTURE0,
+                                                   true,
+                                                   "glCompressedMultiTexImage3DEXT");
+   if (!texObj)
+      return;
+   teximage(ctx, GL_TRUE, 3, texObj, target, level, internalFormat,
+            width, height, depth, border, GL_NONE, GL_NONE, imageSize, pixels, false);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTexImage1D_no_error(GLenum target, GLint level,
+                                    GLenum internalFormat, GLsizei width,
+                                    GLint border, GLsizei imageSize,
+                                    const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_TRUE, 1, target, level, internalFormat, width, 1,
+                     1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTexImage2D_no_error(GLenum target, GLint level,
+                                    GLenum internalFormat, GLsizei width,
+                                    GLsizei height, GLint border,
+                                    GLsizei imageSize, const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_TRUE, 2, target, level, internalFormat, width,
+                     height, 1, border, GL_NONE, GL_NONE, imageSize, data);
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTexImage3D_no_error(GLenum target, GLint level,
+                                    GLenum internalFormat, GLsizei width,
+                                    GLsizei height, GLsizei depth, GLint border,
+                                    GLsizei imageSize, const GLvoid *data)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   teximage_no_error(ctx, GL_TRUE, 3, target, level, internalFormat, width,
+                     height, depth, border, GL_NONE, GL_NONE, imageSize, data);
 }
 
 
 }
 
 
@@ -4529,43 +5576,80 @@ compressed_texture_sub_image(struct gl_context *ctx, GLuint dims,
 }
 
 
 }
 
 
-static ALWAYS_INLINE void
-compressed_tex_sub_image(unsigned dim, GLenum target, GLuint texture,
+enum tex_mode {
+   /* Use bound texture to current unit */
+   TEX_MODE_CURRENT_NO_ERROR = 0,
+   TEX_MODE_CURRENT_ERROR,
+   /* Use the specified texture name */
+   TEX_MODE_DSA_NO_ERROR,
+   TEX_MODE_DSA_ERROR,
+   /* Use the specified texture name + target */
+   TEX_MODE_EXT_DSA_TEXTURE,
+   /* Use the specified texture unit + target */
+   TEX_MODE_EXT_DSA_TEXUNIT,
+};
+
+
+static void
+compressed_tex_sub_image(unsigned dim, GLenum target, GLuint textureOrIndex,
                          GLint level, GLint xoffset, GLint yoffset,
                          GLint zoffset, GLsizei width, GLsizei height,
                          GLsizei depth, GLenum format, GLsizei imageSize,
                          GLint level, GLint xoffset, GLint yoffset,
                          GLint zoffset, GLsizei width, GLsizei height,
                          GLsizei depth, GLenum format, GLsizei imageSize,
-                         const GLvoid *data, bool dsa, bool no_error,
+                         const GLvoid *data, enum tex_mode mode,
                          const char *caller)
 {
                          const char *caller)
 {
-   struct gl_texture_object *texObj;
+   struct gl_texture_object *texObj = NULL;
    struct gl_texture_image *texImage;
    struct gl_texture_image *texImage;
-
+   bool no_error = false;
    GET_CURRENT_CONTEXT(ctx);
 
    GET_CURRENT_CONTEXT(ctx);
 
-   if (dsa) {
-      if (no_error) {
-         texObj = _mesa_lookup_texture(ctx, texture);
-      } else {
-         texObj = _mesa_lookup_texture_err(ctx, texture, caller);
-         if (!texObj)
-            return;
-      }
-
-      target = texObj->Target;
+   switch (mode) {
+      case TEX_MODE_DSA_ERROR:
+         assert(target == 0);
+         texObj = _mesa_lookup_texture_err(ctx, textureOrIndex, caller);
+         if (texObj)
+            target = texObj->Target;
+         break;
+      case TEX_MODE_DSA_NO_ERROR:
+         assert(target == 0);
+         texObj = _mesa_lookup_texture(ctx, textureOrIndex);
+         if (texObj)
+            target = texObj->Target;
+         no_error = true;
+         break;
+      case TEX_MODE_EXT_DSA_TEXTURE:
+         texObj = _mesa_lookup_or_create_texture(ctx, target, textureOrIndex,
+                                                 false, true, caller);
+         break;
+      case TEX_MODE_EXT_DSA_TEXUNIT:
+         texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
+                                                         textureOrIndex,
+                                                         false,
+                                                         caller);
+         break;
+      case TEX_MODE_CURRENT_NO_ERROR:
+         no_error = true;
+      case TEX_MODE_CURRENT_ERROR:
+      default:
+         assert(textureOrIndex == 0);
+         break;
    }
 
    if (!no_error &&
    }
 
    if (!no_error &&
-       compressed_subtexture_target_check(ctx, target, dim, format, dsa,
+       compressed_subtexture_target_check(ctx, target, dim, format,
+                                          mode == TEX_MODE_DSA_ERROR,
                                           caller)) {
       return;
    }
 
                                           caller)) {
       return;
    }
 
-   if (!dsa) {
+   if (mode == TEX_MODE_CURRENT_NO_ERROR ||
+       mode == TEX_MODE_CURRENT_ERROR) {
       texObj = _mesa_get_current_tex_object(ctx, target);
       texObj = _mesa_get_current_tex_object(ctx, target);
-         if (!no_error && !texObj)
-            return;
    }
 
    }
 
+   if (!texObj)
+      return;
+
    if (!no_error &&
        compressed_subtexture_error_check(ctx, dim, texObj, target, level,
                                          xoffset, yoffset, zoffset, width,
    if (!no_error &&
        compressed_subtexture_error_check(ctx, dim, texObj, target, level,
                                          xoffset, yoffset, zoffset, width,
@@ -4575,7 +5659,9 @@ compressed_tex_sub_image(unsigned dim, GLenum target, GLuint texture,
    }
 
    /* Must handle special case GL_TEXTURE_CUBE_MAP. */
    }
 
    /* Must handle special case GL_TEXTURE_CUBE_MAP. */
-   if (dim == 3 && dsa && texObj->Target == GL_TEXTURE_CUBE_MAP) {
+   if (dim == 3 &&
+       (mode == TEX_MODE_DSA_ERROR || mode == TEX_MODE_DSA_NO_ERROR) &&
+       texObj->Target == GL_TEXTURE_CUBE_MAP) {
       const char *pixels = data;
       GLint image_stride;
 
       const char *pixels = data;
       GLint image_stride;
 
@@ -4590,13 +5676,13 @@ compressed_tex_sub_image(unsigned dim, GLenum target, GLuint texture,
       }
 
       /* Copy in each face. */
       }
 
       /* Copy in each face. */
-      for (int i = 0; i < 6; ++i) {
+      for (int i = zoffset; i < zoffset + depth; ++i) {
          texImage = texObj->Image[i][level];
          assert(texImage);
 
          compressed_texture_sub_image(ctx, 3, texObj, texImage,
                                       texObj->Target, level, xoffset, yoffset,
          texImage = texObj->Image[i][level];
          assert(texImage);
 
          compressed_texture_sub_image(ctx, 3, texObj, texImage,
                                       texObj->Target, level, xoffset, yoffset,
-                                      zoffset, width, height, 1, format,
+                                      0, width, height, 1, format,
                                       imageSize, pixels);
 
          /* Compressed images don't have a client format */
                                       imageSize, pixels);
 
          /* Compressed images don't have a client format */
@@ -4624,8 +5710,10 @@ _mesa_CompressedTexSubImage1D_no_error(GLenum target, GLint level,
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
-   compressed_tex_sub_image(1, target, 0, level, xoffset, 0, 0, width,
-                            1, 1, format, imageSize, data, false, true,
+   compressed_tex_sub_image(1, target, 0,
+                            level, xoffset, 0, 0, width,
+                            1, 1, format, imageSize, data,
+                            TEX_MODE_CURRENT_NO_ERROR,
                             "glCompressedTexSubImage1D");
 }
 
                             "glCompressedTexSubImage1D");
 }
 
@@ -4635,8 +5723,10 @@ _mesa_CompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset,
                               GLsizei width, GLenum format,
                               GLsizei imageSize, const GLvoid *data)
 {
                               GLsizei width, GLenum format,
                               GLsizei imageSize, const GLvoid *data)
 {
-   compressed_tex_sub_image(1, target, 0, level, xoffset, 0, 0, width, 1, 1,
-                            format, imageSize, data, false, false,
+   compressed_tex_sub_image(1, target, 0,
+                            level, xoffset, 0, 0, width,
+                            1, 1, format, imageSize, data,
+                            TEX_MODE_CURRENT_ERROR,
                             "glCompressedTexSubImage1D");
 }
 
                             "glCompressedTexSubImage1D");
 }
 
@@ -4647,8 +5737,10 @@ _mesa_CompressedTextureSubImage1D_no_error(GLuint texture, GLint level,
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
-   compressed_tex_sub_image(1, 0, texture, level, xoffset, 0, 0, width, 1, 1,
-                            format, imageSize, data, true, true,
+   compressed_tex_sub_image(1, 0, texture,
+                            level, xoffset, 0, 0,
+                            width, 1, 1, format, imageSize, data,
+                            TEX_MODE_DSA_NO_ERROR,
                             "glCompressedTextureSubImage1D");
 }
 
                             "glCompressedTextureSubImage1D");
 }
 
@@ -4658,11 +5750,42 @@ _mesa_CompressedTextureSubImage1D(GLuint texture, GLint level, GLint xoffset,
                                   GLsizei width, GLenum format,
                                   GLsizei imageSize, const GLvoid *data)
 {
                                   GLsizei width, GLenum format,
                                   GLsizei imageSize, const GLvoid *data)
 {
-   compressed_tex_sub_image(1, 0, texture, level, xoffset, 0, 0, width, 1, 1,
-                            format, imageSize, data, true, false,
+   compressed_tex_sub_image(1, 0, texture,
+                            level, xoffset, 0, 0,
+                            width, 1, 1, format, imageSize, data,
+                            TEX_MODE_DSA_ERROR,
                             "glCompressedTextureSubImage1D");
 }
 
                             "glCompressedTextureSubImage1D");
 }
 
+
+void GLAPIENTRY
+_mesa_CompressedTextureSubImage1DEXT(GLuint texture, GLenum target,
+                                     GLint level, GLint xoffset,
+                                     GLsizei width, GLenum format,
+                                     GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(1, target, texture, level, xoffset, 0,
+                            0, width, 1, 1, format, imageSize,
+                            data,
+                            TEX_MODE_EXT_DSA_TEXTURE,
+                            "glCompressedTextureSubImage1DEXT");
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexSubImage1DEXT(GLenum texunit, GLenum target,
+                                      GLint level, GLint xoffset,
+                                      GLsizei width, GLenum format,
+                                      GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(1, target, texunit - GL_TEXTURE0, level,
+                            xoffset, 0, 0, width, 1, 1, format, imageSize,
+                            data,
+                            TEX_MODE_EXT_DSA_TEXUNIT,
+                            "glCompressedMultiTexSubImage1DEXT");
+}
+
+
 void GLAPIENTRY
 _mesa_CompressedTexSubImage2D_no_error(GLenum target, GLint level,
                                        GLint xoffset, GLint yoffset,
 void GLAPIENTRY
 _mesa_CompressedTexSubImage2D_no_error(GLenum target, GLint level,
                                        GLint xoffset, GLint yoffset,
@@ -4670,8 +5793,10 @@ _mesa_CompressedTexSubImage2D_no_error(GLenum target, GLint level,
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
-   compressed_tex_sub_image(2, target, 0, level, xoffset, yoffset, 0, width,
-                            height, 1, format, imageSize, data, false, true,
+   compressed_tex_sub_image(2, target, 0, level,
+                            xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data,
+                            TEX_MODE_CURRENT_NO_ERROR,
                             "glCompressedTexSubImage2D");
 }
 
                             "glCompressedTexSubImage2D");
 }
 
@@ -4682,12 +5807,43 @@ _mesa_CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
                               GLenum format, GLsizei imageSize,
                               const GLvoid *data)
 {
                               GLenum format, GLsizei imageSize,
                               const GLvoid *data)
 {
-   compressed_tex_sub_image(2, target, 0, level, xoffset, yoffset, 0, width,
-                            height, 1, format, imageSize, data, false, false,
+   compressed_tex_sub_image(2, target, 0, level,
+                            xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data,
+                            TEX_MODE_CURRENT_ERROR,
                             "glCompressedTexSubImage2D");
 }
 
 
                             "glCompressedTexSubImage2D");
 }
 
 
+void GLAPIENTRY
+_mesa_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target,
+                                     GLint level, GLint xoffset,
+                                     GLint yoffset, GLsizei width,
+                                     GLsizei height, GLenum format,
+                                     GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(2, target, texture, level, xoffset,
+                            yoffset, 0, width, height, 1, format,
+                            imageSize, data,
+                            TEX_MODE_EXT_DSA_TEXTURE,
+                            "glCompressedTextureSubImage2DEXT");
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexSubImage2DEXT(GLenum texunit, GLenum target,
+                                      GLint level, GLint xoffset, GLint yoffset,
+                                      GLsizei width, GLsizei height, GLenum format,
+                                      GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(2, target, texunit - GL_TEXTURE0, level,
+                            xoffset, yoffset, 0, width, height, 1, format,
+                            imageSize, data,
+                            TEX_MODE_EXT_DSA_TEXUNIT,
+                            "glCompressedMultiTexSubImage2DEXT");
+}
+
+
 void GLAPIENTRY
 _mesa_CompressedTextureSubImage2D_no_error(GLuint texture, GLint level,
                                            GLint xoffset, GLint yoffset,
 void GLAPIENTRY
 _mesa_CompressedTextureSubImage2D_no_error(GLuint texture, GLint level,
                                            GLint xoffset, GLint yoffset,
@@ -4695,8 +5851,9 @@ _mesa_CompressedTextureSubImage2D_no_error(GLuint texture, GLint level,
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
-   compressed_tex_sub_image(2, 0, texture, level, xoffset, yoffset, 0, width,
-                            height, 1, format, imageSize, data, true, true,
+   compressed_tex_sub_image(2, 0, texture, level, xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data,
+                            TEX_MODE_DSA_NO_ERROR,
                             "glCompressedTextureSubImage2D");
 }
 
                             "glCompressedTextureSubImage2D");
 }
 
@@ -4708,8 +5865,9 @@ _mesa_CompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset,
                                   GLenum format, GLsizei imageSize,
                                   const GLvoid *data)
 {
                                   GLenum format, GLsizei imageSize,
                                   const GLvoid *data)
 {
-   compressed_tex_sub_image(2, 0, texture, level, xoffset, yoffset, 0, width,
-                            height, 1, format, imageSize, data, true, false,
+   compressed_tex_sub_image(2, 0, texture, level, xoffset, yoffset, 0,
+                            width, height, 1, format, imageSize, data,
+                            TEX_MODE_DSA_ERROR,
                             "glCompressedTextureSubImage2D");
 }
 
                             "glCompressedTextureSubImage2D");
 }
 
@@ -4721,9 +5879,11 @@ _mesa_CompressedTexSubImage3D_no_error(GLenum target, GLint level,
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
                                        GLenum format, GLsizei imageSize,
                                        const GLvoid *data)
 {
-   compressed_tex_sub_image(3, target, 0, level, xoffset, yoffset, zoffset,
-                            width, height, depth, format, imageSize, data,
-                            false, true, "glCompressedTexSubImage3D");
+   compressed_tex_sub_image(3, target, 0, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format,
+                            imageSize, data,
+                            TEX_MODE_CURRENT_NO_ERROR,
+                            "glCompressedTexSubImage3D");
 }
 
 void GLAPIENTRY
 }
 
 void GLAPIENTRY
@@ -4732,9 +5892,11 @@ _mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset,
                               GLsizei height, GLsizei depth, GLenum format,
                               GLsizei imageSize, const GLvoid *data)
 {
                               GLsizei height, GLsizei depth, GLenum format,
                               GLsizei imageSize, const GLvoid *data)
 {
-   compressed_tex_sub_image(3, target, 0, level, xoffset, yoffset, zoffset,
-                            width, height, depth, format, imageSize, data,
-                            false, false, "glCompressedTexSubImage3D");
+   compressed_tex_sub_image(3, target, 0, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format,
+                            imageSize, data,
+                            TEX_MODE_CURRENT_ERROR,
+                            "glCompressedTexSubImage3D");
 }
 
 void GLAPIENTRY
 }
 
 void GLAPIENTRY
@@ -4745,9 +5907,11 @@ _mesa_CompressedTextureSubImage3D_no_error(GLuint texture, GLint level,
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
                                            GLenum format, GLsizei imageSize,
                                            const GLvoid *data)
 {
-   compressed_tex_sub_image(3, 0, texture, level, xoffset, yoffset, zoffset,
-                            width, height, depth, format, imageSize, data,
-                            true, true, "glCompressedTextureSubImage3D");
+   compressed_tex_sub_image(3, 0, texture, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format,
+                            imageSize, data,
+                            TEX_MODE_DSA_NO_ERROR,
+                            "glCompressedTextureSubImage3D");
 }
 
 void GLAPIENTRY
 }
 
 void GLAPIENTRY
@@ -4757,13 +5921,47 @@ _mesa_CompressedTextureSubImage3D(GLuint texture, GLint level, GLint xoffset,
                                   GLenum format, GLsizei imageSize,
                                   const GLvoid *data)
 {
                                   GLenum format, GLsizei imageSize,
                                   const GLvoid *data)
 {
-   compressed_tex_sub_image(3, 0, texture, level, xoffset, yoffset, zoffset,
-                            width, height, depth, format, imageSize, data,
-                            true, false, "glCompressedTextureSubImage3D");
+   compressed_tex_sub_image(3, 0, texture, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format,
+                            imageSize, data,
+                            TEX_MODE_DSA_ERROR,
+                            "glCompressedTextureSubImage3D");
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedTextureSubImage3DEXT(GLuint texture, GLenum target,
+                                     GLint level, GLint xoffset,
+                                     GLint yoffset, GLint zoffset,
+                                     GLsizei width, GLsizei height,
+                                     GLsizei depth, GLenum format,
+                                     GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(3, target, texture, level, xoffset, yoffset,
+                            zoffset, width, height, depth, format,
+                            imageSize, data,
+                            TEX_MODE_EXT_DSA_TEXTURE,
+                            "glCompressedTextureSubImage3DEXT");
+}
+
+
+void GLAPIENTRY
+_mesa_CompressedMultiTexSubImage3DEXT(GLenum texunit, GLenum target,
+                                      GLint level, GLint xoffset, GLint yoffset,
+                                      GLint zoffset, GLsizei width, GLsizei height,
+                                      GLsizei depth, GLenum format,
+                                      GLsizei imageSize, const GLvoid *data)
+{
+   compressed_tex_sub_image(3, target, texunit - GL_TEXTURE0, level,
+                            xoffset, yoffset, zoffset, width, height, depth,
+                            format, imageSize, data,
+                            TEX_MODE_EXT_DSA_TEXUNIT,
+                            "glCompressedMultiTexSubImage3DEXT");
 }
 
 }
 
-static mesa_format
-get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
+
+mesa_format
+_mesa_get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
 {
    if (ctx->API == API_OPENGL_COMPAT) {
       switch (internalFormat) {
 {
    if (ctx->API == API_OPENGL_COMPAT) {
       switch (internalFormat) {
@@ -4870,7 +6068,7 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
    case GL_RGBA8:
       return MESA_FORMAT_R8G8B8A8_UNORM;
    case GL_RGBA16:
    case GL_RGBA8:
       return MESA_FORMAT_R8G8B8A8_UNORM;
    case GL_RGBA16:
-      if (_mesa_is_gles(ctx))
+      if (_mesa_is_gles(ctx) && !_mesa_has_EXT_texture_norm16(ctx))
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_RGBA_UNORM16;
    case GL_RGBA16F_ARB:
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_RGBA_UNORM16;
    case GL_RGBA16F_ARB:
@@ -4893,7 +6091,7 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
    case GL_RG8:
       return MESA_FORMAT_R8G8_UNORM;
    case GL_RG16:
    case GL_RG8:
       return MESA_FORMAT_R8G8_UNORM;
    case GL_RG16:
-      if (_mesa_is_gles(ctx))
+      if (_mesa_is_gles(ctx) && !_mesa_has_EXT_texture_norm16(ctx))
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_R16G16_UNORM;
    case GL_RG16F:
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_R16G16_UNORM;
    case GL_RG16F:
@@ -4916,7 +6114,7 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
    case GL_R8:
       return MESA_FORMAT_R_UNORM8;
    case GL_R16:
    case GL_R8:
       return MESA_FORMAT_R_UNORM8;
    case GL_R16:
-      if (_mesa_is_gles(ctx))
+      if (_mesa_is_gles(ctx) && !_mesa_has_EXT_texture_norm16(ctx))
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_R_UNORM16;
    case GL_R16F:
          return MESA_FORMAT_NONE;
       return MESA_FORMAT_R_UNORM16;
    case GL_R16F:
@@ -4946,7 +6144,7 @@ mesa_format
 _mesa_validate_texbuffer_format(const struct gl_context *ctx,
                                 GLenum internalFormat)
 {
 _mesa_validate_texbuffer_format(const struct gl_context *ctx,
                                 GLenum internalFormat)
 {
-   mesa_format format = get_texbuffer_format(ctx, internalFormat);
+   mesa_format format = _mesa_get_texbuffer_format(ctx, internalFormat);
    GLenum datatype;
 
    if (format == MESA_FORMAT_NONE)
    GLenum datatype;
 
    if (format == MESA_FORMAT_NONE)
@@ -4998,8 +6196,8 @@ texture_buffer_range(struct gl_context *ctx,
    GLsizeiptr oldSize = texObj->BufferSize;
    mesa_format format;
 
    GLsizeiptr oldSize = texObj->BufferSize;
    mesa_format format;
 
-   /* NOTE: ARB_texture_buffer_object has interactions with
-    * the compatibility profile that are not implemented.
+   /* NOTE: ARB_texture_buffer_object might not be supported in
+    * the compatibility profile.
     */
    if (!_mesa_has_ARB_texture_buffer_object(ctx) &&
        !_mesa_has_OES_texture_buffer(ctx)) {
     */
    if (!_mesa_has_ARB_texture_buffer_object(ctx) &&
        !_mesa_has_OES_texture_buffer(ctx)) {
@@ -5009,6 +6207,18 @@ texture_buffer_range(struct gl_context *ctx,
       return;
    }
 
       return;
    }
 
+   if (texObj->HandleAllocated) {
+      /* The ARB_bindless_texture spec says:
+       *
+       * "The error INVALID_OPERATION is generated by TexImage*, CopyTexImage*,
+       *  CompressedTexImage*, TexBuffer*, TexParameter*, as well as other
+       *  functions defined in terms of these, if the texture object to be
+       *  modified is referenced by one or more texture or image handles."
+       */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable texture)", caller);
+      return;
+   }
+
    format = _mesa_validate_texbuffer_format(ctx, internalFormat);
    if (format == MESA_FORMAT_NONE) {
       _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat %s)",
    format = _mesa_validate_texbuffer_format(ctx, internalFormat);
    if (format == MESA_FORMAT_NONE) {
       _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat %s)",
@@ -5264,7 +6474,8 @@ _mesa_TextureBufferRange(GLuint texture, GLenum internalFormat, GLuint buffer,
 }
 
 GLboolean
 }
 
 GLboolean
-_mesa_is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat)
+_mesa_is_renderable_texture_format(const struct gl_context *ctx,
+                                   GLenum internalformat)
 {
    /* Everything that is allowed for renderbuffers,
     * except for a base format of GL_STENCIL_INDEX, unless supported.
 {
    /* Everything that is allowed for renderbuffers,
     * except for a base format of GL_STENCIL_INDEX, unless supported.
@@ -5299,11 +6510,13 @@ check_multisample_target(GLuint dims, GLenum target, bool dsa)
 static void
 texture_image_multisample(struct gl_context *ctx, GLuint dims,
                           struct gl_texture_object *texObj,
 static void
 texture_image_multisample(struct gl_context *ctx, GLuint dims,
                           struct gl_texture_object *texObj,
+                          struct gl_memory_object *memObj,
                           GLenum target, GLsizei samples,
                           GLint internalformat, GLsizei width,
                           GLsizei height, GLsizei depth,
                           GLboolean fixedsamplelocations,
                           GLenum target, GLsizei samples,
                           GLint internalformat, GLsizei width,
                           GLsizei height, GLsizei depth,
                           GLboolean fixedsamplelocations,
-                          GLboolean immutable, const char *func)
+                          GLboolean immutable, GLuint64 offset,
+                          const char *func)
 {
    struct gl_texture_image *texImage;
    GLboolean sizeOK, dimensionsOK, samplesOK;
 {
    struct gl_texture_image *texImage;
    GLboolean sizeOK, dimensionsOK, samplesOK;
@@ -5328,14 +6541,10 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
    }
 
    if (!check_multisample_target(dims, target, dsa)) {
    }
 
    if (!check_multisample_target(dims, target, dsa)) {
-      if (dsa) {
-         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(target)", func);
-         return;
-      }
-      else {
-         _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
-         return;
-      }
+      GLenum err = dsa ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
+      _mesa_error(ctx, err, "%s(target=%s)", func,
+                  _mesa_enum_to_string(target));
+      return;
    }
 
    /* check that the specified internalformat is color/depth/stencil-renderable;
    }
 
    /* check that the specified internalformat is color/depth/stencil-renderable;
@@ -5364,7 +6573,7 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
    }
 
    sample_count_error = _mesa_check_sample_count(ctx, target,
    }
 
    sample_count_error = _mesa_check_sample_count(ctx, target,
-         internalformat, samples);
+         internalformat, samples, samples);
    samplesOK = sample_count_error == GL_NO_ERROR;
 
    /* Page 254 of OpenGL 4.4 spec says:
    samplesOK = sample_count_error == GL_NO_ERROR;
 
    /* Page 254 of OpenGL 4.4 spec says:
@@ -5376,7 +6585,7 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
     *    However, if samples is not supported, then no error is generated.
     */
    if (!samplesOK && !_mesa_is_proxy_texture(target)) {
     *    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);
+      _mesa_error(ctx, sample_count_error, "%s(samples=%d)", func, samples);
       return;
    }
 
       return;
    }
 
@@ -5406,9 +6615,9 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
 
    if (_mesa_is_proxy_texture(target)) {
       if (samplesOK && dimensionsOK && sizeOK) {
 
    if (_mesa_is_proxy_texture(target)) {
       if (samplesOK && dimensionsOK && sizeOK) {
-         init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
-                                 internalformat, texFormat,
-                                 samples, fixedsamplelocations);
+         _mesa_init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
+                                       internalformat, texFormat,
+                                       samples, fixedsamplelocations);
       }
       else {
          /* clear all image fields */
       }
       else {
          /* clear all image fields */
@@ -5418,7 +6627,7 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
    else {
       if (!dimensionsOK) {
          _mesa_error(ctx, GL_INVALID_VALUE,
    else {
       if (!dimensionsOK) {
          _mesa_error(ctx, GL_INVALID_VALUE,
-                     "%s(invalid width or height)", func);
+                     "%s(invalid width=%d or height=%d)", func, width, height);
          return;
       }
 
          return;
       }
 
@@ -5435,19 +6644,30 @@ texture_image_multisample(struct gl_context *ctx, GLuint dims,
 
       ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
 
       ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
 
-      init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
-                              internalformat, texFormat,
-                              samples, fixedsamplelocations);
+      _mesa_init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
+                                    internalformat, texFormat,
+                                    samples, fixedsamplelocations);
 
       if (width > 0 && height > 0 && depth > 0) {
 
       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);
+         if (memObj) {
+            if (!ctx->Driver.SetTextureStorageForMemoryObject(ctx, texObj,
+                                                              memObj, 1, width,
+                                                              height, depth,
+                                                              offset)) {
+
+               _mesa_init_teximage_fields(ctx, texImage, 0, 0, 0, 0,
+                                          internalformat, texFormat);
+            }
+         } else {
+            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,
+                                          internalformat, texFormat);
+            }
          }
       }
 
          }
       }
 
@@ -5474,9 +6694,9 @@ _mesa_TexImage2DMultisample(GLenum target, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   texture_image_multisample(ctx, 2, texObj, target, samples,
+   texture_image_multisample(ctx, 2, texObj, NULL, target, samples,
                              internalformat, width, height, 1,
                              internalformat, width, height, 1,
-                             fixedsamplelocations, GL_FALSE,
+                             fixedsamplelocations, GL_FALSE, 0,
                              "glTexImage2DMultisample");
 }
 
                              "glTexImage2DMultisample");
 }
 
@@ -5494,15 +6714,15 @@ _mesa_TexImage3DMultisample(GLenum target, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   texture_image_multisample(ctx, 3, texObj, target, samples,
+   texture_image_multisample(ctx, 3, texObj, NULL, target, samples,
                              internalformat, width, height, depth,
                              internalformat, width, height, depth,
-                             fixedsamplelocations, GL_FALSE,
+                             fixedsamplelocations, GL_FALSE, 0,
                              "glTexImage3DMultisample");
 }
 
 static bool
 valid_texstorage_ms_parameters(GLsizei width, GLsizei height, GLsizei depth,
                              "glTexImage3DMultisample");
 }
 
 static bool
 valid_texstorage_ms_parameters(GLsizei width, GLsizei height, GLsizei depth,
-                               GLsizei samples, unsigned dims)
+                               unsigned dims)
 {
    GET_CURRENT_CONTEXT(ctx);
 
 {
    GET_CURRENT_CONTEXT(ctx);
 
@@ -5527,12 +6747,12 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   if (!valid_texstorage_ms_parameters(width, height, 1, samples, 2))
+   if (!valid_texstorage_ms_parameters(width, height, 1, 2))
       return;
 
       return;
 
-   texture_image_multisample(ctx, 2, texObj, target, samples,
+   texture_image_multisample(ctx, 2, texObj, NULL, target, samples,
                              internalformat, width, height, 1,
                              internalformat, width, height, 1,
-                             fixedsamplelocations, GL_TRUE,
+                             fixedsamplelocations, GL_TRUE, 0,
                              "glTexStorage2DMultisample");
 }
 
                              "glTexStorage2DMultisample");
 }
 
@@ -5549,12 +6769,12 @@ _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   if (!valid_texstorage_ms_parameters(width, height, depth, samples, 3))
+   if (!valid_texstorage_ms_parameters(width, height, depth, 3))
       return;
 
       return;
 
-   texture_image_multisample(ctx, 3, texObj, target, samples,
+   texture_image_multisample(ctx, 3, texObj, NULL, target, samples,
                              internalformat, width, height, depth,
                              internalformat, width, height, depth,
-                             fixedsamplelocations, GL_TRUE,
+                             fixedsamplelocations, GL_TRUE, 0,
                              "glTexStorage3DMultisample");
 }
 
                              "glTexStorage3DMultisample");
 }
 
@@ -5572,12 +6792,12 @@ _mesa_TextureStorage2DMultisample(GLuint texture, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   if (!valid_texstorage_ms_parameters(width, height, 1, samples, 2))
+   if (!valid_texstorage_ms_parameters(width, height, 1, 2))
       return;
 
       return;
 
-   texture_image_multisample(ctx, 2, texObj, texObj->Target, samples,
-                             internalformat, width, height, 1,
-                             fixedsamplelocations, GL_TRUE,
+   texture_image_multisample(ctx, 2, texObj, NULL, texObj->Target,
+                             samples, internalformat, width, height, 1,
+                             fixedsamplelocations, GL_TRUE, 0,
                              "glTextureStorage2DMultisample");
 }
 
                              "glTextureStorage2DMultisample");
 }
 
@@ -5596,11 +6816,29 @@ _mesa_TextureStorage3DMultisample(GLuint texture, GLsizei samples,
    if (!texObj)
       return;
 
    if (!texObj)
       return;
 
-   if (!valid_texstorage_ms_parameters(width, height, depth, samples, 3))
+   if (!valid_texstorage_ms_parameters(width, height, depth, 3))
       return;
 
       return;
 
-   texture_image_multisample(ctx, 3, texObj, texObj->Target, samples,
+   texture_image_multisample(ctx, 3, texObj, NULL, texObj->Target, samples,
                              internalformat, width, height, depth,
                              internalformat, width, height, depth,
-                             fixedsamplelocations, GL_TRUE,
+                             fixedsamplelocations, GL_TRUE, 0,
                              "glTextureStorage3DMultisample");
 }
                              "glTextureStorage3DMultisample");
 }
+
+void
+_mesa_texture_storage_ms_memory(struct gl_context *ctx, GLuint dims,
+                                struct gl_texture_object *texObj,
+                                struct gl_memory_object *memObj,
+                                GLenum target, GLsizei samples,
+                                GLenum internalFormat, GLsizei width,
+                                GLsizei height, GLsizei depth,
+                                GLboolean fixedSampleLocations,
+                                GLuint64 offset, const char* func)
+{
+   assert(memObj);
+
+   texture_image_multisample(ctx, dims, texObj, memObj, target, samples,
+                             internalFormat, width, height, depth,
+                             fixedSampleLocations, GL_TRUE, offset,
+                             func);
+}