gallium: remove some debug assertions in vertex format validation
[mesa.git] / src / mesa / pipe / 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 "pipe/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 *imgFilter = sampler->state->mag_img_filter;
478 *level0 = *level1 = (int) sampler->state->min_lod;
479 }
480 else {
481 float lambda;
482
483 if (1)
484 /* fragment shader */
485 lambda = compute_lambda(sampler, s, t, p, lodbias);
486 else
487 /* vertex shader */
488 lambda = lodbias; /* not really a bias, but absolute LOD */
489
490 if (lambda < 0.0) { /* XXX threshold depends on the filter */
491 /* magnifying */
492 *imgFilter = sampler->state->mag_img_filter;
493 *level0 = *level1 = 0;
494 }
495 else {
496 /* minifying */
497 *imgFilter = sampler->state->min_img_filter;
498
499 /* choose mipmap level(s) and compute the blend factor between them */
500 if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
501 /* Nearest mipmap level */
502 const int lvl = (int) (lambda + 0.5);
503 *level0 =
504 *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
505 }
506 else {
507 /* Linear interpolation between mipmap levels */
508 const int lvl = (int) lambda;
509 *level0 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
510 *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
511 *levelBlend = FRAC(lambda); /* blending weight between levels */
512 }
513 }
514 }
515 }
516
517
518 /**
519 * Get a texel from a texture, using the texture tile cache.
520 *
521 * \param face the cube face in 0..5
522 * \param level the mipmap level
523 * \param x the x coord of texel within 2D image
524 * \param y the y coord of texel within 2D image
525 * \param z which slice of a 3D texture
526 * \param rgba the quad to put the texel/color into
527 * \param j which element of the rgba quad to write to
528 *
529 * XXX maybe move this into sp_tile_cache.c and merge with the
530 * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1...
531 */
532 static void
533 get_texel(struct tgsi_sampler *sampler,
534 unsigned face, unsigned level, int x, int y, int z,
535 float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
536 {
537 const int tx = x % TILE_SIZE;
538 const int ty = y % TILE_SIZE;
539 const struct softpipe_cached_tile *tile
540 = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
541 x, y, z, face, level);
542 rgba[0][j] = tile->data.color[ty][tx][0];
543 rgba[1][j] = tile->data.color[ty][tx][1];
544 rgba[2][j] = tile->data.color[ty][tx][2];
545 rgba[3][j] = tile->data.color[ty][tx][3];
546 }
547
548
549 /**
550 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
551 * When we sampled the depth texture, the depth value was put into all
552 * RGBA channels. We look at the red channel here.
553 */
554 static INLINE void
555 shadow_compare(uint compare_func,
556 float rgba[NUM_CHANNELS][QUAD_SIZE],
557 const float p[QUAD_SIZE],
558 uint j)
559 {
560 int k;
561 switch (compare_func) {
562 case PIPE_FUNC_LESS:
563 k = p[j] < rgba[0][j];
564 break;
565 case PIPE_FUNC_LEQUAL:
566 k = p[j] <= rgba[0][j];
567 break;
568 case PIPE_FUNC_GREATER:
569 k = p[j] > rgba[0][j];
570 break;
571 case PIPE_FUNC_GEQUAL:
572 k = p[j] >= rgba[0][j];
573 break;
574 case PIPE_FUNC_EQUAL:
575 k = p[j] == rgba[0][j];
576 break;
577 case PIPE_FUNC_NOTEQUAL:
578 k = p[j] != rgba[0][j];
579 break;
580 case PIPE_FUNC_ALWAYS:
581 k = 1;
582 break;
583 case PIPE_FUNC_NEVER:
584 k = 0;
585 break;
586 default:
587 assert(0);
588 }
589
590 rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
591 }
592
593
594 /**
595 * Common code for sampling 1D/2D/cube textures.
596 * Could probably extend for 3D...
597 */
598 static void
599 sp_get_samples_2d_common(struct tgsi_sampler *sampler,
600 const float s[QUAD_SIZE],
601 const float t[QUAD_SIZE],
602 const float p[QUAD_SIZE],
603 float lodbias,
604 float rgba[NUM_CHANNELS][QUAD_SIZE],
605 const unsigned faces[4])
606 {
607 const uint compare_func = sampler->state->compare_func;
608 unsigned level0, level1, j, imgFilter;
609 int width, height;
610 float levelBlend;
611
612 choose_mipmap_levels(sampler, s, t, p, lodbias,
613 &level0, &level1, &levelBlend, &imgFilter);
614
615 if (sampler->state->normalized_coords) {
616 width = sampler->texture->width[level0];
617 height = sampler->texture->height[level0];
618 }
619 else {
620 width = height = 1;
621 }
622
623 assert(width > 0);
624
625 switch (imgFilter) {
626 case PIPE_TEX_FILTER_NEAREST:
627 for (j = 0; j < QUAD_SIZE; j++) {
628 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
629 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
630 get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
631 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
632 shadow_compare(compare_func, rgba, p, j);
633 }
634
635 if (level0 != level1) {
636 /* get texels from second mipmap level and blend */
637 float rgba2[4][4];
638 unsigned c;
639 x = x / 2;
640 y = y / 2;
641 get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
642 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
643 shadow_compare(compare_func, rgba2, p, j);
644 }
645
646 for (c = 0; c < NUM_CHANNELS; c++) {
647 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
648 }
649 }
650 }
651 break;
652 case PIPE_TEX_FILTER_LINEAR:
653 for (j = 0; j < QUAD_SIZE; j++) {
654 float tx[4][4], a, b;
655 int x0, y0, x1, y1, c;
656 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &a);
657 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
658 get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
659 get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
660 get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
661 get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
662 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
663 shadow_compare(compare_func, tx, p, 0);
664 shadow_compare(compare_func, tx, p, 1);
665 shadow_compare(compare_func, tx, p, 2);
666 shadow_compare(compare_func, tx, p, 3);
667 }
668
669 for (c = 0; c < 4; c++) {
670 rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
671 }
672
673 if (level0 != level1) {
674 /* get texels from second mipmap level and blend */
675 float rgba2[4][4];
676 x0 = x0 / 2;
677 y0 = y0 / 2;
678 x1 = x1 / 2;
679 y1 = y1 / 2;
680 get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
681 get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
682 get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
683 get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
684 if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
685 shadow_compare(compare_func, tx, p, 0);
686 shadow_compare(compare_func, tx, p, 1);
687 shadow_compare(compare_func, tx, p, 2);
688 shadow_compare(compare_func, tx, p, 3);
689 }
690
691 for (c = 0; c < 4; c++) {
692 rgba2[c][j] = lerp_2d(a, b,
693 tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
694 }
695
696 for (c = 0; c < NUM_CHANNELS; c++) {
697 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
698 }
699 }
700 }
701 break;
702 default:
703 assert(0);
704 }
705 }
706
707
708 static void
709 sp_get_samples_1d(struct tgsi_sampler *sampler,
710 const float s[QUAD_SIZE],
711 const float t[QUAD_SIZE],
712 const float p[QUAD_SIZE],
713 float lodbias,
714 float rgba[NUM_CHANNELS][QUAD_SIZE])
715 {
716 static const unsigned faces[4] = {0, 0, 0, 0};
717 static const float tzero[4] = {0, 0, 0, 0};
718 sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
719 }
720
721
722 static void
723 sp_get_samples_2d(struct tgsi_sampler *sampler,
724 const float s[QUAD_SIZE],
725 const float t[QUAD_SIZE],
726 const float p[QUAD_SIZE],
727 float lodbias,
728 float rgba[NUM_CHANNELS][QUAD_SIZE])
729 {
730 static const unsigned faces[4] = {0, 0, 0, 0};
731 sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
732 }
733
734
735 static void
736 sp_get_samples_3d(struct tgsi_sampler *sampler,
737 const float s[QUAD_SIZE],
738 const float t[QUAD_SIZE],
739 const float p[QUAD_SIZE],
740 float lodbias,
741 float rgba[NUM_CHANNELS][QUAD_SIZE])
742 {
743 /* get/map pipe_surfaces corresponding to 3D tex slices */
744 unsigned level0, level1, j, imgFilter;
745 int width, height, depth;
746 float levelBlend;
747 const uint face = 0;
748
749 choose_mipmap_levels(sampler, s, t, p, lodbias,
750 &level0, &level1, &levelBlend, &imgFilter);
751
752 if (sampler->state->normalized_coords) {
753 width = sampler->texture->width[level0];
754 height = sampler->texture->height[level0];
755 depth = sampler->texture->depth[level0];
756 }
757 else {
758 width = height = depth = 1;
759 }
760
761 assert(width > 0);
762 assert(height > 0);
763 assert(depth > 0);
764
765 switch (imgFilter) {
766 case PIPE_TEX_FILTER_NEAREST:
767 for (j = 0; j < QUAD_SIZE; j++) {
768 int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
769 int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
770 int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
771 get_texel(sampler, face, level0, x, y, z, rgba, j);
772
773 if (level0 != level1) {
774 /* get texels from second mipmap level and blend */
775 float rgba2[4][4];
776 unsigned c;
777 x /= 2;
778 y /= 2;
779 z /= 2;
780 get_texel(sampler, face, level1, x, y, z, rgba2, j);
781 for (c = 0; c < NUM_CHANNELS; c++) {
782 rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
783 }
784 }
785 }
786 break;
787 case PIPE_TEX_FILTER_LINEAR:
788 for (j = 0; j < QUAD_SIZE; j++) {
789 float texel0[4][4], texel1[4][4];
790 float xw, yw, zw; /* interpolation weights */
791 int x0, x1, y0, y1, z0, z1, c;
792 linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &xw);
793 linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
794 linear_texcoord(sampler->state->wrap_r, p[j], depth, &z0, &z1, &zw);
795 get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
796 get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
797 get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
798 get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
799 get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
800 get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
801 get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
802 get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
803
804 /* 3D lerp */
805 for (c = 0; c < 4; c++) {
806 float ctemp0[4][4], ctemp1[4][4];
807 ctemp0[c][j] = lerp_2d(xw, yw,
808 texel0[c][0], texel0[c][1],
809 texel0[c][2], texel0[c][3]);
810 ctemp1[c][j] = lerp_2d(xw, yw,
811 texel1[c][0], texel1[c][1],
812 texel1[c][2], texel1[c][3]);
813 rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
814 }
815
816 if (level0 != level1) {
817 /* get texels from second mipmap level and blend */
818 float rgba2[4][4];
819 x0 /= 2;
820 y0 /= 2;
821 z0 /= 2;
822 x1 /= 2;
823 y1 /= 2;
824 z1 /= 2;
825 get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
826 get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
827 get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
828 get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
829 get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
830 get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
831 get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
832 get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
833
834 /* 3D lerp */
835 for (c = 0; c < 4; c++) {
836 float ctemp0[4][4], ctemp1[4][4];
837 ctemp0[c][j] = lerp_2d(xw, yw,
838 texel0[c][0], texel0[c][1],
839 texel0[c][2], texel0[c][3]);
840 ctemp1[c][j] = lerp_2d(xw, yw,
841 texel1[c][0], texel1[c][1],
842 texel1[c][2], texel1[c][3]);
843 rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
844 }
845
846 /* blend mipmap levels */
847 for (c = 0; c < NUM_CHANNELS; c++) {
848 rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
849 }
850 }
851 }
852 break;
853 default:
854 assert(0);
855 }
856 }
857
858
859 static void
860 sp_get_samples_cube(struct tgsi_sampler *sampler,
861 const float s[QUAD_SIZE],
862 const float t[QUAD_SIZE],
863 const float p[QUAD_SIZE],
864 float lodbias,
865 float rgba[NUM_CHANNELS][QUAD_SIZE])
866 {
867 unsigned faces[QUAD_SIZE], j;
868 float ssss[4], tttt[4];
869 for (j = 0; j < QUAD_SIZE; j++) {
870 faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
871 }
872 sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
873 }
874
875
876 /**
877 * Called via tgsi_sampler::get_samples()
878 * Use the sampler's state setting to get a filtered RGBA value
879 * from the sampler's texture.
880 *
881 * XXX we can implement many versions of this function, each
882 * tightly coded for a specific combination of sampler state
883 * (nearest + repeat), (bilinear mipmap + clamp), etc.
884 *
885 * The update_samplers() function in st_atom_sampler.c could create
886 * a new tgsi_sampler object for each state combo it finds....
887 */
888 void
889 sp_get_samples(struct tgsi_sampler *sampler,
890 const float s[QUAD_SIZE],
891 const float t[QUAD_SIZE],
892 const float p[QUAD_SIZE],
893 float lodbias,
894 float rgba[NUM_CHANNELS][QUAD_SIZE])
895 {
896 if (!sampler->texture)
897 return;
898
899 switch (sampler->texture->target) {
900 case PIPE_TEXTURE_1D:
901 sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
902 break;
903 case PIPE_TEXTURE_2D:
904 sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
905 break;
906 case PIPE_TEXTURE_3D:
907 sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
908 break;
909 case PIPE_TEXTURE_CUBE:
910 sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
911 break;
912 default:
913 assert(0);
914 }
915 }
916