mesa: pass context parameter to gl_renderbuffer::Delete()
[mesa.git] / src / mesa / main / texobj.c
index 8d9c9794a155fee8135b1dfda49556c7996c1f2f..d650c75e4e711fe31aab39f5ce360b6e910afeaf 100644 (file)
@@ -29,6 +29,7 @@
 
 
 #include "mfeatures.h"
+#include "bufferobj.h"
 #include "colortab.h"
 #include "context.h"
 #include "enums.h"
@@ -39,6 +40,7 @@
 #include "macros.h"
 #include "teximage.h"
 #include "texobj.h"
+#include "texstate.h"
 #include "mtypes.h"
 #include "program/prog_instruction.h"
 
@@ -104,7 +106,10 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
           target == GL_TEXTURE_CUBE_MAP_ARB ||
           target == GL_TEXTURE_RECTANGLE_NV ||
           target == GL_TEXTURE_1D_ARRAY_EXT ||
-          target == GL_TEXTURE_2D_ARRAY_EXT);
+          target == GL_TEXTURE_2D_ARRAY_EXT ||
+          target == GL_TEXTURE_EXTERNAL_OES ||
+          target == GL_TEXTURE_CUBE_MAP_ARRAY ||
+          target == GL_TEXTURE_BUFFER);
 
    memset(obj, 0, sizeof(*obj));
    /* init the non-zero fields */
@@ -113,34 +118,43 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
    obj->Name = name;
    obj->Target = target;
    obj->Priority = 1.0F;
-   if (target == GL_TEXTURE_RECTANGLE_NV) {
-      obj->WrapS = GL_CLAMP_TO_EDGE;
-      obj->WrapT = GL_CLAMP_TO_EDGE;
-      obj->WrapR = GL_CLAMP_TO_EDGE;
-      obj->MinFilter = GL_LINEAR;
+   obj->BaseLevel = 0;
+   obj->MaxLevel = 1000;
+
+   /* must be one; no support for (YUV) planes in separate buffers */
+   obj->RequiredTextureImageUnits = 1;
+
+   /* sampler state */
+   if (target == GL_TEXTURE_RECTANGLE_NV ||
+       target == GL_TEXTURE_EXTERNAL_OES) {
+      obj->Sampler.WrapS = GL_CLAMP_TO_EDGE;
+      obj->Sampler.WrapT = GL_CLAMP_TO_EDGE;
+      obj->Sampler.WrapR = GL_CLAMP_TO_EDGE;
+      obj->Sampler.MinFilter = GL_LINEAR;
    }
    else {
-      obj->WrapS = GL_REPEAT;
-      obj->WrapT = GL_REPEAT;
-      obj->WrapR = GL_REPEAT;
-      obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
+      obj->Sampler.WrapS = GL_REPEAT;
+      obj->Sampler.WrapT = GL_REPEAT;
+      obj->Sampler.WrapR = GL_REPEAT;
+      obj->Sampler.MinFilter = GL_NEAREST_MIPMAP_LINEAR;
    }
-   obj->MagFilter = GL_LINEAR;
-   obj->MinLod = -1000.0;
-   obj->MaxLod = 1000.0;
-   obj->LodBias = 0.0;
-   obj->BaseLevel = 0;
-   obj->MaxLevel = 1000;
-   obj->MaxAnisotropy = 1.0;
-   obj->CompareMode = GL_NONE;         /* ARB_shadow */
-   obj->CompareFunc = GL_LEQUAL;       /* ARB_shadow */
-   obj->CompareFailValue = 0.0F;       /* ARB_shadow_ambient */
-   obj->DepthMode = GL_LUMINANCE;      /* ARB_depth_texture */
+   obj->Sampler.MagFilter = GL_LINEAR;
+   obj->Sampler.MinLod = -1000.0;
+   obj->Sampler.MaxLod = 1000.0;
+   obj->Sampler.LodBias = 0.0;
+   obj->Sampler.MaxAnisotropy = 1.0;
+   obj->Sampler.CompareMode = GL_NONE;         /* ARB_shadow */
+   obj->Sampler.CompareFunc = GL_LEQUAL;       /* ARB_shadow */
+   obj->DepthMode = GL_LUMINANCE;
+   obj->Sampler.CubeMapSeamless = GL_FALSE;
    obj->Swizzle[0] = GL_RED;
    obj->Swizzle[1] = GL_GREEN;
    obj->Swizzle[2] = GL_BLUE;
    obj->Swizzle[3] = GL_ALPHA;
    obj->_Swizzle = SWIZZLE_NOOP;
+   obj->Sampler.sRGBDecode = GL_DECODE_EXT;
+   obj->BufferObjectFormat = GL_LUMINANCE8;
+   obj->_BufferObjectFormat = MESA_FORMAT_L8;
 }
 
 
