s_texfilter.c revision 9282ebbaa5fdb4bc1d6234d746acac525660185d
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.3
4 *
5 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "main/glheader.h"
27#include "main/context.h"
28#include "main/colormac.h"
29#include "main/imports.h"
30#include "main/texobj.h"
31#include "main/samplerobj.h"
32
33#include "s_context.h"
34#include "s_texfilter.h"
35
36
37/*
38 * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
39 * see 1-pixel bands of improperly weighted linear-filtered textures.
40 * The tests/texwrap.c demo is a good test.
41 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
42 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
43 */
44#define FRAC(f)  ((f) - IFLOOR(f))
45
46
47
48/**
49 * Linear interpolation macro
50 */
51#define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
52
53
54/**
55 * Do 2D/biliner interpolation of float values.
56 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
57 * a and b are the horizontal and vertical interpolants.
58 * It's important that this function is inlined when compiled with
59 * optimization!  If we find that's not true on some systems, convert
60 * to a macro.
61 */
62static inline GLfloat
63lerp_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 */
76static inline GLfloat
77lerp_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 */
94static inline void
95lerp_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 */
107static inline void
108lerp_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 */
122static inline void
123lerp_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 */
158static inline void
159linear_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 */
287static inline GLint
288nearest_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 */
412static inline void
413linear_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 */
426static inline GLint
427clamp_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 */
446static inline void
447clamp_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 */
488static inline GLint
489tex_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 */
501static inline void
502nearest_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 */
550static inline void
551linear_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 */
609static inline GLint
610linear_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 */
624static inline GLint
625nearest_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 */
660static inline void
661compute_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 */
769static inline void
770get_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 */
806static INLINE void
807apply_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 */
831static GLboolean
832is_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 */
846static inline void
847sample_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 */
871static inline void
872sample_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
913static void
914sample_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
929static void
930sample_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
945static void
946sample_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
971static void
972sample_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 */
998static void
999sample_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 */
1015static void
1016sample_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 */
1032static void
1033sample_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 */
1112static inline void
1113sample_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 */
1146static inline void
1147sample_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 */
1211static inline void
1212sample_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
1244static void
1245sample_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
1259static void
1260sample_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
1275static void
1276sample_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
1301static void
1302sample_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
1327static void
1328sample_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 */
1358static void
1359sample_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 */
1375static void
1376sample_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 */
1410static void
1411opt_sample_rgb_2d(struct gl_context *ctx,
1412                  const struct gl_sampler_object *samp,
1413                  const struct gl_texture_object *tObj,
1414                  GLuint n, const GLfloat texcoords[][4],
1415                  const GLfloat lambda[], GLfloat rgba[][4])
1416{
1417   const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1418   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1419   const GLfloat width = (GLfloat) img->Width;
1420   const GLfloat height = (GLfloat) img->Height;
1421   const GLint colMask = img->Width - 1;
1422   const GLint rowMask = img->Height - 1;
1423   const GLint shift = img->WidthLog2;
1424   GLuint k;
1425   (void) ctx;
1426   (void) lambda;
1427   ASSERT(samp->WrapS==GL_REPEAT);
1428   ASSERT(samp->WrapT==GL_REPEAT);
1429   ASSERT(img->Border==0);
1430   ASSERT(img->TexFormat == MESA_FORMAT_RGB888);
1431   ASSERT(swImg->_IsPowerOfTwo);
1432   (void) swImg;
1433
1434   for (k=0; k<n; k++) {
1435      GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
1436      GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
1437      GLint pos = (j << shift) | i;
1438      GLubyte *texel = swImg->Map + 3 * pos;
1439      rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
1440      rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
1441      rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
1442      rgba[k][ACOMP] = 1.0F;
1443   }
1444}
1445
1446
1447/**
1448 * Optimized 2-D texture sampling:
1449 *    S and T wrap mode == GL_REPEAT
1450 *    GL_NEAREST min/mag filter
1451 *    No border
1452 *    RowStride == Width,
1453 *    Format = GL_RGBA
1454 */
1455static void
1456opt_sample_rgba_2d(struct gl_context *ctx,
1457                   const struct gl_sampler_object *samp,
1458                   const struct gl_texture_object *tObj,
1459                   GLuint n, const GLfloat texcoords[][4],
1460                   const GLfloat lambda[], GLfloat rgba[][4])
1461{
1462   const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1463   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1464   const GLfloat width = (GLfloat) img->Width;
1465   const GLfloat height = (GLfloat) img->Height;
1466   const GLint colMask = img->Width - 1;
1467   const GLint rowMask = img->Height - 1;
1468   const GLint shift = img->WidthLog2;
1469   GLuint i;
1470   (void) ctx;
1471   (void) lambda;
1472   ASSERT(samp->WrapS==GL_REPEAT);
1473   ASSERT(samp->WrapT==GL_REPEAT);
1474   ASSERT(img->Border==0);
1475   ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888);
1476   ASSERT(swImg->_IsPowerOfTwo);
1477   (void) swImg;
1478
1479   for (i = 0; i < n; i++) {
1480      const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
1481      const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
1482      const GLint pos = (row << shift) | col;
1483      const GLuint texel = *((GLuint *) swImg->Map + pos);
1484      rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24)        );
1485      rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
1486      rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >>  8) & 0xff );
1487      rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel      ) & 0xff );
1488   }
1489}
1490
1491
1492/** Sample 2D texture, using lambda to choose between min/magnification */
1493static void
1494sample_lambda_2d(struct gl_context *ctx,
1495                 const struct gl_sampler_object *samp,
1496                 const struct gl_texture_object *tObj,
1497                 GLuint n, const GLfloat texcoords[][4],
1498                 const GLfloat lambda[], GLfloat rgba[][4])
1499{
1500   const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1501   const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1502   GLuint minStart, minEnd;  /* texels with minification */
1503   GLuint magStart, magEnd;  /* texels with magnification */
1504
1505   const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT)
1506      && (samp->WrapT == GL_REPEAT)
1507      && (tImg->Border == 0 && (tImg->Width == swImg->RowStride))
1508      && swImg->_IsPowerOfTwo;
1509
1510   ASSERT(lambda != NULL);
1511   compute_min_mag_ranges(samp, n, lambda,
1512                          &minStart, &minEnd, &magStart, &magEnd);
1513
1514   if (minStart < minEnd) {
1515      /* do the minified texels */
1516      const GLuint m = minEnd - minStart;
1517      switch (samp->MinFilter) {
1518      case GL_NEAREST:
1519         if (repeatNoBorderPOT) {
1520            switch (tImg->TexFormat) {
1521            case MESA_FORMAT_RGB888:
1522               opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart,
1523                                 NULL, rgba + minStart);
1524               break;
1525            case MESA_FORMAT_RGBA8888:
1526	       opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart,
1527                                  NULL, rgba + minStart);
1528               break;
1529            default:
1530               sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1531                                 NULL, rgba + minStart );
1532            }
1533         }
1534         else {
1535            sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1536                              NULL, rgba + minStart);
1537         }
1538         break;
1539      case GL_LINEAR:
1540	 sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart,
1541			  NULL, rgba + minStart);
1542         break;
1543      case GL_NEAREST_MIPMAP_NEAREST:
1544         sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m,
1545                                          texcoords + minStart,
1546                                          lambda + minStart, rgba + minStart);
1547         break;
1548      case GL_LINEAR_MIPMAP_NEAREST:
1549         sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1550                                         lambda + minStart, rgba + minStart);
1551         break;
1552      case GL_NEAREST_MIPMAP_LINEAR:
1553         sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1554                                         lambda + minStart, rgba + minStart);
1555         break;
1556      case GL_LINEAR_MIPMAP_LINEAR:
1557         if (repeatNoBorderPOT)
1558            sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m,
1559                  texcoords + minStart, lambda + minStart, rgba + minStart);
1560         else
1561            sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1562                                        lambda + minStart, rgba + minStart);
1563         break;
1564      default:
1565         _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1566         return;
1567      }
1568   }
1569
1570   if (magStart < magEnd) {
1571      /* do the magnified texels */
1572      const GLuint m = magEnd - magStart;
1573
1574      switch (samp->MagFilter) {
1575      case GL_NEAREST:
1576         if (repeatNoBorderPOT) {
1577            switch (tImg->TexFormat) {
1578            case MESA_FORMAT_RGB888:
1579               opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart,
1580                                 NULL, rgba + magStart);
1581               break;
1582            case MESA_FORMAT_RGBA8888:
1583	       opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart,
1584                                  NULL, rgba + magStart);
1585               break;
1586            default:
1587               sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1588                                 NULL, rgba + magStart );
1589            }
1590         }
1591         else {
1592            sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1593                              NULL, rgba + magStart);
1594         }
1595         break;
1596      case GL_LINEAR:
1597	 sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart,
1598			  NULL, rgba + magStart);
1599         break;
1600      default:
1601         _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1602         break;
1603      }
1604   }
1605}
1606
1607
1608/* For anisotropic filtering */
1609#define WEIGHT_LUT_SIZE 1024
1610
1611static GLfloat *weightLut = NULL;
1612
1613/**
1614 * Creates the look-up table used to speed-up EWA sampling
1615 */
1616static void
1617create_filter_table(void)
1618{
1619   GLuint i;
1620   if (!weightLut) {
1621      weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
1622
1623      for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
1624         GLfloat alpha = 2;
1625         GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
1626         GLfloat weight = (GLfloat) exp(-alpha * r2);
1627         weightLut[i] = weight;
1628      }
1629   }
1630}
1631
1632
1633/**
1634 * Elliptical weighted average (EWA) filter for producing high quality
1635 * anisotropic filtered results.
1636 * Based on the Higher Quality Elliptical Weighted Avarage Filter
1637 * published by Paul S. Heckbert in his Master's Thesis
1638 * "Fundamentals of Texture Mapping and Image Warping" (1989)
1639 */
1640static void
1641sample_2d_ewa(struct gl_context *ctx,
1642              const struct gl_sampler_object *samp,
1643              const struct gl_texture_object *tObj,
1644              const GLfloat texcoord[4],
1645              const GLfloat dudx, const GLfloat dvdx,
1646              const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1647              GLfloat rgba[])
1648{
1649   GLint level = lod > 0 ? lod : 0;
1650   GLfloat scaling = 1.0 / (1 << level);
1651   const struct gl_texture_image *img =	tObj->Image[0][level];
1652   const struct gl_texture_image *mostDetailedImage =
1653      tObj->Image[0][tObj->BaseLevel];
1654   const struct swrast_texture_image *swImg =
1655      swrast_texture_image_const(mostDetailedImage);
1656   GLfloat tex_u=-0.5 + texcoord[0] * swImg->WidthScale * scaling;
1657   GLfloat tex_v=-0.5 + texcoord[1] * swImg->HeightScale * scaling;
1658
1659   GLfloat ux = dudx * scaling;
1660   GLfloat vx = dvdx * scaling;
1661   GLfloat uy = dudy * scaling;
1662   GLfloat vy = dvdy * scaling;
1663
1664   /* compute ellipse coefficients to bound the region:
1665    * A*x*x + B*x*y + C*y*y = F.
1666    */
1667   GLfloat A = vx*vx+vy*vy+1;
1668   GLfloat B = -2*(ux*vx+uy*vy);
1669   GLfloat C = ux*ux+uy*uy+1;
1670   GLfloat F = A*C-B*B/4.0;
1671
1672   /* check if it is an ellipse */
1673   /* ASSERT(F > 0.0); */
1674
1675   /* Compute the ellipse's (u,v) bounding box in texture space */
1676   GLfloat d = -B*B+4.0*C*A;
1677   GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with   */
1678   GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */
1679
1680   GLint u0 = floor(tex_u - box_u);
1681   GLint u1 = ceil (tex_u + box_u);
1682   GLint v0 = floor(tex_v - box_v);
1683   GLint v1 = ceil (tex_v + box_v);
1684
1685   GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1686   GLfloat newCoord[2];
1687   GLfloat den = 0.0F;
1688   GLfloat ddq;
1689   GLfloat U = u0 - tex_u;
1690   GLint v;
1691
1692   /* Scale ellipse formula to directly index the Filter Lookup Table.
1693    * i.e. scale so that F = WEIGHT_LUT_SIZE-1
1694    */
1695   double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F;
1696   A *= formScale;
1697   B *= formScale;
1698   C *= formScale;
1699   /* F *= formScale; */ /* no need to scale F as we don't use it below here */
1700
1701   /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
1702    * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
1703    * value, q, is less than F, we're inside the ellipse
1704    */
1705   ddq = 2 * A;
1706   for (v = v0; v <= v1; ++v) {
1707      GLfloat V = v - tex_v;
1708      GLfloat dq = A * (2 * U + 1) + B * V;
1709      GLfloat q = (C * V + B * U) * V + A * U * U;
1710
1711      GLint u;
1712      for (u = u0; u <= u1; ++u) {
1713         /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
1714         if (q < WEIGHT_LUT_SIZE) {
1715            /* as a LUT is used, q must never be negative;
1716             * should not happen, though
1717             */
1718            const GLint qClamped = q >= 0.0F ? q : 0;
1719            GLfloat weight = weightLut[qClamped];
1720
1721            newCoord[0] = u / ((GLfloat) img->Width2);
1722            newCoord[1] = v / ((GLfloat) img->Height2);
1723
1724            sample_2d_nearest(ctx, samp, img, newCoord, rgba);
1725            num[0] += weight * rgba[0];
1726            num[1] += weight * rgba[1];
1727            num[2] += weight * rgba[2];
1728            num[3] += weight * rgba[3];
1729
1730            den += weight;
1731         }
1732         q += dq;
1733         dq += ddq;
1734      }
1735   }
1736
1737   if (den <= 0.0F) {
1738      /* Reaching this place would mean
1739       * that no pixels intersected the ellipse.
1740       * This should never happen because
1741       * the filter we use always
1742       * intersects at least one pixel.
1743       */
1744
1745      /*rgba[0]=0;
1746      rgba[1]=0;
1747      rgba[2]=0;
1748      rgba[3]=0;*/
1749      /* not enough pixels in resampling, resort to direct interpolation */
1750      sample_2d_linear(ctx, samp, img, texcoord, rgba);
1751      return;
1752   }
1753
1754   rgba[0] = num[0] / den;
1755   rgba[1] = num[1] / den;
1756   rgba[2] = num[2] / den;
1757   rgba[3] = num[3] / den;
1758}
1759
1760
1761/**
1762 * Anisotropic filtering using footprint assembly as outlined in the
1763 * EXT_texture_filter_anisotropic spec:
1764 * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
1765 * Faster than EWA but has less quality (more aliasing effects)
1766 */
1767static void
1768sample_2d_footprint(struct gl_context *ctx,
1769                 const struct gl_sampler_object *samp,
1770                 const struct gl_texture_object *tObj,
1771                 const GLfloat texcoord[4],
1772                 const GLfloat dudx, const GLfloat dvdx,
1773                 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1774                 GLfloat rgba[])
1775{
1776   GLint level = lod > 0 ? lod : 0;
1777   GLfloat scaling = 1.0F / (1 << level);
1778   const struct gl_texture_image *img = tObj->Image[0][level];
1779
1780   GLfloat ux = dudx * scaling;
1781   GLfloat vx = dvdx * scaling;
1782   GLfloat uy = dudy * scaling;
1783   GLfloat vy = dvdy * scaling;
1784
1785   GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
1786   GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
1787
1788   GLint numSamples;
1789   GLfloat ds;
1790   GLfloat dt;
1791
1792   GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1793   GLfloat newCoord[2];
1794   GLint s;
1795
1796   /*  Calculate the per anisotropic sample offsets in s,t space. */
1797   if (Px2 > Py2) {
1798      numSamples = ceil(SQRTF(Px2));
1799      ds = ux / ((GLfloat) img->Width2);
1800      dt = vx / ((GLfloat) img->Height2);
1801   }
1802   else {
1803      numSamples = ceil(SQRTF(Py2));
1804      ds = uy / ((GLfloat) img->Width2);
1805      dt = vy / ((GLfloat) img->Height2);
1806   }
1807
1808   for (s = 0; s<numSamples; s++) {
1809      newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5);
1810      newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5);
1811
1812      sample_2d_linear(ctx, samp, img, newCoord, rgba);
1813      num[0] += rgba[0];
1814      num[1] += rgba[1];
1815      num[2] += rgba[2];
1816      num[3] += rgba[3];
1817   }
1818
1819   rgba[0] = num[0] / numSamples;
1820   rgba[1] = num[1] / numSamples;
1821   rgba[2] = num[2] / numSamples;
1822   rgba[3] = num[3] / numSamples;
1823}
1824
1825
1826/**
1827 * Returns the index of the specified texture object in the
1828 * gl_context texture unit array.
1829 */
1830static inline GLuint
1831texture_unit_index(const struct gl_context *ctx,
1832                   const struct gl_texture_object *tObj)
1833{
1834   const GLuint maxUnit
1835      = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
1836   GLuint u;
1837
1838   /* XXX CoordUnits vs. ImageUnits */
1839   for (u = 0; u < maxUnit; u++) {
1840      if (ctx->Texture.Unit[u]._Current == tObj)
1841         break; /* found */
1842   }
1843   if (u >= maxUnit)
1844      u = 0; /* not found, use 1st one; should never happen */
1845
1846   return u;
1847}
1848
1849
1850/**
1851 * Sample 2D texture using an anisotropic filter.
1852 * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
1853 * the lambda float array but a "hidden" SWspan struct which is required
1854 * by this function but is not available in the texture_sample_func signature.
1855 * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
1856 * this function is called.
1857 */
1858static void
1859sample_lambda_2d_aniso(struct gl_context *ctx,
1860                       const struct gl_sampler_object *samp,
1861                       const struct gl_texture_object *tObj,
1862                       GLuint n, const GLfloat texcoords[][4],
1863                       const GLfloat lambda_iso[], GLfloat rgba[][4])
1864{
1865   const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1866   const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1867   const GLfloat maxEccentricity =
1868      samp->MaxAnisotropy * samp->MaxAnisotropy;
1869
1870   /* re-calculate the lambda values so that they are usable with anisotropic
1871    * filtering
1872    */
1873   SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
1874
1875   /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
1876    * in swrast/s_span.c
1877    */
1878
1879   /* find the texture unit index by looking up the current texture object
1880    * from the context list of available texture objects.
1881    */
1882   const GLuint u = texture_unit_index(ctx, tObj);
1883   const GLuint attr = FRAG_ATTRIB_TEX0 + u;
1884   GLfloat texW, texH;
1885
1886   const GLfloat dsdx = span->attrStepX[attr][0];
1887   const GLfloat dsdy = span->attrStepY[attr][0];
1888   const GLfloat dtdx = span->attrStepX[attr][1];
1889   const GLfloat dtdy = span->attrStepY[attr][1];
1890   const GLfloat dqdx = span->attrStepX[attr][3];
1891   const GLfloat dqdy = span->attrStepY[attr][3];
1892   GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
1893   GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
1894   GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
1895
1896   /* from swrast/s_texcombine.c _swrast_texture_span */
1897   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
1898   const GLboolean adjustLOD =
1899      (texUnit->LodBias + samp->LodBias != 0.0F)
1900      || (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0);
1901
1902   GLuint i;
1903
1904   /* on first access create the lookup table containing the filter weights. */
1905   if (!weightLut) {
1906      create_filter_table();
1907   }
1908
1909   texW = swImg->WidthScale;
1910   texH = swImg->HeightScale;
1911
1912   for (i = 0; i < n; i++) {
1913      const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
1914
1915      GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
1916      GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
1917      GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
1918      GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
1919
1920      /* note: instead of working with Px and Py, we will use the
1921       * squared length instead, to avoid sqrt.
1922       */
1923      GLfloat Px2 = dudx * dudx + dvdx * dvdx;
1924      GLfloat Py2 = dudy * dudy + dvdy * dvdy;
1925
1926      GLfloat Pmax2;
1927      GLfloat Pmin2;
1928      GLfloat e;
1929      GLfloat lod;
1930
1931      s += dsdx;
1932      t += dtdx;
1933      q += dqdx;
1934
1935      if (Px2 < Py2) {
1936         Pmax2 = Py2;
1937         Pmin2 = Px2;
1938      }
1939      else {
1940         Pmax2 = Px2;
1941         Pmin2 = Py2;
1942      }
1943
1944      /* if the eccentricity of the ellipse is too big, scale up the shorter
1945       * of the two vectors to limit the maximum amount of work per pixel
1946       */
1947      e = Pmax2 / Pmin2;
1948      if (e > maxEccentricity) {
1949         /* GLfloat s=e / maxEccentricity;
1950            minor[0] *= s;
1951            minor[1] *= s;
1952            Pmin2 *= s; */
1953         Pmin2 = Pmax2 / maxEccentricity;
1954      }
1955
1956      /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
1957       * this since 0.5*log(x) = log(sqrt(x))
1958       */
1959      lod = 0.5 * LOG2(Pmin2);
1960
1961      if (adjustLOD) {
1962         /* from swrast/s_texcombine.c _swrast_texture_span */
1963         if (texUnit->LodBias + samp->LodBias != 0.0F) {
1964            /* apply LOD bias, but don't clamp yet */
1965            const GLfloat bias =
1966               CLAMP(texUnit->LodBias + samp->LodBias,
1967                     -ctx->Const.MaxTextureLodBias,
1968                     ctx->Const.MaxTextureLodBias);
1969            lod += bias;
1970
1971            if (samp->MinLod != -1000.0 ||
1972                samp->MaxLod != 1000.0) {
1973               /* apply LOD clamping to lambda */
1974               lod = CLAMP(lod, samp->MinLod, samp->MaxLod);
1975            }
1976         }
1977      }
1978
1979      /* If the ellipse covers the whole image, we can
1980       * simply return the average of the whole image.
1981       */
1982      if (lod >= tObj->_MaxLevel) {
1983         sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1984                          texcoords[i], rgba[i]);
1985      }
1986      else {
1987         /* don't bother interpolating between multiple LODs; it doesn't
1988          * seem to be worth the extra running time.
1989          */
1990         sample_2d_ewa(ctx, samp, tObj, texcoords[i],
1991                       dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
1992
1993         /* unused: */
1994         (void) sample_2d_footprint;
1995         /*
1996         sample_2d_footprint(ctx, tObj, texcoords[i],
1997                             dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
1998         */
1999      }
2000   }
2001}
2002
2003
2004
2005/**********************************************************************/
2006/*                    3-D Texture Sampling Functions                  */
2007/**********************************************************************/
2008
2009/**
2010 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2011 */
2012static inline void
2013sample_3d_nearest(struct gl_context *ctx,
2014                  const struct gl_sampler_object *samp,
2015                  const struct gl_texture_image *img,
2016                  const GLfloat texcoord[4],
2017                  GLfloat rgba[4])
2018{
2019   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2020   const GLint width = img->Width2;     /* without border, power of two */
2021   const GLint height = img->Height2;   /* without border, power of two */
2022   const GLint depth = img->Depth2;     /* without border, power of two */
2023   GLint i, j, k;
2024   (void) ctx;
2025
2026   i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2027   j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2028   k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]);
2029
2030   if (i < 0 || i >= (GLint) img->Width ||
2031       j < 0 || j >= (GLint) img->Height ||
2032       k < 0 || k >= (GLint) img->Depth) {
2033      /* Need this test for GL_CLAMP_TO_BORDER mode */
2034      get_border_color(samp, img, rgba);
2035   }
2036   else {
2037      swImg->FetchTexel(swImg, i, j, k, rgba);
2038   }
2039}
2040
2041
2042/**
2043 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2044 */
2045static void
2046sample_3d_linear(struct gl_context *ctx,
2047                 const struct gl_sampler_object *samp,
2048                 const struct gl_texture_image *img,
2049                 const GLfloat texcoord[4],
2050                 GLfloat rgba[4])
2051{
2052   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2053   const GLint width = img->Width2;
2054   const GLint height = img->Height2;
2055   const GLint depth = img->Depth2;
2056   GLint i0, j0, k0, i1, j1, k1;
2057   GLbitfield useBorderColor = 0x0;
2058   GLfloat a, b, c;
2059   GLfloat t000[4], t010[4], t001[4], t011[4];
2060   GLfloat t100[4], t110[4], t101[4], t111[4];
2061
2062   linear_texel_locations(samp->WrapS, img, width, texcoord[0],  &i0, &i1, &a);
2063   linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2064   linear_texel_locations(samp->WrapR, img, depth, texcoord[2],  &k0, &k1, &c);
2065
2066   if (img->Border) {
2067      i0 += img->Border;
2068      i1 += img->Border;
2069      j0 += img->Border;
2070      j1 += img->Border;
2071      k0 += img->Border;
2072      k1 += img->Border;
2073   }
2074   else {
2075      /* check if sampling texture border color */
2076      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
2077      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
2078      if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
2079      if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
2080      if (k0 < 0 || k0 >= depth)   useBorderColor |= K0BIT;
2081      if (k1 < 0 || k1 >= depth)   useBorderColor |= K1BIT;
2082   }
2083
2084   /* Fetch texels */
2085   if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
2086      get_border_color(samp, img, t000);
2087   }
2088   else {
2089      swImg->FetchTexel(swImg, i0, j0, k0, t000);
2090   }
2091   if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
2092      get_border_color(samp, img, t100);
2093   }
2094   else {
2095      swImg->FetchTexel(swImg, i1, j0, k0, t100);
2096   }
2097   if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
2098      get_border_color(samp, img, t010);
2099   }
2100   else {
2101      swImg->FetchTexel(swImg, i0, j1, k0, t010);
2102   }
2103   if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
2104      get_border_color(samp, img, t110);
2105   }
2106   else {
2107      swImg->FetchTexel(swImg, i1, j1, k0, t110);
2108   }
2109
2110   if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
2111      get_border_color(samp, img, t001);
2112   }
2113   else {
2114      swImg->FetchTexel(swImg, i0, j0, k1, t001);
2115   }
2116   if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
2117      get_border_color(samp, img, t101);
2118   }
2119   else {
2120      swImg->FetchTexel(swImg, i1, j0, k1, t101);
2121   }
2122   if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
2123      get_border_color(samp, img, t011);
2124   }
2125   else {
2126      swImg->FetchTexel(swImg, i0, j1, k1, t011);
2127   }
2128   if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
2129      get_border_color(samp, img, t111);
2130   }
2131   else {
2132      swImg->FetchTexel(swImg, i1, j1, k1, t111);
2133   }
2134
2135   /* trilinear interpolation of samples */
2136   lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
2137}
2138
2139
2140static void
2141sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
2142                                 const struct gl_sampler_object *samp,
2143                                 const struct gl_texture_object *tObj,
2144                                 GLuint n, const GLfloat texcoord[][4],
2145                                 const GLfloat lambda[], GLfloat rgba[][4] )
2146{
2147   GLuint i;
2148   for (i = 0; i < n; i++) {
2149      GLint level = nearest_mipmap_level(tObj, lambda[i]);
2150      sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2151   }
2152}
2153
2154
2155static void
2156sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
2157                                const struct gl_sampler_object *samp,
2158                                const struct gl_texture_object *tObj,
2159                                GLuint n, const GLfloat texcoord[][4],
2160                                const GLfloat lambda[], GLfloat rgba[][4])
2161{
2162   GLuint i;
2163   ASSERT(lambda != NULL);
2164   for (i = 0; i < n; i++) {
2165      GLint level = nearest_mipmap_level(tObj, lambda[i]);
2166      sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2167   }
2168}
2169
2170
2171static void
2172sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
2173                                const struct gl_sampler_object *samp,
2174                                const struct gl_texture_object *tObj,
2175                                GLuint n, const GLfloat texcoord[][4],
2176                                const GLfloat lambda[], GLfloat rgba[][4])
2177{
2178   GLuint i;
2179   ASSERT(lambda != NULL);
2180   for (i = 0; i < n; i++) {
2181      GLint level = linear_mipmap_level(tObj, lambda[i]);
2182      if (level >= tObj->_MaxLevel) {
2183         sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2184                           texcoord[i], rgba[i]);
2185      }
2186      else {
2187         GLfloat t0[4], t1[4];  /* texels */
2188         const GLfloat f = FRAC(lambda[i]);
2189         sample_3d_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
2190         sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2191         lerp_rgba(rgba[i], f, t0, t1);
2192      }
2193   }
2194}
2195
2196
2197static void
2198sample_3d_linear_mipmap_linear(struct gl_context *ctx,
2199                               const struct gl_sampler_object *samp,
2200                               const struct gl_texture_object *tObj,
2201                               GLuint n, const GLfloat texcoord[][4],
2202                               const GLfloat lambda[], GLfloat rgba[][4])
2203{
2204   GLuint i;
2205   ASSERT(lambda != NULL);
2206   for (i = 0; i < n; i++) {
2207      GLint level = linear_mipmap_level(tObj, lambda[i]);
2208      if (level >= tObj->_MaxLevel) {
2209         sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2210                          texcoord[i], rgba[i]);
2211      }
2212      else {
2213         GLfloat t0[4], t1[4];  /* texels */
2214         const GLfloat f = FRAC(lambda[i]);
2215         sample_3d_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
2216         sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2217         lerp_rgba(rgba[i], f, t0, t1);
2218      }
2219   }
2220}
2221
2222
2223/** Sample 3D texture, nearest filtering for both min/magnification */
2224static void
2225sample_nearest_3d(struct gl_context *ctx,
2226                  const struct gl_sampler_object *samp,
2227                  const struct gl_texture_object *tObj, GLuint n,
2228                  const GLfloat texcoords[][4], const GLfloat lambda[],
2229                  GLfloat rgba[][4])
2230{
2231   GLuint i;
2232   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2233   (void) lambda;
2234   for (i = 0; i < n; i++) {
2235      sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
2236   }
2237}
2238
2239
2240/** Sample 3D texture, linear filtering for both min/magnification */
2241static void
2242sample_linear_3d(struct gl_context *ctx,
2243                 const struct gl_sampler_object *samp,
2244                 const struct gl_texture_object *tObj, GLuint n,
2245                 const GLfloat texcoords[][4],
2246		 const GLfloat lambda[], GLfloat rgba[][4])
2247{
2248   GLuint i;
2249   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2250   (void) lambda;
2251   for (i = 0; i < n; i++) {
2252      sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]);
2253   }
2254}
2255
2256
2257/** Sample 3D texture, using lambda to choose between min/magnification */
2258static void
2259sample_lambda_3d(struct gl_context *ctx,
2260                 const struct gl_sampler_object *samp,
2261                 const struct gl_texture_object *tObj, GLuint n,
2262                 const GLfloat texcoords[][4], const GLfloat lambda[],
2263                 GLfloat rgba[][4])
2264{
2265   GLuint minStart, minEnd;  /* texels with minification */
2266   GLuint magStart, magEnd;  /* texels with magnification */
2267   GLuint i;
2268
2269   ASSERT(lambda != NULL);
2270   compute_min_mag_ranges(samp, n, lambda,
2271                          &minStart, &minEnd, &magStart, &magEnd);
2272
2273   if (minStart < minEnd) {
2274      /* do the minified texels */
2275      GLuint m = minEnd - minStart;
2276      switch (samp->MinFilter) {
2277      case GL_NEAREST:
2278         for (i = minStart; i < minEnd; i++)
2279            sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2280                              texcoords[i], rgba[i]);
2281         break;
2282      case GL_LINEAR:
2283         for (i = minStart; i < minEnd; i++)
2284            sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2285                             texcoords[i], rgba[i]);
2286         break;
2287      case GL_NEAREST_MIPMAP_NEAREST:
2288         sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2289                                          lambda + minStart, rgba + minStart);
2290         break;
2291      case GL_LINEAR_MIPMAP_NEAREST:
2292         sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2293                                         lambda + minStart, rgba + minStart);
2294         break;
2295      case GL_NEAREST_MIPMAP_LINEAR:
2296         sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2297                                         lambda + minStart, rgba + minStart);
2298         break;
2299      case GL_LINEAR_MIPMAP_LINEAR:
2300         sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2301                                        lambda + minStart, rgba + minStart);
2302         break;
2303      default:
2304         _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
2305         return;
2306      }
2307   }
2308
2309   if (magStart < magEnd) {
2310      /* do the magnified texels */
2311      switch (samp->MagFilter) {
2312      case GL_NEAREST:
2313         for (i = magStart; i < magEnd; i++)
2314            sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2315                              texcoords[i], rgba[i]);
2316         break;
2317      case GL_LINEAR:
2318         for (i = magStart; i < magEnd; i++)
2319            sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2320                             texcoords[i], rgba[i]);
2321         break;
2322      default:
2323         _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
2324         return;
2325      }
2326   }
2327}
2328
2329
2330/**********************************************************************/
2331/*                Texture Cube Map Sampling Functions                 */
2332/**********************************************************************/
2333
2334/**
2335 * Choose one of six sides of a texture cube map given the texture
2336 * coord (rx,ry,rz).  Return pointer to corresponding array of texture
2337 * images.
2338 */
2339static const struct gl_texture_image **
2340choose_cube_face(const struct gl_texture_object *texObj,
2341                 const GLfloat texcoord[4], GLfloat newCoord[4])
2342{
2343   /*
2344      major axis
2345      direction     target                             sc     tc    ma
2346      ----------    -------------------------------    ---    ---   ---
2347       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
2348       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
2349       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
2350       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
2351       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
2352       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
2353   */
2354   const GLfloat rx = texcoord[0];
2355   const GLfloat ry = texcoord[1];
2356   const GLfloat rz = texcoord[2];
2357   const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
2358   GLuint face;
2359   GLfloat sc, tc, ma;
2360
2361   if (arx >= ary && arx >= arz) {
2362      if (rx >= 0.0F) {
2363         face = FACE_POS_X;
2364         sc = -rz;
2365         tc = -ry;
2366         ma = arx;
2367      }
2368      else {
2369         face = FACE_NEG_X;
2370         sc = rz;
2371         tc = -ry;
2372         ma = arx;
2373      }
2374   }
2375   else if (ary >= arx && ary >= arz) {
2376      if (ry >= 0.0F) {
2377         face = FACE_POS_Y;
2378         sc = rx;
2379         tc = rz;
2380         ma = ary;
2381      }
2382      else {
2383         face = FACE_NEG_Y;
2384         sc = rx;
2385         tc = -rz;
2386         ma = ary;
2387      }
2388   }
2389   else {
2390      if (rz > 0.0F) {
2391         face = FACE_POS_Z;
2392         sc = rx;
2393         tc = -ry;
2394         ma = arz;
2395      }
2396      else {
2397         face = FACE_NEG_Z;
2398         sc = -rx;
2399         tc = -ry;
2400         ma = arz;
2401      }
2402   }
2403
2404   {
2405      const float ima = 1.0F / ma;
2406      newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
2407      newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
2408   }
2409
2410   return (const struct gl_texture_image **) texObj->Image[face];
2411}
2412
2413
2414static void
2415sample_nearest_cube(struct gl_context *ctx,
2416                    const struct gl_sampler_object *samp,
2417		    const struct gl_texture_object *tObj, GLuint n,
2418                    const GLfloat texcoords[][4], const GLfloat lambda[],
2419                    GLfloat rgba[][4])
2420{
2421   GLuint i;
2422   (void) lambda;
2423   for (i = 0; i < n; i++) {
2424      const struct gl_texture_image **images;
2425      GLfloat newCoord[4];
2426      images = choose_cube_face(tObj, texcoords[i], newCoord);
2427      sample_2d_nearest(ctx, samp, images[tObj->BaseLevel],
2428                        newCoord, rgba[i]);
2429   }
2430   if (is_depth_texture(tObj)) {
2431      for (i = 0; i < n; i++) {
2432         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2433      }
2434   }
2435}
2436
2437
2438static void
2439sample_linear_cube(struct gl_context *ctx,
2440                   const struct gl_sampler_object *samp,
2441		   const struct gl_texture_object *tObj, GLuint n,
2442                   const GLfloat texcoords[][4],
2443		   const GLfloat lambda[], GLfloat rgba[][4])
2444{
2445   GLuint i;
2446   (void) lambda;
2447   for (i = 0; i < n; i++) {
2448      const struct gl_texture_image **images;
2449      GLfloat newCoord[4];
2450      images = choose_cube_face(tObj, texcoords[i], newCoord);
2451      sample_2d_linear(ctx, samp, images[tObj->BaseLevel],
2452                       newCoord, rgba[i]);
2453   }
2454   if (is_depth_texture(tObj)) {
2455      for (i = 0; i < n; i++) {
2456         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2457      }
2458   }
2459}
2460
2461
2462static void
2463sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
2464                                   const struct gl_sampler_object *samp,
2465                                   const struct gl_texture_object *tObj,
2466                                   GLuint n, const GLfloat texcoord[][4],
2467                                   const GLfloat lambda[], GLfloat rgba[][4])
2468{
2469   GLuint i;
2470   ASSERT(lambda != NULL);
2471   for (i = 0; i < n; i++) {
2472      const struct gl_texture_image **images;
2473      GLfloat newCoord[4];
2474      GLint level;
2475      images = choose_cube_face(tObj, texcoord[i], newCoord);
2476
2477      /* XXX we actually need to recompute lambda here based on the newCoords.
2478       * But we would need the texcoords of adjacent fragments to compute that
2479       * properly, and we don't have those here.
2480       * For now, do an approximation:  subtracting 1 from the chosen mipmap
2481       * level seems to work in some test cases.
2482       * The same adjustment is done in the next few functions.
2483      */
2484      level = nearest_mipmap_level(tObj, lambda[i]);
2485      level = MAX2(level - 1, 0);
2486
2487      sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]);
2488   }
2489   if (is_depth_texture(tObj)) {
2490      for (i = 0; i < n; i++) {
2491         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2492      }
2493   }
2494}
2495
2496
2497static void
2498sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
2499                                  const struct gl_sampler_object *samp,
2500                                  const struct gl_texture_object *tObj,
2501                                  GLuint n, const GLfloat texcoord[][4],
2502                                  const GLfloat lambda[], GLfloat rgba[][4])
2503{
2504   GLuint i;
2505   ASSERT(lambda != NULL);
2506   for (i = 0; i < n; i++) {
2507      const struct gl_texture_image **images;
2508      GLfloat newCoord[4];
2509      GLint level = nearest_mipmap_level(tObj, lambda[i]);
2510      level = MAX2(level - 1, 0); /* see comment above */
2511      images = choose_cube_face(tObj, texcoord[i], newCoord);
2512      sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]);
2513   }
2514   if (is_depth_texture(tObj)) {
2515      for (i = 0; i < n; i++) {
2516         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2517      }
2518   }
2519}
2520
2521
2522static void
2523sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
2524                                  const struct gl_sampler_object *samp,
2525                                  const struct gl_texture_object *tObj,
2526                                  GLuint n, const GLfloat texcoord[][4],
2527                                  const GLfloat lambda[], GLfloat rgba[][4])
2528{
2529   GLuint i;
2530   ASSERT(lambda != NULL);
2531   for (i = 0; i < n; i++) {
2532      const struct gl_texture_image **images;
2533      GLfloat newCoord[4];
2534      GLint level = linear_mipmap_level(tObj, lambda[i]);
2535      level = MAX2(level - 1, 0); /* see comment above */
2536      images = choose_cube_face(tObj, texcoord[i], newCoord);
2537      if (level >= tObj->_MaxLevel) {
2538         sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel],
2539                           newCoord, rgba[i]);
2540      }
2541      else {
2542         GLfloat t0[4], t1[4];  /* texels */
2543         const GLfloat f = FRAC(lambda[i]);
2544         sample_2d_nearest(ctx, samp, images[level  ], newCoord, t0);
2545         sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1);
2546         lerp_rgba(rgba[i], f, t0, t1);
2547      }
2548   }
2549   if (is_depth_texture(tObj)) {
2550      for (i = 0; i < n; i++) {
2551         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2552      }
2553   }
2554}
2555
2556
2557static void
2558sample_cube_linear_mipmap_linear(struct gl_context *ctx,
2559                                 const struct gl_sampler_object *samp,
2560                                 const struct gl_texture_object *tObj,
2561                                 GLuint n, const GLfloat texcoord[][4],
2562                                 const GLfloat lambda[], GLfloat rgba[][4])
2563{
2564   GLuint i;
2565   ASSERT(lambda != NULL);
2566   for (i = 0; i < n; i++) {
2567      const struct gl_texture_image **images;
2568      GLfloat newCoord[4];
2569      GLint level = linear_mipmap_level(tObj, lambda[i]);
2570      level = MAX2(level - 1, 0); /* see comment above */
2571      images = choose_cube_face(tObj, texcoord[i], newCoord);
2572      if (level >= tObj->_MaxLevel) {
2573         sample_2d_linear(ctx, samp, images[tObj->_MaxLevel],
2574                          newCoord, rgba[i]);
2575      }
2576      else {
2577         GLfloat t0[4], t1[4];
2578         const GLfloat f = FRAC(lambda[i]);
2579         sample_2d_linear(ctx, samp, images[level  ], newCoord, t0);
2580         sample_2d_linear(ctx, samp, images[level+1], newCoord, t1);
2581         lerp_rgba(rgba[i], f, t0, t1);
2582      }
2583   }
2584   if (is_depth_texture(tObj)) {
2585      for (i = 0; i < n; i++) {
2586         apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2587      }
2588   }
2589}
2590
2591
2592/** Sample cube texture, using lambda to choose between min/magnification */
2593static void
2594sample_lambda_cube(struct gl_context *ctx,
2595                   const struct gl_sampler_object *samp,
2596		   const struct gl_texture_object *tObj, GLuint n,
2597		   const GLfloat texcoords[][4], const GLfloat lambda[],
2598		   GLfloat rgba[][4])
2599{
2600   GLuint minStart, minEnd;  /* texels with minification */
2601   GLuint magStart, magEnd;  /* texels with magnification */
2602
2603   ASSERT(lambda != NULL);
2604   compute_min_mag_ranges(samp, n, lambda,
2605                          &minStart, &minEnd, &magStart, &magEnd);
2606
2607   if (minStart < minEnd) {
2608      /* do the minified texels */
2609      const GLuint m = minEnd - minStart;
2610      switch (samp->MinFilter) {
2611      case GL_NEAREST:
2612         sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart,
2613                             lambda + minStart, rgba + minStart);
2614         break;
2615      case GL_LINEAR:
2616         sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart,
2617                            lambda + minStart, rgba + minStart);
2618         break;
2619      case GL_NEAREST_MIPMAP_NEAREST:
2620         sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m,
2621                                            texcoords + minStart,
2622                                           lambda + minStart, rgba + minStart);
2623         break;
2624      case GL_LINEAR_MIPMAP_NEAREST:
2625         sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m,
2626                                           texcoords + minStart,
2627                                           lambda + minStart, rgba + minStart);
2628         break;
2629      case GL_NEAREST_MIPMAP_LINEAR:
2630         sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m,
2631                                           texcoords + minStart,
2632                                           lambda + minStart, rgba + minStart);
2633         break;
2634      case GL_LINEAR_MIPMAP_LINEAR:
2635         sample_cube_linear_mipmap_linear(ctx, samp, tObj, m,
2636                                          texcoords + minStart,
2637                                          lambda + minStart, rgba + minStart);
2638         break;
2639      default:
2640         _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2641         break;
2642      }
2643   }
2644
2645   if (magStart < magEnd) {
2646      /* do the magnified texels */
2647      const GLuint m = magEnd - magStart;
2648      switch (samp->MagFilter) {
2649      case GL_NEAREST:
2650         sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart,
2651                             lambda + magStart, rgba + magStart);
2652         break;
2653      case GL_LINEAR:
2654         sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart,
2655                            lambda + magStart, rgba + magStart);
2656         break;
2657      default:
2658         _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2659         break;
2660      }
2661   }
2662}
2663
2664
2665/**********************************************************************/
2666/*               Texture Rectangle Sampling Functions                 */
2667/**********************************************************************/
2668
2669
2670static void
2671sample_nearest_rect(struct gl_context *ctx,
2672                    const struct gl_sampler_object *samp,
2673		    const struct gl_texture_object *tObj, GLuint n,
2674                    const GLfloat texcoords[][4], const GLfloat lambda[],
2675                    GLfloat rgba[][4])
2676{
2677   const struct gl_texture_image *img = tObj->Image[0][0];
2678   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2679   const GLint width = img->Width;
2680   const GLint height = img->Height;
2681   GLuint i;
2682
2683   (void) ctx;
2684   (void) lambda;
2685
2686   ASSERT(samp->WrapS == GL_CLAMP ||
2687          samp->WrapS == GL_CLAMP_TO_EDGE ||
2688          samp->WrapS == GL_CLAMP_TO_BORDER);
2689   ASSERT(samp->WrapT == GL_CLAMP ||
2690          samp->WrapT == GL_CLAMP_TO_EDGE ||
2691          samp->WrapT == GL_CLAMP_TO_BORDER);
2692
2693   for (i = 0; i < n; i++) {
2694      GLint row, col;
2695      col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width);
2696      row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height);
2697      if (col < 0 || col >= width || row < 0 || row >= height)
2698         get_border_color(samp, img, rgba[i]);
2699      else
2700         swImg->FetchTexel(swImg, col, row, 0, rgba[i]);
2701   }
2702}
2703
2704
2705static void
2706sample_linear_rect(struct gl_context *ctx,
2707                   const struct gl_sampler_object *samp,
2708		   const struct gl_texture_object *tObj, GLuint n,
2709                   const GLfloat texcoords[][4],
2710		   const GLfloat lambda[], GLfloat rgba[][4])
2711{
2712   const struct gl_texture_image *img = tObj->Image[0][0];
2713   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2714   const GLint width = img->Width;
2715   const GLint height = img->Height;
2716   GLuint i;
2717
2718   (void) ctx;
2719   (void) lambda;
2720
2721   ASSERT(samp->WrapS == GL_CLAMP ||
2722          samp->WrapS == GL_CLAMP_TO_EDGE ||
2723          samp->WrapS == GL_CLAMP_TO_BORDER);
2724   ASSERT(samp->WrapT == GL_CLAMP ||
2725          samp->WrapT == GL_CLAMP_TO_EDGE ||
2726          samp->WrapT == GL_CLAMP_TO_BORDER);
2727
2728   for (i = 0; i < n; i++) {
2729      GLint i0, j0, i1, j1;
2730      GLfloat t00[4], t01[4], t10[4], t11[4];
2731      GLfloat a, b;
2732      GLbitfield useBorderColor = 0x0;
2733
2734      clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width,
2735                              &i0, &i1, &a);
2736      clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height,
2737                              &j0, &j1, &b);
2738
2739      /* compute integer rows/columns */
2740      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
2741      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
2742      if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
2743      if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
2744
2745      /* get four texel samples */
2746      if (useBorderColor & (I0BIT | J0BIT))
2747         get_border_color(samp, img, t00);
2748      else
2749         swImg->FetchTexel(swImg, i0, j0, 0, t00);
2750
2751      if (useBorderColor & (I1BIT | J0BIT))
2752         get_border_color(samp, img, t10);
2753      else
2754         swImg->FetchTexel(swImg, i1, j0, 0, t10);
2755
2756      if (useBorderColor & (I0BIT | J1BIT))
2757         get_border_color(samp, img, t01);
2758      else
2759         swImg->FetchTexel(swImg, i0, j1, 0, t01);
2760
2761      if (useBorderColor & (I1BIT | J1BIT))
2762         get_border_color(samp, img, t11);
2763      else
2764         swImg->FetchTexel(swImg, i1, j1, 0, t11);
2765
2766      lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
2767   }
2768}
2769
2770
2771/** Sample Rect texture, using lambda to choose between min/magnification */
2772static void
2773sample_lambda_rect(struct gl_context *ctx,
2774                   const struct gl_sampler_object *samp,
2775		   const struct gl_texture_object *tObj, GLuint n,
2776		   const GLfloat texcoords[][4], const GLfloat lambda[],
2777		   GLfloat rgba[][4])
2778{
2779   GLuint minStart, minEnd, magStart, magEnd;
2780
2781   /* We only need lambda to decide between minification and magnification.
2782    * There is no mipmapping with rectangular textures.
2783    */
2784   compute_min_mag_ranges(samp, n, lambda,
2785                          &minStart, &minEnd, &magStart, &magEnd);
2786
2787   if (minStart < minEnd) {
2788      if (samp->MinFilter == GL_NEAREST) {
2789         sample_nearest_rect(ctx, samp, tObj, minEnd - minStart,
2790                             texcoords + minStart, NULL, rgba + minStart);
2791      }
2792      else {
2793         sample_linear_rect(ctx, samp, tObj, minEnd - minStart,
2794                            texcoords + minStart, NULL, rgba + minStart);
2795      }
2796   }
2797   if (magStart < magEnd) {
2798      if (samp->MagFilter == GL_NEAREST) {
2799         sample_nearest_rect(ctx, samp, tObj, magEnd - magStart,
2800                             texcoords + magStart, NULL, rgba + magStart);
2801      }
2802      else {
2803         sample_linear_rect(ctx, samp, tObj, magEnd - magStart,
2804                            texcoords + magStart, NULL, rgba + magStart);
2805      }
2806   }
2807}
2808
2809
2810/**********************************************************************/
2811/*                2D Texture Array Sampling Functions                 */
2812/**********************************************************************/
2813
2814/**
2815 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2816 */
2817static void
2818sample_2d_array_nearest(struct gl_context *ctx,
2819                        const struct gl_sampler_object *samp,
2820                        const struct gl_texture_image *img,
2821                        const GLfloat texcoord[4],
2822                        GLfloat rgba[4])
2823{
2824   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2825   const GLint width = img->Width2;     /* without border, power of two */
2826   const GLint height = img->Height2;   /* without border, power of two */
2827   const GLint depth = img->Depth;
2828   GLint i, j;
2829   GLint array;
2830   (void) ctx;
2831
2832   i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2833   j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2834   array = tex_array_slice(texcoord[2], depth);
2835
2836   if (i < 0 || i >= (GLint) img->Width ||
2837       j < 0 || j >= (GLint) img->Height ||
2838       array < 0 || array >= (GLint) img->Depth) {
2839      /* Need this test for GL_CLAMP_TO_BORDER mode */
2840      get_border_color(samp, img, rgba);
2841   }
2842   else {
2843      swImg->FetchTexel(swImg, i, j, array, rgba);
2844   }
2845}
2846
2847
2848/**
2849 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2850 */
2851static void
2852sample_2d_array_linear(struct gl_context *ctx,
2853                       const struct gl_sampler_object *samp,
2854                       const struct gl_texture_image *img,
2855                       const GLfloat texcoord[4],
2856                       GLfloat rgba[4])
2857{
2858   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2859   const GLint width = img->Width2;
2860   const GLint height = img->Height2;
2861   const GLint depth = img->Depth;
2862   GLint i0, j0, i1, j1;
2863   GLint array;
2864   GLbitfield useBorderColor = 0x0;
2865   GLfloat a, b;
2866   GLfloat t00[4], t01[4], t10[4], t11[4];
2867
2868   linear_texel_locations(samp->WrapS, img, width,  texcoord[0], &i0, &i1, &a);
2869   linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2870   array = tex_array_slice(texcoord[2], depth);
2871
2872   if (array < 0 || array >= depth) {
2873      COPY_4V(rgba, samp->BorderColor.f);
2874   }
2875   else {
2876      if (img->Border) {
2877	 i0 += img->Border;
2878	 i1 += img->Border;
2879	 j0 += img->Border;
2880	 j1 += img->Border;
2881      }
2882      else {
2883	 /* check if sampling texture border color */
2884	 if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
2885	 if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
2886	 if (j0 < 0 || j0 >= height)  useBorderColor |= J0BIT;
2887	 if (j1 < 0 || j1 >= height)  useBorderColor |= J1BIT;
2888      }
2889
2890      /* Fetch texels */
2891      if (useBorderColor & (I0BIT | J0BIT)) {
2892         get_border_color(samp, img, t00);
2893      }
2894      else {
2895	 swImg->FetchTexel(swImg, i0, j0, array, t00);
2896      }
2897      if (useBorderColor & (I1BIT | J0BIT)) {
2898         get_border_color(samp, img, t10);
2899      }
2900      else {
2901	 swImg->FetchTexel(swImg, i1, j0, array, t10);
2902      }
2903      if (useBorderColor & (I0BIT | J1BIT)) {
2904         get_border_color(samp, img, t01);
2905      }
2906      else {
2907	 swImg->FetchTexel(swImg, i0, j1, array, t01);
2908      }
2909      if (useBorderColor & (I1BIT | J1BIT)) {
2910         get_border_color(samp, img, t11);
2911      }
2912      else {
2913	 swImg->FetchTexel(swImg, i1, j1, array, t11);
2914      }
2915
2916      /* trilinear interpolation of samples */
2917      lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
2918   }
2919}
2920
2921
2922static void
2923sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx,
2924                                       const struct gl_sampler_object *samp,
2925                                       const struct gl_texture_object *tObj,
2926                                       GLuint n, const GLfloat texcoord[][4],
2927                                       const GLfloat lambda[], GLfloat rgba[][4])
2928{
2929   GLuint i;
2930   for (i = 0; i < n; i++) {
2931      GLint level = nearest_mipmap_level(tObj, lambda[i]);
2932      sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
2933                              rgba[i]);
2934   }
2935}
2936
2937
2938static void
2939sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx,
2940                                      const struct gl_sampler_object *samp,
2941                                      const struct gl_texture_object *tObj,
2942                                      GLuint n, const GLfloat texcoord[][4],
2943                                      const GLfloat lambda[], GLfloat rgba[][4])
2944{
2945   GLuint i;
2946   ASSERT(lambda != NULL);
2947   for (i = 0; i < n; i++) {
2948      GLint level = nearest_mipmap_level(tObj, lambda[i]);
2949      sample_2d_array_linear(ctx, samp, tObj->Image[0][level],
2950                             texcoord[i], rgba[i]);
2951   }
2952}
2953
2954
2955static void
2956sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx,
2957                                      const struct gl_sampler_object *samp,
2958                                      const struct gl_texture_object *tObj,
2959                                      GLuint n, const GLfloat texcoord[][4],
2960                                      const GLfloat lambda[], GLfloat rgba[][4])
2961{
2962   GLuint i;
2963   ASSERT(lambda != NULL);
2964   for (i = 0; i < n; i++) {
2965      GLint level = linear_mipmap_level(tObj, lambda[i]);
2966      if (level >= tObj->_MaxLevel) {
2967         sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2968                                 texcoord[i], rgba[i]);
2969      }
2970      else {
2971         GLfloat t0[4], t1[4];  /* texels */
2972         const GLfloat f = FRAC(lambda[i]);
2973         sample_2d_array_nearest(ctx, samp, tObj->Image[0][level  ],
2974                                 texcoord[i], t0);
2975         sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1],
2976                                 texcoord[i], t1);
2977         lerp_rgba(rgba[i], f, t0, t1);
2978      }
2979   }
2980}
2981
2982
2983static void
2984sample_2d_array_linear_mipmap_linear(struct gl_context *ctx,
2985                                     const struct gl_sampler_object *samp,
2986                                     const struct gl_texture_object *tObj,
2987                                     GLuint n, const GLfloat texcoord[][4],
2988                                     const GLfloat lambda[], GLfloat rgba[][4])
2989{
2990   GLuint i;
2991   ASSERT(lambda != NULL);
2992   for (i = 0; i < n; i++) {
2993      GLint level = linear_mipmap_level(tObj, lambda[i]);
2994      if (level >= tObj->_MaxLevel) {
2995         sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2996                          texcoord[i], rgba[i]);
2997      }
2998      else {
2999         GLfloat t0[4], t1[4];  /* texels */
3000         const GLfloat f = FRAC(lambda[i]);
3001         sample_2d_array_linear(ctx, samp, tObj->Image[0][level  ],
3002                                texcoord[i], t0);
3003         sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1],
3004                                texcoord[i], t1);
3005         lerp_rgba(rgba[i], f, t0, t1);
3006      }
3007   }
3008}
3009
3010
3011/** Sample 2D Array texture, nearest filtering for both min/magnification */
3012static void
3013sample_nearest_2d_array(struct gl_context *ctx,
3014                        const struct gl_sampler_object *samp,
3015                        const struct gl_texture_object *tObj, GLuint n,
3016                        const GLfloat texcoords[][4], const GLfloat lambda[],
3017                        GLfloat rgba[][4])
3018{
3019   GLuint i;
3020   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3021   (void) lambda;
3022   for (i = 0; i < n; i++) {
3023      sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3024   }
3025}
3026
3027
3028
3029/** Sample 2D Array texture, linear filtering for both min/magnification */
3030static void
3031sample_linear_2d_array(struct gl_context *ctx,
3032                       const struct gl_sampler_object *samp,
3033                       const struct gl_texture_object *tObj, GLuint n,
3034                       const GLfloat texcoords[][4],
3035                       const GLfloat lambda[], GLfloat rgba[][4])
3036{
3037   GLuint i;
3038   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3039   (void) lambda;
3040   for (i = 0; i < n; i++) {
3041      sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3042   }
3043}
3044
3045
3046/** Sample 2D Array texture, using lambda to choose between min/magnification */
3047static void
3048sample_lambda_2d_array(struct gl_context *ctx,
3049                       const struct gl_sampler_object *samp,
3050                       const struct gl_texture_object *tObj, GLuint n,
3051                       const GLfloat texcoords[][4], const GLfloat lambda[],
3052                       GLfloat rgba[][4])
3053{
3054   GLuint minStart, minEnd;  /* texels with minification */
3055   GLuint magStart, magEnd;  /* texels with magnification */
3056   GLuint i;
3057
3058   ASSERT(lambda != NULL);
3059   compute_min_mag_ranges(samp, n, lambda,
3060                          &minStart, &minEnd, &magStart, &magEnd);
3061
3062   if (minStart < minEnd) {
3063      /* do the minified texels */
3064      GLuint m = minEnd - minStart;
3065      switch (samp->MinFilter) {
3066      case GL_NEAREST:
3067         for (i = minStart; i < minEnd; i++)
3068            sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3069                                    texcoords[i], rgba[i]);
3070         break;
3071      case GL_LINEAR:
3072         for (i = minStart; i < minEnd; i++)
3073            sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3074                                   texcoords[i], rgba[i]);
3075         break;
3076      case GL_NEAREST_MIPMAP_NEAREST:
3077         sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m,
3078                                                texcoords + minStart,
3079                                                lambda + minStart,
3080                                                rgba + minStart);
3081         break;
3082      case GL_LINEAR_MIPMAP_NEAREST:
3083         sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3084                                               texcoords + minStart,
3085                                               lambda + minStart,
3086                                               rgba + minStart);
3087         break;
3088      case GL_NEAREST_MIPMAP_LINEAR:
3089         sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m,
3090                                               texcoords + minStart,
3091                                               lambda + minStart,
3092                                               rgba + minStart);
3093         break;
3094      case GL_LINEAR_MIPMAP_LINEAR:
3095         sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3096                                              texcoords + minStart,
3097                                              lambda + minStart,
3098                                              rgba + minStart);
3099         break;
3100      default:
3101         _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
3102         return;
3103      }
3104   }
3105
3106   if (magStart < magEnd) {
3107      /* do the magnified texels */
3108      switch (samp->MagFilter) {
3109      case GL_NEAREST:
3110         for (i = magStart; i < magEnd; i++)
3111            sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3112                              texcoords[i], rgba[i]);
3113         break;
3114      case GL_LINEAR:
3115         for (i = magStart; i < magEnd; i++)
3116            sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3117                                   texcoords[i], rgba[i]);
3118         break;
3119      default:
3120         _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
3121         return;
3122      }
3123   }
3124}
3125
3126
3127
3128
3129/**********************************************************************/
3130/*                1D Texture Array Sampling Functions                 */
3131/**********************************************************************/
3132
3133/**
3134 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
3135 */
3136static void
3137sample_1d_array_nearest(struct gl_context *ctx,
3138                        const struct gl_sampler_object *samp,
3139                        const struct gl_texture_image *img,
3140                        const GLfloat texcoord[4],
3141                        GLfloat rgba[4])
3142{
3143   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3144   const GLint width = img->Width2;     /* without border, power of two */
3145   const GLint height = img->Height;
3146   GLint i;
3147   GLint array;
3148   (void) ctx;
3149
3150   i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
3151   array = tex_array_slice(texcoord[1], height);
3152
3153   if (i < 0 || i >= (GLint) img->Width ||
3154       array < 0 || array >= (GLint) img->Height) {
3155      /* Need this test for GL_CLAMP_TO_BORDER mode */
3156      get_border_color(samp, img, rgba);
3157   }
3158   else {
3159      swImg->FetchTexel(swImg, i, array, 0, rgba);
3160   }
3161}
3162
3163
3164/**
3165 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
3166 */
3167static void
3168sample_1d_array_linear(struct gl_context *ctx,
3169                       const struct gl_sampler_object *samp,
3170                       const struct gl_texture_image *img,
3171                       const GLfloat texcoord[4],
3172                       GLfloat rgba[4])
3173{
3174   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3175   const GLint width = img->Width2;
3176   const GLint height = img->Height;
3177   GLint i0, i1;
3178   GLint array;
3179   GLbitfield useBorderColor = 0x0;
3180   GLfloat a;
3181   GLfloat t0[4], t1[4];
3182
3183   linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
3184   array = tex_array_slice(texcoord[1], height);
3185
3186   if (img->Border) {
3187      i0 += img->Border;
3188      i1 += img->Border;
3189   }
3190   else {
3191      /* check if sampling texture border color */
3192      if (i0 < 0 || i0 >= width)   useBorderColor |= I0BIT;
3193      if (i1 < 0 || i1 >= width)   useBorderColor |= I1BIT;
3194   }
3195
3196   if (array < 0 || array >= height)   useBorderColor |= K0BIT;
3197
3198   /* Fetch texels */
3199   if (useBorderColor & (I0BIT | K0BIT)) {
3200      get_border_color(samp, img, t0);
3201   }
3202   else {
3203      swImg->FetchTexel(swImg, i0, array, 0, t0);
3204   }
3205   if (useBorderColor & (I1BIT | K0BIT)) {
3206      get_border_color(samp, img, t1);
3207   }
3208   else {
3209      swImg->FetchTexel(swImg, i1, array, 0, t1);
3210   }
3211
3212   /* bilinear interpolation of samples */
3213   lerp_rgba(rgba, a, t0, t1);
3214}
3215
3216
3217static void
3218sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx,
3219                                       const struct gl_sampler_object *samp,
3220                                       const struct gl_texture_object *tObj,
3221                                       GLuint n, const GLfloat texcoord[][4],
3222                                       const GLfloat lambda[], GLfloat rgba[][4])
3223{
3224   GLuint i;
3225   for (i = 0; i < n; i++) {
3226      GLint level = nearest_mipmap_level(tObj, lambda[i]);
3227      sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
3228                              rgba[i]);
3229   }
3230}
3231
3232
3233static void
3234sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx,
3235                                      const struct gl_sampler_object *samp,
3236                                      const struct gl_texture_object *tObj,
3237                                      GLuint n, const GLfloat texcoord[][4],
3238                                      const GLfloat lambda[], GLfloat rgba[][4])
3239{
3240   GLuint i;
3241   ASSERT(lambda != NULL);
3242   for (i = 0; i < n; i++) {
3243      GLint level = nearest_mipmap_level(tObj, lambda[i]);
3244      sample_1d_array_linear(ctx, samp, tObj->Image[0][level],
3245                             texcoord[i], rgba[i]);
3246   }
3247}
3248
3249
3250static void
3251sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx,
3252                                      const struct gl_sampler_object *samp,
3253                                      const struct gl_texture_object *tObj,
3254                                      GLuint n, const GLfloat texcoord[][4],
3255                                      const GLfloat lambda[], GLfloat rgba[][4])
3256{
3257   GLuint i;
3258   ASSERT(lambda != NULL);
3259   for (i = 0; i < n; i++) {
3260      GLint level = linear_mipmap_level(tObj, lambda[i]);
3261      if (level >= tObj->_MaxLevel) {
3262         sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3263                                 texcoord[i], rgba[i]);
3264      }
3265      else {
3266         GLfloat t0[4], t1[4];  /* texels */
3267         const GLfloat f = FRAC(lambda[i]);
3268         sample_1d_array_nearest(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
3269         sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3270         lerp_rgba(rgba[i], f, t0, t1);
3271      }
3272   }
3273}
3274
3275
3276static void
3277sample_1d_array_linear_mipmap_linear(struct gl_context *ctx,
3278                                     const struct gl_sampler_object *samp,
3279                                     const struct gl_texture_object *tObj,
3280                                     GLuint n, const GLfloat texcoord[][4],
3281                                     const GLfloat lambda[], GLfloat rgba[][4])
3282{
3283   GLuint i;
3284   ASSERT(lambda != NULL);
3285   for (i = 0; i < n; i++) {
3286      GLint level = linear_mipmap_level(tObj, lambda[i]);
3287      if (level >= tObj->_MaxLevel) {
3288         sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3289                          texcoord[i], rgba[i]);
3290      }
3291      else {
3292         GLfloat t0[4], t1[4];  /* texels */
3293         const GLfloat f = FRAC(lambda[i]);
3294         sample_1d_array_linear(ctx, samp, tObj->Image[0][level  ], texcoord[i], t0);
3295         sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3296         lerp_rgba(rgba[i], f, t0, t1);
3297      }
3298   }
3299}
3300
3301
3302/** Sample 1D Array texture, nearest filtering for both min/magnification */
3303static void
3304sample_nearest_1d_array(struct gl_context *ctx,
3305                        const struct gl_sampler_object *samp,
3306                        const struct gl_texture_object *tObj, GLuint n,
3307                        const GLfloat texcoords[][4], const GLfloat lambda[],
3308                        GLfloat rgba[][4])
3309{
3310   GLuint i;
3311   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3312   (void) lambda;
3313   for (i = 0; i < n; i++) {
3314      sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3315   }
3316}
3317
3318
3319/** Sample 1D Array texture, linear filtering for both min/magnification */
3320static void
3321sample_linear_1d_array(struct gl_context *ctx,
3322                       const struct gl_sampler_object *samp,
3323                       const struct gl_texture_object *tObj, GLuint n,
3324                       const GLfloat texcoords[][4],
3325                       const GLfloat lambda[], GLfloat rgba[][4])
3326{
3327   GLuint i;
3328   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3329   (void) lambda;
3330   for (i = 0; i < n; i++) {
3331      sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3332   }
3333}
3334
3335
3336/** Sample 1D Array texture, using lambda to choose between min/magnification */
3337static void
3338sample_lambda_1d_array(struct gl_context *ctx,
3339                       const struct gl_sampler_object *samp,
3340                       const struct gl_texture_object *tObj, GLuint n,
3341                       const GLfloat texcoords[][4], const GLfloat lambda[],
3342                       GLfloat rgba[][4])
3343{
3344   GLuint minStart, minEnd;  /* texels with minification */
3345   GLuint magStart, magEnd;  /* texels with magnification */
3346   GLuint i;
3347
3348   ASSERT(lambda != NULL);
3349   compute_min_mag_ranges(samp, n, lambda,
3350                          &minStart, &minEnd, &magStart, &magEnd);
3351
3352   if (minStart < minEnd) {
3353      /* do the minified texels */
3354      GLuint m = minEnd - minStart;
3355      switch (samp->MinFilter) {
3356      case GL_NEAREST:
3357         for (i = minStart; i < minEnd; i++)
3358            sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3359                                    texcoords[i], rgba[i]);
3360         break;
3361      case GL_LINEAR:
3362         for (i = minStart; i < minEnd; i++)
3363            sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3364                                   texcoords[i], rgba[i]);
3365         break;
3366      case GL_NEAREST_MIPMAP_NEAREST:
3367         sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
3368                                                lambda + minStart, rgba + minStart);
3369         break;
3370      case GL_LINEAR_MIPMAP_NEAREST:
3371         sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3372                                               texcoords + minStart,
3373                                               lambda + minStart,
3374                                               rgba + minStart);
3375         break;
3376      case GL_NEAREST_MIPMAP_LINEAR:
3377         sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
3378                                               lambda + minStart, rgba + minStart);
3379         break;
3380      case GL_LINEAR_MIPMAP_LINEAR:
3381         sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3382                                              texcoords + minStart,
3383                                              lambda + minStart,
3384                                              rgba + minStart);
3385         break;
3386      default:
3387         _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
3388         return;
3389      }
3390   }
3391
3392   if (magStart < magEnd) {
3393      /* do the magnified texels */
3394      switch (samp->MagFilter) {
3395      case GL_NEAREST:
3396         for (i = magStart; i < magEnd; i++)
3397            sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3398                              texcoords[i], rgba[i]);
3399         break;
3400      case GL_LINEAR:
3401         for (i = magStart; i < magEnd; i++)
3402            sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3403                                   texcoords[i], rgba[i]);
3404         break;
3405      default:
3406         _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
3407         return;
3408      }
3409   }
3410}
3411
3412
3413/**
3414 * Compare texcoord against depth sample.  Return 1.0 or 0.0 value.
3415 */
3416static inline GLfloat
3417shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample)
3418{
3419   switch (function) {
3420   case GL_LEQUAL:
3421      return (coord <= depthSample) ? 1.0F : 0.0F;
3422   case GL_GEQUAL:
3423      return (coord >= depthSample) ? 1.0F : 0.0F;
3424   case GL_LESS:
3425      return (coord < depthSample) ? 1.0F : 0.0F;
3426   case GL_GREATER:
3427      return (coord > depthSample) ? 1.0F : 0.0F;
3428   case GL_EQUAL:
3429      return (coord == depthSample) ? 1.0F : 0.0F;
3430   case GL_NOTEQUAL:
3431      return (coord != depthSample) ? 1.0F : 0.0F;
3432   case GL_ALWAYS:
3433      return 1.0F;
3434   case GL_NEVER:
3435      return 0.0F;
3436   case GL_NONE:
3437      return depthSample;
3438   default:
3439      _mesa_problem(NULL, "Bad compare func in shadow_compare");
3440      return 0.0F;
3441   }
3442}
3443
3444
3445/**
3446 * Compare texcoord against four depth samples.
3447 */
3448static inline GLfloat
3449shadow_compare4(GLenum function, GLfloat coord,
3450                GLfloat depth00, GLfloat depth01,
3451                GLfloat depth10, GLfloat depth11,
3452                GLfloat wi, GLfloat wj)
3453{
3454   const GLfloat d = 0.25F;
3455   GLfloat luminance = 1.0F;
3456
3457   switch (function) {
3458   case GL_LEQUAL:
3459      if (coord > depth00)  luminance -= d;
3460      if (coord > depth01)  luminance -= d;
3461      if (coord > depth10)  luminance -= d;
3462      if (coord > depth11)  luminance -= d;
3463      return luminance;
3464   case GL_GEQUAL:
3465      if (coord < depth00)  luminance -= d;
3466      if (coord < depth01)  luminance -= d;
3467      if (coord < depth10)  luminance -= d;
3468      if (coord < depth11)  luminance -= d;
3469      return luminance;
3470   case GL_LESS:
3471      if (coord >= depth00)  luminance -= d;
3472      if (coord >= depth01)  luminance -= d;
3473      if (coord >= depth10)  luminance -= d;
3474      if (coord >= depth11)  luminance -= d;
3475      return luminance;
3476   case GL_GREATER:
3477      if (coord <= depth00)  luminance -= d;
3478      if (coord <= depth01)  luminance -= d;
3479      if (coord <= depth10)  luminance -= d;
3480      if (coord <= depth11)  luminance -= d;
3481      return luminance;
3482   case GL_EQUAL:
3483      if (coord != depth00)  luminance -= d;
3484      if (coord != depth01)  luminance -= d;
3485      if (coord != depth10)  luminance -= d;
3486      if (coord != depth11)  luminance -= d;
3487      return luminance;
3488   case GL_NOTEQUAL:
3489      if (coord == depth00)  luminance -= d;
3490      if (coord == depth01)  luminance -= d;
3491      if (coord == depth10)  luminance -= d;
3492      if (coord == depth11)  luminance -= d;
3493      return luminance;
3494   case GL_ALWAYS:
3495      return 1.0F;
3496   case GL_NEVER:
3497      return 0.0F;
3498   case GL_NONE:
3499      /* ordinary bilinear filtering */
3500      return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
3501   default:
3502      _mesa_problem(NULL, "Bad compare func in sample_compare4");
3503      return 0.0F;
3504   }
3505}
3506
3507
3508/**
3509 * Choose the mipmap level to use when sampling from a depth texture.
3510 */
3511static int
3512choose_depth_texture_level(const struct gl_sampler_object *samp,
3513                           const struct gl_texture_object *tObj, GLfloat lambda)
3514{
3515   GLint level;
3516
3517   if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) {
3518      /* no mipmapping - use base level */
3519      level = tObj->BaseLevel;
3520   }
3521   else {
3522      /* choose mipmap level */
3523      lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
3524      level = (GLint) lambda;
3525      level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel);
3526   }
3527
3528   return level;
3529}
3530
3531
3532/**
3533 * Sample a shadow/depth texture.  This function is incomplete.  It doesn't
3534 * check for minification vs. magnification, etc.
3535 */
3536static void
3537sample_depth_texture( struct gl_context *ctx,
3538                      const struct gl_sampler_object *samp,
3539                      const struct gl_texture_object *tObj, GLuint n,
3540                      const GLfloat texcoords[][4], const GLfloat lambda[],
3541                      GLfloat texel[][4] )
3542{
3543   const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]);
3544   const struct gl_texture_image *img = tObj->Image[0][level];
3545   const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3546   const GLint width = img->Width;
3547   const GLint height = img->Height;
3548   const GLint depth = img->Depth;
3549   const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
3550       ? 3 : 2;
3551   GLenum function;
3552   GLfloat result;
3553
3554   ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT ||
3555          img->_BaseFormat == GL_DEPTH_STENCIL_EXT);
3556
3557   ASSERT(tObj->Target == GL_TEXTURE_1D ||
3558          tObj->Target == GL_TEXTURE_2D ||
3559          tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
3560          tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
3561          tObj->Target == GL_TEXTURE_2D_ARRAY_EXT ||
3562          tObj->Target == GL_TEXTURE_CUBE_MAP);
3563
3564   /* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */
3565
3566   function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ?
3567      samp->CompareFunc : GL_NONE;
3568
3569   if (samp->MagFilter == GL_NEAREST) {
3570      GLuint i;
3571      for (i = 0; i < n; i++) {
3572         GLfloat depthSample, depthRef;
3573         GLint col, row, slice;
3574
3575         nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice);
3576
3577         if (col >= 0 && row >= 0 && col < width && row < height &&
3578             slice >= 0 && slice < depth) {
3579            swImg->FetchTexel(swImg, col, row, slice, &depthSample);
3580         }
3581         else {
3582            depthSample = samp->BorderColor.f[0];
3583         }
3584
3585         depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3586
3587         result = shadow_compare(function, depthRef, depthSample);
3588
3589         apply_depth_mode(tObj->DepthMode, result, texel[i]);
3590      }
3591   }
3592   else {
3593      GLuint i;
3594      ASSERT(samp->MagFilter == GL_LINEAR);
3595      for (i = 0; i < n; i++) {
3596         GLfloat depth00, depth01, depth10, depth11, depthRef;
3597         GLint i0, i1, j0, j1;
3598         GLint slice;
3599         GLfloat wi, wj;
3600         GLuint useBorderTexel;
3601
3602         linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice,
3603                         &wi, &wj);
3604
3605         useBorderTexel = 0;
3606         if (img->Border) {
3607            i0 += img->Border;
3608            i1 += img->Border;
3609            if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3610               j0 += img->Border;
3611               j1 += img->Border;
3612            }
3613         }
3614         else {
3615            if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
3616            if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
3617            if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
3618            if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
3619         }
3620
3621         if (slice < 0 || slice >= (GLint) depth) {
3622            depth00 = samp->BorderColor.f[0];
3623            depth01 = samp->BorderColor.f[0];
3624            depth10 = samp->BorderColor.f[0];
3625            depth11 = samp->BorderColor.f[0];
3626         }
3627         else {
3628            /* get four depth samples from the texture */
3629            if (useBorderTexel & (I0BIT | J0BIT)) {
3630               depth00 = samp->BorderColor.f[0];
3631            }
3632            else {
3633               swImg->FetchTexel(swImg, i0, j0, slice, &depth00);
3634            }
3635            if (useBorderTexel & (I1BIT | J0BIT)) {
3636               depth10 = samp->BorderColor.f[0];
3637            }
3638            else {
3639               swImg->FetchTexel(swImg, i1, j0, slice, &depth10);
3640            }
3641
3642            if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3643               if (useBorderTexel & (I0BIT | J1BIT)) {
3644                  depth01 = samp->BorderColor.f[0];
3645               }
3646               else {
3647                  swImg->FetchTexel(swImg, i0, j1, slice, &depth01);
3648               }
3649               if (useBorderTexel & (I1BIT | J1BIT)) {
3650                  depth11 = samp->BorderColor.f[0];
3651               }
3652               else {
3653                  swImg->FetchTexel(swImg, i1, j1, slice, &depth11);
3654               }
3655            }
3656            else {
3657               depth01 = depth00;
3658               depth11 = depth10;
3659            }
3660         }
3661
3662         depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3663
3664         result = shadow_compare4(function, depthRef,
3665                                  depth00, depth01, depth10, depth11,
3666                                  wi, wj);
3667
3668         apply_depth_mode(tObj->DepthMode, result, texel[i]);
3669      }  /* for */
3670   }  /* if filter */
3671}
3672
3673
3674/**
3675 * We use this function when a texture object is in an "incomplete" state.
3676 * When a fragment program attempts to sample an incomplete texture we
3677 * return black (see issue 23 in GL_ARB_fragment_program spec).
3678 * Note: fragment programs don't observe the texture enable/disable flags.
3679 */
3680static void
3681null_sample_func( struct gl_context *ctx,
3682                  const struct gl_sampler_object *samp,
3683		  const struct gl_texture_object *tObj, GLuint n,
3684		  const GLfloat texcoords[][4], const GLfloat lambda[],
3685		  GLfloat rgba[][4])
3686{
3687   GLuint i;
3688   (void) ctx;
3689   (void) tObj;
3690   (void) texcoords;
3691   (void) lambda;
3692   (void) samp;
3693   for (i = 0; i < n; i++) {
3694      rgba[i][RCOMP] = 0;
3695      rgba[i][GCOMP] = 0;
3696      rgba[i][BCOMP] = 0;
3697      rgba[i][ACOMP] = 1.0;
3698   }
3699}
3700
3701
3702/**
3703 * Choose the texture sampling function for the given texture object.
3704 */
3705texture_sample_func
3706_swrast_choose_texture_sample_func( struct gl_context *ctx,
3707				    const struct gl_texture_object *t,
3708                                    const struct gl_sampler_object *sampler)
3709{
3710   if (!t || !_mesa_is_texture_complete(t, sampler)) {
3711      return &null_sample_func;
3712   }
3713   else {
3714      const GLboolean needLambda =
3715         (GLboolean) (sampler->MinFilter != sampler->MagFilter);
3716
3717      switch (t->Target) {
3718      case GL_TEXTURE_1D:
3719         if (is_depth_texture(t)) {
3720            return &sample_depth_texture;
3721         }
3722         else if (needLambda) {
3723            return &sample_lambda_1d;
3724         }
3725         else if (sampler->MinFilter == GL_LINEAR) {
3726            return &sample_linear_1d;
3727         }
3728         else {
3729            ASSERT(sampler->MinFilter == GL_NEAREST);
3730            return &sample_nearest_1d;
3731         }
3732      case GL_TEXTURE_2D:
3733         if (is_depth_texture(t)) {
3734            return &sample_depth_texture;
3735         }
3736         else if (needLambda) {
3737            /* Anisotropic filtering extension. Activated only if mipmaps are used */
3738            if (sampler->MaxAnisotropy > 1.0 &&
3739                sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
3740               return &sample_lambda_2d_aniso;
3741            }
3742            return &sample_lambda_2d;
3743         }
3744         else if (sampler->MinFilter == GL_LINEAR) {
3745            return &sample_linear_2d;
3746         }
3747         else {
3748            /* check for a few optimized cases */
3749            const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
3750            const struct swrast_texture_image *swImg =
3751               swrast_texture_image_const(img);
3752            texture_sample_func func;
3753
3754            ASSERT(sampler->MinFilter == GL_NEAREST);
3755            func = &sample_nearest_2d;
3756            if (sampler->WrapS == GL_REPEAT &&
3757                sampler->WrapT == GL_REPEAT &&
3758                swImg->_IsPowerOfTwo &&
3759                img->Border == 0) {
3760               if (img->TexFormat == MESA_FORMAT_RGB888)
3761                  func = &opt_sample_rgb_2d;
3762               else if (img->TexFormat == MESA_FORMAT_RGBA8888)
3763                  func = &opt_sample_rgba_2d;
3764            }
3765
3766            return func;
3767         }
3768      case GL_TEXTURE_3D:
3769         if (needLambda) {
3770            return &sample_lambda_3d;
3771         }
3772         else if (sampler->MinFilter == GL_LINEAR) {
3773            return &sample_linear_3d;
3774         }
3775         else {
3776            ASSERT(sampler->MinFilter == GL_NEAREST);
3777            return &sample_nearest_3d;
3778         }
3779      case GL_TEXTURE_CUBE_MAP:
3780         if (needLambda) {
3781            return &sample_lambda_cube;
3782         }
3783         else if (sampler->MinFilter == GL_LINEAR) {
3784            return &sample_linear_cube;
3785         }
3786         else {
3787            ASSERT(sampler->MinFilter == GL_NEAREST);
3788            return &sample_nearest_cube;
3789         }
3790      case GL_TEXTURE_RECTANGLE_NV:
3791         if (is_depth_texture(t)) {
3792            return &sample_depth_texture;
3793         }
3794         else if (needLambda) {
3795            return &sample_lambda_rect;
3796         }
3797         else if (sampler->MinFilter == GL_LINEAR) {
3798            return &sample_linear_rect;
3799         }
3800         else {
3801            ASSERT(sampler->MinFilter == GL_NEAREST);
3802            return &sample_nearest_rect;
3803         }
3804      case GL_TEXTURE_1D_ARRAY_EXT:
3805         if (is_depth_texture(t)) {
3806            return &sample_depth_texture;
3807         }
3808	 else if (needLambda) {
3809            return &sample_lambda_1d_array;
3810         }
3811         else if (sampler->MinFilter == GL_LINEAR) {
3812            return &sample_linear_1d_array;
3813         }
3814         else {
3815            ASSERT(sampler->MinFilter == GL_NEAREST);
3816            return &sample_nearest_1d_array;
3817         }
3818      case GL_TEXTURE_2D_ARRAY_EXT:
3819         if (is_depth_texture(t)) {
3820            return &sample_depth_texture;
3821         }
3822	 else if (needLambda) {
3823            return &sample_lambda_2d_array;
3824         }
3825         else if (sampler->MinFilter == GL_LINEAR) {
3826            return &sample_linear_2d_array;
3827         }
3828         else {
3829            ASSERT(sampler->MinFilter == GL_NEAREST);
3830            return &sample_nearest_2d_array;
3831         }
3832      default:
3833         _mesa_problem(ctx,
3834                       "invalid target in _swrast_choose_texture_sample_func");
3835         return &null_sample_func;
3836      }
3837   }
3838}
3839