1 /************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * All Rights Reserved. 5 * Copyright 2008-2010 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 VMWARE 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 * Keith Whitwell 35 */ 36 37 #include "pipe/p_context.h" 38 #include "pipe/p_defines.h" 39 #include "pipe/p_shader_tokens.h" 40 #include "util/u_math.h" 41 #include "util/u_format.h" 42 #include "util/u_memory.h" 43 #include "util/u_inlines.h" 44 #include "sp_quad.h" /* only for #define QUAD_* tokens */ 45 #include "sp_tex_sample.h" 46 #include "sp_texture.h" 47 #include "sp_tex_tile_cache.h" 48 49 50 /** Set to one to help debug texture sampling */ 51 #define DEBUG_TEX 0 52 53 54 /* 55 * Return fractional part of 'f'. Used for computing interpolation weights. 56 * Need to be careful with negative values. 57 * Note, if this function isn't perfect you'll sometimes see 1-pixel bands 58 * of improperly weighted linear-filtered textures. 59 * The tests/texwrap.c demo is a good test. 60 */ 61 static inline float 62 frac(float f) 63 { 64 return f - floorf(f); 65 } 66 67 68 69 /** 70 * Linear interpolation macro 71 */ 72 static inline float 73 lerp(float a, float v0, float v1) 74 { 75 return v0 + a * (v1 - v0); 76 } 77 78 79 /** 80 * Do 2D/bilinear interpolation of float values. 81 * v00, v10, v01 and v11 are typically four texture samples in a square/box. 82 * a and b are the horizontal and vertical interpolants. 83 * It's important that this function is inlined when compiled with 84 * optimization! If we find that's not true on some systems, convert 85 * to a macro. 86 */ 87 static inline float 88 lerp_2d(float a, float b, 89 float v00, float v10, float v01, float v11) 90 { 91 const float temp0 = lerp(a, v00, v10); 92 const float temp1 = lerp(a, v01, v11); 93 return lerp(b, temp0, temp1); 94 } 95 96 97 /** 98 * As above, but 3D interpolation of 8 values. 99 */ 100 static inline float 101 lerp_3d(float a, float b, float c, 102 float v000, float v100, float v010, float v110, 103 float v001, float v101, float v011, float v111) 104 { 105 const float temp0 = lerp_2d(a, b, v000, v100, v010, v110); 106 const float temp1 = lerp_2d(a, b, v001, v101, v011, v111); 107 return lerp(c, temp0, temp1); 108 } 109 110 111 112 /** 113 * Compute coord % size for repeat wrap modes. 114 * Note that if coord is negative, coord % size doesn't give the right 115 * value. To avoid that problem we add a large multiple of the size 116 * (rather than using a conditional). 117 */ 118 static inline int 119 repeat(int coord, unsigned size) 120 { 121 return (coord + size * 1024) % size; 122 } 123 124 125 /** 126 * Apply texture coord wrapping mode and return integer texture indexes 127 * for a vector of four texcoords (S or T or P). 128 * \param wrapMode PIPE_TEX_WRAP_x 129 * \param s the incoming texcoords 130 * \param size the texture image size 131 * \param icoord returns the integer texcoords 132 */ 133 static void 134 wrap_nearest_repeat(float s, unsigned size, int offset, int *icoord) 135 { 136 /* s limited to [0,1) */ 137 /* i limited to [0,size-1] */ 138 const int i = util_ifloor(s * size); 139 *icoord = repeat(i + offset, size); 140 } 141 142 143 static void 144 wrap_nearest_clamp(float s, unsigned size, int offset, int *icoord) 145 { 146 /* s limited to [0,1] */ 147 /* i limited to [0,size-1] */ 148 s *= size; 149 s += offset; 150 if (s <= 0.0F) 151 *icoord = 0; 152 else if (s >= size) 153 *icoord = size - 1; 154 else 155 *icoord = util_ifloor(s); 156 } 157 158 159 static void 160 wrap_nearest_clamp_to_edge(float s, unsigned size, int offset, int *icoord) 161 { 162 /* s limited to [min,max] */ 163 /* i limited to [0, size-1] */ 164 const float min = 0.5F; 165 const float max = (float)size - 0.5F; 166 167 s *= size; 168 s += offset; 169 170 if (s < min) 171 *icoord = 0; 172 else if (s > max) 173 *icoord = size - 1; 174 else 175 *icoord = util_ifloor(s); 176 } 177 178 179 static void 180 wrap_nearest_clamp_to_border(float s, unsigned size, int offset, int *icoord) 181 { 182 /* s limited to [min,max] */ 183 /* i limited to [-1, size] */ 184 const float min = -0.5F; 185 const float max = size + 0.5F; 186 187 s *= size; 188 s += offset; 189 if (s <= min) 190 *icoord = -1; 191 else if (s >= max) 192 *icoord = size; 193 else 194 *icoord = util_ifloor(s); 195 } 196 197 static void 198 wrap_nearest_mirror_repeat(float s, unsigned size, int offset, int *icoord) 199 { 200 const float min = 1.0F / (2.0F * size); 201 const float max = 1.0F - min; 202 int flr; 203 float u; 204 205 s += (float)offset / size; 206 flr = util_ifloor(s); 207 u = frac(s); 208 if (flr & 1) 209 u = 1.0F - u; 210 if (u < min) 211 *icoord = 0; 212 else if (u > max) 213 *icoord = size - 1; 214 else 215 *icoord = util_ifloor(u * size); 216 } 217 218 219 static void 220 wrap_nearest_mirror_clamp(float s, unsigned size, int offset, int *icoord) 221 { 222 /* s limited to [0,1] */ 223 /* i limited to [0,size-1] */ 224 const float u = fabsf(s * size + offset); 225 if (u <= 0.0F) 226 *icoord = 0; 227 else if (u >= size) 228 *icoord = size - 1; 229 else 230 *icoord = util_ifloor(u); 231 } 232 233 234 static void 235 wrap_nearest_mirror_clamp_to_edge(float s, unsigned size, int offset, int *icoord) 236 { 237 /* s limited to [min,max] */ 238 /* i limited to [0, size-1] */ 239 const float min = 0.5F; 240 const float max = (float)size - 0.5F; 241 const float u = fabsf(s * size + offset); 242 243 if (u < min) 244 *icoord = 0; 245 else if (u > max) 246 *icoord = size - 1; 247 else 248 *icoord = util_ifloor(u); 249 } 250 251 252 static void 253 wrap_nearest_mirror_clamp_to_border(float s, unsigned size, int offset, int *icoord) 254 { 255 /* u limited to [-0.5, size-0.5] */ 256 const float min = -0.5F; 257 const float max = (float)size + 0.5F; 258 const float u = fabsf(s * size + offset); 259 260 if (u < min) 261 *icoord = -1; 262 else if (u > max) 263 *icoord = size; 264 else 265 *icoord = util_ifloor(u); 266 } 267 268 269 /** 270 * Used to compute texel locations for linear sampling 271 * \param wrapMode PIPE_TEX_WRAP_x 272 * \param s the texcoord 273 * \param size the texture image size 274 * \param icoord0 returns first texture index 275 * \param icoord1 returns second texture index (usually icoord0 + 1) 276 * \param w returns blend factor/weight between texture indices 277 * \param icoord returns the computed integer texture coord 278 */ 279 static void 280 wrap_linear_repeat(float s, unsigned size, int offset, 281 int *icoord0, int *icoord1, float *w) 282 { 283 const float u = s * size - 0.5F; 284 *icoord0 = repeat(util_ifloor(u) + offset, size); 285 *icoord1 = repeat(*icoord0 + 1, size); 286 *w = frac(u); 287 } 288 289 290 static void 291 wrap_linear_clamp(float s, unsigned size, int offset, 292 int *icoord0, int *icoord1, float *w) 293 { 294 const float u = CLAMP(s * size + offset, 0.0F, (float)size) - 0.5f; 295 296 *icoord0 = util_ifloor(u); 297 *icoord1 = *icoord0 + 1; 298 *w = frac(u); 299 } 300 301 302 static void 303 wrap_linear_clamp_to_edge(float s, unsigned size, int offset, 304 int *icoord0, int *icoord1, float *w) 305 { 306 const float u = CLAMP(s * size + offset, 0.0F, (float)size) - 0.5f; 307 *icoord0 = util_ifloor(u); 308 *icoord1 = *icoord0 + 1; 309 if (*icoord0 < 0) 310 *icoord0 = 0; 311 if (*icoord1 >= (int) size) 312 *icoord1 = size - 1; 313 *w = frac(u); 314 } 315 316 317 static void 318 wrap_linear_clamp_to_border(float s, unsigned size, int offset, 319 int *icoord0, int *icoord1, float *w) 320 { 321 const float min = -0.5F; 322 const float max = (float)size + 0.5F; 323 const float u = CLAMP(s * size + offset, min, max) - 0.5f; 324 *icoord0 = util_ifloor(u); 325 *icoord1 = *icoord0 + 1; 326 *w = frac(u); 327 } 328 329 330 static void 331 wrap_linear_mirror_repeat(float s, unsigned size, int offset, 332 int *icoord0, int *icoord1, float *w) 333 { 334 int flr; 335 float u; 336 337 s += (float)offset / size; 338 flr = util_ifloor(s); 339 u = frac(s); 340 if (flr & 1) 341 u = 1.0F - u; 342 u = u * size - 0.5F; 343 *icoord0 = util_ifloor(u); 344 *icoord1 = *icoord0 + 1; 345 if (*icoord0 < 0) 346 *icoord0 = 0; 347 if (*icoord1 >= (int) size) 348 *icoord1 = size - 1; 349 *w = frac(u); 350 } 351 352 353 static void 354 wrap_linear_mirror_clamp(float s, unsigned size, int offset, 355 int *icoord0, int *icoord1, float *w) 356 { 357 float u = fabsf(s * size + offset); 358 if (u >= size) 359 u = (float) size; 360 u -= 0.5F; 361 *icoord0 = util_ifloor(u); 362 *icoord1 = *icoord0 + 1; 363 *w = frac(u); 364 } 365 366 367 static void 368 wrap_linear_mirror_clamp_to_edge(float s, unsigned size, int offset, 369 int *icoord0, int *icoord1, float *w) 370 { 371 float u = fabsf(s * size + offset); 372 if (u >= size) 373 u = (float) size; 374 u -= 0.5F; 375 *icoord0 = util_ifloor(u); 376 *icoord1 = *icoord0 + 1; 377 if (*icoord0 < 0) 378 *icoord0 = 0; 379 if (*icoord1 >= (int) size) 380 *icoord1 = size - 1; 381 *w = frac(u); 382 } 383 384 385 static void 386 wrap_linear_mirror_clamp_to_border(float s, unsigned size, int offset, 387 int *icoord0, int *icoord1, float *w) 388 { 389 const float min = -0.5F; 390 const float max = size + 0.5F; 391 const float t = fabsf(s * size + offset); 392 const float u = CLAMP(t, min, max) - 0.5F; 393 *icoord0 = util_ifloor(u); 394 *icoord1 = *icoord0 + 1; 395 *w = frac(u); 396 } 397 398 399 /** 400 * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords. 401 */ 402 static void 403 wrap_nearest_unorm_clamp(float s, unsigned size, int offset, int *icoord) 404 { 405 const int i = util_ifloor(s); 406 *icoord = CLAMP(i + offset, 0, (int) size-1); 407 } 408 409 410 /** 411 * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords. 412 */ 413 static void 414 wrap_nearest_unorm_clamp_to_border(float s, unsigned size, int offset, int *icoord) 415 { 416 *icoord = util_ifloor( CLAMP(s + offset, -0.5F, (float) size + 0.5F) ); 417 } 418 419 420 /** 421 * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords. 422 */ 423 static void 424 wrap_nearest_unorm_clamp_to_edge(float s, unsigned size, int offset, int *icoord) 425 { 426 *icoord = util_ifloor( CLAMP(s + offset, 0.5F, (float) size - 0.5F) ); 427 } 428 429 430 /** 431 * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords. 432 */ 433 static void 434 wrap_linear_unorm_clamp(float s, unsigned size, int offset, 435 int *icoord0, int *icoord1, float *w) 436 { 437 /* Not exactly what the spec says, but it matches NVIDIA output */ 438 const float u = CLAMP(s + offset - 0.5F, 0.0f, (float) size - 1.0f); 439 *icoord0 = util_ifloor(u); 440 *icoord1 = *icoord0 + 1; 441 *w = frac(u); 442 } 443 444 445 /** 446 * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords. 447 */ 448 static void 449 wrap_linear_unorm_clamp_to_border(float s, unsigned size, int offset, 450 int *icoord0, int *icoord1, float *w) 451 { 452 const float u = CLAMP(s + offset, -0.5F, (float) size + 0.5F) - 0.5F; 453 *icoord0 = util_ifloor(u); 454 *icoord1 = *icoord0 + 1; 455 if (*icoord1 > (int) size - 1) 456 *icoord1 = size - 1; 457 *w = frac(u); 458 } 459 460 461 /** 462 * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords. 463 */ 464 static void 465 wrap_linear_unorm_clamp_to_edge(float s, unsigned size, int offset, 466 int *icoord0, int *icoord1, float *w) 467 { 468 const float u = CLAMP(s + offset, +0.5F, (float) size - 0.5F) - 0.5F; 469 *icoord0 = util_ifloor(u); 470 *icoord1 = *icoord0 + 1; 471 if (*icoord1 > (int) size - 1) 472 *icoord1 = size - 1; 473 *w = frac(u); 474 } 475 476 477 /** 478 * Do coordinate to array index conversion. For array textures. 479 */ 480 static inline int 481 coord_to_layer(float coord, unsigned first_layer, unsigned last_layer) 482 { 483 const int c = util_ifloor(coord + 0.5F); 484 return CLAMP(c, (int)first_layer, (int)last_layer); 485 } 486 487 488 /** 489 * Examine the quad's texture coordinates to compute the partial 490 * derivatives w.r.t X and Y, then compute lambda (level of detail). 491 */ 492 static float 493 compute_lambda_1d(const struct sp_sampler_view *sview, 494 const float s[TGSI_QUAD_SIZE], 495 const float t[TGSI_QUAD_SIZE], 496 const float p[TGSI_QUAD_SIZE]) 497 { 498 const struct pipe_resource *texture = sview->base.texture; 499 const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); 500 const float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); 501 const float rho = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); 502 503 return util_fast_log2(rho); 504 } 505 506 507 static float 508 compute_lambda_2d(const struct sp_sampler_view *sview, 509 const float s[TGSI_QUAD_SIZE], 510 const float t[TGSI_QUAD_SIZE], 511 const float p[TGSI_QUAD_SIZE]) 512 { 513 const struct pipe_resource *texture = sview->base.texture; 514 const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); 515 const float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); 516 const float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); 517 const float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); 518 const float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); 519 const float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level); 520 const float rho = MAX2(maxx, maxy); 521 522 return util_fast_log2(rho); 523 } 524 525 526 static float 527 compute_lambda_3d(const struct sp_sampler_view *sview, 528 const float s[TGSI_QUAD_SIZE], 529 const float t[TGSI_QUAD_SIZE], 530 const float p[TGSI_QUAD_SIZE]) 531 { 532 const struct pipe_resource *texture = sview->base.texture; 533 const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); 534 const float dsdy = fabsf(s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]); 535 const float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]); 536 const float dtdy = fabsf(t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]); 537 const float dpdx = fabsf(p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]); 538 const float dpdy = fabsf(p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT]); 539 const float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level); 540 const float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level); 541 const float maxz = MAX2(dpdx, dpdy) * u_minify(texture->depth0, sview->base.u.tex.first_level); 542 const float rho = MAX3(maxx, maxy, maxz); 543 544 return util_fast_log2(rho); 545 } 546 547 548 /** 549 * Compute lambda for a vertex texture sampler. 550 * Since there aren't derivatives to use, just return 0. 551 */ 552 static float 553 compute_lambda_vert(const struct sp_sampler_view *sview, 554 const float s[TGSI_QUAD_SIZE], 555 const float t[TGSI_QUAD_SIZE], 556 const float p[TGSI_QUAD_SIZE]) 557 { 558 return 0.0f; 559 } 560 561 562 563 /** 564 * Get a texel from a texture, using the texture tile cache. 565 * 566 * \param addr the template tex address containing cube, z, face info. 567 * \param x the x coord of texel within 2D image 568 * \param y the y coord of texel within 2D image 569 * \param rgba the quad to put the texel/color into 570 * 571 * XXX maybe move this into sp_tex_tile_cache.c and merge with the 572 * sp_get_cached_tile_tex() function. 573 */ 574 575 576 577 578 static inline const float * 579 get_texel_2d_no_border(const struct sp_sampler_view *sp_sview, 580 union tex_tile_address addr, int x, int y) 581 { 582 const struct softpipe_tex_cached_tile *tile; 583 addr.bits.x = x / TEX_TILE_SIZE; 584 addr.bits.y = y / TEX_TILE_SIZE; 585 y %= TEX_TILE_SIZE; 586 x %= TEX_TILE_SIZE; 587 588 tile = sp_get_cached_tile_tex(sp_sview->cache, addr); 589 590 return &tile->data.color[y][x][0]; 591 } 592 593 594 static inline const float * 595 get_texel_2d(const struct sp_sampler_view *sp_sview, 596 const struct sp_sampler *sp_samp, 597 union tex_tile_address addr, int x, int y) 598 { 599 const struct pipe_resource *texture = sp_sview->base.texture; 600 const unsigned level = addr.bits.level; 601 602 if (x < 0 || x >= (int) u_minify(texture->width0, level) || 603 y < 0 || y >= (int) u_minify(texture->height0, level)) { 604 return sp_samp->base.border_color.f; 605 } 606 else { 607 return get_texel_2d_no_border( sp_sview, addr, x, y ); 608 } 609 } 610 611 612 /* 613 * Here's the complete logic (HOLY CRAP) for finding next face and doing the 614 * corresponding coord wrapping, implemented by get_next_face, 615 * get_next_xcoord, get_next_ycoord. 616 * Read like that (first line): 617 * If face is +x and s coord is below zero, then 618 * new face is +z, new s is max , new t is old t 619 * (max is always cube size - 1). 620 * 621 * +x s- -> +z: s = max, t = t 622 * +x s+ -> -z: s = 0, t = t 623 * +x t- -> +y: s = max, t = max-s 624 * +x t+ -> -y: s = max, t = s 625 * 626 * -x s- -> -z: s = max, t = t 627 * -x s+ -> +z: s = 0, t = t 628 * -x t- -> +y: s = 0, t = s 629 * -x t+ -> -y: s = 0, t = max-s 630 * 631 * +y s- -> -x: s = t, t = 0 632 * +y s+ -> +x: s = max-t, t = 0 633 * +y t- -> -z: s = max-s, t = 0 634 * +y t+ -> +z: s = s, t = 0 635 * 636 * -y s- -> -x: s = max-t, t = max 637 * -y s+ -> +x: s = t, t = max 638 * -y t- -> +z: s = s, t = max 639 * -y t+ -> -z: s = max-s, t = max 640 641 * +z s- -> -x: s = max, t = t 642 * +z s+ -> +x: s = 0, t = t 643 * +z t- -> +y: s = s, t = max 644 * +z t+ -> -y: s = s, t = 0 645 646 * -z s- -> +x: s = max, t = t 647 * -z s+ -> -x: s = 0, t = t 648 * -z t- -> +y: s = max-s, t = 0 649 * -z t+ -> -y: s = max-s, t = max 650 */ 651 652 653 /* 654 * seamless cubemap neighbour array. 655 * this array is used to find the adjacent face in each of 4 directions, 656 * left, right, up, down. (or -x, +x, -y, +y). 657 */ 658 static const unsigned face_array[PIPE_TEX_FACE_MAX][4] = { 659 /* pos X first then neg X is Z different, Y the same */ 660 /* PIPE_TEX_FACE_POS_X,*/ 661 { PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z, 662 PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y }, 663 /* PIPE_TEX_FACE_NEG_X */ 664 { PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z, 665 PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y }, 666 667 /* pos Y first then neg Y is X different, X the same */ 668 /* PIPE_TEX_FACE_POS_Y */ 669 { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, 670 PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z }, 671 672 /* PIPE_TEX_FACE_NEG_Y */ 673 { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, 674 PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z }, 675 676 /* pos Z first then neg Y is X different, X the same */ 677 /* PIPE_TEX_FACE_POS_Z */ 678 { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, 679 PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y }, 680 681 /* PIPE_TEX_FACE_NEG_Z */ 682 { PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X, 683 PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y } 684 }; 685 686 static inline unsigned 687 get_next_face(unsigned face, int idx) 688 { 689 return face_array[face][idx]; 690 } 691 692 /* 693 * return a new xcoord based on old face, old coords, cube size 694 * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+) 695 */ 696 static inline int 697 get_next_xcoord(unsigned face, unsigned fall_off_index, int max, int xc, int yc) 698 { 699 if ((face == 0 && fall_off_index != 1) || 700 (face == 1 && fall_off_index == 0) || 701 (face == 4 && fall_off_index == 0) || 702 (face == 5 && fall_off_index == 0)) { 703 return max; 704 } 705 if ((face == 1 && fall_off_index != 0) || 706 (face == 0 && fall_off_index == 1) || 707 (face == 4 && fall_off_index == 1) || 708 (face == 5 && fall_off_index == 1)) { 709 return 0; 710 } 711 if ((face == 4 && fall_off_index >= 2) || 712 (face == 2 && fall_off_index == 3) || 713 (face == 3 && fall_off_index == 2)) { 714 return xc; 715 } 716 if ((face == 5 && fall_off_index >= 2) || 717 (face == 2 && fall_off_index == 2) || 718 (face == 3 && fall_off_index == 3)) { 719 return max - xc; 720 } 721 if ((face == 2 && fall_off_index == 0) || 722 (face == 3 && fall_off_index == 1)) { 723 return yc; 724 } 725 /* (face == 2 && fall_off_index == 1) || 726 (face == 3 && fall_off_index == 0)) */ 727 return max - yc; 728 } 729 730 /* 731 * return a new ycoord based on old face, old coords, cube size 732 * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+) 733 */ 734 static inline int 735 get_next_ycoord(unsigned face, unsigned fall_off_index, int max, int xc, int yc) 736 { 737 if ((fall_off_index <= 1) && (face <= 1 || face >= 4)) { 738 return yc; 739 } 740 if (face == 2 || 741 (face == 4 && fall_off_index == 3) || 742 (face == 5 && fall_off_index == 2)) { 743 return 0; 744 } 745 if (face == 3 || 746 (face == 4 && fall_off_index == 2) || 747 (face == 5 && fall_off_index == 3)) { 748 return max; 749 } 750 if ((face == 0 && fall_off_index == 3) || 751 (face == 1 && fall_off_index == 2)) { 752 return xc; 753 } 754 /* (face == 0 && fall_off_index == 2) || 755 (face == 1 && fall_off_index == 3) */ 756 return max - xc; 757 } 758 759 760 /* Gather a quad of adjacent texels within a tile: 761 */ 762 static inline void 763 get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_view *sp_sview, 764 union tex_tile_address addr, 765 unsigned x, unsigned y, 766 const float *out[4]) 767 { 768 const struct softpipe_tex_cached_tile *tile; 769 770 addr.bits.x = x / TEX_TILE_SIZE; 771 addr.bits.y = y / TEX_TILE_SIZE; 772 y %= TEX_TILE_SIZE; 773 x %= TEX_TILE_SIZE; 774 775 tile = sp_get_cached_tile_tex(sp_sview->cache, addr); 776 777 out[0] = &tile->data.color[y ][x ][0]; 778 out[1] = &tile->data.color[y ][x+1][0]; 779 out[2] = &tile->data.color[y+1][x ][0]; 780 out[3] = &tile->data.color[y+1][x+1][0]; 781 } 782 783 784 /* Gather a quad of potentially non-adjacent texels: 785 */ 786 static inline void 787 get_texel_quad_2d_no_border(const struct sp_sampler_view *sp_sview, 788 union tex_tile_address addr, 789 int x0, int y0, 790 int x1, int y1, 791 const float *out[4]) 792 { 793 out[0] = get_texel_2d_no_border( sp_sview, addr, x0, y0 ); 794 out[1] = get_texel_2d_no_border( sp_sview, addr, x1, y0 ); 795 out[2] = get_texel_2d_no_border( sp_sview, addr, x0, y1 ); 796 out[3] = get_texel_2d_no_border( sp_sview, addr, x1, y1 ); 797 } 798 799 /* Can involve a lot of unnecessary checks for border color: 800 */ 801 static inline void 802 get_texel_quad_2d(const struct sp_sampler_view *sp_sview, 803 const struct sp_sampler *sp_samp, 804 union tex_tile_address addr, 805 int x0, int y0, 806 int x1, int y1, 807 const float *out[4]) 808 { 809 out[0] = get_texel_2d( sp_sview, sp_samp, addr, x0, y0 ); 810 out[1] = get_texel_2d( sp_sview, sp_samp, addr, x1, y0 ); 811 out[3] = get_texel_2d( sp_sview, sp_samp, addr, x1, y1 ); 812 out[2] = get_texel_2d( sp_sview, sp_samp, addr, x0, y1 ); 813 } 814 815 816 817 /* 3d variants: 818 */ 819 static inline const float * 820 get_texel_3d_no_border(const struct sp_sampler_view *sp_sview, 821 union tex_tile_address addr, int x, int y, int z) 822 { 823 const struct softpipe_tex_cached_tile *tile; 824 825 addr.bits.x = x / TEX_TILE_SIZE; 826 addr.bits.y = y / TEX_TILE_SIZE; 827 addr.bits.z = z; 828 y %= TEX_TILE_SIZE; 829 x %= TEX_TILE_SIZE; 830 831 tile = sp_get_cached_tile_tex(sp_sview->cache, addr); 832 833 return &tile->data.color[y][x][0]; 834 } 835 836 837 static inline const float * 838 get_texel_3d(const struct sp_sampler_view *sp_sview, 839 const struct sp_sampler *sp_samp, 840 union tex_tile_address addr, int x, int y, int z) 841 { 842 const struct pipe_resource *texture = sp_sview->base.texture; 843 const unsigned level = addr.bits.level; 844 845 if (x < 0 || x >= (int) u_minify(texture->width0, level) || 846 y < 0 || y >= (int) u_minify(texture->height0, level) || 847 z < 0 || z >= (int) u_minify(texture->depth0, level)) { 848 return sp_samp->base.border_color.f; 849 } 850 else { 851 return get_texel_3d_no_border( sp_sview, addr, x, y, z ); 852 } 853 } 854 855 856 /* Get texel pointer for 1D array texture */ 857 static inline const float * 858 get_texel_1d_array(const struct sp_sampler_view *sp_sview, 859 const struct sp_sampler *sp_samp, 860 union tex_tile_address addr, int x, int y) 861 { 862 const struct pipe_resource *texture = sp_sview->base.texture; 863 const unsigned level = addr.bits.level; 864 865 if (x < 0 || x >= (int) u_minify(texture->width0, level)) { 866 return sp_samp->base.border_color.f; 867 } 868 else { 869 return get_texel_2d_no_border(sp_sview, addr, x, y); 870 } 871 } 872 873 874 /* Get texel pointer for 2D array texture */ 875 static inline const float * 876 get_texel_2d_array(const struct sp_sampler_view *sp_sview, 877 const struct sp_sampler *sp_samp, 878 union tex_tile_address addr, int x, int y, int layer) 879 { 880 const struct pipe_resource *texture = sp_sview->base.texture; 881 const unsigned level = addr.bits.level; 882 883 assert(layer < (int) texture->array_size); 884 assert(layer >= 0); 885 886 if (x < 0 || x >= (int) u_minify(texture->width0, level) || 887 y < 0 || y >= (int) u_minify(texture->height0, level)) { 888 return sp_samp->base.border_color.f; 889 } 890 else { 891 return get_texel_3d_no_border(sp_sview, addr, x, y, layer); 892 } 893 } 894 895 896 static inline const float * 897 get_texel_cube_seamless(const struct sp_sampler_view *sp_sview, 898 union tex_tile_address addr, int x, int y, 899 float *corner, int layer, unsigned face) 900 { 901 const struct pipe_resource *texture = sp_sview->base.texture; 902 const unsigned level = addr.bits.level; 903 int new_x, new_y, max_x; 904 905 max_x = (int) u_minify(texture->width0, level); 906 907 assert(texture->width0 == texture->height0); 908 new_x = x; 909 new_y = y; 910 911 /* change the face */ 912 if (x < 0) { 913 /* 914 * Cheat with corners. They are difficult and I believe because we don't get 915 * per-pixel faces we can actually have multiple corner texels per pixel, 916 * which screws things up majorly in any case (as the per spec behavior is 917 * to average the 3 remaining texels, which we might not have). 918 * Hence just make sure that the 2nd coord is clamped, will simply pick the 919 * sample which would have fallen off the x coord, but not y coord. 920 * So the filter weight of the samples will be wrong, but at least this 921 * ensures that only valid texels near the corner are used. 922 */ 923 if (y < 0 || y >= max_x) { 924 y = CLAMP(y, 0, max_x - 1); 925 } 926 new_x = get_next_xcoord(face, 0, max_x -1, x, y); 927 new_y = get_next_ycoord(face, 0, max_x -1, x, y); 928 face = get_next_face(face, 0); 929 } else if (x >= max_x) { 930 if (y < 0 || y >= max_x) { 931 y = CLAMP(y, 0, max_x - 1); 932 } 933 new_x = get_next_xcoord(face, 1, max_x -1, x, y); 934 new_y = get_next_ycoord(face, 1, max_x -1, x, y); 935 face = get_next_face(face, 1); 936 } else if (y < 0) { 937 new_x = get_next_xcoord(face, 2, max_x -1, x, y); 938 new_y = get_next_ycoord(face, 2, max_x -1, x, y); 939 face = get_next_face(face, 2); 940 } else if (y >= max_x) { 941 new_x = get_next_xcoord(face, 3, max_x -1, x, y); 942 new_y = get_next_ycoord(face, 3, max_x -1, x, y); 943 face = get_next_face(face, 3); 944 } 945 946 return get_texel_3d_no_border(sp_sview, addr, new_x, new_y, layer + face); 947 } 948 949 950 /* Get texel pointer for cube array texture */ 951 static inline const float * 952 get_texel_cube_array(const struct sp_sampler_view *sp_sview, 953 const struct sp_sampler *sp_samp, 954 union tex_tile_address addr, int x, int y, int layer) 955 { 956 const struct pipe_resource *texture = sp_sview->base.texture; 957 const unsigned level = addr.bits.level; 958 959 assert(layer < (int) texture->array_size); 960 assert(layer >= 0); 961 962 if (x < 0 || x >= (int) u_minify(texture->width0, level) || 963 y < 0 || y >= (int) u_minify(texture->height0, level)) { 964 return sp_samp->base.border_color.f; 965 } 966 else { 967 return get_texel_3d_no_border(sp_sview, addr, x, y, layer); 968 } 969 } 970 /** 971 * Given the logbase2 of a mipmap's base level size and a mipmap level, 972 * return the size (in texels) of that mipmap level. 973 * For example, if level[0].width = 256 then base_pot will be 8. 974 * If level = 2, then we'll return 64 (the width at level=2). 975 * Return 1 if level > base_pot. 976 */ 977 static inline unsigned 978 pot_level_size(unsigned base_pot, unsigned level) 979 { 980 return (base_pot >= level) ? (1 << (base_pot - level)) : 1; 981 } 982 983 984 static void 985 print_sample(const char *function, const float *rgba) 986 { 987 debug_printf("%s %g %g %g %g\n", 988 function, 989 rgba[0], rgba[TGSI_NUM_CHANNELS], rgba[2*TGSI_NUM_CHANNELS], rgba[3*TGSI_NUM_CHANNELS]); 990 } 991 992 993 static void 994 print_sample_4(const char *function, float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 995 { 996 debug_printf("%s %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n", 997 function, 998 rgba[0][0], rgba[1][0], rgba[2][0], rgba[3][0], 999 rgba[0][1], rgba[1][1], rgba[2][1], rgba[3][1], 1000 rgba[0][2], rgba[1][2], rgba[2][2], rgba[3][2], 1001 rgba[0][3], rgba[1][3], rgba[2][3], rgba[3][3]); 1002 } 1003 1004 1005 /* Some image-filter fastpaths: 1006 */ 1007 static inline void 1008 img_filter_2d_linear_repeat_POT(const struct sp_sampler_view *sp_sview, 1009 const struct sp_sampler *sp_samp, 1010 const struct img_filter_args *args, 1011 float *rgba) 1012 { 1013 const unsigned xpot = pot_level_size(sp_sview->xpot, args->level); 1014 const unsigned ypot = pot_level_size(sp_sview->ypot, args->level); 1015 const int xmax = (xpot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, xpot) - 1; */ 1016 const int ymax = (ypot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, ypot) - 1; */ 1017 union tex_tile_address addr; 1018 int c; 1019 1020 const float u = (args->s * xpot - 0.5F) + args->offset[0]; 1021 const float v = (args->t * ypot - 0.5F) + args->offset[1]; 1022 1023 const int uflr = util_ifloor(u); 1024 const int vflr = util_ifloor(v); 1025 1026 const float xw = u - (float)uflr; 1027 const float yw = v - (float)vflr; 1028 1029 const int x0 = uflr & (xpot - 1); 1030 const int y0 = vflr & (ypot - 1); 1031 1032 const float *tx[4]; 1033 1034 addr.value = 0; 1035 addr.bits.level = args->level; 1036 addr.bits.z = sp_sview->base.u.tex.first_layer; 1037 1038 /* Can we fetch all four at once: 1039 */ 1040 if (x0 < xmax && y0 < ymax) { 1041 get_texel_quad_2d_no_border_single_tile(sp_sview, addr, x0, y0, tx); 1042 } 1043 else { 1044 const unsigned x1 = (x0 + 1) & (xpot - 1); 1045 const unsigned y1 = (y0 + 1) & (ypot - 1); 1046 get_texel_quad_2d_no_border(sp_sview, addr, x0, y0, x1, y1, tx); 1047 } 1048 1049 /* interpolate R, G, B, A */ 1050 for (c = 0; c < TGSI_NUM_CHANNELS; c++) { 1051 rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, 1052 tx[0][c], tx[1][c], 1053 tx[2][c], tx[3][c]); 1054 } 1055 1056 if (DEBUG_TEX) { 1057 print_sample(__FUNCTION__, rgba); 1058 } 1059 } 1060 1061 1062 static inline void 1063 img_filter_2d_nearest_repeat_POT(const struct sp_sampler_view *sp_sview, 1064 const struct sp_sampler *sp_samp, 1065 const struct img_filter_args *args, 1066 float *rgba) 1067 { 1068 const unsigned xpot = pot_level_size(sp_sview->xpot, args->level); 1069 const unsigned ypot = pot_level_size(sp_sview->ypot, args->level); 1070 const float *out; 1071 union tex_tile_address addr; 1072 int c; 1073 1074 const float u = args->s * xpot + args->offset[0]; 1075 const float v = args->t * ypot + args->offset[1]; 1076 1077 const int uflr = util_ifloor(u); 1078 const int vflr = util_ifloor(v); 1079 1080 const int x0 = uflr & (xpot - 1); 1081 const int y0 = vflr & (ypot - 1); 1082 1083 addr.value = 0; 1084 addr.bits.level = args->level; 1085 addr.bits.z = sp_sview->base.u.tex.first_layer; 1086 1087 out = get_texel_2d_no_border(sp_sview, addr, x0, y0); 1088 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1089 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1090 1091 if (DEBUG_TEX) { 1092 print_sample(__FUNCTION__, rgba); 1093 } 1094 } 1095 1096 1097 static inline void 1098 img_filter_2d_nearest_clamp_POT(const struct sp_sampler_view *sp_sview, 1099 const struct sp_sampler *sp_samp, 1100 const struct img_filter_args *args, 1101 float *rgba) 1102 { 1103 const unsigned xpot = pot_level_size(sp_sview->xpot, args->level); 1104 const unsigned ypot = pot_level_size(sp_sview->ypot, args->level); 1105 union tex_tile_address addr; 1106 int c; 1107 1108 const float u = args->s * xpot + args->offset[0]; 1109 const float v = args->t * ypot + args->offset[1]; 1110 1111 int x0, y0; 1112 const float *out; 1113 1114 addr.value = 0; 1115 addr.bits.level = args->level; 1116 addr.bits.z = sp_sview->base.u.tex.first_layer; 1117 1118 x0 = util_ifloor(u); 1119 if (x0 < 0) 1120 x0 = 0; 1121 else if (x0 > (int) xpot - 1) 1122 x0 = xpot - 1; 1123 1124 y0 = util_ifloor(v); 1125 if (y0 < 0) 1126 y0 = 0; 1127 else if (y0 > (int) ypot - 1) 1128 y0 = ypot - 1; 1129 1130 out = get_texel_2d_no_border(sp_sview, addr, x0, y0); 1131 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1132 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1133 1134 if (DEBUG_TEX) { 1135 print_sample(__FUNCTION__, rgba); 1136 } 1137 } 1138 1139 1140 static void 1141 img_filter_1d_nearest(const struct sp_sampler_view *sp_sview, 1142 const struct sp_sampler *sp_samp, 1143 const struct img_filter_args *args, 1144 float *rgba) 1145 { 1146 const struct pipe_resource *texture = sp_sview->base.texture; 1147 const int width = u_minify(texture->width0, args->level); 1148 int x; 1149 union tex_tile_address addr; 1150 const float *out; 1151 int c; 1152 1153 assert(width > 0); 1154 1155 addr.value = 0; 1156 addr.bits.level = args->level; 1157 1158 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1159 1160 out = get_texel_1d_array(sp_sview, sp_samp, addr, x, 1161 sp_sview->base.u.tex.first_layer); 1162 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1163 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1164 1165 if (DEBUG_TEX) { 1166 print_sample(__FUNCTION__, rgba); 1167 } 1168 } 1169 1170 1171 static void 1172 img_filter_1d_array_nearest(const struct sp_sampler_view *sp_sview, 1173 const struct sp_sampler *sp_samp, 1174 const struct img_filter_args *args, 1175 float *rgba) 1176 { 1177 const struct pipe_resource *texture = sp_sview->base.texture; 1178 const int width = u_minify(texture->width0, args->level); 1179 const int layer = coord_to_layer(args->t, sp_sview->base.u.tex.first_layer, 1180 sp_sview->base.u.tex.last_layer); 1181 int x; 1182 union tex_tile_address addr; 1183 const float *out; 1184 int c; 1185 1186 assert(width > 0); 1187 1188 addr.value = 0; 1189 addr.bits.level = args->level; 1190 1191 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1192 1193 out = get_texel_1d_array(sp_sview, sp_samp, addr, x, layer); 1194 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1195 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1196 1197 if (DEBUG_TEX) { 1198 print_sample(__FUNCTION__, rgba); 1199 } 1200 } 1201 1202 1203 static void 1204 img_filter_2d_nearest(const struct sp_sampler_view *sp_sview, 1205 const struct sp_sampler *sp_samp, 1206 const struct img_filter_args *args, 1207 float *rgba) 1208 { 1209 const struct pipe_resource *texture = sp_sview->base.texture; 1210 const int width = u_minify(texture->width0, args->level); 1211 const int height = u_minify(texture->height0, args->level); 1212 int x, y; 1213 union tex_tile_address addr; 1214 const float *out; 1215 int c; 1216 1217 assert(width > 0); 1218 assert(height > 0); 1219 1220 addr.value = 0; 1221 addr.bits.level = args->level; 1222 addr.bits.z = sp_sview->base.u.tex.first_layer; 1223 1224 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1225 sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y); 1226 1227 out = get_texel_2d(sp_sview, sp_samp, addr, x, y); 1228 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1229 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1230 1231 if (DEBUG_TEX) { 1232 print_sample(__FUNCTION__, rgba); 1233 } 1234 } 1235 1236 1237 static void 1238 img_filter_2d_array_nearest(const struct sp_sampler_view *sp_sview, 1239 const struct sp_sampler *sp_samp, 1240 const struct img_filter_args *args, 1241 float *rgba) 1242 { 1243 const struct pipe_resource *texture = sp_sview->base.texture; 1244 const int width = u_minify(texture->width0, args->level); 1245 const int height = u_minify(texture->height0, args->level); 1246 const int layer = coord_to_layer(args->p, sp_sview->base.u.tex.first_layer, 1247 sp_sview->base.u.tex.last_layer); 1248 int x, y; 1249 union tex_tile_address addr; 1250 const float *out; 1251 int c; 1252 1253 assert(width > 0); 1254 assert(height > 0); 1255 1256 addr.value = 0; 1257 addr.bits.level = args->level; 1258 1259 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1260 sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y); 1261 1262 out = get_texel_2d_array(sp_sview, sp_samp, addr, x, y, layer); 1263 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1264 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1265 1266 if (DEBUG_TEX) { 1267 print_sample(__FUNCTION__, rgba); 1268 } 1269 } 1270 1271 1272 static void 1273 img_filter_cube_nearest(const struct sp_sampler_view *sp_sview, 1274 const struct sp_sampler *sp_samp, 1275 const struct img_filter_args *args, 1276 float *rgba) 1277 { 1278 const struct pipe_resource *texture = sp_sview->base.texture; 1279 const int width = u_minify(texture->width0, args->level); 1280 const int height = u_minify(texture->height0, args->level); 1281 const int layerface = args->face_id + sp_sview->base.u.tex.first_layer; 1282 int x, y; 1283 union tex_tile_address addr; 1284 const float *out; 1285 int c; 1286 1287 assert(width > 0); 1288 assert(height > 0); 1289 1290 addr.value = 0; 1291 addr.bits.level = args->level; 1292 1293 /* 1294 * If NEAREST filtering is done within a miplevel, always apply wrap 1295 * mode CLAMP_TO_EDGE. 1296 */ 1297 if (sp_samp->base.seamless_cube_map) { 1298 wrap_nearest_clamp_to_edge(args->s, width, args->offset[0], &x); 1299 wrap_nearest_clamp_to_edge(args->t, height, args->offset[1], &y); 1300 } else { 1301 /* Would probably make sense to ignore mode and just do edge clamp */ 1302 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1303 sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y); 1304 } 1305 1306 out = get_texel_cube_array(sp_sview, sp_samp, addr, x, y, layerface); 1307 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1308 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1309 1310 if (DEBUG_TEX) { 1311 print_sample(__FUNCTION__, rgba); 1312 } 1313 } 1314 1315 static void 1316 img_filter_cube_array_nearest(const struct sp_sampler_view *sp_sview, 1317 const struct sp_sampler *sp_samp, 1318 const struct img_filter_args *args, 1319 float *rgba) 1320 { 1321 const struct pipe_resource *texture = sp_sview->base.texture; 1322 const int width = u_minify(texture->width0, args->level); 1323 const int height = u_minify(texture->height0, args->level); 1324 const int layerface = 1325 coord_to_layer(6 * args->p + sp_sview->base.u.tex.first_layer, 1326 sp_sview->base.u.tex.first_layer, 1327 sp_sview->base.u.tex.last_layer - 5) + args->face_id; 1328 int x, y; 1329 union tex_tile_address addr; 1330 const float *out; 1331 int c; 1332 1333 assert(width > 0); 1334 assert(height > 0); 1335 1336 addr.value = 0; 1337 addr.bits.level = args->level; 1338 1339 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1340 sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y); 1341 1342 out = get_texel_cube_array(sp_sview, sp_samp, addr, x, y, layerface); 1343 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1344 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1345 1346 if (DEBUG_TEX) { 1347 print_sample(__FUNCTION__, rgba); 1348 } 1349 } 1350 1351 static void 1352 img_filter_3d_nearest(const struct sp_sampler_view *sp_sview, 1353 const struct sp_sampler *sp_samp, 1354 const struct img_filter_args *args, 1355 float *rgba) 1356 { 1357 const struct pipe_resource *texture = sp_sview->base.texture; 1358 const int width = u_minify(texture->width0, args->level); 1359 const int height = u_minify(texture->height0, args->level); 1360 const int depth = u_minify(texture->depth0, args->level); 1361 int x, y, z; 1362 union tex_tile_address addr; 1363 const float *out; 1364 int c; 1365 1366 assert(width > 0); 1367 assert(height > 0); 1368 assert(depth > 0); 1369 1370 sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x); 1371 sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y); 1372 sp_samp->nearest_texcoord_p(args->p, depth, args->offset[2], &z); 1373 1374 addr.value = 0; 1375 addr.bits.level = args->level; 1376 1377 out = get_texel_3d(sp_sview, sp_samp, addr, x, y, z); 1378 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1379 rgba[TGSI_NUM_CHANNELS*c] = out[c]; 1380 } 1381 1382 1383 static void 1384 img_filter_1d_linear(const struct sp_sampler_view *sp_sview, 1385 const struct sp_sampler *sp_samp, 1386 const struct img_filter_args *args, 1387 float *rgba) 1388 { 1389 const struct pipe_resource *texture = sp_sview->base.texture; 1390 const int width = u_minify(texture->width0, args->level); 1391 int x0, x1; 1392 float xw; /* weights */ 1393 union tex_tile_address addr; 1394 const float *tx0, *tx1; 1395 int c; 1396 1397 assert(width > 0); 1398 1399 addr.value = 0; 1400 addr.bits.level = args->level; 1401 1402 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1403 1404 tx0 = get_texel_1d_array(sp_sview, sp_samp, addr, x0, 1405 sp_sview->base.u.tex.first_layer); 1406 tx1 = get_texel_1d_array(sp_sview, sp_samp, addr, x1, 1407 sp_sview->base.u.tex.first_layer); 1408 1409 /* interpolate R, G, B, A */ 1410 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1411 rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); 1412 } 1413 1414 1415 static void 1416 img_filter_1d_array_linear(const struct sp_sampler_view *sp_sview, 1417 const struct sp_sampler *sp_samp, 1418 const struct img_filter_args *args, 1419 float *rgba) 1420 { 1421 const struct pipe_resource *texture = sp_sview->base.texture; 1422 const int width = u_minify(texture->width0, args->level); 1423 const int layer = coord_to_layer(args->t, sp_sview->base.u.tex.first_layer, 1424 sp_sview->base.u.tex.last_layer); 1425 int x0, x1; 1426 float xw; /* weights */ 1427 union tex_tile_address addr; 1428 const float *tx0, *tx1; 1429 int c; 1430 1431 assert(width > 0); 1432 1433 addr.value = 0; 1434 addr.bits.level = args->level; 1435 1436 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1437 1438 tx0 = get_texel_1d_array(sp_sview, sp_samp, addr, x0, layer); 1439 tx1 = get_texel_1d_array(sp_sview, sp_samp, addr, x1, layer); 1440 1441 /* interpolate R, G, B, A */ 1442 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1443 rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); 1444 } 1445 1446 /* 1447 * Retrieve the gathered value, need to convert to the 1448 * TGSI expected interface, and take component select 1449 * and swizzling into account. 1450 */ 1451 static float 1452 get_gather_value(const struct sp_sampler_view *sp_sview, 1453 int chan_in, int comp_sel, 1454 const float *tx[4]) 1455 { 1456 int chan; 1457 unsigned swizzle; 1458 1459 /* 1460 * softpipe samples in a different order 1461 * to TGSI expects, so we need to swizzle, 1462 * the samples into the correct slots. 1463 */ 1464 switch (chan_in) { 1465 case 0: 1466 chan = 2; 1467 break; 1468 case 1: 1469 chan = 3; 1470 break; 1471 case 2: 1472 chan = 1; 1473 break; 1474 case 3: 1475 chan = 0; 1476 break; 1477 default: 1478 assert(0); 1479 return 0.0; 1480 } 1481 1482 /* pick which component to use for the swizzle */ 1483 switch (comp_sel) { 1484 case 0: 1485 swizzle = sp_sview->base.swizzle_r; 1486 break; 1487 case 1: 1488 swizzle = sp_sview->base.swizzle_g; 1489 break; 1490 case 2: 1491 swizzle = sp_sview->base.swizzle_b; 1492 break; 1493 case 3: 1494 swizzle = sp_sview->base.swizzle_a; 1495 break; 1496 default: 1497 assert(0); 1498 return 0.0; 1499 } 1500 1501 /* get correct result using the channel and swizzle */ 1502 switch (swizzle) { 1503 case PIPE_SWIZZLE_0: 1504 return 0.0; 1505 case PIPE_SWIZZLE_1: 1506 return 1.0; 1507 default: 1508 return tx[chan][swizzle]; 1509 } 1510 } 1511 1512 1513 static void 1514 img_filter_2d_linear(const struct sp_sampler_view *sp_sview, 1515 const struct sp_sampler *sp_samp, 1516 const struct img_filter_args *args, 1517 float *rgba) 1518 { 1519 const struct pipe_resource *texture = sp_sview->base.texture; 1520 const int width = u_minify(texture->width0, args->level); 1521 const int height = u_minify(texture->height0, args->level); 1522 int x0, y0, x1, y1; 1523 float xw, yw; /* weights */ 1524 union tex_tile_address addr; 1525 const float *tx[4]; 1526 int c; 1527 1528 assert(width > 0); 1529 assert(height > 0); 1530 1531 addr.value = 0; 1532 addr.bits.level = args->level; 1533 addr.bits.z = sp_sview->base.u.tex.first_layer; 1534 1535 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1536 sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw); 1537 1538 tx[0] = get_texel_2d(sp_sview, sp_samp, addr, x0, y0); 1539 tx[1] = get_texel_2d(sp_sview, sp_samp, addr, x1, y0); 1540 tx[2] = get_texel_2d(sp_sview, sp_samp, addr, x0, y1); 1541 tx[3] = get_texel_2d(sp_sview, sp_samp, addr, x1, y1); 1542 1543 if (args->gather_only) { 1544 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1545 rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c, 1546 args->gather_comp, 1547 tx); 1548 } else { 1549 /* interpolate R, G, B, A */ 1550 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1551 rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, 1552 tx[0][c], tx[1][c], 1553 tx[2][c], tx[3][c]); 1554 } 1555 } 1556 1557 1558 static void 1559 img_filter_2d_array_linear(const struct sp_sampler_view *sp_sview, 1560 const struct sp_sampler *sp_samp, 1561 const struct img_filter_args *args, 1562 float *rgba) 1563 { 1564 const struct pipe_resource *texture = sp_sview->base.texture; 1565 const int width = u_minify(texture->width0, args->level); 1566 const int height = u_minify(texture->height0, args->level); 1567 const int layer = coord_to_layer(args->p, sp_sview->base.u.tex.first_layer, 1568 sp_sview->base.u.tex.last_layer); 1569 int x0, y0, x1, y1; 1570 float xw, yw; /* weights */ 1571 union tex_tile_address addr; 1572 const float *tx[4]; 1573 int c; 1574 1575 assert(width > 0); 1576 assert(height > 0); 1577 1578 addr.value = 0; 1579 addr.bits.level = args->level; 1580 1581 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1582 sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw); 1583 1584 tx[0] = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y0, layer); 1585 tx[1] = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y0, layer); 1586 tx[2] = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y1, layer); 1587 tx[3] = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y1, layer); 1588 1589 if (args->gather_only) { 1590 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1591 rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c, 1592 args->gather_comp, 1593 tx); 1594 } else { 1595 /* interpolate R, G, B, A */ 1596 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1597 rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, 1598 tx[0][c], tx[1][c], 1599 tx[2][c], tx[3][c]); 1600 } 1601 } 1602 1603 1604 static void 1605 img_filter_cube_linear(const struct sp_sampler_view *sp_sview, 1606 const struct sp_sampler *sp_samp, 1607 const struct img_filter_args *args, 1608 float *rgba) 1609 { 1610 const struct pipe_resource *texture = sp_sview->base.texture; 1611 const int width = u_minify(texture->width0, args->level); 1612 const int height = u_minify(texture->height0, args->level); 1613 const int layer = sp_sview->base.u.tex.first_layer; 1614 int x0, y0, x1, y1; 1615 float xw, yw; /* weights */ 1616 union tex_tile_address addr; 1617 const float *tx[4]; 1618 float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE], 1619 corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE]; 1620 int c; 1621 1622 assert(width > 0); 1623 assert(height > 0); 1624 1625 addr.value = 0; 1626 addr.bits.level = args->level; 1627 1628 /* 1629 * For seamless if LINEAR filtering is done within a miplevel, 1630 * always apply wrap mode CLAMP_TO_BORDER. 1631 */ 1632 if (sp_samp->base.seamless_cube_map) { 1633 /* Note this is a bit overkill, actual clamping is not required */ 1634 wrap_linear_clamp_to_border(args->s, width, args->offset[0], &x0, &x1, &xw); 1635 wrap_linear_clamp_to_border(args->t, height, args->offset[1], &y0, &y1, &yw); 1636 } else { 1637 /* Would probably make sense to ignore mode and just do edge clamp */ 1638 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1639 sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw); 1640 } 1641 1642 if (sp_samp->base.seamless_cube_map) { 1643 tx[0] = get_texel_cube_seamless(sp_sview, addr, x0, y0, corner0, layer, args->face_id); 1644 tx[1] = get_texel_cube_seamless(sp_sview, addr, x1, y0, corner1, layer, args->face_id); 1645 tx[2] = get_texel_cube_seamless(sp_sview, addr, x0, y1, corner2, layer, args->face_id); 1646 tx[3] = get_texel_cube_seamless(sp_sview, addr, x1, y1, corner3, layer, args->face_id); 1647 } else { 1648 tx[0] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y0, layer + args->face_id); 1649 tx[1] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y0, layer + args->face_id); 1650 tx[2] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y1, layer + args->face_id); 1651 tx[3] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y1, layer + args->face_id); 1652 } 1653 1654 if (args->gather_only) { 1655 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1656 rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c, 1657 args->gather_comp, 1658 tx); 1659 } else { 1660 /* interpolate R, G, B, A */ 1661 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1662 rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, 1663 tx[0][c], tx[1][c], 1664 tx[2][c], tx[3][c]); 1665 } 1666 } 1667 1668 1669 static void 1670 img_filter_cube_array_linear(const struct sp_sampler_view *sp_sview, 1671 const struct sp_sampler *sp_samp, 1672 const struct img_filter_args *args, 1673 float *rgba) 1674 { 1675 const struct pipe_resource *texture = sp_sview->base.texture; 1676 const int width = u_minify(texture->width0, args->level); 1677 const int height = u_minify(texture->height0, args->level); 1678 const int layer = 1679 coord_to_layer(6 * args->p + sp_sview->base.u.tex.first_layer, 1680 sp_sview->base.u.tex.first_layer, 1681 sp_sview->base.u.tex.last_layer - 5); 1682 int x0, y0, x1, y1; 1683 float xw, yw; /* weights */ 1684 union tex_tile_address addr; 1685 const float *tx[4]; 1686 float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE], 1687 corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE]; 1688 int c; 1689 1690 assert(width > 0); 1691 assert(height > 0); 1692 1693 addr.value = 0; 1694 addr.bits.level = args->level; 1695 1696 /* 1697 * For seamless if LINEAR filtering is done within a miplevel, 1698 * always apply wrap mode CLAMP_TO_BORDER. 1699 */ 1700 if (sp_samp->base.seamless_cube_map) { 1701 /* Note this is a bit overkill, actual clamping is not required */ 1702 wrap_linear_clamp_to_border(args->s, width, args->offset[0], &x0, &x1, &xw); 1703 wrap_linear_clamp_to_border(args->t, height, args->offset[1], &y0, &y1, &yw); 1704 } else { 1705 /* Would probably make sense to ignore mode and just do edge clamp */ 1706 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1707 sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw); 1708 } 1709 1710 if (sp_samp->base.seamless_cube_map) { 1711 tx[0] = get_texel_cube_seamless(sp_sview, addr, x0, y0, corner0, layer, args->face_id); 1712 tx[1] = get_texel_cube_seamless(sp_sview, addr, x1, y0, corner1, layer, args->face_id); 1713 tx[2] = get_texel_cube_seamless(sp_sview, addr, x0, y1, corner2, layer, args->face_id); 1714 tx[3] = get_texel_cube_seamless(sp_sview, addr, x1, y1, corner3, layer, args->face_id); 1715 } else { 1716 tx[0] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y0, layer + args->face_id); 1717 tx[1] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y0, layer + args->face_id); 1718 tx[2] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y1, layer + args->face_id); 1719 tx[3] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y1, layer + args->face_id); 1720 } 1721 1722 if (args->gather_only) { 1723 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1724 rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c, 1725 args->gather_comp, 1726 tx); 1727 } else { 1728 /* interpolate R, G, B, A */ 1729 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1730 rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, 1731 tx[0][c], tx[1][c], 1732 tx[2][c], tx[3][c]); 1733 } 1734 } 1735 1736 static void 1737 img_filter_3d_linear(const struct sp_sampler_view *sp_sview, 1738 const struct sp_sampler *sp_samp, 1739 const struct img_filter_args *args, 1740 float *rgba) 1741 { 1742 const struct pipe_resource *texture = sp_sview->base.texture; 1743 const int width = u_minify(texture->width0, args->level); 1744 const int height = u_minify(texture->height0, args->level); 1745 const int depth = u_minify(texture->depth0, args->level); 1746 int x0, x1, y0, y1, z0, z1; 1747 float xw, yw, zw; /* interpolation weights */ 1748 union tex_tile_address addr; 1749 const float *tx00, *tx01, *tx02, *tx03, *tx10, *tx11, *tx12, *tx13; 1750 int c; 1751 1752 addr.value = 0; 1753 addr.bits.level = args->level; 1754 1755 assert(width > 0); 1756 assert(height > 0); 1757 assert(depth > 0); 1758 1759 sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw); 1760 sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw); 1761 sp_samp->linear_texcoord_p(args->p, depth, args->offset[2], &z0, &z1, &zw); 1762 1763 tx00 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z0); 1764 tx01 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z0); 1765 tx02 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z0); 1766 tx03 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z0); 1767 1768 tx10 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z1); 1769 tx11 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z1); 1770 tx12 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z1); 1771 tx13 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z1); 1772 1773 /* interpolate R, G, B, A */ 1774 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 1775 rgba[TGSI_NUM_CHANNELS*c] = lerp_3d(xw, yw, zw, 1776 tx00[c], tx01[c], 1777 tx02[c], tx03[c], 1778 tx10[c], tx11[c], 1779 tx12[c], tx13[c]); 1780 } 1781 1782 1783 /* Calculate level of detail for every fragment, 1784 * with lambda already computed. 1785 * Note that lambda has already been biased by global LOD bias. 1786 * \param biased_lambda per-quad lambda. 1787 * \param lod_in per-fragment lod_bias or explicit_lod. 1788 * \param lod returns the per-fragment lod. 1789 */ 1790 static inline void 1791 compute_lod(const struct pipe_sampler_state *sampler, 1792 enum tgsi_sampler_control control, 1793 const float biased_lambda, 1794 const float lod_in[TGSI_QUAD_SIZE], 1795 float lod[TGSI_QUAD_SIZE]) 1796 { 1797 const float min_lod = sampler->min_lod; 1798 const float max_lod = sampler->max_lod; 1799 uint i; 1800 1801 switch (control) { 1802 case TGSI_SAMPLER_LOD_NONE: 1803 case TGSI_SAMPLER_LOD_ZERO: 1804 /* XXX FIXME */ 1805 case TGSI_SAMPLER_DERIVS_EXPLICIT: 1806 lod[0] = lod[1] = lod[2] = lod[3] = CLAMP(biased_lambda, min_lod, max_lod); 1807 break; 1808 case TGSI_SAMPLER_LOD_BIAS: 1809 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1810 lod[i] = biased_lambda + lod_in[i]; 1811 lod[i] = CLAMP(lod[i], min_lod, max_lod); 1812 } 1813 break; 1814 case TGSI_SAMPLER_LOD_EXPLICIT: 1815 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1816 lod[i] = CLAMP(lod_in[i], min_lod, max_lod); 1817 } 1818 break; 1819 default: 1820 assert(0); 1821 lod[0] = lod[1] = lod[2] = lod[3] = 0.0f; 1822 } 1823 } 1824 1825 1826 /* Calculate level of detail for every fragment. The computed value is not 1827 * clamped to lod_min and lod_max. 1828 * \param lod_in per-fragment lod_bias or explicit_lod. 1829 * \param lod results per-fragment lod. 1830 */ 1831 static inline void 1832 compute_lambda_lod_unclamped(const struct sp_sampler_view *sp_sview, 1833 const struct sp_sampler *sp_samp, 1834 const float s[TGSI_QUAD_SIZE], 1835 const float t[TGSI_QUAD_SIZE], 1836 const float p[TGSI_QUAD_SIZE], 1837 const float lod_in[TGSI_QUAD_SIZE], 1838 enum tgsi_sampler_control control, 1839 float lod[TGSI_QUAD_SIZE]) 1840 { 1841 const struct pipe_sampler_state *sampler = &sp_samp->base; 1842 const float lod_bias = sampler->lod_bias; 1843 float lambda; 1844 uint i; 1845 1846 switch (control) { 1847 case TGSI_SAMPLER_LOD_NONE: 1848 /* XXX FIXME */ 1849 case TGSI_SAMPLER_DERIVS_EXPLICIT: 1850 lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias; 1851 lod[0] = lod[1] = lod[2] = lod[3] = lambda; 1852 break; 1853 case TGSI_SAMPLER_LOD_BIAS: 1854 lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias; 1855 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1856 lod[i] = lambda + lod_in[i]; 1857 } 1858 break; 1859 case TGSI_SAMPLER_LOD_EXPLICIT: 1860 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1861 lod[i] = lod_in[i] + lod_bias; 1862 } 1863 break; 1864 case TGSI_SAMPLER_LOD_ZERO: 1865 case TGSI_SAMPLER_GATHER: 1866 lod[0] = lod[1] = lod[2] = lod[3] = lod_bias; 1867 break; 1868 default: 1869 assert(0); 1870 lod[0] = lod[1] = lod[2] = lod[3] = 0.0f; 1871 } 1872 } 1873 1874 /* Calculate level of detail for every fragment. 1875 * \param lod_in per-fragment lod_bias or explicit_lod. 1876 * \param lod results per-fragment lod. 1877 */ 1878 static inline void 1879 compute_lambda_lod(const struct sp_sampler_view *sp_sview, 1880 const struct sp_sampler *sp_samp, 1881 const float s[TGSI_QUAD_SIZE], 1882 const float t[TGSI_QUAD_SIZE], 1883 const float p[TGSI_QUAD_SIZE], 1884 const float lod_in[TGSI_QUAD_SIZE], 1885 enum tgsi_sampler_control control, 1886 float lod[TGSI_QUAD_SIZE]) 1887 { 1888 const struct pipe_sampler_state *sampler = &sp_samp->base; 1889 const float min_lod = sampler->min_lod; 1890 const float max_lod = sampler->max_lod; 1891 int i; 1892 1893 compute_lambda_lod_unclamped(sp_sview, sp_samp, 1894 s, t, p, lod_in, control, lod); 1895 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1896 lod[i] = CLAMP(lod[i], min_lod, max_lod); 1897 } 1898 } 1899 1900 static inline unsigned 1901 get_gather_component(const float lod_in[TGSI_QUAD_SIZE]) 1902 { 1903 /* gather component is stored in lod_in slot as unsigned */ 1904 return (*(unsigned int *)lod_in) & 0x3; 1905 } 1906 1907 /** 1908 * Clamps given lod to both lod limits and mip level limits. Clamping to the 1909 * latter limits is done so that lod is relative to the first (base) level. 1910 */ 1911 static void 1912 clamp_lod(const struct sp_sampler_view *sp_sview, 1913 const struct sp_sampler *sp_samp, 1914 const float lod[TGSI_QUAD_SIZE], 1915 float clamped[TGSI_QUAD_SIZE]) 1916 { 1917 const float min_lod = sp_samp->base.min_lod; 1918 const float max_lod = sp_samp->base.max_lod; 1919 const float min_level = sp_sview->base.u.tex.first_level; 1920 const float max_level = sp_sview->base.u.tex.last_level; 1921 int i; 1922 1923 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 1924 float cl = lod[i]; 1925 1926 cl = CLAMP(cl, min_lod, max_lod); 1927 cl = CLAMP(cl, 0, max_level - min_level); 1928 clamped[i] = cl; 1929 } 1930 } 1931 1932 /** 1933 * Get mip level relative to base level for linear mip filter 1934 */ 1935 static void 1936 mip_rel_level_linear(const struct sp_sampler_view *sp_sview, 1937 const struct sp_sampler *sp_samp, 1938 const float lod[TGSI_QUAD_SIZE], 1939 float level[TGSI_QUAD_SIZE]) 1940 { 1941 clamp_lod(sp_sview, sp_samp, lod, level); 1942 } 1943 1944 static void 1945 mip_filter_linear(const struct sp_sampler_view *sp_sview, 1946 const struct sp_sampler *sp_samp, 1947 img_filter_func min_filter, 1948 img_filter_func mag_filter, 1949 const float s[TGSI_QUAD_SIZE], 1950 const float t[TGSI_QUAD_SIZE], 1951 const float p[TGSI_QUAD_SIZE], 1952 const float c0[TGSI_QUAD_SIZE], 1953 const float lod_in[TGSI_QUAD_SIZE], 1954 const struct filter_args *filt_args, 1955 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 1956 { 1957 const struct pipe_sampler_view *psview = &sp_sview->base; 1958 int j; 1959 float lod[TGSI_QUAD_SIZE]; 1960 struct img_filter_args args; 1961 1962 compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod); 1963 1964 args.offset = filt_args->offset; 1965 args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER; 1966 args.gather_comp = get_gather_component(lod_in); 1967 1968 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 1969 const int level0 = psview->u.tex.first_level + (int)lod[j]; 1970 1971 args.s = s[j]; 1972 args.t = t[j]; 1973 args.p = p[j]; 1974 args.face_id = filt_args->faces[j]; 1975 1976 if (lod[j] < 0.0) { 1977 args.level = psview->u.tex.first_level; 1978 mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 1979 } 1980 else if (level0 >= (int) psview->u.tex.last_level) { 1981 args.level = psview->u.tex.last_level; 1982 min_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 1983 } 1984 else { 1985 float levelBlend = frac(lod[j]); 1986 float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 1987 int c; 1988 1989 args.level = level0; 1990 min_filter(sp_sview, sp_samp, &args, &rgbax[0][0]); 1991 args.level = level0+1; 1992 min_filter(sp_sview, sp_samp, &args, &rgbax[0][1]); 1993 1994 for (c = 0; c < 4; c++) { 1995 rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); 1996 } 1997 } 1998 } 1999 2000 if (DEBUG_TEX) { 2001 print_sample_4(__FUNCTION__, rgba); 2002 } 2003 } 2004 2005 2006 /** 2007 * Get mip level relative to base level for nearest mip filter 2008 */ 2009 static void 2010 mip_rel_level_nearest(const struct sp_sampler_view *sp_sview, 2011 const struct sp_sampler *sp_samp, 2012 const float lod[TGSI_QUAD_SIZE], 2013 float level[TGSI_QUAD_SIZE]) 2014 { 2015 int j; 2016 2017 clamp_lod(sp_sview, sp_samp, lod, level); 2018 for (j = 0; j < TGSI_QUAD_SIZE; j++) 2019 /* TODO: It should rather be: 2020 * level[j] = ceil(level[j] + 0.5F) - 1.0F; 2021 */ 2022 level[j] = (int)(level[j] + 0.5F); 2023 } 2024 2025 /** 2026 * Compute nearest mipmap level from texcoords. 2027 * Then sample the texture level for four elements of a quad. 2028 * \param c0 the LOD bias factors, or absolute LODs (depending on control) 2029 */ 2030 static void 2031 mip_filter_nearest(const struct sp_sampler_view *sp_sview, 2032 const struct sp_sampler *sp_samp, 2033 img_filter_func min_filter, 2034 img_filter_func mag_filter, 2035 const float s[TGSI_QUAD_SIZE], 2036 const float t[TGSI_QUAD_SIZE], 2037 const float p[TGSI_QUAD_SIZE], 2038 const float c0[TGSI_QUAD_SIZE], 2039 const float lod_in[TGSI_QUAD_SIZE], 2040 const struct filter_args *filt_args, 2041 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2042 { 2043 const struct pipe_sampler_view *psview = &sp_sview->base; 2044 float lod[TGSI_QUAD_SIZE]; 2045 int j; 2046 struct img_filter_args args; 2047 2048 args.offset = filt_args->offset; 2049 args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER; 2050 args.gather_comp = get_gather_component(lod_in); 2051 2052 compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod); 2053 2054 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2055 args.s = s[j]; 2056 args.t = t[j]; 2057 args.p = p[j]; 2058 args.face_id = filt_args->faces[j]; 2059 2060 if (lod[j] < 0.0) { 2061 args.level = psview->u.tex.first_level; 2062 mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2063 } else { 2064 const int level = psview->u.tex.first_level + (int)(lod[j] + 0.5F); 2065 args.level = MIN2(level, (int)psview->u.tex.last_level); 2066 min_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2067 } 2068 } 2069 2070 if (DEBUG_TEX) { 2071 print_sample_4(__FUNCTION__, rgba); 2072 } 2073 } 2074 2075 2076 /** 2077 * Get mip level relative to base level for none mip filter 2078 */ 2079 static void 2080 mip_rel_level_none(const struct sp_sampler_view *sp_sview, 2081 const struct sp_sampler *sp_samp, 2082 const float lod[TGSI_QUAD_SIZE], 2083 float level[TGSI_QUAD_SIZE]) 2084 { 2085 int j; 2086 2087 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2088 level[j] = 0; 2089 } 2090 } 2091 2092 static void 2093 mip_filter_none(const struct sp_sampler_view *sp_sview, 2094 const struct sp_sampler *sp_samp, 2095 img_filter_func min_filter, 2096 img_filter_func mag_filter, 2097 const float s[TGSI_QUAD_SIZE], 2098 const float t[TGSI_QUAD_SIZE], 2099 const float p[TGSI_QUAD_SIZE], 2100 const float c0[TGSI_QUAD_SIZE], 2101 const float lod_in[TGSI_QUAD_SIZE], 2102 const struct filter_args *filt_args, 2103 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2104 { 2105 float lod[TGSI_QUAD_SIZE]; 2106 int j; 2107 struct img_filter_args args; 2108 2109 args.level = sp_sview->base.u.tex.first_level; 2110 args.offset = filt_args->offset; 2111 args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER; 2112 2113 compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod); 2114 2115 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2116 args.s = s[j]; 2117 args.t = t[j]; 2118 args.p = p[j]; 2119 args.face_id = filt_args->faces[j]; 2120 if (lod[j] < 0.0) { 2121 mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2122 } 2123 else { 2124 min_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2125 } 2126 } 2127 } 2128 2129 2130 /** 2131 * Get mip level relative to base level for none mip filter 2132 */ 2133 static void 2134 mip_rel_level_none_no_filter_select(const struct sp_sampler_view *sp_sview, 2135 const struct sp_sampler *sp_samp, 2136 const float lod[TGSI_QUAD_SIZE], 2137 float level[TGSI_QUAD_SIZE]) 2138 { 2139 mip_rel_level_none(sp_sview, sp_samp, lod, level); 2140 } 2141 2142 static void 2143 mip_filter_none_no_filter_select(const struct sp_sampler_view *sp_sview, 2144 const struct sp_sampler *sp_samp, 2145 img_filter_func min_filter, 2146 img_filter_func mag_filter, 2147 const float s[TGSI_QUAD_SIZE], 2148 const float t[TGSI_QUAD_SIZE], 2149 const float p[TGSI_QUAD_SIZE], 2150 const float c0[TGSI_QUAD_SIZE], 2151 const float lod_in[TGSI_QUAD_SIZE], 2152 const struct filter_args *filt_args, 2153 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2154 { 2155 int j; 2156 struct img_filter_args args; 2157 args.level = sp_sview->base.u.tex.first_level; 2158 args.offset = filt_args->offset; 2159 args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER; 2160 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2161 args.s = s[j]; 2162 args.t = t[j]; 2163 args.p = p[j]; 2164 args.face_id = filt_args->faces[j]; 2165 mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2166 } 2167 } 2168 2169 2170 /* For anisotropic filtering */ 2171 #define WEIGHT_LUT_SIZE 1024 2172 2173 static const float *weightLut = NULL; 2174 2175 /** 2176 * Creates the look-up table used to speed-up EWA sampling 2177 */ 2178 static void 2179 create_filter_table(void) 2180 { 2181 unsigned i; 2182 if (!weightLut) { 2183 float *lut = (float *) MALLOC(WEIGHT_LUT_SIZE * sizeof(float)); 2184 2185 for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { 2186 const float alpha = 2; 2187 const float r2 = (float) i / (float) (WEIGHT_LUT_SIZE - 1); 2188 const float weight = (float) exp(-alpha * r2); 2189 lut[i] = weight; 2190 } 2191 weightLut = lut; 2192 } 2193 } 2194 2195 2196 /** 2197 * Elliptical weighted average (EWA) filter for producing high quality 2198 * anisotropic filtered results. 2199 * Based on the Higher Quality Elliptical Weighted Average Filter 2200 * published by Paul S. Heckbert in his Master's Thesis 2201 * "Fundamentals of Texture Mapping and Image Warping" (1989) 2202 */ 2203 static void 2204 img_filter_2d_ewa(const struct sp_sampler_view *sp_sview, 2205 const struct sp_sampler *sp_samp, 2206 img_filter_func min_filter, 2207 img_filter_func mag_filter, 2208 const float s[TGSI_QUAD_SIZE], 2209 const float t[TGSI_QUAD_SIZE], 2210 const float p[TGSI_QUAD_SIZE], 2211 const uint faces[TGSI_QUAD_SIZE], 2212 const int8_t *offset, 2213 unsigned level, 2214 const float dudx, const float dvdx, 2215 const float dudy, const float dvdy, 2216 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2217 { 2218 const struct pipe_resource *texture = sp_sview->base.texture; 2219 2220 // ??? Won't the image filters blow up if level is negative? 2221 const unsigned level0 = level > 0 ? level : 0; 2222 const float scaling = 1.0f / (1 << level0); 2223 const int width = u_minify(texture->width0, level0); 2224 const int height = u_minify(texture->height0, level0); 2225 struct img_filter_args args; 2226 const float ux = dudx * scaling; 2227 const float vx = dvdx * scaling; 2228 const float uy = dudy * scaling; 2229 const float vy = dvdy * scaling; 2230 2231 /* compute ellipse coefficients to bound the region: 2232 * A*x*x + B*x*y + C*y*y = F. 2233 */ 2234 float A = vx*vx+vy*vy+1; 2235 float B = -2*(ux*vx+uy*vy); 2236 float C = ux*ux+uy*uy+1; 2237 float F = A*C-B*B/4.0f; 2238 2239 /* check if it is an ellipse */ 2240 /* assert(F > 0.0); */ 2241 2242 /* Compute the ellipse's (u,v) bounding box in texture space */ 2243 const float d = -B*B+4.0f*C*A; 2244 const float box_u = 2.0f / d * sqrtf(d*C*F); /* box_u -> half of bbox with */ 2245 const float box_v = 2.0f / d * sqrtf(A*d*F); /* box_v -> half of bbox height */ 2246 2247 float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 2248 float s_buffer[TGSI_QUAD_SIZE]; 2249 float t_buffer[TGSI_QUAD_SIZE]; 2250 float weight_buffer[TGSI_QUAD_SIZE]; 2251 int j; 2252 2253 /* For each quad, the du and dx values are the same and so the ellipse is 2254 * also the same. Note that texel/image access can only be performed using 2255 * a quad, i.e. it is not possible to get the pixel value for a single 2256 * tex coord. In order to have a better performance, the access is buffered 2257 * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is 2258 * full, then the pixel values are read from the image. 2259 */ 2260 const float ddq = 2 * A; 2261 2262 /* Scale ellipse formula to directly index the Filter Lookup Table. 2263 * i.e. scale so that F = WEIGHT_LUT_SIZE-1 2264 */ 2265 const double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F; 2266 A *= formScale; 2267 B *= formScale; 2268 C *= formScale; 2269 /* F *= formScale; */ /* no need to scale F as we don't use it below here */ 2270 2271 args.level = level; 2272 args.offset = offset; 2273 2274 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2275 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse 2276 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this 2277 * value, q, is less than F, we're inside the ellipse 2278 */ 2279 const float tex_u = -0.5F + s[j] * texture->width0 * scaling; 2280 const float tex_v = -0.5F + t[j] * texture->height0 * scaling; 2281 2282 const int u0 = (int) floorf(tex_u - box_u); 2283 const int u1 = (int) ceilf(tex_u + box_u); 2284 const int v0 = (int) floorf(tex_v - box_v); 2285 const int v1 = (int) ceilf(tex_v + box_v); 2286 const float U = u0 - tex_u; 2287 2288 float num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; 2289 unsigned buffer_next = 0; 2290 float den = 0; 2291 int v; 2292 args.face_id = faces[j]; 2293 2294 for (v = v0; v <= v1; ++v) { 2295 const float V = v - tex_v; 2296 float dq = A * (2 * U + 1) + B * V; 2297 float q = (C * V + B * U) * V + A * U * U; 2298 2299 int u; 2300 for (u = u0; u <= u1; ++u) { 2301 /* Note that the ellipse has been pre-scaled so F = 2302 * WEIGHT_LUT_SIZE - 1 2303 */ 2304 if (q < WEIGHT_LUT_SIZE) { 2305 /* as a LUT is used, q must never be negative; 2306 * should not happen, though 2307 */ 2308 const int qClamped = q >= 0.0F ? q : 0; 2309 const float weight = weightLut[qClamped]; 2310 2311 weight_buffer[buffer_next] = weight; 2312 s_buffer[buffer_next] = u / ((float) width); 2313 t_buffer[buffer_next] = v / ((float) height); 2314 2315 buffer_next++; 2316 if (buffer_next == TGSI_QUAD_SIZE) { 2317 /* 4 texel coords are in the buffer -> read it now */ 2318 unsigned jj; 2319 /* it is assumed that samp->min_img_filter is set to 2320 * img_filter_2d_nearest or one of the 2321 * accelerated img_filter_2d_nearest_XXX functions. 2322 */ 2323 for (jj = 0; jj < buffer_next; jj++) { 2324 args.s = s_buffer[jj]; 2325 args.t = t_buffer[jj]; 2326 args.p = p[jj]; 2327 min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][jj]); 2328 num[0] += weight_buffer[jj] * rgba_temp[0][jj]; 2329 num[1] += weight_buffer[jj] * rgba_temp[1][jj]; 2330 num[2] += weight_buffer[jj] * rgba_temp[2][jj]; 2331 num[3] += weight_buffer[jj] * rgba_temp[3][jj]; 2332 } 2333 2334 buffer_next = 0; 2335 } 2336 2337 den += weight; 2338 } 2339 q += dq; 2340 dq += ddq; 2341 } 2342 } 2343 2344 /* if the tex coord buffer contains unread values, we will read 2345 * them now. 2346 */ 2347 if (buffer_next > 0) { 2348 unsigned jj; 2349 /* it is assumed that samp->min_img_filter is set to 2350 * img_filter_2d_nearest or one of the 2351 * accelerated img_filter_2d_nearest_XXX functions. 2352 */ 2353 for (jj = 0; jj < buffer_next; jj++) { 2354 args.s = s_buffer[jj]; 2355 args.t = t_buffer[jj]; 2356 args.p = p[jj]; 2357 min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][jj]); 2358 num[0] += weight_buffer[jj] * rgba_temp[0][jj]; 2359 num[1] += weight_buffer[jj] * rgba_temp[1][jj]; 2360 num[2] += weight_buffer[jj] * rgba_temp[2][jj]; 2361 num[3] += weight_buffer[jj] * rgba_temp[3][jj]; 2362 } 2363 } 2364 2365 if (den <= 0.0F) { 2366 /* Reaching this place would mean that no pixels intersected 2367 * the ellipse. This should never happen because the filter 2368 * we use always intersects at least one pixel. 2369 */ 2370 2371 /*rgba[0]=0; 2372 rgba[1]=0; 2373 rgba[2]=0; 2374 rgba[3]=0;*/ 2375 /* not enough pixels in resampling, resort to direct interpolation */ 2376 args.s = s[j]; 2377 args.t = t[j]; 2378 args.p = p[j]; 2379 min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][j]); 2380 den = 1; 2381 num[0] = rgba_temp[0][j]; 2382 num[1] = rgba_temp[1][j]; 2383 num[2] = rgba_temp[2][j]; 2384 num[3] = rgba_temp[3][j]; 2385 } 2386 2387 rgba[0][j] = num[0] / den; 2388 rgba[1][j] = num[1] / den; 2389 rgba[2][j] = num[2] / den; 2390 rgba[3][j] = num[3] / den; 2391 } 2392 } 2393 2394 2395 /** 2396 * Get mip level relative to base level for linear mip filter 2397 */ 2398 static void 2399 mip_rel_level_linear_aniso(const struct sp_sampler_view *sp_sview, 2400 const struct sp_sampler *sp_samp, 2401 const float lod[TGSI_QUAD_SIZE], 2402 float level[TGSI_QUAD_SIZE]) 2403 { 2404 mip_rel_level_linear(sp_sview, sp_samp, lod, level); 2405 } 2406 2407 /** 2408 * Sample 2D texture using an anisotropic filter. 2409 */ 2410 static void 2411 mip_filter_linear_aniso(const struct sp_sampler_view *sp_sview, 2412 const struct sp_sampler *sp_samp, 2413 img_filter_func min_filter, 2414 img_filter_func mag_filter, 2415 const float s[TGSI_QUAD_SIZE], 2416 const float t[TGSI_QUAD_SIZE], 2417 const float p[TGSI_QUAD_SIZE], 2418 const float c0[TGSI_QUAD_SIZE], 2419 const float lod_in[TGSI_QUAD_SIZE], 2420 const struct filter_args *filt_args, 2421 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2422 { 2423 const struct pipe_resource *texture = sp_sview->base.texture; 2424 const struct pipe_sampler_view *psview = &sp_sview->base; 2425 int level0; 2426 float lambda; 2427 float lod[TGSI_QUAD_SIZE]; 2428 2429 const float s_to_u = u_minify(texture->width0, psview->u.tex.first_level); 2430 const float t_to_v = u_minify(texture->height0, psview->u.tex.first_level); 2431 const float dudx = (s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]) * s_to_u; 2432 const float dudy = (s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]) * s_to_u; 2433 const float dvdx = (t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]) * t_to_v; 2434 const float dvdy = (t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT]) * t_to_v; 2435 struct img_filter_args args; 2436 2437 args.offset = filt_args->offset; 2438 2439 if (filt_args->control == TGSI_SAMPLER_LOD_BIAS || 2440 filt_args->control == TGSI_SAMPLER_LOD_NONE || 2441 /* XXX FIXME */ 2442 filt_args->control == TGSI_SAMPLER_DERIVS_EXPLICIT) { 2443 /* note: instead of working with Px and Py, we will use the 2444 * squared length instead, to avoid sqrt. 2445 */ 2446 const float Px2 = dudx * dudx + dvdx * dvdx; 2447 const float Py2 = dudy * dudy + dvdy * dvdy; 2448 2449 float Pmax2; 2450 float Pmin2; 2451 float e; 2452 const float maxEccentricity = sp_samp->base.max_anisotropy * sp_samp->base.max_anisotropy; 2453 2454 if (Px2 < Py2) { 2455 Pmax2 = Py2; 2456 Pmin2 = Px2; 2457 } 2458 else { 2459 Pmax2 = Px2; 2460 Pmin2 = Py2; 2461 } 2462 2463 /* if the eccentricity of the ellipse is too big, scale up the shorter 2464 * of the two vectors to limit the maximum amount of work per pixel 2465 */ 2466 e = Pmax2 / Pmin2; 2467 if (e > maxEccentricity) { 2468 /* float s=e / maxEccentricity; 2469 minor[0] *= s; 2470 minor[1] *= s; 2471 Pmin2 *= s; */ 2472 Pmin2 = Pmax2 / maxEccentricity; 2473 } 2474 2475 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid 2476 * this since 0.5*log(x) = log(sqrt(x)) 2477 */ 2478 lambda = 0.5F * util_fast_log2(Pmin2) + sp_samp->base.lod_bias; 2479 compute_lod(&sp_samp->base, filt_args->control, lambda, lod_in, lod); 2480 } 2481 else { 2482 assert(filt_args->control == TGSI_SAMPLER_LOD_EXPLICIT || 2483 filt_args->control == TGSI_SAMPLER_LOD_ZERO); 2484 compute_lod(&sp_samp->base, filt_args->control, sp_samp->base.lod_bias, lod_in, lod); 2485 } 2486 2487 /* XXX: Take into account all lod values. 2488 */ 2489 lambda = lod[0]; 2490 level0 = psview->u.tex.first_level + (int)lambda; 2491 2492 /* If the ellipse covers the whole image, we can 2493 * simply return the average of the whole image. 2494 */ 2495 if (level0 >= (int) psview->u.tex.last_level) { 2496 int j; 2497 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2498 args.s = s[j]; 2499 args.t = t[j]; 2500 args.p = p[j]; 2501 args.level = psview->u.tex.last_level; 2502 args.face_id = filt_args->faces[j]; 2503 /* 2504 * XXX: we overwrote any linear filter with nearest, so this 2505 * isn't right (albeit if last level is 1x1 and no border it 2506 * will work just the same). 2507 */ 2508 min_filter(sp_sview, sp_samp, &args, &rgba[0][j]); 2509 } 2510 } 2511 else { 2512 /* don't bother interpolating between multiple LODs; it doesn't 2513 * seem to be worth the extra running time. 2514 */ 2515 img_filter_2d_ewa(sp_sview, sp_samp, min_filter, mag_filter, 2516 s, t, p, filt_args->faces, filt_args->offset, 2517 level0, dudx, dvdx, dudy, dvdy, rgba); 2518 } 2519 2520 if (DEBUG_TEX) { 2521 print_sample_4(__FUNCTION__, rgba); 2522 } 2523 } 2524 2525 /** 2526 * Get mip level relative to base level for linear mip filter 2527 */ 2528 static void 2529 mip_rel_level_linear_2d_linear_repeat_POT( 2530 const struct sp_sampler_view *sp_sview, 2531 const struct sp_sampler *sp_samp, 2532 const float lod[TGSI_QUAD_SIZE], 2533 float level[TGSI_QUAD_SIZE]) 2534 { 2535 mip_rel_level_linear(sp_sview, sp_samp, lod, level); 2536 } 2537 2538 /** 2539 * Specialized version of mip_filter_linear with hard-wired calls to 2540 * 2d lambda calculation and 2d_linear_repeat_POT img filters. 2541 */ 2542 static void 2543 mip_filter_linear_2d_linear_repeat_POT( 2544 const struct sp_sampler_view *sp_sview, 2545 const struct sp_sampler *sp_samp, 2546 img_filter_func min_filter, 2547 img_filter_func mag_filter, 2548 const float s[TGSI_QUAD_SIZE], 2549 const float t[TGSI_QUAD_SIZE], 2550 const float p[TGSI_QUAD_SIZE], 2551 const float c0[TGSI_QUAD_SIZE], 2552 const float lod_in[TGSI_QUAD_SIZE], 2553 const struct filter_args *filt_args, 2554 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2555 { 2556 const struct pipe_sampler_view *psview = &sp_sview->base; 2557 int j; 2558 float lod[TGSI_QUAD_SIZE]; 2559 2560 compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod); 2561 2562 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2563 const int level0 = psview->u.tex.first_level + (int)lod[j]; 2564 struct img_filter_args args; 2565 /* Catches both negative and large values of level0: 2566 */ 2567 args.s = s[j]; 2568 args.t = t[j]; 2569 args.p = p[j]; 2570 args.face_id = filt_args->faces[j]; 2571 args.offset = filt_args->offset; 2572 args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER; 2573 if ((unsigned)level0 >= psview->u.tex.last_level) { 2574 if (level0 < 0) 2575 args.level = psview->u.tex.first_level; 2576 else 2577 args.level = psview->u.tex.last_level; 2578 img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args, 2579 &rgba[0][j]); 2580 2581 } 2582 else { 2583 const float levelBlend = frac(lod[j]); 2584 float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 2585 int c; 2586 2587 args.level = level0; 2588 img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args, &rgbax[0][0]); 2589 args.level = level0+1; 2590 img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args, &rgbax[0][1]); 2591 2592 for (c = 0; c < TGSI_NUM_CHANNELS; c++) 2593 rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); 2594 } 2595 } 2596 2597 if (DEBUG_TEX) { 2598 print_sample_4(__FUNCTION__, rgba); 2599 } 2600 } 2601 2602 static const struct sp_filter_funcs funcs_linear = { 2603 mip_rel_level_linear, 2604 mip_filter_linear 2605 }; 2606 2607 static const struct sp_filter_funcs funcs_nearest = { 2608 mip_rel_level_nearest, 2609 mip_filter_nearest 2610 }; 2611 2612 static const struct sp_filter_funcs funcs_none = { 2613 mip_rel_level_none, 2614 mip_filter_none 2615 }; 2616 2617 static const struct sp_filter_funcs funcs_none_no_filter_select = { 2618 mip_rel_level_none_no_filter_select, 2619 mip_filter_none_no_filter_select 2620 }; 2621 2622 static const struct sp_filter_funcs funcs_linear_aniso = { 2623 mip_rel_level_linear_aniso, 2624 mip_filter_linear_aniso 2625 }; 2626 2627 static const struct sp_filter_funcs funcs_linear_2d_linear_repeat_POT = { 2628 mip_rel_level_linear_2d_linear_repeat_POT, 2629 mip_filter_linear_2d_linear_repeat_POT 2630 }; 2631 2632 /** 2633 * Do shadow/depth comparisons. 2634 */ 2635 static void 2636 sample_compare(const struct sp_sampler_view *sp_sview, 2637 const struct sp_sampler *sp_samp, 2638 const float s[TGSI_QUAD_SIZE], 2639 const float t[TGSI_QUAD_SIZE], 2640 const float p[TGSI_QUAD_SIZE], 2641 const float c0[TGSI_QUAD_SIZE], 2642 const float c1[TGSI_QUAD_SIZE], 2643 enum tgsi_sampler_control control, 2644 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2645 { 2646 const struct pipe_sampler_state *sampler = &sp_samp->base; 2647 int j, v; 2648 int k[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 2649 float pc[4]; 2650 const struct util_format_description *format_desc = 2651 util_format_description(sp_sview->base.format); 2652 /* not entirely sure we couldn't end up with non-valid swizzle here */ 2653 const unsigned chan_type = 2654 format_desc->swizzle[0] <= PIPE_SWIZZLE_W ? 2655 format_desc->channel[format_desc->swizzle[0]].type : 2656 UTIL_FORMAT_TYPE_FLOAT; 2657 const bool is_gather = (control == TGSI_SAMPLER_GATHER); 2658 2659 /** 2660 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]' 2661 * for 2D Array texture we need to use the 'c0' (aka Q). 2662 * When we sampled the depth texture, the depth value was put into all 2663 * RGBA channels. We look at the red channel here. 2664 */ 2665 2666 if (sp_sview->base.target == PIPE_TEXTURE_2D_ARRAY || 2667 sp_sview->base.target == PIPE_TEXTURE_CUBE) { 2668 pc[0] = c0[0]; 2669 pc[1] = c0[1]; 2670 pc[2] = c0[2]; 2671 pc[3] = c0[3]; 2672 } else if (sp_sview->base.target == PIPE_TEXTURE_CUBE_ARRAY) { 2673 pc[0] = c1[0]; 2674 pc[1] = c1[1]; 2675 pc[2] = c1[2]; 2676 pc[3] = c1[3]; 2677 } else { 2678 pc[0] = p[0]; 2679 pc[1] = p[1]; 2680 pc[2] = p[2]; 2681 pc[3] = p[3]; 2682 } 2683 2684 if (chan_type != UTIL_FORMAT_TYPE_FLOAT) { 2685 /* 2686 * clamping is a result of conversion to texture format, hence 2687 * doesn't happen with floats. Technically also should do comparison 2688 * in texture format (quantization!). 2689 */ 2690 pc[0] = CLAMP(pc[0], 0.0F, 1.0F); 2691 pc[1] = CLAMP(pc[1], 0.0F, 1.0F); 2692 pc[2] = CLAMP(pc[2], 0.0F, 1.0F); 2693 pc[3] = CLAMP(pc[3], 0.0F, 1.0F); 2694 } 2695 2696 for (v = 0; v < (is_gather ? TGSI_NUM_CHANNELS : 1); v++) { 2697 /* compare four texcoords vs. four texture samples */ 2698 switch (sampler->compare_func) { 2699 case PIPE_FUNC_LESS: 2700 k[v][0] = pc[0] < rgba[v][0]; 2701 k[v][1] = pc[1] < rgba[v][1]; 2702 k[v][2] = pc[2] < rgba[v][2]; 2703 k[v][3] = pc[3] < rgba[v][3]; 2704 break; 2705 case PIPE_FUNC_LEQUAL: 2706 k[v][0] = pc[0] <= rgba[v][0]; 2707 k[v][1] = pc[1] <= rgba[v][1]; 2708 k[v][2] = pc[2] <= rgba[v][2]; 2709 k[v][3] = pc[3] <= rgba[v][3]; 2710 break; 2711 case PIPE_FUNC_GREATER: 2712 k[v][0] = pc[0] > rgba[v][0]; 2713 k[v][1] = pc[1] > rgba[v][1]; 2714 k[v][2] = pc[2] > rgba[v][2]; 2715 k[v][3] = pc[3] > rgba[v][3]; 2716 break; 2717 case PIPE_FUNC_GEQUAL: 2718 k[v][0] = pc[0] >= rgba[v][0]; 2719 k[v][1] = pc[1] >= rgba[v][1]; 2720 k[v][2] = pc[2] >= rgba[v][2]; 2721 k[v][3] = pc[3] >= rgba[v][3]; 2722 break; 2723 case PIPE_FUNC_EQUAL: 2724 k[v][0] = pc[0] == rgba[v][0]; 2725 k[v][1] = pc[1] == rgba[v][1]; 2726 k[v][2] = pc[2] == rgba[v][2]; 2727 k[v][3] = pc[3] == rgba[v][3]; 2728 break; 2729 case PIPE_FUNC_NOTEQUAL: 2730 k[v][0] = pc[0] != rgba[v][0]; 2731 k[v][1] = pc[1] != rgba[v][1]; 2732 k[v][2] = pc[2] != rgba[v][2]; 2733 k[v][3] = pc[3] != rgba[v][3]; 2734 break; 2735 case PIPE_FUNC_ALWAYS: 2736 k[v][0] = k[v][1] = k[v][2] = k[v][3] = 1; 2737 break; 2738 case PIPE_FUNC_NEVER: 2739 k[v][0] = k[v][1] = k[v][2] = k[v][3] = 0; 2740 break; 2741 default: 2742 k[v][0] = k[v][1] = k[v][2] = k[v][3] = 0; 2743 assert(0); 2744 break; 2745 } 2746 } 2747 2748 if (is_gather) { 2749 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2750 for (v = 0; v < TGSI_NUM_CHANNELS; v++) { 2751 rgba[v][j] = k[v][j]; 2752 } 2753 } 2754 } else { 2755 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 2756 rgba[0][j] = k[0][j]; 2757 rgba[1][j] = k[0][j]; 2758 rgba[2][j] = k[0][j]; 2759 rgba[3][j] = 1.0F; 2760 } 2761 } 2762 } 2763 2764 static void 2765 do_swizzling(const struct pipe_sampler_view *sview, 2766 float in[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE], 2767 float out[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 2768 { 2769 int j; 2770 const unsigned swizzle_r = sview->swizzle_r; 2771 const unsigned swizzle_g = sview->swizzle_g; 2772 const unsigned swizzle_b = sview->swizzle_b; 2773 const unsigned swizzle_a = sview->swizzle_a; 2774 2775 switch (swizzle_r) { 2776 case PIPE_SWIZZLE_0: 2777 for (j = 0; j < 4; j++) 2778 out[0][j] = 0.0f; 2779 break; 2780 case PIPE_SWIZZLE_1: 2781 for (j = 0; j < 4; j++) 2782 out[0][j] = 1.0f; 2783 break; 2784 default: 2785 assert(swizzle_r < 4); 2786 for (j = 0; j < 4; j++) 2787 out[0][j] = in[swizzle_r][j]; 2788 } 2789 2790 switch (swizzle_g) { 2791 case PIPE_SWIZZLE_0: 2792 for (j = 0; j < 4; j++) 2793 out[1][j] = 0.0f; 2794 break; 2795 case PIPE_SWIZZLE_1: 2796 for (j = 0; j < 4; j++) 2797 out[1][j] = 1.0f; 2798 break; 2799 default: 2800 assert(swizzle_g < 4); 2801 for (j = 0; j < 4; j++) 2802 out[1][j] = in[swizzle_g][j]; 2803 } 2804 2805 switch (swizzle_b) { 2806 case PIPE_SWIZZLE_0: 2807 for (j = 0; j < 4; j++) 2808 out[2][j] = 0.0f; 2809 break; 2810 case PIPE_SWIZZLE_1: 2811 for (j = 0; j < 4; j++) 2812 out[2][j] = 1.0f; 2813 break; 2814 default: 2815 assert(swizzle_b < 4); 2816 for (j = 0; j < 4; j++) 2817 out[2][j] = in[swizzle_b][j]; 2818 } 2819 2820 switch (swizzle_a) { 2821 case PIPE_SWIZZLE_0: 2822 for (j = 0; j < 4; j++) 2823 out[3][j] = 0.0f; 2824 break; 2825 case PIPE_SWIZZLE_1: 2826 for (j = 0; j < 4; j++) 2827 out[3][j] = 1.0f; 2828 break; 2829 default: 2830 assert(swizzle_a < 4); 2831 for (j = 0; j < 4; j++) 2832 out[3][j] = in[swizzle_a][j]; 2833 } 2834 } 2835 2836 2837 static wrap_nearest_func 2838 get_nearest_unorm_wrap(unsigned mode) 2839 { 2840 switch (mode) { 2841 case PIPE_TEX_WRAP_CLAMP: 2842 return wrap_nearest_unorm_clamp; 2843 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 2844 return wrap_nearest_unorm_clamp_to_edge; 2845 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 2846 return wrap_nearest_unorm_clamp_to_border; 2847 default: 2848 debug_printf("illegal wrap mode %d with non-normalized coords\n", mode); 2849 return wrap_nearest_unorm_clamp; 2850 } 2851 } 2852 2853 2854 static wrap_nearest_func 2855 get_nearest_wrap(unsigned mode) 2856 { 2857 switch (mode) { 2858 case PIPE_TEX_WRAP_REPEAT: 2859 return wrap_nearest_repeat; 2860 case PIPE_TEX_WRAP_CLAMP: 2861 return wrap_nearest_clamp; 2862 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 2863 return wrap_nearest_clamp_to_edge; 2864 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 2865 return wrap_nearest_clamp_to_border; 2866 case PIPE_TEX_WRAP_MIRROR_REPEAT: 2867 return wrap_nearest_mirror_repeat; 2868 case PIPE_TEX_WRAP_MIRROR_CLAMP: 2869 return wrap_nearest_mirror_clamp; 2870 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 2871 return wrap_nearest_mirror_clamp_to_edge; 2872 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 2873 return wrap_nearest_mirror_clamp_to_border; 2874 default: 2875 assert(0); 2876 return wrap_nearest_repeat; 2877 } 2878 } 2879 2880 2881 static wrap_linear_func 2882 get_linear_unorm_wrap(unsigned mode) 2883 { 2884 switch (mode) { 2885 case PIPE_TEX_WRAP_CLAMP: 2886 return wrap_linear_unorm_clamp; 2887 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 2888 return wrap_linear_unorm_clamp_to_edge; 2889 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 2890 return wrap_linear_unorm_clamp_to_border; 2891 default: 2892 debug_printf("illegal wrap mode %d with non-normalized coords\n", mode); 2893 return wrap_linear_unorm_clamp; 2894 } 2895 } 2896 2897 2898 static wrap_linear_func 2899 get_linear_wrap(unsigned mode) 2900 { 2901 switch (mode) { 2902 case PIPE_TEX_WRAP_REPEAT: 2903 return wrap_linear_repeat; 2904 case PIPE_TEX_WRAP_CLAMP: 2905 return wrap_linear_clamp; 2906 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: 2907 return wrap_linear_clamp_to_edge; 2908 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: 2909 return wrap_linear_clamp_to_border; 2910 case PIPE_TEX_WRAP_MIRROR_REPEAT: 2911 return wrap_linear_mirror_repeat; 2912 case PIPE_TEX_WRAP_MIRROR_CLAMP: 2913 return wrap_linear_mirror_clamp; 2914 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: 2915 return wrap_linear_mirror_clamp_to_edge; 2916 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: 2917 return wrap_linear_mirror_clamp_to_border; 2918 default: 2919 assert(0); 2920 return wrap_linear_repeat; 2921 } 2922 } 2923 2924 2925 /** 2926 * Is swizzling needed for the given state key? 2927 */ 2928 static inline bool 2929 any_swizzle(const struct pipe_sampler_view *view) 2930 { 2931 return (view->swizzle_r != PIPE_SWIZZLE_X || 2932 view->swizzle_g != PIPE_SWIZZLE_Y || 2933 view->swizzle_b != PIPE_SWIZZLE_Z || 2934 view->swizzle_a != PIPE_SWIZZLE_W); 2935 } 2936 2937 2938 static img_filter_func 2939 get_img_filter(const struct sp_sampler_view *sp_sview, 2940 const struct pipe_sampler_state *sampler, 2941 unsigned filter, bool gather) 2942 { 2943 switch (sp_sview->base.target) { 2944 case PIPE_BUFFER: 2945 case PIPE_TEXTURE_1D: 2946 if (filter == PIPE_TEX_FILTER_NEAREST) 2947 return img_filter_1d_nearest; 2948 else 2949 return img_filter_1d_linear; 2950 break; 2951 case PIPE_TEXTURE_1D_ARRAY: 2952 if (filter == PIPE_TEX_FILTER_NEAREST) 2953 return img_filter_1d_array_nearest; 2954 else 2955 return img_filter_1d_array_linear; 2956 break; 2957 case PIPE_TEXTURE_2D: 2958 case PIPE_TEXTURE_RECT: 2959 /* Try for fast path: 2960 */ 2961 if (!gather && sp_sview->pot2d && 2962 sampler->wrap_s == sampler->wrap_t && 2963 sampler->normalized_coords) 2964 { 2965 switch (sampler->wrap_s) { 2966 case PIPE_TEX_WRAP_REPEAT: 2967 switch (filter) { 2968 case PIPE_TEX_FILTER_NEAREST: 2969 return img_filter_2d_nearest_repeat_POT; 2970 case PIPE_TEX_FILTER_LINEAR: 2971 return img_filter_2d_linear_repeat_POT; 2972 default: 2973 break; 2974 } 2975 break; 2976 case PIPE_TEX_WRAP_CLAMP: 2977 switch (filter) { 2978 case PIPE_TEX_FILTER_NEAREST: 2979 return img_filter_2d_nearest_clamp_POT; 2980 default: 2981 break; 2982 } 2983 } 2984 } 2985 /* Otherwise use default versions: 2986 */ 2987 if (filter == PIPE_TEX_FILTER_NEAREST) 2988 return img_filter_2d_nearest; 2989 else 2990 return img_filter_2d_linear; 2991 break; 2992 case PIPE_TEXTURE_2D_ARRAY: 2993 if (filter == PIPE_TEX_FILTER_NEAREST) 2994 return img_filter_2d_array_nearest; 2995 else 2996 return img_filter_2d_array_linear; 2997 break; 2998 case PIPE_TEXTURE_CUBE: 2999 if (filter == PIPE_TEX_FILTER_NEAREST) 3000 return img_filter_cube_nearest; 3001 else 3002 return img_filter_cube_linear; 3003 break; 3004 case PIPE_TEXTURE_CUBE_ARRAY: 3005 if (filter == PIPE_TEX_FILTER_NEAREST) 3006 return img_filter_cube_array_nearest; 3007 else 3008 return img_filter_cube_array_linear; 3009 break; 3010 case PIPE_TEXTURE_3D: 3011 if (filter == PIPE_TEX_FILTER_NEAREST) 3012 return img_filter_3d_nearest; 3013 else 3014 return img_filter_3d_linear; 3015 break; 3016 default: 3017 assert(0); 3018 return img_filter_1d_nearest; 3019 } 3020 } 3021 3022 /** 3023 * Get mip filter funcs, and optionally both img min filter and img mag 3024 * filter. Note that both img filter function pointers must be either non-NULL 3025 * or NULL. 3026 */ 3027 static void 3028 get_filters(const struct sp_sampler_view *sp_sview, 3029 const struct sp_sampler *sp_samp, 3030 const enum tgsi_sampler_control control, 3031 const struct sp_filter_funcs **funcs, 3032 img_filter_func *min, 3033 img_filter_func *mag) 3034 { 3035 assert(funcs); 3036 if (control == TGSI_SAMPLER_GATHER) { 3037 *funcs = &funcs_nearest; 3038 if (min) { 3039 *min = get_img_filter(sp_sview, &sp_samp->base, 3040 PIPE_TEX_FILTER_LINEAR, true); 3041 } 3042 } else if (sp_sview->pot2d & sp_samp->min_mag_equal_repeat_linear) { 3043 *funcs = &funcs_linear_2d_linear_repeat_POT; 3044 } else { 3045 *funcs = sp_samp->filter_funcs; 3046 if (min) { 3047 assert(mag); 3048 *min = get_img_filter(sp_sview, &sp_samp->base, 3049 sp_samp->min_img_filter, false); 3050 if (sp_samp->min_mag_equal) { 3051 *mag = *min; 3052 } else { 3053 *mag = get_img_filter(sp_sview, &sp_samp->base, 3054 sp_samp->base.mag_img_filter, false); 3055 } 3056 } 3057 } 3058 } 3059 3060 static void 3061 sample_mip(const struct sp_sampler_view *sp_sview, 3062 const struct sp_sampler *sp_samp, 3063 const float s[TGSI_QUAD_SIZE], 3064 const float t[TGSI_QUAD_SIZE], 3065 const float p[TGSI_QUAD_SIZE], 3066 const float c0[TGSI_QUAD_SIZE], 3067 const float lod[TGSI_QUAD_SIZE], 3068 const struct filter_args *filt_args, 3069 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 3070 { 3071 const struct sp_filter_funcs *funcs = NULL; 3072 img_filter_func min_img_filter = NULL; 3073 img_filter_func mag_img_filter = NULL; 3074 3075 get_filters(sp_sview, sp_samp, filt_args->control, 3076 &funcs, &min_img_filter, &mag_img_filter); 3077 3078 funcs->filter(sp_sview, sp_samp, min_img_filter, mag_img_filter, 3079 s, t, p, c0, lod, filt_args, rgba); 3080 3081 if (sp_samp->base.compare_mode != PIPE_TEX_COMPARE_NONE) { 3082 sample_compare(sp_sview, sp_samp, s, t, p, c0, 3083 lod, filt_args->control, rgba); 3084 } 3085 3086 if (sp_sview->need_swizzle && filt_args->control != TGSI_SAMPLER_GATHER) { 3087 float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 3088 memcpy(rgba_temp, rgba, sizeof(rgba_temp)); 3089 do_swizzling(&sp_sview->base, rgba_temp, rgba); 3090 } 3091 3092 } 3093 3094 3095 /** 3096 * This function uses cube texture coordinates to choose a face of a cube and 3097 * computes the 2D cube face coordinates. Puts face info into the sampler 3098 * faces[] array. 3099 */ 3100 static void 3101 convert_cube(const struct sp_sampler_view *sp_sview, 3102 const struct sp_sampler *sp_samp, 3103 const float s[TGSI_QUAD_SIZE], 3104 const float t[TGSI_QUAD_SIZE], 3105 const float p[TGSI_QUAD_SIZE], 3106 const float c0[TGSI_QUAD_SIZE], 3107 float ssss[TGSI_QUAD_SIZE], 3108 float tttt[TGSI_QUAD_SIZE], 3109 float pppp[TGSI_QUAD_SIZE], 3110 uint faces[TGSI_QUAD_SIZE]) 3111 { 3112 unsigned j; 3113 3114 pppp[0] = c0[0]; 3115 pppp[1] = c0[1]; 3116 pppp[2] = c0[2]; 3117 pppp[3] = c0[3]; 3118 /* 3119 major axis 3120 direction target sc tc ma 3121 ---------- ------------------------------- --- --- --- 3122 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx 3123 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx 3124 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry 3125 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry 3126 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz 3127 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz 3128 */ 3129 3130 /* Choose the cube face and compute new s/t coords for the 2D face. 3131 * 3132 * Use the same cube face for all four pixels in the quad. 3133 * 3134 * This isn't ideal, but if we want to use a different cube face 3135 * per pixel in the quad, we'd have to also compute the per-face 3136 * LOD here too. That's because the four post-face-selection 3137 * texcoords are no longer related to each other (they're 3138 * per-face!) so we can't use subtraction to compute the partial 3139 * deriviates to compute the LOD. Doing so (near cube edges 3140 * anyway) gives us pretty much random values. 3141 */ 3142 { 3143 /* use the average of the four pixel's texcoords to choose the face */ 3144 const float rx = 0.25F * (s[0] + s[1] + s[2] + s[3]); 3145 const float ry = 0.25F * (t[0] + t[1] + t[2] + t[3]); 3146 const float rz = 0.25F * (p[0] + p[1] + p[2] + p[3]); 3147 const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz); 3148 3149 if (arx >= ary && arx >= arz) { 3150 const float sign = (rx >= 0.0F) ? 1.0F : -1.0F; 3151 const uint face = (rx >= 0.0F) ? 3152 PIPE_TEX_FACE_POS_X : PIPE_TEX_FACE_NEG_X; 3153 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3154 const float ima = -0.5F / fabsf(s[j]); 3155 ssss[j] = sign * p[j] * ima + 0.5F; 3156 tttt[j] = t[j] * ima + 0.5F; 3157 faces[j] = face; 3158 } 3159 } 3160 else if (ary >= arx && ary >= arz) { 3161 const float sign = (ry >= 0.0F) ? 1.0F : -1.0F; 3162 const uint face = (ry >= 0.0F) ? 3163 PIPE_TEX_FACE_POS_Y : PIPE_TEX_FACE_NEG_Y; 3164 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3165 const float ima = -0.5F / fabsf(t[j]); 3166 ssss[j] = -s[j] * ima + 0.5F; 3167 tttt[j] = sign * -p[j] * ima + 0.5F; 3168 faces[j] = face; 3169 } 3170 } 3171 else { 3172 const float sign = (rz >= 0.0F) ? 1.0F : -1.0F; 3173 const uint face = (rz >= 0.0F) ? 3174 PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z; 3175 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3176 const float ima = -0.5F / fabsf(p[j]); 3177 ssss[j] = sign * -s[j] * ima + 0.5F; 3178 tttt[j] = t[j] * ima + 0.5F; 3179 faces[j] = face; 3180 } 3181 } 3182 } 3183 } 3184 3185 3186 static void 3187 sp_get_dims(const struct sp_sampler_view *sp_sview, 3188 int level, 3189 int dims[4]) 3190 { 3191 const struct pipe_sampler_view *view = &sp_sview->base; 3192 const struct pipe_resource *texture = view->texture; 3193 3194 if (view->target == PIPE_BUFFER) { 3195 dims[0] = view->u.buf.size / util_format_get_blocksize(view->format); 3196 /* the other values are undefined, but let's avoid potential valgrind 3197 * warnings. 3198 */ 3199 dims[1] = dims[2] = dims[3] = 0; 3200 return; 3201 } 3202 3203 /* undefined according to EXT_gpu_program */ 3204 level += view->u.tex.first_level; 3205 if (level > view->u.tex.last_level) 3206 return; 3207 3208 dims[3] = view->u.tex.last_level - view->u.tex.first_level + 1; 3209 dims[0] = u_minify(texture->width0, level); 3210 3211 switch (view->target) { 3212 case PIPE_TEXTURE_1D_ARRAY: 3213 dims[1] = view->u.tex.last_layer - view->u.tex.first_layer + 1; 3214 /* fallthrough */ 3215 case PIPE_TEXTURE_1D: 3216 return; 3217 case PIPE_TEXTURE_2D_ARRAY: 3218 dims[2] = view->u.tex.last_layer - view->u.tex.first_layer + 1; 3219 /* fallthrough */ 3220 case PIPE_TEXTURE_2D: 3221 case PIPE_TEXTURE_CUBE: 3222 case PIPE_TEXTURE_RECT: 3223 dims[1] = u_minify(texture->height0, level); 3224 return; 3225 case PIPE_TEXTURE_3D: 3226 dims[1] = u_minify(texture->height0, level); 3227 dims[2] = u_minify(texture->depth0, level); 3228 return; 3229 case PIPE_TEXTURE_CUBE_ARRAY: 3230 dims[1] = u_minify(texture->height0, level); 3231 dims[2] = (view->u.tex.last_layer - view->u.tex.first_layer + 1) / 6; 3232 break; 3233 default: 3234 assert(!"unexpected texture target in sp_get_dims()"); 3235 return; 3236 } 3237 } 3238 3239 /** 3240 * This function is only used for getting unfiltered texels via the 3241 * TXF opcode. The GL spec says that out-of-bounds texel fetches 3242 * produce undefined results. Instead of crashing, lets just clamp 3243 * coords to the texture image size. 3244 */ 3245 static void 3246 sp_get_texels(const struct sp_sampler_view *sp_sview, 3247 const int v_i[TGSI_QUAD_SIZE], 3248 const int v_j[TGSI_QUAD_SIZE], 3249 const int v_k[TGSI_QUAD_SIZE], 3250 const int lod[TGSI_QUAD_SIZE], 3251 const int8_t offset[3], 3252 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 3253 { 3254 union tex_tile_address addr; 3255 const struct pipe_resource *texture = sp_sview->base.texture; 3256 int j, c; 3257 const float *tx; 3258 /* TODO write a better test for LOD */ 3259 const unsigned level = 3260 sp_sview->base.target == PIPE_BUFFER ? 0 : 3261 CLAMP(lod[0] + sp_sview->base.u.tex.first_level, 3262 sp_sview->base.u.tex.first_level, 3263 sp_sview->base.u.tex.last_level); 3264 const int width = u_minify(texture->width0, level); 3265 const int height = u_minify(texture->height0, level); 3266 const int depth = u_minify(texture->depth0, level); 3267 unsigned elem_size, first_element, last_element; 3268 3269 addr.value = 0; 3270 addr.bits.level = level; 3271 3272 switch (sp_sview->base.target) { 3273 case PIPE_BUFFER: 3274 elem_size = util_format_get_blocksize(sp_sview->base.format); 3275 first_element = sp_sview->base.u.buf.offset / elem_size; 3276 last_element = (sp_sview->base.u.buf.offset + 3277 sp_sview->base.u.buf.size) / elem_size - 1; 3278 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3279 const int x = CLAMP(v_i[j] + offset[0] + 3280 first_element, 3281 first_element, 3282 last_element); 3283 tx = get_texel_2d_no_border(sp_sview, addr, x, 0); 3284 for (c = 0; c < 4; c++) { 3285 rgba[c][j] = tx[c]; 3286 } 3287 } 3288 break; 3289 case PIPE_TEXTURE_1D: 3290 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3291 const int x = CLAMP(v_i[j] + offset[0], 0, width - 1); 3292 tx = get_texel_2d_no_border(sp_sview, addr, x, 3293 sp_sview->base.u.tex.first_layer); 3294 for (c = 0; c < 4; c++) { 3295 rgba[c][j] = tx[c]; 3296 } 3297 } 3298 break; 3299 case PIPE_TEXTURE_1D_ARRAY: 3300 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3301 const int x = CLAMP(v_i[j] + offset[0], 0, width - 1); 3302 const int y = CLAMP(v_j[j], sp_sview->base.u.tex.first_layer, 3303 sp_sview->base.u.tex.last_layer); 3304 tx = get_texel_2d_no_border(sp_sview, addr, x, y); 3305 for (c = 0; c < 4; c++) { 3306 rgba[c][j] = tx[c]; 3307 } 3308 } 3309 break; 3310 case PIPE_TEXTURE_2D: 3311 case PIPE_TEXTURE_RECT: 3312 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3313 const int x = CLAMP(v_i[j] + offset[0], 0, width - 1); 3314 const int y = CLAMP(v_j[j] + offset[1], 0, height - 1); 3315 tx = get_texel_3d_no_border(sp_sview, addr, x, y, 3316 sp_sview->base.u.tex.first_layer); 3317 for (c = 0; c < 4; c++) { 3318 rgba[c][j] = tx[c]; 3319 } 3320 } 3321 break; 3322 case PIPE_TEXTURE_2D_ARRAY: 3323 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3324 const int x = CLAMP(v_i[j] + offset[0], 0, width - 1); 3325 const int y = CLAMP(v_j[j] + offset[1], 0, height - 1); 3326 const int layer = CLAMP(v_k[j], sp_sview->base.u.tex.first_layer, 3327 sp_sview->base.u.tex.last_layer); 3328 tx = get_texel_3d_no_border(sp_sview, addr, x, y, layer); 3329 for (c = 0; c < 4; c++) { 3330 rgba[c][j] = tx[c]; 3331 } 3332 } 3333 break; 3334 case PIPE_TEXTURE_3D: 3335 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 3336 int x = CLAMP(v_i[j] + offset[0], 0, width - 1); 3337 int y = CLAMP(v_j[j] + offset[1], 0, height - 1); 3338 int z = CLAMP(v_k[j] + offset[2], 0, depth - 1); 3339 tx = get_texel_3d_no_border(sp_sview, addr, x, y, z); 3340 for (c = 0; c < 4; c++) { 3341 rgba[c][j] = tx[c]; 3342 } 3343 } 3344 break; 3345 case PIPE_TEXTURE_CUBE: /* TXF can't work on CUBE according to spec */ 3346 case PIPE_TEXTURE_CUBE_ARRAY: 3347 default: 3348 assert(!"Unknown or CUBE texture type in TXF processing\n"); 3349 break; 3350 } 3351 3352 if (sp_sview->need_swizzle) { 3353 float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; 3354 memcpy(rgba_temp, rgba, sizeof(rgba_temp)); 3355 do_swizzling(&sp_sview->base, rgba_temp, rgba); 3356 } 3357 } 3358 3359 3360 void * 3361 softpipe_create_sampler_state(struct pipe_context *pipe, 3362 const struct pipe_sampler_state *sampler) 3363 { 3364 struct sp_sampler *samp = CALLOC_STRUCT(sp_sampler); 3365 3366 samp->base = *sampler; 3367 3368 /* Note that (for instance) linear_texcoord_s and 3369 * nearest_texcoord_s may be active at the same time, if the 3370 * sampler min_img_filter differs from its mag_img_filter. 3371 */ 3372 if (sampler->normalized_coords) { 3373 samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s ); 3374 samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t ); 3375 samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r ); 3376 3377 samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s ); 3378 samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t ); 3379 samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r ); 3380 } 3381 else { 3382 samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s ); 3383 samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t ); 3384 samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r ); 3385 3386 samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s ); 3387 samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t ); 3388 samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r ); 3389 } 3390 3391 samp->min_img_filter = sampler->min_img_filter; 3392 3393 switch (sampler->min_mip_filter) { 3394 case PIPE_TEX_MIPFILTER_NONE: 3395 if (sampler->min_img_filter == sampler->mag_img_filter) 3396 samp->filter_funcs = &funcs_none_no_filter_select; 3397 else 3398 samp->filter_funcs = &funcs_none; 3399 break; 3400 3401 case PIPE_TEX_MIPFILTER_NEAREST: 3402 samp->filter_funcs = &funcs_nearest; 3403 break; 3404 3405 case PIPE_TEX_MIPFILTER_LINEAR: 3406 if (sampler->min_img_filter == sampler->mag_img_filter && 3407 sampler->normalized_coords && 3408 sampler->wrap_s == PIPE_TEX_WRAP_REPEAT && 3409 sampler->wrap_t == PIPE_TEX_WRAP_REPEAT && 3410 sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR && 3411 sampler->max_anisotropy <= 1) { 3412 samp->min_mag_equal_repeat_linear = TRUE; 3413 } 3414 samp->filter_funcs = &funcs_linear; 3415 3416 /* Anisotropic filtering extension. */ 3417 if (sampler->max_anisotropy > 1) { 3418 samp->filter_funcs = &funcs_linear_aniso; 3419 3420 /* Override min_img_filter: 3421 * min_img_filter needs to be set to NEAREST since we need to access 3422 * each texture pixel as it is and weight it later; using linear 3423 * filters will have incorrect results. 3424 * By setting the filter to NEAREST here, we can avoid calling the 3425 * generic img_filter_2d_nearest in the anisotropic filter function, 3426 * making it possible to use one of the accelerated implementations 3427 */ 3428 samp->min_img_filter = PIPE_TEX_FILTER_NEAREST; 3429 3430 /* on first access create the lookup table containing the filter weights. */ 3431 if (!weightLut) { 3432 create_filter_table(); 3433 } 3434 } 3435 break; 3436 } 3437 if (samp->min_img_filter == sampler->mag_img_filter) { 3438 samp->min_mag_equal = TRUE; 3439 } 3440 3441 return (void *)samp; 3442 } 3443 3444 3445 compute_lambda_func 3446 softpipe_get_lambda_func(const struct pipe_sampler_view *view, unsigned shader) 3447 { 3448 if (shader != PIPE_SHADER_FRAGMENT) 3449 return compute_lambda_vert; 3450 3451 switch (view->target) { 3452 case PIPE_BUFFER: 3453 case PIPE_TEXTURE_1D: 3454 case PIPE_TEXTURE_1D_ARRAY: 3455 return compute_lambda_1d; 3456 case PIPE_TEXTURE_2D: 3457 case PIPE_TEXTURE_2D_ARRAY: 3458 case PIPE_TEXTURE_RECT: 3459 case PIPE_TEXTURE_CUBE: 3460 case PIPE_TEXTURE_CUBE_ARRAY: 3461 return compute_lambda_2d; 3462 case PIPE_TEXTURE_3D: 3463 return compute_lambda_3d; 3464 default: 3465 assert(0); 3466 return compute_lambda_1d; 3467 } 3468 } 3469 3470 3471 struct pipe_sampler_view * 3472 softpipe_create_sampler_view(struct pipe_context *pipe, 3473 struct pipe_resource *resource, 3474 const struct pipe_sampler_view *templ) 3475 { 3476 struct sp_sampler_view *sview = CALLOC_STRUCT(sp_sampler_view); 3477 const struct softpipe_resource *spr = (struct softpipe_resource *)resource; 3478 3479 if (sview) { 3480 struct pipe_sampler_view *view = &sview->base; 3481 *view = *templ; 3482 view->reference.count = 1; 3483 view->texture = NULL; 3484 pipe_resource_reference(&view->texture, resource); 3485 view->context = pipe; 3486 3487 #ifdef DEBUG 3488 /* 3489 * This is possibly too lenient, but the primary reason is just 3490 * to catch state trackers which forget to initialize this, so 3491 * it only catches clearly impossible view targets. 3492 */ 3493 if (view->target != resource->target) { 3494 if (view->target == PIPE_TEXTURE_1D) 3495 assert(resource->target == PIPE_TEXTURE_1D_ARRAY); 3496 else if (view->target == PIPE_TEXTURE_1D_ARRAY) 3497 assert(resource->target == PIPE_TEXTURE_1D); 3498 else if (view->target == PIPE_TEXTURE_2D) 3499 assert(resource->target == PIPE_TEXTURE_2D_ARRAY || 3500 resource->target == PIPE_TEXTURE_CUBE || 3501 resource->target == PIPE_TEXTURE_CUBE_ARRAY); 3502 else if (view->target == PIPE_TEXTURE_2D_ARRAY) 3503 assert(resource->target == PIPE_TEXTURE_2D || 3504 resource->target == PIPE_TEXTURE_CUBE || 3505 resource->target == PIPE_TEXTURE_CUBE_ARRAY); 3506 else if (view->target == PIPE_TEXTURE_CUBE) 3507 assert(resource->target == PIPE_TEXTURE_CUBE_ARRAY || 3508 resource->target == PIPE_TEXTURE_2D_ARRAY); 3509 else if (view->target == PIPE_TEXTURE_CUBE_ARRAY) 3510 assert(resource->target == PIPE_TEXTURE_CUBE || 3511 resource->target == PIPE_TEXTURE_2D_ARRAY); 3512 else 3513 assert(0); 3514 } 3515 #endif 3516 3517 if (any_swizzle(view)) { 3518 sview->need_swizzle = TRUE; 3519 } 3520 3521 sview->need_cube_convert = (view->target == PIPE_TEXTURE_CUBE || 3522 view->target == PIPE_TEXTURE_CUBE_ARRAY); 3523 sview->pot2d = spr->pot && 3524 (view->target == PIPE_TEXTURE_2D || 3525 view->target == PIPE_TEXTURE_RECT); 3526 3527 sview->xpot = util_logbase2( resource->width0 ); 3528 sview->ypot = util_logbase2( resource->height0 ); 3529 } 3530 3531 return (struct pipe_sampler_view *) sview; 3532 } 3533 3534 3535 static inline const struct sp_tgsi_sampler * 3536 sp_tgsi_sampler_cast_c(const struct tgsi_sampler *sampler) 3537 { 3538 return (const struct sp_tgsi_sampler *)sampler; 3539 } 3540 3541 3542 static void 3543 sp_tgsi_get_dims(struct tgsi_sampler *tgsi_sampler, 3544 const unsigned sview_index, 3545 int level, int dims[4]) 3546 { 3547 const struct sp_tgsi_sampler *sp_samp = 3548 sp_tgsi_sampler_cast_c(tgsi_sampler); 3549 3550 assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); 3551 /* always have a view here but texture is NULL if no sampler view was set. */ 3552 if (!sp_samp->sp_sview[sview_index].base.texture) { 3553 dims[0] = dims[1] = dims[2] = dims[3] = 0; 3554 return; 3555 } 3556 sp_get_dims(&sp_samp->sp_sview[sview_index], level, dims); 3557 } 3558 3559 3560 static void 3561 sp_tgsi_get_samples(struct tgsi_sampler *tgsi_sampler, 3562 const unsigned sview_index, 3563 const unsigned sampler_index, 3564 const float s[TGSI_QUAD_SIZE], 3565 const float t[TGSI_QUAD_SIZE], 3566 const float p[TGSI_QUAD_SIZE], 3567 const float c0[TGSI_QUAD_SIZE], 3568 const float lod[TGSI_QUAD_SIZE], 3569 float derivs[3][2][TGSI_QUAD_SIZE], 3570 const int8_t offset[3], 3571 enum tgsi_sampler_control control, 3572 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 3573 { 3574 const struct sp_tgsi_sampler *sp_tgsi_samp = 3575 sp_tgsi_sampler_cast_c(tgsi_sampler); 3576 const struct sp_sampler_view *sp_sview; 3577 const struct sp_sampler *sp_samp; 3578 struct filter_args filt_args; 3579 3580 assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); 3581 assert(sampler_index < PIPE_MAX_SAMPLERS); 3582 assert(sp_tgsi_samp->sp_sampler[sampler_index]); 3583 3584 sp_sview = &sp_tgsi_samp->sp_sview[sview_index]; 3585 sp_samp = sp_tgsi_samp->sp_sampler[sampler_index]; 3586 /* always have a view here but texture is NULL if no sampler view was set. */ 3587 if (!sp_sview->base.texture) { 3588 int i, j; 3589 for (j = 0; j < TGSI_NUM_CHANNELS; j++) { 3590 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 3591 rgba[j][i] = 0.0f; 3592 } 3593 } 3594 return; 3595 } 3596 3597 filt_args.control = control; 3598 filt_args.offset = offset; 3599 3600 if (sp_sview->need_cube_convert) { 3601 float cs[TGSI_QUAD_SIZE]; 3602 float ct[TGSI_QUAD_SIZE]; 3603 float cp[TGSI_QUAD_SIZE]; 3604 uint faces[TGSI_QUAD_SIZE]; 3605 3606 convert_cube(sp_sview, sp_samp, s, t, p, c0, cs, ct, cp, faces); 3607 3608 filt_args.faces = faces; 3609 sample_mip(sp_sview, sp_samp, cs, ct, cp, c0, lod, &filt_args, rgba); 3610 } else { 3611 static const uint zero_faces[TGSI_QUAD_SIZE] = {0, 0, 0, 0}; 3612 3613 filt_args.faces = zero_faces; 3614 sample_mip(sp_sview, sp_samp, s, t, p, c0, lod, &filt_args, rgba); 3615 } 3616 } 3617 3618 static void 3619 sp_tgsi_query_lod(const struct tgsi_sampler *tgsi_sampler, 3620 const unsigned sview_index, 3621 const unsigned sampler_index, 3622 const float s[TGSI_QUAD_SIZE], 3623 const float t[TGSI_QUAD_SIZE], 3624 const float p[TGSI_QUAD_SIZE], 3625 const float c0[TGSI_QUAD_SIZE], 3626 const enum tgsi_sampler_control control, 3627 float mipmap[TGSI_QUAD_SIZE], 3628 float lod[TGSI_QUAD_SIZE]) 3629 { 3630 static const float lod_in[TGSI_QUAD_SIZE] = { 0.0, 0.0, 0.0, 0.0 }; 3631 3632 const struct sp_tgsi_sampler *sp_tgsi_samp = 3633 sp_tgsi_sampler_cast_c(tgsi_sampler); 3634 const struct sp_sampler_view *sp_sview; 3635 const struct sp_sampler *sp_samp; 3636 const struct sp_filter_funcs *funcs; 3637 int i; 3638 3639 assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); 3640 assert(sampler_index < PIPE_MAX_SAMPLERS); 3641 assert(sp_tgsi_samp->sp_sampler[sampler_index]); 3642 3643 sp_sview = &sp_tgsi_samp->sp_sview[sview_index]; 3644 sp_samp = sp_tgsi_samp->sp_sampler[sampler_index]; 3645 /* always have a view here but texture is NULL if no sampler view was 3646 * set. */ 3647 if (!sp_sview->base.texture) { 3648 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 3649 mipmap[i] = 0.0f; 3650 lod[i] = 0.0f; 3651 } 3652 return; 3653 } 3654 3655 if (sp_sview->need_cube_convert) { 3656 float cs[TGSI_QUAD_SIZE]; 3657 float ct[TGSI_QUAD_SIZE]; 3658 float cp[TGSI_QUAD_SIZE]; 3659 uint unused_faces[TGSI_QUAD_SIZE]; 3660 3661 convert_cube(sp_sview, sp_samp, s, t, p, c0, cs, ct, cp, unused_faces); 3662 compute_lambda_lod_unclamped(sp_sview, sp_samp, 3663 cs, ct, cp, lod_in, control, lod); 3664 } else { 3665 compute_lambda_lod_unclamped(sp_sview, sp_samp, 3666 s, t, p, lod_in, control, lod); 3667 } 3668 3669 get_filters(sp_sview, sp_samp, control, &funcs, NULL, NULL); 3670 funcs->relative_level(sp_sview, sp_samp, lod, mipmap); 3671 } 3672 3673 static void 3674 sp_tgsi_get_texel(struct tgsi_sampler *tgsi_sampler, 3675 const unsigned sview_index, 3676 const int i[TGSI_QUAD_SIZE], 3677 const int j[TGSI_QUAD_SIZE], const int k[TGSI_QUAD_SIZE], 3678 const int lod[TGSI_QUAD_SIZE], const int8_t offset[3], 3679 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 3680 { 3681 const struct sp_tgsi_sampler *sp_samp = 3682 sp_tgsi_sampler_cast_c(tgsi_sampler); 3683 3684 assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); 3685 /* always have a view here but texture is NULL if no sampler view was set. */ 3686 if (!sp_samp->sp_sview[sview_index].base.texture) { 3687 int i, j; 3688 for (j = 0; j < TGSI_NUM_CHANNELS; j++) { 3689 for (i = 0; i < TGSI_QUAD_SIZE; i++) { 3690 rgba[j][i] = 0.0f; 3691 } 3692 } 3693 return; 3694 } 3695 sp_get_texels(&sp_samp->sp_sview[sview_index], i, j, k, lod, offset, rgba); 3696 } 3697 3698 3699 struct sp_tgsi_sampler * 3700 sp_create_tgsi_sampler(void) 3701 { 3702 struct sp_tgsi_sampler *samp = CALLOC_STRUCT(sp_tgsi_sampler); 3703 if (!samp) 3704 return NULL; 3705 3706 samp->base.get_dims = sp_tgsi_get_dims; 3707 samp->base.get_samples = sp_tgsi_get_samples; 3708 samp->base.get_texel = sp_tgsi_get_texel; 3709 samp->base.query_lod = sp_tgsi_query_lod; 3710 3711 return samp; 3712 } 3713