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