add a number of PBO validate/map/unmap functions
[mesa.git] / src / mesa / main / teximage.c
index 706d3466955b0e6d20d8f2269656fb589acffe3b..384e1455203c3185d79a7c3ec0c869ca9bbcdcc5 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.1
+ * Version:  7.1
  *
- * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -595,8 +595,12 @@ is_compressed_format(GLcontext *ctx, GLenum internalFormat)
 }
 
 
-static GLuint
-texture_face(GLenum target)
+/**
+ * For cube map faces, return a face index in [0,5].
+ * For other targets return 0;
+ */
+GLuint
+_mesa_tex_target_to_face(GLenum target)
 {
    if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)
@@ -625,10 +629,13 @@ _mesa_set_tex_image(struct gl_texture_object *tObj,
 {
    ASSERT(tObj);
    ASSERT(texImage);
+   /* XXX simplify this with _mesa_tex_target_to_face() */
    switch (target) {
       case GL_TEXTURE_1D:
       case GL_TEXTURE_2D:
       case GL_TEXTURE_3D:
+      case GL_TEXTURE_1D_ARRAY_EXT:
+      case GL_TEXTURE_2D_ARRAY_EXT:
          tObj->Image[0][level] = texImage;
          break;
       case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
@@ -733,7 +740,9 @@ _mesa_is_proxy_texture(GLenum target)
            target == GL_PROXY_TEXTURE_2D ||
            target == GL_PROXY_TEXTURE_3D ||
            target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
-           target == GL_PROXY_TEXTURE_RECTANGLE_NV);
+           target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
+           target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
+           target == GL_PROXY_TEXTURE_2D_ARRAY_EXT);
 }
 
 
@@ -783,6 +792,18 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
       case GL_PROXY_TEXTURE_RECTANGLE_NV:
          return ctx->Extensions.NV_texture_rectangle
                 ? ctx->Texture.ProxyRect : NULL;
+      case GL_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? texUnit->Current1DArray : NULL;
+      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? ctx->Texture.Proxy1DArray : NULL;
+      case GL_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? texUnit->Current2DArray : NULL;
+      case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array
+                ? ctx->Texture.Proxy2DArray : NULL;
       default:
          _mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
          return NULL;
@@ -812,6 +833,7 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) 
       return NULL;
 
+   /* XXX simplify this with _mesa_tex_target_to_face() */
    switch (target) {
       case GL_TEXTURE_1D:
       case GL_PROXY_TEXTURE_1D:
@@ -848,6 +870,13 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
          else 
             return NULL;
 
+      case GL_TEXTURE_1D_ARRAY_EXT:
+      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+      case GL_TEXTURE_2D_ARRAY_EXT:
+      case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+         return (ctx->Extensions.MESA_texture_array)
+            ? texObj->Image[0][level] : NULL;
+
       default:
          return NULL;
    }
@@ -973,6 +1002,36 @@ _mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level)
          texImage->TexObject = ctx->Texture.ProxyRect;
       }
       return texImage;
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+      if (level >= ctx->Const.MaxTextureLevels)
+         return NULL;
+      texImage = ctx->Texture.Proxy1DArray->Image[0][level];
+      if (!texImage) {
+         texImage = ctx->Driver.NewTextureImage(ctx);
+         if (!texImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
+            return NULL;
+         }
+         ctx->Texture.Proxy1DArray->Image[0][level] = texImage;
+         /* Set the 'back' pointer */
+         texImage->TexObject = ctx->Texture.Proxy1DArray;
+      }
+      return texImage;
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+      if (level >= ctx->Const.MaxTextureLevels)
+         return NULL;
+      texImage = ctx->Texture.Proxy2DArray->Image[0][level];
+      if (!texImage) {
+         texImage = ctx->Driver.NewTextureImage(ctx);
+         if (!texImage) {
+            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
+            return NULL;
+         }
+         ctx->Texture.Proxy2DArray->Image[0][level] = texImage;
+         /* Set the 'back' pointer */
+         texImage->TexObject = ctx->Texture.Proxy2DArray;
+      }
+      return texImage;
    default:
       return NULL;
    }
@@ -998,6 +1057,10 @@ _mesa_max_texture_levels(GLcontext *ctx, GLenum target)
    case GL_PROXY_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
+   case GL_TEXTURE_1D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+   case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       return ctx->Const.MaxTextureLevels;
    case GL_TEXTURE_3D:
    case GL_PROXY_TEXTURE_3D:
