sp_tex_sample.c revision 38bee46e83b18ff4ad42d340b507b1a15b4326c7
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 */ 61static INLINE float 62lerp(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 */ 76static INLINE float 77lerp_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 */ 89static INLINE float 90lerp_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 */ 117static INLINE void 118nearest_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 */ 258static INLINE void 259linear_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 */ 385static INLINE void 386nearest_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 */ 414static INLINE void 415linear_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 448static unsigned 449choose_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 */ 522static float 523compute_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 */ 580static void 581choose_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 */ 663static void 664get_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 const 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(samp->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 */ 707static INLINE void 708shadow_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 */ 753static void 754sp_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 881static INLINE void 882sp_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 895static INLINE void 896sp_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 908static INLINE void 909sp_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 1035static void 1036sp_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 1052static void 1053sp_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 //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces); 1066 static const uint face = 0; 1067 const uint compare_func = sampler->compare_func; 1068 unsigned level0, level1, j, imgFilter; 1069 int width, height; 1070 float levelBlend; 1071 1072 choose_mipmap_levels(texture, sampler, s, t, p, lodbias, 1073 &level0, &level1, &levelBlend, &imgFilter); 1074 1075 /* texture RECTS cannot be mipmapped */ 1076 assert(level0 == level1); 1077 1078 width = texture->width[level0]; 1079 height = texture->height[level0]; 1080 1081 assert(width > 0); 1082 1083 switch (imgFilter) { 1084 case PIPE_TEX_FILTER_NEAREST: 1085 { 1086 int x[4], y[4]; 1087 nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x); 1088 nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y); 1089 for (j = 0; j < QUAD_SIZE; j++) { 1090 get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j); 1091 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1092 shadow_compare(compare_func, rgba, p, j); 1093 } 1094 } 1095 } 1096 break; 1097 case PIPE_TEX_FILTER_LINEAR: 1098 case PIPE_TEX_FILTER_ANISO: 1099 { 1100 int x0[4], y0[4], x1[4], y1[4]; 1101 float xw[4], yw[4]; /* weights */ 1102 linear_texcoord_unnorm_4(sampler->wrap_s, s, width, x0, x1, xw); 1103 linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw); 1104 for (j = 0; j < QUAD_SIZE; j++) { 1105 float tx[4][4]; /* texels */ 1106 int c; 1107 get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0); 1108 get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1); 1109 get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2); 1110 get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3); 1111 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1112 shadow_compare(compare_func, tx, p, 0); 1113 shadow_compare(compare_func, tx, p, 1); 1114 shadow_compare(compare_func, tx, p, 2); 1115 shadow_compare(compare_func, tx, p, 3); 1116 } 1117 for (c = 0; c < 4; c++) { 1118 rgba[c][j] = lerp_2d(xw[j], yw[j], 1119 tx[c][0], tx[c][1], tx[c][2], tx[c][3]); 1120 } 1121 } 1122 } 1123 break; 1124 default: 1125 assert(0); 1126 } 1127} 1128 1129 1130/** 1131 * Called via tgsi_sampler::get_samples() 1132 * Use the sampler's state setting to get a filtered RGBA value 1133 * from the sampler's texture. 1134 * 1135 * XXX we can implement many versions of this function, each 1136 * tightly coded for a specific combination of sampler state 1137 * (nearest + repeat), (bilinear mipmap + clamp), etc. 1138 * 1139 * The update_samplers() function in st_atom_sampler.c could create 1140 * a new tgsi_sampler object for each state combo it finds.... 1141 */ 1142void 1143sp_get_samples(struct tgsi_sampler *tgsi_sampler, 1144 const float s[QUAD_SIZE], 1145 const float t[QUAD_SIZE], 1146 const float p[QUAD_SIZE], 1147 float lodbias, 1148 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1149{ 1150 const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); 1151 const struct softpipe_context *sp = samp->sp; 1152 const uint unit = samp->unit; 1153 const struct pipe_texture *texture = sp->texture[unit]; 1154 const struct pipe_sampler_state *sampler = sp->sampler[unit]; 1155 1156 if (!texture) 1157 return; 1158 1159 switch (texture->target) { 1160 case PIPE_TEXTURE_1D: 1161 assert(sampler->normalized_coords); 1162 sp_get_samples_1d(tgsi_sampler, s, t, p, lodbias, rgba); 1163 break; 1164 case PIPE_TEXTURE_2D: 1165 if (sampler->normalized_coords) 1166 sp_get_samples_2d(tgsi_sampler, s, t, p, lodbias, rgba); 1167 else 1168 sp_get_samples_rect(tgsi_sampler, s, t, p, lodbias, rgba); 1169 break; 1170 case PIPE_TEXTURE_3D: 1171 assert(sampler->normalized_coords); 1172 sp_get_samples_3d(tgsi_sampler, s, t, p, lodbias, rgba); 1173 break; 1174 case PIPE_TEXTURE_CUBE: 1175 assert(sampler->normalized_coords); 1176 sp_get_samples_cube(tgsi_sampler, s, t, p, lodbias, rgba); 1177 break; 1178 default: 1179 assert(0); 1180 } 1181 1182#if 0 /* DEBUG */ 1183 { 1184 int i; 1185 printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]); 1186 for (i = 0; i < 4; i++) { 1187 printf("Frag %d: %f %f %f %f\n", i, 1188 rgba[0][i], 1189 rgba[1][i], 1190 rgba[2][i], 1191 rgba[3][i]); 1192 } 1193 } 1194#endif 1195} 1196 1197