Home | History | Annotate | Download | only in swrast
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.3
      4  *
      5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 
     26 #include "main/glheader.h"
     27 #include "main/context.h"
     28 #include "main/colormac.h"
     29 #include "main/imports.h"
     30 #include "main/texobj.h"
     31 #include "main/samplerobj.h"
     32 
     33 #include "s_context.h"
     34 #include "s_texfilter.h"
     35 
     36 
     37 /*
     38  * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
     39  * see 1-pixel bands of improperly weighted linear-filtered textures.
     40  * The tests/texwrap.c demo is a good test.
     41  * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
     42  * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
     43  */
     44 #define FRAC(f)  ((f) - IFLOOR(f))
     45 
     46 
     47 
     48 /**
     49  * Linear interpolation macro
     50  */
     51 #define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
     52 
     53 
     54 /**
     55  * Do 2D/biliner interpolation of float values.
     56  * v00, v10, v01 and v11 are typically four texture samples in a square/box.
     57  * a and b are the horizontal and vertical interpolants.
     58  * It's important that this function is inlined when compiled with
     59  * optimization!  If we find that's not true on some systems, convert
     60  * to a macro.
     61  */
     62 static inline GLfloat
     63 lerp_2d(GLfloat a, GLfloat b,
     64         GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
     65 {
     66    const GLfloat temp0 = LERP(a, v00, v10);
     67    const GLfloat temp1 = LERP(a, v01, v11);
     68    return LERP(b, temp0, temp1);
     69 }
     70 
     71 
     72 /**
     73  * Do 3D/trilinear interpolation of float values.
     74  * \sa lerp_2d
     75  */
     76 static inline GLfloat
     77 lerp_3d(GLfloat a, GLfloat b, GLfloat c,
     78         GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110,
     79         GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111)
     80 {
     81    const GLfloat temp00 = LERP(a, v000, v100);
     82    const GLfloat temp10 = LERP(a, v010, v110);
     83    const GLfloat temp01 = LERP(a, v001, v101);
     84    const GLfloat temp11 = LERP(a, v011, v111);
     85    const GLfloat temp0 = LERP(b, temp00, temp10);
     86    const GLfloat temp1 = LERP(b, temp01, temp11);
     87    return LERP(c, temp0, temp1);
     88 }
     89 
     90 
     91 /**
     92  * Do linear interpolation of colors.
     93  */
     94 static inline void
     95 lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4])
     96 {
     97    result[0] = LERP(t, a[0], b[0]);
     98    result[1] = LERP(t, a[1], b[1]);
     99    result[2] = LERP(t, a[2], b[2]);
    100    result[3] = LERP(t, a[3], b[3]);
    101 }
    102 
    103 
    104 /**
    105  * Do bilinear interpolation of colors.
    106  */
    107 static inline void
    108 lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b,
    109              const GLfloat t00[4], const GLfloat t10[4],
    110              const GLfloat t01[4], const GLfloat t11[4])
    111 {
    112    result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]);
    113    result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]);
    114    result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]);
    115    result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);
    116 }
    117 
    118 
    119 /**
    120  * Do trilinear interpolation of colors.
    121  */
    122 static inline void
    123 lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c,
    124              const GLfloat t000[4], const GLfloat t100[4],
    125              const GLfloat t010[4], const GLfloat t110[4],
    126              const GLfloat t001[4], const GLfloat t101[4],
    127              const GLfloat t011[4], const GLfloat t111[4])
    128 {
    129    GLuint k;
    130    /* compiler should unroll these short loops */
    131    for (k = 0; k < 4; k++) {
    132       result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k],
    133                                    t001[k], t101[k], t011[k], t111[k]);
    134    }
    135 }
    136 
    137 
    138 /**
    139  * Used for GL_REPEAT wrap mode.  Using A % B doesn't produce the
    140  * right results for A<0.  Casting to A to be unsigned only works if B
    141  * is a power of two.  Adding a bias to A (which is a multiple of B)
    142  * avoids the problems with A < 0 (for reasonable A) without using a
    143  * conditional.
    144  */
    145 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
    146 
    147 
    148 /**
    149  * Used to compute texel locations for linear sampling.
    150  * Input:
    151  *    wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
    152  *    s = texcoord in [0,1]
    153  *    size = width (or height or depth) of texture
    154  * Output:
    155  *    i0, i1 = returns two nearest texel indexes
    156  *    weight = returns blend factor between texels
    157  */
    158 static inline void
    159 linear_texel_locations(GLenum wrapMode,
    160                        const struct gl_texture_image *img,
    161                        GLint size, GLfloat s,
    162                        GLint *i0, GLint *i1, GLfloat *weight)
    163 {
    164    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
    165    GLfloat u;
    166    switch (wrapMode) {
    167    case GL_REPEAT:
    168       u = s * size - 0.5F;
    169       if (swImg->_IsPowerOfTwo) {
    170          *i0 = IFLOOR(u) & (size - 1);
    171          *i1 = (*i0 + 1) & (size - 1);
    172       }
    173       else {
    174          *i0 = REMAINDER(IFLOOR(u), size);
    175          *i1 = REMAINDER(*i0 + 1, size);
    176       }
    177       break;
    178    case GL_CLAMP_TO_EDGE:
    179       if (s <= 0.0F)
    180          u = 0.0F;
    181       else if (s >= 1.0F)
    182          u = (GLfloat) size;
    183       else
    184          u = s * size;
    185       u -= 0.5F;
    186       *i0 = IFLOOR(u);
    187       *i1 = *i0 + 1;
    188       if (*i0 < 0)
    189          *i0 = 0;
    190       if (*i1 >= (GLint) size)
    191          *i1 = size - 1;
    192       break;
    193    case GL_CLAMP_TO_BORDER:
    194       {
    195          const GLfloat min = -1.0F / (2.0F * size);
    196          const GLfloat max = 1.0F - min;
    197          if (s <= min)
    198             u = min * size;
    199          else if (s >= max)
    200             u = max * size;
    201          else
    202             u = s * size;
    203          u -= 0.5F;
    204          *i0 = IFLOOR(u);
    205          *i1 = *i0 + 1;
    206       }
    207       break;
    208    case GL_MIRRORED_REPEAT:
    209       {
    210          const GLint flr = IFLOOR(s);
    211          if (flr & 1)
    212             u = 1.0F - (s - (GLfloat) flr);
    213          else
    214             u = s - (GLfloat) flr;
    215          u = (u * size) - 0.5F;
    216          *i0 = IFLOOR(u);
    217          *i1 = *i0 + 1;
    218          if (*i0 < 0)
    219             *i0 = 0;
    220          if (*i1 >= (GLint) size)
    221             *i1 = size - 1;
    222       }
    223       break;
    224    case GL_MIRROR_CLAMP_EXT:
    225       u = FABSF(s);
    226       if (u >= 1.0F)
    227          u = (GLfloat) size;
    228       else
    229          u *= size;
    230       u -= 0.5F;
    231       *i0 = IFLOOR(u);
    232       *i1 = *i0 + 1;
    233       break;
    234    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
    235       u = FABSF(s);
    236       if (u >= 1.0F)
    237          u = (GLfloat) size;
    238       else
    239          u *= size;
    240       u -= 0.5F;
    241       *i0 = IFLOOR(u);
    242       *i1 = *i0 + 1;
    243       if (*i0 < 0)
    244          *i0 = 0;
    245       if (*i1 >= (GLint) size)
    246          *i1 = size - 1;
    247       break;
    248    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
    249       {
    250          const GLfloat min = -1.0F / (2.0F * size);
    251          const GLfloat max = 1.0F - min;
    252          u = FABSF(s);
    253          if (u <= min)
    254             u = min * size;
    255          else if (u >= max)
    256             u = max * size;
    257          else
    258             u *= size;
    259          u -= 0.5F;
    260          *i0 = IFLOOR(u);
    261          *i1 = *i0 + 1;
    262       }
    263       break;
    264    case GL_CLAMP:
    265       if (s <= 0.0F)
    266          u = 0.0F;
    267       else if (s >= 1.0F)
    268          u = (GLfloat) size;
    269       else
    270          u = s * size;
    271       u -= 0.5F;
    272       *i0 = IFLOOR(u);
    273       *i1 = *i0 + 1;
    274       break;
    275    default:
    276       _mesa_problem(NULL, "Bad wrap mode");
    277       u = 0.0F;
    278       break;
    279    }
    280    *weight = FRAC(u);
    281 }
    282 
    283 
    284 /**
    285  * Used to compute texel location for nearest sampling.
    286  */
    287 static inline GLint
    288 nearest_texel_location(GLenum wrapMode,
    289                        const struct gl_texture_image *img,
    290                        GLint size, GLfloat s)
    291 {
    292    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
    293    GLint i;
    294 
    295    switch (wrapMode) {
    296    case GL_REPEAT:
    297       /* s limited to [0,1) */
    298       /* i limited to [0,size-1] */
    299       i = IFLOOR(s * size);
    300       if (swImg->_IsPowerOfTwo)
    301          i &= (size - 1);
    302       else
    303          i = REMAINDER(i, size);
    304       return i;
    305    case GL_CLAMP_TO_EDGE:
    306       {
    307          /* s limited to [min,max] */
    308          /* i limited to [0, size-1] */
    309          const GLfloat min = 1.0F / (2.0F * size);
    310          const GLfloat max = 1.0F - min;
    311          if (s < min)
    312             i = 0;
    313          else if (s > max)
    314             i = size - 1;
    315          else
    316             i = IFLOOR(s * size);
    317       }
    318       return i;
    319    case GL_CLAMP_TO_BORDER:
    320       {
    321          /* s limited to [min,max] */
    322          /* i limited to [-1, size] */
    323          const GLfloat min = -1.0F / (2.0F * size);
    324          const GLfloat max = 1.0F - min;
    325          if (s <= min)
    326             i = -1;
    327          else if (s >= max)
    328             i = size;
    329          else
    330             i = IFLOOR(s * size);
    331       }
    332       return i;
    333    case GL_MIRRORED_REPEAT:
    334       {
    335          const GLfloat min = 1.0F / (2.0F * size);
    336          const GLfloat max = 1.0F - min;
    337          const GLint flr = IFLOOR(s);
    338          GLfloat u;
    339          if (flr & 1)
    340             u = 1.0F - (s - (GLfloat) flr);
    341          else
    342             u = s - (GLfloat) flr;
    343          if (u < min)
    344             i = 0;
    345          else if (u > max)
    346             i = size - 1;
    347          else
    348             i = IFLOOR(u * size);
    349       }
    350       return i;
    351    case GL_MIRROR_CLAMP_EXT:
    352       {
    353          /* s limited to [0,1] */
    354          /* i limited to [0,size-1] */
    355          const GLfloat u = FABSF(s);
    356          if (u <= 0.0F)
    357             i = 0;
    358          else if (u >= 1.0F)
    359             i = size - 1;
    360          else
    361             i = IFLOOR(u * size);
    362       }
    363       return i;
    364    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
    365       {
    366          /* s limited to [min,max] */
    367          /* i limited to [0, size-1] */
    368          const GLfloat min = 1.0F / (2.0F * size);
    369          const GLfloat max = 1.0F - min;
    370          const GLfloat u = FABSF(s);
    371          if (u < min)
    372             i = 0;
    373          else if (u > max)
    374             i = size - 1;
    375          else
    376             i = IFLOOR(u * size);
    377       }
    378       return i;
    379    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
    380       {
    381          /* s limited to [min,max] */
    382          /* i limited to [0, size-1] */
    383          const GLfloat min = -1.0F / (2.0F * size);
    384          const GLfloat max = 1.0F - min;
    385          const GLfloat u = FABSF(s);
    386          if (u < min)
    387             i = -1;
    388          else if (u > max)
    389             i = size;
    390          else
    391             i = IFLOOR(u * size);
    392       }
    393       return i;
    394    case GL_CLAMP:
    395       /* s limited to [0,1] */
    396       /* i limited to [0,size-1] */
    397       if (s <= 0.0F)
    398          i = 0;
    399       else if (s >= 1.0F)
    400          i = size - 1;
    401       else
    402          i = IFLOOR(s * size);
    403       return i;
    404    default:
    405       _mesa_problem(NULL, "Bad wrap mode");
    406       return 0;
    407    }
    408 }
    409 
    410 
    411 /* Power of two image sizes only */
    412 static inline void
    413 linear_repeat_texel_location(GLuint size, GLfloat s,
    414                              GLint *i0, GLint *i1, GLfloat *weight)
    415 {
    416    GLfloat u = s * size - 0.5F;
    417    *i0 = IFLOOR(u) & (size - 1);
    418    *i1 = (*i0 + 1) & (size - 1);
    419    *weight = FRAC(u);
    420 }
    421 
    422 
    423 /**
    424  * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
    425  */
    426 static inline GLint
    427 clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
    428 {
    429    switch (wrapMode) {
    430    case GL_CLAMP:
    431       return IFLOOR( CLAMP(coord, 0.0F, max - 1) );
    432    case GL_CLAMP_TO_EDGE:
    433       return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) );
    434    case GL_CLAMP_TO_BORDER:
    435       return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) );
    436    default:
    437       _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest");
    438       return 0;
    439    }
    440 }
    441 
    442 
    443 /**
    444  * As above, but GL_LINEAR filtering.
    445  */
    446 static inline void
    447 clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
    448                         GLint *i0out, GLint *i1out, GLfloat *weight)
    449 {
    450    GLfloat fcol;
    451    GLint i0, i1;
    452    switch (wrapMode) {
    453    case GL_CLAMP:
    454       /* Not exactly what the spec says, but it matches NVIDIA output */
    455       fcol = CLAMP(coord - 0.5F, 0.0F, max - 1);
    456       i0 = IFLOOR(fcol);
    457       i1 = i0 + 1;
    458       break;
    459    case GL_CLAMP_TO_EDGE:
    460       fcol = CLAMP(coord, 0.5F, max - 0.5F);
    461       fcol -= 0.5F;
    462       i0 = IFLOOR(fcol);
    463       i1 = i0 + 1;
    464       if (i1 > max - 1)
    465          i1 = max - 1;
    466       break;
    467    case GL_CLAMP_TO_BORDER:
    468       fcol = CLAMP(coord, -0.5F, max + 0.5F);
    469       fcol -= 0.5F;
    470       i0 = IFLOOR(fcol);
    471       i1 = i0 + 1;
    472       break;
    473    default:
    474       _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear");
    475       i0 = i1 = 0;
    476       fcol = 0.0F;
    477       break;
    478    }
    479    *i0out = i0;
    480    *i1out = i1;
    481    *weight = FRAC(fcol);
    482 }
    483 
    484 
    485 /**
    486  * Compute slice/image to use for 1D or 2D array texture.
    487  */
    488 static inline GLint
    489 tex_array_slice(GLfloat coord, GLsizei size)
    490 {
    491    GLint slice = IFLOOR(coord + 0.5f);
    492    slice = CLAMP(slice, 0, size - 1);
    493    return slice;
    494 }
    495 
    496 
    497 /**
    498  * Compute nearest integer texcoords for given texobj and coordinate.
    499  * NOTE: only used for depth texture sampling.
    500  */
    501 static inline void
    502 nearest_texcoord(const struct gl_sampler_object *samp,
    503                  const struct gl_texture_object *texObj,
    504                  GLuint level,
    505                  const GLfloat texcoord[4],
    506                  GLint *i, GLint *j, GLint *k)
    507 {
    508    const struct gl_texture_image *img = texObj->Image[0][level];
    509    const GLint width = img->Width;
    510    const GLint height = img->Height;
    511    const GLint depth = img->Depth;
    512 
    513    switch (texObj->Target) {
    514    case GL_TEXTURE_RECTANGLE_ARB:
    515       *i = clamp_rect_coord_nearest(samp->WrapS, texcoord[0], width);
    516       *j = clamp_rect_coord_nearest(samp->WrapT, texcoord[1], height);
    517       *k = 0;
    518       break;
    519    case GL_TEXTURE_1D:
    520       *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
    521       *j = 0;
    522       *k = 0;
    523       break;
    524    case GL_TEXTURE_2D:
    525       *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
    526       *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
    527       *k = 0;
    528       break;
    529    case GL_TEXTURE_1D_ARRAY_EXT:
    530       *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
    531       *j = tex_array_slice(texcoord[1], height);
    532       *k = 0;
    533       break;
    534    case GL_TEXTURE_2D_ARRAY_EXT:
    535       *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
    536       *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
    537       *k = tex_array_slice(texcoord[2], depth);
    538       break;
    539    default:
    540       *i = *j = *k = 0;
    541       break;
    542    }
    543 }
    544 
    545 
    546 /**
    547  * Compute linear integer texcoords for given texobj and coordinate.
    548  * NOTE: only used for depth texture sampling.
    549  */
    550 static inline void
    551 linear_texcoord(const struct gl_sampler_object *samp,
    552                 const struct gl_texture_object *texObj,
    553                 GLuint level,
    554                 const GLfloat texcoord[4],
    555                 GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice,
    556                 GLfloat *wi, GLfloat *wj)
    557 {
    558    const struct gl_texture_image *img = texObj->Image[0][level];
    559    const GLint width = img->Width;
    560    const GLint height = img->Height;
    561    const GLint depth = img->Depth;
    562 
    563    switch (texObj->Target) {
    564    case GL_TEXTURE_RECTANGLE_ARB:
    565       clamp_rect_coord_linear(samp->WrapS, texcoord[0],
    566                               width, i0, i1, wi);
    567       clamp_rect_coord_linear(samp->WrapT, texcoord[1],
    568                               height, j0, j1, wj);
    569       *slice = 0;
    570       break;
    571 
    572    case GL_TEXTURE_1D:
    573    case GL_TEXTURE_2D:
    574       linear_texel_locations(samp->WrapS, img, width,
    575                              texcoord[0], i0, i1, wi);
    576       linear_texel_locations(samp->WrapT, img, height,
    577                              texcoord[1], j0, j1, wj);
    578       *slice = 0;
    579       break;
    580 
    581    case GL_TEXTURE_1D_ARRAY_EXT:
    582       linear_texel_locations(samp->WrapS, img, width,
    583                              texcoord[0], i0, i1, wi);
    584       *j0 = tex_array_slice(texcoord[1], height);
    585       *j1 = *j0;
    586       *slice = 0;
    587       break;
    588 
    589    case GL_TEXTURE_2D_ARRAY_EXT:
    590       linear_texel_locations(samp->WrapS, img, width,
    591                              texcoord[0], i0, i1, wi);
    592       linear_texel_locations(samp->WrapT, img, height,
    593                              texcoord[1], j0, j1, wj);
    594       *slice = tex_array_slice(texcoord[2], depth);
    595       break;
    596 
    597    default:
    598       *slice = 0;
    599       break;
    600    }
    601 }
    602 
    603 
    604 
    605 /**
    606  * For linear interpolation between mipmap levels N and N+1, this function
    607  * computes N.
    608  */
    609 static inline GLint
    610 linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
    611 {
    612    if (lambda < 0.0F)
    613       return tObj->BaseLevel;
    614    else if (lambda > tObj->_MaxLambda)
    615       return (GLint) (tObj->BaseLevel + tObj->_MaxLambda);
    616    else
    617       return (GLint) (tObj->BaseLevel + lambda);
    618 }
    619 
    620 
    621 /**
    622  * Compute the nearest mipmap level to take texels from.
    623  */
    624 static inline GLint
    625 nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
    626 {
    627    GLfloat l;
    628    GLint level;
    629    if (lambda <= 0.5F)
    630       l = 0.0F;
    631    else if (lambda > tObj->_MaxLambda + 0.4999F)
    632       l = tObj->_MaxLambda + 0.4999F;
    633    else
    634       l = lambda;
    635    level = (GLint) (tObj->BaseLevel + l + 0.5F);
    636    if (level > tObj->_MaxLevel)
    637       level = tObj->_MaxLevel;
    638    return level;
    639 }
    640 
    641 
    642 
    643 /*
    644  * Bitflags for texture border color sampling.
    645  */
    646 #define I0BIT   1
    647 #define I1BIT   2
    648 #define J0BIT   4
    649 #define J1BIT   8
    650 #define K0BIT  16
    651 #define K1BIT  32
    652 
    653 
    654 
    655 /**
    656  * The lambda[] array values are always monotonic.  Either the whole span
    657  * will be minified, magnified, or split between the two.  This function
    658  * determines the subranges in [0, n-1] that are to be minified or magnified.
    659  */
    660 static inline void
    661 compute_min_mag_ranges(const struct gl_sampler_object *samp,
    662                        GLuint n, const GLfloat lambda[],
    663                        GLuint *minStart, GLuint *minEnd,
    664                        GLuint *magStart, GLuint *magEnd)
    665 {
    666    GLfloat minMagThresh;
    667 
    668    /* we shouldn't be here if minfilter == magfilter */
    669    ASSERT(samp->MinFilter != samp->MagFilter);
    670 
    671    /* This bit comes from the OpenGL spec: */
    672    if (samp->MagFilter == GL_LINEAR
    673        && (samp->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
    674            samp->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
    675       minMagThresh = 0.5F;
    676    }
    677    else {
    678       minMagThresh = 0.0F;
    679    }
    680 
    681 #if 0
    682    /* DEBUG CODE: Verify that lambda[] is monotonic.
    683     * We can't really use this because the inaccuracy in the LOG2 function
    684     * causes this test to fail, yet the resulting texturing is correct.
    685     */
    686    if (n > 1) {
    687       GLuint i;
    688       printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
    689       if (lambda[0] >= lambda[n-1]) { /* decreasing */
    690          for (i = 0; i < n - 1; i++) {
    691             ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
    692          }
    693       }
    694       else { /* increasing */
    695          for (i = 0; i < n - 1; i++) {
    696             ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
    697          }
    698       }
    699    }
    700 #endif /* DEBUG */
    701 
    702    if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
    703       /* magnification for whole span */
    704       *magStart = 0;
    705       *magEnd = n;
    706       *minStart = *minEnd = 0;
    707    }
    708    else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
    709       /* minification for whole span */
    710       *minStart = 0;
    711       *minEnd = n;
    712       *magStart = *magEnd = 0;
    713    }
    714    else {
    715       /* a mix of minification and magnification */
    716       GLuint i;
    717       if (lambda[0] > minMagThresh) {
    718          /* start with minification */
    719          for (i = 1; i < n; i++) {
    720             if (lambda[i] <= minMagThresh)
    721                break;
    722          }
    723          *minStart = 0;
    724          *minEnd = i;
    725          *magStart = i;
    726          *magEnd = n;
    727       }
    728       else {
    729          /* start with magnification */
    730          for (i = 1; i < n; i++) {
    731             if (lambda[i] > minMagThresh)
    732                break;
    733          }
    734          *magStart = 0;
    735          *magEnd = i;
    736          *minStart = i;
    737          *minEnd = n;
    738       }
    739    }
    740 
    741 #if 0
    742    /* Verify the min/mag Start/End values
    743     * We don't use this either (see above)
    744     */
    745    {
    746       GLint i;
    747       for (i = 0; i < n; i++) {
    748          if (lambda[i] > minMagThresh) {
    749             /* minification */
    750             ASSERT(i >= *minStart);
    751             ASSERT(i < *minEnd);
    752          }
    753          else {
    754             /* magnification */
    755             ASSERT(i >= *magStart);
    756             ASSERT(i < *magEnd);
    757          }
    758       }
    759    }
    760 #endif
    761 }
    762 
    763 
    764 /**
    765  * When we sample the border color, it must be interpreted according to
    766  * the base texture format.  Ex: if the texture base format it GL_ALPHA,
    767  * we return (0,0,0,BorderAlpha).
    768  */
    769 static inline void
    770 get_border_color(const struct gl_sampler_object *samp,
    771                  const struct gl_texture_image *img,
    772                  GLfloat rgba[4])
    773 {
    774    switch (img->_BaseFormat) {
    775    case GL_RGB:
    776       rgba[0] = samp->BorderColor.f[0];
    777       rgba[1] = samp->BorderColor.f[1];
    778       rgba[2] = samp->BorderColor.f[2];
    779       rgba[3] = 1.0F;
    780       break;
    781    case GL_ALPHA:
    782       rgba[0] = rgba[1] = rgba[2] = 0.0;
    783       rgba[3] = samp->BorderColor.f[3];
    784       break;
    785    case GL_LUMINANCE:
    786       rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
    787       rgba[3] = 1.0;
    788       break;
    789    case GL_LUMINANCE_ALPHA:
    790       rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
    791       rgba[3] = samp->BorderColor.f[3];
    792       break;
    793    case GL_INTENSITY:
    794       rgba[0] = rgba[1] = rgba[2] = rgba[3] = samp->BorderColor.f[0];
    795       break;
    796    default:
    797       COPY_4V(rgba, samp->BorderColor.f);
    798       break;
    799    }
    800 }
    801 
    802 
    803 /**
    804  * Put z into texel according to GL_DEPTH_MODE.
    805  */
    806 static INLINE void
    807 apply_depth_mode(GLenum depthMode, GLfloat z, GLfloat texel[4])
    808 {
    809    switch (depthMode) {
    810    case GL_LUMINANCE:
    811       ASSIGN_4V(texel, z, z, z, 1.0F);
    812       break;
    813    case GL_INTENSITY:
    814       ASSIGN_4V(texel, z, z, z, z);
    815       break;
    816    case GL_ALPHA:
    817       ASSIGN_4V(texel, 0.0F, 0.0F, 0.0F, z);
    818       break;
    819    case GL_RED:
    820       ASSIGN_4V(texel, z, 0.0F, 0.0F, 1.0F);
    821       break;
    822    default:
    823       _mesa_problem(NULL, "Bad depth texture mode");
    824    }
    825 }
    826 
    827 
    828 /**
    829  * Is the given texture a depth (or depth/stencil) texture?
    830  */
    831 static GLboolean
    832 is_depth_texture(const struct gl_texture_object *tObj)
    833 {
    834    GLenum format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
    835    return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT;
    836 }
    837 
    838 
    839 /**********************************************************************/
    840 /*                    1-D Texture Sampling Functions                  */
    841 /**********************************************************************/
    842 
    843 /**
    844  * Return the texture sample for coordinate (s) using GL_NEAREST filter.
    845  */
    846 static inline void
    847 sample_1d_nearest(struct gl_context *ctx,
    848                   const struct gl_sampler_object *samp,
    849                   const struct gl_texture_image *img,
    850                   const GLfloat texcoord[4], GLfloat rgba[4])
    851 {
    852    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
    853    const GLint width = img->Width2;  /* without border, power of two */
    854    GLint i;
    855    i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
    856    /* skip over the border, if any */
    857    i += img->Border;
    858    if (i < 0 || i >= (GLint) img->Width) {
    859       /* Need this test for GL_CLAMP_TO_BORDER mode */
    860       get_border_color(samp, img, rgba);
    861    }
    862    else {
    863       swImg->FetchTexel(swImg, i, 0, 0, rgba);
    864    }
    865 }
    866 
    867 
    868 /**
    869  * Return the texture sample for coordinate (s) using GL_LINEAR filter.
    870  */
    871 static inline void
    872 sample_1d_linear(struct gl_context *ctx,
    873                  const struct gl_sampler_object *samp,
    874                  const struct gl_texture_image *img,
    875                  const GLfloat texcoord[4], GLfloat rgba[4])
    876 {
    877    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
    878    const GLint width = img->Width2;
    879    GLint i0, i1;
    880    GLbitfield useBorderColor = 0x0;
    881    GLfloat a;
    882    GLfloat t0[4], t1[4];  /* texels */
    883 
    884    linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
    885 
    886    if (img->Border) {
    887       i0 += img->Border;
    888       i1 += img->Border;
    889    }
    890    else {
    891       if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
    892       if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
    893    }
    894 
    895    /* fetch texel colors */
    896    if (useBorderColor & I0BIT) {
    897       get_border_color(samp, img, t0);
    898    }
    899    else {
    900       swImg->FetchTexel(swImg, i0, 0, 0, t0);
    901    }
    902    if (useBorderColor & I1BIT) {
    903       get_border_color(samp, img, t1);
    904    }
    905    else {
    906       swImg->FetchTexel(swImg, i1, 0, 0, t1);
    907    }
    908 
    909    lerp_rgba(rgba, a, t0, t1);
    910 }
    911 
    912 
    913 static void
    914 sample_1d_nearest_mipmap_nearest(struct gl_context *ctx,
    915                                  const struct gl_sampler_object *samp,
    916                                  const struct gl_texture_object *tObj,
    917                                  GLuint n, const GLfloat texcoord[][4],
    918                                  const GLfloat lambda[], GLfloat rgba[][4])
    919 {
    920    GLuint i;
    921    ASSERT(lambda != NULL);
    922    for (i = 0; i < n; i++) {
    923       GLint level = nearest_mipmap_level(tObj, lambda[i]);
    924       sample_1d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
    925    }
    926 }
    927 
    928 
    929 static void
    930 sample_1d_linear_mipmap_nearest(struct gl_context *ctx,
    931                                 const struct gl_sampler_object *samp,
    932                                 const struct gl_texture_object *tObj,
    933                                 GLuint n, const GLfloat texcoord[][4],
    934                                 const GLfloat lambda[], GLfloat rgba[][4])
    935 {
    936    GLuint i;
    937    ASSERT(lambda != NULL);
    938    for (i = 0; i < n; i++) {
    939       GLint level = nearest_mipmap_level(tObj, lambda[i]);
    940       sample_1d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
    941    }
    942 }
    943 
    944 
    945 static void
    946 sample_1d_nearest_mipmap_linear(struct gl_context *ctx,
    947                                 const struct gl_sampler_object *samp,
    948                                 const struct gl_texture_object *tObj,
    949                                 GLuint n, const GLfloat texcoord[][4],
    950                                 const GLfloat lambda[], GLfloat rgba[][4])
    951 {
    952    GLuint i;
    953    ASSERT(lambda != NULL);
    954    for (i = 0; i < n; i++) {
    955       GLint level = linear_mipmap_level(tObj, lambda[i]);
    956       if (level >= tObj->_MaxLevel) {
    957          sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
    958                            texcoord[i], rgba[i]);
    959       }
    960       else {
    961          GLfloat t0[4], t1[4];
    962          const GLfloat f = FRAC(lambda[i]);
    963          sample_1d_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
    964          sample_1d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
    965          lerp_rgba(rgba[i], f, t0, t1);
    966       }
    967    }
    968 }
    969 
    970 
    971 static void
    972 sample_1d_linear_mipmap_linear(struct gl_context *ctx,
    973                                const struct gl_sampler_object *samp,
    974                                const struct gl_texture_object *tObj,
    975                                GLuint n, const GLfloat texcoord[][4],
    976                                const GLfloat lambda[], GLfloat rgba[][4])
    977 {
    978    GLuint i;
    979    ASSERT(lambda != NULL);
    980    for (i = 0; i < n; i++) {
    981       GLint level = linear_mipmap_level(tObj, lambda[i]);
    982       if (level >= tObj->_MaxLevel) {
    983          sample_1d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
    984                           texcoord[i], rgba[i]);
    985       }
    986       else {
    987          GLfloat t0[4], t1[4];
    988          const GLfloat f = FRAC(lambda[i]);
    989          sample_1d_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
    990          sample_1d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
    991          lerp_rgba(rgba[i], f, t0, t1);
    992       }
    993    }
    994 }
    995 
    996 
    997 /** Sample 1D texture, nearest filtering for both min/magnification */
    998 static void
    999 sample_nearest_1d( struct gl_context *ctx,
   1000                    const struct gl_sampler_object *samp,
   1001                    const struct gl_texture_object *tObj, GLuint n,
   1002                    const GLfloat texcoords[][4], const GLfloat lambda[],
   1003                    GLfloat rgba[][4] )
   1004 {
   1005    GLuint i;
   1006    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   1007    (void) lambda;
   1008    for (i = 0; i < n; i++) {
   1009       sample_1d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
   1010    }
   1011 }
   1012 
   1013 
   1014 /** Sample 1D texture, linear filtering for both min/magnification */
   1015 static void
   1016 sample_linear_1d( struct gl_context *ctx,
   1017                   const struct gl_sampler_object *samp,
   1018                   const struct gl_texture_object *tObj, GLuint n,
   1019                   const GLfloat texcoords[][4], const GLfloat lambda[],
   1020                   GLfloat rgba[][4] )
   1021 {
   1022    GLuint i;
   1023    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   1024    (void) lambda;
   1025    for (i = 0; i < n; i++) {
   1026       sample_1d_linear(ctx, samp, image, texcoords[i], rgba[i]);
   1027    }
   1028 }
   1029 
   1030 
   1031 /** Sample 1D texture, using lambda to choose between min/magnification */
   1032 static void
   1033 sample_lambda_1d( struct gl_context *ctx,
   1034                   const struct gl_sampler_object *samp,
   1035                   const struct gl_texture_object *tObj, GLuint n,
   1036                   const GLfloat texcoords[][4],
   1037                   const GLfloat lambda[], GLfloat rgba[][4] )
   1038 {
   1039    GLuint minStart, minEnd;  /* texels with minification */
   1040    GLuint magStart, magEnd;  /* texels with magnification */
   1041    GLuint i;
   1042 
   1043    ASSERT(lambda != NULL);
   1044    compute_min_mag_ranges(samp, n, lambda,
   1045                           &minStart, &minEnd, &magStart, &magEnd);
   1046 
   1047    if (minStart < minEnd) {
   1048       /* do the minified texels */
   1049       const GLuint m = minEnd - minStart;
   1050       switch (samp->MinFilter) {
   1051       case GL_NEAREST:
   1052          for (i = minStart; i < minEnd; i++)
   1053             sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   1054                               texcoords[i], rgba[i]);
   1055          break;
   1056       case GL_LINEAR:
   1057          for (i = minStart; i < minEnd; i++)
   1058             sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   1059                              texcoords[i], rgba[i]);
   1060          break;
   1061       case GL_NEAREST_MIPMAP_NEAREST:
   1062          sample_1d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   1063                                           lambda + minStart, rgba + minStart);
   1064          break;
   1065       case GL_LINEAR_MIPMAP_NEAREST:
   1066          sample_1d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   1067                                          lambda + minStart, rgba + minStart);
   1068          break;
   1069       case GL_NEAREST_MIPMAP_LINEAR:
   1070          sample_1d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   1071                                          lambda + minStart, rgba + minStart);
   1072          break;
   1073       case GL_LINEAR_MIPMAP_LINEAR:
   1074          sample_1d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   1075                                         lambda + minStart, rgba + minStart);
   1076          break;
   1077       default:
   1078          _mesa_problem(ctx, "Bad min filter in sample_1d_texture");
   1079          return;
   1080       }
   1081    }
   1082 
   1083    if (magStart < magEnd) {
   1084       /* do the magnified texels */
   1085       switch (samp->MagFilter) {
   1086       case GL_NEAREST:
   1087          for (i = magStart; i < magEnd; i++)
   1088             sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   1089                               texcoords[i], rgba[i]);
   1090          break;
   1091       case GL_LINEAR:
   1092          for (i = magStart; i < magEnd; i++)
   1093             sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   1094                              texcoords[i], rgba[i]);
   1095          break;
   1096       default:
   1097          _mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
   1098          return;
   1099       }
   1100    }
   1101 }
   1102 
   1103 
   1104 /**********************************************************************/
   1105 /*                    2-D Texture Sampling Functions                  */
   1106 /**********************************************************************/
   1107 
   1108 
   1109 /**
   1110  * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
   1111  */
   1112 static inline void
   1113 sample_2d_nearest(struct gl_context *ctx,
   1114                   const struct gl_sampler_object *samp,
   1115                   const struct gl_texture_image *img,
   1116                   const GLfloat texcoord[4],
   1117                   GLfloat rgba[])
   1118 {
   1119    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   1120    const GLint width = img->Width2;    /* without border, power of two */
   1121    const GLint height = img->Height2;  /* without border, power of two */
   1122    GLint i, j;
   1123    (void) ctx;
   1124 
   1125    i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
   1126    j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
   1127 
   1128    /* skip over the border, if any */
   1129    i += img->Border;
   1130    j += img->Border;
   1131 
   1132    if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
   1133       /* Need this test for GL_CLAMP_TO_BORDER mode */
   1134       get_border_color(samp, img, rgba);
   1135    }
   1136    else {
   1137       swImg->FetchTexel(swImg, i, j, 0, rgba);
   1138    }
   1139 }
   1140 
   1141 
   1142 /**
   1143  * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
   1144  * New sampling code contributed by Lynn Quam <quam (at) ai.sri.com>.
   1145  */
   1146 static inline void
   1147 sample_2d_linear(struct gl_context *ctx,
   1148                  const struct gl_sampler_object *samp,
   1149                  const struct gl_texture_image *img,
   1150                  const GLfloat texcoord[4],
   1151                  GLfloat rgba[])
   1152 {
   1153    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   1154    const GLint width = img->Width2;
   1155    const GLint height = img->Height2;
   1156    GLint i0, j0, i1, j1;
   1157    GLbitfield useBorderColor = 0x0;
   1158    GLfloat a, b;
   1159    GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
   1160 
   1161    linear_texel_locations(samp->WrapS, img, width, texcoord[0],  &i0, &i1, &a);
   1162    linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
   1163 
   1164    if (img->Border) {
   1165       i0 += img->Border;
   1166       i1 += img->Border;
   1167       j0 += img->Border;
   1168       j1 += img->Border;
   1169    }
   1170    else {
   1171       if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
   1172       if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
   1173       if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
   1174       if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
   1175    }
   1176 
   1177    /* fetch four texel colors */
   1178    if (useBorderColor & (I0BIT | J0BIT)) {
   1179       get_border_color(samp, img, t00);
   1180    }
   1181    else {
   1182       swImg->FetchTexel(swImg, i0, j0, 0, t00);
   1183    }
   1184    if (useBorderColor & (I1BIT | J0BIT)) {
   1185       get_border_color(samp, img, t10);
   1186    }
   1187    else {
   1188       swImg->FetchTexel(swImg, i1, j0, 0, t10);
   1189    }
   1190    if (useBorderColor & (I0BIT | J1BIT)) {
   1191       get_border_color(samp, img, t01);
   1192    }
   1193    else {
   1194       swImg->FetchTexel(swImg, i0, j1, 0, t01);
   1195    }
   1196    if (useBorderColor & (I1BIT | J1BIT)) {
   1197       get_border_color(samp, img, t11);
   1198    }
   1199    else {
   1200       swImg->FetchTexel(swImg, i1, j1, 0, t11);
   1201    }
   1202 
   1203    lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
   1204 }
   1205 
   1206 
   1207 /**
   1208  * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
   1209  * We don't have to worry about the texture border.
   1210  */
   1211 static inline void
   1212 sample_2d_linear_repeat(struct gl_context *ctx,
   1213                         const struct gl_sampler_object *samp,
   1214                         const struct gl_texture_image *img,
   1215                         const GLfloat texcoord[4],
   1216                         GLfloat rgba[])
   1217 {
   1218    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   1219    const GLint width = img->Width2;
   1220    const GLint height = img->Height2;
   1221    GLint i0, j0, i1, j1;
   1222    GLfloat wi, wj;
   1223    GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
   1224 
   1225    (void) ctx;
   1226 
   1227    ASSERT(samp->WrapS == GL_REPEAT);
   1228    ASSERT(samp->WrapT == GL_REPEAT);
   1229    ASSERT(img->Border == 0);
   1230    ASSERT(swImg->_IsPowerOfTwo);
   1231 
   1232    linear_repeat_texel_location(width,  texcoord[0], &i0, &i1, &wi);
   1233    linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj);
   1234 
   1235    swImg->FetchTexel(swImg, i0, j0, 0, t00);
   1236    swImg->FetchTexel(swImg, i1, j0, 0, t10);
   1237    swImg->FetchTexel(swImg, i0, j1, 0, t01);
   1238    swImg->FetchTexel(swImg, i1, j1, 0, t11);
   1239 
   1240    lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11);
   1241 }
   1242 
   1243 
   1244 static void
   1245 sample_2d_nearest_mipmap_nearest(struct gl_context *ctx,
   1246                                  const struct gl_sampler_object *samp,
   1247                                  const struct gl_texture_object *tObj,
   1248                                  GLuint n, const GLfloat texcoord[][4],
   1249                                  const GLfloat lambda[], GLfloat rgba[][4])
   1250 {
   1251    GLuint i;
   1252    for (i = 0; i < n; i++) {
   1253       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   1254       sample_2d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
   1255    }
   1256 }
   1257 
   1258 
   1259 static void
   1260 sample_2d_linear_mipmap_nearest(struct gl_context *ctx,
   1261                                 const struct gl_sampler_object *samp,
   1262                                 const struct gl_texture_object *tObj,
   1263                                 GLuint n, const GLfloat texcoord[][4],
   1264                                 const GLfloat lambda[], GLfloat rgba[][4])
   1265 {
   1266    GLuint i;
   1267    ASSERT(lambda != NULL);
   1268    for (i = 0; i < n; i++) {
   1269       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   1270       sample_2d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
   1271    }
   1272 }
   1273 
   1274 
   1275 static void
   1276 sample_2d_nearest_mipmap_linear(struct gl_context *ctx,
   1277                                 const struct gl_sampler_object *samp,
   1278                                 const struct gl_texture_object *tObj,
   1279                                 GLuint n, const GLfloat texcoord[][4],
   1280                                 const GLfloat lambda[], GLfloat rgba[][4])
   1281 {
   1282    GLuint i;
   1283    ASSERT(lambda != NULL);
   1284    for (i = 0; i < n; i++) {
   1285       GLint level = linear_mipmap_level(tObj, lambda[i]);
   1286       if (level >= tObj->_MaxLevel) {
   1287          sample_2d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   1288                            texcoord[i], rgba[i]);
   1289       }
   1290       else {
   1291          GLfloat t0[4], t1[4];  /* texels */
   1292          const GLfloat f = FRAC(lambda[i]);
   1293          sample_2d_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   1294          sample_2d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   1295          lerp_rgba(rgba[i], f, t0, t1);
   1296       }
   1297    }
   1298 }
   1299 
   1300 
   1301 static void
   1302 sample_2d_linear_mipmap_linear( struct gl_context *ctx,
   1303                                 const struct gl_sampler_object *samp,
   1304                                 const struct gl_texture_object *tObj,
   1305                                 GLuint n, const GLfloat texcoord[][4],
   1306                                 const GLfloat lambda[], GLfloat rgba[][4] )
   1307 {
   1308    GLuint i;
   1309    ASSERT(lambda != NULL);
   1310    for (i = 0; i < n; i++) {
   1311       GLint level = linear_mipmap_level(tObj, lambda[i]);
   1312       if (level >= tObj->_MaxLevel) {
   1313          sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   1314                           texcoord[i], rgba[i]);
   1315       }
   1316       else {
   1317          GLfloat t0[4], t1[4];  /* texels */
   1318          const GLfloat f = FRAC(lambda[i]);
   1319          sample_2d_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   1320          sample_2d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   1321          lerp_rgba(rgba[i], f, t0, t1);
   1322       }
   1323    }
   1324 }
   1325 
   1326 
   1327 static void
   1328 sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx,
   1329                                       const struct gl_sampler_object *samp,
   1330                                       const struct gl_texture_object *tObj,
   1331                                       GLuint n, const GLfloat texcoord[][4],
   1332                                       const GLfloat lambda[], GLfloat rgba[][4])
   1333 {
   1334    GLuint i;
   1335    ASSERT(lambda != NULL);
   1336    ASSERT(samp->WrapS == GL_REPEAT);
   1337    ASSERT(samp->WrapT == GL_REPEAT);
   1338    for (i = 0; i < n; i++) {
   1339       GLint level = linear_mipmap_level(tObj, lambda[i]);
   1340       if (level >= tObj->_MaxLevel) {
   1341          sample_2d_linear_repeat(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   1342                                  texcoord[i], rgba[i]);
   1343       }
   1344       else {
   1345          GLfloat t0[4], t1[4];  /* texels */
   1346          const GLfloat f = FRAC(lambda[i]);
   1347          sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level  ],
   1348                                  texcoord[i], t0);
   1349          sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level+1],
   1350                                  texcoord[i], t1);
   1351          lerp_rgba(rgba[i], f, t0, t1);
   1352       }
   1353    }
   1354 }
   1355 
   1356 
   1357 /** Sample 2D texture, nearest filtering for both min/magnification */
   1358 static void
   1359 sample_nearest_2d(struct gl_context *ctx,
   1360                   const struct gl_sampler_object *samp,
   1361                   const struct gl_texture_object *tObj, GLuint n,
   1362                   const GLfloat texcoords[][4],
   1363                   const GLfloat lambda[], GLfloat rgba[][4])
   1364 {
   1365    GLuint i;
   1366    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   1367    (void) lambda;
   1368    for (i = 0; i < n; i++) {
   1369       sample_2d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
   1370    }
   1371 }
   1372 
   1373 
   1374 /** Sample 2D texture, linear filtering for both min/magnification */
   1375 static void
   1376 sample_linear_2d(struct gl_context *ctx,
   1377                  const struct gl_sampler_object *samp,
   1378                  const struct gl_texture_object *tObj, GLuint n,
   1379                  const GLfloat texcoords[][4],
   1380                  const GLfloat lambda[], GLfloat rgba[][4])
   1381 {
   1382    GLuint i;
   1383    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   1384    const struct swrast_texture_image *swImg = swrast_texture_image_const(image);
   1385    (void) lambda;
   1386    if (samp->WrapS == GL_REPEAT &&
   1387        samp->WrapT == GL_REPEAT &&
   1388        swImg->_IsPowerOfTwo &&
   1389        image->Border == 0) {
   1390       for (i = 0; i < n; i++) {
   1391          sample_2d_linear_repeat(ctx, samp, image, texcoords[i], rgba[i]);
   1392       }
   1393    }
   1394    else {
   1395       for (i = 0; i < n; i++) {
   1396          sample_2d_linear(ctx, samp, image, texcoords[i], rgba[i]);
   1397       }
   1398    }
   1399 }
   1400 
   1401 
   1402 /**
   1403  * Optimized 2-D texture sampling:
   1404  *    S and T wrap mode == GL_REPEAT
   1405  *    GL_NEAREST min/mag filter
   1406  *    No border,
   1407  *    RowStride == Width,
   1408  *    Format = GL_RGB
   1409  */
   1410 static void
   1411 opt_sample_rgb_2d(struct gl_context *ctx,
   1412                   const struct gl_sampler_object *samp,
   1413                   const struct gl_texture_object *tObj,
   1414                   GLuint n, const GLfloat texcoords[][4],
   1415                   const GLfloat lambda[], GLfloat rgba[][4])
   1416 {
   1417    const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
   1418    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   1419    const GLfloat width = (GLfloat) img->Width;
   1420    const GLfloat height = (GLfloat) img->Height;
   1421    const GLint colMask = img->Width - 1;
   1422    const GLint rowMask = img->Height - 1;
   1423    const GLint shift = img->WidthLog2;
   1424    GLuint k;
   1425    (void) ctx;
   1426    (void) lambda;
   1427    ASSERT(samp->WrapS==GL_REPEAT);
   1428    ASSERT(samp->WrapT==GL_REPEAT);
   1429    ASSERT(img->Border==0);
   1430    ASSERT(img->TexFormat == MESA_FORMAT_RGB888);
   1431    ASSERT(swImg->_IsPowerOfTwo);
   1432    (void) swImg;
   1433 
   1434    for (k=0; k<n; k++) {
   1435       GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
   1436       GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
   1437       GLint pos = (j << shift) | i;
   1438       GLubyte *texel = swImg->Map + 3 * pos;
   1439       rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
   1440       rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
   1441       rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
   1442       rgba[k][ACOMP] = 1.0F;
   1443    }
   1444 }
   1445 
   1446 
   1447 /**
   1448  * Optimized 2-D texture sampling:
   1449  *    S and T wrap mode == GL_REPEAT
   1450  *    GL_NEAREST min/mag filter
   1451  *    No border
   1452  *    RowStride == Width,
   1453  *    Format = GL_RGBA
   1454  */
   1455 static void
   1456 opt_sample_rgba_2d(struct gl_context *ctx,
   1457                    const struct gl_sampler_object *samp,
   1458                    const struct gl_texture_object *tObj,
   1459                    GLuint n, const GLfloat texcoords[][4],
   1460                    const GLfloat lambda[], GLfloat rgba[][4])
   1461 {
   1462    const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
   1463    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   1464    const GLfloat width = (GLfloat) img->Width;
   1465    const GLfloat height = (GLfloat) img->Height;
   1466    const GLint colMask = img->Width - 1;
   1467    const GLint rowMask = img->Height - 1;
   1468    const GLint shift = img->WidthLog2;
   1469    GLuint i;
   1470    (void) ctx;
   1471    (void) lambda;
   1472    ASSERT(samp->WrapS==GL_REPEAT);
   1473    ASSERT(samp->WrapT==GL_REPEAT);
   1474    ASSERT(img->Border==0);
   1475    ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888);
   1476    ASSERT(swImg->_IsPowerOfTwo);
   1477    (void) swImg;
   1478 
   1479    for (i = 0; i < n; i++) {
   1480       const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
   1481       const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
   1482       const GLint pos = (row << shift) | col;
   1483       const GLuint texel = *((GLuint *) swImg->Map + pos);
   1484       rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24)        );
   1485       rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
   1486       rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >>  8) & 0xff );
   1487       rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel      ) & 0xff );
   1488    }
   1489 }
   1490 
   1491 
   1492 /** Sample 2D texture, using lambda to choose between min/magnification */
   1493 static void
   1494 sample_lambda_2d(struct gl_context *ctx,
   1495                  const struct gl_sampler_object *samp,
   1496                  const struct gl_texture_object *tObj,
   1497                  GLuint n, const GLfloat texcoords[][4],
   1498                  const GLfloat lambda[], GLfloat rgba[][4])
   1499 {
   1500    const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
   1501    const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
   1502    GLuint minStart, minEnd;  /* texels with minification */
   1503    GLuint magStart, magEnd;  /* texels with magnification */
   1504 
   1505    const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT)
   1506       && (samp->WrapT == GL_REPEAT)
   1507       && (tImg->Border == 0 && (tImg->Width == swImg->RowStride))
   1508       && swImg->_IsPowerOfTwo;
   1509 
   1510    ASSERT(lambda != NULL);
   1511    compute_min_mag_ranges(samp, n, lambda,
   1512                           &minStart, &minEnd, &magStart, &magEnd);
   1513 
   1514    if (minStart < minEnd) {
   1515       /* do the minified texels */
   1516       const GLuint m = minEnd - minStart;
   1517       switch (samp->MinFilter) {
   1518       case GL_NEAREST:
   1519          if (repeatNoBorderPOT) {
   1520             switch (tImg->TexFormat) {
   1521             case MESA_FORMAT_RGB888:
   1522                opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart,
   1523                                  NULL, rgba + minStart);
   1524                break;
   1525             case MESA_FORMAT_RGBA8888:
   1526 	       opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart,
   1527                                   NULL, rgba + minStart);
   1528                break;
   1529             default:
   1530                sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
   1531                                  NULL, rgba + minStart );
   1532             }
   1533          }
   1534          else {
   1535             sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
   1536                               NULL, rgba + minStart);
   1537          }
   1538          break;
   1539       case GL_LINEAR:
   1540 	 sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart,
   1541 			  NULL, rgba + minStart);
   1542          break;
   1543       case GL_NEAREST_MIPMAP_NEAREST:
   1544          sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m,
   1545                                           texcoords + minStart,
   1546                                           lambda + minStart, rgba + minStart);
   1547          break;
   1548       case GL_LINEAR_MIPMAP_NEAREST:
   1549          sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   1550                                          lambda + minStart, rgba + minStart);
   1551          break;
   1552       case GL_NEAREST_MIPMAP_LINEAR:
   1553          sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   1554                                          lambda + minStart, rgba + minStart);
   1555          break;
   1556       case GL_LINEAR_MIPMAP_LINEAR:
   1557          if (repeatNoBorderPOT)
   1558             sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m,
   1559                   texcoords + minStart, lambda + minStart, rgba + minStart);
   1560          else
   1561             sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   1562                                         lambda + minStart, rgba + minStart);
   1563          break;
   1564       default:
   1565          _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
   1566          return;
   1567       }
   1568    }
   1569 
   1570    if (magStart < magEnd) {
   1571       /* do the magnified texels */
   1572       const GLuint m = magEnd - magStart;
   1573 
   1574       switch (samp->MagFilter) {
   1575       case GL_NEAREST:
   1576          if (repeatNoBorderPOT) {
   1577             switch (tImg->TexFormat) {
   1578             case MESA_FORMAT_RGB888:
   1579                opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart,
   1580                                  NULL, rgba + magStart);
   1581                break;
   1582             case MESA_FORMAT_RGBA8888:
   1583 	       opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart,
   1584                                   NULL, rgba + magStart);
   1585                break;
   1586             default:
   1587                sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
   1588                                  NULL, rgba + magStart );
   1589             }
   1590          }
   1591          else {
   1592             sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
   1593                               NULL, rgba + magStart);
   1594          }
   1595          break;
   1596       case GL_LINEAR:
   1597 	 sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart,
   1598 			  NULL, rgba + magStart);
   1599          break;
   1600       default:
   1601          _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
   1602          break;
   1603       }
   1604    }
   1605 }
   1606 
   1607 
   1608 /* For anisotropic filtering */
   1609 #define WEIGHT_LUT_SIZE 1024
   1610 
   1611 static GLfloat *weightLut = NULL;
   1612 
   1613 /**
   1614  * Creates the look-up table used to speed-up EWA sampling
   1615  */
   1616 static void
   1617 create_filter_table(void)
   1618 {
   1619    GLuint i;
   1620    if (!weightLut) {
   1621       weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
   1622 
   1623       for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
   1624          GLfloat alpha = 2;
   1625          GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
   1626          GLfloat weight = (GLfloat) exp(-alpha * r2);
   1627          weightLut[i] = weight;
   1628       }
   1629    }
   1630 }
   1631 
   1632 
   1633 /**
   1634  * Elliptical weighted average (EWA) filter for producing high quality
   1635  * anisotropic filtered results.
   1636  * Based on the Higher Quality Elliptical Weighted Avarage Filter
   1637  * published by Paul S. Heckbert in his Master's Thesis
   1638  * "Fundamentals of Texture Mapping and Image Warping" (1989)
   1639  */
   1640 static void
   1641 sample_2d_ewa(struct gl_context *ctx,
   1642               const struct gl_sampler_object *samp,
   1643               const struct gl_texture_object *tObj,
   1644               const GLfloat texcoord[4],
   1645               const GLfloat dudx, const GLfloat dvdx,
   1646               const GLfloat dudy, const GLfloat dvdy, const GLint lod,
   1647               GLfloat rgba[])
   1648 {
   1649    GLint level = lod > 0 ? lod : 0;
   1650    GLfloat scaling = 1.0 / (1 << level);
   1651    const struct gl_texture_image *img =	tObj->Image[0][level];
   1652    const struct gl_texture_image *mostDetailedImage =
   1653       tObj->Image[0][tObj->BaseLevel];
   1654    const struct swrast_texture_image *swImg =
   1655       swrast_texture_image_const(mostDetailedImage);
   1656    GLfloat tex_u=-0.5 + texcoord[0] * swImg->WidthScale * scaling;
   1657    GLfloat tex_v=-0.5 + texcoord[1] * swImg->HeightScale * scaling;
   1658 
   1659    GLfloat ux = dudx * scaling;
   1660    GLfloat vx = dvdx * scaling;
   1661    GLfloat uy = dudy * scaling;
   1662    GLfloat vy = dvdy * scaling;
   1663 
   1664    /* compute ellipse coefficients to bound the region:
   1665     * A*x*x + B*x*y + C*y*y = F.
   1666     */
   1667    GLfloat A = vx*vx+vy*vy+1;
   1668    GLfloat B = -2*(ux*vx+uy*vy);
   1669    GLfloat C = ux*ux+uy*uy+1;
   1670    GLfloat F = A*C-B*B/4.0;
   1671 
   1672    /* check if it is an ellipse */
   1673    /* ASSERT(F > 0.0); */
   1674 
   1675    /* Compute the ellipse's (u,v) bounding box in texture space */
   1676    GLfloat d = -B*B+4.0*C*A;
   1677    GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with   */
   1678    GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */
   1679 
   1680    GLint u0 = floor(tex_u - box_u);
   1681    GLint u1 = ceil (tex_u + box_u);
   1682    GLint v0 = floor(tex_v - box_v);
   1683    GLint v1 = ceil (tex_v + box_v);
   1684 
   1685    GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
   1686    GLfloat newCoord[2];
   1687    GLfloat den = 0.0F;
   1688    GLfloat ddq;
   1689    GLfloat U = u0 - tex_u;
   1690    GLint v;
   1691 
   1692    /* Scale ellipse formula to directly index the Filter Lookup Table.
   1693     * i.e. scale so that F = WEIGHT_LUT_SIZE-1
   1694     */
   1695    double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F;
   1696    A *= formScale;
   1697    B *= formScale;
   1698    C *= formScale;
   1699    /* F *= formScale; */ /* no need to scale F as we don't use it below here */
   1700 
   1701    /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
   1702     * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
   1703     * value, q, is less than F, we're inside the ellipse
   1704     */
   1705    ddq = 2 * A;
   1706    for (v = v0; v <= v1; ++v) {
   1707       GLfloat V = v - tex_v;
   1708       GLfloat dq = A * (2 * U + 1) + B * V;
   1709       GLfloat q = (C * V + B * U) * V + A * U * U;
   1710 
   1711       GLint u;
   1712       for (u = u0; u <= u1; ++u) {
   1713          /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
   1714          if (q < WEIGHT_LUT_SIZE) {
   1715             /* as a LUT is used, q must never be negative;
   1716              * should not happen, though
   1717              */
   1718             const GLint qClamped = q >= 0.0F ? q : 0;
   1719             GLfloat weight = weightLut[qClamped];
   1720 
   1721             newCoord[0] = u / ((GLfloat) img->Width2);
   1722             newCoord[1] = v / ((GLfloat) img->Height2);
   1723 
   1724             sample_2d_nearest(ctx, samp, img, newCoord, rgba);
   1725             num[0] += weight * rgba[0];
   1726             num[1] += weight * rgba[1];
   1727             num[2] += weight * rgba[2];
   1728             num[3] += weight * rgba[3];
   1729 
   1730             den += weight;
   1731          }
   1732          q += dq;
   1733          dq += ddq;
   1734       }
   1735    }
   1736 
   1737    if (den <= 0.0F) {
   1738       /* Reaching this place would mean
   1739        * that no pixels intersected the ellipse.
   1740        * This should never happen because
   1741        * the filter we use always
   1742        * intersects at least one pixel.
   1743        */
   1744 
   1745       /*rgba[0]=0;
   1746       rgba[1]=0;
   1747       rgba[2]=0;
   1748       rgba[3]=0;*/
   1749       /* not enough pixels in resampling, resort to direct interpolation */
   1750       sample_2d_linear(ctx, samp, img, texcoord, rgba);
   1751       return;
   1752    }
   1753 
   1754    rgba[0] = num[0] / den;
   1755    rgba[1] = num[1] / den;
   1756    rgba[2] = num[2] / den;
   1757    rgba[3] = num[3] / den;
   1758 }
   1759 
   1760 
   1761 /**
   1762  * Anisotropic filtering using footprint assembly as outlined in the
   1763  * EXT_texture_filter_anisotropic spec:
   1764  * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
   1765  * Faster than EWA but has less quality (more aliasing effects)
   1766  */
   1767 static void
   1768 sample_2d_footprint(struct gl_context *ctx,
   1769                  const struct gl_sampler_object *samp,
   1770                  const struct gl_texture_object *tObj,
   1771                  const GLfloat texcoord[4],
   1772                  const GLfloat dudx, const GLfloat dvdx,
   1773                  const GLfloat dudy, const GLfloat dvdy, const GLint lod,
   1774                  GLfloat rgba[])
   1775 {
   1776    GLint level = lod > 0 ? lod : 0;
   1777    GLfloat scaling = 1.0F / (1 << level);
   1778    const struct gl_texture_image *img = tObj->Image[0][level];
   1779 
   1780    GLfloat ux = dudx * scaling;
   1781    GLfloat vx = dvdx * scaling;
   1782    GLfloat uy = dudy * scaling;
   1783    GLfloat vy = dvdy * scaling;
   1784 
   1785    GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
   1786    GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
   1787 
   1788    GLint numSamples;
   1789    GLfloat ds;
   1790    GLfloat dt;
   1791 
   1792    GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
   1793    GLfloat newCoord[2];
   1794    GLint s;
   1795 
   1796    /*  Calculate the per anisotropic sample offsets in s,t space. */
   1797    if (Px2 > Py2) {
   1798       numSamples = ceil(SQRTF(Px2));
   1799       ds = ux / ((GLfloat) img->Width2);
   1800       dt = vx / ((GLfloat) img->Height2);
   1801    }
   1802    else {
   1803       numSamples = ceil(SQRTF(Py2));
   1804       ds = uy / ((GLfloat) img->Width2);
   1805       dt = vy / ((GLfloat) img->Height2);
   1806    }
   1807 
   1808    for (s = 0; s<numSamples; s++) {
   1809       newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5);
   1810       newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5);
   1811 
   1812       sample_2d_linear(ctx, samp, img, newCoord, rgba);
   1813       num[0] += rgba[0];
   1814       num[1] += rgba[1];
   1815       num[2] += rgba[2];
   1816       num[3] += rgba[3];
   1817    }
   1818 
   1819    rgba[0] = num[0] / numSamples;
   1820    rgba[1] = num[1] / numSamples;
   1821    rgba[2] = num[2] / numSamples;
   1822    rgba[3] = num[3] / numSamples;
   1823 }
   1824 
   1825 
   1826 /**
   1827  * Returns the index of the specified texture object in the
   1828  * gl_context texture unit array.
   1829  */
   1830 static inline GLuint
   1831 texture_unit_index(const struct gl_context *ctx,
   1832                    const struct gl_texture_object *tObj)
   1833 {
   1834    const GLuint maxUnit
   1835       = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
   1836    GLuint u;
   1837 
   1838    /* XXX CoordUnits vs. ImageUnits */
   1839    for (u = 0; u < maxUnit; u++) {
   1840       if (ctx->Texture.Unit[u]._Current == tObj)
   1841          break; /* found */
   1842    }
   1843    if (u >= maxUnit)
   1844       u = 0; /* not found, use 1st one; should never happen */
   1845 
   1846    return u;
   1847 }
   1848 
   1849 
   1850 /**
   1851  * Sample 2D texture using an anisotropic filter.
   1852  * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
   1853  * the lambda float array but a "hidden" SWspan struct which is required
   1854  * by this function but is not available in the texture_sample_func signature.
   1855  * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
   1856  * this function is called.
   1857  */
   1858 static void
   1859 sample_lambda_2d_aniso(struct gl_context *ctx,
   1860                        const struct gl_sampler_object *samp,
   1861                        const struct gl_texture_object *tObj,
   1862                        GLuint n, const GLfloat texcoords[][4],
   1863                        const GLfloat lambda_iso[], GLfloat rgba[][4])
   1864 {
   1865    const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
   1866    const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
   1867    const GLfloat maxEccentricity =
   1868       samp->MaxAnisotropy * samp->MaxAnisotropy;
   1869 
   1870    /* re-calculate the lambda values so that they are usable with anisotropic
   1871     * filtering
   1872     */
   1873    SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
   1874 
   1875    /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
   1876     * in swrast/s_span.c
   1877     */
   1878 
   1879    /* find the texture unit index by looking up the current texture object
   1880     * from the context list of available texture objects.
   1881     */
   1882    const GLuint u = texture_unit_index(ctx, tObj);
   1883    const GLuint attr = FRAG_ATTRIB_TEX0 + u;
   1884    GLfloat texW, texH;
   1885 
   1886    const GLfloat dsdx = span->attrStepX[attr][0];
   1887    const GLfloat dsdy = span->attrStepY[attr][0];
   1888    const GLfloat dtdx = span->attrStepX[attr][1];
   1889    const GLfloat dtdy = span->attrStepY[attr][1];
   1890    const GLfloat dqdx = span->attrStepX[attr][3];
   1891    const GLfloat dqdy = span->attrStepY[attr][3];
   1892    GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
   1893    GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
   1894    GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
   1895 
   1896    /* from swrast/s_texcombine.c _swrast_texture_span */
   1897    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
   1898    const GLboolean adjustLOD =
   1899       (texUnit->LodBias + samp->LodBias != 0.0F)
   1900       || (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0);
   1901 
   1902    GLuint i;
   1903 
   1904    /* on first access create the lookup table containing the filter weights. */
   1905    if (!weightLut) {
   1906       create_filter_table();
   1907    }
   1908 
   1909    texW = swImg->WidthScale;
   1910    texH = swImg->HeightScale;
   1911 
   1912    for (i = 0; i < n; i++) {
   1913       const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
   1914 
   1915       GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
   1916       GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
   1917       GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
   1918       GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
   1919 
   1920       /* note: instead of working with Px and Py, we will use the
   1921        * squared length instead, to avoid sqrt.
   1922        */
   1923       GLfloat Px2 = dudx * dudx + dvdx * dvdx;
   1924       GLfloat Py2 = dudy * dudy + dvdy * dvdy;
   1925 
   1926       GLfloat Pmax2;
   1927       GLfloat Pmin2;
   1928       GLfloat e;
   1929       GLfloat lod;
   1930 
   1931       s += dsdx;
   1932       t += dtdx;
   1933       q += dqdx;
   1934 
   1935       if (Px2 < Py2) {
   1936          Pmax2 = Py2;
   1937          Pmin2 = Px2;
   1938       }
   1939       else {
   1940          Pmax2 = Px2;
   1941          Pmin2 = Py2;
   1942       }
   1943 
   1944       /* if the eccentricity of the ellipse is too big, scale up the shorter
   1945        * of the two vectors to limit the maximum amount of work per pixel
   1946        */
   1947       e = Pmax2 / Pmin2;
   1948       if (e > maxEccentricity) {
   1949          /* GLfloat s=e / maxEccentricity;
   1950             minor[0] *= s;
   1951             minor[1] *= s;
   1952             Pmin2 *= s; */
   1953          Pmin2 = Pmax2 / maxEccentricity;
   1954       }
   1955 
   1956       /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
   1957        * this since 0.5*log(x) = log(sqrt(x))
   1958        */
   1959       lod = 0.5 * LOG2(Pmin2);
   1960 
   1961       if (adjustLOD) {
   1962          /* from swrast/s_texcombine.c _swrast_texture_span */
   1963          if (texUnit->LodBias + samp->LodBias != 0.0F) {
   1964             /* apply LOD bias, but don't clamp yet */
   1965             const GLfloat bias =
   1966                CLAMP(texUnit->LodBias + samp->LodBias,
   1967                      -ctx->Const.MaxTextureLodBias,
   1968                      ctx->Const.MaxTextureLodBias);
   1969             lod += bias;
   1970 
   1971             if (samp->MinLod != -1000.0 ||
   1972                 samp->MaxLod != 1000.0) {
   1973                /* apply LOD clamping to lambda */
   1974                lod = CLAMP(lod, samp->MinLod, samp->MaxLod);
   1975             }
   1976          }
   1977       }
   1978 
   1979       /* If the ellipse covers the whole image, we can
   1980        * simply return the average of the whole image.
   1981        */
   1982       if (lod >= tObj->_MaxLevel) {
   1983          sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   1984                           texcoords[i], rgba[i]);
   1985       }
   1986       else {
   1987          /* don't bother interpolating between multiple LODs; it doesn't
   1988           * seem to be worth the extra running time.
   1989           */
   1990          sample_2d_ewa(ctx, samp, tObj, texcoords[i],
   1991                        dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
   1992 
   1993          /* unused: */
   1994          (void) sample_2d_footprint;
   1995          /*
   1996          sample_2d_footprint(ctx, tObj, texcoords[i],
   1997                              dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
   1998          */
   1999       }
   2000    }
   2001 }
   2002 
   2003 
   2004 
   2005 /**********************************************************************/
   2006 /*                    3-D Texture Sampling Functions                  */
   2007 /**********************************************************************/
   2008 
   2009 /**
   2010  * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
   2011  */
   2012 static inline void
   2013 sample_3d_nearest(struct gl_context *ctx,
   2014                   const struct gl_sampler_object *samp,
   2015                   const struct gl_texture_image *img,
   2016                   const GLfloat texcoord[4],
   2017                   GLfloat rgba[4])
   2018 {
   2019    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2020    const GLint width = img->Width2;     /* without border, power of two */
   2021    const GLint height = img->Height2;   /* without border, power of two */
   2022    const GLint depth = img->Depth2;     /* without border, power of two */
   2023    GLint i, j, k;
   2024    (void) ctx;
   2025 
   2026    i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
   2027    j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
   2028    k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]);
   2029 
   2030    if (i < 0 || i >= (GLint) img->Width ||
   2031        j < 0 || j >= (GLint) img->Height ||
   2032        k < 0 || k >= (GLint) img->Depth) {
   2033       /* Need this test for GL_CLAMP_TO_BORDER mode */
   2034       get_border_color(samp, img, rgba);
   2035    }
   2036    else {
   2037       swImg->FetchTexel(swImg, i, j, k, rgba);
   2038    }
   2039 }
   2040 
   2041 
   2042 /**
   2043  * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
   2044  */
   2045 static void
   2046 sample_3d_linear(struct gl_context *ctx,
   2047                  const struct gl_sampler_object *samp,
   2048                  const struct gl_texture_image *img,
   2049                  const GLfloat texcoord[4],
   2050                  GLfloat rgba[4])
   2051 {
   2052    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2053    const GLint width = img->Width2;
   2054    const GLint height = img->Height2;
   2055    const GLint depth = img->Depth2;
   2056    GLint i0, j0, k0, i1, j1, k1;
   2057    GLbitfield useBorderColor = 0x0;
   2058    GLfloat a, b, c;
   2059    GLfloat t000[4], t010[4], t001[4], t011[4];
   2060    GLfloat t100[4], t110[4], t101[4], t111[4];
   2061 
   2062    linear_texel_locations(samp->WrapS, img, width, texcoord[0],  &i0, &i1, &a);
   2063    linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
   2064    linear_texel_locations(samp->WrapR, img, depth, texcoord[2],  &k0, &k1, &c);
   2065 
   2066    if (img->Border) {
   2067       i0 += img->Border;
   2068       i1 += img->Border;
   2069       j0 += img->Border;
   2070       j1 += img->Border;
   2071       k0 += img->Border;
   2072       k1 += img->Border;
   2073    }
   2074    else {
   2075       /* check if sampling texture border color */
   2076       if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
   2077       if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
   2078       if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
   2079       if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
   2080       if (k0 < 0 || k0 >= depth)   useBorderColor |= K0BIT;
   2081       if (k1 < 0 || k1 >= depth)   useBorderColor |= K1BIT;
   2082    }
   2083 
   2084    /* Fetch texels */
   2085    if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
   2086       get_border_color(samp, img, t000);
   2087    }
   2088    else {
   2089       swImg->FetchTexel(swImg, i0, j0, k0, t000);
   2090    }
   2091    if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
   2092       get_border_color(samp, img, t100);
   2093    }
   2094    else {
   2095       swImg->FetchTexel(swImg, i1, j0, k0, t100);
   2096    }
   2097    if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
   2098       get_border_color(samp, img, t010);
   2099    }
   2100    else {
   2101       swImg->FetchTexel(swImg, i0, j1, k0, t010);
   2102    }
   2103    if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
   2104       get_border_color(samp, img, t110);
   2105    }
   2106    else {
   2107       swImg->FetchTexel(swImg, i1, j1, k0, t110);
   2108    }
   2109 
   2110    if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
   2111       get_border_color(samp, img, t001);
   2112    }
   2113    else {
   2114       swImg->FetchTexel(swImg, i0, j0, k1, t001);
   2115    }
   2116    if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
   2117       get_border_color(samp, img, t101);
   2118    }
   2119    else {
   2120       swImg->FetchTexel(swImg, i1, j0, k1, t101);
   2121    }
   2122    if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
   2123       get_border_color(samp, img, t011);
   2124    }
   2125    else {
   2126       swImg->FetchTexel(swImg, i0, j1, k1, t011);
   2127    }
   2128    if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
   2129       get_border_color(samp, img, t111);
   2130    }
   2131    else {
   2132       swImg->FetchTexel(swImg, i1, j1, k1, t111);
   2133    }
   2134 
   2135    /* trilinear interpolation of samples */
   2136    lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
   2137 }
   2138 
   2139 
   2140 static void
   2141 sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
   2142                                  const struct gl_sampler_object *samp,
   2143                                  const struct gl_texture_object *tObj,
   2144                                  GLuint n, const GLfloat texcoord[][4],
   2145                                  const GLfloat lambda[], GLfloat rgba[][4] )
   2146 {
   2147    GLuint i;
   2148    for (i = 0; i < n; i++) {
   2149       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   2150       sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
   2151    }
   2152 }
   2153 
   2154 
   2155 static void
   2156 sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
   2157                                 const struct gl_sampler_object *samp,
   2158                                 const struct gl_texture_object *tObj,
   2159                                 GLuint n, const GLfloat texcoord[][4],
   2160                                 const GLfloat lambda[], GLfloat rgba[][4])
   2161 {
   2162    GLuint i;
   2163    ASSERT(lambda != NULL);
   2164    for (i = 0; i < n; i++) {
   2165       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   2166       sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
   2167    }
   2168 }
   2169 
   2170 
   2171 static void
   2172 sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
   2173                                 const struct gl_sampler_object *samp,
   2174                                 const struct gl_texture_object *tObj,
   2175                                 GLuint n, const GLfloat texcoord[][4],
   2176                                 const GLfloat lambda[], GLfloat rgba[][4])
   2177 {
   2178    GLuint i;
   2179    ASSERT(lambda != NULL);
   2180    for (i = 0; i < n; i++) {
   2181       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2182       if (level >= tObj->_MaxLevel) {
   2183          sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   2184                            texcoord[i], rgba[i]);
   2185       }
   2186       else {
   2187          GLfloat t0[4], t1[4];  /* texels */
   2188          const GLfloat f = FRAC(lambda[i]);
   2189          sample_3d_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   2190          sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   2191          lerp_rgba(rgba[i], f, t0, t1);
   2192       }
   2193    }
   2194 }
   2195 
   2196 
   2197 static void
   2198 sample_3d_linear_mipmap_linear(struct gl_context *ctx,
   2199                                const struct gl_sampler_object *samp,
   2200                                const struct gl_texture_object *tObj,
   2201                                GLuint n, const GLfloat texcoord[][4],
   2202                                const GLfloat lambda[], GLfloat rgba[][4])
   2203 {
   2204    GLuint i;
   2205    ASSERT(lambda != NULL);
   2206    for (i = 0; i < n; i++) {
   2207       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2208       if (level >= tObj->_MaxLevel) {
   2209          sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   2210                           texcoord[i], rgba[i]);
   2211       }
   2212       else {
   2213          GLfloat t0[4], t1[4];  /* texels */
   2214          const GLfloat f = FRAC(lambda[i]);
   2215          sample_3d_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   2216          sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   2217          lerp_rgba(rgba[i], f, t0, t1);
   2218       }
   2219    }
   2220 }
   2221 
   2222 
   2223 /** Sample 3D texture, nearest filtering for both min/magnification */
   2224 static void
   2225 sample_nearest_3d(struct gl_context *ctx,
   2226                   const struct gl_sampler_object *samp,
   2227                   const struct gl_texture_object *tObj, GLuint n,
   2228                   const GLfloat texcoords[][4], const GLfloat lambda[],
   2229                   GLfloat rgba[][4])
   2230 {
   2231    GLuint i;
   2232    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   2233    (void) lambda;
   2234    for (i = 0; i < n; i++) {
   2235       sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
   2236    }
   2237 }
   2238 
   2239 
   2240 /** Sample 3D texture, linear filtering for both min/magnification */
   2241 static void
   2242 sample_linear_3d(struct gl_context *ctx,
   2243                  const struct gl_sampler_object *samp,
   2244                  const struct gl_texture_object *tObj, GLuint n,
   2245                  const GLfloat texcoords[][4],
   2246 		 const GLfloat lambda[], GLfloat rgba[][4])
   2247 {
   2248    GLuint i;
   2249    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   2250    (void) lambda;
   2251    for (i = 0; i < n; i++) {
   2252       sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]);
   2253    }
   2254 }
   2255 
   2256 
   2257 /** Sample 3D texture, using lambda to choose between min/magnification */
   2258 static void
   2259 sample_lambda_3d(struct gl_context *ctx,
   2260                  const struct gl_sampler_object *samp,
   2261                  const struct gl_texture_object *tObj, GLuint n,
   2262                  const GLfloat texcoords[][4], const GLfloat lambda[],
   2263                  GLfloat rgba[][4])
   2264 {
   2265    GLuint minStart, minEnd;  /* texels with minification */
   2266    GLuint magStart, magEnd;  /* texels with magnification */
   2267    GLuint i;
   2268 
   2269    ASSERT(lambda != NULL);
   2270    compute_min_mag_ranges(samp, n, lambda,
   2271                           &minStart, &minEnd, &magStart, &magEnd);
   2272 
   2273    if (minStart < minEnd) {
   2274       /* do the minified texels */
   2275       GLuint m = minEnd - minStart;
   2276       switch (samp->MinFilter) {
   2277       case GL_NEAREST:
   2278          for (i = minStart; i < minEnd; i++)
   2279             sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   2280                               texcoords[i], rgba[i]);
   2281          break;
   2282       case GL_LINEAR:
   2283          for (i = minStart; i < minEnd; i++)
   2284             sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   2285                              texcoords[i], rgba[i]);
   2286          break;
   2287       case GL_NEAREST_MIPMAP_NEAREST:
   2288          sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   2289                                           lambda + minStart, rgba + minStart);
   2290          break;
   2291       case GL_LINEAR_MIPMAP_NEAREST:
   2292          sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   2293                                          lambda + minStart, rgba + minStart);
   2294          break;
   2295       case GL_NEAREST_MIPMAP_LINEAR:
   2296          sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   2297                                          lambda + minStart, rgba + minStart);
   2298          break;
   2299       case GL_LINEAR_MIPMAP_LINEAR:
   2300          sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   2301                                         lambda + minStart, rgba + minStart);
   2302          break;
   2303       default:
   2304          _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
   2305          return;
   2306       }
   2307    }
   2308 
   2309    if (magStart < magEnd) {
   2310       /* do the magnified texels */
   2311       switch (samp->MagFilter) {
   2312       case GL_NEAREST:
   2313          for (i = magStart; i < magEnd; i++)
   2314             sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   2315                               texcoords[i], rgba[i]);
   2316          break;
   2317       case GL_LINEAR:
   2318          for (i = magStart; i < magEnd; i++)
   2319             sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   2320                              texcoords[i], rgba[i]);
   2321          break;
   2322       default:
   2323          _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
   2324          return;
   2325       }
   2326    }
   2327 }
   2328 
   2329 
   2330 /**********************************************************************/
   2331 /*                Texture Cube Map Sampling Functions                 */
   2332 /**********************************************************************/
   2333 
   2334 /**
   2335  * Choose one of six sides of a texture cube map given the texture
   2336  * coord (rx,ry,rz).  Return pointer to corresponding array of texture
   2337  * images.
   2338  */
   2339 static const struct gl_texture_image **
   2340 choose_cube_face(const struct gl_texture_object *texObj,
   2341                  const GLfloat texcoord[4], GLfloat newCoord[4])
   2342 {
   2343    /*
   2344       major axis
   2345       direction     target                             sc     tc    ma
   2346       ----------    -------------------------------    ---    ---   ---
   2347        +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
   2348        -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
   2349        +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
   2350        -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
   2351        +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
   2352        -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
   2353    */
   2354    const GLfloat rx = texcoord[0];
   2355    const GLfloat ry = texcoord[1];
   2356    const GLfloat rz = texcoord[2];
   2357    const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
   2358    GLuint face;
   2359    GLfloat sc, tc, ma;
   2360 
   2361    if (arx >= ary && arx >= arz) {
   2362       if (rx >= 0.0F) {
   2363          face = FACE_POS_X;
   2364          sc = -rz;
   2365          tc = -ry;
   2366          ma = arx;
   2367       }
   2368       else {
   2369          face = FACE_NEG_X;
   2370          sc = rz;
   2371          tc = -ry;
   2372          ma = arx;
   2373       }
   2374    }
   2375    else if (ary >= arx && ary >= arz) {
   2376       if (ry >= 0.0F) {
   2377          face = FACE_POS_Y;
   2378          sc = rx;
   2379          tc = rz;
   2380          ma = ary;
   2381       }
   2382       else {
   2383          face = FACE_NEG_Y;
   2384          sc = rx;
   2385          tc = -rz;
   2386          ma = ary;
   2387       }
   2388    }
   2389    else {
   2390       if (rz > 0.0F) {
   2391          face = FACE_POS_Z;
   2392          sc = rx;
   2393          tc = -ry;
   2394          ma = arz;
   2395       }
   2396       else {
   2397          face = FACE_NEG_Z;
   2398          sc = -rx;
   2399          tc = -ry;
   2400          ma = arz;
   2401       }
   2402    }
   2403 
   2404    {
   2405       const float ima = 1.0F / ma;
   2406       newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
   2407       newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
   2408    }
   2409 
   2410    return (const struct gl_texture_image **) texObj->Image[face];
   2411 }
   2412 
   2413 
   2414 static void
   2415 sample_nearest_cube(struct gl_context *ctx,
   2416                     const struct gl_sampler_object *samp,
   2417 		    const struct gl_texture_object *tObj, GLuint n,
   2418                     const GLfloat texcoords[][4], const GLfloat lambda[],
   2419                     GLfloat rgba[][4])
   2420 {
   2421    GLuint i;
   2422    (void) lambda;
   2423    for (i = 0; i < n; i++) {
   2424       const struct gl_texture_image **images;
   2425       GLfloat newCoord[4];
   2426       images = choose_cube_face(tObj, texcoords[i], newCoord);
   2427       sample_2d_nearest(ctx, samp, images[tObj->BaseLevel],
   2428                         newCoord, rgba[i]);
   2429    }
   2430    if (is_depth_texture(tObj)) {
   2431       for (i = 0; i < n; i++) {
   2432          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2433       }
   2434    }
   2435 }
   2436 
   2437 
   2438 static void
   2439 sample_linear_cube(struct gl_context *ctx,
   2440                    const struct gl_sampler_object *samp,
   2441 		   const struct gl_texture_object *tObj, GLuint n,
   2442                    const GLfloat texcoords[][4],
   2443 		   const GLfloat lambda[], GLfloat rgba[][4])
   2444 {
   2445    GLuint i;
   2446    (void) lambda;
   2447    for (i = 0; i < n; i++) {
   2448       const struct gl_texture_image **images;
   2449       GLfloat newCoord[4];
   2450       images = choose_cube_face(tObj, texcoords[i], newCoord);
   2451       sample_2d_linear(ctx, samp, images[tObj->BaseLevel],
   2452                        newCoord, rgba[i]);
   2453    }
   2454    if (is_depth_texture(tObj)) {
   2455       for (i = 0; i < n; i++) {
   2456          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2457       }
   2458    }
   2459 }
   2460 
   2461 
   2462 static void
   2463 sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
   2464                                    const struct gl_sampler_object *samp,
   2465                                    const struct gl_texture_object *tObj,
   2466                                    GLuint n, const GLfloat texcoord[][4],
   2467                                    const GLfloat lambda[], GLfloat rgba[][4])
   2468 {
   2469    GLuint i;
   2470    ASSERT(lambda != NULL);
   2471    for (i = 0; i < n; i++) {
   2472       const struct gl_texture_image **images;
   2473       GLfloat newCoord[4];
   2474       GLint level;
   2475       images = choose_cube_face(tObj, texcoord[i], newCoord);
   2476 
   2477       /* XXX we actually need to recompute lambda here based on the newCoords.
   2478        * But we would need the texcoords of adjacent fragments to compute that
   2479        * properly, and we don't have those here.
   2480        * For now, do an approximation:  subtracting 1 from the chosen mipmap
   2481        * level seems to work in some test cases.
   2482        * The same adjustment is done in the next few functions.
   2483       */
   2484       level = nearest_mipmap_level(tObj, lambda[i]);
   2485       level = MAX2(level - 1, 0);
   2486 
   2487       sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]);
   2488    }
   2489    if (is_depth_texture(tObj)) {
   2490       for (i = 0; i < n; i++) {
   2491          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2492       }
   2493    }
   2494 }
   2495 
   2496 
   2497 static void
   2498 sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
   2499                                   const struct gl_sampler_object *samp,
   2500                                   const struct gl_texture_object *tObj,
   2501                                   GLuint n, const GLfloat texcoord[][4],
   2502                                   const GLfloat lambda[], GLfloat rgba[][4])
   2503 {
   2504    GLuint i;
   2505    ASSERT(lambda != NULL);
   2506    for (i = 0; i < n; i++) {
   2507       const struct gl_texture_image **images;
   2508       GLfloat newCoord[4];
   2509       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   2510       level = MAX2(level - 1, 0); /* see comment above */
   2511       images = choose_cube_face(tObj, texcoord[i], newCoord);
   2512       sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]);
   2513    }
   2514    if (is_depth_texture(tObj)) {
   2515       for (i = 0; i < n; i++) {
   2516          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2517       }
   2518    }
   2519 }
   2520 
   2521 
   2522 static void
   2523 sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
   2524                                   const struct gl_sampler_object *samp,
   2525                                   const struct gl_texture_object *tObj,
   2526                                   GLuint n, const GLfloat texcoord[][4],
   2527                                   const GLfloat lambda[], GLfloat rgba[][4])
   2528 {
   2529    GLuint i;
   2530    ASSERT(lambda != NULL);
   2531    for (i = 0; i < n; i++) {
   2532       const struct gl_texture_image **images;
   2533       GLfloat newCoord[4];
   2534       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2535       level = MAX2(level - 1, 0); /* see comment above */
   2536       images = choose_cube_face(tObj, texcoord[i], newCoord);
   2537       if (level >= tObj->_MaxLevel) {
   2538          sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel],
   2539                            newCoord, rgba[i]);
   2540       }
   2541       else {
   2542          GLfloat t0[4], t1[4];  /* texels */
   2543          const GLfloat f = FRAC(lambda[i]);
   2544          sample_2d_nearest(ctx, samp, images[level  ], newCoord, t0);
   2545          sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1);
   2546          lerp_rgba(rgba[i], f, t0, t1);
   2547       }
   2548    }
   2549    if (is_depth_texture(tObj)) {
   2550       for (i = 0; i < n; i++) {
   2551          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2552       }
   2553    }
   2554 }
   2555 
   2556 
   2557 static void
   2558 sample_cube_linear_mipmap_linear(struct gl_context *ctx,
   2559                                  const struct gl_sampler_object *samp,
   2560                                  const struct gl_texture_object *tObj,
   2561                                  GLuint n, const GLfloat texcoord[][4],
   2562                                  const GLfloat lambda[], GLfloat rgba[][4])
   2563 {
   2564    GLuint i;
   2565    ASSERT(lambda != NULL);
   2566    for (i = 0; i < n; i++) {
   2567       const struct gl_texture_image **images;
   2568       GLfloat newCoord[4];
   2569       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2570       level = MAX2(level - 1, 0); /* see comment above */
   2571       images = choose_cube_face(tObj, texcoord[i], newCoord);
   2572       if (level >= tObj->_MaxLevel) {
   2573          sample_2d_linear(ctx, samp, images[tObj->_MaxLevel],
   2574                           newCoord, rgba[i]);
   2575       }
   2576       else {
   2577          GLfloat t0[4], t1[4];
   2578          const GLfloat f = FRAC(lambda[i]);
   2579          sample_2d_linear(ctx, samp, images[level  ], newCoord, t0);
   2580          sample_2d_linear(ctx, samp, images[level+1], newCoord, t1);
   2581          lerp_rgba(rgba[i], f, t0, t1);
   2582       }
   2583    }
   2584    if (is_depth_texture(tObj)) {
   2585       for (i = 0; i < n; i++) {
   2586          apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
   2587       }
   2588    }
   2589 }
   2590 
   2591 
   2592 /** Sample cube texture, using lambda to choose between min/magnification */
   2593 static void
   2594 sample_lambda_cube(struct gl_context *ctx,
   2595                    const struct gl_sampler_object *samp,
   2596 		   const struct gl_texture_object *tObj, GLuint n,
   2597 		   const GLfloat texcoords[][4], const GLfloat lambda[],
   2598 		   GLfloat rgba[][4])
   2599 {
   2600    GLuint minStart, minEnd;  /* texels with minification */
   2601    GLuint magStart, magEnd;  /* texels with magnification */
   2602 
   2603    ASSERT(lambda != NULL);
   2604    compute_min_mag_ranges(samp, n, lambda,
   2605                           &minStart, &minEnd, &magStart, &magEnd);
   2606 
   2607    if (minStart < minEnd) {
   2608       /* do the minified texels */
   2609       const GLuint m = minEnd - minStart;
   2610       switch (samp->MinFilter) {
   2611       case GL_NEAREST:
   2612          sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart,
   2613                              lambda + minStart, rgba + minStart);
   2614          break;
   2615       case GL_LINEAR:
   2616          sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart,
   2617                             lambda + minStart, rgba + minStart);
   2618          break;
   2619       case GL_NEAREST_MIPMAP_NEAREST:
   2620          sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m,
   2621                                             texcoords + minStart,
   2622                                            lambda + minStart, rgba + minStart);
   2623          break;
   2624       case GL_LINEAR_MIPMAP_NEAREST:
   2625          sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m,
   2626                                            texcoords + minStart,
   2627                                            lambda + minStart, rgba + minStart);
   2628          break;
   2629       case GL_NEAREST_MIPMAP_LINEAR:
   2630          sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m,
   2631                                            texcoords + minStart,
   2632                                            lambda + minStart, rgba + minStart);
   2633          break;
   2634       case GL_LINEAR_MIPMAP_LINEAR:
   2635          sample_cube_linear_mipmap_linear(ctx, samp, tObj, m,
   2636                                           texcoords + minStart,
   2637                                           lambda + minStart, rgba + minStart);
   2638          break;
   2639       default:
   2640          _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
   2641          break;
   2642       }
   2643    }
   2644 
   2645    if (magStart < magEnd) {
   2646       /* do the magnified texels */
   2647       const GLuint m = magEnd - magStart;
   2648       switch (samp->MagFilter) {
   2649       case GL_NEAREST:
   2650          sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart,
   2651                              lambda + magStart, rgba + magStart);
   2652          break;
   2653       case GL_LINEAR:
   2654          sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart,
   2655                             lambda + magStart, rgba + magStart);
   2656          break;
   2657       default:
   2658          _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
   2659          break;
   2660       }
   2661    }
   2662 }
   2663 
   2664 
   2665 /**********************************************************************/
   2666 /*               Texture Rectangle Sampling Functions                 */
   2667 /**********************************************************************/
   2668 
   2669 
   2670 static void
   2671 sample_nearest_rect(struct gl_context *ctx,
   2672                     const struct gl_sampler_object *samp,
   2673 		    const struct gl_texture_object *tObj, GLuint n,
   2674                     const GLfloat texcoords[][4], const GLfloat lambda[],
   2675                     GLfloat rgba[][4])
   2676 {
   2677    const struct gl_texture_image *img = tObj->Image[0][0];
   2678    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2679    const GLint width = img->Width;
   2680    const GLint height = img->Height;
   2681    GLuint i;
   2682 
   2683    (void) ctx;
   2684    (void) lambda;
   2685 
   2686    ASSERT(samp->WrapS == GL_CLAMP ||
   2687           samp->WrapS == GL_CLAMP_TO_EDGE ||
   2688           samp->WrapS == GL_CLAMP_TO_BORDER);
   2689    ASSERT(samp->WrapT == GL_CLAMP ||
   2690           samp->WrapT == GL_CLAMP_TO_EDGE ||
   2691           samp->WrapT == GL_CLAMP_TO_BORDER);
   2692 
   2693    for (i = 0; i < n; i++) {
   2694       GLint row, col;
   2695       col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width);
   2696       row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height);
   2697       if (col < 0 || col >= width || row < 0 || row >= height)
   2698          get_border_color(samp, img, rgba[i]);
   2699       else
   2700          swImg->FetchTexel(swImg, col, row, 0, rgba[i]);
   2701    }
   2702 }
   2703 
   2704 
   2705 static void
   2706 sample_linear_rect(struct gl_context *ctx,
   2707                    const struct gl_sampler_object *samp,
   2708 		   const struct gl_texture_object *tObj, GLuint n,
   2709                    const GLfloat texcoords[][4],
   2710 		   const GLfloat lambda[], GLfloat rgba[][4])
   2711 {
   2712    const struct gl_texture_image *img = tObj->Image[0][0];
   2713    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2714    const GLint width = img->Width;
   2715    const GLint height = img->Height;
   2716    GLuint i;
   2717 
   2718    (void) ctx;
   2719    (void) lambda;
   2720 
   2721    ASSERT(samp->WrapS == GL_CLAMP ||
   2722           samp->WrapS == GL_CLAMP_TO_EDGE ||
   2723           samp->WrapS == GL_CLAMP_TO_BORDER);
   2724    ASSERT(samp->WrapT == GL_CLAMP ||
   2725           samp->WrapT == GL_CLAMP_TO_EDGE ||
   2726           samp->WrapT == GL_CLAMP_TO_BORDER);
   2727 
   2728    for (i = 0; i < n; i++) {
   2729       GLint i0, j0, i1, j1;
   2730       GLfloat t00[4], t01[4], t10[4], t11[4];
   2731       GLfloat a, b;
   2732       GLbitfield useBorderColor = 0x0;
   2733 
   2734       clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width,
   2735                               &i0, &i1, &a);
   2736       clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height,
   2737                               &j0, &j1, &b);
   2738 
   2739       /* compute integer rows/columns */
   2740       if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
   2741       if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
   2742       if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
   2743       if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
   2744 
   2745       /* get four texel samples */
   2746       if (useBorderColor & (I0BIT | J0BIT))
   2747          get_border_color(samp, img, t00);
   2748       else
   2749          swImg->FetchTexel(swImg, i0, j0, 0, t00);
   2750 
   2751       if (useBorderColor & (I1BIT | J0BIT))
   2752          get_border_color(samp, img, t10);
   2753       else
   2754          swImg->FetchTexel(swImg, i1, j0, 0, t10);
   2755 
   2756       if (useBorderColor & (I0BIT | J1BIT))
   2757          get_border_color(samp, img, t01);
   2758       else
   2759          swImg->FetchTexel(swImg, i0, j1, 0, t01);
   2760 
   2761       if (useBorderColor & (I1BIT | J1BIT))
   2762          get_border_color(samp, img, t11);
   2763       else
   2764          swImg->FetchTexel(swImg, i1, j1, 0, t11);
   2765 
   2766       lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
   2767    }
   2768 }
   2769 
   2770 
   2771 /** Sample Rect texture, using lambda to choose between min/magnification */
   2772 static void
   2773 sample_lambda_rect(struct gl_context *ctx,
   2774                    const struct gl_sampler_object *samp,
   2775 		   const struct gl_texture_object *tObj, GLuint n,
   2776 		   const GLfloat texcoords[][4], const GLfloat lambda[],
   2777 		   GLfloat rgba[][4])
   2778 {
   2779    GLuint minStart, minEnd, magStart, magEnd;
   2780 
   2781    /* We only need lambda to decide between minification and magnification.
   2782     * There is no mipmapping with rectangular textures.
   2783     */
   2784    compute_min_mag_ranges(samp, n, lambda,
   2785                           &minStart, &minEnd, &magStart, &magEnd);
   2786 
   2787    if (minStart < minEnd) {
   2788       if (samp->MinFilter == GL_NEAREST) {
   2789          sample_nearest_rect(ctx, samp, tObj, minEnd - minStart,
   2790                              texcoords + minStart, NULL, rgba + minStart);
   2791       }
   2792       else {
   2793          sample_linear_rect(ctx, samp, tObj, minEnd - minStart,
   2794                             texcoords + minStart, NULL, rgba + minStart);
   2795       }
   2796    }
   2797    if (magStart < magEnd) {
   2798       if (samp->MagFilter == GL_NEAREST) {
   2799          sample_nearest_rect(ctx, samp, tObj, magEnd - magStart,
   2800                              texcoords + magStart, NULL, rgba + magStart);
   2801       }
   2802       else {
   2803          sample_linear_rect(ctx, samp, tObj, magEnd - magStart,
   2804                             texcoords + magStart, NULL, rgba + magStart);
   2805       }
   2806    }
   2807 }
   2808 
   2809 
   2810 /**********************************************************************/
   2811 /*                2D Texture Array Sampling Functions                 */
   2812 /**********************************************************************/
   2813 
   2814 /**
   2815  * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
   2816  */
   2817 static void
   2818 sample_2d_array_nearest(struct gl_context *ctx,
   2819                         const struct gl_sampler_object *samp,
   2820                         const struct gl_texture_image *img,
   2821                         const GLfloat texcoord[4],
   2822                         GLfloat rgba[4])
   2823 {
   2824    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2825    const GLint width = img->Width2;     /* without border, power of two */
   2826    const GLint height = img->Height2;   /* without border, power of two */
   2827    const GLint depth = img->Depth;
   2828    GLint i, j;
   2829    GLint array;
   2830    (void) ctx;
   2831 
   2832    i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
   2833    j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
   2834    array = tex_array_slice(texcoord[2], depth);
   2835 
   2836    if (i < 0 || i >= (GLint) img->Width ||
   2837        j < 0 || j >= (GLint) img->Height ||
   2838        array < 0 || array >= (GLint) img->Depth) {
   2839       /* Need this test for GL_CLAMP_TO_BORDER mode */
   2840       get_border_color(samp, img, rgba);
   2841    }
   2842    else {
   2843       swImg->FetchTexel(swImg, i, j, array, rgba);
   2844    }
   2845 }
   2846 
   2847 
   2848 /**
   2849  * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
   2850  */
   2851 static void
   2852 sample_2d_array_linear(struct gl_context *ctx,
   2853                        const struct gl_sampler_object *samp,
   2854                        const struct gl_texture_image *img,
   2855                        const GLfloat texcoord[4],
   2856                        GLfloat rgba[4])
   2857 {
   2858    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   2859    const GLint width = img->Width2;
   2860    const GLint height = img->Height2;
   2861    const GLint depth = img->Depth;
   2862    GLint i0, j0, i1, j1;
   2863    GLint array;
   2864    GLbitfield useBorderColor = 0x0;
   2865    GLfloat a, b;
   2866    GLfloat t00[4], t01[4], t10[4], t11[4];
   2867 
   2868    linear_texel_locations(samp->WrapS, img, width,  texcoord[0], &i0, &i1, &a);
   2869    linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
   2870    array = tex_array_slice(texcoord[2], depth);
   2871 
   2872    if (array < 0 || array >= depth) {
   2873       COPY_4V(rgba, samp->BorderColor.f);
   2874    }
   2875    else {
   2876       if (img->Border) {
   2877 	 i0 += img->Border;
   2878 	 i1 += img->Border;
   2879 	 j0 += img->Border;
   2880 	 j1 += img->Border;
   2881       }
   2882       else {
   2883 	 /* check if sampling texture border color */
   2884 	 if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
   2885 	 if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
   2886 	 if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
   2887 	 if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
   2888       }
   2889 
   2890       /* Fetch texels */
   2891       if (useBorderColor & (I0BIT | J0BIT)) {
   2892          get_border_color(samp, img, t00);
   2893       }
   2894       else {
   2895 	 swImg->FetchTexel(swImg, i0, j0, array, t00);
   2896       }
   2897       if (useBorderColor & (I1BIT | J0BIT)) {
   2898          get_border_color(samp, img, t10);
   2899       }
   2900       else {
   2901 	 swImg->FetchTexel(swImg, i1, j0, array, t10);
   2902       }
   2903       if (useBorderColor & (I0BIT | J1BIT)) {
   2904          get_border_color(samp, img, t01);
   2905       }
   2906       else {
   2907 	 swImg->FetchTexel(swImg, i0, j1, array, t01);
   2908       }
   2909       if (useBorderColor & (I1BIT | J1BIT)) {
   2910          get_border_color(samp, img, t11);
   2911       }
   2912       else {
   2913 	 swImg->FetchTexel(swImg, i1, j1, array, t11);
   2914       }
   2915 
   2916       /* trilinear interpolation of samples */
   2917       lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
   2918    }
   2919 }
   2920 
   2921 
   2922 static void
   2923 sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx,
   2924                                        const struct gl_sampler_object *samp,
   2925                                        const struct gl_texture_object *tObj,
   2926                                        GLuint n, const GLfloat texcoord[][4],
   2927                                        const GLfloat lambda[], GLfloat rgba[][4])
   2928 {
   2929    GLuint i;
   2930    for (i = 0; i < n; i++) {
   2931       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   2932       sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
   2933                               rgba[i]);
   2934    }
   2935 }
   2936 
   2937 
   2938 static void
   2939 sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx,
   2940                                       const struct gl_sampler_object *samp,
   2941                                       const struct gl_texture_object *tObj,
   2942                                       GLuint n, const GLfloat texcoord[][4],
   2943                                       const GLfloat lambda[], GLfloat rgba[][4])
   2944 {
   2945    GLuint i;
   2946    ASSERT(lambda != NULL);
   2947    for (i = 0; i < n; i++) {
   2948       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   2949       sample_2d_array_linear(ctx, samp, tObj->Image[0][level],
   2950                              texcoord[i], rgba[i]);
   2951    }
   2952 }
   2953 
   2954 
   2955 static void
   2956 sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx,
   2957                                       const struct gl_sampler_object *samp,
   2958                                       const struct gl_texture_object *tObj,
   2959                                       GLuint n, const GLfloat texcoord[][4],
   2960                                       const GLfloat lambda[], GLfloat rgba[][4])
   2961 {
   2962    GLuint i;
   2963    ASSERT(lambda != NULL);
   2964    for (i = 0; i < n; i++) {
   2965       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2966       if (level >= tObj->_MaxLevel) {
   2967          sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   2968                                  texcoord[i], rgba[i]);
   2969       }
   2970       else {
   2971          GLfloat t0[4], t1[4];  /* texels */
   2972          const GLfloat f = FRAC(lambda[i]);
   2973          sample_2d_array_nearest(ctx, samp, tObj->Image[0][level  ],
   2974                                  texcoord[i], t0);
   2975          sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1],
   2976                                  texcoord[i], t1);
   2977          lerp_rgba(rgba[i], f, t0, t1);
   2978       }
   2979    }
   2980 }
   2981 
   2982 
   2983 static void
   2984 sample_2d_array_linear_mipmap_linear(struct gl_context *ctx,
   2985                                      const struct gl_sampler_object *samp,
   2986                                      const struct gl_texture_object *tObj,
   2987                                      GLuint n, const GLfloat texcoord[][4],
   2988                                      const GLfloat lambda[], GLfloat rgba[][4])
   2989 {
   2990    GLuint i;
   2991    ASSERT(lambda != NULL);
   2992    for (i = 0; i < n; i++) {
   2993       GLint level = linear_mipmap_level(tObj, lambda[i]);
   2994       if (level >= tObj->_MaxLevel) {
   2995          sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   2996                           texcoord[i], rgba[i]);
   2997       }
   2998       else {
   2999          GLfloat t0[4], t1[4];  /* texels */
   3000          const GLfloat f = FRAC(lambda[i]);
   3001          sample_2d_array_linear(ctx, samp, tObj->Image[0][level  ],
   3002                                 texcoord[i], t0);
   3003          sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1],
   3004                                 texcoord[i], t1);
   3005          lerp_rgba(rgba[i], f, t0, t1);
   3006       }
   3007    }
   3008 }
   3009 
   3010 
   3011 /** Sample 2D Array texture, nearest filtering for both min/magnification */
   3012 static void
   3013 sample_nearest_2d_array(struct gl_context *ctx,
   3014                         const struct gl_sampler_object *samp,
   3015                         const struct gl_texture_object *tObj, GLuint n,
   3016                         const GLfloat texcoords[][4], const GLfloat lambda[],
   3017                         GLfloat rgba[][4])
   3018 {
   3019    GLuint i;
   3020    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   3021    (void) lambda;
   3022    for (i = 0; i < n; i++) {
   3023       sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
   3024    }
   3025 }
   3026 
   3027 
   3028 
   3029 /** Sample 2D Array texture, linear filtering for both min/magnification */
   3030 static void
   3031 sample_linear_2d_array(struct gl_context *ctx,
   3032                        const struct gl_sampler_object *samp,
   3033                        const struct gl_texture_object *tObj, GLuint n,
   3034                        const GLfloat texcoords[][4],
   3035                        const GLfloat lambda[], GLfloat rgba[][4])
   3036 {
   3037    GLuint i;
   3038    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   3039    (void) lambda;
   3040    for (i = 0; i < n; i++) {
   3041       sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
   3042    }
   3043 }
   3044 
   3045 
   3046 /** Sample 2D Array texture, using lambda to choose between min/magnification */
   3047 static void
   3048 sample_lambda_2d_array(struct gl_context *ctx,
   3049                        const struct gl_sampler_object *samp,
   3050                        const struct gl_texture_object *tObj, GLuint n,
   3051                        const GLfloat texcoords[][4], const GLfloat lambda[],
   3052                        GLfloat rgba[][4])
   3053 {
   3054    GLuint minStart, minEnd;  /* texels with minification */
   3055    GLuint magStart, magEnd;  /* texels with magnification */
   3056    GLuint i;
   3057 
   3058    ASSERT(lambda != NULL);
   3059    compute_min_mag_ranges(samp, n, lambda,
   3060                           &minStart, &minEnd, &magStart, &magEnd);
   3061 
   3062    if (minStart < minEnd) {
   3063       /* do the minified texels */
   3064       GLuint m = minEnd - minStart;
   3065       switch (samp->MinFilter) {
   3066       case GL_NEAREST:
   3067          for (i = minStart; i < minEnd; i++)
   3068             sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3069                                     texcoords[i], rgba[i]);
   3070          break;
   3071       case GL_LINEAR:
   3072          for (i = minStart; i < minEnd; i++)
   3073             sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3074                                    texcoords[i], rgba[i]);
   3075          break;
   3076       case GL_NEAREST_MIPMAP_NEAREST:
   3077          sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m,
   3078                                                 texcoords + minStart,
   3079                                                 lambda + minStart,
   3080                                                 rgba + minStart);
   3081          break;
   3082       case GL_LINEAR_MIPMAP_NEAREST:
   3083          sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
   3084                                                texcoords + minStart,
   3085                                                lambda + minStart,
   3086                                                rgba + minStart);
   3087          break;
   3088       case GL_NEAREST_MIPMAP_LINEAR:
   3089          sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m,
   3090                                                texcoords + minStart,
   3091                                                lambda + minStart,
   3092                                                rgba + minStart);
   3093          break;
   3094       case GL_LINEAR_MIPMAP_LINEAR:
   3095          sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m,
   3096                                               texcoords + minStart,
   3097                                               lambda + minStart,
   3098                                               rgba + minStart);
   3099          break;
   3100       default:
   3101          _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
   3102          return;
   3103       }
   3104    }
   3105 
   3106    if (magStart < magEnd) {
   3107       /* do the magnified texels */
   3108       switch (samp->MagFilter) {
   3109       case GL_NEAREST:
   3110          for (i = magStart; i < magEnd; i++)
   3111             sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3112                               texcoords[i], rgba[i]);
   3113          break;
   3114       case GL_LINEAR:
   3115          for (i = magStart; i < magEnd; i++)
   3116             sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3117                                    texcoords[i], rgba[i]);
   3118          break;
   3119       default:
   3120          _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
   3121          return;
   3122       }
   3123    }
   3124 }
   3125 
   3126 
   3127 
   3128 
   3129 /**********************************************************************/
   3130 /*                1D Texture Array Sampling Functions                 */
   3131 /**********************************************************************/
   3132 
   3133 /**
   3134  * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
   3135  */
   3136 static void
   3137 sample_1d_array_nearest(struct gl_context *ctx,
   3138                         const struct gl_sampler_object *samp,
   3139                         const struct gl_texture_image *img,
   3140                         const GLfloat texcoord[4],
   3141                         GLfloat rgba[4])
   3142 {
   3143    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   3144    const GLint width = img->Width2;     /* without border, power of two */
   3145    const GLint height = img->Height;
   3146    GLint i;
   3147    GLint array;
   3148    (void) ctx;
   3149 
   3150    i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
   3151    array = tex_array_slice(texcoord[1], height);
   3152 
   3153    if (i < 0 || i >= (GLint) img->Width ||
   3154        array < 0 || array >= (GLint) img->Height) {
   3155       /* Need this test for GL_CLAMP_TO_BORDER mode */
   3156       get_border_color(samp, img, rgba);
   3157    }
   3158    else {
   3159       swImg->FetchTexel(swImg, i, array, 0, rgba);
   3160    }
   3161 }
   3162 
   3163 
   3164 /**
   3165  * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
   3166  */
   3167 static void
   3168 sample_1d_array_linear(struct gl_context *ctx,
   3169                        const struct gl_sampler_object *samp,
   3170                        const struct gl_texture_image *img,
   3171                        const GLfloat texcoord[4],
   3172                        GLfloat rgba[4])
   3173 {
   3174    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   3175    const GLint width = img->Width2;
   3176    const GLint height = img->Height;
   3177    GLint i0, i1;
   3178    GLint array;
   3179    GLbitfield useBorderColor = 0x0;
   3180    GLfloat a;
   3181    GLfloat t0[4], t1[4];
   3182 
   3183    linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
   3184    array = tex_array_slice(texcoord[1], height);
   3185 
   3186    if (img->Border) {
   3187       i0 += img->Border;
   3188       i1 += img->Border;
   3189    }
   3190    else {
   3191       /* check if sampling texture border color */
   3192       if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
   3193       if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
   3194    }
   3195 
   3196    if (array < 0 || array >= height)   useBorderColor |= K0BIT;
   3197 
   3198    /* Fetch texels */
   3199    if (useBorderColor & (I0BIT | K0BIT)) {
   3200       get_border_color(samp, img, t0);
   3201    }
   3202    else {
   3203       swImg->FetchTexel(swImg, i0, array, 0, t0);
   3204    }
   3205    if (useBorderColor & (I1BIT | K0BIT)) {
   3206       get_border_color(samp, img, t1);
   3207    }
   3208    else {
   3209       swImg->FetchTexel(swImg, i1, array, 0, t1);
   3210    }
   3211 
   3212    /* bilinear interpolation of samples */
   3213    lerp_rgba(rgba, a, t0, t1);
   3214 }
   3215 
   3216 
   3217 static void
   3218 sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx,
   3219                                        const struct gl_sampler_object *samp,
   3220                                        const struct gl_texture_object *tObj,
   3221                                        GLuint n, const GLfloat texcoord[][4],
   3222                                        const GLfloat lambda[], GLfloat rgba[][4])
   3223 {
   3224    GLuint i;
   3225    for (i = 0; i < n; i++) {
   3226       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   3227       sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
   3228                               rgba[i]);
   3229    }
   3230 }
   3231 
   3232 
   3233 static void
   3234 sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx,
   3235                                       const struct gl_sampler_object *samp,
   3236                                       const struct gl_texture_object *tObj,
   3237                                       GLuint n, const GLfloat texcoord[][4],
   3238                                       const GLfloat lambda[], GLfloat rgba[][4])
   3239 {
   3240    GLuint i;
   3241    ASSERT(lambda != NULL);
   3242    for (i = 0; i < n; i++) {
   3243       GLint level = nearest_mipmap_level(tObj, lambda[i]);
   3244       sample_1d_array_linear(ctx, samp, tObj->Image[0][level],
   3245                              texcoord[i], rgba[i]);
   3246    }
   3247 }
   3248 
   3249 
   3250 static void
   3251 sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx,
   3252                                       const struct gl_sampler_object *samp,
   3253                                       const struct gl_texture_object *tObj,
   3254                                       GLuint n, const GLfloat texcoord[][4],
   3255                                       const GLfloat lambda[], GLfloat rgba[][4])
   3256 {
   3257    GLuint i;
   3258    ASSERT(lambda != NULL);
   3259    for (i = 0; i < n; i++) {
   3260       GLint level = linear_mipmap_level(tObj, lambda[i]);
   3261       if (level >= tObj->_MaxLevel) {
   3262          sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   3263                                  texcoord[i], rgba[i]);
   3264       }
   3265       else {
   3266          GLfloat t0[4], t1[4];  /* texels */
   3267          const GLfloat f = FRAC(lambda[i]);
   3268          sample_1d_array_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   3269          sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   3270          lerp_rgba(rgba[i], f, t0, t1);
   3271       }
   3272    }
   3273 }
   3274 
   3275 
   3276 static void
   3277 sample_1d_array_linear_mipmap_linear(struct gl_context *ctx,
   3278                                      const struct gl_sampler_object *samp,
   3279                                      const struct gl_texture_object *tObj,
   3280                                      GLuint n, const GLfloat texcoord[][4],
   3281                                      const GLfloat lambda[], GLfloat rgba[][4])
   3282 {
   3283    GLuint i;
   3284    ASSERT(lambda != NULL);
   3285    for (i = 0; i < n; i++) {
   3286       GLint level = linear_mipmap_level(tObj, lambda[i]);
   3287       if (level >= tObj->_MaxLevel) {
   3288          sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
   3289                           texcoord[i], rgba[i]);
   3290       }
   3291       else {
   3292          GLfloat t0[4], t1[4];  /* texels */
   3293          const GLfloat f = FRAC(lambda[i]);
   3294          sample_1d_array_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
   3295          sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
   3296          lerp_rgba(rgba[i], f, t0, t1);
   3297       }
   3298    }
   3299 }
   3300 
   3301 
   3302 /** Sample 1D Array texture, nearest filtering for both min/magnification */
   3303 static void
   3304 sample_nearest_1d_array(struct gl_context *ctx,
   3305                         const struct gl_sampler_object *samp,
   3306                         const struct gl_texture_object *tObj, GLuint n,
   3307                         const GLfloat texcoords[][4], const GLfloat lambda[],
   3308                         GLfloat rgba[][4])
   3309 {
   3310    GLuint i;
   3311    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   3312    (void) lambda;
   3313    for (i = 0; i < n; i++) {
   3314       sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
   3315    }
   3316 }
   3317 
   3318 
   3319 /** Sample 1D Array texture, linear filtering for both min/magnification */
   3320 static void
   3321 sample_linear_1d_array(struct gl_context *ctx,
   3322                        const struct gl_sampler_object *samp,
   3323                        const struct gl_texture_object *tObj, GLuint n,
   3324                        const GLfloat texcoords[][4],
   3325                        const GLfloat lambda[], GLfloat rgba[][4])
   3326 {
   3327    GLuint i;
   3328    struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
   3329    (void) lambda;
   3330    for (i = 0; i < n; i++) {
   3331       sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
   3332    }
   3333 }
   3334 
   3335 
   3336 /** Sample 1D Array texture, using lambda to choose between min/magnification */
   3337 static void
   3338 sample_lambda_1d_array(struct gl_context *ctx,
   3339                        const struct gl_sampler_object *samp,
   3340                        const struct gl_texture_object *tObj, GLuint n,
   3341                        const GLfloat texcoords[][4], const GLfloat lambda[],
   3342                        GLfloat rgba[][4])
   3343 {
   3344    GLuint minStart, minEnd;  /* texels with minification */
   3345    GLuint magStart, magEnd;  /* texels with magnification */
   3346    GLuint i;
   3347 
   3348    ASSERT(lambda != NULL);
   3349    compute_min_mag_ranges(samp, n, lambda,
   3350                           &minStart, &minEnd, &magStart, &magEnd);
   3351 
   3352    if (minStart < minEnd) {
   3353       /* do the minified texels */
   3354       GLuint m = minEnd - minStart;
   3355       switch (samp->MinFilter) {
   3356       case GL_NEAREST:
   3357          for (i = minStart; i < minEnd; i++)
   3358             sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3359                                     texcoords[i], rgba[i]);
   3360          break;
   3361       case GL_LINEAR:
   3362          for (i = minStart; i < minEnd; i++)
   3363             sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3364                                    texcoords[i], rgba[i]);
   3365          break;
   3366       case GL_NEAREST_MIPMAP_NEAREST:
   3367          sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
   3368                                                 lambda + minStart, rgba + minStart);
   3369          break;
   3370       case GL_LINEAR_MIPMAP_NEAREST:
   3371          sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
   3372                                                texcoords + minStart,
   3373                                                lambda + minStart,
   3374                                                rgba + minStart);
   3375          break;
   3376       case GL_NEAREST_MIPMAP_LINEAR:
   3377          sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
   3378                                                lambda + minStart, rgba + minStart);
   3379          break;
   3380       case GL_LINEAR_MIPMAP_LINEAR:
   3381          sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m,
   3382                                               texcoords + minStart,
   3383                                               lambda + minStart,
   3384                                               rgba + minStart);
   3385          break;
   3386       default:
   3387          _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
   3388          return;
   3389       }
   3390    }
   3391 
   3392    if (magStart < magEnd) {
   3393       /* do the magnified texels */
   3394       switch (samp->MagFilter) {
   3395       case GL_NEAREST:
   3396          for (i = magStart; i < magEnd; i++)
   3397             sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3398                               texcoords[i], rgba[i]);
   3399          break;
   3400       case GL_LINEAR:
   3401          for (i = magStart; i < magEnd; i++)
   3402             sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
   3403                                    texcoords[i], rgba[i]);
   3404          break;
   3405       default:
   3406          _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
   3407          return;
   3408       }
   3409    }
   3410 }
   3411 
   3412 
   3413 /**
   3414  * Compare texcoord against depth sample.  Return 1.0 or 0.0 value.
   3415  */
   3416 static inline GLfloat
   3417 shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample)
   3418 {
   3419    switch (function) {
   3420    case GL_LEQUAL:
   3421       return (coord <= depthSample) ? 1.0F : 0.0F;
   3422    case GL_GEQUAL:
   3423       return (coord >= depthSample) ? 1.0F : 0.0F;
   3424    case GL_LESS:
   3425       return (coord < depthSample) ? 1.0F : 0.0F;
   3426    case GL_GREATER:
   3427       return (coord > depthSample) ? 1.0F : 0.0F;
   3428    case GL_EQUAL:
   3429       return (coord == depthSample) ? 1.0F : 0.0F;
   3430    case GL_NOTEQUAL:
   3431       return (coord != depthSample) ? 1.0F : 0.0F;
   3432    case GL_ALWAYS:
   3433       return 1.0F;
   3434    case GL_NEVER:
   3435       return 0.0F;
   3436    case GL_NONE:
   3437       return depthSample;
   3438    default:
   3439       _mesa_problem(NULL, "Bad compare func in shadow_compare");
   3440       return 0.0F;
   3441    }
   3442 }
   3443 
   3444 
   3445 /**
   3446  * Compare texcoord against four depth samples.
   3447  */
   3448 static inline GLfloat
   3449 shadow_compare4(GLenum function, GLfloat coord,
   3450                 GLfloat depth00, GLfloat depth01,
   3451                 GLfloat depth10, GLfloat depth11,
   3452                 GLfloat wi, GLfloat wj)
   3453 {
   3454    const GLfloat d = 0.25F;
   3455    GLfloat luminance = 1.0F;
   3456 
   3457    switch (function) {
   3458    case GL_LEQUAL:
   3459       if (coord > depth00)  luminance -= d;
   3460       if (coord > depth01)  luminance -= d;
   3461       if (coord > depth10)  luminance -= d;
   3462       if (coord > depth11)  luminance -= d;
   3463       return luminance;
   3464    case GL_GEQUAL:
   3465       if (coord < depth00)  luminance -= d;
   3466       if (coord < depth01)  luminance -= d;
   3467       if (coord < depth10)  luminance -= d;
   3468       if (coord < depth11)  luminance -= d;
   3469       return luminance;
   3470    case GL_LESS:
   3471       if (coord >= depth00)  luminance -= d;
   3472       if (coord >= depth01)  luminance -= d;
   3473       if (coord >= depth10)  luminance -= d;
   3474       if (coord >= depth11)  luminance -= d;
   3475       return luminance;
   3476    case GL_GREATER:
   3477       if (coord <= depth00)  luminance -= d;
   3478       if (coord <= depth01)  luminance -= d;
   3479       if (coord <= depth10)  luminance -= d;
   3480       if (coord <= depth11)  luminance -= d;
   3481       return luminance;
   3482    case GL_EQUAL:
   3483       if (coord != depth00)  luminance -= d;
   3484       if (coord != depth01)  luminance -= d;
   3485       if (coord != depth10)  luminance -= d;
   3486       if (coord != depth11)  luminance -= d;
   3487       return luminance;
   3488    case GL_NOTEQUAL:
   3489       if (coord == depth00)  luminance -= d;
   3490       if (coord == depth01)  luminance -= d;
   3491       if (coord == depth10)  luminance -= d;
   3492       if (coord == depth11)  luminance -= d;
   3493       return luminance;
   3494    case GL_ALWAYS:
   3495       return 1.0F;
   3496    case GL_NEVER:
   3497       return 0.0F;
   3498    case GL_NONE:
   3499       /* ordinary bilinear filtering */
   3500       return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
   3501    default:
   3502       _mesa_problem(NULL, "Bad compare func in sample_compare4");
   3503       return 0.0F;
   3504    }
   3505 }
   3506 
   3507 
   3508 /**
   3509  * Choose the mipmap level to use when sampling from a depth texture.
   3510  */
   3511 static int
   3512 choose_depth_texture_level(const struct gl_sampler_object *samp,
   3513                            const struct gl_texture_object *tObj, GLfloat lambda)
   3514 {
   3515    GLint level;
   3516 
   3517    if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) {
   3518       /* no mipmapping - use base level */
   3519       level = tObj->BaseLevel;
   3520    }
   3521    else {
   3522       /* choose mipmap level */
   3523       lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
   3524       level = (GLint) lambda;
   3525       level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel);
   3526    }
   3527 
   3528    return level;
   3529 }
   3530 
   3531 
   3532 /**
   3533  * Sample a shadow/depth texture.  This function is incomplete.  It doesn't
   3534  * check for minification vs. magnification, etc.
   3535  */
   3536 static void
   3537 sample_depth_texture( struct gl_context *ctx,
   3538                       const struct gl_sampler_object *samp,
   3539                       const struct gl_texture_object *tObj, GLuint n,
   3540                       const GLfloat texcoords[][4], const GLfloat lambda[],
   3541                       GLfloat texel[][4] )
   3542 {
   3543    const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]);
   3544    const struct gl_texture_image *img = tObj->Image[0][level];
   3545    const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
   3546    const GLint width = img->Width;
   3547    const GLint height = img->Height;
   3548    const GLint depth = img->Depth;
   3549    const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
   3550        ? 3 : 2;
   3551    GLenum function;
   3552    GLfloat result;
   3553 
   3554    ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT ||
   3555           img->_BaseFormat == GL_DEPTH_STENCIL_EXT);
   3556 
   3557    ASSERT(tObj->Target == GL_TEXTURE_1D ||
   3558           tObj->Target == GL_TEXTURE_2D ||
   3559           tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
   3560           tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
   3561           tObj->Target == GL_TEXTURE_2D_ARRAY_EXT ||
   3562           tObj->Target == GL_TEXTURE_CUBE_MAP);
   3563 
   3564    /* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */
   3565 
   3566    function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ?
   3567       samp->CompareFunc : GL_NONE;
   3568 
   3569    if (samp->MagFilter == GL_NEAREST) {
   3570       GLuint i;
   3571       for (i = 0; i < n; i++) {
   3572          GLfloat depthSample, depthRef;
   3573          GLint col, row, slice;
   3574 
   3575          nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice);
   3576 
   3577          if (col >= 0 && row >= 0 && col < width && row < height &&
   3578              slice >= 0 && slice < depth) {
   3579             swImg->FetchTexel(swImg, col, row, slice, &depthSample);
   3580          }
   3581          else {
   3582             depthSample = samp->BorderColor.f[0];
   3583          }
   3584 
   3585          depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
   3586 
   3587          result = shadow_compare(function, depthRef, depthSample);
   3588 
   3589          apply_depth_mode(tObj->DepthMode, result, texel[i]);
   3590       }
   3591    }
   3592    else {
   3593       GLuint i;
   3594       ASSERT(samp->MagFilter == GL_LINEAR);
   3595       for (i = 0; i < n; i++) {
   3596          GLfloat depth00, depth01, depth10, depth11, depthRef;
   3597          GLint i0, i1, j0, j1;
   3598          GLint slice;
   3599          GLfloat wi, wj;
   3600          GLuint useBorderTexel;
   3601 
   3602          linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice,
   3603                          &wi, &wj);
   3604 
   3605          useBorderTexel = 0;
   3606          if (img->Border) {
   3607             i0 += img->Border;
   3608             i1 += img->Border;
   3609             if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
   3610                j0 += img->Border;
   3611                j1 += img->Border;
   3612             }
   3613          }
   3614          else {
   3615             if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
   3616             if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
   3617             if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
   3618             if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
   3619          }
   3620 
   3621          if (slice < 0 || slice >= (GLint) depth) {
   3622             depth00 = samp->BorderColor.f[0];
   3623             depth01 = samp->BorderColor.f[0];
   3624             depth10 = samp->BorderColor.f[0];
   3625             depth11 = samp->BorderColor.f[0];
   3626          }
   3627          else {
   3628             /* get four depth samples from the texture */
   3629             if (useBorderTexel & (I0BIT | J0BIT)) {
   3630                depth00 = samp->BorderColor.f[0];
   3631             }
   3632             else {
   3633                swImg->FetchTexel(swImg, i0, j0, slice, &depth00);
   3634             }
   3635             if (useBorderTexel & (I1BIT | J0BIT)) {
   3636                depth10 = samp->BorderColor.f[0];
   3637             }
   3638             else {
   3639                swImg->FetchTexel(swImg, i1, j0, slice, &depth10);
   3640             }
   3641 
   3642             if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
   3643                if (useBorderTexel & (I0BIT | J1BIT)) {
   3644                   depth01 = samp->BorderColor.f[0];
   3645                }
   3646                else {
   3647                   swImg->FetchTexel(swImg, i0, j1, slice, &depth01);
   3648                }
   3649                if (useBorderTexel & (I1BIT | J1BIT)) {
   3650                   depth11 = samp->BorderColor.f[0];
   3651                }
   3652                else {
   3653                   swImg->FetchTexel(swImg, i1, j1, slice, &depth11);
   3654                }
   3655             }
   3656             else {
   3657                depth01 = depth00;
   3658                depth11 = depth10;
   3659             }
   3660          }
   3661 
   3662          depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
   3663 
   3664          result = shadow_compare4(function, depthRef,
   3665                                   depth00, depth01, depth10, depth11,
   3666                                   wi, wj);
   3667 
   3668          apply_depth_mode(tObj->DepthMode, result, texel[i]);
   3669       }  /* for */
   3670    }  /* if filter */
   3671 }
   3672 
   3673 
   3674 /**
   3675  * We use this function when a texture object is in an "incomplete" state.
   3676  * When a fragment program attempts to sample an incomplete texture we
   3677  * return black (see issue 23 in GL_ARB_fragment_program spec).
   3678  * Note: fragment programs don't observe the texture enable/disable flags.
   3679  */
   3680 static void
   3681 null_sample_func( struct gl_context *ctx,
   3682                   const struct gl_sampler_object *samp,
   3683 		  const struct gl_texture_object *tObj, GLuint n,
   3684 		  const GLfloat texcoords[][4], const GLfloat lambda[],
   3685 		  GLfloat rgba[][4])
   3686 {
   3687    GLuint i;
   3688    (void) ctx;
   3689    (void) tObj;
   3690    (void) texcoords;
   3691    (void) lambda;
   3692    (void) samp;
   3693    for (i = 0; i < n; i++) {
   3694       rgba[i][RCOMP] = 0;
   3695       rgba[i][GCOMP] = 0;
   3696       rgba[i][BCOMP] = 0;
   3697       rgba[i][ACOMP] = 1.0;
   3698    }
   3699 }
   3700 
   3701 
   3702 /**
   3703  * Choose the texture sampling function for the given texture object.
   3704  */
   3705 texture_sample_func
   3706 _swrast_choose_texture_sample_func( struct gl_context *ctx,
   3707 				    const struct gl_texture_object *t,
   3708                                     const struct gl_sampler_object *sampler)
   3709 {
   3710    if (!t || !_mesa_is_texture_complete(t, sampler)) {
   3711       return &null_sample_func;
   3712    }
   3713    else {
   3714       const GLboolean needLambda =
   3715          (GLboolean) (sampler->MinFilter != sampler->MagFilter);
   3716 
   3717       switch (t->Target) {
   3718       case GL_TEXTURE_1D:
   3719          if (is_depth_texture(t)) {
   3720             return &sample_depth_texture;
   3721          }
   3722          else if (needLambda) {
   3723             return &sample_lambda_1d;
   3724          }
   3725          else if (sampler->MinFilter == GL_LINEAR) {
   3726             return &sample_linear_1d;
   3727          }
   3728          else {
   3729             ASSERT(sampler->MinFilter == GL_NEAREST);
   3730             return &sample_nearest_1d;
   3731          }
   3732       case GL_TEXTURE_2D:
   3733          if (is_depth_texture(t)) {
   3734             return &sample_depth_texture;
   3735          }
   3736          else if (needLambda) {
   3737             /* Anisotropic filtering extension. Activated only if mipmaps are used */
   3738             if (sampler->MaxAnisotropy > 1.0 &&
   3739                 sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
   3740                return &sample_lambda_2d_aniso;
   3741             }
   3742             return &sample_lambda_2d;
   3743          }
   3744          else if (sampler->MinFilter == GL_LINEAR) {
   3745             return &sample_linear_2d;
   3746          }
   3747          else {
   3748             /* check for a few optimized cases */
   3749             const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
   3750             const struct swrast_texture_image *swImg =
   3751                swrast_texture_image_const(img);
   3752             texture_sample_func func;
   3753 
   3754             ASSERT(sampler->MinFilter == GL_NEAREST);
   3755             func = &sample_nearest_2d;
   3756             if (sampler->WrapS == GL_REPEAT &&
   3757                 sampler->WrapT == GL_REPEAT &&
   3758                 swImg->_IsPowerOfTwo &&
   3759                 img->Border == 0) {
   3760                if (img->TexFormat == MESA_FORMAT_RGB888)
   3761                   func = &opt_sample_rgb_2d;
   3762                else if (img->TexFormat == MESA_FORMAT_RGBA8888)
   3763                   func = &opt_sample_rgba_2d;
   3764             }
   3765 
   3766             return func;
   3767          }
   3768       case GL_TEXTURE_3D:
   3769          if (needLambda) {
   3770             return &sample_lambda_3d;
   3771          }
   3772          else if (sampler->MinFilter == GL_LINEAR) {
   3773             return &sample_linear_3d;
   3774          }
   3775          else {
   3776             ASSERT(sampler->MinFilter == GL_NEAREST);
   3777             return &sample_nearest_3d;
   3778          }
   3779       case GL_TEXTURE_CUBE_MAP:
   3780          if (needLambda) {
   3781             return &sample_lambda_cube;
   3782          }
   3783          else if (sampler->MinFilter == GL_LINEAR) {
   3784             return &sample_linear_cube;
   3785          }
   3786          else {
   3787             ASSERT(sampler->MinFilter == GL_NEAREST);
   3788             return &sample_nearest_cube;
   3789          }
   3790       case GL_TEXTURE_RECTANGLE_NV:
   3791          if (is_depth_texture(t)) {
   3792             return &sample_depth_texture;
   3793          }
   3794          else if (needLambda) {
   3795             return &sample_lambda_rect;
   3796          }
   3797          else if (sampler->MinFilter == GL_LINEAR) {
   3798             return &sample_linear_rect;
   3799          }
   3800          else {
   3801             ASSERT(sampler->MinFilter == GL_NEAREST);
   3802             return &sample_nearest_rect;
   3803          }
   3804       case GL_TEXTURE_1D_ARRAY_EXT:
   3805          if (is_depth_texture(t)) {
   3806             return &sample_depth_texture;
   3807          }
   3808 	 else if (needLambda) {
   3809             return &sample_lambda_1d_array;
   3810          }
   3811          else if (sampler->MinFilter == GL_LINEAR) {
   3812             return &sample_linear_1d_array;
   3813          }
   3814          else {
   3815             ASSERT(sampler->MinFilter == GL_NEAREST);
   3816             return &sample_nearest_1d_array;
   3817          }
   3818       case GL_TEXTURE_2D_ARRAY_EXT:
   3819          if (is_depth_texture(t)) {
   3820             return &sample_depth_texture;
   3821          }
   3822 	 else if (needLambda) {
   3823             return &sample_lambda_2d_array;
   3824          }
   3825          else if (sampler->MinFilter == GL_LINEAR) {
   3826             return &sample_linear_2d_array;
   3827          }
   3828          else {
   3829             ASSERT(sampler->MinFilter == GL_NEAREST);
   3830             return &sample_nearest_2d_array;
   3831          }
   3832       default:
   3833          _mesa_problem(ctx,
   3834                        "invalid target in _swrast_choose_texture_sample_func");
   3835          return &null_sample_func;
   3836       }
   3837    }
   3838 }
   3839