@@ -154,12 +168,13 @@ finish_texture_init(struct gl_context *ctx, GLenum target,
 {
    assert(obj->Target == 0);
 
-   if (target == GL_TEXTURE_RECTANGLE_NV) {
+   if (target == GL_TEXTURE_RECTANGLE_NV ||
+       target == GL_TEXTURE_EXTERNAL_OES) {
       /* have to init wrap and filter state here - kind of klunky */
-      obj->WrapS = GL_CLAMP_TO_EDGE;
-      obj->WrapT = GL_CLAMP_TO_EDGE;
-      obj->WrapR = GL_CLAMP_TO_EDGE;
-      obj->MinFilter = GL_LINEAR;
+      obj->Sampler.WrapS = GL_CLAMP_TO_EDGE;
+      obj->Sampler.WrapT = GL_CLAMP_TO_EDGE;
+      obj->Sampler.WrapR = GL_CLAMP_TO_EDGE;
+      obj->Sampler.MinFilter = GL_LINEAR;
       if (ctx->Driver.TexParameter) {
          static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
          static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
@@ -191,17 +206,17 @@ _mesa_delete_texture_object(struct gl_context *ctx,
     */
    texObj->Target = 0x99;
 
-   _mesa_free_colortable_data(&texObj->Palette);
-
    /* free the texture images */
    for (face = 0; face < 6; face++) {
       for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
          if (texObj->Image[face][i]) {
-            _mesa_delete_texture_image( ctx, texObj->Image[face][i] );
+            ctx->Driver.DeleteTextureImage(ctx, texObj->Image[face][i]);
          }
       }
    }
 
+   _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL);
+
    /* destroy the mutex -- it may have allocated memory (eg on bsd) */
    _glthread_DESTROY_MUTEX(texObj->Mutex);
 
@@ -225,32 +240,35 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
    dest->Target = src->Target;
    dest->Name = src->Name;
    dest->Priority = src->Priority;
-   dest->BorderColor.f[0] = src->BorderColor.f[0];
-   dest->BorderColor.f[1] = src->BorderColor.f[1];
-   dest->BorderColor.f[2] = src->BorderColor.f[2];
-   dest->BorderColor.f[3] = src->BorderColor.f[3];
-   dest->WrapS = src->WrapS;
-   dest->WrapT = src->WrapT;
-   dest->WrapR = src->WrapR;
-   dest->MinFilter = src->MinFilter;
-   dest->MagFilter = src->MagFilter;
-   dest->MinLod = src->MinLod;
-   dest->MaxLod = src->MaxLod;
-   dest->LodBias = src->LodBias;
+   dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0];
+   dest->Sampler.BorderColor.f[1] = src->Sampler.BorderColor.f[1];
+   dest->Sampler.BorderColor.f[2] = src->Sampler.BorderColor.f[2];
+   dest->Sampler.BorderColor.f[3] = src->Sampler.BorderColor.f[3];
+   dest->Sampler.WrapS = src->Sampler.WrapS;
+   dest->Sampler.WrapT = src->Sampler.WrapT;
+   dest->Sampler.WrapR = src->Sampler.WrapR;
+   dest->Sampler.MinFilter = src->Sampler.MinFilter;
+   dest->Sampler.MagFilter = src->Sampler.MagFilter;
+   dest->Sampler.MinLod = src->Sampler.MinLod;
+   dest->Sampler.MaxLod = src->Sampler.MaxLod;
+   dest->Sampler.LodBias = src->Sampler.LodBias;
    dest->BaseLevel = src->BaseLevel;
    dest->MaxLevel = src->MaxLevel;
-   dest->MaxAnisotropy = src->MaxAnisotropy;
-   dest->CompareMode = src->CompareMode;
-   dest->CompareFunc = src->CompareFunc;
-   dest->CompareFailValue = src->CompareFailValue;
+   dest->Sampler.MaxAnisotropy = src->Sampler.MaxAnisotropy;
+   dest->Sampler.CompareMode = src->Sampler.CompareMode;
+   dest->Sampler.CompareFunc = src->Sampler.CompareFunc;
+   dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless;
    dest->DepthMode = src->DepthMode;
+   dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode;
    dest->_MaxLevel = src->_MaxLevel;
    dest->_MaxLambda = src->_MaxLambda;
    dest->GenerateMipmap = src->GenerateMipmap;
-   dest->Palette = src->Palette;
-   dest->_Complete = src->_Complete;
+   dest->_BaseComplete = src->_BaseComplete;
+   dest->_MipmapComplete = src->_MipmapComplete;
    COPY_4V(dest->Swizzle, src->Swizzle);
    dest->_Swizzle = src->_Swizzle;
+
+   dest->RequiredTextureImageUnits = src->RequiredTextureImageUnits;
 }
 
 
@@ -297,6 +315,9 @@ valid_texture_object(const struct gl_texture_object *tex)
    case GL_TEXTURE_RECTANGLE_NV:
    case GL_TEXTURE_1D_ARRAY_EXT:
    case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_TEXTURE_BUFFER:
+   case GL_TEXTURE_EXTERNAL_OES:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
       return GL_TRUE;
    case 0x99:
       _mesa_problem(NULL, "invalid reference to a deleted texture object");
@@ -313,16 +334,14 @@ valid_texture_object(const struct gl_texture_object *tex)
  * Reference (or unreference) a texture object.
  * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
  * If 'tex' is non-null, increment its refcount.
+ * This is normally only called from the _mesa_reference_texobj() macro
+ * when there's a real pointer change.
  */
 void
-_mesa_reference_texobj(struct gl_texture_object **ptr,
-                       struct gl_texture_object *tex)
+_mesa_reference_texobj_(struct gl_texture_object **ptr,
+                        struct gl_texture_object *tex)
 {
    assert(ptr);
-   if (*ptr == tex) {
-      /* no change */
-      return;
-   }
 
    if (*ptr) {
       /* Unreference the old texture */
@@ -370,28 +389,41 @@ _mesa_reference_texobj(struct gl_texture_object **ptr,
 }
 
 
+enum base_mipmap { BASE, MIPMAP };
+
 
 /**
- * Report why a texture object is incomplete.  
- *
- * \param t texture object.
- * \param why string describing why it's incomplete.
+ * Mark a texture object as incomplete.  There are actually three kinds of
+ * (in)completeness:
+ * 1. "base incomplete": the base level of the texture is invalid so no
+ *    texturing is possible.
+ * 2. "mipmap incomplete": a non-base level of the texture is invalid so
+ *    mipmap filtering isn't possible, but non-mipmap filtering is.
+ * 3. "texture incompleteness": some combination of texture state and
+ *    sampler state renders the texture incomplete.
  *
- * \note For debug purposes only.
+ * \param t  texture object
+ * \param bm  either BASE or MIPMAP to indicate what's incomplete
+ * \param fmt...  string describing why it's incomplete (for debugging).
  */
 static void
-incomplete(const struct gl_texture_object *t, const char *fmt, ...)
+incomplete(struct gl_texture_object *t, enum base_mipmap bm,
+           const char *fmt, ...)
 {
-#if 0
-   va_list args;
-   char s[100];
+   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_TEXTURE) {
+      va_list args;
+      char s[100];
+
+      va_start(args, fmt);
+      vsnprintf(s, sizeof(s), fmt, args);
+      va_end(args);
 
-   va_start(args, fmt);
-   vsnprintf(s, sizeof(s), fmt, args);
-   va_end(args);
+      _mesa_debug(NULL, "Texture Obj %d incomplete because: %s\n", t->Name, s);
+   }
 
-   printf("Texture Obj %d incomplete because: %s\n", t->Name, s);
-#endif
+   if (bm == BASE)
+      t->_BaseComplete = GL_FALSE;
+   t->_MipmapComplete = GL_FALSE;
 }
 
 
@@ -412,276 +444,205 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
                                 struct gl_texture_object *t )
 {
    const GLint baseLevel = t->BaseLevel;
-   GLint maxLog2 = 0, maxLevels = 0;
+   const struct gl_texture_image *baseImage;
+   GLint maxLevels = 0;
+
+   /* We'll set these to FALSE if tests fail below */
+   t->_BaseComplete = GL_TRUE;
+   t->_MipmapComplete = GL_TRUE;
 
-   t->_Complete = GL_TRUE;  /* be optimistic */
+   if (t->Target == GL_TEXTURE_BUFFER) {
+      /* Buffer textures are always considered complete.  The obvious case where
+       * they would be incomplete (no BO attached) is actually specced to be
+       * undefined rendering results.
+       */
+      return;
+   }
 
    /* Detect cases where the application set the base level to an invalid
     * value.
     */
    if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
-      incomplete(t, "base level = %d is invalid", baseLevel);
-      t->_Complete = GL_FALSE;
+      incomplete(t, BASE, "base level = %d is invalid", baseLevel);
       return;
    }
 
+   if (t->MaxLevel < baseLevel) {
+      incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
+                t->MaxLevel, baseLevel);
+      return;
+   }
+
+   baseImage = t->Image[0][baseLevel];
+
    /* Always need the base level image */
-   if (!t->Image[0][baseLevel]) {
-      incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel);
-      t->_Complete = GL_FALSE;
+   if (!baseImage) {
+      incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel);
       return;
    }
 
    /* Check width/height/depth for zero */
