• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
64 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)65 lerp_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  */
78 static GLfloat
lerp_3d(GLfloat a,GLfloat b,GLfloat c,GLfloat v000,GLfloat v100,GLfloat v010,GLfloat v110,GLfloat v001,GLfloat v101,GLfloat v011,GLfloat v111)79 lerp_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  */
96 static void
lerp_rgba(GLfloat result[4],GLfloat t,const GLfloat a[4],const GLfloat b[4])97 lerp_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  */
109 static void
lerp_rgba_2d(GLfloat result[4],GLfloat a,GLfloat b,const GLfloat t00[4],const GLfloat t10[4],const GLfloat t01[4],const GLfloat t11[4])110 lerp_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  */
124 static void
lerp_rgba_3d(GLfloat result[4],GLfloat a,GLfloat b,GLfloat c,const GLfloat t000[4],const GLfloat t100[4],const GLfloat t010[4],const GLfloat t110[4],const GLfloat t001[4],const GLfloat t101[4],const GLfloat t011[4],const GLfloat t111[4])125 lerp_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  */
160 static void
linear_texel_locations(GLenum wrapMode,const struct gl_texture_image * img,GLint size,GLfloat s,GLint * i0,GLint * i1,GLfloat * weight)161 linear_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  */
290 static GLint
nearest_texel_location(GLenum wrapMode,const struct gl_texture_image * img,GLint size,GLfloat s)291 nearest_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 */
415 static void
linear_repeat_texel_location(GLuint size,GLfloat s,GLint * i0,GLint * i1,GLfloat * weight)416 linear_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  */
429 static GLint
clamp_rect_coord_nearest(GLenum wrapMode,GLfloat coord,GLint max)430 clamp_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  */
449 static void
clamp_rect_coord_linear(GLenum wrapMode,GLfloat coord,GLint max,GLint * i0out,GLint * i1out,GLfloat * weight)450 clamp_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  */
491 static GLint
tex_array_slice(GLfloat coord,GLsizei size)492 tex_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  */
504 static void
nearest_texcoord(const struct gl_sampler_object * samp,const struct gl_texture_object * texObj,GLuint level,const GLfloat texcoord[4],GLint * i,GLint * j,GLint * k)505 nearest_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  */
553 static void
linear_texcoord(const struct gl_sampler_object * samp,const struct gl_texture_object * texObj,GLuint level,const GLfloat texcoord[4],GLint * i0,GLint * i1,GLint * j0,GLint * j1,GLint * slice,GLfloat * wi,GLfloat * wj)554 linear_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  */
612 static GLint
linear_mipmap_level(const struct gl_texture_object * tObj,GLfloat lambda)613 linear_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  */
627 static GLint
nearest_mipmap_level(const struct gl_texture_object * tObj,GLfloat lambda)628 nearest_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  */
663 static void
compute_min_mag_ranges(const struct gl_sampler_object * samp,GLuint n,const GLfloat lambda[],GLuint * minStart,GLuint * minEnd,GLuint * magStart,GLuint * magEnd)664 compute_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  */
772 static void
get_border_color(const struct gl_sampler_object * samp,const struct gl_texture_image * img,GLfloat rgba[4])773 get_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  */
809 static void
apply_depth_mode(GLenum depthMode,GLfloat z,GLfloat texel[4])810 apply_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  */
834 static GLboolean
is_depth_texture(const struct gl_texture_object * tObj)835 is_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  */
849 static void
sample_1d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])850 sample_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  */
874 static void
sample_1d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])875 sample_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 
916 static void
sample_1d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])917 sample_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 
932 static void
sample_1d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])933 sample_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 
948 static void
sample_1d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])949 sample_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 
974 static void
sample_1d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])975 sample_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 */
1001 static void
sample_nearest_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1002 sample_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 */
1018 static void
sample_linear_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1019 sample_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 */
1035 static void
sample_lambda_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1036 sample_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  */
1115 static void
sample_2d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1116 sample_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  */
1149 static void
sample_2d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1150 sample_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  */
1214 static void
sample_2d_linear_repeat(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1215 sample_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 
1247 static void
sample_2d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1248 sample_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 
1262 static void
sample_2d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1263 sample_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 
1278 static void
sample_2d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1279 sample_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 
1304 static void
sample_2d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1305 sample_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 
1330 static void
sample_2d_linear_mipmap_linear_repeat(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1331 sample_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 */
1361 static void
sample_nearest_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1362 sample_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 */
1378 static void
sample_linear_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1379 sample_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  */
1413 static void
opt_sample_rgb_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1414 opt_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  */
1458 static void
opt_sample_rgba_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1459 opt_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 */
1496 static void
sample_lambda_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1497 sample_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 
1616 static GLfloat *weightLut = NULL;
1617 
1618 /**
1619  * Creates the look-up table used to speed-up EWA sampling
1620  */
1621 static void
create_filter_table(void)1622 create_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  */
1645 static void
sample_2d_ewa(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,const GLfloat texcoord[4],const GLfloat dudx,const GLfloat dvdx,const GLfloat dudy,const GLfloat dvdy,const GLint lod,GLfloat rgba[])1646 sample_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  */
1772 static void
sample_2d_footprint(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,const GLfloat texcoord[4],const GLfloat dudx,const GLfloat dvdx,const GLfloat dudy,const GLfloat dvdy,const GLint lod,GLfloat rgba[])1773 sample_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  */
1835 static GLuint
texture_unit_index(const struct gl_context * ctx,const struct gl_texture_object * tObj)1836 texture_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  */
1863 static void
sample_lambda_2d_aniso(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda_iso[],GLfloat rgba[][4])1864 sample_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  */
2017 static void
sample_3d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2018 sample_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  */
2050 static void
sample_3d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2051 sample_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 
2145 static void
sample_3d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2146 sample_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 
2160 static void
sample_3d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2161 sample_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 
2176 static void
sample_3d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2177 sample_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 
2202 static void
sample_3d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2203 sample_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 */
2229 static void
sample_nearest_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2230 sample_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 */
2246 static void
sample_linear_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2247 sample_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 */
2263 static void
sample_lambda_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2264 sample_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  */
2344 static const struct gl_texture_image **
choose_cube_face(const struct gl_texture_object * texObj,const GLfloat texcoord[4],GLfloat newCoord[4])2345 choose_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 
2419 static void
sample_nearest_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2420 sample_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 
2443 static void
sample_linear_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2444 sample_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 
2467 static void
sample_cube_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2468 sample_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 
2502 static void
sample_cube_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2503 sample_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 
2527 static void
sample_cube_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2528 sample_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 
2562 static void
sample_cube_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2563 sample_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 */
2598 static void
sample_lambda_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2599 sample_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 
2675 static void
sample_nearest_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2676 sample_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 
2710 static void
sample_linear_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2711 sample_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 */
2777 static void
sample_lambda_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2778 sample_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  */
2822 static void
sample_2d_array_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2823 sample_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  */
2856 static void
sample_2d_array_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2857 sample_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 
2927 static void
sample_2d_array_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2928 sample_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 
2943 static void
sample_2d_array_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2944 sample_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 
2960 static void
sample_2d_array_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2961 sample_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 
2988 static void
sample_2d_array_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2989 sample_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 */
3017 static void
sample_nearest_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3018 sample_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 */
3035 static void
sample_linear_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3036 sample_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 */
3052 static void
sample_lambda_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3053 sample_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  */
3141 static void
sample_1d_array_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])3142 sample_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  */
3172 static void
sample_1d_array_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])3173 sample_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 
3222 static void
sample_1d_array_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3223 sample_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 
3238 static void
sample_1d_array_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3239 sample_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 
3255 static void
sample_1d_array_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3256 sample_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 
3281 static void
sample_1d_array_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3282 sample_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 */
3308 static void
sample_nearest_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3309 sample_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 */
3325 static void
sample_linear_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3326 sample_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 */
3342 static void
sample_lambda_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3343 sample_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  */
3421 static GLfloat
shadow_compare(GLenum function,GLfloat coord,GLfloat depthSample)3422 shadow_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  */
3453 static GLfloat
shadow_compare4(GLenum function,GLfloat coord,GLfloat depth00,GLfloat depth01,GLfloat depth10,GLfloat depth11,GLfloat wi,GLfloat wj)3454 shadow_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  */
3516 static int
choose_depth_texture_level(const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLfloat lambda)3517 choose_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  */
3541 static void
sample_depth_texture(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat texel[][4])3542 sample_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  */
3685 static void
null_sample_func(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3686 null_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  */
3710 texture_sample_func
_swrast_choose_texture_sample_func(struct gl_context * ctx,const struct gl_texture_object * t,const struct gl_sampler_object * sampler)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