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