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