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