illegal to set GL_TEXTURE_MAX_LEVEL w/ GL_TEXTURE_RECTANGLE_ARB
[mesa.git] / src / mesa / main / texstate.c
index 2cc7eb52114d999aecfaa29720f05003ab961fd5..51e19b7f4e7a589dea938c4dad9f2d1f98a12548 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  6.5.3
  *
- * Copyright (C) 1999-2005  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"),
 #include "colortab.h"
 #include "context.h"
 #include "enums.h"
-#include "extensions.h"
 #include "macros.h"
-#include "nvfragprog.h"
+#include "texcompress.h"
 #include "texobj.h"
 #include "teximage.h"
 #include "texstate.h"
 #include "texenvprogram.h"
 #include "mtypes.h"
 #include "math/m_xform.h"
-#include "math/m_matrix.h"
 
 
-
-#ifdef SPECIALCAST
-/* Needed for an Amiga compiler */
 #define ENUM_TO_FLOAT(X) ((GLfloat)(GLint)(X))
 #define ENUM_TO_DOUBLE(X) ((GLdouble)(GLint)(X))
-#else
-/* all other compilers */
-#define ENUM_TO_FLOAT(X) ((GLfloat)(X))
-#define ENUM_TO_DOUBLE(X) ((GLdouble)(X))
-#endif
+
 
 /**
  * Default texture combine environment state.  This is used to initialize
@@ -72,6 +63,35 @@ static const struct gl_tex_env_combine_state default_combine_state = {
 };
 
 
+/**
+ * Copy a texture binding.  Helper used by _mesa_copy_texture_state().
+ */
+static void
+copy_texture_binding(const GLcontext *ctx,
+                     struct gl_texture_object **dst,
+                     struct gl_texture_object *src)
+{
+   /* only copy if names differ (per OpenGL SI) */
+   if ((*dst)->Name != src->Name) {
+      /* unbind/delete dest binding which we're changing */
+      (*dst)->RefCount--;
+      if ((*dst)->RefCount == 0) {
+         /* time to delete this texture object */
+         ASSERT((*dst)->Name != 0);
+         ASSERT(ctx->Driver.DeleteTexture);
+         /* XXX cast-away const, unfortunately */
+         (*ctx->Driver.DeleteTexture)((GLcontext *) ctx, *dst);
+      }
+      /* make new binding, incrementing ref count */
+      *dst = src;
+      src->RefCount++;
+   }
+}
+
+
+/**
+ * Used by glXCopyContext to copy texture state from one context to another.
+ */
 void
 _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst )
 {
@@ -121,17 +141,21 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst )
       dst->Texture.Unit[i].Combine.ScaleShiftRGB = src->Texture.Unit[i].Combine.ScaleShiftRGB;
       dst->Texture.Unit[i].Combine.ScaleShiftA = src->Texture.Unit[i].Combine.ScaleShiftA;
 
-      /* texture object state */
-      _mesa_copy_texture_object(dst->Texture.Unit[i].Current1D,
-                                src->Texture.Unit[i].Current1D);
-      _mesa_copy_texture_object(dst->Texture.Unit[i].Current2D,
-                                src->Texture.Unit[i].Current2D);
-      _mesa_copy_texture_object(dst->Texture.Unit[i].Current3D,
-                                src->Texture.Unit[i].Current3D);
-      _mesa_copy_texture_object(dst->Texture.Unit[i].CurrentCubeMap,
-                                src->Texture.Unit[i].CurrentCubeMap);
-      _mesa_copy_texture_object(dst->Texture.Unit[i].CurrentRect,
-                                src->Texture.Unit[i].CurrentRect);
+      /* copy texture object bindings, not contents of texture objects */
+      _mesa_lock_context_textures(dst);
+
+      copy_texture_binding(src, &dst->Texture.Unit[i].Current1D,
+                           src->Texture.Unit[i].Current1D);
+      copy_texture_binding(src, &dst->Texture.Unit[i].Current2D,
+                           src->Texture.Unit[i].Current2D);
+      copy_texture_binding(src, &dst->Texture.Unit[i].Current3D,
+                           src->Texture.Unit[i].Current3D);
+      copy_texture_binding(src, &dst->Texture.Unit[i].CurrentCubeMap,
+                           src->Texture.Unit[i].CurrentCubeMap);
+      copy_texture_binding(src, &dst->Texture.Unit[i].CurrentRect,
+                           src->Texture.Unit[i].CurrentRect);
+
+      _mesa_unlock_context_textures(dst);
    }
 }
 
