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