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