-   if (t->Image[0][baseLevel]->Width == 0 ||
-       t->Image[0][baseLevel]->Height == 0 ||
-       t->Image[0][baseLevel]->Depth == 0) {
-      incomplete(t, "texture width = 0");
-      t->_Complete = GL_FALSE;
+   if (baseImage->Width == 0 ||
+       baseImage->Height == 0 ||
+       baseImage->Depth == 0) {
+      incomplete(t, BASE, "texture width or height or depth = 0");
       return;
    }
 
-   /* Compute _MaxLevel */
-   if ((t->Target == GL_TEXTURE_1D) ||
-       (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
-      maxLog2 = t->Image[0][baseLevel]->WidthLog2;
-      maxLevels = ctx->Const.MaxTextureLevels;
+   /* Check if the texture values are integer */
+   {
+      GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat);
+      t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT;
    }
-   else if ((t->Target == GL_TEXTURE_2D) ||
-            (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
-      maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
-                     t->Image[0][baseLevel]->HeightLog2);
+
+   /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the
+    * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state).
+    */
+   switch (t->Target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_1D_ARRAY_EXT:
       maxLevels = ctx->Const.MaxTextureLevels;
-   }
-   else if (t->Target == GL_TEXTURE_3D) {
-      GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
-                       t->Image[0][baseLevel]->HeightLog2);
-      maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
+      break;
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_2D_ARRAY_EXT:
+      maxLevels = ctx->Const.MaxTextureLevels;
+      break;
+   case GL_TEXTURE_3D:
       maxLevels = ctx->Const.Max3DTextureLevels;
-   }
-   else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
-      maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
-                     t->Image[0][baseLevel]->HeightLog2);
+      break;
+   case GL_TEXTURE_CUBE_MAP_ARB:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
       maxLevels = ctx->Const.MaxCubeTextureLevels;
-   }
-   else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
-      maxLog2 = 0;  /* not applicable */
+      break;
+   case GL_TEXTURE_RECTANGLE_NV:
+   case GL_TEXTURE_BUFFER:
+   case GL_TEXTURE_EXTERNAL_OES:
       maxLevels = 1;  /* no mipmapping */
-   }
-   else {
+      break;
+   default:
       _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
       return;
    }
 
    ASSERT(maxLevels > 0);
 
-   t->_MaxLevel = baseLevel + maxLog2;
+   t->_MaxLevel =
+      baseLevel + baseImage->MaxNumLevels - 1; /* 'p' in the GL spec */
    t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
-   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
+   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */
 
    /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
-   t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
+   t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel);
+
+   if (t->Immutable) {
+      /* This texture object was created with glTexStorage1/2/3D() so we
+       * know that all the mipmap levels are the right size and all cube
+       * map faces are the same size.
+       * We don't need to do any of the additional checks below.
+       */
+      return;
+   }
 
    if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
-      /* make sure that all six cube map level 0 images are the same size */
-      const GLuint w = t->Image[0][baseLevel]->Width2;
-      const GLuint h = t->Image[0][baseLevel]->Height2;
+      /* Make sure that all six cube map level 0 images are the same size.
+       * Note:  we know that the image's width==height (we enforce that
+       * at glTexImage time) so we only need to test the width here.
+       */
       GLuint face;
