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