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