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