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