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