@@ -291,10 +315,20 @@ calculate_derived_texenv( struct gl_tex_env_combine_state *state,
 void GLAPIENTRY
 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
 {
+   GLuint maxUnit;
    GET_CURRENT_CONTEXT(ctx);
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_unit *texUnit;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+   if (ctx->Texture.CurrentUnit >= maxUnit) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
 #define TE_ERROR(errCode, msg, value)                          \
    _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
 
@@ -774,10 +808,20 @@ _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
 void GLAPIENTRY
 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
 {
+   GLuint maxUnit;
+   const struct gl_texture_unit *texUnit;
    GET_CURRENT_CONTEXT(ctx);
-   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+   if (ctx->Texture.CurrentUnit >= maxUnit) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    if (target == GL_TEXTURE_ENV) {
       switch (pname) {
          case GL_TEXTURE_ENV_MODE:
@@ -985,10 +1029,20 @@ _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
 void GLAPIENTRY
 _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
 {
+   GLuint maxUnit;
+   const struct gl_texture_unit *texUnit;
    GET_CURRENT_CONTEXT(ctx);
-   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+   if (ctx->Texture.CurrentUnit >= maxUnit) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    if (target == GL_TEXTURE_ENV) {
       switch (pname) {
          case GL_TEXTURE_ENV_MODE:
@@ -1243,10 +1297,10 @@ _mesa_TexParameterf( GLenum target, GLenum pname, GLfloat param )
 void GLAPIENTRY
 _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-   GLenum eparam = (GLenum) (GLint) params[0];
+   const GLenum eparam = (GLenum) (GLint) params[0];
+   struct gl_texture_unit *texUnit;
    struct gl_texture_object *texObj;
+   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
@@ -1256,6 +1310,12 @@ _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
                   *params,
                  _mesa_lookup_enum_by_nr(eparam));
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexParameterfv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
 
    switch (target) {
       case GL_TEXTURE_1D:
@@ -1380,11 +1440,11 @@ _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
          break;
       case GL_TEXTURE_BASE_LEVEL:
          if (params[0] < 0.0) {
-            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
+            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)");
             return;
          }
-         if (target == GL_TEXTURE_RECTANGLE_NV && params[0] != 0.0) {
-            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
+         if (target == GL_TEXTURE_RECTANGLE_ARB && params[0] != 0.0) {
+            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)");
             return;
          }
          FLUSH_VERTICES(ctx, _NEW_TEXTURE);
@@ -1392,7 +1452,11 @@ _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
          break;
       case GL_TEXTURE_MAX_LEVEL:
          if (params[0] < 0.0) {
-            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)" );
+            _mesa_error(ctx, GL_INVALID_VALUE, "glTexParameter(param)");
+            return;
+         }
+         if (target == GL_TEXTURE_RECTANGLE_ARB) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glTexParameter(param)");
             return;
          }
          FLUSH_VERTICES(ctx, _NEW_TEXTURE);
@@ -1641,14 +1705,23 @@ void GLAPIENTRY
 _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                               GLenum pname, GLint *params )
 {
-   GET_CURRENT_CONTEXT(ctx);
-   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   const struct gl_texture_unit *texUnit;
+   struct gl_texture_object *texObj;
    const struct gl_texture_image *img = NULL;
    GLuint dimensions;
    GLboolean isProxy;
    GLint maxLevels;
+   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTexLevelParameteriv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    /* this will catch bad target values */
    dimensions = tex_image_dimensions(ctx, target);  /* 1, 2 or 3 */
    if (dimensions == 0) {
@@ -1656,32 +1729,10 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
       return;
    }
 
-   switch (target) {
-   case GL_TEXTURE_1D:
-   case GL_PROXY_TEXTURE_1D:
-   case GL_TEXTURE_2D:
-   case GL_PROXY_TEXTURE_2D:
-      maxLevels = ctx->Const.MaxTextureLevels;
-      break;
-   case GL_TEXTURE_3D:
-   case GL_PROXY_TEXTURE_3D:
-      maxLevels = ctx->Const.Max3DTextureLevels;
-      break;
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-   case GL_PROXY_TEXTURE_CUBE_MAP:
-      maxLevels = ctx->Const.MaxCubeTextureLevels;
-      break;
-   case GL_TEXTURE_RECTANGLE_NV:
-   case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      maxLevels = 1;
-      break;
-   default:
-      _mesa_problem(ctx, "switch in _mesa_GetTexLevelParameter");
+   maxLevels = _mesa_max_texture_levels(ctx, target);
+   if (maxLevels == 0) {
+      /* should not happen since <target> was just checked above */
+      _mesa_problem(ctx, "maxLevels=0 in _mesa_GetTexLevelParameter");
       return;
    }
 
@@ -1690,86 +1741,86 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
       return;
    }
 
-   img = _mesa_select_tex_image(ctx, texUnit, target, level);
+   texObj = _mesa_select_tex_object(ctx, texUnit, target);
+   _mesa_lock_texture(ctx, texObj);
+
+   img = _mesa_select_tex_image(ctx, texObj, target, level);
    if (!img || !img->TexFormat) {
       /* undefined texture image */
       if (pname == GL_TEXTURE_COMPONENTS)
          *params = 1;
       else
          *params = 0;
-      return;
+      goto out;
    }
 
-   isProxy = (target == GL_PROXY_TEXTURE_1D) ||
-             (target == GL_PROXY_TEXTURE_2D) ||
-             (target == GL_PROXY_TEXTURE_3D) ||
-             (target == GL_PROXY_TEXTURE_CUBE_MAP) ||
-             (target == GL_PROXY_TEXTURE_RECTANGLE_NV);
+   isProxy = _mesa_is_proxy_texture(target);
 
    switch (pname) {
       case GL_TEXTURE_WIDTH:
          *params = img->Width;
-         return;
+         break;
       case GL_TEXTURE_HEIGHT:
          *params = img->Height;
-         return;
+         break;
       case GL_TEXTURE_DEPTH:
          *params = img->Depth;
-         return;
+         break;
       case GL_TEXTURE_INTERNAL_FORMAT:
-         *params = img->IntFormat;
-         return;
+         *params = img->InternalFormat;
+         break;
       case GL_TEXTURE_BORDER:
          *params = img->Border;
-         return;
+         break;
       case GL_TEXTURE_RED_SIZE:
-         if (img->Format == GL_RGB || img->Format == GL_RGBA)
+         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
             *params = img->TexFormat->RedBits;
          else
             *params = 0;
-         return;
+         break;
       case GL_TEXTURE_GREEN_SIZE:
-         if (img->Format == GL_RGB || img->Format == GL_RGBA)
+         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
             *params = img->TexFormat->GreenBits;
          else
             *params = 0;
-         return;
+         break;
       case GL_TEXTURE_BLUE_SIZE:
-         if (img->Format == GL_RGB || img->Format == GL_RGBA)
+         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
             *params = img->TexFormat->BlueBits;
          else
             *params = 0;
-         return;
+         break;
       case GL_TEXTURE_ALPHA_SIZE:
-         if (img->Format == GL_ALPHA || img->Format == GL_LUMINANCE_ALPHA ||
-             img->Format == GL_RGBA)
+         if (img->_BaseFormat == GL_ALPHA ||
+             img->_BaseFormat == GL_LUMINANCE_ALPHA ||
+             img->_BaseFormat == GL_RGBA)
             *params = img->TexFormat->AlphaBits;
          else
             *params = 0;
-         return;
+         break;
       case GL_TEXTURE_INTENSITY_SIZE:
-         if (img->Format != GL_INTENSITY)
+         if (img->_BaseFormat != GL_INTENSITY)
             *params = 0;
          else if (img->TexFormat->IntensityBits > 0)
             *params = img->TexFormat->IntensityBits;
          else /* intensity probably stored as rgb texture */
             *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits);
-         return;
+         break;
       case GL_TEXTURE_LUMINANCE_SIZE:
-         if (img->Format != GL_LUMINANCE &&
-             img->Format != GL_LUMINANCE_ALPHA)
+         if (img->_BaseFormat != GL_LUMINANCE &&
+             img->_BaseFormat != GL_LUMINANCE_ALPHA)
             *params = 0;
          else if (img->TexFormat->LuminanceBits > 0)
             *params = img->TexFormat->LuminanceBits;
          else /* luminance probably stored as rgb texture */
             *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits);
-         return;
+         break;
       case GL_TEXTURE_INDEX_SIZE_EXT:
-         if (img->Format == GL_COLOR_INDEX)
+         if (img->_BaseFormat == GL_COLOR_INDEX)
             *params = img->TexFormat->IndexBits;
          else
             *params = 0;
-         return;
+         break;
       case GL_TEXTURE_DEPTH_SIZE_ARB:
          if (ctx->Extensions.SGIX_depth_texture ||
              ctx->Extensions.ARB_depth_texture)
@@ -1777,7 +1828,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
          else
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
-         return;
+         break;
       case GL_TEXTURE_STENCIL_SIZE_EXT:
          if (ctx->Extensions.EXT_packed_depth_stencil) {
             *params = img->TexFormat->StencilBits;
@@ -1786,22 +1837,29 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
 
       /* GL_ARB_texture_compression */
       case GL_TEXTURE_COMPRESSED_IMAGE_SIZE:
          if (ctx->Extensions.ARB_texture_compression) {
-            if (img->IsCompressed && !isProxy)
-               *params = img->CompressedSize;
-            else
+            if (img->IsCompressed && !isProxy) {
+               /* Don't use ctx->Driver.CompressedTextureSize() since that
+                * may returned a padded hardware size.
+                */
+               *params = _mesa_compressed_texture_size(ctx, img->Width,
+                                                   img->Height, img->Depth,
+                                                   img->TexFormat->MesaFormat);
+            }
+            else {
                _mesa_error(ctx, GL_INVALID_OPERATION,
                            "glGetTexLevelParameter[if]v(pname)");
+            }
          }
          else {
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_COMPRESSED:
          if (ctx->Extensions.ARB_texture_compression) {
             *params = (GLint) img->IsCompressed;
@@ -1810,7 +1868,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
 
       /* GL_ARB_texture_float */
       case GL_TEXTURE_RED_TYPE_ARB:
@@ -1821,7 +1879,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_GREEN_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->GreenBits ? img->TexFormat->DataType : GL_NONE;
@@ -1830,7 +1888,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_BLUE_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->BlueBits ? img->TexFormat->DataType : GL_NONE;
@@ -1839,7 +1897,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_ALPHA_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->AlphaBits ? img->TexFormat->DataType : GL_NONE;
@@ -1848,7 +1906,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_LUMINANCE_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->LuminanceBits ? img->TexFormat->DataType : GL_NONE;
@@ -1857,7 +1915,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_INTENSITY_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->IntensityBits ? img->TexFormat->DataType : GL_NONE;
@@ -1866,7 +1924,7 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
       case GL_TEXTURE_DEPTH_TYPE_ARB:
          if (ctx->Extensions.ARB_texture_float) {
             *params = img->TexFormat->DepthBits ? img->TexFormat->DataType : GL_NONE;
@@ -1875,12 +1933,15 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
             _mesa_error(ctx, GL_INVALID_ENUM,
                         "glGetTexLevelParameter[if]v(pname)");
          }
-         return;
+         break;
 
       default:
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glGetTexLevelParameter[if]v(pname)");
    }
+
+ out:
+   _mesa_unlock_texture(ctx, texObj);
 }
 
 
@@ -1888,39 +1949,49 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level,
 void GLAPIENTRY
 _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params )
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_unit *texUnit;
    struct gl_texture_object *obj;
+   GLboolean error = GL_FALSE;
+   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTexParameterfv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    obj = _mesa_select_tex_object(ctx, texUnit, target);
    if (!obj) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(target)");
       return;
    }
 
+   _mesa_lock_texture(ctx, obj);
    switch (pname) {
       case GL_TEXTURE_MAG_FILTER:
         *params = ENUM_TO_FLOAT(obj->MagFilter);
-        return;
+        break;
       case GL_TEXTURE_MIN_FILTER:
          *params = ENUM_TO_FLOAT(obj->MinFilter);
-         return;
+         break;
       case GL_TEXTURE_WRAP_S:
          *params = ENUM_TO_FLOAT(obj->WrapS);
-         return;
+         break;
       case GL_TEXTURE_WRAP_T:
          *params = ENUM_TO_FLOAT(obj->WrapT);
-         return;
+         break;
       case GL_TEXTURE_WRAP_R:
          *params = ENUM_TO_FLOAT(obj->WrapR);
-         return;
+         break;
       case GL_TEXTURE_BORDER_COLOR:
          params[0] = CLAMP(obj->BorderColor[0], 0.0F, 1.0F);
          params[1] = CLAMP(obj->BorderColor[1], 0.0F, 1.0F);
          params[2] = CLAMP(obj->BorderColor[2], 0.0F, 1.0F);
          params[3] = CLAMP(obj->BorderColor[3], 0.0F, 1.0F);
-         return;
+         break;
       case GL_TEXTURE_RESIDENT:
          {
             GLboolean resident;
@@ -1930,93 +2001,113 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params )
                resident = GL_TRUE;
             *params = ENUM_TO_FLOAT(resident);
          }
-         return;
+         break;
       case GL_TEXTURE_PRIORITY:
          *params = obj->Priority;
-         return;
+         break;
       case GL_TEXTURE_MIN_LOD:
          *params = obj->MinLod;
-         return;
+         break;
       case GL_TEXTURE_MAX_LOD:
          *params = obj->MaxLod;
-         return;
+         break;
       case GL_TEXTURE_BASE_LEVEL:
          *params = (GLfloat) obj->BaseLevel;
-         return;
+         break;
       case GL_TEXTURE_MAX_LEVEL:
          *params = (GLfloat) obj->MaxLevel;
-         return;
+         break;
       case GL_TEXTURE_MAX_ANISOTROPY_EXT:
          if (ctx->Extensions.EXT_texture_filter_anisotropic) {
             *params = obj->MaxAnisotropy;
-            return;
          }
+        else
+           error = 1;
          break;
       case GL_TEXTURE_COMPARE_SGIX:
          if (ctx->Extensions.SGIX_shadow) {
             *params = (GLfloat) obj->CompareFlag;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_TEXTURE_COMPARE_OPERATOR_SGIX:
          if (ctx->Extensions.SGIX_shadow) {
             *params = (GLfloat) obj->CompareOperator;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_SHADOW_AMBIENT_SGIX: /* aka GL_TEXTURE_COMPARE_FAIL_VALUE_ARB */
          if (ctx->Extensions.SGIX_shadow_ambient) {
             *params = obj->ShadowAmbient;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_GENERATE_MIPMAP_SGIS:
          if (ctx->Extensions.SGIS_generate_mipmap) {
             *params = (GLfloat) obj->GenerateMipmap;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_TEXTURE_COMPARE_MODE_ARB:
          if (ctx->Extensions.ARB_shadow) {
             *params = (GLfloat) obj->CompareMode;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_TEXTURE_COMPARE_FUNC_ARB:
          if (ctx->Extensions.ARB_shadow) {
             *params = (GLfloat) obj->CompareFunc;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_DEPTH_TEXTURE_MODE_ARB:
          if (ctx->Extensions.ARB_depth_texture) {
             *params = (GLfloat) obj->DepthMode;
-            return;
          }
+        else 
+           error = 1;
          break;
       case GL_TEXTURE_LOD_BIAS:
          if (ctx->Extensions.EXT_texture_lod_bias) {
             *params = obj->LodBias;
-            return;
          }
+        else 
+           error = 1;
          break;
       default:
-         ; /* silence warnings */
+        error = 1;
+        break;
    }
-   /* If we get here, pname was an unrecognized enum */
-   _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)",
-               pname);
+   if (error)
+      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameterfv(pname=0x%x)",
+                 pname);
+
+   _mesa_unlock_texture(ctx, obj);
 }
 
 
 void GLAPIENTRY
 _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params )
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   struct gl_texture_unit *texUnit;
    struct gl_texture_object *obj;
+   GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureImageUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTexParameteriv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    obj = _mesa_select_tex_object(ctx, texUnit, target);
    if (!obj) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexParameteriv(target)");
@@ -2150,8 +2241,7 @@ void GLAPIENTRY
 _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLuint tUnit = ctx->Texture.CurrentUnit;
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[tUnit];
+   struct gl_texture_unit *texUnit;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
@@ -2161,6 +2251,13 @@ _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
                   *params,
                  _mesa_lookup_enum_by_nr((GLenum) (GLint) *params));
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexGen(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    switch (coord) {
       case GL_S:
          if (pname==GL_TEXTURE_GEN_MODE) {
@@ -2196,14 +2293,10 @@ _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
            if (TEST_EQ_4V(texUnit->ObjectPlaneS, params))
                return;
            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->ObjectPlaneS[0] = params[0];
-           texUnit->ObjectPlaneS[1] = params[1];
-           texUnit->ObjectPlaneS[2] = params[2];
-           texUnit->ObjectPlaneS[3] = params[3];
+            COPY_4FV(texUnit->ObjectPlaneS, params);
         }
         else if (pname==GL_EYE_PLANE) {
            GLfloat tmp[4];
-
             /* Transform plane equation by the inverse modelview matrix */
             if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) {
                _math_matrix_analyse( ctx->ModelviewMatrixStack.Top );
@@ -2253,10 +2346,7 @@ _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
            if (TEST_EQ_4V(texUnit->ObjectPlaneT, params))
                return;
            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->ObjectPlaneT[0] = params[0];
-           texUnit->ObjectPlaneT[1] = params[1];
-           texUnit->ObjectPlaneT[2] = params[2];
-           texUnit->ObjectPlaneT[3] = params[3];
+            COPY_4FV(texUnit->ObjectPlaneT, params);
         }
         else if (pname==GL_EYE_PLANE) {
            GLfloat tmp[4];
@@ -2306,10 +2396,7 @@ _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
            if (TEST_EQ_4V(texUnit->ObjectPlaneR, params))
                return;
            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->ObjectPlaneR[0] = params[0];
-           texUnit->ObjectPlaneR[1] = params[1];
-           texUnit->ObjectPlaneR[2] = params[2];
-           texUnit->ObjectPlaneR[3] = params[3];
+           COPY_4FV(texUnit->ObjectPlaneR, params);
         }
         else if (pname==GL_EYE_PLANE) {
            GLfloat tmp[4];
@@ -2353,10 +2440,7 @@ _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params )
            if (TEST_EQ_4V(texUnit->ObjectPlaneQ, params))
                return;
            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->ObjectPlaneQ[0] = params[0];
-           texUnit->ObjectPlaneQ[1] = params[1];
-           texUnit->ObjectPlaneQ[2] = params[2];
-           texUnit->ObjectPlaneQ[3] = params[3];
+            COPY_4FV(texUnit->ObjectPlaneQ, params);
         }
         else if (pname==GL_EYE_PLANE) {
            GLfloat tmp[4];
@@ -2445,11 +2529,17 @@ _mesa_TexGeni( GLenum coord, GLenum pname, GLint param )
 void GLAPIENTRY
 _mesa_GetTexGendv( GLenum coord, GLenum pname, GLdouble *params )
 {
+   const struct gl_texture_unit *texUnit;
    GET_CURRENT_CONTEXT(ctx);
-   GLuint tUnit = ctx->Texture.CurrentUnit;
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[tUnit];
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGendv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    switch (coord) {
       case GL_S:
          if (pname==GL_TEXTURE_GEN_MODE) {
@@ -2522,11 +2612,17 @@ _mesa_GetTexGendv( GLenum coord, GLenum pname, GLdouble *params )
 void GLAPIENTRY
 _mesa_GetTexGenfv( GLenum coord, GLenum pname, GLfloat *params )
 {
+   const struct gl_texture_unit *texUnit;
    GET_CURRENT_CONTEXT(ctx);
-   GLuint tUnit = ctx->Texture.CurrentUnit;
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[tUnit];
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGenfv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    switch (coord) {
       case GL_S:
          if (pname==GL_TEXTURE_GEN_MODE) {
@@ -2599,11 +2695,17 @@ _mesa_GetTexGenfv( GLenum coord, GLenum pname, GLfloat *params )
 void GLAPIENTRY
 _mesa_GetTexGeniv( GLenum coord, GLenum pname, GLint *params )
 {
+   const struct gl_texture_unit *texUnit;
    GET_CURRENT_CONTEXT(ctx);
-   GLuint tUnit = ctx->Texture.CurrentUnit;
-   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[tUnit];
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
+   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexGeniv(current unit)");
+      return;
+   }
+
+   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+
    switch (coord) {
       case GL_S:
          if (pname==GL_TEXTURE_GEN_MODE) {
@@ -2696,21 +2798,22 @@ _mesa_GetTexGeniv( GLenum coord, GLenum pname, GLint *params )
 }
 #endif
 
+
 /* GL_ARB_multitexture */
 void GLAPIENTRY
-_mesa_ActiveTextureARB( GLenum target )
+_mesa_ActiveTextureARB(GLenum texture)
 {
    GET_CURRENT_CONTEXT(ctx);
-   const GLuint texUnit = target - GL_TEXTURE0;
+   const GLuint texUnit = texture - GL_TEXTURE0;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
       _mesa_debug(ctx, "glActiveTexture %s\n",
-                  _mesa_lookup_enum_by_nr(target));
+                  _mesa_lookup_enum_by_nr(texture));
 
-   /* Cater for texture unit 0 is first, therefore use >= */
+   /* XXX error-check against max(coordunits, imageunits) */
    if (texUnit >= ctx->Const.MaxTextureUnits) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(target)");
+      _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture)");
       return;
    }
 
@@ -2733,14 +2836,14 @@ _mesa_ActiveTextureARB( GLenum target )
 
 /* GL_ARB_multitexture */
 void GLAPIENTRY
-_mesa_ClientActiveTextureARB( GLenum target )
+_mesa_ClientActiveTextureARB(GLenum texture)
 {
    GET_CURRENT_CONTEXT(ctx);
-   GLuint texUnit = target - GL_TEXTURE0;
+   GLuint texUnit = texture - GL_TEXTURE0;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
-   if (texUnit > ctx->Const.MaxTextureUnits) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(target)");
+   if (texUnit >= ctx->Const.MaxTextureCoordUnits) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(texture)");
       return;
    }
 
@@ -2750,138 +2853,6 @@ _mesa_ClientActiveTextureARB( GLenum target )
 
 
 
-/**********************************************************************/
-/*                     Pixel Texgen Extensions                        */
-/**********************************************************************/
-
-void GLAPIENTRY
-_mesa_PixelTexGenSGIX(GLenum mode)
-{
-   GLenum newRgbSource, newAlphaSource;
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   switch (mode) {
-      case GL_NONE:
-         newRgbSource = GL_PIXEL_GROUP_COLOR_SGIS;
-         newAlphaSource = GL_PIXEL_GROUP_COLOR_SGIS;
-         break;
-      case GL_ALPHA:
-         newRgbSource = GL_PIXEL_GROUP_COLOR_SGIS;
-         newAlphaSource = GL_CURRENT_RASTER_COLOR;
-         break;
-      case GL_RGB:
-         newRgbSource = GL_CURRENT_RASTER_COLOR;
-         newAlphaSource = GL_PIXEL_GROUP_COLOR_SGIS;
-         break;
-      case GL_RGBA:
-         newRgbSource = GL_CURRENT_RASTER_COLOR;
-         newAlphaSource = GL_CURRENT_RASTER_COLOR;
-         break;
-      default:
-         _mesa_error(ctx, GL_INVALID_ENUM, "glPixelTexGenSGIX(mode)");
-         return;
-   }
-
-   if (newRgbSource == ctx->Pixel.FragmentRgbSource &&
-       newAlphaSource == ctx->Pixel.FragmentAlphaSource)
-      return;
-
-   FLUSH_VERTICES(ctx, _NEW_PIXEL);
-   ctx->Pixel.FragmentRgbSource = newRgbSource;
-   ctx->Pixel.FragmentAlphaSource = newAlphaSource;
-}
-
-
-void GLAPIENTRY
-_mesa_PixelTexGenParameterfSGIS(GLenum target, GLfloat value)
-{
-   _mesa_PixelTexGenParameteriSGIS(target, (GLint) value);
-}
-
-
-void GLAPIENTRY
-_mesa_PixelTexGenParameterfvSGIS(GLenum target, const GLfloat *value)
-{
-   _mesa_PixelTexGenParameteriSGIS(target, (GLint) *value);
-}
-
-
-void GLAPIENTRY
-_mesa_PixelTexGenParameteriSGIS(GLenum target, GLint value)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   if (value != GL_CURRENT_RASTER_COLOR && value != GL_PIXEL_GROUP_COLOR_SGIS) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glPixelTexGenParameterSGIS(value)");
-      return;
-   }
-
-   switch (target) {
-   case GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS:
-      if (ctx->Pixel.FragmentRgbSource == (GLenum) value)
-        return;
-      FLUSH_VERTICES(ctx, _NEW_PIXEL);
-      ctx->Pixel.FragmentRgbSource = (GLenum) value;
-      break;
-   case GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS:
-      if (ctx->Pixel.FragmentAlphaSource == (GLenum) value)
-        return;
-      FLUSH_VERTICES(ctx, _NEW_PIXEL);
-      ctx->Pixel.FragmentAlphaSource = (GLenum) value;
-      break;
-   default:
-      _mesa_error(ctx, GL_INVALID_ENUM, "glPixelTexGenParameterSGIS(target)");
-      return;
-   }
-}
-
-
-void GLAPIENTRY
-_mesa_PixelTexGenParameterivSGIS(GLenum target, const GLint *value)
-{
-  _mesa_PixelTexGenParameteriSGIS(target, *value);
-}
-
-
-void GLAPIENTRY
-_mesa_GetPixelTexGenParameterfvSGIS(GLenum target, GLfloat *value)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   if (target == GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS) {
-      *value = (GLfloat) ctx->Pixel.FragmentRgbSource;
-   }
-   else if (target == GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS) {
-      *value = (GLfloat) ctx->Pixel.FragmentAlphaSource;
-   }
-   else {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelTexGenParameterfvSGIS(target)");
-   }
-}
-
-
-void GLAPIENTRY
-_mesa_GetPixelTexGenParameterivSGIS(GLenum target, GLint *value)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
-
-   if (target == GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS) {
-      *value = (GLint) ctx->Pixel.FragmentRgbSource;
-   }
-   else if (target == GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS) {
-      *value = (GLint) ctx->Pixel.FragmentAlphaSource;
-   }
-   else {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelTexGenParameterivSGIS(target)");
-   }
-}
-
-
-
 /**********************************************************************/
 /*****                    State management                        *****/
 /**********************************************************************/
@@ -2917,6 +2888,25 @@ update_texture_matrices( GLcontext *ctx )
 }
 
 
+/**
+ * Helper function for determining which texture object (1D, 2D, cube, etc)
+ * should actually be used.
+ */
+static void
+texture_override(GLcontext *ctx,
+                 struct gl_texture_unit *texUnit, GLbitfield enableBits,
+                 struct gl_texture_object *texObj, GLuint textureBit)
+{
+   if (!texUnit->_ReallyEnabled && (enableBits & textureBit)) {
+      if (!texObj->Complete) {
+         _mesa_test_texobj_completeness(ctx, texObj);
+      }
+      if (texObj->Complete) {
+         texUnit->_ReallyEnabled = textureBit;
+         texUnit->_Current = texObj;
+      }
+   }
+}
 
 
 /**
@@ -2931,6 +2921,18 @@ static void
 update_texture_state( GLcontext *ctx )
 {
    GLuint unit;
+   struct gl_fragment_program *fprog;
+
+   if (ctx->Shader.CurrentProgram &&
+       ctx->Shader.CurrentProgram->LinkStatus) {
+      fprog = ctx->Shader.CurrentProgram->FragmentProgram;
+   }
+   else if (ctx->FragmentProgram._Enabled) {
+      fprog = ctx->FragmentProgram.Current;
+   }
+   else {
+      fprog = NULL;
+   }
 
    ctx->NewState |= _NEW_TEXTURE; /* TODO: only set this if there are 
                                   * actual changes. 
@@ -2941,9 +2943,8 @@ update_texture_state( GLcontext *ctx )
    ctx->Texture._TexMatEnabled = 0;
    ctx->Texture._TexGenEnabled = 0;
 
-   /* Update texture unit state.
-    * XXX this loop should probably be broken into separate loops for
-    * texture coord units and texture image units.
+   /*
+    * Update texture unit state.
     */
    for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
@@ -2953,9 +2954,14 @@ update_texture_state( GLcontext *ctx )
       texUnit->_ReallyEnabled = 0;
       texUnit->_GenFlags = 0;
 
-      /* Get the bitmask of texture enables */
-      if (ctx->FragmentProgram._Enabled) {
-         enableBits = ctx->FragmentProgram.Current->TexturesUsed[unit];
+      /* Get the bitmask of texture enables.
+       * enableBits will be a mask of the TEXTURE_*_BIT flags indicating
+       * which texture targets are enabled (fixed function) or referenced
+       * by a fragment shader/program.  When multiple flags are set, we'll
+       * settle on the one with highest priority (see texture_override below).
+       */
+      if (fprog) {
+         enableBits = fprog->Base.TexturesUsed[unit];
       }
       else {
          if (!texUnit->Enabled)
@@ -2967,60 +2973,16 @@ update_texture_state( GLcontext *ctx )
        * complete.  That's the one we'll use for texturing.  If we're using
        * a fragment program we're guaranteed that bitcount(enabledBits) <= 1.
        */
-      if (enableBits & TEXTURE_CUBE_BIT) {
-         struct gl_texture_object *texObj = texUnit->CurrentCubeMap;
-         if (!texObj->Complete) {
-            _mesa_test_texobj_completeness(ctx, texObj);
-         }
-         if (texObj->Complete) {
-            texUnit->_ReallyEnabled = TEXTURE_CUBE_BIT;
-            texUnit->_Current = texObj;
-         }
-      }
-
-      if (!texUnit->_ReallyEnabled && (enableBits & TEXTURE_3D_BIT)) {
-         struct gl_texture_object *texObj = texUnit->Current3D;
-         if (!texObj->Complete) {
-            _mesa_test_texobj_completeness(ctx, texObj);
-         }
-         if (texObj->Complete) {
-            texUnit->_ReallyEnabled = TEXTURE_3D_BIT;
-            texUnit->_Current = texObj;
-         }
-      }
-
-      if (!texUnit->_ReallyEnabled && (enableBits & TEXTURE_RECT_BIT)) {
-         struct gl_texture_object *texObj = texUnit->CurrentRect;
-         if (!texObj->Complete) {
-            _mesa_test_texobj_completeness(ctx, texObj);
-         }
-         if (texObj->Complete) {
-            texUnit->_ReallyEnabled = TEXTURE_RECT_BIT;
-            texUnit->_Current = texObj;
-         }
-      }
-
-      if (!texUnit->_ReallyEnabled && (enableBits & TEXTURE_2D_BIT)) {
-         struct gl_texture_object *texObj = texUnit->Current2D;
-         if (!texObj->Complete) {
-            _mesa_test_texobj_completeness(ctx, texObj);
-         }
-         if (texObj->Complete) {
-            texUnit->_ReallyEnabled = TEXTURE_2D_BIT;
-            texUnit->_Current = texObj;
-         }
-      }
-
-      if (!texUnit->_ReallyEnabled && (enableBits & TEXTURE_1D_BIT)) {
-         struct gl_texture_object *texObj = texUnit->Current1D;
-         if (!texObj->Complete) {
-            _mesa_test_texobj_completeness(ctx, texObj);
-         }
-         if (texObj->Complete) {
-            texUnit->_ReallyEnabled = TEXTURE_1D_BIT;
-            texUnit->_Current = texObj;
-         }
-      }
+      texture_override(ctx, texUnit, enableBits,
+                       texUnit->CurrentCubeMap, TEXTURE_CUBE_BIT);
+      texture_override(ctx, texUnit, enableBits,
+                       texUnit->Current3D, TEXTURE_3D_BIT);
+      texture_override(ctx, texUnit, enableBits,
+                       texUnit->CurrentRect, TEXTURE_RECT_BIT);
+      texture_override(ctx, texUnit, enableBits,
+                       texUnit->Current2D, TEXTURE_2D_BIT);
+      texture_override(ctx, texUnit, enableBits,
+                       texUnit->Current1D, TEXTURE_1D_BIT);
 
       if (!texUnit->_ReallyEnabled) {
          continue;
@@ -3033,12 +2995,14 @@ update_texture_state( GLcontext *ctx )
         texUnit->_CurrentCombine = & texUnit->Combine;
       }
       else {
-         GLenum format = texUnit->_Current->Image[0][0]->Format;
+         const struct gl_texture_object *texObj = texUnit->_Current;
+         GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat;
          if (format == GL_COLOR_INDEX) {
             format = GL_RGBA;  /* a bit of a hack */
          }
-         else if (format == GL_DEPTH_COMPONENT) {
-            format = texUnit->_Current->DepthMode;
+         else if (format == GL_DEPTH_COMPONENT
+                  || format == GL_DEPTH_STENCIL_EXT) {
+            format = texObj->DepthMode;
          }
         calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format);
         texUnit->_CurrentCombine = & texUnit->_EnvMode;
@@ -3114,18 +3078,23 @@ update_texture_state( GLcontext *ctx )
         ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(unit);
    }
 
-   ctx->Texture._EnabledCoordUnits = ctx->Texture._EnabledUnits;
-   /* Fragment programs may need texture coordinates but not the
-    * corresponding texture images.
-    */
-   if (ctx->FragmentProgram._Enabled) {
-      ctx->Texture._EnabledCoordUnits |=
-         (ctx->FragmentProgram.Current->InputsRead >> FRAG_ATTRIB_TEX0);
+   /* Determine which texture coordinate sets are actually needed */
+   if (fprog) {
+      const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
+      ctx->Texture._EnabledCoordUnits
+         = (fprog->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask;
+   }
+   else {
+      ctx->Texture._EnabledCoordUnits = ctx->Texture._EnabledUnits;
    }
 }
 
 
-void _mesa_update_texture( GLcontext *ctx, GLuint new_state )
+/**
+ * Update texture-related derived state.
+ */
+void
+_mesa_update_texture( GLcontext *ctx, GLuint new_state )
 {
    if (new_state & _NEW_TEXTURE_MATRIX)
       update_texture_matrices( ctx );
@@ -3134,6 +3103,7 @@ void _mesa_update_texture( GLcontext *ctx, GLuint new_state )
       update_texture_state( ctx );
 }
 
+
 /**********************************************************************/
 /*****                      Initialization                        *****/
 /**********************************************************************/
@@ -3234,9 +3204,13 @@ init_texture_unit( GLcontext *ctx, GLuint unit )
 }
 
 
-GLboolean _mesa_init_texture( GLcontext * ctx )
+/**
+ * Initialize texture state for the given context.
+ */
+GLboolean
+_mesa_init_texture(GLcontext *ctx)
 {
-   int i;
+   GLuint i;
 
    assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
    assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
@@ -3256,6 +3230,8 @@ GLboolean _mesa_init_texture( GLcontext * ctx )
    ctx->Texture.SharedPalette = GL_FALSE;
    _mesa_init_colortable(&ctx->Texture.Palette);
 
+   _mesa_TexEnvProgramCacheInit( ctx );
+
    /* Allocate proxy textures */
    if (!alloc_proxy_textures( ctx ))
       return GL_FALSE;
@@ -3263,9 +3239,14 @@ GLboolean _mesa_init_texture( GLcontext * ctx )
    return GL_TRUE;
 }
 
-void _mesa_free_texture_data( GLcontext *ctx )
+
+/**
+ * Free dynamically-allocted texture data attached to the given context.
+ */
+void
+_mesa_free_texture_data(GLcontext *ctx)
 {
-   int i;
+   GLuint i;
 
    /* Free proxy texture objects */
    (ctx->Driver.DeleteTexture)(ctx,  ctx->Texture.Proxy1D );