Merge commit 'origin/master' into gallium-0.2
[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 "tgsi/tgsi_exec.h"
43 #include "util/u_math.h"
44 #include "util/u_memory.h"
45
46
47 /*
48 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
49 * see 1-pixel bands of improperly weighted linear-filtered textures.
50 * The tests/texwrap.c demo is a good test.
51 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
52 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
53 */
54 #define FRAC(f) ((f) - util_ifloor(f))
55
56
57 /**
58 * Linear interpolation macro
59 */
60 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
61
62
63 /**
64 * Do 2D/biliner interpolation of float values.
65 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
66 * a and b are the horizontal and vertical interpolants.
67 * It's important that this function is inlined when compiled with
68 * optimization! If we find that's not true on some systems, convert
69 * to a macro.
70 */
71 static INLINE float
72 lerp_2d(float a, float b,
73 float v00, float v10, float v01, float v11)
74 {
75 const float temp0 = LERP(a, v00, v10);
76 const float temp1 = LERP(a, v01, v11);
77 return LERP(b, temp0, temp1);
78 }
79
80
81 /**
82 * If A is a signed integer, A % B doesn't give the right value for A < 0
83 * (in terms of texture repeat). Just casting to unsigned fixes that.
84 */
85 #define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
86
87
88 /**
89 * Apply texture coord wrapping mode and return integer texture index.
90 * \param wrapMode PIPE_TEX_WRAP_x
91 * \param s the texcoord
92 * \param size the texture image size
93 * \return integer texture index
94 */
95 static INLINE int
96 nearest_texcoord(unsigned wrapMode, float s, unsigned size)
97 {
98 int i;
99 switch (wrapMode) {
100 case PIPE_TEX_WRAP_REPEAT:
101 /* s limited to [0,1) */
102 /* i limited to [0,size-1] */
103 i = util_ifloor(s * size);
104 i = REMAINDER(i, size);
105 return i;
106 case PIPE_TEX_WRAP_CLAMP:
107 /* s limited to [0,1] */
108 /* i limited to [0,size-1] */
109 if (s <= 0.0F)
110 i = 0;
111 else if (s >= 1.0F)
112 i = size - 1;
113 else
114 i = util_ifloor(s * size);
115 return i;
116 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
117 {
118 /* s limited to [min,max] */
119 /* i limited to [0, size-1] */
120 const float min = 1.0F / (2.0F * size);
121 const float max = 1.0F - min;
122 if (s < min)
123 i = 0;
124 else if (s > max)
125 i = size - 1;
126 else
127 i = util_ifloor(s * size);
128 }
129 return i;
130 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
131 {
132 /* s limited to [min,max] */
133 /* i limited to [-1, size] */
134 const float min = -1.0F / (2.0F * size);
135 const float max = 1.0F - min;
136 if (s <= min)
137 i = -1;
138 else if (s >= max)
139 i = size;
140 else
141 i = util_ifloor(s * size);
142 }
143 return i;
144 case PIPE_TEX_WRAP_MIRROR_REPEAT:
145 {
146 const float min = 1.0F / (2.0F * size);
147 const float max = 1.0F - min;
148 const int flr = util_ifloor(s);
149 float u;
150 if (flr & 1)
151 u = 1.0F - (s - (float) flr);
152 else
153 u = s - (float) flr;
154 if (u < min)
155 i = 0;
156 else if (u > max)
157 i = size - 1;
158 else
159 i = util_ifloor(u * size);
160 }
161 return i;
162 case PIPE_TEX_WRAP_MIRROR_CLAMP:
163 {
164 /* s limited to [0,1] */
165 /* i limited to [0,size-1] */
166 const float u = fabsf(s);
167 if (u <= 0.0F)
168 i = 0;
169 else if (u >= 1.0F)
170 i = size - 1;
171 else
172 i = util_ifloor(u * size);
173 }
174 return i;
175 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
176 {
177 /* s limited to [min,max] */
178 /* i limited to [0, size-1] */
179 const float min = 1.0F / (2.0F * size);
180 const float max = 1.0F - min;
181 const float u = fabsf(s);
182 if (u < min)
183 i = 0;
184 else if (u > max)
185 i = size - 1;
186 else
187 i = util_ifloor(u * size);
188 }
189 return i;
190 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
191 {
192 /* s limited to [min,max] */
193 /* i limited to [0, size-1] */
194 const float min = -1.0F / (2.0F * size);
195 const float max = 1.0F - min;
196 const float u = fabsf(s);
197 if (u < min)
198 i = -1;
199 else if (u > max)
200 i = size;
201 else
202 i = util_ifloor(u * size);
203 }
204 return i;
205 default:
206 assert(0);
207 return 0;
208 }
209 }
210
211
212 /**
213 * Used to compute texel locations for linear sampling.
214 * \param wrapMode PIPE_TEX_WRAP_x
215 * \param s the texcoord
216 * \param size the texture image size
217 * \param i0 returns first texture index
218 * \param i1 returns second texture index (usually *i0 + 1)
219 * \param a returns blend factor/weight between texture indexes
220 */
221 static INLINE void
222 linear_texcoord(unsigned wrapMode, float s, unsigned size,
223 int *i0, int *i1, float *a)
224 {
225 float u;
226 switch (wrapMode) {
227 case PIPE_TEX_WRAP_REPEAT:
228 u = s * size - 0.5F;
229 *i0 = REMAINDER(util_ifloor(u), size);
230 *i1 = REMAINDER(*i0 + 1, size);
231 break;
232 case PIPE_TEX_WRAP_CLAMP:
233 if (s <= 0.0F)
234 u = 0.0F;
235 else if (s >= 1.0F)
236 u = (float) size;
237 else
238 u = s * size;
239 u -= 0.5F;
240 *i0 = util_ifloor(u);
241 *i1 = *i0 + 1;
242 break;
243 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
244 if (s <= 0.0F)
245 u = 0.0F;
246 else if (s >= 1.0F)
247 u = (float) size;
248 else
249 u = s * size;
250 u -= 0.5F;
251 *i0 = util_ifloor(u);
252 *i1 = *i0 + 1;
253 if (*i0 < 0)
254 *i0 = 0;
255 if (*i1 >= (int) size)
256 *i1 = size - 1;
257 break;
258 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
259 {
260 const float min = -1.0F / (2.0F * size);
261 const float max = 1.0F - min;
262 if (s <= min)
263 u = min * size;
264 else if (s >= max)
265 u = max * size;
266 else
267 u = s * size;
268 u -= 0.5F;
269 *i0 = util_ifloor(u);
270 *i1 = *i0 + 1;
271 }
272 break;
273 case PIPE_TEX_WRAP_MIRROR_REPEAT:
274 {
275 const int flr = util_ifloor(s);
276 if (flr & 1)
277 u = 1.0F - (s - (float) flr);
278 else
279 u = s - (float) flr;
280 u = (u * size) - 0.5F;
281 *i0 = util_ifloor(u);
282 *i1 = *i0 + 1;
283 if (*i0 < 0)
284 *i0 = 0;
285 if (*i1 >= (int) size)
286 *i1 = size - 1;
287 }
288 break;
289 case PIPE_TEX_WRAP_MIRROR_CLAMP:
290 u = fabsf(s);
291 if (u >= 1.0F)
292 u = (float) size;
293 else
294 u *= size;
295 u -= 0.5F;
296 *i0 = util_ifloor(u);
297 *i1 = *i0 + 1;
298 break;
299 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
300 u = fabsf(s);
301 if (u >= 1.0F)
302 u = (float) size;
303 else
304 u *= size;
305 u -= 0.5F;
306 *i0 = util_ifloor(u);
307 *i1 = *i0 + 1;
308 if (*i0 < 0)
309 *i0 = 0;
310 if (*i1 >= (int) size)
311 *i1 = size - 1;
312 break;
313 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
314 {
315 const float min = -1.0F / (2.0F * size);
316 const float max = 1.0F - min;
317 u = fabsf(s);
318 if (u <= min)
319 u = min * size;
320 else if (u >= max)
321 u = max * size;
322 else
323 u *= size;
324 u -= 0.5F;
325 *i0 = util_ifloor(u);
326 *i1 = *i0 + 1;
327 }
328 break;
329 default:
330 assert(0);
331 }
332 *a = FRAC(u);
333 }
334
335
336 /**
337 * For RECT textures / unnormalized texcoords
338 * Only a subset of wrap modes supported.
339 */
340 static INLINE int
341 nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size)
342 {
343 int i;
344 switch (wrapMode) {
345 case PIPE_TEX_WRAP_CLAMP:
346 i = util_ifloor(s);
347 return CLAMP(i, 0, (int) size-1);
348 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
349 /* fall-through */
350 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
351 return util_ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) );
352 default:
353 assert(0);
354 return 0;
355 }
356 }
357
358
359 /**
360 * For RECT textures / unnormalized texcoords.
361 * Only a subset of wrap modes supported.
362 */
363 static INLINE void
364 linear_texcoord_unnorm(unsigned wrapMode, float s, unsigned size,
365 int *i0, int *i1, float *a)
366 {
367 switch (wrapMode) {
368 case PIPE_TEX_WRAP_CLAMP:
369 /* Not exactly what the spec says, but it matches NVIDIA output */
370 s = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f);
371 *i0 = util_ifloor(s);
372 *i1 = *i0 + 1;
373 break;
374 case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
375 /* fall-through */
376 case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
377 s = CLAMP(s, 0.5F, (float) size - 0.5F);
378 s -= 0.5F;
379 *i0 = util_ifloor(s);
380 *i1 = *i0 + 1;
381 if (*i1 > (int) size - 1)
382 *i1 = size - 1;
383 break;
384 default:
385 assert(0);
386 }
387 *a = FRAC(s);
388 }
389
390
391 static unsigned
392 choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
393 {
394 /*
395 major axis
396 direction target sc tc ma
397 ---------- ------------------------------- --- --- ---
398 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
399 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
400 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
401 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
402 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
403 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
404 */
405 const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
406 unsigned face;
407 float sc, tc, ma;
408
409 if (arx > ary && arx > arz) {
410 if (rx >= 0.0F) {
411 face = PIPE_TEX_FACE_POS_X;
412 sc = -rz;
413 tc = -ry;
414 ma = arx;
415 }
416 else {
417 face = PIPE_TEX_FACE_NEG_X;
418 sc = rz;
419 tc = -ry;
420 ma = arx;
421 }
422 }
423 else if (ary > arx && ary > arz) {
424 if (ry >= 0.0F) {
425 face = PIPE_TEX_FACE_POS_Y;
426 sc = rx;
427 tc = rz;
428 ma = ary;
429 }
430 else {
431 face = PIPE_TEX_FACE_NEG_Y;
432 sc = rx;
433 tc = -rz;
434 ma = ary;
435 }
436 }
437 else {
438 if (rz > 0.0F) {
439 face = PIPE_TEX_FACE_POS_Z;
440 sc = rx;
441 tc = -ry;
442 ma = arz;
443 }
444 else {
445 face = PIPE_TEX_FACE_NEG_Z;
446 sc = -rx;
447 tc = -ry;
448 ma = arz;
449 }
450 }
451
452 *newS = ( sc / ma + 1.0F ) * 0.5F;
453 *newT = ( tc / ma + 1.0F ) * 0.5F;
454
455 return face;
456 }
457
458
459 /**
460 * Examine the quad's texture coordinates to compute the partial
461 * derivatives w.r.t X and Y, then compute lambda (level of detail).
462 *
463 * This is only done for fragment shaders, not vertex shaders.
464 */
465 static float
466 compute_lambda(struct tgsi_sampler *sampler,
467 const float s[QUAD_SIZE],
468 const float t[QUAD_SIZE],
469 const float p[QUAD_SIZE],
470 float lodbias)
471 {
472 float rho, lambda;
473
474 assert(sampler->state->normalized_coords);
475
476 assert(s);
477 {
478 float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
479 float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT];
480 dsdx = fabsf(dsdx);
481 dsdy = fabsf(dsdy);
482 rho = MAX2(dsdx, dsdy) * sampler->texture->width[0];
483 }
484 if (t) {
485 float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
486 float dtdy = t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT];
487 float max;
488 dtdx = fabsf(dtdx);
489 dtdy = fabsf(dtdy);
490 max = MAX2(dtdx, dtdy) * sampler->texture->height[0];
491 rho = MAX2(rho, max);
492 }
493 if (p) {
494 float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
495 float dpdy = p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT];
496 float max;
497 dpdx = fabsf(dpdx);
498 dpdy = fabsf(dpdy);
499 max = MAX2(dpdx, dpdy) * sampler->texture->depth[0];
500 rho = MAX2(rho, max);
501 }
502
503 lambda = util_fast_log2(rho);
504 lambda += lodbias + sampler->state->lod_bias;
505 lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
506
507 return lambda;
508 }
509
510
511 /**
512 * Do several things here:
513 * 1. Compute lambda from the texcoords, if needed
514 * 2. Determine if we're minifying or magnifying
515 * 3. If minifying, choose mipmap levels
516 * 4. Return image filter to use within mipmap images
517 */
518 static void
519 choose_mipmap_levels(struct tgsi_sampler *sampler,
520 const float s[QUAD_SIZE],
521 const float t[QUAD_SIZE],
522 const float p[QUAD_SIZE],
523 float lodbias,
524 unsigned *level0, unsigned *level1, float *levelBlend,
525 unsigned *imgFilter)
526 {
527 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
528 /* no mipmap selection needed */
529 *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
530 0, (int) sampler->texture->last_level);
531
532 if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
533 /* non-mipmapped texture, but still need to determine if doing
534 * minification or magnification.
535 */
536 float lambda = compute_lambda(sampler, s, t, p, lodbias);
537 if (lambda <= 0.0) {
538 *imgFilter = sampler->state->mag_img_filter;
539 }
540 else {
541 *imgFilter = sampler->state->min_img_filter;
542 }
543 }
544 else {
545 *imgFilter = sampler->state->mag_img_filter;
546 }
547 }
548 else {
549 float lambda;
550
551 if (1)
552 /* fragment shader */
553 lambda = compute_lambda(sampler, s, t, p, lodbias);
554 else
555 /* vertex shader */
556 lambda = lodbias; /* not really a bias, but absolute LOD */
557
558 if (lambda <= 0.0) { /* XXX threshold depends on the filter */
559 /* magnifying */
560 *imgFilter = sampler->state->mag_img_filter;
561 *level0 = *level1 = 0;
562 }
563 else {
564 /* minifying */
565 *imgFilter = sampler->state->min_img_filter;
566
567 /* choose mipmap level(s) and compute the blend factor between them */
568 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
569 /* Nearest mipmap level */
570 const int lvl = (int) (lambda + 0.5);
571 *level0 =
572 *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
573 }
574 else {
575 /* Linear interpolation between mipmap levels */
576 const int lvl = (int) lambda;
577 *level0 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
578 *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
579 *levelBlend = FRAC(lambda); /* blending weight between levels */
580 }
581 }
582 }
583 }
584
585
586 /**
587 * Get a texel from a texture, using the texture tile cache.
588 *
589 * \param face the cube face in 0..5
590 * \param level the mipmap level
591 * \param x the x coord of texel within 2D image
592 * \param y the y coord of texel within 2D image
593 * \param z which slice of a 3D texture
594 * \param rgba the quad to put the texel/color into
595 * \param j which element of the rgba quad to write to
596 *
597 * XXX maybe move this into sp_tile_cache.c and merge with the
598 * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1...
599 */
600 static void
601 get_texel(struct tgsi_sampler *sampler,
602 unsigned face, unsigned level, int x, int y, int z,
603 float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
604 {
605 if (x < 0 || x >= (int) sampler->texture->width[level] ||
606 y < 0 || y >= (int) sampler->texture->height[level] ||
607 z < 0 || z >= (int) sampler->texture->depth[level]) {
608 rgba[0][j] = sampler->state->border_color[0];
609 rgba[1][j] = sampler->state->border_color[1];
610 rgba[2][j] = sampler->state->border_color[2];
611 rgba[3][j] = sampler->state->border_color[3];
612 }
613 else {
614 const int tx = x % TILE_SIZE;
615 const int ty = y % TILE_SIZE;
616 const struct softpipe_cached_tile *tile
617 = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
618 x, y, z, face, level);
619 rgba[0][j] = tile->data.color[ty][tx][0];
620 rgba[1][j] = tile->data.color[ty][tx][1];
621 rgba[2][j] = tile->data.color[ty][tx][2];
622 rgba[3][j] = tile->data.color[ty][tx][3];
623 if (0)
624 {
625 debug_printf("Get texel %f %f %f %f from %s\n",
626 rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j],
627 pf_name(sampler->texture->format));
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