@@ -1151,19 +1214,30 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
    img->Width = width;
    img->Height = height;
    img->Depth = depth;
+
    img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
-   img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
-   img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
    img->WidthLog2 = logbase2(img->Width2);
-   if (height == 1)  /* 1-D texture */
+
+   if (height == 1) { /* 1-D texture */
+      img->Height2 = 1;
       img->HeightLog2 = 0;
-   else
+   }
+   else {
+      img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
       img->HeightLog2 = logbase2(img->Height2);
-   if (depth == 1)   /* 2-D texture */
+   }
+
+   if (depth == 1) {  /* 2-D texture */
+      img->Depth2 = 1;
       img->DepthLog2 = 0;
-   else
+   }
+   else {
+      img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
       img->DepthLog2 = logbase2(img->Depth2);
+   }
+
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
+
    img->IsCompressed = GL_FALSE;
    img->CompressedSize = 0;
 
@@ -1207,6 +1281,10 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
  * A hardware driver might override this function if, for example, the
  * max 3D texture size is 512x512x64 (i.e. not a cube).
  *
+ * Note that width, height, depth == 0 is not an error.  However, a
+ * texture with zero width/height/depth will be considered "incomplete"
+ * and texturing will effectively be disabled.
+ *
  * \param target  one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D,
  *                GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV,
  *                GL_PROXY_TEXTURE_CUBE_MAP_ARB.
@@ -1236,7 +1314,7 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width >0 && _mesa_bitcount(width - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or level */
          return GL_FALSE;
@@ -1246,10 +1324,10 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or height or level */
          return GL_FALSE;
@@ -1259,21 +1337,21 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           depth < 2 * border || depth > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(depth - 2 * border) != 1) ||
+           depth > 0 && _mesa_bitcount(depth - 2 * border) != 1) ||
           level >= ctx->Const.Max3DTextureLevels) {
          /* bad width or height or depth or level */
          return GL_FALSE;
       }
       return GL_TRUE;
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      if (width < 1 || width > ctx->Const.MaxTextureRectSize ||
-          height < 1 || height > ctx->Const.MaxTextureRectSize ||
+      if (width < 0 || width > ctx->Const.MaxTextureRectSize ||
+          height < 0 || height > ctx->Const.MaxTextureRectSize ||
           level != 0) {
          /* bad width or height or level */
          return GL_FALSE;
@@ -1283,15 +1361,45 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(width - 2 * border) != 1) ||
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
           (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           _mesa_bitcount(height - 2 * border) != 1) ||
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxCubeTextureLevels) {
          /* bad width or height */
          return GL_FALSE;
       }
       return GL_TRUE;
+   case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
+      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
+      if (width < 2 * border || width > 2 + maxSize ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
+          level >= ctx->Const.MaxTextureLevels) {
+         /* bad width or level */
+         return GL_FALSE;
+      }
+
+      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) {
+         return GL_FALSE;
+      }
+      return GL_TRUE;
+   case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
+      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
+      if (width < 2 * border || width > 2 + maxSize ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
+          height < 2 * border || height > 2 + maxSize ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
+          level >= ctx->Const.MaxTextureLevels) {
+         /* bad width or height or level */
+         return GL_FALSE;
+      }
+      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) {
+         return GL_FALSE;
+      }
+      return GL_TRUE;
    default:
       _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
       return GL_FALSE;
@@ -1299,6 +1407,23 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
 }
 
 
