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