lp_tex_sample.c revision 1e4376a68fae2156018d2e3423df521c6db70013
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 "lp_context.h" 37#include "lp_quad.h" 38#include "lp_surface.h" 39#include "lp_texture.h" 40#include "lp_tex_sample.h" 41#include "lp_tex_cache.h" 42#include "pipe/p_context.h" 43#include "pipe/p_defines.h" 44#include "pipe/p_shader_tokens.h" 45#include "util/u_math.h" 46#include "util/u_memory.h" 47 48 49 50/* 51 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes 52 * see 1-pixel bands of improperly weighted linear-filtered textures. 53 * The tests/texwrap.c demo is a good test. 54 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. 55 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). 56 */ 57#define FRAC(f) ((f) - util_ifloor(f)) 58 59 60/** 61 * Linear interpolation macro 62 */ 63static INLINE float 64lerp(float a, float v0, float v1) 65{ 66 return v0 + a * (v1 - v0); 67} 68 69 70/** 71 * Do 2D/biliner interpolation of float values. 72 * v00, v10, v01 and v11 are typically four texture samples in a square/box. 73 * a and b are the horizontal and vertical interpolants. 74 * It's important that this function is inlined when compiled with 75 * optimization! If we find that's not true on some systems, convert 76 * to a macro. 77 */ 78static INLINE float 79lerp_2d(float a, float b, 80 float v00, float v10, float v01, float v11) 81{ 82 const float temp0 = lerp(a, v00, v10); 83 const float temp1 = lerp(a, v01, v11); 84 return lerp(b, temp0, temp1); 85} 86 87 88/** 89 * As above, but 3D interpolation of 8 values. 90 */ 91static INLINE float 92lerp_3d(float a, float b, float c, 93 float v000, float v100, float v010, float v110, 94 float v001, float v101, float v011, float v111) 95{ 96 const float temp0 = lerp_2d(a, b, v000, v100, v010, v110); 97 const float temp1 = lerp_2d(a, b, v001, v101, v011, v111); 98 return lerp(c, temp0, temp1); 99} 100 101 102 103/** 104 * If A is a signed integer, A % B doesn't give the right value for A < 0 105 * (in terms of texture repeat). Just casting to unsigned fixes that. 106 */ 107#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B)) 108 109 110/** 111 * Apply texture coord wrapping mode and return integer texture indexes 112 * for a vector of four texcoords (S or T or P). 113 * \param wrapMode PIPE_TEX_WRAP_x 114 * \param s the incoming texcoords 115 * \param size the texture image size 116 * \param icoord returns the integer texcoords 117 * \return integer texture index 118 */ 119static INLINE void 120nearest_texcoord_4(unsigned wrapMode, const float s[4], unsigned size, 121 int icoord[4]) 122{ 123 uint ch; 124 switch (wrapMode) { 125 case PIPE_TEX_WRAP_REPEAT: 126 /* s limited to [0,1) */ 127 /* i limited to [0,size-1] */ 128 for (ch = 0; ch < 4; ch++) { 129 int i = util_ifloor(s[ch] * size); 130 icoord[ch] = REMAINDER(i, size); 131 } 132 return; 133 case PIPE_TEX_WRAP_CLAMP: 134 /* s limited to [0,1] */ 135 /* i limited to [0,size-1] */ 136 for (ch = 0; ch < 4; ch++) { 137 if (s[ch] <= 0.0F) 138 icoord[ch] = 0; 139 else if (s[ch] >= 1.0F) 140 icoord[ch] = size - 1; 141 else 142 icoord[ch] = util_ifloor(s[ch] * size); 143 } 144 return; 145 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 146 { 147 /* s limited to [min,max] */ 148 /* i limited to [0, size-1] */ 149 const float min = 1.0F / (2.0F * size); 150 const float max = 1.0F - min; 151 for (ch = 0; ch < 4; ch++) { 152 if (s[ch] < min) 153 icoord[ch] = 0; 154 else if (s[ch] > max) 155 icoord[ch] = size - 1; 156 else 157 icoord[ch] = util_ifloor(s[ch] * size); 158 } 159 } 160 return; 161 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 162 { 163 /* s limited to [min,max] */ 164 /* i limited to [-1, size] */ 165 const float min = -1.0F / (2.0F * size); 166 const float max = 1.0F - min; 167 for (ch = 0; ch < 4; ch++) { 168 if (s[ch] <= min) 169 icoord[ch] = -1; 170 else if (s[ch] >= max) 171 icoord[ch] = size; 172 else 173 icoord[ch] = util_ifloor(s[ch] * size); 174 } 175 } 176 return; 177 case PIPE_TEX_WRAP_MIRROR_REPEAT: 178 { 179 const float min = 1.0F / (2.0F * size); 180 const float max = 1.0F - min; 181 for (ch = 0; ch < 4; ch++) { 182 const int flr = util_ifloor(s[ch]); 183 float u; 184 if (flr & 1) 185 u = 1.0F - (s[ch] - (float) flr); 186 else 187 u = s[ch] - (float) flr; 188 if (u < min) 189 icoord[ch] = 0; 190 else if (u > max) 191 icoord[ch] = size - 1; 192 else 193 icoord[ch] = util_ifloor(u * size); 194 } 195 } 196 return; 197 case PIPE_TEX_WRAP_MIRROR_CLAMP: 198 for (ch = 0; ch < 4; ch++) { 199 /* s limited to [0,1] */ 200 /* i limited to [0,size-1] */ 201 const float u = fabsf(s[ch]); 202 if (u <= 0.0F) 203 icoord[ch] = 0; 204 else if (u >= 1.0F) 205 icoord[ch] = size - 1; 206 else 207 icoord[ch] = util_ifloor(u * size); 208 } 209 return; 210 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 211 { 212 /* s limited to [min,max] */ 213 /* i limited to [0, size-1] */ 214 const float min = 1.0F / (2.0F * size); 215 const float max = 1.0F - min; 216 for (ch = 0; ch < 4; ch++) { 217 const float u = fabsf(s[ch]); 218 if (u < min) 219 icoord[ch] = 0; 220 else if (u > max) 221 icoord[ch] = size - 1; 222 else 223 icoord[ch] = util_ifloor(u * size); 224 } 225 } 226 return; 227 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 228 { 229 /* s limited to [min,max] */ 230 /* i limited to [0, size-1] */ 231 const float min = -1.0F / (2.0F * size); 232 const float max = 1.0F - min; 233 for (ch = 0; ch < 4; ch++) { 234 const float u = fabsf(s[ch]); 235 if (u < min) 236 icoord[ch] = -1; 237 else if (u > max) 238 icoord[ch] = size; 239 else 240 icoord[ch] = util_ifloor(u * size); 241 } 242 } 243 return; 244 default: 245 assert(0); 246 } 247} 248 249 250/** 251 * Used to compute texel locations for linear sampling for four texcoords. 252 * \param wrapMode PIPE_TEX_WRAP_x 253 * \param s the texcoords 254 * \param size the texture image size 255 * \param icoord0 returns first texture indexes 256 * \param icoord1 returns second texture indexes (usually icoord0 + 1) 257 * \param w returns blend factor/weight between texture indexes 258 * \param icoord returns the computed integer texture coords 259 */ 260static INLINE void 261linear_texcoord_4(unsigned wrapMode, const float s[4], unsigned size, 262 int icoord0[4], int icoord1[4], float w[4]) 263{ 264 uint ch; 265 266 switch (wrapMode) { 267 case PIPE_TEX_WRAP_REPEAT: 268 for (ch = 0; ch < 4; ch++) { 269 float u = s[ch] * size - 0.5F; 270 icoord0[ch] = REMAINDER(util_ifloor(u), size); 271 icoord1[ch] = REMAINDER(icoord0[ch] + 1, size); 272 w[ch] = FRAC(u); 273 } 274 break;; 275 case PIPE_TEX_WRAP_CLAMP: 276 for (ch = 0; ch < 4; ch++) { 277 float u = CLAMP(s[ch], 0.0F, 1.0F); 278 u = u * size - 0.5f; 279 icoord0[ch] = util_ifloor(u); 280 icoord1[ch] = icoord0[ch] + 1; 281 w[ch] = FRAC(u); 282 } 283 break;; 284 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 285 for (ch = 0; ch < 4; ch++) { 286 float u = CLAMP(s[ch], 0.0F, 1.0F); 287 u = u * size - 0.5f; 288 icoord0[ch] = util_ifloor(u); 289 icoord1[ch] = icoord0[ch] + 1; 290 if (icoord0[ch] < 0) 291 icoord0[ch] = 0; 292 if (icoord1[ch] >= (int) size) 293 icoord1[ch] = size - 1; 294 w[ch] = FRAC(u); 295 } 296 break;; 297 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 298 { 299 const float min = -1.0F / (2.0F * size); 300 const float max = 1.0F - min; 301 for (ch = 0; ch < 4; ch++) { 302 float u = CLAMP(s[ch], min, max); 303 u = u * size - 0.5f; 304 icoord0[ch] = util_ifloor(u); 305 icoord1[ch] = icoord0[ch] + 1; 306 w[ch] = FRAC(u); 307 } 308 } 309 break;; 310 case PIPE_TEX_WRAP_MIRROR_REPEAT: 311 for (ch = 0; ch < 4; ch++) { 312 const int flr = util_ifloor(s[ch]); 313 float u; 314 if (flr & 1) 315 u = 1.0F - (s[ch] - (float) flr); 316 else 317 u = s[ch] - (float) flr; 318 u = u * size - 0.5F; 319 icoord0[ch] = util_ifloor(u); 320 icoord1[ch] = icoord0[ch] + 1; 321 if (icoord0[ch] < 0) 322 icoord0[ch] = 0; 323 if (icoord1[ch] >= (int) size) 324 icoord1[ch] = size - 1; 325 w[ch] = FRAC(u); 326 } 327 break;; 328 case PIPE_TEX_WRAP_MIRROR_CLAMP: 329 for (ch = 0; ch < 4; ch++) { 330 float u = fabsf(s[ch]); 331 if (u >= 1.0F) 332 u = (float) size; 333 else 334 u *= size; 335 u -= 0.5F; 336 icoord0[ch] = util_ifloor(u); 337 icoord1[ch] = icoord0[ch] + 1; 338 w[ch] = FRAC(u); 339 } 340 break;; 341 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 342 for (ch = 0; ch < 4; ch++) { 343 float u = fabsf(s[ch]); 344 if (u >= 1.0F) 345 u = (float) size; 346 else 347 u *= size; 348 u -= 0.5F; 349 icoord0[ch] = util_ifloor(u); 350 icoord1[ch] = icoord0[ch] + 1; 351 if (icoord0[ch] < 0) 352 icoord0[ch] = 0; 353 if (icoord1[ch] >= (int) size) 354 icoord1[ch] = size - 1; 355 w[ch] = FRAC(u); 356 } 357 break;; 358 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 359 { 360 const float min = -1.0F / (2.0F * size); 361 const float max = 1.0F - min; 362 for (ch = 0; ch < 4; ch++) { 363 float u = fabsf(s[ch]); 364 if (u <= min) 365 u = min * size; 366 else if (u >= max) 367 u = max * size; 368 else 369 u *= size; 370 u -= 0.5F; 371 icoord0[ch] = util_ifloor(u); 372 icoord1[ch] = icoord0[ch] + 1; 373 w[ch] = FRAC(u); 374 } 375 } 376 break;; 377 default: 378 assert(0); 379 } 380} 381 382 383/** 384 * For RECT textures / unnormalized texcoords 385 * Only a subset of wrap modes supported. 386 */ 387static INLINE void 388nearest_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size, 389 int icoord[4]) 390{ 391 uint ch; 392 switch (wrapMode) { 393 case PIPE_TEX_WRAP_CLAMP: 394 for (ch = 0; ch < 4; ch++) { 395 int i = util_ifloor(s[ch]); 396 icoord[ch]= CLAMP(i, 0, (int) size-1); 397 } 398 return; 399 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 400 /* fall-through */ 401 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 402 for (ch = 0; ch < 4; ch++) { 403 icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) ); 404 } 405 return; 406 default: 407 assert(0); 408 } 409} 410 411 412/** 413 * For RECT textures / unnormalized texcoords. 414 * Only a subset of wrap modes supported. 415 */ 416static INLINE void 417linear_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size, 418 int icoord0[4], int icoord1[4], float w[4]) 419{ 420 uint ch; 421 switch (wrapMode) { 422 case PIPE_TEX_WRAP_CLAMP: 423 for (ch = 0; ch < 4; ch++) { 424 /* Not exactly what the spec says, but it matches NVIDIA output */ 425 float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f); 426 icoord0[ch] = util_ifloor(u); 427 icoord1[ch] = icoord0[ch] + 1; 428 w[ch] = FRAC(u); 429 } 430 return; 431 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 432 /* fall-through */ 433 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 434 for (ch = 0; ch < 4; ch++) { 435 float u = CLAMP(s[ch], 0.5F, (float) size - 0.5F); 436 u -= 0.5F; 437 icoord0[ch] = util_ifloor(u); 438 icoord1[ch] = icoord0[ch] + 1; 439 if (icoord1[ch] > (int) size - 1) 440 icoord1[ch] = size - 1; 441 w[ch] = FRAC(u); 442 } 443 break; 444 default: 445 assert(0); 446 } 447} 448 449 450static unsigned 451choose_cube_face(float rx, float ry, float rz, float *newS, float *newT) 452{ 453 /* 454 major axis 455 direction target sc tc ma 456 ---------- ------------------------------- --- --- --- 457 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx 458 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx 459 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry 460 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry 461 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz 462 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz 463 */ 464 const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz); 465 unsigned face; 466 float sc, tc, ma; 467 468 if (arx > ary && arx > arz) { 469 if (rx >= 0.0F) { 470 face = PIPE_TEX_FACE_POS_X; 471 sc = -rz; 472 tc = -ry; 473 ma = arx; 474 } 475 else { 476 face = PIPE_TEX_FACE_NEG_X; 477 sc = rz; 478 tc = -ry; 479 ma = arx; 480 } 481 } 482 else if (ary > arx && ary > arz) { 483 if (ry >= 0.0F) { 484 face = PIPE_TEX_FACE_POS_Y; 485 sc = rx; 486 tc = rz; 487 ma = ary; 488 } 489 else { 490 face = PIPE_TEX_FACE_NEG_Y; 491 sc = rx; 492 tc = -rz; 493 ma = ary; 494 } 495 } 496 else { 497 if (rz > 0.0F) { 498 face = PIPE_TEX_FACE_POS_Z; 499 sc = rx; 500 tc = -ry; 501 ma = arz; 502 } 503 else { 504 face = PIPE_TEX_FACE_NEG_Z; 505 sc = -rx; 506 tc = -ry; 507 ma = arz; 508 } 509 } 510 511 *newS = ( sc / ma + 1.0F ) * 0.5F; 512 *newT = ( tc / ma + 1.0F ) * 0.5F; 513 514 return face; 515} 516 517 518/** 519 * Examine the quad's texture coordinates to compute the partial 520 * derivatives w.r.t X and Y, then compute lambda (level of detail). 521 * 522 * This is only done for fragment shaders, not vertex shaders. 523 */ 524static float 525compute_lambda(struct tgsi_sampler *tgsi_sampler, 526 const float s[QUAD_SIZE], 527 const float t[QUAD_SIZE], 528 const float p[QUAD_SIZE], 529 float lodbias) 530{ 531 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 532 const struct pipe_texture *texture = samp->texture; 533 const struct pipe_sampler_state *sampler = samp->sampler; 534 float rho, lambda; 535 536 if (samp->processor == TGSI_PROCESSOR_VERTEX) 537 return lodbias; 538 539 assert(sampler->normalized_coords); 540 541 assert(s); 542 { 543 float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]; 544 float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]; 545 dsdx = fabsf(dsdx); 546 dsdy = fabsf(dsdy); 547 rho = MAX2(dsdx, dsdy) * texture->width[0]; 548 } 549 if (t) { 550 float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]; 551 float dtdy = t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]; 552 float max; 553 dtdx = fabsf(dtdx); 554 dtdy = fabsf(dtdy); 555 max = MAX2(dtdx, dtdy) * texture->height[0]; 556 rho = MAX2(rho, max); 557 } 558 if (p) { 559 float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]; 560 float dpdy = p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT]; 561 float max; 562 dpdx = fabsf(dpdx); 563 dpdy = fabsf(dpdy); 564 max = MAX2(dpdx, dpdy) * texture->depth[0]; 565 rho = MAX2(rho, max); 566 } 567 568 lambda = util_fast_log2(rho); 569 lambda += lodbias + sampler->lod_bias; 570 lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod); 571 572 return lambda; 573} 574 575 576/** 577 * Do several things here: 578 * 1. Compute lambda from the texcoords, if needed 579 * 2. Determine if we're minifying or magnifying 580 * 3. If minifying, choose mipmap levels 581 * 4. Return image filter to use within mipmap images 582 * \param level0 Returns first mipmap level to sample from 583 * \param level1 Returns second mipmap level to sample from 584 * \param levelBlend Returns blend factor between levels, in [0,1] 585 * \param imgFilter Returns either the min or mag filter, depending on lambda 586 */ 587static void 588choose_mipmap_levels(struct tgsi_sampler *tgsi_sampler, 589 const float s[QUAD_SIZE], 590 const float t[QUAD_SIZE], 591 const float p[QUAD_SIZE], 592 float lodbias, 593 unsigned *level0, unsigned *level1, float *levelBlend, 594 unsigned *imgFilter) 595{ 596 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 597 const struct pipe_texture *texture = samp->texture; 598 const struct pipe_sampler_state *sampler = samp->sampler; 599 600 if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { 601 /* no mipmap selection needed */ 602 *level0 = *level1 = CLAMP((int) sampler->min_lod, 603 0, (int) texture->last_level); 604 605 if (sampler->min_img_filter != sampler->mag_img_filter) { 606 /* non-mipmapped texture, but still need to determine if doing 607 * minification or magnification. 608 */ 609 float lambda = compute_lambda(tgsi_sampler, s, t, p, lodbias); 610 if (lambda <= 0.0) { 611 *imgFilter = sampler->mag_img_filter; 612 } 613 else { 614 *imgFilter = sampler->min_img_filter; 615 } 616 } 617 else { 618 *imgFilter = sampler->mag_img_filter; 619 } 620 } 621 else { 622 float lambda = compute_lambda(tgsi_sampler, s, t, p, lodbias); 623 624 if (lambda <= 0.0) { /* XXX threshold depends on the filter */ 625 /* magnifying */ 626 *imgFilter = sampler->mag_img_filter; 627 *level0 = *level1 = 0; 628 } 629 else { 630 /* minifying */ 631 *imgFilter = sampler->min_img_filter; 632 633 /* choose mipmap level(s) and compute the blend factor between them */ 634 if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { 635 /* Nearest mipmap level */ 636 const int lvl = (int) (lambda + 0.5); 637 *level0 = 638 *level1 = CLAMP(lvl, 0, (int) texture->last_level); 639 } 640 else { 641 /* Linear interpolation between mipmap levels */ 642 const int lvl = (int) lambda; 643 *level0 = CLAMP(lvl, 0, (int) texture->last_level); 644 *level1 = CLAMP(lvl + 1, 0, (int) texture->last_level); 645 *levelBlend = FRAC(lambda); /* blending weight between levels */ 646 } 647 } 648 } 649} 650 651 652/** 653 * Get a texel from a texture, using the texture tile cache. 654 * 655 * \param face the cube face in 0..5 656 * \param level the mipmap level 657 * \param x the x coord of texel within 2D image 658 * \param y the y coord of texel within 2D image 659 * \param z which slice of a 3D texture 660 * \param rgba the quad to put the texel/color into 661 * \param j which element of the rgba quad to write to 662 * 663 * XXX maybe move this into lp_tile_cache.c and merge with the 664 * lp_get_cached_tile_tex() function. Also, get 4 texels instead of 1... 665 */ 666static void 667get_texel_quad_2d(const struct tgsi_sampler *tgsi_sampler, 668 unsigned face, unsigned level, int x, int y, 669 const float *out[4]) 670{ 671 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 672 673 const struct llvmpipe_cached_tex_tile *tile 674 = lp_get_cached_tex_tile(samp->cache, 675 tex_tile_address(x, y, 0, face, level)); 676 677 y %= TEX_TILE_SIZE; 678 x %= TEX_TILE_SIZE; 679 680 out[0] = &tile->color[y ][x ][0]; 681 out[1] = &tile->color[y ][x+1][0]; 682 out[2] = &tile->color[y+1][x ][0]; 683 out[3] = &tile->color[y+1][x+1][0]; 684} 685 686static INLINE const float * 687get_texel_2d_ptr(const struct tgsi_sampler *tgsi_sampler, 688 unsigned face, unsigned level, int x, int y) 689{ 690 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 691 692 const struct llvmpipe_cached_tex_tile *tile 693 = lp_get_cached_tex_tile(samp->cache, 694 tex_tile_address(x, y, 0, face, level)); 695 696 y %= TEX_TILE_SIZE; 697 x %= TEX_TILE_SIZE; 698 699 return &tile->color[y][x][0]; 700} 701 702 703static void 704get_texel_quad_2d_mt(const struct tgsi_sampler *tgsi_sampler, 705 unsigned face, unsigned level, 706 int x0, int y0, 707 int x1, int y1, 708 const float *out[4]) 709{ 710 unsigned i; 711 712 for (i = 0; i < 4; i++) { 713 unsigned tx = (i & 1) ? x1 : x0; 714 unsigned ty = (i >> 1) ? y1 : y0; 715 716 out[i] = get_texel_2d_ptr( tgsi_sampler, face, level, tx, ty ); 717 } 718} 719 720static void 721get_texel(const struct tgsi_sampler *tgsi_sampler, 722 unsigned face, unsigned level, int x, int y, int z, 723 float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j) 724{ 725 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 726 const struct pipe_texture *texture = samp->texture; 727 const struct pipe_sampler_state *sampler = samp->sampler; 728 729 if (x < 0 || x >= (int) texture->width[level] || 730 y < 0 || y >= (int) texture->height[level] || 731 z < 0 || z >= (int) texture->depth[level]) { 732 rgba[0][j] = sampler->border_color[0]; 733 rgba[1][j] = sampler->border_color[1]; 734 rgba[2][j] = sampler->border_color[2]; 735 rgba[3][j] = sampler->border_color[3]; 736 } 737 else { 738 const unsigned tx = x % TEX_TILE_SIZE; 739 const unsigned ty = y % TEX_TILE_SIZE; 740 const struct llvmpipe_cached_tex_tile *tile; 741 742 tile = lp_get_cached_tex_tile(samp->cache, 743 tex_tile_address(x, y, z, face, level)); 744 745 rgba[0][j] = tile->color[ty][tx][0]; 746 rgba[1][j] = tile->color[ty][tx][1]; 747 rgba[2][j] = tile->color[ty][tx][2]; 748 rgba[3][j] = tile->color[ty][tx][3]; 749 if (0) 750 { 751 debug_printf("Get texel %f %f %f %f from %s\n", 752 rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j], 753 pf_name(texture->format)); 754 } 755 } 756} 757 758 759/** 760 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]' 761 * When we sampled the depth texture, the depth value was put into all 762 * RGBA channels. We look at the red channel here. 763 * \param rgba quad of (depth) texel values 764 * \param p texture 'P' components for four pixels in quad 765 * \param j which pixel in the quad to test [0..3] 766 */ 767static INLINE void 768shadow_compare(const struct pipe_sampler_state *sampler, 769 float rgba[NUM_CHANNELS][QUAD_SIZE], 770 const float p[QUAD_SIZE], 771 uint j) 772{ 773 int k; 774 switch (sampler->compare_func) { 775 case PIPE_FUNC_LESS: 776 k = p[j] < rgba[0][j]; 777 break; 778 case PIPE_FUNC_LEQUAL: 779 k = p[j] <= rgba[0][j]; 780 break; 781 case PIPE_FUNC_GREATER: 782 k = p[j] > rgba[0][j]; 783 break; 784 case PIPE_FUNC_GEQUAL: 785 k = p[j] >= rgba[0][j]; 786 break; 787 case PIPE_FUNC_EQUAL: 788 k = p[j] == rgba[0][j]; 789 break; 790 case PIPE_FUNC_NOTEQUAL: 791 k = p[j] != rgba[0][j]; 792 break; 793 case PIPE_FUNC_ALWAYS: 794 k = 1; 795 break; 796 case PIPE_FUNC_NEVER: 797 k = 0; 798 break; 799 default: 800 k = 0; 801 assert(0); 802 break; 803 } 804 805 /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ 806 rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k; 807 rgba[3][j] = 1.0F; 808} 809 810 811/** 812 * As above, but do four z/texture comparisons. 813 */ 814static INLINE void 815shadow_compare4(const struct pipe_sampler_state *sampler, 816 float rgba[NUM_CHANNELS][QUAD_SIZE], 817 const float p[QUAD_SIZE]) 818{ 819 int j, k0, k1, k2, k3; 820 float val; 821 822 /* compare four texcoords vs. four texture samples */ 823 switch (sampler->compare_func) { 824 case PIPE_FUNC_LESS: 825 k0 = p[0] < rgba[0][0]; 826 k1 = p[1] < rgba[0][1]; 827 k2 = p[2] < rgba[0][2]; 828 k3 = p[3] < rgba[0][3]; 829 break; 830 case PIPE_FUNC_LEQUAL: 831 k0 = p[0] <= rgba[0][0]; 832 k1 = p[1] <= rgba[0][1]; 833 k2 = p[2] <= rgba[0][2]; 834 k3 = p[3] <= rgba[0][3]; 835 break; 836 case PIPE_FUNC_GREATER: 837 k0 = p[0] > rgba[0][0]; 838 k1 = p[1] > rgba[0][1]; 839 k2 = p[2] > rgba[0][2]; 840 k3 = p[3] > rgba[0][3]; 841 break; 842 case PIPE_FUNC_GEQUAL: 843 k0 = p[0] >= rgba[0][0]; 844 k1 = p[1] >= rgba[0][1]; 845 k2 = p[2] >= rgba[0][2]; 846 k3 = p[3] >= rgba[0][3]; 847 break; 848 case PIPE_FUNC_EQUAL: 849 k0 = p[0] == rgba[0][0]; 850 k1 = p[1] == rgba[0][1]; 851 k2 = p[2] == rgba[0][2]; 852 k3 = p[3] == rgba[0][3]; 853 break; 854 case PIPE_FUNC_NOTEQUAL: 855 k0 = p[0] != rgba[0][0]; 856 k1 = p[1] != rgba[0][1]; 857 k2 = p[2] != rgba[0][2]; 858 k3 = p[3] != rgba[0][3]; 859 break; 860 case PIPE_FUNC_ALWAYS: 861 k0 = k1 = k2 = k3 = 1; 862 break; 863 case PIPE_FUNC_NEVER: 864 k0 = k1 = k2 = k3 = 0; 865 break; 866 default: 867 k0 = k1 = k2 = k3 = 0; 868 assert(0); 869 break; 870 } 871 872 /* convert four pass/fail values to an intensity in [0,1] */ 873 val = 0.25F * (k0 + k1 + k2 + k3); 874 875 /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ 876 for (j = 0; j < 4; j++) { 877 rgba[0][j] = rgba[1][j] = rgba[2][j] = val; 878 rgba[3][j] = 1.0F; 879 } 880} 881 882 883 884static void 885lp_get_samples_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler, 886 const float s[QUAD_SIZE], 887 const float t[QUAD_SIZE], 888 const float p[QUAD_SIZE], 889 float lodbias, 890 float rgba[NUM_CHANNELS][QUAD_SIZE]) 891{ 892 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 893 unsigned j; 894 unsigned level = samp->level; 895 unsigned xpot = 1 << (samp->xpot - level); 896 unsigned ypot = 1 << (samp->ypot - level); 897 unsigned xmax = (xpot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, xpot) - 1; */ 898 unsigned ymax = (ypot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, ypot) - 1; */ 899 900 for (j = 0; j < QUAD_SIZE; j++) { 901 int c; 902 903 float u = s[j] * xpot - 0.5F; 904 float v = t[j] * ypot - 0.5F; 905 906 int uflr = util_ifloor(u); 907 int vflr = util_ifloor(v); 908 909 float xw = u - (float)uflr; 910 float yw = v - (float)vflr; 911 912 int x0 = uflr & (xpot - 1); 913 int y0 = vflr & (ypot - 1); 914 915 const float *tx[4]; 916 917 918 /* Can we fetch all four at once: 919 */ 920 if (x0 < xmax && y0 < ymax) 921 { 922 get_texel_quad_2d(tgsi_sampler, 0, level, x0, y0, tx); 923 } 924 else 925 { 926 unsigned x1 = (x0 + 1) & (xpot - 1); 927 unsigned y1 = (y0 + 1) & (ypot - 1); 928 get_texel_quad_2d_mt(tgsi_sampler, 0, level, 929 x0, y0, x1, y1, tx); 930 } 931 932 933 /* interpolate R, G, B, A */ 934 for (c = 0; c < 4; c++) { 935 rgba[c][j] = lerp_2d(xw, yw, 936 tx[0][c], tx[1][c], 937 tx[2][c], tx[3][c]); 938 } 939 } 940} 941 942 943static void 944lp_get_samples_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler, 945 const float s[QUAD_SIZE], 946 const float t[QUAD_SIZE], 947 const float p[QUAD_SIZE], 948 float lodbias, 949 float rgba[NUM_CHANNELS][QUAD_SIZE]) 950{ 951 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 952 unsigned j; 953 unsigned level = samp->level; 954 unsigned xpot = 1 << (samp->xpot - level); 955 unsigned ypot = 1 << (samp->ypot - level); 956 957 for (j = 0; j < QUAD_SIZE; j++) { 958 int c; 959 960 float u = s[j] * xpot; 961 float v = t[j] * ypot; 962 963 int uflr = util_ifloor(u); 964 int vflr = util_ifloor(v); 965 966 int x0 = uflr & (xpot - 1); 967 int y0 = vflr & (ypot - 1); 968 969 const float *out = get_texel_2d_ptr(tgsi_sampler, 0, level, x0, y0); 970 971 for (c = 0; c < 4; c++) { 972 rgba[c][j] = out[c]; 973 } 974 } 975} 976 977 978static void 979lp_get_samples_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler, 980 const float s[QUAD_SIZE], 981 const float t[QUAD_SIZE], 982 const float p[QUAD_SIZE], 983 float lodbias, 984 float rgba[NUM_CHANNELS][QUAD_SIZE]) 985{ 986 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 987 unsigned j; 988 unsigned level = samp->level; 989 unsigned xpot = 1 << (samp->xpot - level); 990 unsigned ypot = 1 << (samp->ypot - level); 991 992 for (j = 0; j < QUAD_SIZE; j++) { 993 int c; 994 995 float u = s[j] * xpot; 996 float v = t[j] * ypot; 997 998 int x0, y0; 999 const float *out; 1000 1001 x0 = util_ifloor(u); 1002 if (x0 < 0) 1003 x0 = 0; 1004 else if (x0 > xpot - 1) 1005 x0 = xpot - 1; 1006 1007 y0 = util_ifloor(v); 1008 if (y0 < 0) 1009 y0 = 0; 1010 else if (y0 > ypot - 1) 1011 y0 = ypot - 1; 1012 1013 out = get_texel_2d_ptr(tgsi_sampler, 0, level, x0, y0); 1014 1015 for (c = 0; c < 4; c++) { 1016 rgba[c][j] = out[c]; 1017 } 1018 } 1019} 1020 1021 1022static void 1023lp_get_samples_2d_linear_mip_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler, 1024 const float s[QUAD_SIZE], 1025 const float t[QUAD_SIZE], 1026 const float p[QUAD_SIZE], 1027 float lodbias, 1028 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1029{ 1030 struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 1031 const struct pipe_texture *texture = samp->texture; 1032 int level0; 1033 float lambda; 1034 1035 lambda = compute_lambda(tgsi_sampler, s, t, p, lodbias); 1036 level0 = (int)lambda; 1037 1038 if (lambda < 0.0) { 1039 samp->level = 0; 1040 lp_get_samples_2d_linear_repeat_POT( tgsi_sampler, 1041 s, t, p, 0, rgba ); 1042 } 1043 else if (level0 >= texture->last_level) { 1044 samp->level = texture->last_level; 1045 lp_get_samples_2d_linear_repeat_POT( tgsi_sampler, 1046 s, t, p, 0, rgba ); 1047 } 1048 else { 1049 float levelBlend = lambda - level0; 1050 float rgba0[4][4]; 1051 float rgba1[4][4]; 1052 int c,j; 1053 1054 samp->level = level0; 1055 lp_get_samples_2d_linear_repeat_POT( tgsi_sampler, 1056 s, t, p, 0, rgba0 ); 1057 1058 samp->level = level0+1; 1059 lp_get_samples_2d_linear_repeat_POT( tgsi_sampler, 1060 s, t, p, 0, rgba1 ); 1061 1062 for (j = 0; j < QUAD_SIZE; j++) { 1063 for (c = 0; c < 4; c++) { 1064 rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]); 1065 } 1066 } 1067 } 1068} 1069 1070/** 1071 * Common code for sampling 1D/2D/cube textures. 1072 * Could probably extend for 3D... 1073 */ 1074static void 1075lp_get_samples_2d_common(struct tgsi_sampler *tgsi_sampler, 1076 const float s[QUAD_SIZE], 1077 const float t[QUAD_SIZE], 1078 const float p[QUAD_SIZE], 1079 float lodbias, 1080 float rgba[NUM_CHANNELS][QUAD_SIZE], 1081 const unsigned faces[4]) 1082{ 1083 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 1084 const struct pipe_texture *texture = samp->texture; 1085 const struct pipe_sampler_state *sampler = samp->sampler; 1086 unsigned level0, level1, j, imgFilter; 1087 int width, height; 1088 float levelBlend; 1089 1090 choose_mipmap_levels(tgsi_sampler, s, t, p, 1091 lodbias, 1092 &level0, &level1, &levelBlend, &imgFilter); 1093 1094 assert(sampler->normalized_coords); 1095 1096 width = texture->width[level0]; 1097 height = texture->height[level0]; 1098 1099 assert(width > 0); 1100 1101 switch (imgFilter) { 1102 case PIPE_TEX_FILTER_NEAREST: 1103 { 1104 int x[4], y[4]; 1105 nearest_texcoord_4(sampler->wrap_s, s, width, x); 1106 nearest_texcoord_4(sampler->wrap_t, t, height, y); 1107 1108 for (j = 0; j < QUAD_SIZE; j++) { 1109 get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j); 1110 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1111 shadow_compare(sampler, rgba, p, j); 1112 } 1113 1114 if (level0 != level1) { 1115 /* get texels from second mipmap level and blend */ 1116 float rgba2[4][4]; 1117 unsigned c; 1118 x[j] /= 2; 1119 y[j] /= 2; 1120 get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0, 1121 rgba2, j); 1122 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ 1123 shadow_compare(sampler, rgba2, p, j); 1124 } 1125 1126 for (c = 0; c < NUM_CHANNELS; c++) { 1127 rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); 1128 } 1129 } 1130 } 1131 } 1132 break; 1133 case PIPE_TEX_FILTER_LINEAR: 1134 case PIPE_TEX_FILTER_ANISO: 1135 { 1136 int x0[4], y0[4], x1[4], y1[4]; 1137 float xw[4], yw[4]; /* weights */ 1138 1139 linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); 1140 linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); 1141 1142 for (j = 0; j < QUAD_SIZE; j++) { 1143 float tx[4][4]; /* texels */ 1144 int c; 1145 get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0); 1146 get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1); 1147 get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2); 1148 get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3); 1149 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1150 shadow_compare4(sampler, tx, p); 1151 } 1152 1153 /* interpolate R, G, B, A */ 1154 for (c = 0; c < 4; c++) { 1155 rgba[c][j] = lerp_2d(xw[j], yw[j], 1156 tx[c][0], tx[c][1], 1157 tx[c][2], tx[c][3]); 1158 } 1159 1160 if (level0 != level1) { 1161 /* get texels from second mipmap level and blend */ 1162 float rgba2[4][4]; 1163 1164 /* XXX: This is incorrect -- will often end up with (x0 1165 * == x1 && y0 == y1), meaning that we fetch the same 1166 * texel four times and linearly interpolate between 1167 * identical values. The correct approach would be to 1168 * call linear_texcoord again for the second level. 1169 */ 1170 x0[j] /= 2; 1171 y0[j] /= 2; 1172 x1[j] /= 2; 1173 y1[j] /= 2; 1174 get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0); 1175 get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1); 1176 get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2); 1177 get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3); 1178 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ 1179 shadow_compare4(sampler, tx, p); 1180 } 1181 1182 /* interpolate R, G, B, A */ 1183 for (c = 0; c < 4; c++) { 1184 rgba2[c][j] = lerp_2d(xw[j], yw[j], 1185 tx[c][0], tx[c][1], tx[c][2], tx[c][3]); 1186 } 1187 1188 for (c = 0; c < NUM_CHANNELS; c++) { 1189 rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); 1190 } 1191 } 1192 } 1193 } 1194 break; 1195 default: 1196 assert(0); 1197 } 1198} 1199 1200 1201static INLINE void 1202lp_get_samples_1d(struct tgsi_sampler *sampler, 1203 const float s[QUAD_SIZE], 1204 const float t[QUAD_SIZE], 1205 const float p[QUAD_SIZE], 1206 float lodbias, 1207 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1208{ 1209 static const unsigned faces[4] = {0, 0, 0, 0}; 1210 static const float tzero[4] = {0, 0, 0, 0}; 1211 lp_get_samples_2d_common(sampler, s, tzero, NULL, 1212 lodbias, rgba, faces); 1213} 1214 1215 1216static INLINE void 1217lp_get_samples_2d(struct tgsi_sampler *sampler, 1218 const float s[QUAD_SIZE], 1219 const float t[QUAD_SIZE], 1220 const float p[QUAD_SIZE], 1221 float lodbias, 1222 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1223{ 1224 static const unsigned faces[4] = {0, 0, 0, 0}; 1225 lp_get_samples_2d_common(sampler, s, t, p, 1226 lodbias, rgba, faces); 1227} 1228 1229 1230static INLINE void 1231lp_get_samples_3d(struct tgsi_sampler *tgsi_sampler, 1232 const float s[QUAD_SIZE], 1233 const float t[QUAD_SIZE], 1234 const float p[QUAD_SIZE], 1235 float lodbias, 1236 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1237{ 1238 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 1239 const struct pipe_texture *texture = samp->texture; 1240 const struct pipe_sampler_state *sampler = samp->sampler; 1241 /* get/map pipe_surfaces corresponding to 3D tex slices */ 1242 unsigned level0, level1, j, imgFilter; 1243 int width, height, depth; 1244 float levelBlend; 1245 const uint face = 0; 1246 1247 choose_mipmap_levels(tgsi_sampler, s, t, p, 1248 lodbias, 1249 &level0, &level1, &levelBlend, &imgFilter); 1250 1251 assert(sampler->normalized_coords); 1252 1253 width = texture->width[level0]; 1254 height = texture->height[level0]; 1255 depth = texture->depth[level0]; 1256 1257 assert(width > 0); 1258 assert(height > 0); 1259 assert(depth > 0); 1260 1261 switch (imgFilter) { 1262 case PIPE_TEX_FILTER_NEAREST: 1263 { 1264 int x[4], y[4], z[4]; 1265 nearest_texcoord_4(sampler->wrap_s, s, width, x); 1266 nearest_texcoord_4(sampler->wrap_t, t, height, y); 1267 nearest_texcoord_4(sampler->wrap_r, p, depth, z); 1268 for (j = 0; j < QUAD_SIZE; j++) { 1269 get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j); 1270 if (level0 != level1) { 1271 /* get texels from second mipmap level and blend */ 1272 float rgba2[4][4]; 1273 unsigned c; 1274 x[j] /= 2; 1275 y[j] /= 2; 1276 z[j] /= 2; 1277 get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j); 1278 for (c = 0; c < NUM_CHANNELS; c++) { 1279 rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]); 1280 } 1281 } 1282 } 1283 } 1284 break; 1285 case PIPE_TEX_FILTER_LINEAR: 1286 case PIPE_TEX_FILTER_ANISO: 1287 { 1288 int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4]; 1289 float xw[4], yw[4], zw[4]; /* interpolation weights */ 1290 linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); 1291 linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); 1292 linear_texcoord_4(sampler->wrap_r, p, depth, z0, z1, zw); 1293 1294 for (j = 0; j < QUAD_SIZE; j++) { 1295 int c; 1296 float tx0[4][4], tx1[4][4]; 1297 get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0); 1298 get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1); 1299 get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2); 1300 get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3); 1301 get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0); 1302 get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1); 1303 get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2); 1304 get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3); 1305 1306 /* interpolate R, G, B, A */ 1307 for (c = 0; c < 4; c++) { 1308 rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j], 1309 tx0[c][0], tx0[c][1], 1310 tx0[c][2], tx0[c][3], 1311 tx1[c][0], tx1[c][1], 1312 tx1[c][2], tx1[c][3]); 1313 } 1314 1315 if (level0 != level1) { 1316 /* get texels from second mipmap level and blend */ 1317 float rgba2[4][4]; 1318 x0[j] /= 2; 1319 y0[j] /= 2; 1320 z0[j] /= 2; 1321 x1[j] /= 2; 1322 y1[j] /= 2; 1323 z1[j] /= 2; 1324 get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0); 1325 get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1); 1326 get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2); 1327 get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3); 1328 get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0); 1329 get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1); 1330 get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2); 1331 get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3); 1332 1333 /* interpolate R, G, B, A */ 1334 for (c = 0; c < 4; c++) { 1335 rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j], 1336 tx0[c][0], tx0[c][1], 1337 tx0[c][2], tx0[c][3], 1338 tx1[c][0], tx1[c][1], 1339 tx1[c][2], tx1[c][3]); 1340 } 1341 1342 /* blend mipmap levels */ 1343 for (c = 0; c < NUM_CHANNELS; c++) { 1344 rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); 1345 } 1346 } 1347 } 1348 } 1349 break; 1350 default: 1351 assert(0); 1352 } 1353} 1354 1355 1356static void 1357lp_get_samples_cube(struct tgsi_sampler *sampler, 1358 const float s[QUAD_SIZE], 1359 const float t[QUAD_SIZE], 1360 const float p[QUAD_SIZE], 1361 float lodbias, 1362 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1363{ 1364 unsigned faces[QUAD_SIZE], j; 1365 float ssss[4], tttt[4]; 1366 for (j = 0; j < QUAD_SIZE; j++) { 1367 faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j); 1368 } 1369 lp_get_samples_2d_common(sampler, ssss, tttt, NULL, 1370 lodbias, rgba, faces); 1371} 1372 1373 1374static void 1375lp_get_samples_rect(struct tgsi_sampler *tgsi_sampler, 1376 const float s[QUAD_SIZE], 1377 const float t[QUAD_SIZE], 1378 const float p[QUAD_SIZE], 1379 float lodbias, 1380 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1381{ 1382 const struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 1383 const struct pipe_texture *texture = samp->texture; 1384 const struct pipe_sampler_state *sampler = samp->sampler; 1385 const uint face = 0; 1386 unsigned level0, level1, j, imgFilter; 1387 int width, height; 1388 float levelBlend; 1389 1390 choose_mipmap_levels(tgsi_sampler, s, t, p, 1391 lodbias, 1392 &level0, &level1, &levelBlend, &imgFilter); 1393 1394 /* texture RECTS cannot be mipmapped */ 1395 assert(level0 == level1); 1396 1397 width = texture->width[level0]; 1398 height = texture->height[level0]; 1399 1400 assert(width > 0); 1401 1402 switch (imgFilter) { 1403 case PIPE_TEX_FILTER_NEAREST: 1404 { 1405 int x[4], y[4]; 1406 nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x); 1407 nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y); 1408 for (j = 0; j < QUAD_SIZE; j++) { 1409 get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j); 1410 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1411 shadow_compare(sampler, rgba, p, j); 1412 } 1413 } 1414 } 1415 break; 1416 case PIPE_TEX_FILTER_LINEAR: 1417 case PIPE_TEX_FILTER_ANISO: 1418 { 1419 int x0[4], y0[4], x1[4], y1[4]; 1420 float xw[4], yw[4]; /* weights */ 1421 linear_texcoord_unnorm_4(sampler->wrap_s, s, width, x0, x1, xw); 1422 linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw); 1423 for (j = 0; j < QUAD_SIZE; j++) { 1424 float tx[4][4]; /* texels */ 1425 int c; 1426 get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0); 1427 get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1); 1428 get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2); 1429 get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3); 1430 if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { 1431 shadow_compare4(sampler, tx, p); 1432 } 1433 for (c = 0; c < 4; c++) { 1434 rgba[c][j] = lerp_2d(xw[j], yw[j], 1435 tx[c][0], tx[c][1], tx[c][2], tx[c][3]); 1436 } 1437 } 1438 } 1439 break; 1440 default: 1441 assert(0); 1442 } 1443} 1444 1445 1446/** 1447 * Error condition handler 1448 */ 1449static INLINE void 1450lp_get_samples_null(struct tgsi_sampler *tgsi_sampler, 1451 const float s[QUAD_SIZE], 1452 const float t[QUAD_SIZE], 1453 const float p[QUAD_SIZE], 1454 float lodbias, 1455 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1456{ 1457 int i,j; 1458 1459 for (i = 0; i < 4; i++) 1460 for (j = 0; j < 4; j++) 1461 rgba[i][j] = 1.0; 1462} 1463 1464/** 1465 * Called via tgsi_sampler::get_samples() when using a sampler for the 1466 * first time. Determine the actual sampler function, link it in and 1467 * call it. 1468 */ 1469void 1470lp_get_samples(struct tgsi_sampler *tgsi_sampler, 1471 const float s[QUAD_SIZE], 1472 const float t[QUAD_SIZE], 1473 const float p[QUAD_SIZE], 1474 float lodbias, 1475 float rgba[NUM_CHANNELS][QUAD_SIZE]) 1476{ 1477 struct lp_shader_sampler *samp = lp_shader_sampler(tgsi_sampler); 1478 const struct pipe_texture *texture = samp->texture; 1479 const struct pipe_sampler_state *sampler = samp->sampler; 1480 1481 /* Default to the 'undefined' case: 1482 */ 1483 tgsi_sampler->get_samples = lp_get_samples_null; 1484 1485 if (!texture) { 1486 assert(0); /* is this legal?? */ 1487 goto out; 1488 } 1489 1490 if (!sampler->normalized_coords) { 1491 assert (texture->target == PIPE_TEXTURE_2D); 1492 tgsi_sampler->get_samples = lp_get_samples_rect; 1493 goto out; 1494 } 1495 1496 switch (texture->target) { 1497 case PIPE_TEXTURE_1D: 1498 tgsi_sampler->get_samples = lp_get_samples_1d; 1499 break; 1500 case PIPE_TEXTURE_2D: 1501 tgsi_sampler->get_samples = lp_get_samples_2d; 1502 break; 1503 case PIPE_TEXTURE_3D: 1504 tgsi_sampler->get_samples = lp_get_samples_3d; 1505 break; 1506 case PIPE_TEXTURE_CUBE: 1507 tgsi_sampler->get_samples = lp_get_samples_cube; 1508 break; 1509 default: 1510 assert(0); 1511 break; 1512 } 1513 1514 /* Do this elsewhere: 1515 */ 1516 samp->xpot = util_unsigned_logbase2( samp->texture->width[0] ); 1517 samp->ypot = util_unsigned_logbase2( samp->texture->height[0] ); 1518 1519 /* Try to hook in a faster sampler. Ultimately we'll have to 1520 * code-generate these. Luckily most of this looks like it is 1521 * orthogonal state within the sampler. 1522 */ 1523 if (texture->target == PIPE_TEXTURE_2D && 1524 sampler->min_img_filter == sampler->mag_img_filter && 1525 sampler->wrap_s == sampler->wrap_t && 1526 sampler->compare_mode == FALSE && 1527 sampler->normalized_coords) 1528 { 1529 if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { 1530 samp->level = CLAMP((int) sampler->min_lod, 1531 0, (int) texture->last_level); 1532 1533 if (sampler->wrap_s == PIPE_TEX_WRAP_REPEAT) { 1534 switch (sampler->min_img_filter) { 1535 case PIPE_TEX_FILTER_NEAREST: 1536 tgsi_sampler->get_samples = lp_get_samples_2d_nearest_repeat_POT; 1537 break; 1538 case PIPE_TEX_FILTER_LINEAR: 1539 tgsi_sampler->get_samples = lp_get_samples_2d_linear_repeat_POT; 1540 break; 1541 default: 1542 break; 1543 } 1544 } 1545 else if (sampler->wrap_s == PIPE_TEX_WRAP_CLAMP) { 1546 switch (sampler->min_img_filter) { 1547 case PIPE_TEX_FILTER_NEAREST: 1548 tgsi_sampler->get_samples = lp_get_samples_2d_nearest_clamp_POT; 1549 break; 1550 default: 1551 break; 1552 } 1553 } 1554 } 1555 else if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { 1556 if (sampler->wrap_s == PIPE_TEX_WRAP_REPEAT) { 1557 switch (sampler->min_img_filter) { 1558 case PIPE_TEX_FILTER_LINEAR: 1559 tgsi_sampler->get_samples = lp_get_samples_2d_linear_mip_linear_repeat_POT; 1560 break; 1561 default: 1562 break; 1563 } 1564 } 1565 } 1566 } 1567 else if (0) { 1568 _debug_printf("target %d/%d min_mip %d/%d min_img %d/%d wrap %d/%d compare %d/%d norm %d/%d\n", 1569 texture->target, PIPE_TEXTURE_2D, 1570 sampler->min_mip_filter, PIPE_TEX_MIPFILTER_NONE, 1571 sampler->min_img_filter, sampler->mag_img_filter, 1572 sampler->wrap_s, sampler->wrap_t, 1573 sampler->compare_mode, FALSE, 1574 sampler->normalized_coords, TRUE); 1575 } 1576 1577out: 1578 tgsi_sampler->get_samples( tgsi_sampler, s, t, p, lodbias, rgba ); 1579} 1580 1581