+/**
+ * Helper function to determine whether a target supports compressed textures
+ */
+static GLboolean
+target_can_be_compressed(GLcontext *ctx, GLenum target)
+{
+   return (((target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D))
+           || ((ctx->Extensions.ARB_texture_cube_map &&
+                (target == GL_PROXY_TEXTURE_CUBE_MAP ||
+                 (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
+                  target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))))
+           || ((ctx->Extensions.MESA_texture_array &&
+                ((target == GL_PROXY_TEXTURE_2D_ARRAY_EXT) ||
+                 (target == GL_TEXTURE_2D_ARRAY_EXT)))));
+}
+
+
 /**
  * Test the glTexImage[123]D() parameters for errors.
  * 
@@ -1329,8 +1454,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
                      GLint depth, GLint border )
 {
    const GLboolean isProxy = _mesa_is_proxy_texture(target);
-   GLboolean sizeOK;
+   GLboolean sizeOK = GL_TRUE;
    GLboolean colorFormat, indexFormat;
+   GLenum proxy_target;
 
    /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
    if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
@@ -1365,10 +1491,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
     */
    if (dimensions == 1) {
       if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_1D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, 1, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_1D;
+         height = 1;
+         depth = 1;
       }
       else {
          _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
@@ -1376,11 +1501,9 @@ texture_error_check( GLcontext *ctx, GLenum target,
       }
    }
    else if (dimensions == 2) {
+      depth = 1;
       if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_2D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_2D;
       }
       else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
                (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
@@ -1389,10 +1512,8 @@ texture_error_check( GLcontext *ctx, GLenum target,
             _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
             return GL_TRUE;
          }
-         sizeOK = (width == height) &&
-            ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_CUBE_MAP_ARB,
-                                          level, internalFormat, format, type,
-                                          width, height, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
+         sizeOK = (width == height);
       }
       else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
                target == GL_TEXTURE_RECTANGLE_NV) {
@@ -1400,11 +1521,11 @@ texture_error_check( GLcontext *ctx, GLenum target,
             _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
             return GL_TRUE;
          }
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
-                                                GL_PROXY_TEXTURE_RECTANGLE_NV,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, 1, border);
+         proxy_target = GL_PROXY_TEXTURE_RECTANGLE_NV;
+      }
+      else if (target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
+               target == GL_TEXTURE_1D_ARRAY_EXT) {
+         proxy_target = GL_PROXY_TEXTURE_1D_ARRAY_EXT;
       }
       else {
          _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
@@ -1413,10 +1534,11 @@ texture_error_check( GLcontext *ctx, GLenum target,
    }
    else if (dimensions == 3) {
       if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) {
-         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_3D,
-                                                level, internalFormat,
-                                                format, type,
-                                                width, height, depth, border);
+         proxy_target = GL_PROXY_TEXTURE_3D;
+      }
+      else if (target == GL_PROXY_TEXTURE_2D_ARRAY_EXT ||
+               target == GL_TEXTURE_2D_ARRAY_EXT) {
+         proxy_target = GL_PROXY_TEXTURE_2D_ARRAY_EXT;
       }
       else {
          _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
@@ -1428,6 +1550,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
       return GL_TRUE;
    }
 
