OSDN Git Service

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