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