Merge commit 'origin/gallium-0.1'
[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 fcol = 0.0F;
2068 }
2069 *i0out = i0;
2070 *i1out = i1;
2071 *weight = FRAC(fcol);
2072 }
2073
2074
2075 static void
2076 sample_nearest_rect(GLcontext *ctx,
2077 const struct gl_texture_object *tObj, GLuint n,
2078 const GLfloat texcoords[][4], const GLfloat lambda[],
2079 GLchan rgba[][4])
2080 {
2081 const struct gl_texture_image *img = tObj->Image[0][0];
2082 const GLint width = img->Width;
2083 const GLint height = img->Height;
2084 GLuint i;
2085
2086 (void) ctx;
2087 (void) lambda;
2088
2089 ASSERT(tObj->WrapS == GL_CLAMP ||
2090 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2091 tObj->WrapS == GL_CLAMP_TO_BORDER);
2092 ASSERT(tObj->WrapT == GL_CLAMP ||
2093 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2094 tObj->WrapT == GL_CLAMP_TO_BORDER);
2095 ASSERT(img->TexFormat->BaseFormat != GL_COLOR_INDEX);
2096
2097 for (i = 0; i < n; i++) {
2098 GLint row, col;
2099 col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width);
2100 row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
2101 if (col < 0 || col >= width || row < 0 || row >= height)
2102 COPY_CHAN4(rgba[i], tObj->_BorderChan);
2103 else
2104 img->FetchTexelc(img, col, row, 0, rgba[i]);
2105 }
2106 }
2107
2108
2109 static void
2110 sample_linear_rect(GLcontext *ctx,
2111 const struct gl_texture_object *tObj, GLuint n,
2112 const GLfloat texcoords[][4],
2113 const GLfloat lambda[], GLchan rgba[][4])
2114 {
2115 const struct gl_texture_image *img = tObj->Image[0][0];
2116 const GLint width = img->Width;
2117 const GLint height = img->Height;
2118 GLuint i;
2119
2120 (void) ctx;
2121 (void) lambda;
2122
2123 ASSERT(tObj->WrapS == GL_CLAMP ||
2124 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2125 tObj->WrapS == GL_CLAMP_TO_BORDER);
2126 ASSERT(tObj->WrapT == GL_CLAMP ||
2127 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2128 tObj->WrapT == GL_CLAMP_TO_BORDER);
2129 ASSERT(img->TexFormat->BaseFormat != GL_COLOR_INDEX);
2130
2131 for (i = 0; i < n; i++) {
2132 GLint i0, j0, i1, j1;
2133 GLchan t00[4], t01[4], t10[4], t11[4];
2134 GLfloat a, b;
2135 GLbitfield useBorderColor = 0x0;
2136
2137 clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0], width,
2138 &i0, &i1, &a);
2139 clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1], height,
2140 &j0, &j1, &b);
2141
2142 /* compute integer rows/columns */
2143 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2144 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2145 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2146 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2147
2148 /* get four texel samples */
2149 if (useBorderColor & (I0BIT | J0BIT))
2150 COPY_CHAN4(t00, tObj->_BorderChan);
2151 else
2152 img->FetchTexelc(img, i0, j0, 0, t00);
2153
2154 if (useBorderColor & (I1BIT | J0BIT))
2155 COPY_CHAN4(t10, tObj->_BorderChan);
2156 else
2157 img->FetchTexelc(img, i1, j0, 0, t10);
2158
2159 if (useBorderColor & (I0BIT | J1BIT))
2160 COPY_CHAN4(t01, tObj->_BorderChan);
2161 else
2162 img->FetchTexelc(img, i0, j1, 0, t01);
2163
2164 if (useBorderColor & (I1BIT | J1BIT))
2165 COPY_CHAN4(t11, tObj->_BorderChan);
2166 else
2167 img->FetchTexelc(img, i1, j1, 0, t11);
2168
2169 lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
2170 }
2171 }
2172
2173
2174 /** Sample Rect texture, using lambda to choose between min/magnification */
2175 static void
2176 sample_lambda_rect(GLcontext *ctx,
2177 const struct gl_texture_object *tObj, GLuint n,
2178 const GLfloat texcoords[][4], const GLfloat lambda[],
2179 GLchan rgba[][4])
2180 {
2181 GLuint minStart, minEnd, magStart, magEnd;
2182
2183 /* We only need lambda to decide between minification and magnification.
2184 * There is no mipmapping with rectangular textures.
2185 */
2186 compute_min_mag_ranges(tObj, n, lambda,
2187 &minStart, &minEnd, &magStart, &magEnd);
2188
2189 if (minStart < minEnd) {
2190 if (tObj->MinFilter == GL_NEAREST) {
2191 sample_nearest_rect(ctx, tObj, minEnd - minStart,
2192 texcoords + minStart, NULL, rgba + minStart);
2193 }
2194 else {
2195 sample_linear_rect(ctx, tObj, minEnd - minStart,
2196 texcoords + minStart, NULL, rgba + minStart);
2197 }
2198 }
2199 if (magStart < magEnd) {
2200 if (tObj->MagFilter == GL_NEAREST) {
2201 sample_nearest_rect(ctx, tObj, magEnd - magStart,
2202 texcoords + magStart, NULL, rgba + magStart);
2203 }
2204 else {
2205 sample_linear_rect(ctx, tObj, magEnd - magStart,
2206 texcoords + magStart, NULL, rgba + magStart);
2207 }
2208 }
2209 }
2210
2211
2212
2213 /**********************************************************************/
2214 /* 2D Texture Array Sampling Functions */
2215 /**********************************************************************/
2216
2217 /**
2218 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2219 */
2220 static void
2221 sample_2d_array_nearest(GLcontext *ctx,
2222 const struct gl_texture_object *tObj,
2223 const struct gl_texture_image *img,
2224 const GLfloat texcoord[4],
2225 GLchan rgba[4])
2226 {
2227 const GLint width = img->Width2; /* without border, power of two */
2228 const GLint height = img->Height2; /* without border, power of two */
2229 const GLint depth = img->Depth;
2230 GLint i, j;
2231 GLint array;
2232 (void) ctx;
2233
2234 i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]);
2235 j = nearest_texel_location(tObj->WrapT, img, height, texcoord[1]);
2236 array = clamp_rect_coord_nearest(tObj->WrapR, texcoord[2], depth);
2237
2238 if (i < 0 || i >= (GLint) img->Width ||
2239 j < 0 || j >= (GLint) img->Height ||
2240 array < 0 || array >= (GLint) img->Depth) {
2241 /* Need this test for GL_CLAMP_TO_BORDER mode */
2242 COPY_CHAN4(rgba, tObj->_BorderChan);
2243 }
2244 else {
2245 img->FetchTexelc(img, i, j, array, rgba);
2246 }
2247 }
2248
2249
2250 /**
2251 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2252 */
2253 static void
2254 sample_2d_array_linear(GLcontext *ctx,
2255 const struct gl_texture_object *tObj,
2256 const struct gl_texture_image *img,
2257 const GLfloat texcoord[4],
2258 GLchan rgba[4])
2259 {
2260 const GLint width = img->Width2;
2261 const GLint height = img->Height2;
2262 const GLint depth = img->Depth;
2263 GLint i0, j0, i1, j1;
2264 GLint array;
2265 GLbitfield useBorderColor = 0x0;
2266 GLfloat a, b;
2267 GLchan t00[4], t01[4], t10[4], t11[4];
2268
2269 linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2270 linear_texel_locations(tObj->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2271 array = clamp_rect_coord_nearest(tObj->WrapR, texcoord[2], depth);
2272
2273 if (array < 0 || array >= depth) {
2274 COPY_CHAN4(rgba, tObj->_BorderChan);
2275 }
2276 else {
2277 if (img->Border) {
2278 i0 += img->Border;
2279 i1 += img->Border;
2280 j0 += img->Border;
2281 j1 += img->Border;
2282 }
2283 else {
2284 /* check if sampling texture border color */
2285 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2286 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2287 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2288 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2289 }
2290
2291 /* Fetch texels */
2292 if (useBorderColor & (I0BIT | J0BIT)) {
2293 COPY_CHAN4(t00, tObj->_BorderChan);
2294 }
2295 else {
2296 img->FetchTexelc(img, i0, j0, array, t00);
2297 }
2298 if (useBorderColor & (I1BIT | J0BIT)) {
2299 COPY_CHAN4(t10, tObj->_BorderChan);
2300 }
2301 else {
2302 img->FetchTexelc(img, i1, j0, array, t10);
2303 }
2304 if (useBorderColor & (I0BIT | J1BIT)) {
2305 COPY_CHAN4(t01, tObj->_BorderChan);
2306 }
2307 else {
2308 img->FetchTexelc(img, i0, j1, array, t01);
2309 }
2310 if (useBorderColor & (I1BIT | J1BIT)) {
2311 COPY_CHAN4(t11, tObj->_BorderChan);
2312 }
2313 else {
2314 img->FetchTexelc(img, i1, j1, array, t11);
2315 }
2316
2317 /* trilinear interpolation of samples */
2318 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
2319 }
2320 }
2321
2322
2323 static void
2324 sample_2d_array_nearest_mipmap_nearest(GLcontext *ctx,
2325 const struct gl_texture_object *tObj,
2326 GLuint n, const GLfloat texcoord[][4],
2327 const GLfloat lambda[], GLchan rgba[][4])
2328 {
2329 GLuint i;
2330 for (i = 0; i < n; i++) {
2331 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2332 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
2333 rgba[i]);
2334 }
2335 }
2336
2337
2338 static void
2339 sample_2d_array_linear_mipmap_nearest(GLcontext *ctx,
2340 const struct gl_texture_object *tObj,
2341 GLuint n, const GLfloat texcoord[][4],
2342 const GLfloat lambda[], GLchan rgba[][4])
2343 {
2344 GLuint i;
2345 ASSERT(lambda != NULL);
2346 for (i = 0; i < n; i++) {
2347 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2348 sample_2d_array_linear(ctx, tObj, tObj->Image[0][level],
2349 texcoord[i], rgba[i]);
2350 }
2351 }
2352
2353
2354 static void
2355 sample_2d_array_nearest_mipmap_linear(GLcontext *ctx,
2356 const struct gl_texture_object *tObj,
2357 GLuint n, const GLfloat texcoord[][4],
2358 const GLfloat lambda[], GLchan rgba[][4])
2359 {
2360 GLuint i;
2361 ASSERT(lambda != NULL);
2362 for (i = 0; i < n; i++) {
2363 GLint level = linear_mipmap_level(tObj, lambda[i]);
2364 if (level >= tObj->_MaxLevel) {
2365 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2366 texcoord[i], rgba[i]);
2367 }
2368 else {
2369 GLchan t0[4], t1[4]; /* texels */
2370 const GLfloat f = FRAC(lambda[i]);
2371 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ],
2372 texcoord[i], t0);
2373 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1],
2374 texcoord[i], t1);
2375 lerp_rgba(rgba[i], f, t0, t1);
2376 }
2377 }
2378 }
2379
2380
2381 static void
2382 sample_2d_array_linear_mipmap_linear(GLcontext *ctx,
2383 const struct gl_texture_object *tObj,
2384 GLuint n, const GLfloat texcoord[][4],
2385 const GLfloat lambda[], GLchan rgba[][4])
2386 {
2387 GLuint i;
2388 ASSERT(lambda != NULL);
2389 for (i = 0; i < n; i++) {
2390 GLint level = linear_mipmap_level(tObj, lambda[i]);
2391 if (level >= tObj->_MaxLevel) {
2392 sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2393 texcoord[i], rgba[i]);
2394 }
2395 else {
2396 GLchan t0[4], t1[4]; /* texels */
2397 const GLfloat f = FRAC(lambda[i]);
2398 sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ],
2399 texcoord[i], t0);
2400 sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1],
2401 texcoord[i], t1);
2402 lerp_rgba(rgba[i], f, t0, t1);
2403 }
2404 }
2405 }
2406
2407
2408 /** Sample 2D Array texture, nearest filtering for both min/magnification */
2409 static void
2410 sample_nearest_2d_array(GLcontext *ctx,
2411 const struct gl_texture_object *tObj, GLuint n,
2412 const GLfloat texcoords[][4], const GLfloat lambda[],
2413 GLchan rgba[][4])
2414 {
2415 GLuint i;
2416 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2417 (void) lambda;
2418 for (i = 0; i < n; i++) {
2419 sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
2420 }
2421 }
2422
2423
2424
2425 /** Sample 2D Array texture, linear filtering for both min/magnification */
2426 static void
2427 sample_linear_2d_array(GLcontext *ctx,
2428 const struct gl_texture_object *tObj, GLuint n,
2429 const GLfloat texcoords[][4],
2430 const GLfloat lambda[], GLchan rgba[][4])
2431 {
2432 GLuint i;
2433 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2434 (void) lambda;
2435 for (i = 0; i < n; i++) {
2436 sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
2437 }
2438 }
2439
2440
2441 /** Sample 2D Array texture, using lambda to choose between min/magnification */
2442 static void
2443 sample_lambda_2d_array(GLcontext *ctx,
2444 const struct gl_texture_object *tObj, GLuint n,
2445 const GLfloat texcoords[][4], const GLfloat lambda[],
2446 GLchan rgba[][4])
2447 {
2448 GLuint minStart, minEnd; /* texels with minification */
2449 GLuint magStart, magEnd; /* texels with magnification */
2450 GLuint i;
2451
2452 ASSERT(lambda != NULL);
2453 compute_min_mag_ranges(tObj, n, lambda,
2454 &minStart, &minEnd, &magStart, &magEnd);
2455
2456 if (minStart < minEnd) {
2457 /* do the minified texels */
2458 GLuint m = minEnd - minStart;
2459 switch (tObj->MinFilter) {
2460 case GL_NEAREST:
2461 for (i = minStart; i < minEnd; i++)
2462 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2463 texcoords[i], rgba[i]);
2464 break;
2465 case GL_LINEAR:
2466 for (i = minStart; i < minEnd; i++)
2467 sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2468 texcoords[i], rgba[i]);
2469 break;
2470 case GL_NEAREST_MIPMAP_NEAREST:
2471 sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m,
2472 texcoords + minStart,
2473 lambda + minStart,
2474 rgba + minStart);
2475 break;
2476 case GL_LINEAR_MIPMAP_NEAREST:
2477 sample_2d_array_linear_mipmap_nearest(ctx, tObj, m,
2478 texcoords + minStart,
2479 lambda + minStart,
2480 rgba + minStart);
2481 break;
2482 case GL_NEAREST_MIPMAP_LINEAR:
2483 sample_2d_array_nearest_mipmap_linear(ctx, tObj, m,
2484 texcoords + minStart,
2485 lambda + minStart,
2486 rgba + minStart);
2487 break;
2488 case GL_LINEAR_MIPMAP_LINEAR:
2489 sample_2d_array_linear_mipmap_linear(ctx, tObj, m,
2490 texcoords + minStart,
2491 lambda + minStart,
2492 rgba + minStart);
2493 break;
2494 default:
2495 _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
2496 return;
2497 }
2498 }
2499
2500 if (magStart < magEnd) {
2501 /* do the magnified texels */
2502 switch (tObj->MagFilter) {
2503 case GL_NEAREST:
2504 for (i = magStart; i < magEnd; i++)
2505 sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2506 texcoords[i], rgba[i]);
2507 break;
2508 case GL_LINEAR:
2509 for (i = magStart; i < magEnd; i++)
2510 sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2511 texcoords[i], rgba[i]);
2512 break;
2513 default:
2514 _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
2515 return;
2516 }
2517 }
2518 }
2519
2520
2521
2522
2523 /**********************************************************************/
2524 /* 1D Texture Array Sampling Functions */
2525 /**********************************************************************/
2526
2527 /**
2528 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2529 */
2530 static void
2531 sample_1d_array_nearest(GLcontext *ctx,
2532 const struct gl_texture_object *tObj,
2533 const struct gl_texture_image *img,
2534 const GLfloat texcoord[4],
2535 GLchan rgba[4])
2536 {
2537 const GLint width = img->Width2; /* without border, power of two */
2538 const GLint height = img->Height;
2539 GLint i;
2540 GLint array;
2541 (void) ctx;
2542
2543 i = nearest_texel_location(tObj->WrapS, img, width, texcoord[0]);
2544 array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
2545
2546 if (i < 0 || i >= (GLint) img->Width ||
2547 array < 0 || array >= (GLint) img->Height) {
2548 /* Need this test for GL_CLAMP_TO_BORDER mode */
2549 COPY_CHAN4(rgba, tObj->_BorderChan);
2550 }
2551 else {
2552 img->FetchTexelc(img, i, array, 0, rgba);
2553 }
2554 }
2555
2556
2557 /**
2558 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2559 */
2560 static void
2561 sample_1d_array_linear(GLcontext *ctx,
2562 const struct gl_texture_object *tObj,
2563 const struct gl_texture_image *img,
2564 const GLfloat texcoord[4],
2565 GLchan rgba[4])
2566 {
2567 const GLint width = img->Width2;
2568 const GLint height = img->Height;
2569 GLint i0, i1;
2570 GLint array;
2571 GLbitfield useBorderColor = 0x0;
2572 GLfloat a;
2573 GLchan t0[4], t1[4];
2574
2575 linear_texel_locations(tObj->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2576 array = clamp_rect_coord_nearest(tObj->WrapT, texcoord[1], height);
2577
2578 if (img->Border) {
2579 i0 += img->Border;
2580 i1 += img->Border;
2581 }
2582 else {
2583 /* check if sampling texture border color */
2584 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2585 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2586 }
2587
2588 if (array < 0 || array >= height) useBorderColor |= K0BIT;
2589
2590 /* Fetch texels */
2591 if (useBorderColor & (I0BIT | K0BIT)) {
2592 COPY_CHAN4(t0, tObj->_BorderChan);
2593 }
2594 else {
2595 img->FetchTexelc(img, i0, array, 0, t0);
2596 }
2597 if (useBorderColor & (I1BIT | K0BIT)) {
2598 COPY_CHAN4(t1, tObj->_BorderChan);
2599 }
2600 else {
2601 img->FetchTexelc(img, i1, array, 0, t1);
2602 }
2603
2604 /* bilinear interpolation of samples */
2605 lerp_rgba(rgba, a, t0, t1);
2606 }
2607
2608
2609 static void
2610 sample_1d_array_nearest_mipmap_nearest(GLcontext *ctx,
2611 const struct gl_texture_object *tObj,
2612 GLuint n, const GLfloat texcoord[][4],
2613 const GLfloat lambda[], GLchan rgba[][4])
2614 {
2615 GLuint i;
2616 for (i = 0; i < n; i++) {
2617 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2618 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i],
2619 rgba[i]);
2620 }
2621 }
2622
2623
2624 static void
2625 sample_1d_array_linear_mipmap_nearest(GLcontext *ctx,
2626 const struct gl_texture_object *tObj,
2627 GLuint n, const GLfloat texcoord[][4],
2628 const GLfloat lambda[], GLchan rgba[][4])
2629 {
2630 GLuint i;
2631 ASSERT(lambda != NULL);
2632 for (i = 0; i < n; i++) {
2633 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2634 sample_1d_array_linear(ctx, tObj, tObj->Image[0][level],
2635 texcoord[i], rgba[i]);
2636 }
2637 }
2638
2639
2640 static void
2641 sample_1d_array_nearest_mipmap_linear(GLcontext *ctx,
2642 const struct gl_texture_object *tObj,
2643 GLuint n, const GLfloat texcoord[][4],
2644 const GLfloat lambda[], GLchan rgba[][4])
2645 {
2646 GLuint i;
2647 ASSERT(lambda != NULL);
2648 for (i = 0; i < n; i++) {
2649 GLint level = linear_mipmap_level(tObj, lambda[i]);
2650 if (level >= tObj->_MaxLevel) {
2651 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2652 texcoord[i], rgba[i]);
2653 }
2654 else {
2655 GLchan t0[4], t1[4]; /* texels */
2656 const GLfloat f = FRAC(lambda[i]);
2657 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
2658 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
2659 lerp_rgba(rgba[i], f, t0, t1);
2660 }
2661 }
2662 }
2663
2664
2665 static void
2666 sample_1d_array_linear_mipmap_linear(GLcontext *ctx,
2667 const struct gl_texture_object *tObj,
2668 GLuint n, const GLfloat texcoord[][4],
2669 const GLfloat lambda[], GLchan rgba[][4])
2670 {
2671 GLuint i;
2672 ASSERT(lambda != NULL);
2673 for (i = 0; i < n; i++) {
2674 GLint level = linear_mipmap_level(tObj, lambda[i]);
2675 if (level >= tObj->_MaxLevel) {
2676 sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
2677 texcoord[i], rgba[i]);
2678 }
2679 else {
2680 GLchan t0[4], t1[4]; /* texels */
2681 const GLfloat f = FRAC(lambda[i]);
2682 sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
2683 sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
2684 lerp_rgba(rgba[i], f, t0, t1);
2685 }
2686 }
2687 }
2688
2689
2690 /** Sample 1D Array texture, nearest filtering for both min/magnification */
2691 static void
2692 sample_nearest_1d_array(GLcontext *ctx,
2693 const struct gl_texture_object *tObj, GLuint n,
2694 const GLfloat texcoords[][4], const GLfloat lambda[],
2695 GLchan rgba[][4])
2696 {
2697 GLuint i;
2698 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2699 (void) lambda;
2700 for (i = 0; i < n; i++) {
2701 sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
2702 }
2703 }
2704
2705
2706 /** Sample 1D Array texture, linear filtering for both min/magnification */
2707 static void
2708 sample_linear_1d_array(GLcontext *ctx,
2709 const struct gl_texture_object *tObj, GLuint n,
2710 const GLfloat texcoords[][4],
2711 const GLfloat lambda[], GLchan rgba[][4])
2712 {
2713 GLuint i;
2714 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2715 (void) lambda;
2716 for (i = 0; i < n; i++) {
2717 sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]);
2718 }
2719 }
2720
2721
2722 /** Sample 1D Array texture, using lambda to choose between min/magnification */
2723 static void
2724 sample_lambda_1d_array(GLcontext *ctx,
2725 const struct gl_texture_object *tObj, GLuint n,
2726 const GLfloat texcoords[][4], const GLfloat lambda[],
2727 GLchan rgba[][4])
2728 {
2729 GLuint minStart, minEnd; /* texels with minification */
2730 GLuint magStart, magEnd; /* texels with magnification */
2731 GLuint i;
2732
2733 ASSERT(lambda != NULL);
2734 compute_min_mag_ranges(tObj, n, lambda,
2735 &minStart, &minEnd, &magStart, &magEnd);
2736
2737 if (minStart < minEnd) {
2738 /* do the minified texels */
2739 GLuint m = minEnd - minStart;
2740 switch (tObj->MinFilter) {
2741 case GL_NEAREST:
2742 for (i = minStart; i < minEnd; i++)
2743 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2744 texcoords[i], rgba[i]);
2745 break;
2746 case GL_LINEAR:
2747 for (i = minStart; i < minEnd; i++)
2748 sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2749 texcoords[i], rgba[i]);
2750 break;
2751 case GL_NEAREST_MIPMAP_NEAREST:
2752 sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
2753 lambda + minStart, rgba + minStart);
2754 break;
2755 case GL_LINEAR_MIPMAP_NEAREST:
2756 sample_1d_array_linear_mipmap_nearest(ctx, tObj, m,
2757 texcoords + minStart,
2758 lambda + minStart,
2759 rgba + minStart);
2760 break;
2761 case GL_NEAREST_MIPMAP_LINEAR:
2762 sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
2763 lambda + minStart, rgba + minStart);
2764 break;
2765 case GL_LINEAR_MIPMAP_LINEAR:
2766 sample_1d_array_linear_mipmap_linear(ctx, tObj, m,
2767 texcoords + minStart,
2768 lambda + minStart,
2769 rgba + minStart);
2770 break;
2771 default:
2772 _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
2773 return;
2774 }
2775 }
2776
2777 if (magStart < magEnd) {
2778 /* do the magnified texels */
2779 switch (tObj->MagFilter) {
2780 case GL_NEAREST:
2781 for (i = magStart; i < magEnd; i++)
2782 sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2783 texcoords[i], rgba[i]);
2784 break;
2785 case GL_LINEAR:
2786 for (i = magStart; i < magEnd; i++)
2787 sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
2788 texcoords[i], rgba[i]);
2789 break;
2790 default:
2791 _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
2792 return;
2793 }
2794 }
2795 }
2796
2797
2798 /**
2799 * Sample a shadow/depth texture.
2800 */
2801 static void
2802 sample_depth_texture( GLcontext *ctx,
2803 const struct gl_texture_object *tObj, GLuint n,
2804 const GLfloat texcoords[][4], const GLfloat lambda[],
2805 GLchan texel[][4] )
2806 {
2807 const GLint baseLevel = tObj->BaseLevel;
2808 const struct gl_texture_image *img = tObj->Image[0][baseLevel];
2809 const GLint width = img->Width;
2810 const GLint height = img->Height;
2811 const GLint depth = img->Depth;
2812 const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
2813 ? 3 : 2;
2814 GLchan ambient;
2815 GLenum function;
2816 GLchan result;
2817
2818 (void) lambda;
2819
2820 ASSERT(img->TexFormat->BaseFormat == GL_DEPTH_COMPONENT ||
2821 img->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT);
2822
2823 ASSERT(tObj->Target == GL_TEXTURE_1D ||
2824 tObj->Target == GL_TEXTURE_2D ||
2825 tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
2826 tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
2827 tObj->Target == GL_TEXTURE_2D_ARRAY_EXT);
2828
2829 UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->CompareFailValue);
2830
2831 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2832
2833 function = tObj->_Function;
2834 if (tObj->MagFilter == GL_NEAREST) {
2835 GLuint i;
2836 for (i = 0; i < n; i++) {
2837 GLfloat depthSample;
2838 GLint col, row, slice;
2839
2840 switch (tObj->Target) {
2841 case GL_TEXTURE_RECTANGLE_ARB:
2842 col = clamp_rect_coord_nearest(tObj->WrapS, texcoords[i][0], width);
2843 row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
2844 slice = 0;
2845 break;
2846
2847 case GL_TEXTURE_1D:
2848 col = nearest_texel_location(tObj->WrapS, img, width,
2849 texcoords[i][0]);
2850 row = 0;
2851 slice = 0;
2852 break;
2853
2854 case GL_TEXTURE_2D:
2855 col = nearest_texel_location(tObj->WrapS, img, width,
2856 texcoords[i][0]);
2857 row = nearest_texel_location(tObj->WrapT, img, height,
2858 texcoords[i][1]);
2859 slice = 0;
2860 break;
2861
2862 case GL_TEXTURE_1D_ARRAY_EXT:
2863 col = nearest_texel_location(tObj->WrapS, img, width,
2864 texcoords[i][0]);
2865 row = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
2866 slice = 0;
2867 break;
2868
2869 case GL_TEXTURE_2D_ARRAY_EXT:
2870 col = nearest_texel_location(tObj->WrapS, img, width,
2871 texcoords[i][0]);
2872 row = nearest_texel_location(tObj->WrapT, img, height,
2873 texcoords[i][1]);
2874 slice = clamp_rect_coord_nearest(tObj->WrapR, texcoords[i][2], depth);
2875 break;
2876 default:
2877 col = row = slice = 0;
2878 }
2879
2880 if (col >= 0 && row >= 0 && col < width && row < height &&
2881 slice >= 0 && slice < depth) {
2882 img->FetchTexelf(img, col, row, slice, &depthSample);
2883 }
2884 else {
2885 depthSample = tObj->BorderColor[0];
2886 }
2887
2888 switch (function) {
2889 case GL_LEQUAL:
2890 result = (texcoords[i][compare_coord] <= depthSample) ? CHAN_MAX : ambient;
2891 break;
2892 case GL_GEQUAL:
2893 result = (texcoords[i][compare_coord] >= depthSample) ? CHAN_MAX : ambient;
2894 break;
2895 case GL_LESS:
2896 result = (texcoords[i][compare_coord] < depthSample) ? CHAN_MAX : ambient;
2897 break;
2898 case GL_GREATER:
2899 result = (texcoords[i][compare_coord] > depthSample) ? CHAN_MAX : ambient;
2900 break;
2901 case GL_EQUAL:
2902 result = (texcoords[i][compare_coord] == depthSample) ? CHAN_MAX : ambient;
2903 break;
2904 case GL_NOTEQUAL:
2905 result = (texcoords[i][compare_coord] != depthSample) ? CHAN_MAX : ambient;
2906 break;
2907 case GL_ALWAYS:
2908 result = CHAN_MAX;
2909 break;
2910 case GL_NEVER:
2911 result = ambient;
2912 break;
2913 case GL_NONE:
2914 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
2915 break;
2916 default:
2917 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
2918 return;
2919 }
2920
2921 switch (tObj->DepthMode) {
2922 case GL_LUMINANCE:
2923 texel[i][RCOMP] = result;
2924 texel[i][GCOMP] = result;
2925 texel[i][BCOMP] = result;
2926 texel[i][ACOMP] = CHAN_MAX;
2927 break;
2928 case GL_INTENSITY:
2929 texel[i][RCOMP] = result;
2930 texel[i][GCOMP] = result;
2931 texel[i][BCOMP] = result;
2932 texel[i][ACOMP] = result;
2933 break;
2934 case GL_ALPHA:
2935 texel[i][RCOMP] = 0;
2936 texel[i][GCOMP] = 0;
2937 texel[i][BCOMP] = 0;
2938 texel[i][ACOMP] = result;
2939 break;
2940 default:
2941 _mesa_problem(ctx, "Bad depth texture mode");
2942 }
2943 }
2944 }
2945 else {
2946 GLuint i;
2947 ASSERT(tObj->MagFilter == GL_LINEAR);
2948 for (i = 0; i < n; i++) {
2949 GLfloat depth00, depth01, depth10, depth11;
2950 GLint i0, i1, j0, j1;
2951 GLint slice;
2952 GLfloat a, b;
2953 GLuint useBorderTexel;
2954
2955 switch (tObj->Target) {
2956 case GL_TEXTURE_RECTANGLE_ARB:
2957 clamp_rect_coord_linear(tObj->WrapS, texcoords[i][0],
2958 width, &i0, &i1, &a);
2959 clamp_rect_coord_linear(tObj->WrapT, texcoords[i][1],
2960 height, &j0, &j1, &b);
2961 slice = 0;
2962 break;
2963
2964 case GL_TEXTURE_1D:
2965 case GL_TEXTURE_2D:
2966 linear_texel_locations(tObj->WrapS, img, width,
2967 texcoords[i][0], &i0, &i1, &a);
2968 linear_texel_locations(tObj->WrapT, img, height,
2969 texcoords[i][1], &j0, &j1, &b);
2970 slice = 0;
2971 break;
2972
2973 case GL_TEXTURE_1D_ARRAY_EXT:
2974 linear_texel_locations(tObj->WrapS, img, width,
2975 texcoords[i][0], &i0, &i1, &a);
2976 j0 = clamp_rect_coord_nearest(tObj->WrapT, texcoords[i][1], height);
2977 j1 = j0;
2978 slice = 0;
2979 break;
2980
2981 case GL_TEXTURE_2D_ARRAY_EXT:
2982 linear_texel_locations(tObj->WrapS, img, width,
2983 texcoords[i][0], &i0, &i1, &a);
2984 linear_texel_locations(tObj->WrapT, img, height,
2985 texcoords[i][1], &j0, &j1, &b);
2986 slice = clamp_rect_coord_nearest(tObj->WrapR, texcoords[i][2], depth);
2987 break;
2988 default:
2989 slice = 0;
2990 }
2991
2992 useBorderTexel = 0;
2993 if (img->Border) {
2994 i0 += img->Border;
2995 i1 += img->Border;
2996 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
2997 j0 += img->Border;
2998 j1 += img->Border;
2999 }
3000 }
3001 else {
3002 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
3003 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
3004 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
3005 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
3006 }
3007
3008 if (slice < 0 || slice >= (GLint) depth) {
3009 depth00 = tObj->BorderColor[0];
3010 depth01 = tObj->BorderColor[0];
3011 depth10 = tObj->BorderColor[0];
3012 depth11 = tObj->BorderColor[0];
3013 }
3014 else {
3015 /* get four depth samples from the texture */
3016 if (useBorderTexel & (I0BIT | J0BIT)) {
3017 depth00 = tObj->BorderColor[0];
3018 }
3019 else {
3020 img->FetchTexelf(img, i0, j0, slice, &depth00);
3021 }
3022 if (useBorderTexel & (I1BIT | J0BIT)) {
3023 depth10 = tObj->BorderColor[0];
3024 }
3025 else {
3026 img->FetchTexelf(img, i1, j0, slice, &depth10);
3027 }
3028
3029 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3030 if (useBorderTexel & (I0BIT | J1BIT)) {
3031 depth01 = tObj->BorderColor[0];
3032 }
3033 else {
3034 img->FetchTexelf(img, i0, j1, slice, &depth01);
3035 }
3036 if (useBorderTexel & (I1BIT | J1BIT)) {
3037 depth11 = tObj->BorderColor[0];
3038 }
3039 else {
3040 img->FetchTexelf(img, i1, j1, slice, &depth11);
3041 }
3042 }
3043 else {
3044 depth01 = depth00;
3045 depth11 = depth10;
3046 }
3047 }
3048
3049 if (0) {
3050 /* compute a single weighted depth sample and do one comparison */
3051 const GLfloat depthSample
3052 = lerp_2d(a, b, depth00, depth10, depth01, depth11);
3053 if ((depthSample <= texcoords[i][compare_coord] && function == GL_LEQUAL) ||
3054 (depthSample >= texcoords[i][compare_coord] && function == GL_GEQUAL)) {
3055 result = ambient;
3056 }
3057 else {
3058 result = CHAN_MAX;
3059 }
3060 }
3061 else {
3062 /* Do four depth/R comparisons and compute a weighted result.
3063 * If this touches on somebody's I.P., I'll remove this code
3064 * upon request.
3065 */
3066 const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
3067 GLfloat luminance = CHAN_MAXF;
3068
3069 switch (function) {
3070 case GL_LEQUAL:
3071 if (depth00 <= texcoords[i][compare_coord]) luminance -= d;
3072 if (depth01 <= texcoords[i][compare_coord]) luminance -= d;
3073 if (depth10 <= texcoords[i][compare_coord]) luminance -= d;
3074 if (depth11 <= texcoords[i][compare_coord]) luminance -= d;
3075 result = (GLchan) luminance;
3076 break;
3077 case GL_GEQUAL:
3078 if (depth00 >= texcoords[i][compare_coord]) luminance -= d;
3079 if (depth01 >= texcoords[i][compare_coord]) luminance -= d;
3080 if (depth10 >= texcoords[i][compare_coord]) luminance -= d;
3081 if (depth11 >= texcoords[i][compare_coord]) luminance -= d;
3082 result = (GLchan) luminance;
3083 break;
3084 case GL_LESS:
3085 if (depth00 < texcoords[i][compare_coord]) luminance -= d;
3086 if (depth01 < texcoords[i][compare_coord]) luminance -= d;
3087 if (depth10 < texcoords[i][compare_coord]) luminance -= d;
3088 if (depth11 < texcoords[i][compare_coord]) luminance -= d;
3089 result = (GLchan) luminance;
3090 break;
3091 case GL_GREATER:
3092 if (depth00 > texcoords[i][compare_coord]) luminance -= d;
3093 if (depth01 > texcoords[i][compare_coord]) luminance -= d;
3094 if (depth10 > texcoords[i][compare_coord]) luminance -= d;
3095 if (depth11 > texcoords[i][compare_coord]) luminance -= d;
3096 result = (GLchan) luminance;
3097 break;
3098 case GL_EQUAL:
3099 if (depth00 == texcoords[i][compare_coord]) luminance -= d;
3100 if (depth01 == texcoords[i][compare_coord]) luminance -= d;
3101 if (depth10 == texcoords[i][compare_coord]) luminance -= d;
3102 if (depth11 == texcoords[i][compare_coord]) luminance -= d;
3103 result = (GLchan) luminance;
3104 break;
3105 case GL_NOTEQUAL:
3106 if (depth00 != texcoords[i][compare_coord]) luminance -= d;
3107 if (depth01 != texcoords[i][compare_coord]) luminance -= d;
3108 if (depth10 != texcoords[i][compare_coord]) luminance -= d;
3109 if (depth11 != texcoords[i][compare_coord]) luminance -= d;
3110 result = (GLchan) luminance;
3111 break;
3112 case GL_ALWAYS:
3113 result = 0;
3114 break;
3115 case GL_NEVER:
3116 result = CHAN_MAX;
3117 break;
3118 case GL_NONE:
3119 /* ordinary bilinear filtering */
3120 {
3121 const GLfloat depthSample
3122 = lerp_2d(a, b, depth00, depth10, depth01, depth11);
3123 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
3124 }
3125 break;
3126 default:
3127 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
3128 return;
3129 }
3130 }
3131
3132 switch (tObj->DepthMode) {
3133 case GL_LUMINANCE:
3134 texel[i][RCOMP] = result;
3135 texel[i][GCOMP] = result;
3136 texel[i][BCOMP] = result;
3137 texel[i][ACOMP] = CHAN_MAX;
3138 break;
3139 case GL_INTENSITY:
3140 texel[i][RCOMP] = result;
3141 texel[i][GCOMP] = result;
3142 texel[i][BCOMP] = result;
3143 texel[i][ACOMP] = result;
3144 break;
3145 case GL_ALPHA:
3146 texel[i][RCOMP] = 0;
3147 texel[i][GCOMP] = 0;
3148 texel[i][BCOMP] = 0;
3149 texel[i][ACOMP] = result;
3150 break;
3151 default:
3152 _mesa_problem(ctx, "Bad depth texture mode");
3153 }
3154 } /* for */
3155 } /* if filter */
3156 }
3157
3158
3159 /**
3160 * We use this function when a texture object is in an "incomplete" state.
3161 * When a fragment program attempts to sample an incomplete texture we
3162 * return black (see issue 23 in GL_ARB_fragment_program spec).
3163 * Note: fragment programs don't observe the texture enable/disable flags.
3164 */
3165 static void
3166 null_sample_func( GLcontext *ctx,
3167 const struct gl_texture_object *tObj, GLuint n,
3168 const GLfloat texcoords[][4], const GLfloat lambda[],
3169 GLchan rgba[][4])
3170 {
3171 GLuint i;
3172 (void) ctx;
3173 (void) tObj;
3174 (void) texcoords;
3175 (void) lambda;
3176 for (i = 0; i < n; i++) {
3177 rgba[i][RCOMP] = 0;
3178 rgba[i][GCOMP] = 0;
3179 rgba[i][BCOMP] = 0;
3180 rgba[i][ACOMP] = CHAN_MAX;
3181 }
3182 }
3183
3184
3185 /**
3186 * Choose the texture sampling function for the given texture object.
3187 */
3188 texture_sample_func
3189 _swrast_choose_texture_sample_func( GLcontext *ctx,
3190 const struct gl_texture_object *t )
3191 {
3192 if (!t || !t->_Complete) {
3193 return &null_sample_func;
3194 }
3195 else {
3196 const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
3197 const GLenum format = t->Image[0][t->BaseLevel]->TexFormat->BaseFormat;
3198
3199 switch (t->Target) {
3200 case GL_TEXTURE_1D:
3201 if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
3202 return &sample_depth_texture;
3203 }
3204 else if (needLambda) {
3205 return &sample_lambda_1d;
3206 }
3207 else if (t->MinFilter == GL_LINEAR) {
3208 return &sample_linear_1d;
3209 }
3210 else {
3211 ASSERT(t->MinFilter == GL_NEAREST);
3212 return &sample_nearest_1d;
3213 }
3214 case GL_TEXTURE_2D:
3215 if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
3216 return &sample_depth_texture;
3217 }
3218 else if (needLambda) {
3219 return &sample_lambda_2d;
3220 }
3221 else if (t->MinFilter == GL_LINEAR) {
3222 return &sample_linear_2d;
3223 }
3224 else {
3225 /* check for a few optimized cases */
3226 const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
3227 ASSERT(t->MinFilter == GL_NEAREST);
3228 if (t->WrapS == GL_REPEAT &&
3229 t->WrapT == GL_REPEAT &&
3230 img->_IsPowerOfTwo &&
3231 img->Border == 0 &&
3232 img->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
3233 return &opt_sample_rgb_2d;
3234 }
3235 else if (t->WrapS == GL_REPEAT &&
3236 t->WrapT == GL_REPEAT &&
3237 img->_IsPowerOfTwo &&
3238 img->Border == 0 &&
3239 img->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
3240 return &opt_sample_rgba_2d;
3241 }
3242 else {
3243 return &sample_nearest_2d;
3244 }
3245 }
3246 case GL_TEXTURE_3D:
3247 if (needLambda) {
3248 return &sample_lambda_3d;
3249 }
3250 else if (t->MinFilter == GL_LINEAR) {
3251 return &sample_linear_3d;
3252 }
3253 else {
3254 ASSERT(t->MinFilter == GL_NEAREST);
3255 return &sample_nearest_3d;
3256 }
3257 case GL_TEXTURE_CUBE_MAP:
3258 if (needLambda) {
3259 return &sample_lambda_cube;
3260 }
3261 else if (t->MinFilter == GL_LINEAR) {
3262 return &sample_linear_cube;
3263 }
3264 else {
3265 ASSERT(t->MinFilter == GL_NEAREST);
3266 return &sample_nearest_cube;
3267 }
3268 case GL_TEXTURE_RECTANGLE_NV:
3269 if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) {
3270 return &sample_depth_texture;
3271 }
3272 else if (needLambda) {
3273 return &sample_lambda_rect;
3274 }
3275 else if (t->MinFilter == GL_LINEAR) {
3276 return &sample_linear_rect;
3277 }
3278 else {
3279 ASSERT(t->MinFilter == GL_NEAREST);
3280 return &sample_nearest_rect;
3281 }
3282 case GL_TEXTURE_1D_ARRAY_EXT:
3283 if (needLambda) {
3284 return &sample_lambda_1d_array;
3285 }
3286 else if (t->MinFilter == GL_LINEAR) {
3287 return &sample_linear_1d_array;
3288 }
3289 else {
3290 ASSERT(t->MinFilter == GL_NEAREST);
3291 return &sample_nearest_1d_array;
3292 }
3293 case GL_TEXTURE_2D_ARRAY_EXT:
3294 if (needLambda) {
3295 return &sample_lambda_2d_array;
3296 }
3297 else if (t->MinFilter == GL_LINEAR) {
3298 return &sample_linear_2d_array;
3299 }
3300 else {
3301 ASSERT(t->MinFilter == GL_NEAREST);
3302 return &sample_nearest_2d_array;
3303 }
3304 default:
3305 _mesa_problem(ctx,
3306 "invalid target in _swrast_choose_texture_sample_func");
3307 return &null_sample_func;
3308 }
3309 }
3310 }