+   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxy_target, level,
+                                                    internalFormat, format,
+                                                    type, width, height,
+                                                    depth, border);
    if (!sizeOK) {
       if (!isProxy) {
          _mesa_error(ctx, GL_INVALID_VALUE,
@@ -1522,21 +1648,10 @@ texture_error_check( GLcontext *ctx, GLenum target,
 
    /* additional checks for compressed textures */
    if (is_compressed_format(ctx, internalFormat)) {
-      if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
-         /* OK */
-      }
-      else if (ctx->Extensions.ARB_texture_cube_map &&
-               (target == GL_PROXY_TEXTURE_CUBE_MAP ||
-                (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                 target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
-         /* OK */
-      }
-      else {
-         if (!isProxy) {
-            _mesa_error(ctx, GL_INVALID_ENUM,
-                        "glTexImage%d(target)", dimensions);
-            return GL_TRUE;
-         }
+      if (!target_can_be_compressed(ctx, target) && !isProxy) {
+         _mesa_error(ctx, GL_INVALID_ENUM,
+                     "glTexImage%d(target)", dimensions);
+         return GL_TRUE;
       }
       if (border != 0) {
          if (!isProxy) {
@@ -1602,13 +1717,25 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions,
             return GL_TRUE;
          }
       }
+      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
+        if (!ctx->Extensions.MESA_texture_array) {
+           _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
+           return GL_TRUE;
+        }
+      }
       else if (target != GL_TEXTURE_2D) {
          _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
          return GL_TRUE;
       }
    }
    else if (dimensions == 3) {
-      if (target != GL_TEXTURE_3D) {
+      if (target == GL_TEXTURE_2D_ARRAY_EXT) {
+         if (!ctx->Extensions.MESA_texture_array) {
+            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
+            return GL_TRUE;
+         }
+      }
+      else if (target != GL_TEXTURE_3D) {
          _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
          return GL_TRUE;
       }
@@ -1711,16 +1838,7 @@ subtexture_error_check2( GLcontext *ctx, GLuint dimensions,
 #endif
 
    if (destTex->IsCompressed) {
-      if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) {
-         /* OK */
-      }
-      else if (ctx->Extensions.ARB_texture_cube_map &&
-               (target == GL_PROXY_TEXTURE_CUBE_MAP ||
-                (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-                 target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
-         /* OK */
-      }
-      else {
+      if (!target_can_be_compressed(ctx, target)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glTexSubImage%D(target)", dimensions);
          return GL_TRUE;
@@ -1862,6 +1980,17 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions,
                                                 format, type,
                                                 width, height, 1, border);
       }
+      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
+         if (!ctx->Extensions.MESA_texture_array) {
+            _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)");
+            return GL_TRUE;
+         }
+         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
+                                                GL_PROXY_TEXTURE_1D_ARRAY_EXT,
+                                                level, internalFormat,
+                                                format, type,
+                                                width, height, 1, border);
+      }
       else {
          _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
          return GL_TRUE;
@@ -1975,15 +2104,23 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
             return GL_TRUE;
          }
       }
+      else if (target == GL_TEXTURE_1D_ARRAY_EXT) {
+         if (!ctx->Extensions.MESA_texture_array) {
+            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
+            return GL_TRUE;
+         }
+      }
       else if (target != GL_TEXTURE_2D) {
          _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
          return GL_TRUE;
       }
    }
    else if (dimensions == 3) {
-      if (target != GL_TEXTURE_3D) {
-         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
-         return GL_TRUE;
+      if (((target != GL_TEXTURE_2D_ARRAY_EXT) ||
+          (!ctx->Extensions.MESA_texture_array))
+         && (target != GL_TEXTURE_3D)) {
+        _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
+        return GL_TRUE;
       }
    }
 
@@ -2186,9 +2323,6 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
       return;
    }
 
-   if (!pixels)
-      return;
-
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
@@ -2304,7 +2438,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      const GLuint face = texture_face(target);
+      const GLuint face = _mesa_tex_target_to_face(target);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 1, postConvWidth, 1, 1, border)) {
@@ -2347,7 +2481,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
         update_fbo_texture(ctx, texObj, face, level);
         
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
@@ -2400,12 +2534,14 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
         target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
         target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) ||
        (ctx->Extensions.NV_texture_rectangle &&
-        target == GL_TEXTURE_RECTANGLE_NV)) {
+        target == GL_TEXTURE_RECTANGLE_NV) ||
+       (ctx->Extensions.MESA_texture_array &&
+        target == GL_TEXTURE_1D_ARRAY_EXT)) {
       /* non-proxy target */
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      const GLuint face = texture_face(target);
+      const GLuint face = _mesa_tex_target_to_face(target);
 
       if (texture_error_check(ctx, target, level, internalFormat,
                               format, type, 2, postConvWidth, postConvHeight,
@@ -2448,7 +2584,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
         update_fbo_texture(ctx, texObj, face, level);
 
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
@@ -2458,7 +2594,9 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
             (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB &&
              ctx->Extensions.ARB_texture_cube_map) ||
             (target == GL_PROXY_TEXTURE_RECTANGLE_NV &&
-             ctx->Extensions.NV_texture_rectangle)) {
+             ctx->Extensions.NV_texture_rectangle) ||
+            (ctx->Extensions.MESA_texture_array &&
+             target == GL_PROXY_TEXTURE_1D_ARRAY_EXT)) {
       /* Proxy texture: check for errors and update proxy state */
       struct gl_texture_image *texImage;
       texImage = _mesa_get_proxy_tex_image(ctx, target, level);
@@ -2498,12 +2636,14 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-   if (target == GL_TEXTURE_3D) {
+   if (target == GL_TEXTURE_3D ||
+       (ctx->Extensions.MESA_texture_array &&
+        target == GL_TEXTURE_2D_ARRAY_EXT)) {
       /* non-proxy target */
       struct gl_texture_unit *texUnit;
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
-      const GLuint face = texture_face(target);
+      const GLuint face = _mesa_tex_target_to_face(target);
 
       if (texture_error_check(ctx, target, level, (GLint) internalFormat,
                               format, type, 3, width, height, depth, border)) {
@@ -2545,13 +2685,15 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
         update_fbo_texture(ctx, texObj, face, level);
 
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
       _mesa_unlock_texture(ctx, texObj);
    }
-   else if (target == GL_PROXY_TEXTURE_3D) {
+   else if (target == GL_PROXY_TEXTURE_3D ||
+       (ctx->Extensions.MESA_texture_array &&
+        target == GL_PROXY_TEXTURE_2D_ARRAY_EXT)) {
       /* Proxy texture: check for errors and update proxy state */
       struct gl_texture_image *texImage;
       texImage = _mesa_get_proxy_tex_image(ctx, target, level);
@@ -2769,7 +2911,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
-   const GLuint face = texture_face(target);
+   const GLuint face = _mesa_tex_target_to_face(target);
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2814,7 +2956,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
       update_fbo_texture(ctx, texObj, face, level);
 
       /* state update */
-      texObj->Complete = GL_FALSE;
+      texObj->_Complete = GL_FALSE;
       ctx->NewState |= _NEW_TEXTURE;
    }
  out:
@@ -2832,7 +2974,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width, postConvHeight = height;
-   const GLuint face = texture_face(target);
+   const GLuint face = _mesa_tex_target_to_face(target);
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2880,7 +3022,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
       update_fbo_texture(ctx, texObj, face, level);
 
       /* state update */
-      texObj->Complete = GL_FALSE;
+      texObj->_Complete = GL_FALSE;
       ctx->NewState |= _NEW_TEXTURE;
    }
  out:
@@ -2896,6 +3038,9 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLsizei postConvWidth = width;
+   GLint yoffset = 0;
+   GLsizei height = 1;
+
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
@@ -2925,8 +3070,13 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level,
       /* If we have a border, xoffset=-1 is legal.  Bias by border width */
       xoffset += texImage->Border;
 
-      ASSERT(ctx->Driver.CopyTexSubImage1D);
-      (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width);
+      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                     &width, &height)) {
+         ASSERT(ctx->Driver.CopyTexSubImage1D);
+         ctx->Driver.CopyTexSubImage1D(ctx, target, level,
+                                       xoffset, x, y, width);
+      }
+
       ctx->NewState |= _NEW_TEXTURE;
    }
  out:
@@ -2971,10 +3121,14 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level,
       /* If we have a border, xoffset=-1 is legal.  Bias by border width */
       xoffset += texImage->Border;
       yoffset += texImage->Border;
-      
-      ASSERT(ctx->Driver.CopyTexSubImage2D);
-      (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level,
+
+      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                     &width, &height)) {
+         ASSERT(ctx->Driver.CopyTexSubImage2D);
+         ctx->Driver.CopyTexSubImage2D(ctx, target, level,
                                       xoffset, yoffset, x, y, width, height);
+      }
+
       ctx->NewState |= _NEW_TEXTURE;
    }
  out:
