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