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