@@ -3022,10 +3176,14 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
       yoffset += texImage->Border;
       zoffset += texImage->Border;
       
-      ASSERT(ctx->Driver.CopyTexSubImage3D);
-      (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level,
+      if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+                                     &width, &height)) {
+         ASSERT(ctx->Driver.CopyTexSubImage3D);
+         ctx->Driver.CopyTexSubImage3D(ctx, target, level,
                                       xoffset, yoffset, zoffset,
                                       x, y, width, height);
+      }
+
       ctx->NewState |= _NEW_TEXTURE;
    }
  out:
@@ -3274,7 +3432,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level,
                                             texObj, texImage);
 
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
@@ -3371,7 +3529,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level,
                                             texObj, texImage);
         
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
@@ -3467,7 +3625,7 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level,
                                             texObj, texImage);
         
         /* state update */
-        texObj->Complete = GL_FALSE;
+        texObj->_Complete = GL_FALSE;
         ctx->NewState |= _NEW_TEXTURE;
       }
    out:
@@ -3644,7 +3802,7 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
                                              width, height, depth, /*size*/
                                              format, imageSize);
    if (error) {
-      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
+      _mesa_error(ctx, error, "glCompressedTexSubImage3D");
       return;
    }
 
@@ -3695,7 +3853,6 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
 
-
    texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    texObj = _mesa_select_tex_object(ctx, texUnit, target);
    if (!texObj) {
@@ -3716,24 +3873,25 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
       return;
    }
 
-
    _mesa_lock_texture(ctx, texObj);
    {
       texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-      if (!texImage) {
-        /* probably invalid mipmap level */
-        _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
-        goto out;
+      if (texImage) {
+         if (texImage->IsCompressed) {
+            /* this typically calls _mesa_get_compressed_teximage() */
+            ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
+                                              texObj, texImage);
+         }
+         else {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glGetCompressedTexImageARB");
+         }
       }
-
-      if (!texImage->IsCompressed) {
-        _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB");
-        goto out;
+      else {
+         /* probably invalid mipmap level */
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glGetCompressedTexImageARB(level)");
       }
-
-      /* this typically calls _mesa_get_compressed_teximage() */
-      ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage);
    }
- out:
    _mesa_unlock_texture(ctx, texObj);
 }