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