[MESA]
[reactos.git] / reactos / dll / opengl / mesa / src / mesa / swrast / s_texfilter.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.3
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/imports.h"
30
31 #include "s_context.h"
32 #include "s_texfilter.h"
33
34
35 /*
36 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
37 * see 1-pixel bands of improperly weighted linear-filtered textures.
38 * The tests/texwrap.c demo is a good test.
39 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
40 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
41 */
42 #define FRAC(f) ((f) - IFLOOR(f))
43
44
45
46 /**
47 * Linear interpolation macro
48 */
49 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
50
51
52 /**
53 * Do 2D/biliner interpolation of float values.
54 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
55 * a and b are the horizontal and vertical interpolants.
56 * It's important that this function is inlined when compiled with
57 * optimization! If we find that's not true on some systems, convert
58 * to a macro.
59 */
60 static inline GLfloat
61 lerp_2d(GLfloat a, GLfloat b,
62 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
63 {
64 const GLfloat temp0 = LERP(a, v00, v10);
65 const GLfloat temp1 = LERP(a, v01, v11);
66 return LERP(b, temp0, temp1);
67 }
68
69
70 /**
71 * Do 3D/trilinear interpolation of float values.
72 * \sa lerp_2d
73 */
74 static inline GLfloat
75 lerp_3d(GLfloat a, GLfloat b, GLfloat c,
76 GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110,
77 GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111)
78 {
79 const GLfloat temp00 = LERP(a, v000, v100);
80 const GLfloat temp10 = LERP(a, v010, v110);
81 const GLfloat temp01 = LERP(a, v001, v101);
82 const GLfloat temp11 = LERP(a, v011, v111);
83 const GLfloat temp0 = LERP(b, temp00, temp10);
84 const GLfloat temp1 = LERP(b, temp01, temp11);
85 return LERP(c, temp0, temp1);
86 }
87
88
89 /**
90 * Do linear interpolation of colors.
91 */
92 static inline void
93 lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4])
94 {
95 result[0] = LERP(t, a[0], b[0]);
96 result[1] = LERP(t, a[1], b[1]);
97 result[2] = LERP(t, a[2], b[2]);
98 result[3] = LERP(t, a[3], b[3]);
99 }
100
101
102 /**
103 * Do bilinear interpolation of colors.
104 */
105 static inline void
106 lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b,
107 const GLfloat t00[4], const GLfloat t10[4],
108 const GLfloat t01[4], const GLfloat t11[4])
109 {
110 result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]);
111 result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]);
112 result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]);
113 result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);
114 }
115
116
117 /**
118 * Do trilinear interpolation of colors.
119 */
120 static inline void
121 lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c,
122 const GLfloat t000[4], const GLfloat t100[4],
123 const GLfloat t010[4], const GLfloat t110[4],
124 const GLfloat t001[4], const GLfloat t101[4],
125 const GLfloat t011[4], const GLfloat t111[4])
126 {
127 GLuint k;
128 /* compiler should unroll these short loops */
129 for (k = 0; k < 4; k++) {
130 result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k],
131 t001[k], t101[k], t011[k], t111[k]);
132 }
133 }
134
135
136 /**
137 * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the
138 * right results for A<0. Casting to A to be unsigned only works if B
139 * is a power of two. Adding a bias to A (which is a multiple of B)
140 * avoids the problems with A < 0 (for reasonable A) without using a
141 * conditional.
142 */
143 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
144
145
146 /**
147 * Used to compute texel locations for linear sampling.
148 * Input:
149 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
150 * s = texcoord in [0,1]
151 * size = width (or height or depth) of texture
152 * Output:
153 * i0, i1 = returns two nearest texel indexes
154 * weight = returns blend factor between texels
155 */
156 static inline void
157 linear_texel_locations(GLenum wrapMode,
158 const struct gl_texture_image *img,
159 GLint size, GLfloat s,
160 GLint *i0, GLint *i1, GLfloat *weight)
161 {
162 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
163 GLfloat u;
164 switch (wrapMode) {
165 case GL_REPEAT:
166 u = s * size - 0.5F;
167 if (swImg->_IsPowerOfTwo) {
168 *i0 = IFLOOR(u) & (size - 1);
169 *i1 = (*i0 + 1) & (size - 1);
170 }
171 else {
172 *i0 = REMAINDER(IFLOOR(u), size);
173 *i1 = REMAINDER(*i0 + 1, size);
174 }
175 break;
176 case GL_CLAMP_TO_EDGE:
177 if (s <= 0.0F)
178 u = 0.0F;
179 else if (s >= 1.0F)
180 u = (GLfloat) size;
181 else
182 u = s * size;
183 u -= 0.5F;
184 *i0 = IFLOOR(u);
185 *i1 = *i0 + 1;
186 if (*i0 < 0)
187 *i0 = 0;
188 if (*i1 >= (GLint) size)
189 *i1 = size - 1;
190 break;
191 case GL_CLAMP_TO_BORDER:
192 {
193 const GLfloat min = -1.0F / (2.0F * size);
194 const GLfloat max = 1.0F - min;
195 if (s <= min)
196 u = min * size;
197 else if (s >= max)
198 u = max * size;
199 else
200 u = s * size;
201 u -= 0.5F;
202 *i0 = IFLOOR(u);
203 *i1 = *i0 + 1;
204 }
205 break;
206 case GL_MIRRORED_REPEAT:
207 {
208 const GLint flr = IFLOOR(s);
209 if (flr & 1)
210 u = 1.0F - (s - (GLfloat) flr);
211 else
212 u = s - (GLfloat) flr;
213 u = (u * size) - 0.5F;
214 *i0 = IFLOOR(u);
215 *i1 = *i0 + 1;
216 if (*i0 < 0)
217 *i0 = 0;
218 if (*i1 >= (GLint) size)
219 *i1 = size - 1;
220 }
221 break;
222 case GL_MIRROR_CLAMP_EXT:
223 u = FABSF(s);
224 if (u >= 1.0F)
225 u = (GLfloat) size;
226 else
227 u *= size;
228 u -= 0.5F;
229 *i0 = IFLOOR(u);
230 *i1 = *i0 + 1;
231 break;
232 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
233 u = FABSF(s);
234 if (u >= 1.0F)
235 u = (GLfloat) size;
236 else
237 u *= size;
238 u -= 0.5F;
239 *i0 = IFLOOR(u);
240 *i1 = *i0 + 1;
241 if (*i0 < 0)
242 *i0 = 0;
243 if (*i1 >= (GLint) size)
244 *i1 = size - 1;
245 break;
246 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
247 {
248 const GLfloat min = -1.0F / (2.0F * size);
249 const GLfloat max = 1.0F - min;
250 u = FABSF(s);
251 if (u <= min)
252 u = min * size;
253 else if (u >= max)
254 u = max * size;
255 else
256 u *= size;
257 u -= 0.5F;
258 *i0 = IFLOOR(u);
259 *i1 = *i0 + 1;
260 }
261 break;
262 case GL_CLAMP:
263 if (s <= 0.0F)
264 u = 0.0F;
265 else if (s >= 1.0F)
266 u = (GLfloat) size;
267 else
268 u = s * size;
269 u -= 0.5F;
270 *i0 = IFLOOR(u);
271 *i1 = *i0 + 1;
272 break;
273 default:
274 _mesa_problem(NULL, "Bad wrap mode");
275 u = 0.0F;
276 break;
277 }
278 *weight = FRAC(u);
279 }
280
281
282 /**
283 * Used to compute texel location for nearest sampling.
284 */
285 static inline GLint
286 nearest_texel_location(GLenum wrapMode,
287 const struct gl_texture_image *img,
288 GLint size, GLfloat s)
289 {
290 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
291 GLint i;
292
293 switch (wrapMode) {
294 case GL_REPEAT:
295 /* s limited to [0,1) */
296 /* i limited to [0,size-1] */
297 i = IFLOOR(s * size);
298 if (swImg->_IsPowerOfTwo)
299 i &= (size - 1);
300 else
301 i = REMAINDER(i, size);
302 return i;
303 case GL_CLAMP_TO_EDGE:
304 {
305 /* s limited to [min,max] */
306 /* i limited to [0, size-1] */
307 const GLfloat min = 1.0F / (2.0F * size);
308 const GLfloat max = 1.0F - min;
309 if (s < min)
310 i = 0;
311 else if (s > max)
312 i = size - 1;
313 else
314 i = IFLOOR(s * size);
315 }
316 return i;
317 case GL_CLAMP_TO_BORDER:
318 {
319 /* s limited to [min,max] */
320 /* i limited to [-1, size] */
321 const GLfloat min = -1.0F / (2.0F * size);
322 const GLfloat max = 1.0F - min;
323 if (s <= min)
324 i = -1;
325 else if (s >= max)
326 i = size;
327 else
328 i = IFLOOR(s * size);
329 }
330 return i;
331 case GL_MIRRORED_REPEAT:
332 {
333 const GLfloat min = 1.0F / (2.0F * size);
334 const GLfloat max = 1.0F - min;
335 const GLint flr = IFLOOR(s);
336 GLfloat u;
337 if (flr & 1)
338 u = 1.0F - (s - (GLfloat) flr);
339 else
340 u = s - (GLfloat) flr;
341 if (u < min)
342 i = 0;
343 else if (u > max)
344 i = size - 1;
345 else
346 i = IFLOOR(u * size);
347 }
348 return i;
349 case GL_MIRROR_CLAMP_EXT:
350 {
351 /* s limited to [0,1] */
352 /* i limited to [0,size-1] */
353 const GLfloat u = FABSF(s);
354 if (u <= 0.0F)
355 i = 0;
356 else if (u >= 1.0F)
357 i = size - 1;
358 else
359 i = IFLOOR(u * size);
360 }
361 return i;
362 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
363 {
364 /* s limited to [min,max] */
365 /* i limited to [0, size-1] */
366 const GLfloat min = 1.0F / (2.0F * size);
367 const GLfloat max = 1.0F - min;
368 const GLfloat u = FABSF(s);
369 if (u < min)
370 i = 0;
371 else if (u > max)
372 i = size - 1;
373 else
374 i = IFLOOR(u * size);
375 }
376 return i;
377 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
378 {
379 /* s limited to [min,max] */
380 /* i limited to [0, size-1] */
381 const GLfloat min = -1.0F / (2.0F * size);
382 const GLfloat max = 1.0F - min;
383 const GLfloat u = FABSF(s);
384 if (u < min)
385 i = -1;
386 else if (u > max)
387 i = size;
388 else
389 i = IFLOOR(u * size);
390 }
391 return i;
392 case GL_CLAMP:
393 /* s limited to [0,1] */
394 /* i limited to [0,size-1] */
395 if (s <= 0.0F)
396 i = 0;
397 else if (s >= 1.0F)
398 i = size - 1;
399 else
400 i = IFLOOR(s * size);
401 return i;
402 default:
403 _mesa_problem(NULL, "Bad wrap mode");
404 return 0;
405 }
406 }
407
408
409 /* Power of two image sizes only */
410 static inline void
411 linear_repeat_texel_location(GLuint size, GLfloat s,
412 GLint *i0, GLint *i1, GLfloat *weight)
413 {
414 GLfloat u = s * size - 0.5F;
415 *i0 = IFLOOR(u) & (size - 1);
416 *i1 = (*i0 + 1) & (size - 1);
417 *weight = FRAC(u);
418 }
419
420
421 /**
422 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
423 */
424 static inline GLint
425 clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
426 {
427 switch (wrapMode) {
428 case GL_CLAMP:
429 return IFLOOR( CLAMP(coord, 0.0F, max - 1) );
430 case GL_CLAMP_TO_EDGE:
431 return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) );
432 case GL_CLAMP_TO_BORDER:
433 return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) );
434 default:
435 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest");
436 return 0;
437 }
438 }
439
440
441 /**
442 * As above, but GL_LINEAR filtering.
443 */
444 static inline void
445 clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
446 GLint *i0out, GLint *i1out, GLfloat *weight)
447 {
448 GLfloat fcol;
449 GLint i0, i1;
450 switch (wrapMode) {
451 case GL_CLAMP:
452 /* Not exactly what the spec says, but it matches NVIDIA output */
453 fcol = CLAMP(coord - 0.5F, 0.0F, max - 1);
454 i0 = IFLOOR(fcol);
455 i1 = i0 + 1;
456 break;
457 case GL_CLAMP_TO_EDGE:
458 fcol = CLAMP(coord, 0.5F, max - 0.5F);
459 fcol -= 0.5F;
460 i0 = IFLOOR(fcol);
461 i1 = i0 + 1;
462 if (i1 > max - 1)
463 i1 = max - 1;
464 break;
465 case GL_CLAMP_TO_BORDER:
466 fcol = CLAMP(coord, -0.5F, max + 0.5F);
467 fcol -= 0.5F;
468 i0 = IFLOOR(fcol);
469 i1 = i0 + 1;
470 break;
471 default:
472 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear");
473 i0 = i1 = 0;
474 fcol = 0.0F;
475 break;
476 }
477 *i0out = i0;
478 *i1out = i1;
479 *weight = FRAC(fcol);
480 }
481
482
483 /**
484 * Compute slice/image to use for 1D or 2D array texture.
485 */
486 static inline GLint
487 tex_array_slice(GLfloat coord, GLsizei size)
488 {
489 GLint slice = IFLOOR(coord + 0.5f);
490 slice = CLAMP(slice, 0, size - 1);
491 return slice;
492 }
493
494
495 /**
496 * Compute nearest integer texcoords for given texobj and coordinate.
497 * NOTE: only used for depth texture sampling.
498 */
499 static inline void
500 nearest_texcoord(const struct gl_texture_object *texObj,
501 GLuint level,
502 const GLfloat texcoord[4],
503 GLint *i, GLint *j, GLint *k)
504 {
505 const struct gl_texture_image *img = texObj->Image[0][level];
506 const GLint width = img->Width;
507 const GLint height = img->Height;
508
509 switch (texObj->Target) {
510 case GL_TEXTURE_1D:
511 *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]);
512 *j = 0;
513 *k = 0;
514 break;
515 case GL_TEXTURE_2D:
516 *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]);
517 *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]);
518 *k = 0;
519 break;
520 default:
521 *i = *j = *k = 0;
522 break;
523 }
524 }
525
526
527 /**
528 * Compute linear integer texcoords for given texobj and coordinate.
529 * NOTE: only used for depth texture sampling.
530 */
531 static inline void
532 linear_texcoord(const struct gl_texture_object *texObj,
533 GLuint level,
534 const GLfloat texcoord[4],
535 GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice,
536 GLfloat *wi, GLfloat *wj)
537 {
538 const struct gl_texture_image *img = texObj->Image[0][level];
539 const GLint width = img->Width;
540 const GLint height = img->Height;
541
542 switch (texObj->Target) {
543 case GL_TEXTURE_1D:
544 case GL_TEXTURE_2D:
545 linear_texel_locations(texObj->Sampler.WrapS, img, width,
546 texcoord[0], i0, i1, wi);
547 linear_texel_locations(texObj->Sampler.WrapT, img, height,
548 texcoord[1], j0, j1, wj);
549 *slice = 0;
550 break;
551
552 default:
553 *slice = 0;
554 break;
555 }
556 }
557
558
559
560 /**
561 * For linear interpolation between mipmap levels N and N+1, this function
562 * computes N.
563 */
564 static inline GLint
565 linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
566 {
567 if (lambda < 0.0F)
568 return tObj->BaseLevel;
569 else if (lambda > tObj->_MaxLambda)
570 return (GLint) (tObj->BaseLevel + tObj->_MaxLambda);
571 else
572 return (GLint) (tObj->BaseLevel + lambda);
573 }
574
575
576 /**
577 * Compute the nearest mipmap level to take texels from.
578 */
579 static inline GLint
580 nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
581 {
582 GLfloat l;
583 GLint level;
584 if (lambda <= 0.5F)
585 l = 0.0F;
586 else if (lambda > tObj->_MaxLambda + 0.4999F)
587 l = tObj->_MaxLambda + 0.4999F;
588 else
589 l = lambda;
590 level = (GLint) (tObj->BaseLevel + l + 0.5F);
591 if (level > tObj->_MaxLevel)
592 level = tObj->_MaxLevel;
593 return level;
594 }
595
596
597
598 /*
599 * Bitflags for texture border color sampling.
600 */
601 #define I0BIT 1
602 #define I1BIT 2
603 #define J0BIT 4
604 #define J1BIT 8
605 #define K0BIT 16
606 #define K1BIT 32
607
608
609
610 /**
611 * The lambda[] array values are always monotonic. Either the whole span
612 * will be minified, magnified, or split between the two. This function
613 * determines the subranges in [0, n-1] that are to be minified or magnified.
614 */
615 static inline void
616 compute_min_mag_ranges(const struct gl_texture_object *tObj,
617 GLuint n, const GLfloat lambda[],
618 GLuint *minStart, GLuint *minEnd,
619 GLuint *magStart, GLuint *magEnd)
620 {
621 GLfloat minMagThresh;
622
623 /* we shouldn't be here if minfilter == magfilter */
624 ASSERT(tObj->Sampler.MinFilter != tObj->Sampler.MagFilter);
625
626 /* This bit comes from the OpenGL spec: */
627 if (tObj->Sampler.MagFilter == GL_LINEAR
628 && (tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
629 tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
630 minMagThresh = 0.5F;
631 }
632 else {
633 minMagThresh = 0.0F;
634 }
635
636 #if 0
637 /* DEBUG CODE: Verify that lambda[] is monotonic.
638 * We can't really use this because the inaccuracy in the LOG2 function
639 * causes this test to fail, yet the resulting texturing is correct.
640 */
641 if (n > 1) {
642 GLuint i;
643 printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
644 if (lambda[0] >= lambda[n-1]) { /* decreasing */
645 for (i = 0; i < n - 1; i++) {
646 ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
647 }
648 }
649 else { /* increasing */
650 for (i = 0; i < n - 1; i++) {
651 ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
652 }
653 }
654 }
655 #endif /* DEBUG */
656
657 if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
658 /* magnification for whole span */
659 *magStart = 0;
660 *magEnd = n;
661 *minStart = *minEnd = 0;
662 }
663 else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
664 /* minification for whole span */
665 *minStart = 0;
666 *minEnd = n;
667 *magStart = *magEnd = 0;
668 }
669 else {
670 /* a mix of minification and magnification */
671 GLuint i;
672 if (lambda[0] > minMagThresh) {
673 /* start with minification */
674 for (i = 1; i < n; i++) {
675 if (lambda[i] <= minMagThresh)
676 break;
677 }
678 *minStart = 0;
679 *minEnd = i;
680 *magStart = i;
681 *magEnd = n;
682 }
683 else {
684 /* start with magnification */
685 for (i = 1; i < n; i++) {
686 if (lambda[i] > minMagThresh)
687 break;
688 }
689 *magStart = 0;
690 *magEnd = i;
691 *minStart = i;
692 *minEnd = n;
693 }
694 }
695
696 #if 0
697 /* Verify the min/mag Start/End values
698 * We don't use this either (see above)
699 */
700 {
701 GLint i;
702 for (i = 0; i < n; i++) {
703 if (lambda[i] > minMagThresh) {
704 /* minification */
705 ASSERT(i >= *minStart);
706 ASSERT(i < *minEnd);
707 }
708 else {
709 /* magnification */
710 ASSERT(i >= *magStart);
711 ASSERT(i < *magEnd);
712 }
713 }
714 }
715 #endif
716 }
717
718
719 /**
720 * When we sample the border color, it must be interpreted according to
721 * the base texture format. Ex: if the texture base format it GL_ALPHA,
722 * we return (0,0,0,BorderAlpha).
723 */
724 static inline void
725 get_border_color(const struct gl_texture_object *tObj,
726 const struct gl_texture_image *img,
727 GLfloat rgba[4])
728 {
729 switch (img->_BaseFormat) {
730 case GL_RGB:
731 rgba[0] = tObj->Sampler.BorderColor.f[0];
732 rgba[1] = tObj->Sampler.BorderColor.f[1];
733 rgba[2] = tObj->Sampler.BorderColor.f[2];
734 rgba[3] = 1.0F;
735 break;
736 case GL_ALPHA:
737 rgba[0] = rgba[1] = rgba[2] = 0.0;
738 rgba[3] = tObj->Sampler.BorderColor.f[3];
739 break;
740 case GL_LUMINANCE:
741 rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0];
742 rgba[3] = 1.0;
743 break;
744 case GL_LUMINANCE_ALPHA:
745 rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0];
746 rgba[3] = tObj->Sampler.BorderColor.f[3];
747 break;
748 case GL_INTENSITY:
749 rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->Sampler.BorderColor.f[0];
750 break;
751 default:
752 COPY_4V(rgba, tObj->Sampler.BorderColor.f);
753 break;
754 }
755 }
756
757
758 /**********************************************************************/
759 /* 1-D Texture Sampling Functions */
760 /**********************************************************************/
761
762 /**
763 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
764 */
765 static inline void
766 sample_1d_nearest(struct gl_context *ctx,
767 const struct gl_texture_object *tObj,
768 const struct gl_texture_image *img,
769 const GLfloat texcoord[4], GLfloat rgba[4])
770 {
771 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
772 const GLint width = img->Width2; /* without border, power of two */
773 GLint i;
774 i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]);
775 /* skip over the border, if any */
776 i += img->Border;
777 if (i < 0 || i >= (GLint) img->Width) {
778 /* Need this test for GL_CLAMP_TO_BORDER mode */
779 get_border_color(tObj, img, rgba);
780 }
781 else {
782 swImg->FetchTexel(swImg, i, 0, 0, rgba);
783 }
784 }
785
786
787 /**
788 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
789 */
790 static inline void
791 sample_1d_linear(struct gl_context *ctx,
792 const struct gl_texture_object *tObj,
793 const struct gl_texture_image *img,
794 const GLfloat texcoord[4], GLfloat rgba[4])
795 {
796 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
797 const GLint width = img->Width2;
798 GLint i0, i1;
799 GLbitfield useBorderColor = 0x0;
800 GLfloat a;
801 GLfloat t0[4], t1[4]; /* texels */
802
803 linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a);
804
805 if (img->Border) {
806 i0 += img->Border;
807 i1 += img->Border;
808 }
809 else {
810 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
811 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
812 }
813
814 /* fetch texel colors */
815 if (useBorderColor & I0BIT) {
816 get_border_color(tObj, img, t0);
817 }
818 else {
819 swImg->FetchTexel(swImg, i0, 0, 0, t0);
820 }
821 if (useBorderColor & I1BIT) {
822 get_border_color(tObj, img, t1);
823 }
824 else {
825 swImg->FetchTexel(swImg, i1, 0, 0, t1);
826 }
827
828 lerp_rgba(rgba, a, t0, t1);
829 }
830
831
832 static void
833 sample_1d_nearest_mipmap_nearest(struct gl_context *ctx,
834 const struct gl_texture_object *tObj,
835 GLuint n, const GLfloat texcoord[][4],
836 const GLfloat lambda[], GLfloat rgba[][4])
837 {
838 GLuint i;
839 ASSERT(lambda != NULL);
840 for (i = 0; i < n; i++) {
841 GLint level = nearest_mipmap_level(tObj, lambda[i]);
842 sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
843 }
844 }
845
846
847 static void
848 sample_1d_linear_mipmap_nearest(struct gl_context *ctx,
849 const struct gl_texture_object *tObj,
850 GLuint n, const GLfloat texcoord[][4],
851 const GLfloat lambda[], GLfloat rgba[][4])
852 {
853 GLuint i;
854 ASSERT(lambda != NULL);
855 for (i = 0; i < n; i++) {
856 GLint level = nearest_mipmap_level(tObj, lambda[i]);
857 sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
858 }
859 }
860
861
862 static void
863 sample_1d_nearest_mipmap_linear(struct gl_context *ctx,
864 const struct gl_texture_object *tObj,
865 GLuint n, const GLfloat texcoord[][4],
866 const GLfloat lambda[], GLfloat rgba[][4])
867 {
868 GLuint i;
869 ASSERT(lambda != NULL);
870 for (i = 0; i < n; i++) {
871 GLint level = linear_mipmap_level(tObj, lambda[i]);
872 if (level >= tObj->_MaxLevel) {
873 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
874 texcoord[i], rgba[i]);
875 }
876 else {
877 GLfloat t0[4], t1[4];
878 const GLfloat f = FRAC(lambda[i]);
879 sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
880 sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
881 lerp_rgba(rgba[i], f, t0, t1);
882 }
883 }
884 }
885
886
887 static void
888 sample_1d_linear_mipmap_linear(struct gl_context *ctx,
889 const struct gl_texture_object *tObj,
890 GLuint n, const GLfloat texcoord[][4],
891 const GLfloat lambda[], GLfloat rgba[][4])
892 {
893 GLuint i;
894 ASSERT(lambda != NULL);
895 for (i = 0; i < n; i++) {
896 GLint level = linear_mipmap_level(tObj, lambda[i]);
897 if (level >= tObj->_MaxLevel) {
898 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
899 texcoord[i], rgba[i]);
900 }
901 else {
902 GLfloat t0[4], t1[4];
903 const GLfloat f = FRAC(lambda[i]);
904 sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
905 sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
906 lerp_rgba(rgba[i], f, t0, t1);
907 }
908 }
909 }
910
911
912 /** Sample 1D texture, nearest filtering for both min/magnification */
913 static void
914 sample_nearest_1d( struct gl_context *ctx,
915 const struct gl_texture_object *tObj, GLuint n,
916 const GLfloat texcoords[][4], const GLfloat lambda[],
917 GLfloat rgba[][4] )
918 {
919 GLuint i;
920 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
921 (void) lambda;
922 for (i = 0; i < n; i++) {
923 sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
924 }
925 }
926
927
928 /** Sample 1D texture, linear filtering for both min/magnification */
929 static void
930 sample_linear_1d( struct gl_context *ctx,
931 const struct gl_texture_object *tObj, GLuint n,
932 const GLfloat texcoords[][4], const GLfloat lambda[],
933 GLfloat rgba[][4] )
934 {
935 GLuint i;
936 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
937 (void) lambda;
938 for (i = 0; i < n; i++) {
939 sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
940 }
941 }
942
943
944 /** Sample 1D texture, using lambda to choose between min/magnification */
945 static void
946 sample_lambda_1d( struct gl_context *ctx,
947 const struct gl_texture_object *tObj, GLuint n,
948 const GLfloat texcoords[][4],
949 const GLfloat lambda[], GLfloat rgba[][4] )
950 {
951 GLuint minStart, minEnd; /* texels with minification */
952 GLuint magStart, magEnd; /* texels with magnification */
953 GLuint i;
954
955 ASSERT(lambda != NULL);
956 compute_min_mag_ranges(tObj, n, lambda,
957 &minStart, &minEnd, &magStart, &magEnd);
958
959 if (minStart < minEnd) {
960 /* do the minified texels */
961 const GLuint m = minEnd - minStart;
962 switch (tObj->Sampler.MinFilter) {
963 case GL_NEAREST:
964 for (i = minStart; i < minEnd; i++)
965 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
966 texcoords[i], rgba[i]);
967 break;
968 case GL_LINEAR:
969 for (i = minStart; i < minEnd; i++)
970 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
971 texcoords[i], rgba[i]);
972 break;
973 case GL_NEAREST_MIPMAP_NEAREST:
974 sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
975 lambda + minStart, rgba + minStart);
976 break;
977 case GL_LINEAR_MIPMAP_NEAREST:
978 sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
979 lambda + minStart, rgba + minStart);
980 break;
981 case GL_NEAREST_MIPMAP_LINEAR:
982 sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
983 lambda + minStart, rgba + minStart);
984 break;
985 case GL_LINEAR_MIPMAP_LINEAR:
986 sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
987 lambda + minStart, rgba + minStart);
988 break;
989 default:
990 _mesa_problem(ctx, "Bad min filter in sample_1d_texture");
991 return;
992 }
993 }
994
995 if (magStart < magEnd) {
996 /* do the magnified texels */
997 switch (tObj->Sampler.MagFilter) {
998 case GL_NEAREST:
999 for (i = magStart; i < magEnd; i++)
1000 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1001 texcoords[i], rgba[i]);
1002 break;
1003 case GL_LINEAR:
1004 for (i = magStart; i < magEnd; i++)
1005 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1006 texcoords[i], rgba[i]);
1007 break;
1008 default:
1009 _mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
1010 return;
1011 }
1012 }
1013 }
1014
1015
1016 /**********************************************************************/
1017 /* 2-D Texture Sampling Functions */
1018 /**********************************************************************/
1019
1020
1021 /**
1022 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
1023 */
1024 static inline void
1025 sample_2d_nearest(struct gl_context *ctx,
1026 const struct gl_texture_object *tObj,
1027 const struct gl_texture_image *img,
1028 const GLfloat texcoord[4],
1029 GLfloat rgba[])
1030 {
1031 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1032 const GLint width = img->Width2; /* without border, power of two */
1033 const GLint height = img->Height2; /* without border, power of two */
1034 GLint i, j;
1035 (void) ctx;
1036
1037 i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]);
1038 j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]);
1039
1040 /* skip over the border, if any */
1041 i += img->Border;
1042 j += img->Border;
1043
1044 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
1045 /* Need this test for GL_CLAMP_TO_BORDER mode */
1046 get_border_color(tObj, img, rgba);
1047 }
1048 else {
1049 swImg->FetchTexel(swImg, i, j, 0, rgba);
1050 }
1051 }
1052
1053
1054 /**
1055 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
1056 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
1057 */
1058 static inline void
1059 sample_2d_linear(struct gl_context *ctx,
1060 const struct gl_texture_object *tObj,
1061 const struct gl_texture_image *img,
1062 const GLfloat texcoord[4],
1063 GLfloat rgba[])
1064 {
1065 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1066 const GLint width = img->Width2;
1067 const GLint height = img->Height2;
1068 GLint i0, j0, i1, j1;
1069 GLbitfield useBorderColor = 0x0;
1070 GLfloat a, b;
1071 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1072
1073 linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a);
1074 linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b);
1075
1076 if (img->Border) {
1077 i0 += img->Border;
1078 i1 += img->Border;
1079 j0 += img->Border;
1080 j1 += img->Border;
1081 }
1082 else {
1083 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1084 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1085 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1086 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1087 }
1088
1089 /* fetch four texel colors */
1090 if (useBorderColor & (I0BIT | J0BIT)) {
1091 get_border_color(tObj, img, t00);
1092 }
1093 else {
1094 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1095 }
1096 if (useBorderColor & (I1BIT | J0BIT)) {
1097 get_border_color(tObj, img, t10);
1098 }
1099 else {
1100 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1101 }
1102 if (useBorderColor & (I0BIT | J1BIT)) {
1103 get_border_color(tObj, img, t01);
1104 }
1105 else {
1106 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1107 }
1108 if (useBorderColor & (I1BIT | J1BIT)) {
1109 get_border_color(tObj, img, t11);
1110 }
1111 else {
1112 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1113 }
1114
1115 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
1116 }
1117
1118
1119 /**
1120 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1121 * We don't have to worry about the texture border.
1122 */
1123 static inline void
1124 sample_2d_linear_repeat(struct gl_context *ctx,
1125 const struct gl_texture_object *tObj,
1126 const struct gl_texture_image *img,
1127 const GLfloat texcoord[4],
1128 GLfloat rgba[])
1129 {
1130 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1131 const GLint width = img->Width2;
1132 const GLint height = img->Height2;
1133 GLint i0, j0, i1, j1;
1134 GLfloat wi, wj;
1135 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1136
1137 (void) ctx;
1138
1139 ASSERT(tObj->Sampler.WrapS == GL_REPEAT);
1140 ASSERT(tObj->Sampler.WrapT == GL_REPEAT);
1141 ASSERT(img->Border == 0);
1142 ASSERT(swImg->_IsPowerOfTwo);
1143
1144 linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi);
1145 linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj);
1146
1147 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1148 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1149 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1150 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1151
1152 lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11);
1153 }
1154
1155
1156 static void
1157 sample_2d_nearest_mipmap_nearest(struct gl_context *ctx,
1158 const struct gl_texture_object *tObj,
1159 GLuint n, const GLfloat texcoord[][4],
1160 const GLfloat lambda[], GLfloat rgba[][4])
1161 {
1162 GLuint i;
1163 for (i = 0; i < n; i++) {
1164 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1165 sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1166 }
1167 }
1168
1169
1170 static void
1171 sample_2d_linear_mipmap_nearest(struct gl_context *ctx,
1172 const struct gl_texture_object *tObj,
1173 GLuint n, const GLfloat texcoord[][4],
1174 const GLfloat lambda[], GLfloat rgba[][4])
1175 {
1176 GLuint i;
1177 ASSERT(lambda != NULL);
1178 for (i = 0; i < n; i++) {
1179 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1180 sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1181 }
1182 }
1183
1184
1185 static void
1186 sample_2d_nearest_mipmap_linear(struct gl_context *ctx,
1187 const struct gl_texture_object *tObj,
1188 GLuint n, const GLfloat texcoord[][4],
1189 const GLfloat lambda[], GLfloat rgba[][4])
1190 {
1191 GLuint i;
1192 ASSERT(lambda != NULL);
1193 for (i = 0; i < n; i++) {
1194 GLint level = linear_mipmap_level(tObj, lambda[i]);
1195 if (level >= tObj->_MaxLevel) {
1196 sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1197 texcoord[i], rgba[i]);
1198 }
1199 else {
1200 GLfloat t0[4], t1[4]; /* texels */
1201 const GLfloat f = FRAC(lambda[i]);
1202 sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1203 sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1204 lerp_rgba(rgba[i], f, t0, t1);
1205 }
1206 }
1207 }
1208
1209
1210 static void
1211 sample_2d_linear_mipmap_linear( struct gl_context *ctx,
1212 const struct gl_texture_object *tObj,
1213 GLuint n, const GLfloat texcoord[][4],
1214 const GLfloat lambda[], GLfloat rgba[][4] )
1215 {
1216 GLuint i;
1217 ASSERT(lambda != NULL);
1218 for (i = 0; i < n; i++) {
1219 GLint level = linear_mipmap_level(tObj, lambda[i]);
1220 if (level >= tObj->_MaxLevel) {
1221 sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1222 texcoord[i], rgba[i]);
1223 }
1224 else {
1225 GLfloat t0[4], t1[4]; /* texels */
1226 const GLfloat f = FRAC(lambda[i]);
1227 sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1228 sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1229 lerp_rgba(rgba[i], f, t0, t1);
1230 }
1231 }
1232 }
1233
1234
1235 static void
1236 sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx,
1237 const struct gl_texture_object *tObj,
1238 GLuint n, const GLfloat texcoord[][4],
1239 const GLfloat lambda[], GLfloat rgba[][4])
1240 {
1241 GLuint i;
1242 ASSERT(lambda != NULL);
1243 ASSERT(tObj->Sampler.WrapS == GL_REPEAT);
1244 ASSERT(tObj->Sampler.WrapT == GL_REPEAT);
1245 for (i = 0; i < n; i++) {
1246 GLint level = linear_mipmap_level(tObj, lambda[i]);
1247 if (level >= tObj->_MaxLevel) {
1248 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1249 texcoord[i], rgba[i]);
1250 }
1251 else {
1252 GLfloat t0[4], t1[4]; /* texels */
1253 const GLfloat f = FRAC(lambda[i]);
1254 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ],
1255 texcoord[i], t0);
1256 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1],
1257 texcoord[i], t1);
1258 lerp_rgba(rgba[i], f, t0, t1);
1259 }
1260 }
1261 }
1262
1263
1264 /** Sample 2D texture, nearest filtering for both min/magnification */
1265 static void
1266 sample_nearest_2d(struct gl_context *ctx,
1267 const struct gl_texture_object *tObj, GLuint n,
1268 const GLfloat texcoords[][4],
1269 const GLfloat lambda[], GLfloat rgba[][4])
1270 {
1271 GLuint i;
1272 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1273 (void) lambda;
1274 for (i = 0; i < n; i++) {
1275 sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
1276 }
1277 }
1278
1279
1280 /** Sample 2D texture, linear filtering for both min/magnification */
1281 static void
1282 sample_linear_2d(struct gl_context *ctx,
1283 const struct gl_texture_object *tObj, GLuint n,
1284 const GLfloat texcoords[][4],
1285 const GLfloat lambda[], GLfloat rgba[][4])
1286 {
1287 GLuint i;
1288 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1289 const struct swrast_texture_image *swImg = swrast_texture_image_const(image);
1290 (void) lambda;
1291 if (tObj->Sampler.WrapS == GL_REPEAT &&
1292 tObj->Sampler.WrapT == GL_REPEAT &&
1293 swImg->_IsPowerOfTwo &&
1294 image->Border == 0) {
1295 for (i = 0; i < n; i++) {
1296 sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]);
1297 }
1298 }
1299 else {
1300 for (i = 0; i < n; i++) {
1301 sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
1302 }
1303 }
1304 }
1305
1306
1307 /**
1308 * Optimized 2-D texture sampling:
1309 * S and T wrap mode == GL_REPEAT
1310 * GL_NEAREST min/mag filter
1311 * No border,
1312 * RowStride == Width,
1313 * Format = GL_RGB
1314 */
1315 static void
1316 opt_sample_rgb_2d(struct gl_context *ctx,
1317 const struct gl_texture_object *tObj,
1318 GLuint n, const GLfloat texcoords[][4],
1319 const GLfloat lambda[], GLfloat rgba[][4])
1320 {
1321 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1322 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1323 const GLfloat width = (GLfloat) img->Width;
1324 const GLfloat height = (GLfloat) img->Height;
1325 const GLint colMask = img->Width - 1;
1326 const GLint rowMask = img->Height - 1;
1327 const GLint shift = img->WidthLog2;
1328 GLuint k;
1329 (void) ctx;
1330 (void) lambda;
1331 ASSERT(tObj->Sampler.WrapS==GL_REPEAT);
1332 ASSERT(tObj->Sampler.WrapT==GL_REPEAT);
1333 ASSERT(img->Border==0);
1334 ASSERT(img->TexFormat == MESA_FORMAT_RGB888);
1335 ASSERT(swImg->_IsPowerOfTwo);
1336 (void) swImg;
1337
1338 for (k=0; k<n; k++) {
1339 GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
1340 GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
1341 GLint pos = (j << shift) | i;
1342 GLubyte *texel = swImg->Map + 3 * pos;
1343 rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
1344 rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
1345 rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
1346 rgba[k][ACOMP] = 1.0F;
1347 }
1348 }
1349
1350
1351 /**
1352 * Optimized 2-D texture sampling:
1353 * S and T wrap mode == GL_REPEAT
1354 * GL_NEAREST min/mag filter
1355 * No border
1356 * RowStride == Width,
1357 * Format = GL_RGBA
1358 */
1359 static void
1360 opt_sample_rgba_2d(struct gl_context *ctx,
1361 const struct gl_texture_object *tObj,
1362 GLuint n, const GLfloat texcoords[][4],
1363 const GLfloat lambda[], GLfloat rgba[][4])
1364 {
1365 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1366 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1367 const GLfloat width = (GLfloat) img->Width;
1368 const GLfloat height = (GLfloat) img->Height;
1369 const GLint colMask = img->Width - 1;
1370 const GLint rowMask = img->Height - 1;
1371 const GLint shift = img->WidthLog2;
1372 GLuint i;
1373 (void) ctx;
1374 (void) lambda;
1375 ASSERT(tObj->Sampler.WrapS==GL_REPEAT);
1376 ASSERT(tObj->Sampler.WrapT==GL_REPEAT);
1377 ASSERT(img->Border==0);
1378 ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888);
1379 ASSERT(swImg->_IsPowerOfTwo);
1380 (void) swImg;
1381
1382 for (i = 0; i < n; i++) {
1383 const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
1384 const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
1385 const GLint pos = (row << shift) | col;
1386 const GLuint texel = *((GLuint *) swImg->Map + pos);
1387 rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) );
1388 rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
1389 rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff );
1390 rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff );
1391 }
1392 }
1393
1394
1395 /** Sample 2D texture, using lambda to choose between min/magnification */
1396 static void
1397 sample_lambda_2d(struct gl_context *ctx,
1398 const struct gl_texture_object *tObj,
1399 GLuint n, const GLfloat texcoords[][4],
1400 const GLfloat lambda[], GLfloat rgba[][4])
1401 {
1402 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1403 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1404 GLuint minStart, minEnd; /* texels with minification */
1405 GLuint magStart, magEnd; /* texels with magnification */
1406
1407 const GLboolean repeatNoBorderPOT = (tObj->Sampler.WrapS == GL_REPEAT)
1408 && (tObj->Sampler.WrapT == GL_REPEAT)
1409 && (tImg->Border == 0 && (tImg->Width == swImg->RowStride))
1410 && swImg->_IsPowerOfTwo;
1411
1412 ASSERT(lambda != NULL);
1413 compute_min_mag_ranges(tObj, n, lambda,
1414 &minStart, &minEnd, &magStart, &magEnd);
1415
1416 if (minStart < minEnd) {
1417 /* do the minified texels */
1418 const GLuint m = minEnd - minStart;
1419 switch (tObj->Sampler.MinFilter) {
1420 case GL_NEAREST:
1421 if (repeatNoBorderPOT) {
1422 switch (tImg->TexFormat) {
1423 case MESA_FORMAT_RGB888:
1424 opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart,
1425 NULL, rgba + minStart);
1426 break;
1427 case MESA_FORMAT_RGBA8888:
1428 opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart,
1429 NULL, rgba + minStart);
1430 break;
1431 default:
1432 sample_nearest_2d(ctx, tObj, m, texcoords + minStart,
1433 NULL, rgba + minStart );
1434 }
1435 }
1436 else {
1437 sample_nearest_2d(ctx, tObj, m, texcoords + minStart,
1438 NULL, rgba + minStart);
1439 }
1440 break;
1441 case GL_LINEAR:
1442 sample_linear_2d(ctx, tObj, m, texcoords + minStart,
1443 NULL, rgba + minStart);
1444 break;
1445 case GL_NEAREST_MIPMAP_NEAREST:
1446 sample_2d_nearest_mipmap_nearest(ctx, tObj, m,
1447 texcoords + minStart,
1448 lambda + minStart, rgba + minStart);
1449 break;
1450 case GL_LINEAR_MIPMAP_NEAREST:
1451 sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
1452 lambda + minStart, rgba + minStart);
1453 break;
1454 case GL_NEAREST_MIPMAP_LINEAR:
1455 sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1456 lambda + minStart, rgba + minStart);
1457 break;
1458 case GL_LINEAR_MIPMAP_LINEAR:
1459 if (repeatNoBorderPOT)
1460 sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m,
1461 texcoords + minStart, lambda + minStart, rgba + minStart);
1462 else
1463 sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1464 lambda + minStart, rgba + minStart);
1465 break;
1466 default:
1467 _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1468 return;
1469 }
1470 }
1471
1472 if (magStart < magEnd) {
1473 /* do the magnified texels */
1474 const GLuint m = magEnd - magStart;
1475
1476 switch (tObj->Sampler.MagFilter) {
1477 case GL_NEAREST:
1478 if (repeatNoBorderPOT) {
1479 switch (tImg->TexFormat) {
1480 case MESA_FORMAT_RGB888:
1481 opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart,
1482 NULL, rgba + magStart);
1483 break;
1484 case MESA_FORMAT_RGBA8888:
1485 opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart,
1486 NULL, rgba + magStart);
1487 break;
1488 default:
1489 sample_nearest_2d(ctx, tObj, m, texcoords + magStart,
1490 NULL, rgba + magStart );
1491 }
1492 }
1493 else {
1494 sample_nearest_2d(ctx, tObj, m, texcoords + magStart,
1495 NULL, rgba + magStart);
1496 }
1497 break;
1498 case GL_LINEAR:
1499 sample_linear_2d(ctx, tObj, m, texcoords + magStart,
1500 NULL, rgba + magStart);
1501 break;
1502 default:
1503 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1504 break;
1505 }
1506 }
1507 }
1508
1509
1510 /* For anisotropic filtering */
1511 #define WEIGHT_LUT_SIZE 1024
1512
1513 static GLfloat *weightLut = NULL;
1514
1515 /**
1516 * Creates the look-up table used to speed-up EWA sampling
1517 */
1518 static void
1519 create_filter_table(void)
1520 {
1521 GLuint i;
1522 if (!weightLut) {
1523 weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
1524
1525 for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
1526 GLfloat alpha = 2;
1527 GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
1528 GLfloat weight = (GLfloat) exp(-alpha * r2);
1529 weightLut[i] = weight;
1530 }
1531 }
1532 }
1533
1534
1535 /**
1536 * Elliptical weighted average (EWA) filter for producing high quality
1537 * anisotropic filtered results.
1538 * Based on the Higher Quality Elliptical Weighted Avarage Filter
1539 * published by Paul S. Heckbert in his Master's Thesis
1540 * "Fundamentals of Texture Mapping and Image Warping" (1989)
1541 */
1542 static void
1543 sample_2d_ewa(struct gl_context *ctx,
1544 const struct gl_texture_object *tObj,
1545 const GLfloat texcoord[4],
1546 const GLfloat dudx, const GLfloat dvdx,
1547 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1548 GLfloat rgba[])
1549 {
1550 GLint level = lod > 0 ? lod : 0;
1551 GLfloat scaling = 1.0 / (1 << level);
1552 const struct gl_texture_image *img = tObj->Image[0][level];
1553 const struct gl_texture_image *mostDetailedImage =
1554 tObj->Image[0][tObj->BaseLevel];
1555 const struct swrast_texture_image *swImg =
1556 swrast_texture_image_const(mostDetailedImage);
1557 GLfloat tex_u=-0.5 + texcoord[0] * swImg->WidthScale * scaling;
1558 GLfloat tex_v=-0.5 + texcoord[1] * swImg->HeightScale * scaling;
1559
1560 GLfloat ux = dudx * scaling;
1561 GLfloat vx = dvdx * scaling;
1562 GLfloat uy = dudy * scaling;
1563 GLfloat vy = dvdy * scaling;
1564
1565 /* compute ellipse coefficients to bound the region:
1566 * A*x*x + B*x*y + C*y*y = F.
1567 */
1568 GLfloat A = vx*vx+vy*vy+1;
1569 GLfloat B = -2*(ux*vx+uy*vy);
1570 GLfloat C = ux*ux+uy*uy+1;
1571 GLfloat F = A*C-B*B/4.0;
1572
1573 /* check if it is an ellipse */
1574 /* ASSERT(F > 0.0); */
1575
1576 /* Compute the ellipse's (u,v) bounding box in texture space */
1577 GLfloat d = -B*B+4.0*C*A;
1578 GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with */
1579 GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */
1580
1581 GLint u0 = floor(tex_u - box_u);
1582 GLint u1 = ceil (tex_u + box_u);
1583 GLint v0 = floor(tex_v - box_v);
1584 GLint v1 = ceil (tex_v + box_v);
1585
1586 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1587 GLfloat newCoord[2];
1588 GLfloat den = 0.0F;
1589 GLfloat ddq;
1590 GLfloat U = u0 - tex_u;
1591 GLint v;
1592
1593 /* Scale ellipse formula to directly index the Filter Lookup Table.
1594 * i.e. scale so that F = WEIGHT_LUT_SIZE-1
1595 */
1596 double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F;
1597 A *= formScale;
1598 B *= formScale;
1599 C *= formScale;
1600 /* F *= formScale; */ /* no need to scale F as we don't use it below here */
1601
1602 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
1603 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
1604 * value, q, is less than F, we're inside the ellipse
1605 */
1606 ddq = 2 * A;
1607 for (v = v0; v <= v1; ++v) {
1608 GLfloat V = v - tex_v;
1609 GLfloat dq = A * (2 * U + 1) + B * V;
1610 GLfloat q = (C * V + B * U) * V + A * U * U;
1611
1612 GLint u;
1613 for (u = u0; u <= u1; ++u) {
1614 /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
1615 if (q < WEIGHT_LUT_SIZE) {
1616 /* as a LUT is used, q must never be negative;
1617 * should not happen, though
1618 */
1619 const GLint qClamped = q >= 0.0F ? q : 0;
1620 GLfloat weight = weightLut[qClamped];
1621
1622 newCoord[0] = u / ((GLfloat) img->Width2);
1623 newCoord[1] = v / ((GLfloat) img->Height2);
1624
1625 sample_2d_nearest(ctx, tObj, img, newCoord, rgba);
1626 num[0] += weight * rgba[0];
1627 num[1] += weight * rgba[1];
1628 num[2] += weight * rgba[2];
1629 num[3] += weight * rgba[3];
1630
1631 den += weight;
1632 }
1633 q += dq;
1634 dq += ddq;
1635 }
1636 }
1637
1638 if (den <= 0.0F) {
1639 /* Reaching this place would mean
1640 * that no pixels intersected the ellipse.
1641 * This should never happen because
1642 * the filter we use always
1643 * intersects at least one pixel.
1644 */
1645
1646 /*rgba[0]=0;
1647 rgba[1]=0;
1648 rgba[2]=0;
1649 rgba[3]=0;*/
1650 /* not enough pixels in resampling, resort to direct interpolation */
1651 sample_2d_linear(ctx, tObj, img, texcoord, rgba);
1652 return;
1653 }
1654
1655 rgba[0] = num[0] / den;
1656 rgba[1] = num[1] / den;
1657 rgba[2] = num[2] / den;
1658 rgba[3] = num[3] / den;
1659 }
1660
1661
1662 /**
1663 * Anisotropic filtering using footprint assembly as outlined in the
1664 * EXT_texture_filter_anisotropic spec:
1665 * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
1666 * Faster than EWA but has less quality (more aliasing effects)
1667 */
1668 static void
1669 sample_2d_footprint(struct gl_context *ctx,
1670 const struct gl_texture_object *tObj,
1671 const GLfloat texcoord[4],
1672 const GLfloat dudx, const GLfloat dvdx,
1673 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1674 GLfloat rgba[])
1675 {
1676 GLint level = lod > 0 ? lod : 0;
1677 GLfloat scaling = 1.0F / (1 << level);
1678 const struct gl_texture_image *img = tObj->Image[0][level];
1679
1680 GLfloat ux = dudx * scaling;
1681 GLfloat vx = dvdx * scaling;
1682 GLfloat uy = dudy * scaling;
1683 GLfloat vy = dvdy * scaling;
1684
1685 GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
1686 GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
1687
1688 GLint numSamples;
1689 GLfloat ds;
1690 GLfloat dt;
1691
1692 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1693 GLfloat newCoord[2];
1694 GLint s;
1695
1696 /* Calculate the per anisotropic sample offsets in s,t space. */
1697 if (Px2 > Py2) {
1698 numSamples = ceil(SQRTF(Px2));
1699 ds = ux / ((GLfloat) img->Width2);
1700 dt = vx / ((GLfloat) img->Height2);
1701 }
1702 else {
1703 numSamples = ceil(SQRTF(Py2));
1704 ds = uy / ((GLfloat) img->Width2);
1705 dt = vy / ((GLfloat) img->Height2);
1706 }
1707
1708 for (s = 0; s<numSamples; s++) {
1709 newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5);
1710 newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5);
1711
1712 sample_2d_linear(ctx, tObj, img, newCoord, rgba);
1713 num[0] += rgba[0];
1714 num[1] += rgba[1];
1715 num[2] += rgba[2];
1716 num[3] += rgba[3];
1717 }
1718
1719 rgba[0] = num[0] / numSamples;
1720 rgba[1] = num[1] / numSamples;
1721 rgba[2] = num[2] / numSamples;
1722 rgba[3] = num[3] / numSamples;
1723 }
1724
1725
1726 /**
1727 * Returns the index of the specified texture object in the
1728 * gl_context texture unit array.
1729 */
1730 static inline GLuint
1731 texture_unit_index(const struct gl_context *ctx,
1732 const struct gl_texture_object *tObj)
1733 {
1734 const GLuint maxUnit
1735 = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
1736 GLuint u;
1737
1738 /* XXX CoordUnits vs. ImageUnits */
1739 for (u = 0; u < maxUnit; u++) {
1740 if (ctx->Texture.Unit[u]._Current == tObj)
1741 break; /* found */
1742 }
1743 if (u >= maxUnit)
1744 u = 0; /* not found, use 1st one; should never happen */
1745
1746 return u;
1747 }
1748
1749
1750 /**
1751 * Sample 2D texture using an anisotropic filter.
1752 * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
1753 * the lambda float array but a "hidden" SWspan struct which is required
1754 * by this function but is not available in the texture_sample_func signature.
1755 * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
1756 * this function is called.
1757 */
1758 static void
1759 sample_lambda_2d_aniso(struct gl_context *ctx,
1760 const struct gl_texture_object *tObj,
1761 GLuint n, const GLfloat texcoords[][4],
1762 const GLfloat lambda_iso[], GLfloat rgba[][4])
1763 {
1764 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1765 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1766 const GLfloat maxEccentricity =
1767 tObj->Sampler.MaxAnisotropy * tObj->Sampler.MaxAnisotropy;
1768
1769 /* re-calculate the lambda values so that they are usable with anisotropic
1770 * filtering
1771 */
1772 SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
1773
1774 /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
1775 * in swrast/s_span.c
1776 */
1777
1778 /* find the texture unit index by looking up the current texture object
1779 * from the context list of available texture objects.
1780 */
1781 const GLuint u = texture_unit_index(ctx, tObj);
1782 const GLuint attr = FRAG_ATTRIB_TEX0 + u;
1783 GLfloat texW, texH;
1784
1785 const GLfloat dsdx = span->attrStepX[attr][0];
1786 const GLfloat dsdy = span->attrStepY[attr][0];
1787 const GLfloat dtdx = span->attrStepX[attr][1];
1788 const GLfloat dtdy = span->attrStepY[attr][1];
1789 const GLfloat dqdx = span->attrStepX[attr][3];
1790 const GLfloat dqdy = span->attrStepY[attr][3];
1791 GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
1792 GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
1793 GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
1794
1795 GLuint i;
1796
1797 /* on first access create the lookup table containing the filter weights. */
1798 if (!weightLut) {
1799 create_filter_table();
1800 }
1801
1802 texW = swImg->WidthScale;
1803 texH = swImg->HeightScale;
1804
1805 for (i = 0; i < n; i++) {
1806 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
1807
1808 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
1809 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
1810 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
1811 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
1812
1813 /* note: instead of working with Px and Py, we will use the
1814 * squared length instead, to avoid sqrt.
1815 */
1816 GLfloat Px2 = dudx * dudx + dvdx * dvdx;
1817 GLfloat Py2 = dudy * dudy + dvdy * dvdy;
1818
1819 GLfloat Pmax2;
1820 GLfloat Pmin2;
1821 GLfloat e;
1822 GLfloat lod;
1823
1824 s += dsdx;
1825 t += dtdx;
1826 q += dqdx;
1827
1828 if (Px2 < Py2) {
1829 Pmax2 = Py2;
1830 Pmin2 = Px2;
1831 }
1832 else {
1833 Pmax2 = Px2;
1834 Pmin2 = Py2;
1835 }
1836
1837 /* if the eccentricity of the ellipse is too big, scale up the shorter
1838 * of the two vectors to limit the maximum amount of work per pixel
1839 */
1840 e = Pmax2 / Pmin2;
1841 if (e > maxEccentricity) {
1842 /* GLfloat s=e / maxEccentricity;
1843 minor[0] *= s;
1844 minor[1] *= s;
1845 Pmin2 *= s; */
1846 Pmin2 = Pmax2 / maxEccentricity;
1847 }
1848
1849 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
1850 * this since 0.5*log(x) = log(sqrt(x))
1851 */
1852 lod = 0.5 * LOG2(Pmin2);
1853
1854 /* If the ellipse covers the whole image, we can
1855 * simply return the average of the whole image.
1856 */
1857 if (lod >= tObj->_MaxLevel) {
1858 sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1859 texcoords[i], rgba[i]);
1860 }
1861 else {
1862 /* don't bother interpolating between multiple LODs; it doesn't
1863 * seem to be worth the extra running time.
1864 */
1865 sample_2d_ewa(ctx, tObj, texcoords[i],
1866 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
1867
1868 /* unused: */
1869 (void) sample_2d_footprint;
1870 /*
1871 sample_2d_footprint(ctx, tObj, texcoords[i],
1872 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
1873 */
1874 }
1875 }
1876 }
1877
1878
1879
1880 /**********************************************************************/
1881 /* 3-D Texture Sampling Functions */
1882 /**********************************************************************/
1883
1884 /**
1885 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1886 */
1887 static inline void
1888 sample_3d_nearest(struct gl_context *ctx,
1889 const struct gl_texture_object *tObj,
1890 const struct gl_texture_image *img,
1891 const GLfloat texcoord[4],
1892 GLfloat rgba[4])
1893 {
1894 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1895 const GLint width = img->Width2; /* without border, power of two */
1896 const GLint height = img->Height2; /* without border, power of two */
1897 const GLint depth = img->Depth2; /* without border, power of two */
1898 GLint i, j, k;
1899 (void) ctx;
1900
1901 i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]);
1902 j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]);
1903 k = nearest_texel_location(tObj->Sampler.WrapR, img, depth, texcoord[2]);
1904
1905 if (i < 0 || i >= (GLint) img->Width ||
1906 j < 0 || j >= (GLint) img->Height ||
1907 k < 0 || k >= (GLint) img->Depth) {
1908 /* Need this test for GL_CLAMP_TO_BORDER mode */
1909 get_border_color(tObj, img, rgba);
1910 }
1911 else {
1912 swImg->FetchTexel(swImg, i, j, k, rgba);
1913 }
1914 }
1915
1916
1917 /**
1918 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1919 */
1920 static void
1921 sample_3d_linear(struct gl_context *ctx,
1922 const struct gl_texture_object *tObj,
1923 const struct gl_texture_image *img,
1924 const GLfloat texcoord[4],
1925 GLfloat rgba[4])
1926 {
1927 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1928 const GLint width = img->Width2;
1929 const GLint height = img->Height2;
1930 const GLint depth = img->Depth2;
1931 GLint i0, j0, k0, i1, j1, k1;
1932 GLbitfield useBorderColor = 0x0;
1933 GLfloat a, b, c;
1934 GLfloat t000[4], t010[4], t001[4], t011[4];
1935 GLfloat t100[4], t110[4], t101[4], t111[4];
1936
1937 linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a);
1938 linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b);
1939 linear_texel_locations(tObj->Sampler.WrapR, img, depth, texcoord[2], &k0, &k1, &c);
1940
1941 if (img->Border) {
1942 i0 += img->Border;
1943 i1 += img->Border;
1944 j0 += img->Border;
1945 j1 += img->Border;
1946 k0 += img->Border;
1947 k1 += img->Border;
1948 }
1949 else {
1950 /* check if sampling texture border color */
1951 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1952 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1953 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1954 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1955 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
1956 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
1957 }
1958
1959 /* Fetch texels */
1960 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
1961 get_border_color(tObj, img, t000);
1962 }
1963 else {
1964 swImg->FetchTexel(swImg, i0, j0, k0, t000);
1965 }
1966 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
1967 get_border_color(tObj, img, t100);
1968 }
1969 else {
1970 swImg->FetchTexel(swImg, i1, j0, k0, t100);
1971 }
1972 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
1973 get_border_color(tObj, img, t010);
1974 }
1975 else {
1976 swImg->FetchTexel(swImg, i0, j1, k0, t010);
1977 }
1978 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
1979 get_border_color(tObj, img, t110);
1980 }
1981 else {
1982 swImg->FetchTexel(swImg, i1, j1, k0, t110);
1983 }
1984
1985 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
1986 get_border_color(tObj, img, t001);
1987 }
1988 else {
1989 swImg->FetchTexel(swImg, i0, j0, k1, t001);
1990 }
1991 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
1992 get_border_color(tObj, img, t101);
1993 }
1994 else {
1995 swImg->FetchTexel(swImg, i1, j0, k1, t101);
1996 }
1997 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
1998 get_border_color(tObj, img, t011);
1999 }
2000 else {
2001 swImg->FetchTexel(swImg, i0, j1, k1, t011);
2002 }
2003 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
2004 get_border_color(tObj, img, t111);
2005 }
2006 else {
2007 swImg->FetchTexel(swImg, i1, j1, k1, t111);
2008 }
2009
2010 /* trilinear interpolation of samples */
2011 lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
2012 }
2013
2014
2015 static void
2016 sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
2017 const struct gl_texture_object *tObj,
2018 GLuint n, const GLfloat texcoord[][4],
2019 const GLfloat lambda[], GLfloat rgba[][4] )
2020 {
2021 GLuint i;
2022 for (i = 0; i < n; i++) {
2023 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2024 sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
2025 }
2026 }
2027
2028
2029 static void
2030 sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
2031 const struct gl_texture_object *tObj,
2032 GLuint n, const GLfloat texcoord[][4],
2033 const GLfloat lambda[], GLfloat rgba[][4])
2034 {
2035 GLuint i;
2036 ASSERT(lambda != NULL);
2037 for (i = 0; i < n; i++) {
2038 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2039 sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
2040 }
2041 }
2042
2043
2044 static void
2045 sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
2046 const struct gl_texture_object *tObj,
2047 GLuint n, const GLfloat texcoord[][4],
2048 const GLfloat lambda[], GLfloat rgba[][4])
2049 {
2050 GLuint i;
2051 ASSERT(lambda != NULL);
2052 for (i = 0; i < n; i++) {
2053 GLint level = linear_mipmap_level(tObj, lambda[i]);
2054 if (level >= tObj->_MaxLevel) {
2055 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2056 texcoord[i], rgba[i]);
2057 }
2058 else {
2059 GLfloat t0[4], t1[4]; /* texels */
2060 const GLfloat f = FRAC(lambda[i]);
2061 sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
2062 sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
2063 lerp_rgba(rgba[i], f, t0, t1);
2064 }
2065 }
2066 }
2067
2068
2069 static void
2070 sample_3d_linear_mipmap_linear(struct gl_context *ctx,
2071 const struct gl_texture_object *tObj,
2072 GLuint n, const GLfloat texcoord[][4],
2073 const GLfloat lambda[], GLfloat rgba[][4])
2074 {
2075 GLuint i;
2076 ASSERT(lambda != NULL);
2077 for (i = 0; i < n; i++) {
2078 GLint level = linear_mipmap_level(tObj, lambda[i]);
2079 if (level >= tObj->_MaxLevel) {
2080 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2081 texcoord[i], rgba[i]);
2082 }
2083 else {
2084 GLfloat t0[4], t1[4]; /* texels */
2085 const GLfloat f = FRAC(lambda[i]);
2086 sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
2087 sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
2088 lerp_rgba(rgba[i], f, t0, t1);
2089 }
2090 }
2091 }
2092
2093
2094 /** Sample 3D texture, nearest filtering for both min/magnification */
2095 static void
2096 sample_nearest_3d(struct gl_context *ctx,
2097 const struct gl_texture_object *tObj, GLuint n,
2098 const GLfloat texcoords[][4], const GLfloat lambda[],
2099 GLfloat rgba[][4])
2100 {
2101 GLuint i;
2102 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2103 (void) lambda;
2104 for (i = 0; i < n; i++) {
2105 sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
2106 }
2107 }
2108
2109
2110 /** Sample 3D texture, linear filtering for both min/magnification */
2111 static void
2112 sample_linear_3d(struct gl_context *ctx,
2113 const struct gl_texture_object *tObj, GLuint n,
2114 const GLfloat texcoords[][4],
2115 const GLfloat lambda[], GLfloat rgba[][4])
2116 {
2117 GLuint i;
2118 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2119 (void) lambda;
2120 for (i = 0; i < n; i++) {
2121 sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
2122 }
2123 }
2124
2125
2126 /** Sample 3D texture, using lambda to choose between min/magnification */
2127 static void
2128 sample_lambda_3d(struct gl_context *ctx,
2129 const struct gl_texture_object *tObj, GLuint n,
2130 const GLfloat texcoords[][4], const GLfloat lambda[],
2131 GLfloat rgba[][4])
2132 {
2133 GLuint minStart, minEnd; /* texels with minification */
2134 GLuint magStart, magEnd; /* texels with magnification */
2135 GLuint i;
2136
2137 ASSERT(lambda != NULL);
2138 compute_min_mag_ranges(tObj, n, lambda,
2139 &minStart, &minEnd, &magStart, &magEnd);
2140
2141 if (minStart < minEnd) {
2142 /* do the minified texels */
2143 GLuint m = minEnd - minStart;
2144 switch (tObj->Sampler.MinFilter) {
2145 case GL_NEAREST:
2146 for (i = minStart; i < minEnd; i++)
2147 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2148 texcoords[i], rgba[i]);
2149 break;
2150 case GL_LINEAR:
2151 for (i = minStart; i < minEnd; i++)
2152 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2153 texcoords[i], rgba[i]);
2154 break;
2155 case GL_NEAREST_MIPMAP_NEAREST:
2156 sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
2157 lambda + minStart, rgba + minStart);
2158 break;
2159 case GL_LINEAR_MIPMAP_NEAREST:
2160 sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
2161 lambda + minStart, rgba + minStart);
2162 break;
2163 case GL_NEAREST_MIPMAP_LINEAR:
2164 sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
2165 lambda + minStart, rgba + minStart);
2166 break;
2167 case GL_LINEAR_MIPMAP_LINEAR:
2168 sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
2169 lambda + minStart, rgba + minStart);
2170 break;
2171 default:
2172 _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
2173 return;
2174 }
2175 }
2176
2177 if (magStart < magEnd) {
2178 /* do the magnified texels */
2179 switch (tObj->Sampler.MagFilter) {
2180 case GL_NEAREST:
2181 for (i = magStart; i < magEnd; i++)
2182 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2183 texcoords[i], rgba[i]);
2184 break;
2185 case GL_LINEAR:
2186 for (i = magStart; i < magEnd; i++)
2187 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2188 texcoords[i], rgba[i]);
2189 break;
2190 default:
2191 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
2192 return;
2193 }
2194 }
2195 }
2196
2197
2198 /**********************************************************************/
2199 /* Texture Cube Map Sampling Functions */
2200 /**********************************************************************/
2201
2202 /**
2203 * Choose one of six sides of a texture cube map given the texture
2204 * coord (rx,ry,rz). Return pointer to corresponding array of texture
2205 * images.
2206 */
2207 static const struct gl_texture_image **
2208 choose_cube_face(const struct gl_texture_object *texObj,
2209 const GLfloat texcoord[4], GLfloat newCoord[4])
2210 {
2211 /*
2212 major axis
2213 direction target sc tc ma
2214 ---------- ------------------------------- --- --- ---
2215 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
2216 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
2217 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
2218 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
2219 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
2220 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
2221 */
2222 const GLfloat rx = texcoord[0];
2223 const GLfloat ry = texcoord[1];
2224 const GLfloat rz = texcoord[2];
2225 const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
2226 GLuint face;
2227 GLfloat sc, tc, ma;
2228
2229 if (arx >= ary && arx >= arz) {
2230 if (rx >= 0.0F) {
2231 face = FACE_POS_X;
2232 sc = -rz;
2233 tc = -ry;
2234 ma = arx;
2235 }
2236 else {
2237 face = FACE_NEG_X;
2238 sc = rz;
2239 tc = -ry;
2240 ma = arx;
2241 }
2242 }
2243 else if (ary >= arx && ary >= arz) {
2244 if (ry >= 0.0F) {
2245 face = FACE_POS_Y;
2246 sc = rx;
2247 tc = rz;
2248 ma = ary;
2249 }
2250 else {
2251 face = FACE_NEG_Y;
2252 sc = rx;
2253 tc = -rz;
2254 ma = ary;
2255 }
2256 }
2257 else {
2258 if (rz > 0.0F) {
2259 face = FACE_POS_Z;
2260 sc = rx;
2261 tc = -ry;
2262 ma = arz;
2263 }
2264 else {
2265 face = FACE_NEG_Z;
2266 sc = -rx;
2267 tc = -ry;
2268 ma = arz;
2269 }
2270 }
2271
2272 {
2273 const float ima = 1.0F / ma;
2274 newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
2275 newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
2276 }
2277
2278 return (const struct gl_texture_image **) texObj->Image[face];
2279 }
2280
2281
2282 static void
2283 sample_nearest_cube(struct gl_context *ctx,
2284 const struct gl_texture_object *tObj, GLuint n,
2285 const GLfloat texcoords[][4], const GLfloat lambda[],
2286 GLfloat rgba[][4])
2287 {
2288 GLuint i;
2289 (void) lambda;
2290 for (i = 0; i < n; i++) {
2291 const struct gl_texture_image **images;
2292 GLfloat newCoord[4];
2293 images = choose_cube_face(tObj, texcoords[i], newCoord);
2294 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
2295 newCoord, rgba[i]);
2296 }
2297 }
2298
2299
2300 static void
2301 sample_linear_cube(struct gl_context *ctx,
2302 const struct gl_texture_object *tObj, GLuint n,
2303 const GLfloat texcoords[][4],
2304 const GLfloat lambda[], GLfloat rgba[][4])
2305 {
2306 GLuint i;
2307 (void) lambda;
2308 for (i = 0; i < n; i++) {
2309 const struct gl_texture_image **images;
2310 GLfloat newCoord[4];
2311 images = choose_cube_face(tObj, texcoords[i], newCoord);
2312 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
2313 newCoord, rgba[i]);
2314 }
2315 }
2316
2317
2318 static void
2319 sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
2320 const struct gl_texture_object *tObj,
2321 GLuint n, const GLfloat texcoord[][4],
2322 const GLfloat lambda[], GLfloat rgba[][4])
2323 {
2324 GLuint i;
2325 ASSERT(lambda != NULL);
2326 for (i = 0; i < n; i++) {
2327 const struct gl_texture_image **images;
2328 GLfloat newCoord[4];
2329 GLint level;
2330 images = choose_cube_face(tObj, texcoord[i], newCoord);
2331
2332 /* XXX we actually need to recompute lambda here based on the newCoords.
2333 * But we would need the texcoords of adjacent fragments to compute that
2334 * properly, and we don't have those here.
2335 * For now, do an approximation: subtracting 1 from the chosen mipmap
2336 * level seems to work in some test cases.
2337 * The same adjustment is done in the next few functions.
2338 */
2339 level = nearest_mipmap_level(tObj, lambda[i]);
2340 level = MAX2(level - 1, 0);
2341
2342 sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]);
2343 }
2344 }
2345
2346
2347 static void
2348 sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
2349 const struct gl_texture_object *tObj,
2350 GLuint n, const GLfloat texcoord[][4],
2351 const GLfloat lambda[], GLfloat rgba[][4])
2352 {
2353 GLuint i;
2354 ASSERT(lambda != NULL);
2355 for (i = 0; i < n; i++) {
2356 const struct gl_texture_image **images;
2357 GLfloat newCoord[4];
2358 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2359 level = MAX2(level - 1, 0); /* see comment above */
2360 images = choose_cube_face(tObj, texcoord[i], newCoord);
2361 sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]);
2362 }
2363 }
2364
2365
2366 static void
2367 sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
2368 const struct gl_texture_object *tObj,
2369 GLuint n, const GLfloat texcoord[][4],
2370 const GLfloat lambda[], GLfloat rgba[][4])
2371 {
2372 GLuint i;
2373 ASSERT(lambda != NULL);
2374 for (i = 0; i < n; i++) {
2375 const struct gl_texture_image **images;
2376 GLfloat newCoord[4];
2377 GLint level = linear_mipmap_level(tObj, lambda[i]);
2378 level = MAX2(level - 1, 0); /* see comment above */
2379 images = choose_cube_face(tObj, texcoord[i], newCoord);
2380 if (level >= tObj->_MaxLevel) {
2381 sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel],
2382 newCoord, rgba[i]);
2383 }
2384 else {
2385 GLfloat t0[4], t1[4]; /* texels */
2386 const GLfloat f = FRAC(lambda[i]);
2387 sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0);
2388 sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1);
2389 lerp_rgba(rgba[i], f, t0, t1);
2390 }
2391 }
2392 }
2393
2394
2395 static void
2396 sample_cube_linear_mipmap_linear(struct gl_context *ctx,
2397 const struct gl_texture_object *tObj,
2398 GLuint n, const GLfloat texcoord[][4],
2399 const GLfloat lambda[], GLfloat rgba[][4])
2400 {
2401 GLuint i;
2402 ASSERT(lambda != NULL);
2403 for (i = 0; i < n; i++) {
2404 const struct gl_texture_image **images;
2405 GLfloat newCoord[4];
2406 GLint level = linear_mipmap_level(tObj, lambda[i]);
2407 level = MAX2(level - 1, 0); /* see comment above */
2408 images = choose_cube_face(tObj, texcoord[i], newCoord);
2409 if (level >= tObj->_MaxLevel) {
2410 sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel],
2411 newCoord, rgba[i]);
2412 }
2413 else {
2414 GLfloat t0[4], t1[4];
2415 const GLfloat f = FRAC(lambda[i]);
2416 sample_2d_linear(ctx, tObj, images[level ], newCoord, t0);
2417 sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1);
2418 lerp_rgba(rgba[i], f, t0, t1);
2419 }
2420 }
2421 }
2422
2423
2424 /** Sample cube texture, using lambda to choose between min/magnification */
2425 static void
2426 sample_lambda_cube(struct gl_context *ctx,
2427 const struct gl_texture_object *tObj, GLuint n,
2428 const GLfloat texcoords[][4], const GLfloat lambda[],
2429 GLfloat rgba[][4])
2430 {
2431 GLuint minStart, minEnd; /* texels with minification */
2432 GLuint magStart, magEnd; /* texels with magnification */
2433
2434 ASSERT(lambda != NULL);
2435 compute_min_mag_ranges(tObj, n, lambda,
2436 &minStart, &minEnd, &magStart, &magEnd);
2437
2438 if (minStart < minEnd) {
2439 /* do the minified texels */
2440 const GLuint m = minEnd - minStart;
2441 switch (tObj->Sampler.MinFilter) {
2442 case GL_NEAREST:
2443 sample_nearest_cube(ctx, tObj, m, texcoords + minStart,
2444 lambda + minStart, rgba + minStart);
2445 break;
2446 case GL_LINEAR:
2447 sample_linear_cube(ctx, tObj, m, texcoords + minStart,
2448 lambda + minStart, rgba + minStart);
2449 break;
2450 case GL_NEAREST_MIPMAP_NEAREST:
2451 sample_cube_nearest_mipmap_nearest(ctx, tObj, m,
2452 texcoords + minStart,
2453 lambda + minStart, rgba + minStart);
2454 break;
2455 case GL_LINEAR_MIPMAP_NEAREST:
2456 sample_cube_linear_mipmap_nearest(ctx, tObj, m,
2457 texcoords + minStart,
2458 lambda + minStart, rgba + minStart);
2459 break;
2460 case GL_NEAREST_MIPMAP_LINEAR:
2461 sample_cube_nearest_mipmap_linear(ctx, tObj, m,
2462 texcoords + minStart,
2463 lambda + minStart, rgba + minStart);
2464 break;
2465 case GL_LINEAR_MIPMAP_LINEAR:
2466 sample_cube_linear_mipmap_linear(ctx, tObj, m,
2467 texcoords + minStart,
2468 lambda + minStart, rgba + minStart);
2469 break;
2470 default:
2471 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2472 break;
2473 }
2474 }
2475
2476 if (magStart < magEnd) {
2477 /* do the magnified texels */
2478 const GLuint m = magEnd - magStart;
2479 switch (tObj->Sampler.MagFilter) {
2480 case GL_NEAREST:
2481 sample_nearest_cube(ctx, tObj, m, texcoords + magStart,
2482 lambda + magStart, rgba + magStart);
2483 break;
2484 case GL_LINEAR:
2485 sample_linear_cube(ctx, tObj, m, texcoords + magStart,
2486 lambda + magStart, rgba + magStart);
2487 break;
2488 default:
2489 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2490 break;
2491 }
2492 }
2493 }
2494
2495 /**
2496 * Compare texcoord against depth sample. Return 1.0 or the ambient value.
2497 */
2498 static inline GLfloat
2499 shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample,
2500 GLfloat ambient)
2501 {
2502 switch (function) {
2503 case GL_LEQUAL:
2504 return (coord <= depthSample) ? 1.0F : ambient;
2505 case GL_GEQUAL:
2506 return (coord >= depthSample) ? 1.0F : ambient;
2507 case GL_LESS:
2508 return (coord < depthSample) ? 1.0F : ambient;
2509 case GL_GREATER:
2510 return (coord > depthSample) ? 1.0F : ambient;
2511 case GL_EQUAL:
2512 return (coord == depthSample) ? 1.0F : ambient;
2513 case GL_NOTEQUAL:
2514 return (coord != depthSample) ? 1.0F : ambient;
2515 case GL_ALWAYS:
2516 return 1.0F;
2517 case GL_NEVER:
2518 return ambient;
2519 case GL_NONE:
2520 return depthSample;
2521 default:
2522 _mesa_problem(NULL, "Bad compare func in shadow_compare");
2523 return ambient;
2524 }
2525 }
2526
2527
2528 /**
2529 * Compare texcoord against four depth samples.
2530 */
2531 static inline GLfloat
2532 shadow_compare4(GLenum function, GLfloat coord,
2533 GLfloat depth00, GLfloat depth01,
2534 GLfloat depth10, GLfloat depth11,
2535 GLfloat ambient, GLfloat wi, GLfloat wj)
2536 {
2537 const GLfloat d = (1.0F - (GLfloat) ambient) * 0.25F;
2538 GLfloat luminance = 1.0F;
2539
2540 switch (function) {
2541 case GL_LEQUAL:
2542 if (coord > depth00) luminance -= d;
2543 if (coord > depth01) luminance -= d;
2544 if (coord > depth10) luminance -= d;
2545 if (coord > depth11) luminance -= d;
2546 return luminance;
2547 case GL_GEQUAL:
2548 if (coord < depth00) luminance -= d;
2549 if (coord < depth01) luminance -= d;
2550 if (coord < depth10) luminance -= d;
2551 if (coord < depth11) luminance -= d;
2552 return luminance;
2553 case GL_LESS:
2554 if (coord >= depth00) luminance -= d;
2555 if (coord >= depth01) luminance -= d;
2556 if (coord >= depth10) luminance -= d;
2557 if (coord >= depth11) luminance -= d;
2558 return luminance;
2559 case GL_GREATER:
2560 if (coord <= depth00) luminance -= d;
2561 if (coord <= depth01) luminance -= d;
2562 if (coord <= depth10) luminance -= d;
2563 if (coord <= depth11) luminance -= d;
2564 return luminance;
2565 case GL_EQUAL:
2566 if (coord != depth00) luminance -= d;
2567 if (coord != depth01) luminance -= d;
2568 if (coord != depth10) luminance -= d;
2569 if (coord != depth11) luminance -= d;
2570 return luminance;
2571 case GL_NOTEQUAL:
2572 if (coord == depth00) luminance -= d;
2573 if (coord == depth01) luminance -= d;
2574 if (coord == depth10) luminance -= d;
2575 if (coord == depth11) luminance -= d;
2576 return luminance;
2577 case GL_ALWAYS:
2578 return 1.0F;
2579 case GL_NEVER:
2580 return ambient;
2581 case GL_NONE:
2582 /* ordinary bilinear filtering */
2583 return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
2584 default:
2585 _mesa_problem(NULL, "Bad compare func in sample_compare4");
2586 return ambient;
2587 }
2588 }
2589
2590 /**
2591 * We use this function when a texture object is in an "incomplete" state.
2592 * When a fragment program attempts to sample an incomplete texture we
2593 * return black (see issue 23 in GL_ARB_fragment_program spec).
2594 * Note: fragment programs don't observe the texture enable/disable flags.
2595 */
2596 static void
2597 null_sample_func( struct gl_context *ctx,
2598 const struct gl_texture_object *tObj, GLuint n,
2599 const GLfloat texcoords[][4], const GLfloat lambda[],
2600 GLfloat rgba[][4])
2601 {
2602 GLuint i;
2603 (void) ctx;
2604 (void) tObj;
2605 (void) texcoords;
2606 (void) lambda;
2607 for (i = 0; i < n; i++) {
2608 rgba[i][RCOMP] = 0;
2609 rgba[i][GCOMP] = 0;
2610 rgba[i][BCOMP] = 0;
2611 rgba[i][ACOMP] = 1.0;
2612 }
2613 }
2614
2615
2616 /**
2617 * Choose the texture sampling function for the given texture object.
2618 */
2619 texture_sample_func
2620 _swrast_choose_texture_sample_func( struct gl_context *ctx,
2621 const struct gl_texture_object *t )
2622 {
2623 if (!t || !t->_Complete) {
2624 return &null_sample_func;
2625 }
2626 else {
2627 const GLboolean needLambda =
2628 (GLboolean) (t->Sampler.MinFilter != t->Sampler.MagFilter);
2629
2630 switch (t->Target) {
2631 case GL_TEXTURE_1D:
2632 if (needLambda) {
2633 return &sample_lambda_1d;
2634 }
2635 else if (t->Sampler.MinFilter == GL_LINEAR) {
2636 return &sample_linear_1d;
2637 }
2638 else {
2639 ASSERT(t->Sampler.MinFilter == GL_NEAREST);
2640 return &sample_nearest_1d;
2641 }
2642 case GL_TEXTURE_2D:
2643 if (needLambda) {
2644 /* Anisotropic filtering extension. Activated only if mipmaps are used */
2645 if (t->Sampler.MaxAnisotropy > 1.0 &&
2646 t->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
2647 return &sample_lambda_2d_aniso;
2648 }
2649 return &sample_lambda_2d;
2650 }
2651 else if (t->Sampler.MinFilter == GL_LINEAR) {
2652 return &sample_linear_2d;
2653 }
2654 else {
2655 /* check for a few optimized cases */
2656 const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
2657 const struct swrast_texture_image *swImg =
2658 swrast_texture_image_const(img);
2659 texture_sample_func func;
2660
2661 ASSERT(t->Sampler.MinFilter == GL_NEAREST);
2662 func = &sample_nearest_2d;
2663 if (t->Sampler.WrapS == GL_REPEAT &&
2664 t->Sampler.WrapT == GL_REPEAT &&
2665 swImg->_IsPowerOfTwo &&
2666 img->Border == 0) {
2667 if (img->TexFormat == MESA_FORMAT_RGB888)
2668 func = &opt_sample_rgb_2d;
2669 else if (img->TexFormat == MESA_FORMAT_RGBA8888)
2670 func = &opt_sample_rgba_2d;
2671 }
2672
2673 return func;
2674 }
2675 case GL_TEXTURE_3D:
2676 if (needLambda) {
2677 return &sample_lambda_3d;
2678 }
2679 else if (t->Sampler.MinFilter == GL_LINEAR) {
2680 return &sample_linear_3d;
2681 }
2682 else {
2683 ASSERT(t->Sampler.MinFilter == GL_NEAREST);
2684 return &sample_nearest_3d;
2685 }
2686 case GL_TEXTURE_CUBE_MAP:
2687 if (needLambda) {
2688 return &sample_lambda_cube;
2689 }
2690 else if (t->Sampler.MinFilter == GL_LINEAR) {
2691 return &sample_linear_cube;
2692 }
2693 else {
2694 ASSERT(t->Sampler.MinFilter == GL_NEAREST);
2695 return &sample_nearest_cube;
2696 }
2697 default:
2698 _mesa_problem(ctx,
2699 "invalid target in _swrast_choose_texture_sample_func");
2700 return &null_sample_func;
2701 }
2702 }
2703 }