+      assert(baseImage->Width2 == baseImage->Height);
       for (face = 1; face < 6; face++) {
+         assert(t->Image[face][baseLevel] == NULL ||
+                t->Image[face][baseLevel]->Width2 ==
+                t->Image[face][baseLevel]->Height2);
          if (t->Image[face][baseLevel] == NULL ||
-             t->Image[face][baseLevel]->Width2 != w ||
-             t->Image[face][baseLevel]->Height2 != h) {
-            t->_Complete = GL_FALSE;
-            incomplete(t, "Cube face missing or mismatched size");
+             t->Image[face][baseLevel]->Width2 != baseImage->Width2) {
+            incomplete(t, BASE, "Cube face missing or mismatched size");
             return;
          }
       }
    }
 
-   /* extra checking for mipmaps */
-   if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
-      /*
-       * Mipmapping: determine if we have a complete set of mipmaps
-       */
+   /*
+    * Do mipmap consistency checking.
+    * Note: we don't care about the current texture sampler state here.
+    * To determine texture completeness we'll either look at _BaseComplete
+    * or _MipmapComplete depending on the current minification filter mode.
+    */
+   {
       GLint i;
-      GLint minLevel = baseLevel;
-      GLint maxLevel = t->_MaxLevel;
+      const GLint minLevel = baseLevel;
+      const GLint maxLevel = t->_MaxLevel;
+      const GLuint numFaces = _mesa_num_tex_faces(t->Target);
+      GLuint width, height, depth, face;
 
       if (minLevel > maxLevel) {
-         t->_Complete = GL_FALSE;
-         incomplete(t, "minLevel > maxLevel");
+         incomplete(t, BASE, "minLevel > maxLevel");
          return;
       }
 
-      /* Test dimension-independent attributes */
-      for (i = minLevel; i <= maxLevel; i++) {
-         if (t->Image[0][i]) {
-            if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
-               t->_Complete = GL_FALSE;
-               incomplete(t, "Format[i] != Format[baseLevel]");
-               return;
-            }
-            if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
-               t->_Complete = GL_FALSE;
-               incomplete(t, "Border[i] != Border[baseLevel]");
-               return;
-            }
-         }
-      }
+      /* Get the base image's dimensions */
+      width = baseImage->Width2;
+      height = baseImage->Height2;
+      depth = baseImage->Depth2;
 
-      /* Test things which depend on number of texture image dimensions */
-      if ((t->Target == GL_TEXTURE_1D) ||
-          (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
-         /* Test 1-D mipmaps */
-         GLuint width = t->Image[0][baseLevel]->Width2;
-         for (i = baseLevel + 1; i < maxLevels; i++) {
-            if (width > 1) {
-               width /= 2;
-            }
-            if (i >= minLevel && i <= maxLevel) {
-               if (!t->Image[0][i]) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "1D Image[0][i] == NULL");
-                  return;
-               }
-               if (t->Image[0][i]->Width2 != width ) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "1D Image[0][i] bad width");
-                  return;
-               }
-            }
-            if (width == 1) {
-               return;  /* found smallest needed mipmap, all done! */
-            }
+      /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL textures */
+      for (i = baseLevel + 1; i < maxLevels; i++) {
+         /* Compute the expected size of image at level[i] */
+         if (width > 1) {
+            width /= 2;
          }
-      }
-      else if ((t->Target == GL_TEXTURE_2D) ||
-               (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
-         /* Test 2-D mipmaps */
-         GLuint width = t->Image[0][baseLevel]->Width2;
-         GLuint height = t->Image[0][baseLevel]->Height2;
-         for (i = baseLevel + 1; i < maxLevels; i++) {
-            if (width > 1) {
-               width /= 2;
-            }
-            if (height > 1) {
-               height /= 2;
-            }
+         if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) {
+            height /= 2;
+         }
+         if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) {
+            depth /= 2;
+         }
+
+         /* loop over cube faces (or single face otherwise) */
+         for (face = 0; face < numFaces; face++) {
             if (i >= minLevel && i <= maxLevel) {
-               if (!t->Image[0][i]) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "2D Image[0][i] == NULL");
-                  return;
-               }
-               if (t->Image[0][i]->Width2 != width) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "2D Image[0][i] bad width");
+               const struct gl_texture_image *img = t->Image[face][i];
+
+               if (!img) {
+                  incomplete(t, MIPMAP, "TexImage[%d] is missing", i);
                   return;
                }
-               if (t->Image[0][i]->Height2 != height) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "2D Image[0][i] bad height");
+               if (img->TexFormat != baseImage->TexFormat) {
+                  incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]");
                   return;
                }
-               if (width==1 && height==1) {
-                  return;  /* found smallest needed mipmap, all done! */
-               }
-            }
-         }
-      }
-      else if (t->Target == GL_TEXTURE_3D) {
-         /* Test 3-D mipmaps */
-         GLuint width = t->Image[0][baseLevel]->Width2;
-         GLuint height = t->Image[0][baseLevel]->Height2;
-         GLuint depth = t->Image[0][baseLevel]->Depth2;
-         for (i = baseLevel + 1; i < maxLevels; i++) {
-            if (width > 1) {
-               width /= 2;
-            }
-            if (height > 1) {
-               height /= 2;
-            }
-            if (depth > 1) {
-               depth /= 2;
-            }
-            if (i >= minLevel && i <= maxLevel) {
-               if (!t->Image[0][i]) {
-                  incomplete(t, "3D Image[0][i] == NULL");
-                  t->_Complete = GL_FALSE;
+               if (img->Border != baseImage->Border) {
+                  incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]");
                   return;
                }
-               if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
+               if (img->Width2 != width) {
+                  incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2);
                   return;
                }
-               if (t->Image[0][i]->Width2 != width) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "3D Image[0][i] bad width");
+               if (img->Height2 != height) {
+                  incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2);
                   return;
                }
