Merge remote branch 'nouveau/gallium-0.1' into nouveau-gallium-0.1
[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/exec/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 const int tx = x % TILE_SIZE;
605 const int ty = y % TILE_SIZE;
606 const struct softpipe_cached_tile *tile
607 = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
608 x, y, z, face, level);
609 rgba[0][j] = tile->data.color[ty][tx][0];
610 rgba[1][j] = tile->data.color[ty][tx][1];
611 rgba[2][j] = tile->data.color[ty][tx][2];
612 rgba[3][j] = tile->data.color[ty][tx][3];
613 }
614
615
616 /**
617 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
618 * When we sampled the depth texture, the depth value was put into all
619 * RGBA channels. We look at the red channel here.
620 */
621 static INLINE void
622 shadow_compare(uint compare_func,
623 float rgba[NUM_CHANNELS][QUAD_SIZE],
624 const float p[QUAD_SIZE],
625 uint j)
626 {
627 int k;
628 switch (compare_func) {
629 case PIPE_FUNC_LESS:
630 k = p[j] < rgba[0][j];
631 break;
632 case PIPE_FUNC_LEQUAL:
633 k = p[j] <= rgba[0][j];
634 break;
635 case PIPE_FUNC_GREATER:
636 k = p[j] > rgba[0][j];
637 break;
638 case PIPE_FUNC_GEQUAL:
639 k = p[j] >= rgba[0][j];
640 break;
641 case PIPE_FUNC_EQUAL:
642 k = p[j] == rgba[0][j];
643 break;
644 case PIPE_FUNC_NOTEQUAL:
645 k = p[j] != rgba[0][j];
646 break;
647 case PIPE_FUNC_ALWAYS:
648 k = 1;
649 break;
650 case PIPE_FUNC_NEVER:
651 k = 0;
652 break;
653 default:
654 assert(0);
655 }
656
657 rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
658 }
659
660
661 /**
662 * Common code for sampling 1D/2D/cube textures.
663 * Could probably extend for 3D...
664 */
665 static void
666 sp_get_samples_2d_common(struct tgsi_sampler *sampler,
667 const float s[QUAD_SIZE],
668 const float t[QUAD_SIZE],
669 const float p[QUAD_SIZE],
670 float lodbias,
671 float rgba[NUM_CHANNELS][QUAD_SIZE],
672 const unsigned faces[4])
673 {
674 const uint compare_func = sampler->state->compare_func;
675 unsigned level0, level1, j, imgFilter;
676 int width, height;
677 float levelBlend;
678
679 choose_mipmap_levels(sampler, s, t, p, lodbias,
680 &level0, &level1, &levelBlend, &imgFilter);
681
682 assert(sampler->state->normalized_coords);
683
684 width = sampler->texture->width[level0];
685 height = sampler->texture->height[level0];
686
687 assert(width > 0);
688
689 switch (imgFilter) {
690 case PIPE_TEX_FILTER_NEAREST:
691 for (j = 0; j < QUAD_SIZE; j++) {
692 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
693 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
694 get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
695 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
696 shadow_compare(compare_func, rgba, p, j);
697 }
698
699 if (level0 != level1) {
700 /* get texels from second mipmap level and blend */
701 float rgba2[4][4];
702 unsigned c;
703 x = x / 2;
704 y = y / 2;
705 get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
706 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
707 shadow_compare(compare_func, rgba2, p, j);
708 }
709
710 for (c = 0; c < NUM_CHANNELS; c++) {
711 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
712 }
713 }
714 }
715 break;
716 case PIPE_TEX_FILTER_LINEAR:
717 for (j = 0; j < QUAD_SIZE; j++) {
718 float tx[4][4], a, b;
719 int x0, y0, x1, y1, c;
720 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
721 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
722 get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
723 get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
724 get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
725 get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
726 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
727 shadow_compare(compare_func, tx, p, 0);
728 shadow_compare(compare_func, tx, p, 1);
729 shadow_compare(compare_func, tx, p, 2);
730 shadow_compare(compare_func, tx, p, 3);
731 }
732
733 for (c = 0; c < 4; c++) {
734 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
735 }
736
737 if (level0 != level1) {
738 /* get texels from second mipmap level and blend */
739 float rgba2[4][4];
740 x0 = x0 / 2;
741 y0 = y0 / 2;
742 x1 = x1 / 2;
743 y1 = y1 / 2;
744 get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
745 get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
746 get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
747 get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
748 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
749 shadow_compare(compare_func, tx, p, 0);
750 shadow_compare(compare_func, tx, p, 1);
751 shadow_compare(compare_func, tx, p, 2);
752 shadow_compare(compare_func, tx, p, 3);
753 }
754
755 for (c = 0; c < 4; c++) {
756 rgba2[c][j] = lerp_2d(a, b,
757 tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
758 }
759
760 for (c = 0; c < NUM_CHANNELS; c++) {
761 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
762 }
763 }
764 }
765 break;
766 default:
767 assert(0);
768 }
769 }
770
771
772 static void
773 sp_get_samples_1d(struct tgsi_sampler *sampler,
774 const float s[QUAD_SIZE],
775 const float t[QUAD_SIZE],
776 const float p[QUAD_SIZE],
777 float lodbias,
778 float rgba[NUM_CHANNELS][QUAD_SIZE])
779 {
780 static const unsigned faces[4] = {0, 0, 0, 0};
781 static const float tzero[4] = {0, 0, 0, 0};
782 sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
783 }
784
785
786 static void
787 sp_get_samples_2d(struct tgsi_sampler *sampler,
788 const float s[QUAD_SIZE],
789 const float t[QUAD_SIZE],
790 const float p[QUAD_SIZE],
791 float lodbias,
792 float rgba[NUM_CHANNELS][QUAD_SIZE])
793 {
794 static const unsigned faces[4] = {0, 0, 0, 0};
795 sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
796 }
797
798
799 static void
800 sp_get_samples_3d(struct tgsi_sampler *sampler,
801 const float s[QUAD_SIZE],
802 const float t[QUAD_SIZE],
803 const float p[QUAD_SIZE],
804 float lodbias,
805 float rgba[NUM_CHANNELS][QUAD_SIZE])
806 {
807 /* get/map pipe_surfaces corresponding to 3D tex slices */
808 unsigned level0, level1, j, imgFilter;
809 int width, height, depth;
810 float levelBlend;
811 const uint face = 0;
812
813 choose_mipmap_levels(sampler, s, t, p, lodbias,
814 &level0, &level1, &levelBlend, &imgFilter);
815
816 assert(sampler->state->normalized_coords);
817
818 width = sampler->texture->width[level0];
819 height = sampler->texture->height[level0];
820 depth = sampler->texture->depth[level0];
821
822 assert(width > 0);
823 assert(height > 0);
824 assert(depth > 0);
825
826 switch (imgFilter) {
827 case PIPE_TEX_FILTER_NEAREST:
828 for (j = 0; j < QUAD_SIZE; j++) {
829 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
830 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
831 int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
832 get_texel(sampler, face, level0, x, y, z, rgba, j);
833
834 if (level0 != level1) {
835 /* get texels from second mipmap level and blend */
836 float rgba2[4][4];
837 unsigned c;
838 x /= 2;
839 y /= 2;
840 z /= 2;
841 get_texel(sampler, face, level1, x, y, z, rgba2, j);
842 for (c = 0; c < NUM_CHANNELS; c++) {
843 rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
844 }
845 }
846 }
847 break;
848 case PIPE_TEX_FILTER_LINEAR:
849 for (j = 0; j < QUAD_SIZE; j++) {
850 float texel0[4][4], texel1[4][4];
851 float xw, yw, zw; /* interpolation weights */
852 int x0, x1, y0, y1, z0, z1, c;
853 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &xw);
854 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
855 linear_texcoord(sampler->state->wrap_r, p[j], depth, &z0, &z1, &zw);
856 get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
857 get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
858 get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
859 get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
860 get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
861 get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
862 get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
863 get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
864
865 /* 3D lerp */
866 for (c = 0; c < 4; c++) {
867 float ctemp0[4][4], ctemp1[4][4];
868 ctemp0[c][j] = lerp_2d(xw, yw,
869 texel0[c][0], texel0[c][1],
870 texel0[c][2], texel0[c][3]);
871 ctemp1[c][j] = lerp_2d(xw, yw,
872 texel1[c][0], texel1[c][1],
873 texel1[c][2], texel1[c][3]);
874 rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
875 }
876
877 if (level0 != level1) {
878 /* get texels from second mipmap level and blend */
879 float rgba2[4][4];
880 x0 /= 2;
881 y0 /= 2;
882 z0 /= 2;
883 x1 /= 2;
884 y1 /= 2;
885 z1 /= 2;
886 get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
887 get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
888 get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
889 get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
890 get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
891 get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
892 get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
893 get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
894
895 /* 3D lerp */
896 for (c = 0; c < 4; c++) {
897 float ctemp0[4][4], ctemp1[4][4];
898 ctemp0[c][j] = lerp_2d(xw, yw,
899 texel0[c][0], texel0[c][1],
900 texel0[c][2], texel0[c][3]);
901 ctemp1[c][j] = lerp_2d(xw, yw,
902 texel1[c][0], texel1[c][1],
903 texel1[c][2], texel1[c][3]);
904 rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
905 }
906
907 /* blend mipmap levels */
908 for (c = 0; c < NUM_CHANNELS; c++) {
909 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
910 }
911 }
912 }
913 break;
914 default:
915 assert(0);
916 }
917 }
918
919
920 static void
921 sp_get_samples_cube(struct tgsi_sampler *sampler,
922 const float s[QUAD_SIZE],
923 const float t[QUAD_SIZE],
924 const float p[QUAD_SIZE],
925 float lodbias,
926 float rgba[NUM_CHANNELS][QUAD_SIZE])
927 {
928 unsigned faces[QUAD_SIZE], j;
929 float ssss[4], tttt[4];
930 for (j = 0; j < QUAD_SIZE; j++) {
931 faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
932 }
933 sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
934 }
935
936
937 static void
938 sp_get_samples_rect(struct tgsi_sampler *sampler,
939 const float s[QUAD_SIZE],
940 const float t[QUAD_SIZE],
941 const float p[QUAD_SIZE],
942 float lodbias,
943 float rgba[NUM_CHANNELS][QUAD_SIZE])
944 {
945 //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
946 static const uint face = 0;
947 const uint compare_func = sampler->state->compare_func;
948 unsigned level0, level1, j, imgFilter;
949 int width, height;
950 float levelBlend;
951
952 choose_mipmap_levels(sampler, s, t, p, lodbias,
953 &level0, &level1, &levelBlend, &imgFilter);
954
955 /* texture RECTS cannot be mipmapped */
956 assert(level0 == level1);
957
958 width = sampler->texture->width[level0];
959 height = sampler->texture->height[level0];
960
961 assert(width > 0);
962
963 switch (imgFilter) {
964 case PIPE_TEX_FILTER_NEAREST:
965 for (j = 0; j < QUAD_SIZE; j++) {
966 int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width);
967 int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height);
968 get_texel(sampler, face, level0, x, y, 0, rgba, j);
969 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
970 shadow_compare(compare_func, rgba, p, j);
971 }
972 }
973 break;
974 case PIPE_TEX_FILTER_LINEAR:
975 for (j = 0; j < QUAD_SIZE; j++) {
976 float tx[4][4], a, b;
977 int x0, y0, x1, y1, c;
978 linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
979 linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
980 get_texel(sampler, face, level0, x0, y0, 0, tx, 0);
981 get_texel(sampler, face, level0, x1, y0, 0, tx, 1);
982 get_texel(sampler, face, level0, x0, y1, 0, tx, 2);
983 get_texel(sampler, face, level0, x1, y1, 0, tx, 3);
984 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
985 shadow_compare(compare_func, tx, p, 0);
986 shadow_compare(compare_func, tx, p, 1);
987 shadow_compare(compare_func, tx, p, 2);
988 shadow_compare(compare_func, tx, p, 3);
989 }
990
991 for (c = 0; c < 4; c++) {
992 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
993 }
994 }
995 break;
996 default:
997 assert(0);
998 }
999 }
1000
1001
1002
1003
1004 /**
1005 * Called via tgsi_sampler::get_samples()
1006 * Use the sampler's state setting to get a filtered RGBA value
1007 * from the sampler's texture.
1008 *
1009 * XXX we can implement many versions of this function, each
1010 * tightly coded for a specific combination of sampler state
1011 * (nearest + repeat), (bilinear mipmap + clamp), etc.
1012 *
1013 * The update_samplers() function in st_atom_sampler.c could create
1014 * a new tgsi_sampler object for each state combo it finds....
1015 */
1016 void
1017 sp_get_samples(struct tgsi_sampler *sampler,
1018 const float s[QUAD_SIZE],
1019 const float t[QUAD_SIZE],
1020 const float p[QUAD_SIZE],
1021 float lodbias,
1022 float rgba[NUM_CHANNELS][QUAD_SIZE])
1023 {
1024 if (!sampler->texture)
1025 return;
1026
1027 switch (sampler->texture->target) {
1028 case PIPE_TEXTURE_1D:
1029 assert(sampler->state->normalized_coords);
1030 sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
1031 break;
1032 case PIPE_TEXTURE_2D:
1033 if (sampler->state->normalized_coords)
1034 sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
1035 else
1036 sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
1037 break;
1038 case PIPE_TEXTURE_3D:
1039 assert(sampler->state->normalized_coords);
1040 sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
1041 break;
1042 case PIPE_TEXTURE_CUBE:
1043 assert(sampler->state->normalized_coords);
1044 sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
1045 break;
1046 default:
1047 assert(0);
1048 }
1049 }
1050