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