-               if (t->Image[0][i]->Height2 != height) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "3D Image[0][i] bad height");
+               if (img->Depth2 != depth) {
+                  incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2);
                   return;
                }
-               if (t->Image[0][i]->Depth2 != depth) {
-                  t->_Complete = GL_FALSE;
-                  incomplete(t, "3D Image[0][i] bad depth");
-                  return;
-               }
-            }
-            if (width == 1 && height == 1 && depth == 1) {
-               return;  /* found smallest needed mipmap, all done! */
-            }
-         }
-      }
-      else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
-         /* make sure 6 cube faces are consistant */
-         GLuint width = t->Image[0][baseLevel]->Width2;
-         GLuint height = t->Image[0][baseLevel]->Height2;
-         for (i = baseLevel + 1; i < maxLevels; i++) {
-            if (width > 1) {
-               width /= 2;
-            }
-            if (height > 1) {
-               height /= 2;
-            }
-            if (i >= minLevel && i <= maxLevel) {
-              GLuint face;
-              for (face = 0; face < 6; face++) {
-                 /* check that we have images defined */
-                 if (!t->Image[face][i]) {
-                    t->_Complete = GL_FALSE;
-                    incomplete(t, "CubeMap Image[n][i] == NULL");
-                    return;
-                 }
-                 /* Don't support GL_DEPTH_COMPONENT for cube maps */
-                 if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
-                    t->_Complete = GL_FALSE;
-                    incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
-                    return;
-                 }
-                 /* check that all six images have same size */
-                  if (t->Image[face][i]->Width2 != width || 
-                      t->Image[face][i]->Height2 != height) {
-                    t->_Complete = GL_FALSE;
-                    incomplete(t, "CubeMap Image[n][i] bad size");
+
+               /* Extra checks for cube textures */
+               if (face > 0) {
+                  /* check that cube faces are the same size */
+                  if (img->Width2 != t->Image[0][i]->Width2 || 
+                      img->Height2 != t->Image[0][i]->Height2) {
+                    incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size");
                     return;
                  }
-              }
-           }
-           if (width == 1 && height == 1) {
-              return;  /* found smallest needed mipmap, all done! */
+               }
             }
          }
-      }
-      else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
-         /* XXX special checking? */
-      }
-      else {
-         /* Target = ??? */
-         _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
+         
+         if (width == 1 && height == 1 && depth == 1) {
+            return;  /* found smallest needed mipmap, all done! */
+         }
       }
    }
 }
@@ -737,69 +698,241 @@ void
 _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
                    GLboolean invalidate_state)
 {
-   texObj->_Complete = GL_FALSE;
+   texObj->_BaseComplete = GL_FALSE;
+   texObj->_MipmapComplete = GL_FALSE;
    if (invalidate_state)
       ctx->NewState |= _NEW_TEXTURE;
 }
 
 
 /**
- * Return pointer to a default/fallback texture.
- * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1).
- * That's the value a sampler should get when sampling from an
+ * Return pointer to a default/fallback texture of the given type/target.
+ * The texture is an RGBA texture with all texels = (0,0,0,1).
+ * That's the value a GLSL sampler should get when sampling from an
  * incomplete texture.
  */
 struct gl_texture_object *
-_mesa_get_fallback_texture(struct gl_context *ctx)
+_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
 {
-   if (!ctx->Shared->FallbackTex) {
+   if (!ctx->Shared->FallbackTex[tex]) {
       /* create fallback texture now */
-      static GLubyte texels[8 * 8][4];
+      const GLsizei width = 1, height = 1, depth = 1;
+      GLubyte texel[4];
       struct gl_texture_object *texObj;
       struct gl_texture_image *texImage;
       gl_format texFormat;
-      GLuint i;
-
-      for (i = 0; i < 8 * 8; i++) {
-         texels[i][0] =
-         texels[i][1] =
-         texels[i][2] = 0x0;
-         texels[i][3] = 0xff;
+      GLuint dims, face, numFaces = 1;
+      GLenum target;
+
+      texel[0] =
+      texel[1] =
+      texel[2] = 0x0;
+      texel[3] = 0xff;
+
+      switch (tex) {
+      case TEXTURE_2D_ARRAY_INDEX:
+         dims = 3;
+         target = GL_TEXTURE_2D_ARRAY;
+         break;
+      case TEXTURE_1D_ARRAY_INDEX:
+         dims = 2;
+         target = GL_TEXTURE_1D_ARRAY;
+         break;
+      case TEXTURE_CUBE_INDEX:
+         dims = 2;
+         target = GL_TEXTURE_CUBE_MAP;
+         numFaces = 6;
+         break;
+      case TEXTURE_3D_INDEX:
+         dims = 3;
+         target = GL_TEXTURE_3D;
+         break;
+      case TEXTURE_RECT_INDEX:
+         dims = 2;
+         target = GL_TEXTURE_RECTANGLE;
+         break;
+      case TEXTURE_2D_INDEX:
+         dims = 2;
+         target = GL_TEXTURE_2D;
+         break;
+      case TEXTURE_1D_INDEX:
+         dims = 1;
+         target = GL_TEXTURE_1D;
+         break;
+      case TEXTURE_BUFFER_INDEX:
+         dims = 0;
+         target = GL_TEXTURE_BUFFER;
+         break;
+     case TEXTURE_CUBE_ARRAY_INDEX:
+         dims = 3;
+         target = GL_TEXTURE_CUBE_MAP_ARRAY;
+         break;
+      case TEXTURE_EXTERNAL_INDEX:
+         dims = 2;
+         target = GL_TEXTURE_EXTERNAL_OES;
+         break;
+      default:
+         /* no-op */
+         return NULL;
       }
 
       /* create texture object */
-      texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D);
-      assert(texObj->RefCount == 1);
-      texObj->MinFilter = GL_NEAREST;
-      texObj->MagFilter = GL_NEAREST;
+      texObj = ctx->Driver.NewTextureObject(ctx, 0, target);
+      if (!texObj)
+         return NULL;
 
-      /* create level[0] texture image */
-      texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0);
+      assert(texObj->RefCount == 1);
+      texObj->Sampler.MinFilter = GL_NEAREST;
+      texObj->Sampler.MagFilter = GL_NEAREST;
 
-      texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA,
+      texFormat = ctx->Driver.ChooseTextureFormat(ctx, target,
+                                                  GL_RGBA, GL_RGBA,
                                                   GL_UNSIGNED_BYTE);
 
-      /* init the image fields */
-      _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage,
-                                 8, 8, 1, 0, GL_RGBA, texFormat); 
+      /* need a loop here just for cube maps */
+      for (face = 0; face < numFaces; face++) {
+         GLenum faceTarget;
 
-      ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
+         if (target == GL_TEXTURE_CUBE_MAP)
+            faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+         else
+            faceTarget = target;
+
+         /* initialize level[0] texture image */
+         texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0);
 
-      /* set image data */
-      ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA,
-                             8, 8, 0,
-                             GL_RGBA, GL_UNSIGNED_BYTE, texels,
-                             &ctx->DefaultPacking, texObj, texImage);
+         _mesa_init_teximage_fields(ctx, texImage,
+                                    width,
+                                    (dims > 1) ? height : 1,
+                                    (dims > 2) ? depth : 1,
+                                    0, /* border */
+                                    GL_RGBA, texFormat);
+
+         ctx->Driver.TexImage(ctx, dims, texImage,
+                              GL_RGBA, GL_UNSIGNED_BYTE, texel,
+                              &ctx->DefaultPacking);
+      }
 
       _mesa_test_texobj_completeness(ctx, texObj);
