gallium: add missing mip level clamp
[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 static unsigned
336 choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
337 {
338 /*
339 major axis
340 direction target sc tc ma
341 ---------- ------------------------------- --- --- ---
342 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
343 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
344 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
345 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
346 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
347 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
348 */
349 const float arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
350 unsigned face;
351 float sc, tc, ma;
352
353 if (arx > ary && arx > arz) {
354 if (rx >= 0.0F) {
355 face = PIPE_TEX_FACE_POS_X;
356 sc = -rz;
357 tc = -ry;
358 ma = arx;
359 }
360 else {
361 face = PIPE_TEX_FACE_NEG_X;
362 sc = rz;
363 tc = -ry;
364 ma = arx;
365 }
366 }
367 else if (ary > arx && ary > arz) {
368 if (ry >= 0.0F) {
369 face = PIPE_TEX_FACE_POS_Y;
370 sc = rx;
371 tc = rz;
372 ma = ary;
373 }
374 else {
375 face = PIPE_TEX_FACE_NEG_Y;
376 sc = rx;
377 tc = -rz;
378 ma = ary;
379 }
380 }
381 else {
382 if (rz > 0.0F) {
383 face = PIPE_TEX_FACE_POS_Z;
384 sc = rx;
385 tc = -ry;
386 ma = arz;
387 }
388 else {
389 face = PIPE_TEX_FACE_NEG_Z;
390 sc = -rx;
391 tc = -ry;
392 ma = arz;
393 }
394 }
395
396 *newS = ( sc / ma + 1.0F ) * 0.5F;
397 *newT = ( tc / ma + 1.0F ) * 0.5F;
398
399 return face;
400 }
401
402
403 /**
404 * Examine the quad's texture coordinates to compute the partial
405 * derivatives w.r.t X and Y, then compute lambda (level of detail).
406 *
407 * This is only done for fragment shaders, not vertex shaders.
408 */
409 static float
410 compute_lambda(struct tgsi_sampler *sampler,
411 const float s[QUAD_SIZE],
412 const float t[QUAD_SIZE],
413 const float p[QUAD_SIZE],
414 float lodbias)
415 {
416 float rho, lambda;
417
418 assert(s);
419 {
420 float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
421 float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT];
422 dsdx = FABSF(dsdx);
423 dsdy = FABSF(dsdy);
424 rho = MAX2(dsdx, dsdy);
425 if (sampler->state->normalized_coords)
426 rho *= sampler->texture->width[0];
427 }
428 if (t) {
429 float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
430 float dtdy = t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT];
431 float max;
432 dtdx = FABSF(dtdx);
433 dtdy = FABSF(dtdy);
434 max = MAX2(dtdx, dtdy);
435 if (sampler->state->normalized_coords)
436 max *= sampler->texture->height[0];
437 rho = MAX2(rho, max);
438 }
439 if (p) {
440 float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
441 float dpdy = p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT];
442 float max;
443 dpdx = FABSF(dpdx);
444 dpdy = FABSF(dpdy);
445 max = MAX2(dpdx, dpdy);
446 if (sampler->state->normalized_coords)
447 max *= sampler->texture->depth[0];
448 rho = MAX2(rho, max);
449 }
450
451 lambda = LOG2(rho);
452 lambda += lodbias + sampler->state->lod_bias;
453 lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
454
455 return lambda;
456 }
457
458
459 /**
460 * Do several things here:
461 * 1. Compute lambda from the texcoords, if needed
462 * 2. Determine if we're minifying or magnifying
463 * 3. If minifying, choose mipmap levels
464 * 4. Return image filter to use within mipmap images
465 */
466 static void
467 choose_mipmap_levels(struct tgsi_sampler *sampler,
468 const float s[QUAD_SIZE],
469 const float t[QUAD_SIZE],
470 const float p[QUAD_SIZE],
471 float lodbias,
472 unsigned *level0, unsigned *level1, float *levelBlend,
473 unsigned *imgFilter)
474 {
475 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
476 /* no mipmap selection needed */
477 *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
478 0, (int) sampler->texture->last_level);
479
480 if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
481 /* non-mipmapped texture, but still need to determine if doing
482 * minification or magnification.
483 */
484 float lambda = compute_lambda(sampler, s, t, p, lodbias);
485 if (lambda <= 0.0) {
486 *imgFilter = sampler->state->mag_img_filter;
487 }
488 else {
489 *imgFilter = sampler->state->min_img_filter;
490 }
491 }
492 else {
493 *imgFilter = sampler->state->mag_img_filter;
494 }
495 }
496 else {
497 float lambda;
498
499 if (1)
500 /* fragment shader */
501 lambda = compute_lambda(sampler, s, t, p, lodbias);
502 else
503 /* vertex shader */
504 lambda = lodbias; /* not really a bias, but absolute LOD */
505
506 if (lambda <= 0.0) { /* XXX threshold depends on the filter */
507 /* magnifying */
508 *imgFilter = sampler->state->mag_img_filter;
509 *level0 = *level1 = 0;
510 }
511 else {
512 /* minifying */
513 *imgFilter = sampler->state->min_img_filter;
514
515 /* choose mipmap level(s) and compute the blend factor between them */
516 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
517 /* Nearest mipmap level */
518 const int lvl = (int) (lambda + 0.5);
519 *level0 =
520 *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
521 }
522 else {
523 /* Linear interpolation between mipmap levels */
524 const int lvl = (int) lambda;
525 *level0 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
526 *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
527 *levelBlend = FRAC(lambda); /* blending weight between levels */
528 }
529 }
530 }
531 }
532
533
534 /**
535 * Get a texel from a texture, using the texture tile cache.
536 *
537 * \param face the cube face in 0..5
538 * \param level the mipmap level
539 * \param x the x coord of texel within 2D image
540 * \param y the y coord of texel within 2D image
541 * \param z which slice of a 3D texture
542 * \param rgba the quad to put the texel/color into
543 * \param j which element of the rgba quad to write to
544 *
545 * XXX maybe move this into sp_tile_cache.c and merge with the
546 * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1...
547 */
548 static void
549 get_texel(struct tgsi_sampler *sampler,
550 unsigned face, unsigned level, int x, int y, int z,
551 float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
552 {
553 const int tx = x % TILE_SIZE;
554 const int ty = y % TILE_SIZE;
555 const struct softpipe_cached_tile *tile
556 = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
557 x, y, z, face, level);
558 rgba[0][j] = tile->data.color[ty][tx][0];
559 rgba[1][j] = tile->data.color[ty][tx][1];
560 rgba[2][j] = tile->data.color[ty][tx][2];
561 rgba[3][j] = tile->data.color[ty][tx][3];
562 }
563
564
565 /**
566 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
567 * When we sampled the depth texture, the depth value was put into all
568 * RGBA channels. We look at the red channel here.
569 */
570 static INLINE void
571 shadow_compare(uint compare_func,
572 float rgba[NUM_CHANNELS][QUAD_SIZE],
573 const float p[QUAD_SIZE],
574 uint j)
575 {
576 int k;
577 switch (compare_func) {
578 case PIPE_FUNC_LESS:
579 k = p[j] < rgba[0][j];
580 break;
581 case PIPE_FUNC_LEQUAL:
582 k = p[j] <= rgba[0][j];
583 break;
584 case PIPE_FUNC_GREATER:
585 k = p[j] > rgba[0][j];
586 break;
587 case PIPE_FUNC_GEQUAL:
588 k = p[j] >= rgba[0][j];
589 break;
590 case PIPE_FUNC_EQUAL:
591 k = p[j] == rgba[0][j];
592 break;
593 case PIPE_FUNC_NOTEQUAL:
594 k = p[j] != rgba[0][j];
595 break;
596 case PIPE_FUNC_ALWAYS:
597 k = 1;
598 break;
599 case PIPE_FUNC_NEVER:
600 k = 0;
601 break;
602 default:
603 assert(0);
604 }
605
606 rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
607 }
608
609
610 /**
611 * Common code for sampling 1D/2D/cube textures.
612 * Could probably extend for 3D...
613 */
614 static void
615 sp_get_samples_2d_common(struct tgsi_sampler *sampler,
616 const float s[QUAD_SIZE],
617 const float t[QUAD_SIZE],
618 const float p[QUAD_SIZE],
619 float lodbias,
620 float rgba[NUM_CHANNELS][QUAD_SIZE],
621 const unsigned faces[4])
622 {
623 const uint compare_func = sampler->state->compare_func;
624 unsigned level0, level1, j, imgFilter;
625 int width, height;
626 float levelBlend;
627
628 choose_mipmap_levels(sampler, s, t, p, lodbias,
629 &level0, &level1, &levelBlend, &imgFilter);
630
631 if (sampler->state->normalized_coords) {
632 width = sampler->texture->width[level0];
633 height = sampler->texture->height[level0];
634 }
635 else {
636 width = height = 1;
637 }
638
639 assert(width > 0);
640
641 switch (imgFilter) {
642 case PIPE_TEX_FILTER_NEAREST:
643 for (j = 0; j < QUAD_SIZE; j++) {
644 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
645 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
646 get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
647 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
648 shadow_compare(compare_func, rgba, p, j);
649 }
650
651 if (level0 != level1) {
652 /* get texels from second mipmap level and blend */
653 float rgba2[4][4];
654 unsigned c;
655 x = x / 2;
656 y = y / 2;
657 get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
658 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
659 shadow_compare(compare_func, rgba2, p, j);
660 }
661
662 for (c = 0; c < NUM_CHANNELS; c++) {
663 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
664 }
665 }
666 }
667 break;
668 case PIPE_TEX_FILTER_LINEAR:
669 for (j = 0; j < QUAD_SIZE; j++) {
670 float tx[4][4], a, b;
671 int x0, y0, x1, y1, c;
672 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
673 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
674 get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
675 get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
676 get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
677 get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
678 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
679 shadow_compare(compare_func, tx, p, 0);
680 shadow_compare(compare_func, tx, p, 1);
681 shadow_compare(compare_func, tx, p, 2);
682 shadow_compare(compare_func, tx, p, 3);
683 }
684
685 for (c = 0; c < 4; c++) {
686 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
687 }
688
689 if (level0 != level1) {
690 /* get texels from second mipmap level and blend */
691 float rgba2[4][4];
692 x0 = x0 / 2;
693 y0 = y0 / 2;
694 x1 = x1 / 2;
695 y1 = y1 / 2;
696 get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
697 get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
698 get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
699 get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
700 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
701 shadow_compare(compare_func, tx, p, 0);
702 shadow_compare(compare_func, tx, p, 1);
703 shadow_compare(compare_func, tx, p, 2);
704 shadow_compare(compare_func, tx, p, 3);
705 }
706
707 for (c = 0; c < 4; c++) {
708 rgba2[c][j] = lerp_2d(a, b,
709 tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
710 }
711
712 for (c = 0; c < NUM_CHANNELS; c++) {
713 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
714 }
715 }
716 }
717 break;
718 default:
719 assert(0);
720 }
721 }
722
723
724 static void
725 sp_get_samples_1d(struct tgsi_sampler *sampler,
726 const float s[QUAD_SIZE],
727 const float t[QUAD_SIZE],
728 const float p[QUAD_SIZE],
729 float lodbias,
730 float rgba[NUM_CHANNELS][QUAD_SIZE])
731 {
732 static const unsigned faces[4] = {0, 0, 0, 0};
733 static const float tzero[4] = {0, 0, 0, 0};
734 sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
735 }
736
737
738 static void
739 sp_get_samples_2d(struct tgsi_sampler *sampler,
740 const float s[QUAD_SIZE],
741 const float t[QUAD_SIZE],
742 const float p[QUAD_SIZE],
743 float lodbias,
744 float rgba[NUM_CHANNELS][QUAD_SIZE])
745 {
746 static const unsigned faces[4] = {0, 0, 0, 0};
747 sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
748 }
749
750
751 static void
752 sp_get_samples_3d(struct tgsi_sampler *sampler,
753 const float s[QUAD_SIZE],
754 const float t[QUAD_SIZE],
755 const float p[QUAD_SIZE],
756 float lodbias,
757 float rgba[NUM_CHANNELS][QUAD_SIZE])
758 {
759 /* get/map pipe_surfaces corresponding to 3D tex slices */
760 unsigned level0, level1, j, imgFilter;
761 int width, height, depth;
762 float levelBlend;
763 const uint face = 0;
764
765 choose_mipmap_levels(sampler, s, t, p, lodbias,
766 &level0, &level1, &levelBlend, &imgFilter);
767
768 if (sampler->state->normalized_coords) {
769 width = sampler->texture->width[level0];
770 height = sampler->texture->height[level0];
771 depth = sampler->texture->depth[level0];
772 }
773 else {
774 width = height = depth = 1;
775 }
776
777 assert(width > 0);
778 assert(height > 0);
779 assert(depth > 0);
780
781 switch (imgFilter) {
782 case PIPE_TEX_FILTER_NEAREST:
783 for (j = 0; j < QUAD_SIZE; j++) {
784 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
785 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
786 int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
787 get_texel(sampler, face, level0, x, y, z, rgba, j);
788
789 if (level0 != level1) {
790 /* get texels from second mipmap level and blend */
791 float rgba2[4][4];
792 unsigned c;
793 x /= 2;
794 y /= 2;
795 z /= 2;
796 get_texel(sampler, face, level1, x, y, z, rgba2, j);
797 for (c = 0; c < NUM_CHANNELS; c++) {
798 rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
799 }
800 }
801 }
802 break;
803 case PIPE_TEX_FILTER_LINEAR:
804 for (j = 0; j < QUAD_SIZE; j++) {
805 float texel0[4][4], texel1[4][4];
806 float xw, yw, zw; /* interpolation weights */
807 int x0, x1, y0, y1, z0, z1, c;
808 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &xw);
809 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
810 linear_texcoord(sampler->state->wrap_r, p[j], depth, &z0, &z1, &zw);
811 get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
812 get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
813 get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
814 get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
815 get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
816 get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
817 get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
818 get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
819
820 /* 3D lerp */
821 for (c = 0; c < 4; c++) {
822 float ctemp0[4][4], ctemp1[4][4];
823 ctemp0[c][j] = lerp_2d(xw, yw,
824 texel0[c][0], texel0[c][1],
825 texel0[c][2], texel0[c][3]);
826 ctemp1[c][j] = lerp_2d(xw, yw,
827 texel1[c][0], texel1[c][1],
828 texel1[c][2], texel1[c][3]);
829 rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
830 }
831
832 if (level0 != level1) {
833 /* get texels from second mipmap level and blend */
834 float rgba2[4][4];
835 x0 /= 2;
836 y0 /= 2;
837 z0 /= 2;
838 x1 /= 2;
839 y1 /= 2;
840 z1 /= 2;
841 get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
842 get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
843 get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
844 get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
845 get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
846 get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
847 get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
848 get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
849
850 /* 3D lerp */
851 for (c = 0; c < 4; c++) {
852 float ctemp0[4][4], ctemp1[4][4];
853 ctemp0[c][j] = lerp_2d(xw, yw,
854 texel0[c][0], texel0[c][1],
855 texel0[c][2], texel0[c][3]);
856 ctemp1[c][j] = lerp_2d(xw, yw,
857 texel1[c][0], texel1[c][1],
858 texel1[c][2], texel1[c][3]);
859 rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
860 }
861
862 /* blend mipmap levels */
863 for (c = 0; c < NUM_CHANNELS; c++) {
864 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
865 }
866 }
867 }
868 break;
869 default:
870 assert(0);
871 }
872 }
873
874
875 static void
876 sp_get_samples_cube(struct tgsi_sampler *sampler,
877 const float s[QUAD_SIZE],
878 const float t[QUAD_SIZE],
879 const float p[QUAD_SIZE],
880 float lodbias,
881 float rgba[NUM_CHANNELS][QUAD_SIZE])
882 {
883 unsigned faces[QUAD_SIZE], j;
884 float ssss[4], tttt[4];
885 for (j = 0; j < QUAD_SIZE; j++) {
886 faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
887 }
888 sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
889 }
890
891
892 /**
893 * Called via tgsi_sampler::get_samples()
894 * Use the sampler's state setting to get a filtered RGBA value
895 * from the sampler's texture.
896 *
897 * XXX we can implement many versions of this function, each
898 * tightly coded for a specific combination of sampler state
899 * (nearest + repeat), (bilinear mipmap + clamp), etc.
900 *
901 * The update_samplers() function in st_atom_sampler.c could create
902 * a new tgsi_sampler object for each state combo it finds....
903 */
904 void
905 sp_get_samples(struct tgsi_sampler *sampler,
906 const float s[QUAD_SIZE],
907 const float t[QUAD_SIZE],
908 const float p[QUAD_SIZE],
909 float lodbias,
910 float rgba[NUM_CHANNELS][QUAD_SIZE])
911 {
912 if (!sampler->texture)
913 return;
914
915 switch (sampler->texture->target) {
916 case PIPE_TEXTURE_1D:
917 sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
918 break;
919 case PIPE_TEXTURE_2D:
920 sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
921 break;
922 case PIPE_TEXTURE_3D:
923 sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
924 break;
925 case PIPE_TEXTURE_CUBE:
926 sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
927 break;
928 default:
929 assert(0);
930 }
931 }
932