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