gallium: new/better debug code (disabled)
[mesa.git] / src / gallium / drivers / softpipe / sp_tex_sample.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * Texture sampling
30 *
31 * Authors:
32 * Brian Paul
33 */
34
35 #include "sp_context.h"
36 #include "sp_headers.h"
37 #include "sp_surface.h"
38 #include "sp_tex_sample.h"
39 #include "sp_tile_cache.h"
40 #include "pipe/p_context.h"
41 #include "pipe/p_defines.h"
42 #include "pipe/p_util.h"
43 #include "tgsi/tgsi_exec.h"
44
45
46 /*
47 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
48 * see 1-pixel bands of improperly weighted linear-filtered textures.
49 * The tests/texwrap.c demo is a good test.
50 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
51 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
52 */
53 #define FRAC(f) ((f) - ifloor(f))
54
55
56 /**
57 * Linear interpolation macro
58 */
59 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
60
61
62 /**
63 * Do 2D/biliner interpolation of float values.
64 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
65 * a and b are the horizontal and vertical interpolants.
66 * It's important that this function is inlined when compiled with
67 * optimization! If we find that's not true on some systems, convert
68 * to a macro.
69 */
70 static INLINE float
71 lerp_2d(float a, float b,
72 float v00, float v10, float v01, float v11)
73 {
74 const float temp0 = LERP(a, v00, v10);
75 const float temp1 = LERP(a, v01, v11);
76 return LERP(b, temp0, temp1);
77 }
78
79
80 /**
81 * If A is a signed integer, A % B doesn't give the right value for A < 0
82 * (in terms of texture repeat). Just casting to unsigned fixes that.
83 */
84 #define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
85
86
87 /**
88 * Apply texture coord wrapping mode and return integer texture index.
89 * \param wrapMode PIPE_TEX_WRAP_x
90 * \param s the texcoord
91 * \param size the texture image size
92 * \return integer texture index
93 */
94 static INLINE int
95 nearest_texcoord(unsigned wrapMode, float s, unsigned size)
96 {
97 int i;
98 switch (wrapMode) {
99 case PIPE_TEX_WRAP_REPEAT:
100 /* s limited to [0,1) */
101 /* i limited to [0,size-1] */
102 i = ifloor(s * size);
103 i = REMAINDER(i, size);
104 return i;
105 case PIPE_TEX_WRAP_CLAMP:
106 /* s limited to [0,1] */
107 /* i limited to [0,size-1] */
108 if (s <= 0.0F)
109 i = 0;
110 else if (s >= 1.0F)
111 i = size - 1;
112 else
113 i = ifloor(s * size);
114 return i;
115 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
116 {
117 /* s limited to [min,max] */
118 /* i limited to [0, size-1] */
119 const float min = 1.0F / (2.0F * size);
120 const float max = 1.0F - min;
121 if (s < min)
122 i = 0;
123 else if (s > max)
124 i = size - 1;
125 else
126 i = ifloor(s * size);
127 }
128 return i;
129 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
130 {
131 /* s limited to [min,max] */
132 /* i limited to [-1, size] */
133 const float min = -1.0F / (2.0F * size);
134 const float max = 1.0F - min;
135 if (s <= min)
136 i = -1;
137 else if (s >= max)
138 i = size;
139 else
140 i = ifloor(s * size);
141 }
142 return i;
143 case PIPE_TEX_WRAP_MIRROR_REPEAT:
144 {
145 const float min = 1.0F / (2.0F * size);
146 const float max = 1.0F - min;
147 const int flr = ifloor(s);
148 float u;
149 if (flr & 1)
150 u = 1.0F - (s - (float) flr);
151 else
152 u = s - (float) flr;
153 if (u < min)
154 i = 0;
155 else if (u > max)
156 i = size - 1;
157 else
158 i = ifloor(u * size);
159 }
160 return i;
161 case PIPE_TEX_WRAP_MIRROR_CLAMP:
162 {
163 /* s limited to [0,1] */
164 /* i limited to [0,size-1] */
165 const float u = FABSF(s);
166 if (u <= 0.0F)
167 i = 0;
168 else if (u >= 1.0F)
169 i = size - 1;
170 else
171 i = ifloor(u * size);
172 }
173 return i;
174 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
175 {
176 /* s limited to [min,max] */
177 /* i limited to [0, size-1] */
178 const float min = 1.0F / (2.0F * size);
179 const float max = 1.0F - min;
180 const float u = FABSF(s);
181 if (u < min)
182 i = 0;
183 else if (u > max)
184 i = size - 1;
185 else
186 i = ifloor(u * size);
187 }
188 return i;
189 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
190 {
191 /* s limited to [min,max] */
192 /* i limited to [0, size-1] */
193 const float min = -1.0F / (2.0F * size);
194 const float max = 1.0F - min;
195 const float u = FABSF(s);
196 if (u < min)
197 i = -1;
198 else if (u > max)
199 i = size;
200 else
201 i = ifloor(u * size);
202 }
203 return i;
204 default:
205 assert(0);
206 return 0;
207 }
208 }
209
210
211 /**
212 * Used to compute texel locations for linear sampling.
213 * \param wrapMode PIPE_TEX_WRAP_x
214 * \param s the texcoord
215 * \param size the texture image size
216 * \param i0 returns first texture index
217 * \param i1 returns second texture index (usually *i0 + 1)
218 * \param a returns blend factor/weight between texture indexes
219 */
220 static INLINE void
221 linear_texcoord(unsigned wrapMode, float s, unsigned size,
222 int *i0, int *i1, float *a)
223 {
224 float u;
225 switch (wrapMode) {
226 case PIPE_TEX_WRAP_REPEAT:
227 u = s * size - 0.5F;
228 *i0 = REMAINDER(ifloor(u), size);
229 *i1 = REMAINDER(*i0 + 1, size);
230 break;
231 case PIPE_TEX_WRAP_CLAMP:
232 if (s <= 0.0F)
233 u = 0.0F;
234 else if (s >= 1.0F)
235 u = (float) size;
236 else
237 u = s * size;
238 u -= 0.5F;
239 *i0 = ifloor(u);
240 *i1 = *i0 + 1;
241 break;
242 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
243 if (s <= 0.0F)
244 u = 0.0F;
245 else if (s >= 1.0F)
246 u = (float) size;
247 else
248 u = s * size;
249 u -= 0.5F;
250 *i0 = ifloor(u);
251 *i1 = *i0 + 1;
252 if (*i0 < 0)
253 *i0 = 0;
254 if (*i1 >= (int) size)
255 *i1 = size - 1;
256 break;
257 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
258 {
259 const float min = -1.0F / (2.0F * size);
260 const float max = 1.0F - min;
261 if (s <= min)
262 u = min * size;
263 else if (s >= max)
264 u = max * size;
265 else
266 u = s * size;
267 u -= 0.5F;
268 *i0 = ifloor(u);
269 *i1 = *i0 + 1;
270 }
271 break;
272 case PIPE_TEX_WRAP_MIRROR_REPEAT:
273 {
274 const int flr = ifloor(s);
275 if (flr & 1)
276 u = 1.0F - (s - (float) flr);
277 else
278 u = s - (float) flr;
279 u = (u * size) - 0.5F;
280 *i0 = ifloor(u);
281 *i1 = *i0 + 1;
282 if (*i0 < 0)
283 *i0 = 0;
284 if (*i1 >= (int) size)
285 *i1 = size - 1;
286 }
287 break;
288 case PIPE_TEX_WRAP_MIRROR_CLAMP:
289 u = FABSF(s);
290 if (u >= 1.0F)
291 u = (float) size;
292 else
293 u *= size;
294 u -= 0.5F;
295 *i0 = ifloor(u);
296 *i1 = *i0 + 1;
297 break;
298 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
299 u = FABSF(s);
300 if (u >= 1.0F)
301 u = (float) size;
302 else
303 u *= size;
304 u -= 0.5F;
305 *i0 = ifloor(u);
306 *i1 = *i0 + 1;
307 if (*i0 < 0)
308 *i0 = 0;
309 if (*i1 >= (int) size)
310 *i1 = size - 1;
311 break;
312 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
313 {
314 const float min = -1.0F / (2.0F * size);
315 const float max = 1.0F - min;
316 u = FABSF(s);
317 if (u <= min)
318 u = min * size;
319 else if (u >= max)
320 u = max * size;
321 else
322 u *= size;
323 u -= 0.5F;
324 *i0 = ifloor(u);
325 *i1 = *i0 + 1;
326 }
327 break;
328 default:
329 assert(0);
330 }
331 *a = FRAC(u);
332 }
333
334
335 /**
336 * For RECT textures / unnormalized texcoords
337 * Only a subset of wrap modes supported.
338 */
339 static INLINE int
340 nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size)
341 {
342 int i;
343 switch (wrapMode) {
344 case PIPE_TEX_WRAP_CLAMP:
345 i = ifloor(s);
346 return CLAMP(i, 0, (int) size-1);
347 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
348 /* fall-through */
349 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
350 return ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) );
351 default:
352 assert(0);
353 return 0;
354 }
355 }
356
357
358 /**
359 * For RECT textures / unnormalized texcoords.
360 * Only a subset of wrap modes supported.
361 */
362 static INLINE void
363 linear_texcoord_unnorm(unsigned wrapMode, float s, unsigned size,
364 int *i0, int *i1, float *a)
365 {
366 switch (wrapMode) {
367 case PIPE_TEX_WRAP_CLAMP:
368 /* Not exactly what the spec says, but it matches NVIDIA output */
369 s = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f);
370 *i0 = ifloor(s);
371 *i1 = *i0 + 1;
372 break;
373 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
374 /* fall-through */
375 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
376 s = CLAMP(s, 0.5F, (float) size - 0.5F);
377 s -= 0.5F;
378 *i0 = ifloor(s);
379 *i1 = *i0 + 1;
380 if (*i1 > (int) size - 1)
381 *i1 = size - 1;
382 break;
383 default:
384 assert(0);
385 }
386 *a = FRAC(s);
387 }
388
389
390 static unsigned
391 choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
392 {
393 /*
394 major axis
395 direction target sc tc ma
396 ---------- ------------------------------- --- --- ---
397 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
398 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
399 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
400 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
401 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
402 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
403 */
404 const float arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
405 unsigned face;
406 float sc, tc, ma;
407
408 if (arx > ary && arx > arz) {
409 if (rx >= 0.0F) {
410 face = PIPE_TEX_FACE_POS_X;
411 sc = -rz;
412 tc = -ry;
413 ma = arx;
414 }
415 else {
416 face = PIPE_TEX_FACE_NEG_X;
417 sc = rz;
418 tc = -ry;
419 ma = arx;
420 }
421 }
422 else if (ary > arx && ary > arz) {
423 if (ry >= 0.0F) {
424 face = PIPE_TEX_FACE_POS_Y;
425 sc = rx;
426 tc = rz;
427 ma = ary;
428 }
429 else {
430 face = PIPE_TEX_FACE_NEG_Y;
431 sc = rx;
432 tc = -rz;
433 ma = ary;
434 }
435 }
436 else {
437 if (rz > 0.0F) {
438 face = PIPE_TEX_FACE_POS_Z;
439 sc = rx;
440 tc = -ry;
441 ma = arz;
442 }
443 else {
444 face = PIPE_TEX_FACE_NEG_Z;
445 sc = -rx;
446 tc = -ry;
447 ma = arz;
448 }
449 }
450
451 *newS = ( sc / ma + 1.0F ) * 0.5F;
452 *newT = ( tc / ma + 1.0F ) * 0.5F;
453
454 return face;
455 }
456
457
458 /**
459 * Examine the quad's texture coordinates to compute the partial
460 * derivatives w.r.t X and Y, then compute lambda (level of detail).
461 *
462 * This is only done for fragment shaders, not vertex shaders.
463 */
464 static float
465 compute_lambda(struct tgsi_sampler *sampler,
466 const float s[QUAD_SIZE],
467 const float t[QUAD_SIZE],
468 const float p[QUAD_SIZE],
469 float lodbias)
470 {
471 float rho, lambda;
472
473 assert(sampler->state->normalized_coords);
474
475 assert(s);
476 {
477 float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
478 float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT];
479 dsdx = FABSF(dsdx);
480 dsdy = FABSF(dsdy);
481 rho = MAX2(dsdx, dsdy) * sampler->texture->width[0];
482 }
483 if (t) {
484 float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
485 float dtdy = t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT];
486 float max;
487 dtdx = FABSF(dtdx);
488 dtdy = FABSF(dtdy);
489 max = MAX2(dtdx, dtdy) * sampler->texture->height[0];
490 rho = MAX2(rho, max);
491 }
492 if (p) {
493 float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
494 float dpdy = p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT];
495 float max;
496 dpdx = FABSF(dpdx);
497 dpdy = FABSF(dpdy);
498 max = MAX2(dpdx, dpdy) * sampler->texture->depth[0];
499 rho = MAX2(rho, max);
500 }
501
502 lambda = LOG2(rho);
503 lambda += lodbias + sampler->state->lod_bias;
504 lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
505
506 return lambda;
507 }
508
509
510 /**
511 * Do several things here:
512 * 1. Compute lambda from the texcoords, if needed
513 * 2. Determine if we're minifying or magnifying
514 * 3. If minifying, choose mipmap levels
515 * 4. Return image filter to use within mipmap images
516 */
517 static void
518 choose_mipmap_levels(struct tgsi_sampler *sampler,
519 const float s[QUAD_SIZE],
520 const float t[QUAD_SIZE],
521 const float p[QUAD_SIZE],
522 float lodbias,
523 unsigned *level0, unsigned *level1, float *levelBlend,
524 unsigned *imgFilter)
525 {
526 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
527 /* no mipmap selection needed */
528 *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
529 0, (int) sampler->texture->last_level);
530
531 if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
532 /* non-mipmapped texture, but still need to determine if doing
533 * minification or magnification.
534 */
535 float lambda = compute_lambda(sampler, s, t, p, lodbias);
536 if (lambda <= 0.0) {
537 *imgFilter = sampler->state->mag_img_filter;
538 }
539 else {
540 *imgFilter = sampler->state->min_img_filter;
541 }
542 }
543 else {
544 *imgFilter = sampler->state->mag_img_filter;
545 }
546 }
547 else {
548 float lambda;
549
550 if (1)
551 /* fragment shader */
552 lambda = compute_lambda(sampler, s, t, p, lodbias);
553 else
554 /* vertex shader */
555 lambda = lodbias; /* not really a bias, but absolute LOD */
556
557 if (lambda <= 0.0) { /* XXX threshold depends on the filter */
558 /* magnifying */
559 *imgFilter = sampler->state->mag_img_filter;
560 *level0 = *level1 = 0;
561 }
562 else {
563 /* minifying */
564 *imgFilter = sampler->state->min_img_filter;
565
566 /* choose mipmap level(s) and compute the blend factor between them */
567 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
568 /* Nearest mipmap level */
569 const int lvl = (int) (lambda + 0.5);
570 *level0 =
571 *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
572 }
573 else {
574 /* Linear interpolation between mipmap levels */
575 const int lvl = (int) lambda;
576 *level0 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
577 *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
578 *levelBlend = FRAC(lambda); /* blending weight between levels */
579 }
580 }
581 }
582 }
583
584
585 /**
586 * Get a texel from a texture, using the texture tile cache.
587 *
588 * \param face the cube face in 0..5
589 * \param level the mipmap level
590 * \param x the x coord of texel within 2D image
591 * \param y the y coord of texel within 2D image
592 * \param z which slice of a 3D texture
593 * \param rgba the quad to put the texel/color into
594 * \param j which element of the rgba quad to write to
595 *
596 * XXX maybe move this into sp_tile_cache.c and merge with the
597 * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1...
598 */
599 static void
600 get_texel(struct tgsi_sampler *sampler,
601 unsigned face, unsigned level, int x, int y, int z,
602 float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
603 {
604 if (x < 0 || x >= (int) sampler->texture->width[level] ||
605 y < 0 || y >= (int) sampler->texture->height[level] ||
606 z < 0 || z >= (int) sampler->texture->depth[level]) {
607 rgba[0][j] = sampler->state->border_color[0];
608 rgba[1][j] = sampler->state->border_color[1];
609 rgba[2][j] = sampler->state->border_color[2];
610 rgba[3][j] = sampler->state->border_color[3];
611 }
612 else {
613 const int tx = x % TILE_SIZE;
614 const int ty = y % TILE_SIZE;
615 const struct softpipe_cached_tile *tile
616 = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
617 x, y, z, face, level);
618 rgba[0][j] = tile->data.color[ty][tx][0];
619 rgba[1][j] = tile->data.color[ty][tx][1];
620 rgba[2][j] = tile->data.color[ty][tx][2];
621 rgba[3][j] = tile->data.color[ty][tx][3];
622 if (0)
623 {
624 char fmt[100];
625 pf_sprint_name( fmt, sampler->texture->format);
626 printf("Get texel %f %f %f %f from %s\n",
627 rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j], fmt);
628 }
629 }
630 }
631
632
633 /**
634 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
635 * When we sampled the depth texture, the depth value was put into all
636 * RGBA channels. We look at the red channel here.
637 */
638 static INLINE void
639 shadow_compare(uint compare_func,
640 float rgba[NUM_CHANNELS][QUAD_SIZE],
641 const float p[QUAD_SIZE],
642 uint j)
643 {
644 int k;
645 switch (compare_func) {
646 case PIPE_FUNC_LESS:
647 k = p[j] < rgba[0][j];
648 break;
649 case PIPE_FUNC_LEQUAL:
650 k = p[j] <= rgba[0][j];
651 break;
652 case PIPE_FUNC_GREATER:
653 k = p[j] > rgba[0][j];
654 break;
655 case PIPE_FUNC_GEQUAL:
656 k = p[j] >= rgba[0][j];
657 break;
658 case PIPE_FUNC_EQUAL:
659 k = p[j] == rgba[0][j];
660 break;
661 case PIPE_FUNC_NOTEQUAL:
662 k = p[j] != rgba[0][j];
663 break;
664 case PIPE_FUNC_ALWAYS:
665 k = 1;
666 break;
667 case PIPE_FUNC_NEVER:
668 k = 0;
669 break;
670 default:
671 k = 0;
672 assert(0);
673 break;
674 }
675
676 rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
677 }
678
679
680 /**
681 * Common code for sampling 1D/2D/cube textures.
682 * Could probably extend for 3D...
683 */
684 static void
685 sp_get_samples_2d_common(struct tgsi_sampler *sampler,
686 const float s[QUAD_SIZE],
687 const float t[QUAD_SIZE],
688 const float p[QUAD_SIZE],
689 float lodbias,
690 float rgba[NUM_CHANNELS][QUAD_SIZE],
691 const unsigned faces[4])
692 {
693 const uint compare_func = sampler->state->compare_func;
694 unsigned level0, level1, j, imgFilter;
695 int width, height;
696 float levelBlend;
697
698 choose_mipmap_levels(sampler, s, t, p, lodbias,
699 &level0, &level1, &levelBlend, &imgFilter);
700
701 assert(sampler->state->normalized_coords);
702
703 width = sampler->texture->width[level0];
704 height = sampler->texture->height[level0];
705
706 assert(width > 0);
707
708 switch (imgFilter) {
709 case PIPE_TEX_FILTER_NEAREST:
710 for (j = 0; j < QUAD_SIZE; j++) {
711 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
712 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
713 get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
714 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
715 shadow_compare(compare_func, rgba, p, j);
716 }
717
718 if (level0 != level1) {
719 /* get texels from second mipmap level and blend */
720 float rgba2[4][4];
721 unsigned c;
722 x = x / 2;
723 y = y / 2;
724 get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
725 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
726 shadow_compare(compare_func, rgba2, p, j);
727 }
728
729 for (c = 0; c < NUM_CHANNELS; c++) {
730 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
731 }
732 }
733 }
734 break;
735 case PIPE_TEX_FILTER_LINEAR:
736 case PIPE_TEX_FILTER_ANISO:
737 for (j = 0; j < QUAD_SIZE; j++) {
738 float tx[4][4], a, b;
739 int x0, y0, x1, y1, c;
740 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
741 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
742 get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
743 get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
744 get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
745 get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
746 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
747 shadow_compare(compare_func, tx, p, 0);
748 shadow_compare(compare_func, tx, p, 1);
749 shadow_compare(compare_func, tx, p, 2);
750 shadow_compare(compare_func, tx, p, 3);
751 }
752
753 for (c = 0; c < 4; c++) {
754 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
755 }
756
757 if (level0 != level1) {
758 /* get texels from second mipmap level and blend */
759 float rgba2[4][4];
760 x0 = x0 / 2;
761 y0 = y0 / 2;
762 x1 = x1 / 2;
763 y1 = y1 / 2;
764 get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
765 get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
766 get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
767 get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
768 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
769 shadow_compare(compare_func, tx, p, 0);
770 shadow_compare(compare_func, tx, p, 1);
771 shadow_compare(compare_func, tx, p, 2);
772 shadow_compare(compare_func, tx, p, 3);
773 }
774
775 for (c = 0; c < 4; c++) {
776 rgba2[c][j] = lerp_2d(a, b,
777 tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
778 }
779
780 for (c = 0; c < NUM_CHANNELS; c++) {
781 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
782 }
783 }
784 }
785 break;
786 default:
787 assert(0);
788 }
789 }
790
791
792 static void
793 sp_get_samples_1d(struct tgsi_sampler *sampler,
794 const float s[QUAD_SIZE],
795 const float t[QUAD_SIZE],
796 const float p[QUAD_SIZE],
797 float lodbias,
798 float rgba[NUM_CHANNELS][QUAD_SIZE])
799 {
800 static const unsigned faces[4] = {0, 0, 0, 0};
801 static const float tzero[4] = {0, 0, 0, 0};
802 sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
803 }
804
805
806 static void
807 sp_get_samples_2d(struct tgsi_sampler *sampler,
808 const float s[QUAD_SIZE],
809 const float t[QUAD_SIZE],
810 const float p[QUAD_SIZE],
811 float lodbias,
812 float rgba[NUM_CHANNELS][QUAD_SIZE])
813 {
814 static const unsigned faces[4] = {0, 0, 0, 0};
815 sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
816 }
817
818
819 static void
820 sp_get_samples_3d(struct tgsi_sampler *sampler,
821 const float s[QUAD_SIZE],
822 const float t[QUAD_SIZE],
823 const float p[QUAD_SIZE],
824 float lodbias,
825 float rgba[NUM_CHANNELS][QUAD_SIZE])
826 {
827 /* get/map pipe_surfaces corresponding to 3D tex slices */
828 unsigned level0, level1, j, imgFilter;
829 int width, height, depth;
830 float levelBlend;
831 const uint face = 0;
832
833 choose_mipmap_levels(sampler, s, t, p, lodbias,
834 &level0, &level1, &levelBlend, &imgFilter);
835
836 assert(sampler->state->normalized_coords);
837
838 width = sampler->texture->width[level0];
839 height = sampler->texture->height[level0];
840 depth = sampler->texture->depth[level0];
841
842 assert(width > 0);
843 assert(height > 0);
844 assert(depth > 0);
845
846 switch (imgFilter) {
847 case PIPE_TEX_FILTER_NEAREST:
848 for (j = 0; j < QUAD_SIZE; j++) {
849 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
850 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
851 int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
852 get_texel(sampler, face, level0, x, y, z, rgba, j);
853
854 if (level0 != level1) {
855 /* get texels from second mipmap level and blend */
856 float rgba2[4][4];
857 unsigned c;
858 x /= 2;
859 y /= 2;
860 z /= 2;
861 get_texel(sampler, face, level1, x, y, z, rgba2, j);
862 for (c = 0; c < NUM_CHANNELS; c++) {
863 rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
864 }
865 }
866 }
867 break;
868 case PIPE_TEX_FILTER_LINEAR:
869 case PIPE_TEX_FILTER_ANISO:
870 for (j = 0; j < QUAD_SIZE; j++) {
871 float texel0[4][4], texel1[4][4];
872 float xw, yw, zw; /* interpolation weights */
873 int x0, x1, y0, y1, z0, z1, c;
874 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &xw);
875 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
876 linear_texcoord(sampler->state->wrap_r, p[j], depth, &z0, &z1, &zw);
877 get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
878 get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
879 get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
880 get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
881 get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
882 get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
883 get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
884 get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
885
886 /* 3D lerp */
887 for (c = 0; c < 4; c++) {
888 float ctemp0[4][4], ctemp1[4][4];
889 ctemp0[c][j] = lerp_2d(xw, yw,
890 texel0[c][0], texel0[c][1],
891 texel0[c][2], texel0[c][3]);
892 ctemp1[c][j] = lerp_2d(xw, yw,
893 texel1[c][0], texel1[c][1],
894 texel1[c][2], texel1[c][3]);
895 rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
896 }
897
898 if (level0 != level1) {
899 /* get texels from second mipmap level and blend */
900 float rgba2[4][4];
901 x0 /= 2;
902 y0 /= 2;
903 z0 /= 2;
904 x1 /= 2;
905 y1 /= 2;
906 z1 /= 2;
907 get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
908 get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
909 get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
910 get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
911 get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
912 get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
913 get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
914 get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
915
916 /* 3D lerp */
917 for (c = 0; c < 4; c++) {
918 float ctemp0[4][4], ctemp1[4][4];
919 ctemp0[c][j] = lerp_2d(xw, yw,
920 texel0[c][0], texel0[c][1],
921 texel0[c][2], texel0[c][3]);
922 ctemp1[c][j] = lerp_2d(xw, yw,
923 texel1[c][0], texel1[c][1],
924 texel1[c][2], texel1[c][3]);
925 rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
926 }
927
928 /* blend mipmap levels */
929 for (c = 0; c < NUM_CHANNELS; c++) {
930 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
931 }
932 }
933 }
934 break;
935 default:
936 assert(0);
937 }
938 }
939
940
941 static void
942 sp_get_samples_cube(struct tgsi_sampler *sampler,
943 const float s[QUAD_SIZE],
944 const float t[QUAD_SIZE],
945 const float p[QUAD_SIZE],
946 float lodbias,
947 float rgba[NUM_CHANNELS][QUAD_SIZE])
948 {
949 unsigned faces[QUAD_SIZE], j;
950 float ssss[4], tttt[4];
951 for (j = 0; j < QUAD_SIZE; j++) {
952 faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
953 }
954 sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
955 }
956
957
958 static void
959 sp_get_samples_rect(struct tgsi_sampler *sampler,
960 const float s[QUAD_SIZE],
961 const float t[QUAD_SIZE],
962 const float p[QUAD_SIZE],
963 float lodbias,
964 float rgba[NUM_CHANNELS][QUAD_SIZE])
965 {
966 //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
967 static const uint face = 0;
968 const uint compare_func = sampler->state->compare_func;
969 unsigned level0, level1, j, imgFilter;
970 int width, height;
971 float levelBlend;
972
973 choose_mipmap_levels(sampler, s, t, p, lodbias,
974 &level0, &level1, &levelBlend, &imgFilter);
975
976 /* texture RECTS cannot be mipmapped */
977 assert(level0 == level1);
978
979 width = sampler->texture->width[level0];
980 height = sampler->texture->height[level0];
981
982 assert(width > 0);
983
984 switch (imgFilter) {
985 case PIPE_TEX_FILTER_NEAREST:
986 for (j = 0; j < QUAD_SIZE; j++) {
987 int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width);
988 int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height);
989 get_texel(sampler, face, level0, x, y, 0, rgba, j);
990 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
991 shadow_compare(compare_func, rgba, p, j);
992 }
993 }
994 break;
995 case PIPE_TEX_FILTER_LINEAR:
996 case PIPE_TEX_FILTER_ANISO:
997 for (j = 0; j < QUAD_SIZE; j++) {
998 float tx[4][4], a, b;
999 int x0, y0, x1, y1, c;
1000 linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
1001 linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
1002 get_texel(sampler, face, level0, x0, y0, 0, tx, 0);
1003 get_texel(sampler, face, level0, x1, y0, 0, tx, 1);
1004 get_texel(sampler, face, level0, x0, y1, 0, tx, 2);
1005 get_texel(sampler, face, level0, x1, y1, 0, tx, 3);
1006 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
1007 shadow_compare(compare_func, tx, p, 0);
1008 shadow_compare(compare_func, tx, p, 1);
1009 shadow_compare(compare_func, tx, p, 2);
1010 shadow_compare(compare_func, tx, p, 3);
1011 }
1012
1013 for (c = 0; c < 4; c++) {
1014 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
1015 }
1016 }
1017 break;
1018 default:
1019 assert(0);
1020 }
1021 }
1022
1023
1024
1025
1026 /**
1027 * Called via tgsi_sampler::get_samples()
1028 * Use the sampler's state setting to get a filtered RGBA value
1029 * from the sampler's texture.
1030 *
1031 * XXX we can implement many versions of this function, each
1032 * tightly coded for a specific combination of sampler state
1033 * (nearest + repeat), (bilinear mipmap + clamp), etc.
1034 *
1035 * The update_samplers() function in st_atom_sampler.c could create
1036 * a new tgsi_sampler object for each state combo it finds....
1037 */
1038 void
1039 sp_get_samples(struct tgsi_sampler *sampler,
1040 const float s[QUAD_SIZE],
1041 const float t[QUAD_SIZE],
1042 const float p[QUAD_SIZE],
1043 float lodbias,
1044 float rgba[NUM_CHANNELS][QUAD_SIZE])
1045 {
1046 if (!sampler->texture)
1047 return;
1048
1049 switch (sampler->texture->target) {
1050 case PIPE_TEXTURE_1D:
1051 assert(sampler->state->normalized_coords);
1052 sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
1053 break;
1054 case PIPE_TEXTURE_2D:
1055 if (sampler->state->normalized_coords)
1056 sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
1057 else
1058 sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
1059 break;
1060 case PIPE_TEXTURE_3D:
1061 assert(sampler->state->normalized_coords);
1062 sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
1063 break;
1064 case PIPE_TEXTURE_CUBE:
1065 assert(sampler->state->normalized_coords);
1066 sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
1067 break;
1068 default:
1069 assert(0);
1070 }
1071
1072 #if 0 /* DEBUG */
1073 {
1074 int i;
1075 printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
1076 for (i = 0; i < 4; i++) {
1077 printf("Frag %d: %f %f %f %f\n", i,
1078 rgba[0][i],
1079 rgba[1][i],
1080 rgba[2][i],
1081 rgba[3][i]);
1082 }
1083 }
1084 #endif
1085 }
1086