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