-      assert(texObj->_Complete);
+      assert(texObj->_BaseComplete);
+      assert(texObj->_MipmapComplete);
 
-      ctx->Shared->FallbackTex = texObj;
+      ctx->Shared->FallbackTex[tex] = texObj;
    }
-   return ctx->Shared->FallbackTex;
+   return ctx->Shared->FallbackTex[tex];
+}
+
+
+/**
+ * Compute the size of the given texture object, in bytes.
+ */
+static GLuint
+texture_size(const struct gl_texture_object *texObj)
+{
+   const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
+   GLuint face, level, size = 0;
+
+   for (face = 0; face < numFaces; face++) {
+      for (level = 0; level < MAX_TEXTURE_LEVELS; level++) {
+         const struct gl_texture_image *img = texObj->Image[face][level];
+         if (img) {
+            GLuint sz = _mesa_format_image_size(img->TexFormat, img->Width,
+                                                img->Height, img->Depth);
+            size += sz;
+         }
+      }
+   }
+
+   return size;
+}
+
+
+/**
+ * Callback called from _mesa_HashWalk()
+ */
+static void
+count_tex_size(GLuint key, void *data, void *userData)
+{
+   const struct gl_texture_object *texObj =
+      (const struct gl_texture_object *) data;
+   GLuint *total = (GLuint *) userData;
+
+   *total = *total + texture_size(texObj);
 }
 
 
+/**
+ * Compute total size (in bytes) of all textures for the given context.
+ * For debugging purposes.
+ */
+GLuint
+_mesa_total_texture_memory(struct gl_context *ctx)
+{
+   GLuint tgt, total = 0;
+
+   _mesa_HashWalk(ctx->Shared->TexObjects, count_tex_size, &total);
+
+   /* plus, the default texture objects */
+   for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
+      total += texture_size(ctx->Shared->DefaultTex[tgt]);
+   }
+
+   return total;
+}
+
+static struct gl_texture_object *
+invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
+                                 GLint level, const char *name)
+{
+   /* The GL_ARB_invalidate_subdata spec says:
+    *
+    *     "If <texture> is zero or is not the name of a texture, the error
+    *     INVALID_VALUE is generated."
+    *
+    * This performs the error check in a different order than listed in the
+    * spec.  We have to get the texture object before we can validate the
+    * other parameters against values in the texture object.
+    */
+   struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture);
+   if (texture == 0 || t == NULL) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name);
+      return NULL;
+   }
+
+   /* The GL_ARB_invalidate_subdata spec says:
+    *
+    *     "If <level> is less than zero or greater than the base 2 logarithm
+    *     of the maximum texture width, height, or depth, the error
+    *     INVALID_VALUE is generated."
+    */
+   if (level < 0 || level > t->MaxLevel) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
+      return NULL;
+   }
+
+   /* The GL_ARB_invalidate_subdata spec says:
+    *
+    *     "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER,
+    *     TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level>
+    *     is not zero, the error INVALID_VALUE is generated."
+    */
+   if (level != 0) {
+      switch (t->Target) {
+      case GL_TEXTURE_RECTANGLE:
+      case GL_TEXTURE_BUFFER:
+      case GL_TEXTURE_2D_MULTISAMPLE:
+      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
+         return NULL;
+
+      default:
+         break;
+      }
+   }
+
+   return t;
+}
+
 /*@}*/
 
 
@@ -848,7 +981,7 @@ _mesa_GenTextures( GLsizei n, GLuint *textures )
       struct gl_texture_object *texObj;
       GLuint name = first + i;
       GLenum target = 0;
