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