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