-      texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
+      texObj = ctx->Driver.NewTextureObject(ctx, name, target);
       if (!texObj) {
          _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
@@ -878,11 +1011,13 @@ unbind_texobj_from_fbo(struct gl_context *ctx,
 
    for (i = 0; i < n; i++) {
       struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
-      if (fb->Name) {
+      if (_mesa_is_user_fbo(fb)) {
          GLuint j;
          for (j = 0; j < BUFFER_COUNT; j++) {
             if (fb->Attachment[j].Type == GL_TEXTURE &&
                 fb->Attachment[j].Texture == texObj) {
+              /* Vertices are already flushed by _mesa_DeleteTextures */
+              ctx->NewState |= _NEW_BUFFERS;
                _mesa_remove_attachment(ctx, fb->Attachment + j);         
             }
          }
@@ -901,7 +1036,7 @@ unbind_texobj_from_texunits(struct gl_context *ctx,
 {
    GLuint u, tex;
 
-   for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
+   for (u = 0; u < Elements(ctx->Texture.Unit); u++) {
       struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
       for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
          if (texObj == unit->CurrentTex[tex]) {
@@ -986,23 +1121,41 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
  * \return TEXTURE_x_INDEX or -1 if target is invalid
  */
 static GLint
-target_enum_to_index(GLenum target)
+target_enum_to_index(struct gl_context *ctx, GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
-      return TEXTURE_1D_INDEX;
+      return _mesa_is_desktop_gl(ctx) ? TEXTURE_1D_INDEX : -1;
    case GL_TEXTURE_2D:
       return TEXTURE_2D_INDEX;
    case GL_TEXTURE_3D:
       return TEXTURE_3D_INDEX;
    case GL_TEXTURE_CUBE_MAP_ARB:
-      return TEXTURE_CUBE_INDEX;
+      return ctx->Extensions.ARB_texture_cube_map
+         ? TEXTURE_CUBE_INDEX : -1;
    case GL_TEXTURE_RECTANGLE_NV:
-      return TEXTURE_RECT_INDEX;
+      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle
+         ? TEXTURE_RECT_INDEX : -1;
    case GL_TEXTURE_1D_ARRAY_EXT:
-      return TEXTURE_1D_ARRAY_INDEX;
+      return _mesa_is_desktop_gl(ctx)
+         && (ctx->Extensions.EXT_texture_array
+             || ctx->Extensions.MESA_texture_array)
+         ? TEXTURE_1D_ARRAY_INDEX : -1;
    case GL_TEXTURE_2D_ARRAY_EXT:
-      return TEXTURE_2D_ARRAY_INDEX;
+      return (_mesa_is_desktop_gl(ctx)
+              && (ctx->Extensions.EXT_texture_array
+                  || ctx->Extensions.MESA_texture_array))
+         || _mesa_is_gles3(ctx)
+         ? TEXTURE_2D_ARRAY_INDEX : -1;
+   case GL_TEXTURE_BUFFER_ARB:
+      return _mesa_is_desktop_gl(ctx)
+         && ctx->Extensions.ARB_texture_buffer_object
+         ? TEXTURE_BUFFER_INDEX : -1;
+   case GL_TEXTURE_EXTERNAL_OES:
+      return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
+         ? TEXTURE_EXTERNAL_INDEX : -1;
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+      return TEXTURE_CUBE_ARRAY_INDEX;
    default:
       return -1;
    }
@@ -1028,30 +1181,28 @@ void GLAPIENTRY
 _mesa_BindTexture( GLenum target, GLuint texName )
 {
    GET_CURRENT_CONTEXT(ctx);
-   const GLuint unit = ctx->Texture.CurrentUnit;
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
-   struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL;
+   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
+   struct gl_texture_object *newTexObj = NULL;
    GLint targetIndex;
-   GLboolean early_out = GL_FALSE;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glBindTexture %s %d\n",
                   _mesa_lookup_enum_by_nr(target), (GLint) texName);
 
-   targetIndex = target_enum_to_index(target);
+   targetIndex = target_enum_to_index(ctx, target);
    if (targetIndex < 0) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
       return;
    }
    assert(targetIndex < NUM_TEXTURE_TARGETS);
-   defaultTexObj = ctx->Shared->DefaultTex[targetIndex];
 
    /*
     * Get pointer to new texture object (newTexObj)
     */
    if (texName == 0) {
-      newTexObj = defaultTexObj;
+      /* Use a default texture object */
+      newTexObj = ctx->Shared->DefaultTex[targetIndex];
    }
    else {
       /* non-default texture object */
@@ -1069,8 +1220,13 @@ _mesa_BindTexture( GLenum target, GLuint texName )
          }
       }
       else {
+         if (ctx->API == API_OPENGL_CORE) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture(non-gen name)");
+            return;
+         }
+
          /* if this is a new texture id, allocate a texture object now */
-         newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
+         newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target);
          if (!newTexObj) {
             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
             return;
@@ -1086,15 +1242,18 @@ _mesa_BindTexture( GLenum target, GLuint texName )
 
    assert(valid_texture_object(newTexObj));
 
-   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
-   if ((ctx->Shared->RefCount == 1)
-       && (newTexObj == texUnit->CurrentTex[targetIndex])) {
-      early_out = GL_TRUE;
-   }
-   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
-   if (early_out) {
-      return;
+   /* Check if this texture is only used by this context and is already bound.
+    * If so, just return.
+    */
+   {
+      GLboolean early_out;
+      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
+      early_out = ((ctx->Shared->RefCount == 1)
+                   && (newTexObj == texUnit->CurrentTex[targetIndex]));
+      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
+      if (early_out) {
+         return;
+      }
    }
 
    /* flush before changing binding */
@@ -1109,7 +1268,7 @@ _mesa_BindTexture( GLenum target, GLuint texName )
 
    /* Pass BindTexture call to device driver */
    if (ctx->Driver.BindTexture)
-      (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
+      ctx->Driver.BindTexture(ctx, target, newTexObj);
 }
 
 
@@ -1164,10 +1323,7 @@ _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
  *
  * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 
  * 
- * \sa glAreTexturesResident().
- *
- * Looks up each texture in the hash and calls
- * dd_function_table::IsTextureResident.
+ * Note: we assume all textures are always resident
  */
 GLboolean GLAPIENTRY
 _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
@@ -1175,7 +1331,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
 {
    GET_CURRENT_CONTEXT(ctx);
    GLboolean allResident = GL_TRUE;
-   GLint i, j;
+   GLint i;
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
    if (n < 0) {
@@ -1186,6 +1342,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
    if (!texName || !residences)
       return GL_FALSE;
 
+   /* We only do error checking on the texture names */
    for (i = 0; i < n; i++) {
       struct gl_texture_object *t;
       if (texName[i] == 0) {
@@ -1197,21 +1354,6 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
          _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
          return GL_FALSE;
       }
-      if (!ctx->Driver.IsTextureResident ||
-          ctx->Driver.IsTextureResident(ctx, t)) {
-         /* The texture is resident */
-         if (!allResident)
-            residences[i] = GL_TRUE;
-      }
-      else {
-         /* The texture is not resident */
-         if (allResident) {
-            allResident = GL_FALSE;
-            for (j = 0; j < i; j++)
-               residences[j] = GL_TRUE;
-         }
-         residences[i] = GL_FALSE;
-      }
    }
    
    return allResident;
@@ -1277,4 +1419,164 @@ _mesa_unlock_context_textures( struct gl_context *ctx )
    _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
 }
 
+void GLAPIENTRY
+_mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
+                            GLint yoffset, GLint zoffset, GLsizei width,
+                            GLsizei height, GLsizei depth)
+{
+   struct gl_texture_object *t;
+   struct gl_texture_image *image;
+   GET_CURRENT_CONTEXT(ctx);
+
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   t = invalidate_tex_image_error_check(ctx, texture, level,
+                                        "glInvalidateTexSubImage");
+
+   /* The GL_ARB_invalidate_subdata spec says:
+    *
+    *     "...the specified subregion must be between -<b> and <dim>+<b> where
+    *     <dim> is the size of the dimension of the texture image, and <b> is
+    *     the size of the border of that texture image, otherwise
+    *     INVALID_VALUE is generated (border is not applied to dimensions that
+    *     don't exist in a given texture target)."
+    */
+   image = t->Image[0][level];
+   if (image) {
+      int xBorder;
+      int yBorder;
+      int zBorder;
+      int imageWidth;
+      int imageHeight;
+      int imageDepth;
+
+      /* The GL_ARB_invalidate_subdata spec says:
+       *
+       *     "For texture targets that don't have certain dimensions, this
+       *     command treats those dimensions as having a size of 1. For
+       *     example, to invalidate a portion of a two-dimensional texture,
+       *     the application would use <zoffset> equal to zero and <depth>
+       *     equal to one."
+       */
+      switch (t->Target) {
+      case GL_TEXTURE_BUFFER:
+         xBorder = 0;
+         yBorder = 0;
+         zBorder = 0;
+         imageWidth = 1;
+         imageHeight = 1;
+         imageDepth = 1;
+         break;
+      case GL_TEXTURE_1D:
+         xBorder = image->Border;
+         yBorder = 0;
+         zBorder = 0;
+         imageWidth = image->Width;
+         imageHeight = 1;
+         imageDepth = 1;
+         break;
+      case GL_TEXTURE_1D_ARRAY:
+         xBorder = image->Border;
+         yBorder = 0;
+         zBorder = 0;
+         imageWidth = image->Width;
+         imageHeight = image->Height;
+         imageDepth = 1;
+         break;
+      case GL_TEXTURE_2D:
+      case GL_TEXTURE_CUBE_MAP:
+      case GL_TEXTURE_RECTANGLE:
+      case GL_TEXTURE_2D_MULTISAMPLE:
+         xBorder = image->Border;
+         yBorder = image->Border;
+         zBorder = 0;
+         imageWidth = image->Width;
+         imageHeight = image->Height;
+         imageDepth = 1;
+         break;
+      case GL_TEXTURE_2D_ARRAY:
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+         xBorder = image->Border;
+         yBorder = image->Border;
+         zBorder = 0;
+         imageWidth = image->Width;
+         imageHeight = image->Height;
+         imageDepth = image->Depth;
+         break;
+      case GL_TEXTURE_3D:
+         xBorder = image->Border;
+         yBorder = image->Border;
+         zBorder = image->Border;
+         imageWidth = image->Width;
+         imageHeight = image->Height;
+         imageDepth = image->Depth;
+         break;
+      default:
+         assert(!"Should not get here.");
+         xBorder = 0;
+         yBorder = 0;
+         zBorder = 0;
+         imageWidth = 0;
+         imageHeight = 0;
+         imageDepth = 0;
+         break;
+      }
+
+      if (xoffset < -xBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(xoffset)");
+         return;
+      }
+
+      if (xoffset + width > imageWidth + xBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glInvalidateSubTexImage(xoffset+width)");
+         return;
+      }
+
+      if (yoffset < -yBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(yoffset)");
+         return;
+      }
+
+      if (yoffset + height > imageHeight + yBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glInvalidateSubTexImage(yoffset+height)");
+         return;
+      }
+
+      if (zoffset < -zBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glInvalidateSubTexImage(zoffset)");
+         return;
+      }
+
+      if (zoffset + depth  > imageDepth + zBorder) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glInvalidateSubTexImage(zoffset+depth)");
+         return;
+      }
+   }
+
+   /* We don't actually do anything for this yet.  Just return after
+    * validating the parameters and generating the required errors.
+    */
+   return;
+}
+
+void GLAPIENTRY
+_mesa_InvalidateTexImage(GLuint texture, GLint level)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   invalidate_tex_image_error_check(ctx, texture, level,
+                                    "glInvalidateTexImage");
+
+   /* We don't actually do anything for this yet.  Just return after
+    * validating the parameters and generating the required errors.
+    */
+   return;
+}
+
 /*@}*/