Merge branch 'master' into gallium-0.2
[mesa.git] / src / mesa / swrast / s_texfilter.c
index 59673bb978acc88909de932da3bd7203067917e3..9e44fba3daf146c4c39634acef67a1278f595dac 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  7.0.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 "glheader.h"
-#include "context.h"
-#include "colormac.h"
-#include "imports.h"
-#include "texformat.h"
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/colormac.h"
+#include "main/imports.h"
+#include "main/texformat.h"
 
 #include "s_context.h"
 #include "s_texfilter.h"
@@ -213,17 +213,10 @@ lerp_rgba_3d(GLchan result[4], GLfloat a, GLfloat b, GLfloat c,
 
 
 /**
- * Compute the remainder of a divided by b, but be careful with
- * negative values so that GL_REPEAT mode works right.
+ * If A is a signed integer, A % B doesn't give the right value for A < 0
+ * (in terms of texture repeat).  Just casting to unsigned fixes that.
  */
-static INLINE GLint
-repeat_remainder(GLint a, GLint b)
-{
-   if (a >= 0)
-      return a % b;
-   else
-      return (a + 1) % b + b - 1;
-}
+#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
 
 
 /**
@@ -241,13 +234,13 @@ repeat_remainder(GLint a, GLint b)
    switch (wrapMode) {                                                 \
    case GL_REPEAT:                                                     \
       U = S * SIZE - 0.5F;                                             \
-      if (tObj->_IsPowerOfTwo) {                                       \
+      if (img->_IsPowerOfTwo) {                                                \
          I0 = IFLOOR(U) & (SIZE - 1);                                  \
          I1 = (I0 + 1) & (SIZE - 1);                                   \
       }                                                                        \
       else {                                                           \
-         I0 = repeat_remainder(IFLOOR(U), SIZE);                       \
-         I1 = repeat_remainder(I0 + 1, SIZE);                          \
+         I0 = REMAINDER(IFLOOR(U), SIZE);                              \
+         I1 = REMAINDER(I0 + 1, SIZE);                                 \
       }                                                                        \
       break;                                                           \
    case GL_CLAMP_TO_EDGE:                                              \
@@ -297,7 +290,7 @@ repeat_remainder(GLint a, GLint b)
       }                                                                        \
       break;                                                           \
    case GL_MIRROR_CLAMP_EXT:                                           \
-      U = (GLfloat) fabs(S);                                           \
+      U = FABSF(S);                                                    \
       if (U >= 1.0F)                                                   \
          U = (GLfloat) SIZE;                                           \
       else                                                             \
@@ -307,7 +300,7 @@ repeat_remainder(GLint a, GLint b)
       I1 = I0 + 1;                                                     \
       break;                                                           \
    case GL_MIRROR_CLAMP_TO_EDGE_EXT:                                   \
-      U = (GLfloat) fabs(S);                                           \
+      U = FABSF(S);                                                    \
       if (U >= 1.0F)                                                   \
          U = (GLfloat) SIZE;                                           \
       else                                                             \
@@ -324,7 +317,7 @@ repeat_remainder(GLint a, GLint b)
       {                                                                        \
          const GLfloat min = -1.0F / (2.0F * SIZE);                    \
          const GLfloat max = 1.0F - min;                               \
-         U = (GLfloat) fabs(S);                                                \
+         U = FABSF(S);                                                 \
          if (U <= min)                                                 \
             U = min * SIZE;                                            \
          else if (U >= max)                                            \
@@ -349,6 +342,7 @@ repeat_remainder(GLint a, GLint b)
       break;                                                           \
    default:                                                            \
       _mesa_problem(ctx, "Bad wrap mode");                             \
+      return;                                                          \
    }                                                                   \
 }
 
@@ -363,10 +357,10 @@ repeat_remainder(GLint a, GLint b)
       /* s limited to [0,1) */                                         \
       /* i limited to [0,size-1] */                                    \
       I = IFLOOR(S * SIZE);                                            \
-      if (tObj->_IsPowerOfTwo)                                         \
+      if (img->_IsPowerOfTwo)                                          \
          I &= (SIZE - 1);                                              \
       else                                                             \
-         I = repeat_remainder(I, SIZE);                                        \
+         I = REMAINDER(I, SIZE);                                       \
       break;                                                           \
    case GL_CLAMP_TO_EDGE:                                              \
       {                                                                        \
@@ -418,7 +412,7 @@ repeat_remainder(GLint a, GLint b)
       {                                                                        \
          /* s limited to [0,1] */                                      \
          /* i limited to [0,size-1] */                                 \
-         const GLfloat u = (GLfloat) fabs(S);                          \
+         const GLfloat u = FABSF(S);                                   \
          if (u <= 0.0F)                                                        \
             I = 0;                                                     \
          else if (u >= 1.0F)                                           \
@@ -433,7 +427,7 @@ repeat_remainder(GLint a, GLint b)
          /* i limited to [0, size-1] */                                        \
          const GLfloat min = 1.0F / (2.0F * SIZE);                     \
          const GLfloat max = 1.0F - min;                               \
-         const GLfloat u = (GLfloat) fabs(S);                          \
+         const GLfloat u = FABSF(S);                                   \
          if (u < min)                                                  \
             I = 0;                                                     \
          else if (u > max)                                             \
@@ -448,7 +442,7 @@ repeat_remainder(GLint a, GLint b)
          /* i limited to [0, size-1] */                                        \
          const GLfloat min = -1.0F / (2.0F * SIZE);                    \
          const GLfloat max = 1.0F - min;                               \
-         const GLfloat u = (GLfloat) fabs(S);                          \
+         const GLfloat u = FABSF(S);                                   \
          if (u < min)                                                  \
             I = -1;                                                    \
          else if (u > max)                                             \
@@ -469,6 +463,7 @@ repeat_remainder(GLint a, GLint b)
       break;                                                           \
    default:                                                            \
       _mesa_problem(ctx, "Bad wrap mode");                             \
+      return;                                                          \
    }                                                                   \
 }
 
@@ -590,13 +585,13 @@ compute_min_mag_ranges(const struct gl_texture_object *tObj,
    }
 #endif /* DEBUG */
 
-   if (lambda[0] <= minMagThresh && lambda[n-1] <= minMagThresh) {
+   if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
       /* magnification for whole span */
       *magStart = 0;
       *magEnd = n;
       *minStart = *minEnd = 0;
    }
-   else if (lambda[0] > minMagThresh && lambda[n-1] > minMagThresh) {
+   else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
       /* minification for whole span */
       *minStart = 0;
       *minEnd = n;
@@ -1038,10 +1033,12 @@ sample_2d_linear_repeat(GLcontext *ctx,
    GLfloat a, b;
    GLchan t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
 
+   (void) ctx;
+
    ASSERT(tObj->WrapS == GL_REPEAT);
    ASSERT(tObj->WrapT == GL_REPEAT);
    ASSERT(img->Border == 0);
-   ASSERT(img->Format != GL_COLOR_INDEX);
+   ASSERT(img->TexFormat->BaseFormat != GL_COLOR_INDEX);
    ASSERT(img->_IsPowerOfTwo);
 
    COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord[0], u, width,  i0, i1);
@@ -1152,7 +1149,6 @@ sample_2d_linear_mipmap_linear_repeat( GLcontext *ctx,
    ASSERT(lambda != NULL);
    ASSERT(tObj->WrapS == GL_REPEAT);
    ASSERT(tObj->WrapT == GL_REPEAT);
-   ASSERT(tObj->_IsPowerOfTwo);
    for (i = 0; i < n; i++) {
       GLint level = linear_mipmap_level(tObj, lambda[i]);
       if (level >= tObj->_MaxLevel) {
@@ -1195,7 +1191,10 @@ sample_linear_2d( GLcontext *ctx,
    GLuint i;
    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
    (void) lambda;
-   if (tObj->WrapS == GL_REPEAT && tObj->WrapT == GL_REPEAT) {
+   if (tObj->WrapS == GL_REPEAT &&
+       tObj->WrapT == GL_REPEAT &&
+       image->_IsPowerOfTwo &&
+       image->Border == 0) {
       for (i=0;i<n;i++) {
          sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]);
       }
@@ -1234,7 +1233,7 @@ opt_sample_rgb_2d( GLcontext *ctx,
    ASSERT(tObj->WrapS==GL_REPEAT);
    ASSERT(tObj->WrapT==GL_REPEAT);
    ASSERT(img->Border==0);
-   ASSERT(img->Format==GL_RGB);
+   ASSERT(img->TexFormat->MesaFormat==MESA_FORMAT_RGB);
    ASSERT(img->_IsPowerOfTwo);
 
    for (k=0; k<n; k++) {
@@ -1275,7 +1274,7 @@ opt_sample_rgba_2d( GLcontext *ctx,
    ASSERT(tObj->WrapS==GL_REPEAT);
    ASSERT(tObj->WrapT==GL_REPEAT);
    ASSERT(img->Border==0);
-   ASSERT(img->Format==GL_RGBA);
+   ASSERT(img->TexFormat->MesaFormat==MESA_FORMAT_RGBA);
    ASSERT(img->_IsPowerOfTwo);
 
    for (i = 0; i < n; i++) {
@@ -1305,7 +1304,7 @@ sample_lambda_2d( GLcontext *ctx,
    const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT)
       && (tObj->WrapT == GL_REPEAT)
       && (tImg->Border == 0 && (tImg->Width == tImg->RowStride))
-      && (tImg->Format != GL_COLOR_INDEX)
+      && (tImg->TexFormat->BaseFormat != GL_COLOR_INDEX)
       && tImg->_IsPowerOfTwo;
 
    ASSERT(lambda != NULL);
@@ -1320,16 +1319,10 @@ sample_lambda_2d( GLcontext *ctx,
          if (repeatNoBorderPOT) {
             switch (tImg->TexFormat->MesaFormat) {
             case MESA_FORMAT_RGB:
-            case MESA_FORMAT_RGB888:
-            /*case MESA_FORMAT_BGR888:*/
                opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart,
                                  NULL, rgba + minStart);
                break;
             case MESA_FORMAT_RGBA:
-            case MESA_FORMAT_RGBA8888:
-            case MESA_FORMAT_ARGB8888:
-            /*case MESA_FORMAT_ABGR8888:*/
-            /*case MESA_FORMAT_BGRA8888:*/
               opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart,
                                   NULL, rgba + minStart);
                break;
@@ -1383,16 +1376,10 @@ sample_lambda_2d( GLcontext *ctx,
          if (repeatNoBorderPOT) {
             switch (tImg->TexFormat->MesaFormat) {
             case MESA_FORMAT_RGB:
-            case MESA_FORMAT_RGB888:
-            /*case MESA_FORMAT_BGR888:*/
                opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart,
                                  NULL, rgba + magStart);
                break;
             case MESA_FORMAT_RGBA:
-            case MESA_FORMAT_RGBA8888:
-            case MESA_FORMAT_ARGB8888:
-            /*case MESA_FORMAT_ABGR8888:*/
-            /*case MESA_FORMAT_BGRA8888:*/
               opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart,
                                   NULL, rgba + magStart);
                break;
@@ -1869,8 +1856,19 @@ sample_cube_nearest_mipmap_nearest(GLcontext *ctx,
    for (i = 0; i < n; i++) {
       const struct gl_texture_image **images;
       GLfloat newCoord[4];
-      GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      GLint level;
       images = choose_cube_face(tObj, texcoord[i], newCoord);
+
+      /* XXX we actually need to recompute lambda here based on the newCoords.
+       * But we would need the texcoords of adjacent fragments to compute that
+       * properly, and we don't have those here.
+       * For now, do an approximation:  subtracting 1 from the chosen mipmap
+       * level seems to work in some test cases.
+       * The same adjustment is done in the next few functions.
+      */
+      level = nearest_mipmap_level(tObj, lambda[i]);
+      level = MAX2(level - 1, 0);
+
       sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]);
    }
 }
@@ -1888,6 +1886,7 @@ sample_cube_linear_mipmap_nearest(GLcontext *ctx,
       const struct gl_texture_image **images;
       GLfloat newCoord[4];
       GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      level = MAX2(level - 1, 0); /* see comment above */
       images = choose_cube_face(tObj, texcoord[i], newCoord);
       sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]);
    }
@@ -1906,6 +1905,7 @@ sample_cube_nearest_mipmap_linear(GLcontext *ctx,
       const struct gl_texture_image **images;
       GLfloat newCoord[4];
       GLint level = linear_mipmap_level(tObj, lambda[i]);
+      level = MAX2(level - 1, 0); /* see comment above */
       images = choose_cube_face(tObj, texcoord[i], newCoord);
       if (level >= tObj->_MaxLevel) {
          sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel],
@@ -1934,6 +1934,7 @@ sample_cube_linear_mipmap_linear(GLcontext *ctx,
       const struct gl_texture_image **images;
       GLfloat newCoord[4];
       GLint level = linear_mipmap_level(tObj, lambda[i]);
+      level = MAX2(level - 1, 0); /* see comment above */
       images = choose_cube_face(tObj, texcoord[i], newCoord);
       if (level >= tObj->_MaxLevel) {
          sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel],
@@ -2023,6 +2024,60 @@ sample_lambda_cube( GLcontext *ctx,
 /*               Texture Rectangle Sampling Functions                 */
 /**********************************************************************/
 
+
+/**
+ * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
+ */
+static INLINE GLint
+clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
+{
+   if (wrapMode == GL_CLAMP) {
+      return IFLOOR( CLAMP(coord, 0.0F, max - 1) );
+   }
+   else if (wrapMode == GL_CLAMP_TO_EDGE) {
+      return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) );
+   }
+   else {
+      return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) );
+   }
+}
+
+
+/*
+ * As above, but GL_LINEAR filtering.
+ */
+static INLINE void
+clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
+                        GLint *i0out, GLint *i1out)
+{
+   GLfloat fcol;
+   GLint i0, i1;
+   if (wrapMode == GL_CLAMP) {
+      /* Not exactly what the spec says, but it matches NVIDIA output */
+      fcol = CLAMP(coord - 0.5F, 0.0, max-1);
+      i0 = IFLOOR(fcol);
+      i1 = i0 + 1;
+   }
+   else if (wrapMode == GL_CLAMP_TO_EDGE) {
+      fcol = CLAMP(coord, 0.5F, max - 0.5F);
+      fcol -= 0.5F;
+      i0 = IFLOOR(fcol);
+      i1 = i0 + 1;
+      if (i1 > max - 1)
+         i1 = max - 1;
+   }
+   else {
+      ASSERT(wrapMode == GL_CLAMP_TO_BORDER);
+      fcol = CLAMP(coord, -0.5F, max + 0.5F);
+      fcol -= 0.5F;
+      i0 = IFLOOR(fcol);
+      i1 = i0 + 1;
+   }
+   *i0out = i0;
+   *i1out = i1;
+}
+
+
 static void
 sample_nearest_rect(GLcontext *ctx,
                    const struct gl_texture_object *tObj, GLuint n,
@@ -2045,31 +2100,12 @@ sample_nearest_rect(GLcontext *ctx,
    ASSERT(tObj->WrapT == GL_CLAMP ||
           tObj->WrapT == GL_CLAMP_TO_EDGE ||
           tObj->WrapT == GL_CLAMP_TO_BORDER);
-   ASSERT(img->Format != GL_COLOR_INDEX);
+   ASSERT(img->TexFormat->BaseFormat != GL_COLOR_INDEX);
 
-   /* XXX move Wrap mode tests outside of loops for common cases */
    for (i = 0; i < n; i++) {
       GLint row, col;
-      /* NOTE: we DO NOT use [0, 1] texture coordinates! */
-      if (tObj->WrapS == GL_CLAMP) {
-         col = IFLOOR( CLAMP(texcoords[i][0], 0.0F, width - 1) );
-      }
-      else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
-         col = IFLOOR( CLAMP(texcoords[i][0], 0.5F, width - 0.5F) );
-      }
-      else {
-         col = IFLOOR( CLAMP(texcoords[i][0], -0.5F, width + 0.5F) );
-      }
-      if (tObj->WrapT == GL_CLAMP) {
-         row = IFLOOR( CLAMP(texcoords[i][1], 0.0F, height - 1) );
-      }
-      else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
-         row = IFLOOR( CLAMP(texcoords[i][1], 0.5F, height - 0.5F) );
-      }
-      else {
-         row = IFLOOR( CLAMP(texcoords[i][1], -0.5F, height + 0.5F) );
-      }
-
+      col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width);
+      row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
       if (col < 0 || col > width_minus_1 || row < 0 || row > height_minus_1)
          COPY_CHAN4(rgba[i], tObj->_BorderChan);
       else
@@ -2100,7 +2136,7 @@ sample_linear_rect(GLcontext *ctx,
    ASSERT(tObj->WrapT == GL_CLAMP ||
           tObj->WrapT == GL_CLAMP_TO_EDGE ||
           tObj->WrapT == GL_CLAMP_TO_BORDER);
-   ASSERT(img->Format != GL_COLOR_INDEX);
+   ASSERT(img->TexFormat->BaseFormat != GL_COLOR_INDEX);
 
    /* XXX lots of opportunity for optimization in this loop */
    for (i = 0; i < n; i++) {
@@ -2229,181 +2265,850 @@ sample_lambda_rect( GLcontext *ctx,
 
 
 
+/**********************************************************************/
+/*                2D Texture Array Sampling Functions                 */
+/**********************************************************************/
+
 /*
- * Sample a shadow/depth texture.
+ * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
  */
 static void
-sample_depth_texture( GLcontext *ctx,
-                      const struct gl_texture_object *tObj, GLuint n,
-                      const GLfloat texcoords[][4], const GLfloat lambda[],
-                      GLchan texel[][4] )
+sample_2d_array_nearest(GLcontext *ctx,
+                        const struct gl_texture_object *tObj,
+                        const struct gl_texture_image *img,
+                        const GLfloat texcoord[4],
+                        GLchan rgba[4])
 {
-   const GLint baseLevel = tObj->BaseLevel;
-   const struct gl_texture_image *texImage = tObj->Image[0][baseLevel];
-   const GLuint width = texImage->Width;
-   const GLuint height = texImage->Height;
-   GLchan ambient;
-   GLenum function;
-   GLchan result;
+   const GLint width = img->Width2;     /* without border, power of two */
+   const GLint height = img->Height2;   /* without border, power of two */
+   const GLint depth = img->Depth;
+   GLint i, j;
+   GLint array;
+   (void) ctx;
 
-   (void) lambda;
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width,  i);
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
+   array = clamp_rect_coord_nearest(tObj->WrapR, texcoord[2], depth);
 
-   ASSERT(tObj->Image[0][tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
-   ASSERT(tObj->Target == GL_TEXTURE_1D ||
-          tObj->Target == GL_TEXTURE_2D ||
-          tObj->Target == GL_TEXTURE_RECTANGLE_NV);
+   if (i < 0 || i >= (GLint) img->Width ||
+       j < 0 || j >= (GLint) img->Height ||
+       array < 0 || array >= (GLint) img->Depth) {
+      /* Need this test for GL_CLAMP_TO_BORDER mode */
+      COPY_CHAN4(rgba, tObj->_BorderChan);
+   }
+   else {
+      img->FetchTexelc(img, i, j, array, rgba);
+   }
+}
 
-   UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
 
-   /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
 
-   /* XXX this could be precomputed and saved in the texture object */
-   if (tObj->CompareFlag) {
-      /* GL_SGIX_shadow */
-      if (tObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
-         function = GL_LEQUAL;
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
+ */
+static void
+sample_2d_array_linear(GLcontext *ctx,
+                       const struct gl_texture_object *tObj,
+                       const struct gl_texture_image *img,
+                       const GLfloat texcoord[4],
+                       GLchan rgba[4])
+{
+   const GLint width = img->Width2;
+   const GLint height = img->Height2;
+   const GLint depth = img->Depth;
+   GLint i0, j0, i1, j1;
+   GLint array;
+   GLbitfield useBorderColor = 0x0;
+   GLfloat u, v;
+   GLfloat a, b;
+   GLchan t00[4], t01[4], t10[4], t11[4];
+
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width,  i0, i1);
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
+   array = clamp_rect_coord_nearest(tObj->WrapR, texcoord[2], depth);
+
+   if (array < 0 || array >= depth) {
+      COPY_CHAN4(rgba, tObj->_BorderChan);
+   }
+   else {
+      if (img->Border) {
+        i0 += img->Border;
+        i1 += img->Border;
+        j0 += img->Border;
+        j1 += img->Border;
       }
       else {
-         ASSERT(tObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
-         function = GL_GEQUAL;
+        /* check if sampling texture border color */
+        if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
+        if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
+        if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
+        if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
       }
+
+      /* Fetch texels */
+      if (useBorderColor & (I0BIT | J0BIT)) {
+        COPY_CHAN4(t00, tObj->_BorderChan);
+      }
+      else {
+        img->FetchTexelc(img, i0, j0, array, t00);
+      }
+      if (useBorderColor & (I1BIT | J0BIT)) {
+        COPY_CHAN4(t10, tObj->_BorderChan);
+      }
+      else {
+        img->FetchTexelc(img, i1, j0, array, t10);
+      }
+      if (useBorderColor & (I0BIT | J1BIT)) {
+        COPY_CHAN4(t01, tObj->_BorderChan);
+      }
+      else {
+        img->FetchTexelc(img, i0, j1, array, t01);
+      }
+      if (useBorderColor & (I1BIT | J1BIT)) {
+        COPY_CHAN4(t11, tObj->_BorderChan);
+      }
+      else {
+        img->FetchTexelc(img, i1, j1, array, t11);
+      }
+      
+      /* trilinear interpolation of samples */
+      a = FRAC(u);
+      b = FRAC(v);
+      lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
    }
-   else if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
-      /* GL_ARB_shadow */
-      function = tObj->CompareFunc;
-   }
-   else {
-      function = GL_NONE;  /* pass depth through as grayscale */
+}
+
+
+
+static void
+sample_2d_array_nearest_mipmap_nearest(GLcontext *ctx,
+                                       const struct gl_texture_object *tObj,
+                                       GLuint n, const GLfloat texcoord[][4],
+                                       const GLfloat lambda[], GLchan rgba[][4] )
+{
+   GLuint i;
+   for (i = 0; i < n; i++) {
+      GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
+                              rgba[i]);
    }
+}
 
-   if (tObj->MagFilter == GL_NEAREST) {
-      GLuint i;
-      for (i = 0; i < n; i++) {
-         GLfloat depthSample;
-         GLint col, row;
-         /* XXX fix for texture rectangle! */
-         COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
-         COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
-         texImage->FetchTexelf(texImage, col, row, 0, &depthSample);
 
-         switch (function) {
-         case GL_LEQUAL:
-            result = (texcoords[i][2] <= depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_GEQUAL:
-            result = (texcoords[i][2] >= depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_LESS:
-            result = (texcoords[i][2] < depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_GREATER:
-            result = (texcoords[i][2] > depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_EQUAL:
-            result = (texcoords[i][2] == depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_NOTEQUAL:
-            result = (texcoords[i][2] != depthSample) ? CHAN_MAX : ambient;
-            break;
-         case GL_ALWAYS:
-            result = CHAN_MAX;
-            break;
-         case GL_NEVER:
-            result = ambient;
-            break;
-         case GL_NONE:
-            CLAMPED_FLOAT_TO_CHAN(result, depthSample);
-            break;
-         default:
-            _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
-            return;
-         }
+static void
+sample_2d_array_linear_mipmap_nearest(GLcontext *ctx,
+                                      const struct gl_texture_object *tObj,
+                                      GLuint n, const GLfloat texcoord[][4],
+                                      const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      sample_2d_array_linear(ctx, tObj, tObj->Image[0][level],
+                             texcoord[i], rgba[i]);
+   }
+}
 
-         switch (tObj->DepthMode) {
-         case GL_LUMINANCE:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = CHAN_MAX;
-            break;
-         case GL_INTENSITY:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = result;
-            break;
-         case GL_ALPHA:
-            texel[i][RCOMP] = 0;
-            texel[i][GCOMP] = 0;
-            texel[i][BCOMP] = 0;
-            texel[i][ACOMP] = result;
-            break;
-         default:
-            _mesa_problem(ctx, "Bad depth texture mode");
-         }
+
+static void
+sample_2d_array_nearest_mipmap_linear(GLcontext *ctx,
+                                      const struct gl_texture_object *tObj,
+                                      GLuint n, const GLfloat texcoord[][4],
+                                      const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = linear_mipmap_level(tObj, lambda[i]);
+      if (level >= tObj->_MaxLevel) {
+         sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+                                 texcoord[i], rgba[i]);
+      }
+      else {
+         GLchan t0[4], t1[4];  /* texels */
+         const GLfloat f = FRAC(lambda[i]);
+         sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level  ], texcoord[i], t0);
+         sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+         lerp_rgba(rgba[i], f, t0, t1);
       }
    }
-   else {
-      GLuint i;
-      ASSERT(tObj->MagFilter == GL_LINEAR);
-      for (i = 0; i < n; i++) {
-         GLfloat depth00, depth01, depth10, depth11;
-         GLint i0, i1, j0, j1;
-         GLfloat u, v;
-         GLuint useBorderTexel;
+}
 
-         /* XXX fix for texture rectangle! */
-         COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
-         COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
 
-         useBorderTexel = 0;
-         if (texImage->Border) {
-            i0 += texImage->Border;
-            i1 += texImage->Border;
-            j0 += texImage->Border;
-            j1 += texImage->Border;
-         }
-         else {
-            if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
-            if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
-            if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
-            if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
-         }
+static void
+sample_2d_array_linear_mipmap_linear(GLcontext *ctx,
+                               const struct gl_texture_object *tObj,
+                               GLuint n, const GLfloat texcoord[][4],
+                               const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = linear_mipmap_level(tObj, lambda[i]);
+      if (level >= tObj->_MaxLevel) {
+         sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+                          texcoord[i], rgba[i]);
+      }
+      else {
+         GLchan t0[4], t1[4];  /* texels */
+         const GLfloat f = FRAC(lambda[i]);
+         sample_2d_array_linear(ctx, tObj, tObj->Image[0][level  ], texcoord[i], t0);
+         sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+         lerp_rgba(rgba[i], f, t0, t1);
+      }
+   }
+}
 
-         /* get four depth samples from the texture */
-         if (useBorderTexel & (I0BIT | J0BIT)) {
-            depth00 = 1.0;
-         }
-         else {
-            texImage->FetchTexelf(texImage, i0, j0, 0, &depth00);
-         }
-         if (useBorderTexel & (I1BIT | J0BIT)) {
-            depth10 = 1.0;
-         }
-         else {
-            texImage->FetchTexelf(texImage, i1, j0, 0, &depth10);
-         }
-         if (useBorderTexel & (I0BIT | J1BIT)) {
-            depth01 = 1.0;
-         }
-         else {
-            texImage->FetchTexelf(texImage, i0, j1, 0, &depth01);
-         }
-         if (useBorderTexel & (I1BIT | J1BIT)) {
-            depth11 = 1.0;
-         }
-         else {
-            texImage->FetchTexelf(texImage, i1, j1, 0, &depth11);
-         }
 
-         if (0) {
-            /* compute a single weighted depth sample and do one comparison */
-            const GLfloat a = FRAC(u + 1.0F);
-            const GLfloat b = FRAC(v + 1.0F);
-            const GLfloat depthSample
-               = lerp_2d(a, b, depth00, depth10, depth01, depth11);
-            if ((depthSample <= texcoords[i][2] && function == GL_LEQUAL) ||
-                (depthSample >= texcoords[i][2] && function == GL_GEQUAL)) {
+static void
+sample_nearest_2d_array(GLcontext *ctx,
+                  const struct gl_texture_object *tObj, GLuint n,
+                  const GLfloat texcoords[][4], const GLfloat lambda[],
+                  GLchan rgba[][4])
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
+   }
+}
+
+
+
+static void
+sample_linear_2d_array(GLcontext *ctx,
+                       const struct gl_texture_object *tObj, GLuint n,
+                       const GLfloat texcoords[][4],
+                       const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
+   }
+}
+
+
+/*
+ * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void
+sample_lambda_2d_array(GLcontext *ctx,
+                       const struct gl_texture_object *tObj, GLuint n,
+                       const GLfloat texcoords[][4], const GLfloat lambda[],
+                       GLchan rgba[][4])
+{
+   GLuint minStart, minEnd;  /* texels with minification */
+   GLuint magStart, magEnd;  /* texels with magnification */
+   GLuint i;
+
+   ASSERT(lambda != NULL);
+   compute_min_mag_ranges(tObj, n, lambda,
+                          &minStart, &minEnd, &magStart, &magEnd);
+
+   if (minStart < minEnd) {
+      /* do the minified texels */
+      GLuint m = minEnd - minStart;
+      switch (tObj->MinFilter) {
+      case GL_NEAREST:
+         for (i = minStart; i < minEnd; i++)
+            sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                    texcoords[i], rgba[i]);
+         break;
+      case GL_LINEAR:
+         for (i = minStart; i < minEnd; i++)
+            sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                   texcoords[i], rgba[i]);
+         break;
+      case GL_NEAREST_MIPMAP_NEAREST:
+         sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
+                                                lambda + minStart, rgba + minStart);
+         break;
+      case GL_LINEAR_MIPMAP_NEAREST:
+         sample_2d_array_linear_mipmap_nearest(ctx, tObj, m, 
+                                               texcoords + minStart,
+                                               lambda + minStart,
+                                               rgba + minStart);
+         break;
+      case GL_NEAREST_MIPMAP_LINEAR:
+         sample_2d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
+                                               lambda + minStart, rgba + minStart);
+         break;
+      case GL_LINEAR_MIPMAP_LINEAR:
+         sample_2d_array_linear_mipmap_linear(ctx, tObj, m, 
+                                              texcoords + minStart,
+                                              lambda + minStart, 
+                                              rgba + minStart);
+         break;
+      default:
+         _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
+         return;
+      }
+   }
+
+   if (magStart < magEnd) {
+      /* do the magnified texels */
+      switch (tObj->MagFilter) {
+      case GL_NEAREST:
+         for (i = magStart; i < magEnd; i++)
+            sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                              texcoords[i], rgba[i]);
+         break;
+      case GL_LINEAR:
+         for (i = magStart; i < magEnd; i++)
+            sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                   texcoords[i], rgba[i]);
+         break;
+      default:
+         _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
+         return;
+      }
+   }
+}
+
+
+
+
+/**********************************************************************/
+/*                1D Texture Array Sampling Functions                 */
+/**********************************************************************/
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
+ */
+static void
+sample_1d_array_nearest(GLcontext *ctx,
+                        const struct gl_texture_object *tObj,
+                        const struct gl_texture_image *img,
+                        const GLfloat texcoord[4],
+                        GLchan rgba[4])
+{
+   const GLint width = img->Width2;     /* without border, power of two */
+   const GLint height = img->Height;
+   GLint i;
+   GLint array;
+   (void) ctx;
+
+   COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width,  i);
+   array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
+
+   if (i < 0 || i >= (GLint) img->Width ||
+       array < 0 || array >= (GLint) img->Height) {
+      /* Need this test for GL_CLAMP_TO_BORDER mode */
+      COPY_CHAN4(rgba, tObj->_BorderChan);
+   }
+   else {
+      img->FetchTexelc(img, i, array, 0, rgba);
+   }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
+ */
+static void
+sample_1d_array_linear(GLcontext *ctx,
+                       const struct gl_texture_object *tObj,
+                       const struct gl_texture_image *img,
+                       const GLfloat texcoord[4],
+                       GLchan rgba[4])
+{
+   const GLint width = img->Width2;
+   const GLint height = img->Height;
+   GLint i0, i1;
+   GLint array;
+   GLbitfield useBorderColor = 0x0;
+   GLfloat u;
+   GLfloat a;
+   GLchan t0[4], t1[4];
+
+   COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width,  i0, i1);
+   array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
+
+   if (img->Border) {
+      i0 += img->Border;
+      i1 += img->Border;
+   }
+   else {
+      /* check if sampling texture border color */
+      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
+      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
+   }
+
+   if (array < 0 || array >= height)   useBorderColor |= K0BIT;
+
+   /* Fetch texels */
+   if (useBorderColor & (I0BIT | K0BIT)) {
+      COPY_CHAN4(t0, tObj->_BorderChan);
+   }
+   else {
+      img->FetchTexelc(img, i0, array, 0, t0);
+   }
+   if (useBorderColor & (I1BIT | K0BIT)) {
+      COPY_CHAN4(t1, tObj->_BorderChan);
+   }
+   else {
+      img->FetchTexelc(img, i1, array, 0, t1);
+   }
+
+   /* bilinear interpolation of samples */
+   a = FRAC(u);
+   lerp_rgba(rgba, a, t0, t1);
+}
+
+
+
+static void
+sample_1d_array_nearest_mipmap_nearest(GLcontext *ctx,
+                                       const struct gl_texture_object *tObj,
+                                       GLuint n, const GLfloat texcoord[][4],
+                                       const GLfloat lambda[], GLchan rgba[][4] )
+{
+   GLuint i;
+   for (i = 0; i < n; i++) {
+      GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
+                              rgba[i]);
+   }
+}
+
+
+static void
+sample_1d_array_linear_mipmap_nearest(GLcontext *ctx,
+                                      const struct gl_texture_object *tObj,
+                                      GLuint n, const GLfloat texcoord[][4],
+                                      const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = nearest_mipmap_level(tObj, lambda[i]);
+      sample_1d_array_linear(ctx, tObj, tObj->Image[0][level],
+                             texcoord[i], rgba[i]);
+   }
+}
+
+
+static void
+sample_1d_array_nearest_mipmap_linear(GLcontext *ctx,
+                                      const struct gl_texture_object *tObj,
+                                      GLuint n, const GLfloat texcoord[][4],
+                                      const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = linear_mipmap_level(tObj, lambda[i]);
+      if (level >= tObj->_MaxLevel) {
+         sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+                                 texcoord[i], rgba[i]);
+      }
+      else {
+         GLchan t0[4], t1[4];  /* texels */
+         const GLfloat f = FRAC(lambda[i]);
+         sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level  ], texcoord[i], t0);
+         sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+         lerp_rgba(rgba[i], f, t0, t1);
+      }
+   }
+}
+
+
+static void
+sample_1d_array_linear_mipmap_linear(GLcontext *ctx,
+                               const struct gl_texture_object *tObj,
+                               GLuint n, const GLfloat texcoord[][4],
+                               const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   ASSERT(lambda != NULL);
+   for (i = 0; i < n; i++) {
+      GLint level = linear_mipmap_level(tObj, lambda[i]);
+      if (level >= tObj->_MaxLevel) {
+         sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
+                          texcoord[i], rgba[i]);
+      }
+      else {
+         GLchan t0[4], t1[4];  /* texels */
+         const GLfloat f = FRAC(lambda[i]);
+         sample_1d_array_linear(ctx, tObj, tObj->Image[0][level  ], texcoord[i], t0);
+         sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
+         lerp_rgba(rgba[i], f, t0, t1);
+      }
+   }
+}
+
+
+static void
+sample_nearest_1d_array(GLcontext *ctx,
+                  const struct gl_texture_object *tObj, GLuint n,
+                  const GLfloat texcoords[][4], const GLfloat lambda[],
+                  GLchan rgba[][4])
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
+   }
+}
+
+
+
+static void
+sample_linear_1d_array(GLcontext *ctx,
+                       const struct gl_texture_object *tObj, GLuint n,
+                       const GLfloat texcoords[][4],
+                       const GLfloat lambda[], GLchan rgba[][4])
+{
+   GLuint i;
+   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+   (void) lambda;
+   for (i=0;i<n;i++) {
+      sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
+   }
+}
+
+
+/*
+ * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void
+sample_lambda_1d_array(GLcontext *ctx,
+                       const struct gl_texture_object *tObj, GLuint n,
+                       const GLfloat texcoords[][4], const GLfloat lambda[],
+                       GLchan rgba[][4])
+{
+   GLuint minStart, minEnd;  /* texels with minification */
+   GLuint magStart, magEnd;  /* texels with magnification */
+   GLuint i;
+
+   ASSERT(lambda != NULL);
+   compute_min_mag_ranges(tObj, n, lambda,
+                          &minStart, &minEnd, &magStart, &magEnd);
+
+   if (minStart < minEnd) {
+      /* do the minified texels */
+      GLuint m = minEnd - minStart;
+      switch (tObj->MinFilter) {
+      case GL_NEAREST:
+         for (i = minStart; i < minEnd; i++)
+            sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                    texcoords[i], rgba[i]);
+         break;
+      case GL_LINEAR:
+         for (i = minStart; i < minEnd; i++)
+            sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                   texcoords[i], rgba[i]);
+         break;
+      case GL_NEAREST_MIPMAP_NEAREST:
+         sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
+                                                lambda + minStart, rgba + minStart);
+         break;
+      case GL_LINEAR_MIPMAP_NEAREST:
+         sample_1d_array_linear_mipmap_nearest(ctx, tObj, m, 
+                                               texcoords + minStart,
+                                               lambda + minStart,
+                                               rgba + minStart);
+         break;
+      case GL_NEAREST_MIPMAP_LINEAR:
+         sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
+                                               lambda + minStart, rgba + minStart);
+         break;
+      case GL_LINEAR_MIPMAP_LINEAR:
+         sample_1d_array_linear_mipmap_linear(ctx, tObj, m, 
+                                              texcoords + minStart,
+                                              lambda + minStart, 
+                                              rgba + minStart);
+         break;
+      default:
+         _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
+         return;
+      }
+   }
+
+   if (magStart < magEnd) {
+      /* do the magnified texels */
+      switch (tObj->MagFilter) {
+      case GL_NEAREST:
+         for (i = magStart; i < magEnd; i++)
+            sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                              texcoords[i], rgba[i]);
+         break;
+      case GL_LINEAR:
+         for (i = magStart; i < magEnd; i++)
+            sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
+                                   texcoords[i], rgba[i]);
+         break;
+      default:
+         _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
+         return;
+      }
+   }
+}
+
+
+
+
+/*
+ * Sample a shadow/depth texture.
+ */
+static void
+sample_depth_texture( GLcontext *ctx,
+                      const struct gl_texture_object *tObj, GLuint n,
+                      const GLfloat texcoords[][4], const GLfloat lambda[],
+                      GLchan texel[][4] )
+{
+   const GLint baseLevel = tObj->BaseLevel;
+   const struct gl_texture_image *img = tObj->Image[0][baseLevel];
+   const GLint width = img->Width;
+   const GLint height = img->Height;
+   const GLint depth = img->Depth;
+   const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
+       ? 3 : 2;
+   GLchan ambient;
+   GLenum function;
+   GLchan result;
+
+   (void) lambda;
+
+   ASSERT(img->TexFormat->BaseFormat == GL_DEPTH_COMPONENT ||
+          img->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT);
+
+   ASSERT(tObj->Target == GL_TEXTURE_1D ||
+          tObj->Target == GL_TEXTURE_2D ||
+          tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
+          tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
+          tObj->Target == GL_TEXTURE_2D_ARRAY_EXT);
+
+   UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
+
+   /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
+
+   function = tObj->_Function;
+   if (tObj->MagFilter == GL_NEAREST) {
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         GLfloat depthSample;
+         GLint col, row, slice;
+
+         switch (tObj->Target) {
+         case GL_TEXTURE_RECTANGLE_ARB:
+            col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width);
+            row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
+            slice = 0;
+            break;
+            
+         case GL_TEXTURE_1D:
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0],
+                                           width, col);
+            row = 0;
+            slice = 0;
+            break;
+
+         case GL_TEXTURE_2D:
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0],
+                                           width, col);
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1],
+                                           height, row);
+            slice = 0;
+            break;
+
+         case GL_TEXTURE_1D_ARRAY_EXT:
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0],
+                                           width, col);
+            row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
+            slice = 0;
+
+         case GL_TEXTURE_2D_ARRAY_EXT:
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0],
+                                           width, col);
+            COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1],
+                                           height, row);
+            slice = clamp_rect_coord_nearest(tObj->WrapR, texcoords[i][2], depth);
+            break;
+         }
+
+         if (col >= 0 && row >= 0 && col < width && row < height && 
+             slice >= 0 && slice < depth) {
+            img->FetchTexelf(img, col, row, slice, &depthSample);
+         }
+         else {
+            depthSample = tObj->BorderColor[0];
+         }
+
+         switch (function) {
+         case GL_LEQUAL:
+            result = (texcoords[i][compare_coord] <= depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_GEQUAL:
+            result = (texcoords[i][compare_coord] >= depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_LESS:
+            result = (texcoords[i][compare_coord] < depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_GREATER:
+            result = (texcoords[i][compare_coord] > depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_EQUAL:
+            result = (texcoords[i][compare_coord] == depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_NOTEQUAL:
+            result = (texcoords[i][compare_coord] != depthSample) ? CHAN_MAX : ambient;
+            break;
+         case GL_ALWAYS:
+            result = CHAN_MAX;
+            break;
+         case GL_NEVER:
+            result = ambient;
+            break;
+         case GL_NONE:
+            CLAMPED_FLOAT_TO_CHAN(result, depthSample);
+            break;
+         default:
+            _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
+            return;
+         }
+
+         switch (tObj->DepthMode) {
+         case GL_LUMINANCE:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = CHAN_MAX;
+            break;
+         case GL_INTENSITY:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = result;
+            break;
+         case GL_ALPHA:
+            texel[i][RCOMP] = 0;
+            texel[i][GCOMP] = 0;
+            texel[i][BCOMP] = 0;
+            texel[i][ACOMP] = result;
+            break;
+         default:
+            _mesa_problem(ctx, "Bad depth texture mode");
+         }
+      }
+   }
+   else {
+      GLuint i;
+      ASSERT(tObj->MagFilter == GL_LINEAR);
+      for (i = 0; i < n; i++) {
+         GLfloat depth00, depth01, depth10, depth11;
+         GLint i0, i1, j0, j1;
+         GLint slice;
+         GLfloat u, v;
+         GLuint useBorderTexel;
+
+         switch (tObj->Target) {
+         case GL_TEXTURE_RECTANGLE_ARB:
+            clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0],
+                                    width, &i0, &i1);
+            clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1],
+                                    height, &j0, &j1);
+            slice = 0;
+            break;
+
+         case GL_TEXTURE_1D:
+         case GL_TEXTURE_2D:
+            COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0],
+                                           u, width, i0, i1);
+            COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1],
+                                           v, height,j0, j1);
+            slice = 0;
+            break;
+
+         case GL_TEXTURE_1D_ARRAY_EXT:
+            COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0],
+                                           u, width, i0, i1);
+            j0 = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
+            j1 = j0;
+            slice = 0;
+
+         case GL_TEXTURE_2D_ARRAY_EXT:
+            COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0],
+                                           u, width, i0, i1);
+            COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1],
+                                           v, height,j0, j1);
+            slice = clamp_rect_coord_nearest(tObj->WrapR, texcoords[i][2], depth);
+            break;
+         }
+
+         useBorderTexel = 0;
+         if (img->Border) {
+            i0 += img->Border;
+            i1 += img->Border;
+            if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
+               j0 += img->Border;
+               j1 += img->Border;
+            }
+         }
+         else {
+            if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
+            if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
+            if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
+            if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
+         }
+
+         if (slice < 0 || slice >= (GLint) depth) {
+            depth00 = tObj->BorderColor[0];
+            depth01 = tObj->BorderColor[0];
+            depth10 = tObj->BorderColor[0];
+            depth11 = tObj->BorderColor[0];
+         }
+         else {
+            /* get four depth samples from the texture */
+            if (useBorderTexel & (I0BIT | J0BIT)) {
+               depth00 = tObj->BorderColor[0];
+            }
+            else {
+               img->FetchTexelf(img, i0, j0, slice, &depth00);
+            }
+            if (useBorderTexel & (I1BIT | J0BIT)) {
+               depth10 = tObj->BorderColor[0];
+            }
+            else {
+               img->FetchTexelf(img, i1, j0, slice, &depth10);
+            }
+
+            if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
+               if (useBorderTexel & (I0BIT | J1BIT)) {
+                  depth01 = tObj->BorderColor[0];
+               }
+               else {
+                  img->FetchTexelf(img, i0, j1, slice, &depth01);
+               }
+               if (useBorderTexel & (I1BIT | J1BIT)) {
+                  depth11 = tObj->BorderColor[0];
+               }
+               else {
+                  img->FetchTexelf(img, i1, j1, slice, &depth11);
+               }
+            }
+            else {
+               depth01 = depth00;
+               depth11 = depth10;
+            }
+         }
+
+         if (0) {
+            /* compute a single weighted depth sample and do one comparison */
+            const GLfloat a = FRAC(u + 1.0F);
+            const GLfloat b = FRAC(v + 1.0F);
+            const GLfloat depthSample
+               = lerp_2d(a, b, depth00, depth10, depth01, depth11);
+            if ((depthSample <= texcoords[i][compare_coord] && function == GL_LEQUAL) ||
+                (depthSample >= texcoords[i][compare_coord] && function == GL_GEQUAL)) {
                result  = ambient;
             }
             else {
@@ -2420,45 +3125,45 @@ sample_depth_texture( GLcontext *ctx,
 
             switch (function) {
             case GL_LEQUAL:
-               if (depth00 <= texcoords[i][2])  luminance -= d;
-               if (depth01 <= texcoords[i][2])  luminance -= d;
-               if (depth10 <= texcoords[i][2])  luminance -= d;
-               if (depth11 <= texcoords[i][2])  luminance -= d;
+               if (depth00 <= texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 <= texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 <= texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 <= texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_GEQUAL:
-               if (depth00 >= texcoords[i][2])  luminance -= d;
-               if (depth01 >= texcoords[i][2])  luminance -= d;
-               if (depth10 >= texcoords[i][2])  luminance -= d;
-               if (depth11 >= texcoords[i][2])  luminance -= d;
+               if (depth00 >= texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 >= texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 >= texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 >= texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_LESS:
-               if (depth00 < texcoords[i][2])  luminance -= d;
-               if (depth01 < texcoords[i][2])  luminance -= d;
-               if (depth10 < texcoords[i][2])  luminance -= d;
-               if (depth11 < texcoords[i][2])  luminance -= d;
+               if (depth00 < texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 < texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 < texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 < texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_GREATER:
-               if (depth00 > texcoords[i][2])  luminance -= d;
-               if (depth01 > texcoords[i][2])  luminance -= d;
-               if (depth10 > texcoords[i][2])  luminance -= d;
-               if (depth11 > texcoords[i][2])  luminance -= d;
+               if (depth00 > texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 > texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 > texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 > texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_EQUAL:
-               if (depth00 == texcoords[i][2])  luminance -= d;
-               if (depth01 == texcoords[i][2])  luminance -= d;
-               if (depth10 == texcoords[i][2])  luminance -= d;
-               if (depth11 == texcoords[i][2])  luminance -= d;
+               if (depth00 == texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 == texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 == texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 == texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_NOTEQUAL:
-               if (depth00 != texcoords[i][2])  luminance -= d;
-               if (depth01 != texcoords[i][2])  luminance -= d;
-               if (depth10 != texcoords[i][2])  luminance -= d;
-               if (depth11 != texcoords[i][2])  luminance -= d;
+               if (depth00 != texcoords[i][compare_coord])  luminance -= d;
+               if (depth01 != texcoords[i][compare_coord])  luminance -= d;
+               if (depth10 != texcoords[i][compare_coord])  luminance -= d;
+               if (depth11 != texcoords[i][compare_coord])  luminance -= d;
                result = (GLchan) luminance;
                break;
             case GL_ALWAYS:
@@ -2542,7 +3247,7 @@ sample_depth_texture2(const GLcontext *ctx,
     * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
     * isn't a depth texture.
     */
-   if (texImage->Format != GL_DEPTH_COMPONENT) {
+   if (texImage->TexFormat->BaseFormat != GL_DEPTH_COMPONENT) {
       _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
       return;
    }
@@ -2611,7 +3316,7 @@ sample_depth_texture2(const GLcontext *ctx,
  * We use this function when a texture object is in an "incomplete" state.
  * When a fragment program attempts to sample an incomplete texture we
  * return black (see issue 23 in GL_ARB_fragment_program spec).
- * Note: fragment programss don't observe the texture enable/disable flags.
+ * Note: fragment programs don't observe the texture enable/disable flags.
  */
 static void
 null_sample_func( GLcontext *ctx,
@@ -2640,16 +3345,16 @@ texture_sample_func
 _swrast_choose_texture_sample_func( GLcontext *ctx,
                                    const struct gl_texture_object *t )
 {
-   if (!t || !t->Complete) {
+   if (!t || !t->_Complete) {
       return &null_sample_func;
    }
    else {
       const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
-      const GLenum format = t->Image[0][t->BaseLevel]->Format;
+      const GLenum format = t->Image[0][t->BaseLevel]->TexFormat->BaseFormat;
 
       switch (t->Target) {
       case GL_TEXTURE_1D:
-         if (format == GL_DEPTH_COMPONENT) {
+         if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
             return &sample_depth_texture;
          }
          else if (needLambda) {
@@ -2663,7 +3368,7 @@ _swrast_choose_texture_sample_func( GLcontext *ctx,
             return &sample_nearest_1d;
          }
       case GL_TEXTURE_2D:
-         if (format == GL_DEPTH_COMPONENT) {
+         if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
             return &sample_depth_texture;
          }
          else if (needLambda) {
@@ -2673,20 +3378,21 @@ _swrast_choose_texture_sample_func( GLcontext *ctx,
             return &sample_linear_2d;
          }
          else {
-            GLint baseLevel = t->BaseLevel;
+            /* check for a few optimized cases */
+            const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
             ASSERT(t->MinFilter == GL_NEAREST);
             if (t->WrapS == GL_REPEAT &&
                 t->WrapT == GL_REPEAT &&
-                t->_IsPowerOfTwo &&
-                t->Image[0][baseLevel]->Border == 0 &&
-                t->Image[0][baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
+                img->_IsPowerOfTwo &&
+                img->Border == 0 &&
+                img->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
                return &opt_sample_rgb_2d;
             }
             else if (t->WrapS == GL_REPEAT &&
                      t->WrapT == GL_REPEAT &&
-                     t->_IsPowerOfTwo &&
-                     t->Image[0][baseLevel]->Border == 0 &&
-                     t->Image[0][baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
+                     img->_IsPowerOfTwo &&
+                     img->Border == 0 &&
+                     img->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
                return &opt_sample_rgba_2d;
             }
             else {
@@ -2716,7 +3422,10 @@ _swrast_choose_texture_sample_func( GLcontext *ctx,
             return &sample_nearest_cube;
          }
       case GL_TEXTURE_RECTANGLE_NV:
-         if (needLambda) {
+         if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
+            return &sample_depth_texture;
+         }
+         else if (needLambda) {
             return &sample_lambda_rect;
          }
          else if (t->MinFilter == GL_LINEAR) {
@@ -2726,6 +3435,28 @@ _swrast_choose_texture_sample_func( GLcontext *ctx,
             ASSERT(t->MinFilter == GL_NEAREST);
             return &sample_nearest_rect;
          }
+      case GL_TEXTURE_1D_ARRAY_EXT:
+         if (needLambda) {
+            return &sample_lambda_1d_array;
+         }
+         else if (t->MinFilter == GL_LINEAR) {
+            return &sample_linear_1d_array;
+         }
+         else {
+            ASSERT(t->MinFilter == GL_NEAREST);
+            return &sample_nearest_1d_array;
+         }
+      case GL_TEXTURE_2D_ARRAY_EXT:
+         if (needLambda) {
+            return &sample_lambda_2d_array;
+         }
+         else if (t->MinFilter == GL_LINEAR) {
+            return &sample_linear_2d_array;
+         }
+         else {
+            ASSERT(t->MinFilter == GL_NEAREST);
+            return &sample_nearest_2d_array;
+         }
       default:
          _mesa_problem(ctx,
                        "invalid target in _swrast_choose_texture_sample_func");