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