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