1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.3 4 * 5 * Copyright (C) 1999-2008 Brian Paul 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 "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26 #include "main/glheader.h" 27 #include "main/context.h" 28 #include "main/colormac.h" 29 #include "main/imports.h" 30 #include "main/texobj.h" 31 #include "main/samplerobj.h" 32 33 #include "s_context.h" 34 #include "s_texfilter.h" 35 36 37 /* 38 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes 39 * see 1-pixel bands of improperly weighted linear-filtered textures. 40 * The tests/texwrap.c demo is a good test. 41 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. 42 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). 43 */ 44 #define FRAC(f) ((f) - IFLOOR(f)) 45 46 47 48 /** 49 * Linear interpolation macro 50 */ 51 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 52 53 54 /** 55 * Do 2D/biliner interpolation of float values. 56 * v00, v10, v01 and v11 are typically four texture samples in a square/box. 57 * a and b are the horizontal and vertical interpolants. 58 * It's important that this function is inlined when compiled with 59 * optimization! If we find that's not true on some systems, convert 60 * to a macro. 61 */ 62 static inline GLfloat 63 lerp_2d(GLfloat a, GLfloat b, 64 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 65 { 66 const GLfloat temp0 = LERP(a, v00, v10); 67 const GLfloat temp1 = LERP(a, v01, v11); 68 return LERP(b, temp0, temp1); 69 } 70 71 72 /** 73 * Do 3D/trilinear interpolation of float values. 74 * \sa lerp_2d 75 */ 76 static inline GLfloat 77 lerp_3d(GLfloat a, GLfloat b, GLfloat c, 78 GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, 79 GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111) 80 { 81 const GLfloat temp00 = LERP(a, v000, v100); 82 const GLfloat temp10 = LERP(a, v010, v110); 83 const GLfloat temp01 = LERP(a, v001, v101); 84 const GLfloat temp11 = LERP(a, v011, v111); 85 const GLfloat temp0 = LERP(b, temp00, temp10); 86 const GLfloat temp1 = LERP(b, temp01, temp11); 87 return LERP(c, temp0, temp1); 88 } 89 90 91 /** 92 * Do linear interpolation of colors. 93 */ 94 static inline void 95 lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4]) 96 { 97 result[0] = LERP(t, a[0], b[0]); 98 result[1] = LERP(t, a[1], b[1]); 99 result[2] = LERP(t, a[2], b[2]); 100 result[3] = LERP(t, a[3], b[3]); 101 } 102 103 104 /** 105 * Do bilinear interpolation of colors. 106 */ 107 static inline void 108 lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b, 109 const GLfloat t00[4], const GLfloat t10[4], 110 const GLfloat t01[4], const GLfloat t11[4]) 111 { 112 result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); 113 result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); 114 result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); 115 result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]); 116 } 117 118 119 /** 120 * Do trilinear interpolation of colors. 121 */ 122 static inline void 123 lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c, 124 const GLfloat t000[4], const GLfloat t100[4], 125 const GLfloat t010[4], const GLfloat t110[4], 126 const GLfloat t001[4], const GLfloat t101[4], 127 const GLfloat t011[4], const GLfloat t111[4]) 128 { 129 GLuint k; 130 /* compiler should unroll these short loops */ 131 for (k = 0; k < 4; k++) { 132 result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], 133 t001[k], t101[k], t011[k], t111[k]); 134 } 135 } 136 137 138 /** 139 * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the 140 * right results for A<0. Casting to A to be unsigned only works if B 141 * is a power of two. Adding a bias to A (which is a multiple of B) 142 * avoids the problems with A < 0 (for reasonable A) without using a 143 * conditional. 144 */ 145 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B)) 146 147 148 /** 149 * Used to compute texel locations for linear sampling. 150 * Input: 151 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER 152 * s = texcoord in [0,1] 153 * size = width (or height or depth) of texture 154 * Output: 155 * i0, i1 = returns two nearest texel indexes 156 * weight = returns blend factor between texels 157 */ 158 static inline void 159 linear_texel_locations(GLenum wrapMode, 160 const struct gl_texture_image *img, 161 GLint size, GLfloat s, 162 GLint *i0, GLint *i1, GLfloat *weight) 163 { 164 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 165 GLfloat u; 166 switch (wrapMode) { 167 case GL_REPEAT: 168 u = s * size - 0.5F; 169 if (swImg->_IsPowerOfTwo) { 170 *i0 = IFLOOR(u) & (size - 1); 171 *i1 = (*i0 + 1) & (size - 1); 172 } 173 else { 174 *i0 = REMAINDER(IFLOOR(u), size); 175 *i1 = REMAINDER(*i0 + 1, size); 176 } 177 break; 178 case GL_CLAMP_TO_EDGE: 179 if (s <= 0.0F) 180 u = 0.0F; 181 else if (s >= 1.0F) 182 u = (GLfloat) size; 183 else 184 u = s * size; 185 u -= 0.5F; 186 *i0 = IFLOOR(u); 187 *i1 = *i0 + 1; 188 if (*i0 < 0) 189 *i0 = 0; 190 if (*i1 >= (GLint) size) 191 *i1 = size - 1; 192 break; 193 case GL_CLAMP_TO_BORDER: 194 { 195 const GLfloat min = -1.0F / (2.0F * size); 196 const GLfloat max = 1.0F - min; 197 if (s <= min) 198 u = min * size; 199 else if (s >= max) 200 u = max * size; 201 else 202 u = s * size; 203 u -= 0.5F; 204 *i0 = IFLOOR(u); 205 *i1 = *i0 + 1; 206 } 207 break; 208 case GL_MIRRORED_REPEAT: 209 { 210 const GLint flr = IFLOOR(s); 211 if (flr & 1) 212 u = 1.0F - (s - (GLfloat) flr); 213 else 214 u = s - (GLfloat) flr; 215 u = (u * size) - 0.5F; 216 *i0 = IFLOOR(u); 217 *i1 = *i0 + 1; 218 if (*i0 < 0) 219 *i0 = 0; 220 if (*i1 >= (GLint) size) 221 *i1 = size - 1; 222 } 223 break; 224 case GL_MIRROR_CLAMP_EXT: 225 u = FABSF(s); 226 if (u >= 1.0F) 227 u = (GLfloat) size; 228 else 229 u *= size; 230 u -= 0.5F; 231 *i0 = IFLOOR(u); 232 *i1 = *i0 + 1; 233 break; 234 case GL_MIRROR_CLAMP_TO_EDGE_EXT: 235 u = FABSF(s); 236 if (u >= 1.0F) 237 u = (GLfloat) size; 238 else 239 u *= size; 240 u -= 0.5F; 241 *i0 = IFLOOR(u); 242 *i1 = *i0 + 1; 243 if (*i0 < 0) 244 *i0 = 0; 245 if (*i1 >= (GLint) size) 246 *i1 = size - 1; 247 break; 248 case GL_MIRROR_CLAMP_TO_BORDER_EXT: 249 { 250 const GLfloat min = -1.0F / (2.0F * size); 251 const GLfloat max = 1.0F - min; 252 u = FABSF(s); 253 if (u <= min) 254 u = min * size; 255 else if (u >= max) 256 u = max * size; 257 else 258 u *= size; 259 u -= 0.5F; 260 *i0 = IFLOOR(u); 261 *i1 = *i0 + 1; 262 } 263 break; 264 case GL_CLAMP: 265 if (s <= 0.0F) 266 u = 0.0F; 267 else if (s >= 1.0F) 268 u = (GLfloat) size; 269 else 270 u = s * size; 271 u -= 0.5F; 272 *i0 = IFLOOR(u); 273 *i1 = *i0 + 1; 274 break; 275 default: 276 _mesa_problem(NULL, "Bad wrap mode"); 277 u = 0.0F; 278 break; 279 } 280 *weight = FRAC(u); 281 } 282 283 284 /** 285 * Used to compute texel location for nearest sampling. 286 */ 287 static inline GLint 288 nearest_texel_location(GLenum wrapMode, 289 const struct gl_texture_image *img, 290 GLint size, GLfloat s) 291 { 292 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 293 GLint i; 294 295 switch (wrapMode) { 296 case GL_REPEAT: 297 /* s limited to [0,1) */ 298 /* i limited to [0,size-1] */ 299 i = IFLOOR(s * size); 300 if (swImg->_IsPowerOfTwo) 301 i &= (size - 1); 302 else 303 i = REMAINDER(i, size); 304 return i; 305 case GL_CLAMP_TO_EDGE: 306 { 307 /* s limited to [min,max] */ 308 /* i limited to [0, size-1] */ 309 const GLfloat min = 1.0F / (2.0F * size); 310 const GLfloat max = 1.0F - min; 311 if (s < min) 312 i = 0; 313 else if (s > max) 314 i = size - 1; 315 else 316 i = IFLOOR(s * size); 317 } 318 return i; 319 case GL_CLAMP_TO_BORDER: 320 { 321 /* s limited to [min,max] */ 322 /* i limited to [-1, size] */ 323 const GLfloat min = -1.0F / (2.0F * size); 324 const GLfloat max = 1.0F - min; 325 if (s <= min) 326 i = -1; 327 else if (s >= max) 328 i = size; 329 else 330 i = IFLOOR(s * size); 331 } 332 return i; 333 case GL_MIRRORED_REPEAT: 334 { 335 const GLfloat min = 1.0F / (2.0F * size); 336 const GLfloat max = 1.0F - min; 337 const GLint flr = IFLOOR(s); 338 GLfloat u; 339 if (flr & 1) 340 u = 1.0F - (s - (GLfloat) flr); 341 else 342 u = s - (GLfloat) flr; 343 if (u < min) 344 i = 0; 345 else if (u > max) 346 i = size - 1; 347 else 348 i = IFLOOR(u * size); 349 } 350 return i; 351 case GL_MIRROR_CLAMP_EXT: 352 { 353 /* s limited to [0,1] */ 354 /* i limited to [0,size-1] */ 355 const GLfloat u = FABSF(s); 356 if (u <= 0.0F) 357 i = 0; 358 else if (u >= 1.0F) 359 i = size - 1; 360 else 361 i = IFLOOR(u * size); 362 } 363 return i; 364 case GL_MIRROR_CLAMP_TO_EDGE_EXT: 365 { 366 /* s limited to [min,max] */ 367 /* i limited to [0, size-1] */ 368 const GLfloat min = 1.0F / (2.0F * size); 369 const GLfloat max = 1.0F - min; 370 const GLfloat u = FABSF(s); 371 if (u < min) 372 i = 0; 373 else if (u > max) 374 i = size - 1; 375 else 376 i = IFLOOR(u * size); 377 } 378 return i; 379 case GL_MIRROR_CLAMP_TO_BORDER_EXT: 380 { 381 /* s limited to [min,max] */ 382 /* i limited to [0, size-1] */ 383 const GLfloat min = -1.0F / (2.0F * size); 384 const GLfloat max = 1.0F - min; 385 const GLfloat u = FABSF(s); 386 if (u < min) 387 i = -1; 388 else if (u > max) 389 i = size; 390 else 391 i = IFLOOR(u * size); 392 } 393 return i; 394 case GL_CLAMP: 395 /* s limited to [0,1] */ 396 /* i limited to [0,size-1] */ 397 if (s <= 0.0F) 398 i = 0; 399 else if (s >= 1.0F) 400 i = size - 1; 401 else 402 i = IFLOOR(s * size); 403 return i; 404 default: 405 _mesa_problem(NULL, "Bad wrap mode"); 406 return 0; 407 } 408 } 409 410 411 /* Power of two image sizes only */ 412 static inline void 413 linear_repeat_texel_location(GLuint size, GLfloat s, 414 GLint *i0, GLint *i1, GLfloat *weight) 415 { 416 GLfloat u = s * size - 0.5F; 417 *i0 = IFLOOR(u) & (size - 1); 418 *i1 = (*i0 + 1) & (size - 1); 419 *weight = FRAC(u); 420 } 421 422 423 /** 424 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode. 425 */ 426 static inline GLint 427 clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max) 428 { 429 switch (wrapMode) { 430 case GL_CLAMP: 431 return IFLOOR( CLAMP(coord, 0.0F, max - 1) ); 432 case GL_CLAMP_TO_EDGE: 433 return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) ); 434 case GL_CLAMP_TO_BORDER: 435 return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) ); 436 default: 437 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest"); 438 return 0; 439 } 440 } 441 442 443 /** 444 * As above, but GL_LINEAR filtering. 445 */ 446 static inline void 447 clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, 448 GLint *i0out, GLint *i1out, GLfloat *weight) 449 { 450 GLfloat fcol; 451 GLint i0, i1; 452 switch (wrapMode) { 453 case GL_CLAMP: 454 /* Not exactly what the spec says, but it matches NVIDIA output */ 455 fcol = CLAMP(coord - 0.5F, 0.0F, max - 1); 456 i0 = IFLOOR(fcol); 457 i1 = i0 + 1; 458 break; 459 case GL_CLAMP_TO_EDGE: 460 fcol = CLAMP(coord, 0.5F, max - 0.5F); 461 fcol -= 0.5F; 462 i0 = IFLOOR(fcol); 463 i1 = i0 + 1; 464 if (i1 > max - 1) 465 i1 = max - 1; 466 break; 467 case GL_CLAMP_TO_BORDER: 468 fcol = CLAMP(coord, -0.5F, max + 0.5F); 469 fcol -= 0.5F; 470 i0 = IFLOOR(fcol); 471 i1 = i0 + 1; 472 break; 473 default: 474 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); 475 i0 = i1 = 0; 476 fcol = 0.0F; 477 break; 478 } 479 *i0out = i0; 480 *i1out = i1; 481 *weight = FRAC(fcol); 482 } 483 484 485 /** 486 * Compute slice/image to use for 1D or 2D array texture. 487 */ 488 static inline GLint 489 tex_array_slice(GLfloat coord, GLsizei size) 490 { 491 GLint slice = IFLOOR(coord + 0.5f); 492 slice = CLAMP(slice, 0, size - 1); 493 return slice; 494 } 495 496 497 /** 498 * Compute nearest integer texcoords for given texobj and coordinate. 499 * NOTE: only used for depth texture sampling. 500 */ 501 static inline void 502 nearest_texcoord(const struct gl_sampler_object *samp, 503 const struct gl_texture_object *texObj, 504 GLuint level, 505 const GLfloat texcoord[4], 506 GLint *i, GLint *j, GLint *k) 507 { 508 const struct gl_texture_image *img = texObj->Image[0][level]; 509 const GLint width = img->Width; 510 const GLint height = img->Height; 511 const GLint depth = img->Depth; 512 513 switch (texObj->Target) { 514 case GL_TEXTURE_RECTANGLE_ARB: 515 *i = clamp_rect_coord_nearest(samp->WrapS, texcoord[0], width); 516 *j = clamp_rect_coord_nearest(samp->WrapT, texcoord[1], height); 517 *k = 0; 518 break; 519 case GL_TEXTURE_1D: 520 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 521 *j = 0; 522 *k = 0; 523 break; 524 case GL_TEXTURE_2D: 525 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 526 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]); 527 *k = 0; 528 break; 529 case GL_TEXTURE_1D_ARRAY_EXT: 530 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 531 *j = tex_array_slice(texcoord[1], height); 532 *k = 0; 533 break; 534 case GL_TEXTURE_2D_ARRAY_EXT: 535 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 536 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]); 537 *k = tex_array_slice(texcoord[2], depth); 538 break; 539 default: 540 *i = *j = *k = 0; 541 break; 542 } 543 } 544 545 546 /** 547 * Compute linear integer texcoords for given texobj and coordinate. 548 * NOTE: only used for depth texture sampling. 549 */ 550 static inline void 551 linear_texcoord(const struct gl_sampler_object *samp, 552 const struct gl_texture_object *texObj, 553 GLuint level, 554 const GLfloat texcoord[4], 555 GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice, 556 GLfloat *wi, GLfloat *wj) 557 { 558 const struct gl_texture_image *img = texObj->Image[0][level]; 559 const GLint width = img->Width; 560 const GLint height = img->Height; 561 const GLint depth = img->Depth; 562 563 switch (texObj->Target) { 564 case GL_TEXTURE_RECTANGLE_ARB: 565 clamp_rect_coord_linear(samp->WrapS, texcoord[0], 566 width, i0, i1, wi); 567 clamp_rect_coord_linear(samp->WrapT, texcoord[1], 568 height, j0, j1, wj); 569 *slice = 0; 570 break; 571 572 case GL_TEXTURE_1D: 573 case GL_TEXTURE_2D: 574 linear_texel_locations(samp->WrapS, img, width, 575 texcoord[0], i0, i1, wi); 576 linear_texel_locations(samp->WrapT, img, height, 577 texcoord[1], j0, j1, wj); 578 *slice = 0; 579 break; 580 581 case GL_TEXTURE_1D_ARRAY_EXT: 582 linear_texel_locations(samp->WrapS, img, width, 583 texcoord[0], i0, i1, wi); 584 *j0 = tex_array_slice(texcoord[1], height); 585 *j1 = *j0; 586 *slice = 0; 587 break; 588 589 case GL_TEXTURE_2D_ARRAY_EXT: 590 linear_texel_locations(samp->WrapS, img, width, 591 texcoord[0], i0, i1, wi); 592 linear_texel_locations(samp->WrapT, img, height, 593 texcoord[1], j0, j1, wj); 594 *slice = tex_array_slice(texcoord[2], depth); 595 break; 596 597 default: 598 *slice = 0; 599 break; 600 } 601 } 602 603 604 605 /** 606 * For linear interpolation between mipmap levels N and N+1, this function 607 * computes N. 608 */ 609 static inline GLint 610 linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) 611 { 612 if (lambda < 0.0F) 613 return tObj->BaseLevel; 614 else if (lambda > tObj->_MaxLambda) 615 return (GLint) (tObj->BaseLevel + tObj->_MaxLambda); 616 else 617 return (GLint) (tObj->BaseLevel + lambda); 618 } 619 620 621 /** 622 * Compute the nearest mipmap level to take texels from. 623 */ 624 static inline GLint 625 nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) 626 { 627 GLfloat l; 628 GLint level; 629 if (lambda <= 0.5F) 630 l = 0.0F; 631 else if (lambda > tObj->_MaxLambda + 0.4999F) 632 l = tObj->_MaxLambda + 0.4999F; 633 else 634 l = lambda; 635 level = (GLint) (tObj->BaseLevel + l + 0.5F); 636 if (level > tObj->_MaxLevel) 637 level = tObj->_MaxLevel; 638 return level; 639 } 640 641 642 643 /* 644 * Bitflags for texture border color sampling. 645 */ 646 #define I0BIT 1 647 #define I1BIT 2 648 #define J0BIT 4 649 #define J1BIT 8 650 #define K0BIT 16 651 #define K1BIT 32 652 653 654 655 /** 656 * The lambda[] array values are always monotonic. Either the whole span 657 * will be minified, magnified, or split between the two. This function 658 * determines the subranges in [0, n-1] that are to be minified or magnified. 659 */ 660 static inline void 661 compute_min_mag_ranges(const struct gl_sampler_object *samp, 662 GLuint n, const GLfloat lambda[], 663 GLuint *minStart, GLuint *minEnd, 664 GLuint *magStart, GLuint *magEnd) 665 { 666 GLfloat minMagThresh; 667 668 /* we shouldn't be here if minfilter == magfilter */ 669 ASSERT(samp->MinFilter != samp->MagFilter); 670 671 /* This bit comes from the OpenGL spec: */ 672 if (samp->MagFilter == GL_LINEAR 673 && (samp->MinFilter == GL_NEAREST_MIPMAP_NEAREST || 674 samp->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { 675 minMagThresh = 0.5F; 676 } 677 else { 678 minMagThresh = 0.0F; 679 } 680 681 #if 0 682 /* DEBUG CODE: Verify that lambda[] is monotonic. 683 * We can't really use this because the inaccuracy in the LOG2 function 684 * causes this test to fail, yet the resulting texturing is correct. 685 */ 686 if (n > 1) { 687 GLuint i; 688 printf("lambda delta = %g\n", lambda[0] - lambda[n-1]); 689 if (lambda[0] >= lambda[n-1]) { /* decreasing */ 690 for (i = 0; i < n - 1; i++) { 691 ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10)); 692 } 693 } 694 else { /* increasing */ 695 for (i = 0; i < n - 1; i++) { 696 ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10)); 697 } 698 } 699 } 700 #endif /* DEBUG */ 701 702 if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) { 703 /* magnification for whole span */ 704 *magStart = 0; 705 *magEnd = n; 706 *minStart = *minEnd = 0; 707 } 708 else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) { 709 /* minification for whole span */ 710 *minStart = 0; 711 *minEnd = n; 712 *magStart = *magEnd = 0; 713 } 714 else { 715 /* a mix of minification and magnification */ 716 GLuint i; 717 if (lambda[0] > minMagThresh) { 718 /* start with minification */ 719 for (i = 1; i < n; i++) { 720 if (lambda[i] <= minMagThresh) 721 break; 722 } 723 *minStart = 0; 724 *minEnd = i; 725 *magStart = i; 726 *magEnd = n; 727 } 728 else { 729 /* start with magnification */ 730 for (i = 1; i < n; i++) { 731 if (lambda[i] > minMagThresh) 732 break; 733 } 734 *magStart = 0; 735 *magEnd = i; 736 *minStart = i; 737 *minEnd = n; 738 } 739 } 740 741 #if 0 742 /* Verify the min/mag Start/End values 743 * We don't use this either (see above) 744 */ 745 { 746 GLint i; 747 for (i = 0; i < n; i++) { 748 if (lambda[i] > minMagThresh) { 749 /* minification */ 750 ASSERT(i >= *minStart); 751 ASSERT(i < *minEnd); 752 } 753 else { 754 /* magnification */ 755 ASSERT(i >= *magStart); 756 ASSERT(i < *magEnd); 757 } 758 } 759 } 760 #endif 761 } 762 763 764 /** 765 * When we sample the border color, it must be interpreted according to 766 * the base texture format. Ex: if the texture base format it GL_ALPHA, 767 * we return (0,0,0,BorderAlpha). 768 */ 769 static inline void 770 get_border_color(const struct gl_sampler_object *samp, 771 const struct gl_texture_image *img, 772 GLfloat rgba[4]) 773 { 774 switch (img->_BaseFormat) { 775 case GL_RGB: 776 rgba[0] = samp->BorderColor.f[0]; 777 rgba[1] = samp->BorderColor.f[1]; 778 rgba[2] = samp->BorderColor.f[2]; 779 rgba[3] = 1.0F; 780 break; 781 case GL_ALPHA: 782 rgba[0] = rgba[1] = rgba[2] = 0.0; 783 rgba[3] = samp->BorderColor.f[3]; 784 break; 785 case GL_LUMINANCE: 786 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0]; 787 rgba[3] = 1.0; 788 break; 789 case GL_LUMINANCE_ALPHA: 790 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0]; 791 rgba[3] = samp->BorderColor.f[3]; 792 break; 793 case GL_INTENSITY: 794 rgba[0] = rgba[1] = rgba[2] = rgba[3] = samp->BorderColor.f[0]; 795 break; 796 default: 797 COPY_4V(rgba, samp->BorderColor.f); 798 break; 799 } 800 } 801 802 803 /** 804 * Put z into texel according to GL_DEPTH_MODE. 805 */ 806 static INLINE void 807 apply_depth_mode(GLenum depthMode, GLfloat z, GLfloat texel[4]) 808 { 809 switch (depthMode) { 810 case GL_LUMINANCE: 811 ASSIGN_4V(texel, z, z, z, 1.0F); 812 break; 813 case GL_INTENSITY: 814 ASSIGN_4V(texel, z, z, z, z); 815 break; 816 case GL_ALPHA: 817 ASSIGN_4V(texel, 0.0F, 0.0F, 0.0F, z); 818 break; 819 case GL_RED: 820 ASSIGN_4V(texel, z, 0.0F, 0.0F, 1.0F); 821 break; 822 default: 823 _mesa_problem(NULL, "Bad depth texture mode"); 824 } 825 } 826 827 828 /** 829 * Is the given texture a depth (or depth/stencil) texture? 830 */ 831 static GLboolean 832 is_depth_texture(const struct gl_texture_object *tObj) 833 { 834 GLenum format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; 835 return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT; 836 } 837 838 839 /**********************************************************************/ 840 /* 1-D Texture Sampling Functions */ 841 /**********************************************************************/ 842 843 /** 844 * Return the texture sample for coordinate (s) using GL_NEAREST filter. 845 */ 846 static inline void 847 sample_1d_nearest(struct gl_context *ctx, 848 const struct gl_sampler_object *samp, 849 const struct gl_texture_image *img, 850 const GLfloat texcoord[4], GLfloat rgba[4]) 851 { 852 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 853 const GLint width = img->Width2; /* without border, power of two */ 854 GLint i; 855 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 856 /* skip over the border, if any */ 857 i += img->Border; 858 if (i < 0 || i >= (GLint) img->Width) { 859 /* Need this test for GL_CLAMP_TO_BORDER mode */ 860 get_border_color(samp, img, rgba); 861 } 862 else { 863 swImg->FetchTexel(swImg, i, 0, 0, rgba); 864 } 865 } 866 867 868 /** 869 * Return the texture sample for coordinate (s) using GL_LINEAR filter. 870 */ 871 static inline void 872 sample_1d_linear(struct gl_context *ctx, 873 const struct gl_sampler_object *samp, 874 const struct gl_texture_image *img, 875 const GLfloat texcoord[4], GLfloat rgba[4]) 876 { 877 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 878 const GLint width = img->Width2; 879 GLint i0, i1; 880 GLbitfield useBorderColor = 0x0; 881 GLfloat a; 882 GLfloat t0[4], t1[4]; /* texels */ 883 884 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a); 885 886 if (img->Border) { 887 i0 += img->Border; 888 i1 += img->Border; 889 } 890 else { 891 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 892 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 893 } 894 895 /* fetch texel colors */ 896 if (useBorderColor & I0BIT) { 897 get_border_color(samp, img, t0); 898 } 899 else { 900 swImg->FetchTexel(swImg, i0, 0, 0, t0); 901 } 902 if (useBorderColor & I1BIT) { 903 get_border_color(samp, img, t1); 904 } 905 else { 906 swImg->FetchTexel(swImg, i1, 0, 0, t1); 907 } 908 909 lerp_rgba(rgba, a, t0, t1); 910 } 911 912 913 static void 914 sample_1d_nearest_mipmap_nearest(struct gl_context *ctx, 915 const struct gl_sampler_object *samp, 916 const struct gl_texture_object *tObj, 917 GLuint n, const GLfloat texcoord[][4], 918 const GLfloat lambda[], GLfloat rgba[][4]) 919 { 920 GLuint i; 921 ASSERT(lambda != NULL); 922 for (i = 0; i < n; i++) { 923 GLint level = nearest_mipmap_level(tObj, lambda[i]); 924 sample_1d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 925 } 926 } 927 928 929 static void 930 sample_1d_linear_mipmap_nearest(struct gl_context *ctx, 931 const struct gl_sampler_object *samp, 932 const struct gl_texture_object *tObj, 933 GLuint n, const GLfloat texcoord[][4], 934 const GLfloat lambda[], GLfloat rgba[][4]) 935 { 936 GLuint i; 937 ASSERT(lambda != NULL); 938 for (i = 0; i < n; i++) { 939 GLint level = nearest_mipmap_level(tObj, lambda[i]); 940 sample_1d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 941 } 942 } 943 944 945 static void 946 sample_1d_nearest_mipmap_linear(struct gl_context *ctx, 947 const struct gl_sampler_object *samp, 948 const struct gl_texture_object *tObj, 949 GLuint n, const GLfloat texcoord[][4], 950 const GLfloat lambda[], GLfloat rgba[][4]) 951 { 952 GLuint i; 953 ASSERT(lambda != NULL); 954 for (i = 0; i < n; i++) { 955 GLint level = linear_mipmap_level(tObj, lambda[i]); 956 if (level >= tObj->_MaxLevel) { 957 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 958 texcoord[i], rgba[i]); 959 } 960 else { 961 GLfloat t0[4], t1[4]; 962 const GLfloat f = FRAC(lambda[i]); 963 sample_1d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 964 sample_1d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 965 lerp_rgba(rgba[i], f, t0, t1); 966 } 967 } 968 } 969 970 971 static void 972 sample_1d_linear_mipmap_linear(struct gl_context *ctx, 973 const struct gl_sampler_object *samp, 974 const struct gl_texture_object *tObj, 975 GLuint n, const GLfloat texcoord[][4], 976 const GLfloat lambda[], GLfloat rgba[][4]) 977 { 978 GLuint i; 979 ASSERT(lambda != NULL); 980 for (i = 0; i < n; i++) { 981 GLint level = linear_mipmap_level(tObj, lambda[i]); 982 if (level >= tObj->_MaxLevel) { 983 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 984 texcoord[i], rgba[i]); 985 } 986 else { 987 GLfloat t0[4], t1[4]; 988 const GLfloat f = FRAC(lambda[i]); 989 sample_1d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 990 sample_1d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 991 lerp_rgba(rgba[i], f, t0, t1); 992 } 993 } 994 } 995 996 997 /** Sample 1D texture, nearest filtering for both min/magnification */ 998 static void 999 sample_nearest_1d( struct gl_context *ctx, 1000 const struct gl_sampler_object *samp, 1001 const struct gl_texture_object *tObj, GLuint n, 1002 const GLfloat texcoords[][4], const GLfloat lambda[], 1003 GLfloat rgba[][4] ) 1004 { 1005 GLuint i; 1006 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 1007 (void) lambda; 1008 for (i = 0; i < n; i++) { 1009 sample_1d_nearest(ctx, samp, image, texcoords[i], rgba[i]); 1010 } 1011 } 1012 1013 1014 /** Sample 1D texture, linear filtering for both min/magnification */ 1015 static void 1016 sample_linear_1d( struct gl_context *ctx, 1017 const struct gl_sampler_object *samp, 1018 const struct gl_texture_object *tObj, GLuint n, 1019 const GLfloat texcoords[][4], const GLfloat lambda[], 1020 GLfloat rgba[][4] ) 1021 { 1022 GLuint i; 1023 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 1024 (void) lambda; 1025 for (i = 0; i < n; i++) { 1026 sample_1d_linear(ctx, samp, image, texcoords[i], rgba[i]); 1027 } 1028 } 1029 1030 1031 /** Sample 1D texture, using lambda to choose between min/magnification */ 1032 static void 1033 sample_lambda_1d( struct gl_context *ctx, 1034 const struct gl_sampler_object *samp, 1035 const struct gl_texture_object *tObj, GLuint n, 1036 const GLfloat texcoords[][4], 1037 const GLfloat lambda[], GLfloat rgba[][4] ) 1038 { 1039 GLuint minStart, minEnd; /* texels with minification */ 1040 GLuint magStart, magEnd; /* texels with magnification */ 1041 GLuint i; 1042 1043 ASSERT(lambda != NULL); 1044 compute_min_mag_ranges(samp, n, lambda, 1045 &minStart, &minEnd, &magStart, &magEnd); 1046 1047 if (minStart < minEnd) { 1048 /* do the minified texels */ 1049 const GLuint m = minEnd - minStart; 1050 switch (samp->MinFilter) { 1051 case GL_NEAREST: 1052 for (i = minStart; i < minEnd; i++) 1053 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 1054 texcoords[i], rgba[i]); 1055 break; 1056 case GL_LINEAR: 1057 for (i = minStart; i < minEnd; i++) 1058 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 1059 texcoords[i], rgba[i]); 1060 break; 1061 case GL_NEAREST_MIPMAP_NEAREST: 1062 sample_1d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 1063 lambda + minStart, rgba + minStart); 1064 break; 1065 case GL_LINEAR_MIPMAP_NEAREST: 1066 sample_1d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 1067 lambda + minStart, rgba + minStart); 1068 break; 1069 case GL_NEAREST_MIPMAP_LINEAR: 1070 sample_1d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 1071 lambda + minStart, rgba + minStart); 1072 break; 1073 case GL_LINEAR_MIPMAP_LINEAR: 1074 sample_1d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 1075 lambda + minStart, rgba + minStart); 1076 break; 1077 default: 1078 _mesa_problem(ctx, "Bad min filter in sample_1d_texture"); 1079 return; 1080 } 1081 } 1082 1083 if (magStart < magEnd) { 1084 /* do the magnified texels */ 1085 switch (samp->MagFilter) { 1086 case GL_NEAREST: 1087 for (i = magStart; i < magEnd; i++) 1088 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 1089 texcoords[i], rgba[i]); 1090 break; 1091 case GL_LINEAR: 1092 for (i = magStart; i < magEnd; i++) 1093 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 1094 texcoords[i], rgba[i]); 1095 break; 1096 default: 1097 _mesa_problem(ctx, "Bad mag filter in sample_1d_texture"); 1098 return; 1099 } 1100 } 1101 } 1102 1103 1104 /**********************************************************************/ 1105 /* 2-D Texture Sampling Functions */ 1106 /**********************************************************************/ 1107 1108 1109 /** 1110 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. 1111 */ 1112 static inline void 1113 sample_2d_nearest(struct gl_context *ctx, 1114 const struct gl_sampler_object *samp, 1115 const struct gl_texture_image *img, 1116 const GLfloat texcoord[4], 1117 GLfloat rgba[]) 1118 { 1119 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 1120 const GLint width = img->Width2; /* without border, power of two */ 1121 const GLint height = img->Height2; /* without border, power of two */ 1122 GLint i, j; 1123 (void) ctx; 1124 1125 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 1126 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]); 1127 1128 /* skip over the border, if any */ 1129 i += img->Border; 1130 j += img->Border; 1131 1132 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) { 1133 /* Need this test for GL_CLAMP_TO_BORDER mode */ 1134 get_border_color(samp, img, rgba); 1135 } 1136 else { 1137 swImg->FetchTexel(swImg, i, j, 0, rgba); 1138 } 1139 } 1140 1141 1142 /** 1143 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. 1144 * New sampling code contributed by Lynn Quam <quam (at) ai.sri.com>. 1145 */ 1146 static inline void 1147 sample_2d_linear(struct gl_context *ctx, 1148 const struct gl_sampler_object *samp, 1149 const struct gl_texture_image *img, 1150 const GLfloat texcoord[4], 1151 GLfloat rgba[]) 1152 { 1153 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 1154 const GLint width = img->Width2; 1155 const GLint height = img->Height2; 1156 GLint i0, j0, i1, j1; 1157 GLbitfield useBorderColor = 0x0; 1158 GLfloat a, b; 1159 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ 1160 1161 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a); 1162 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b); 1163 1164 if (img->Border) { 1165 i0 += img->Border; 1166 i1 += img->Border; 1167 j0 += img->Border; 1168 j1 += img->Border; 1169 } 1170 else { 1171 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 1172 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 1173 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; 1174 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; 1175 } 1176 1177 /* fetch four texel colors */ 1178 if (useBorderColor & (I0BIT | J0BIT)) { 1179 get_border_color(samp, img, t00); 1180 } 1181 else { 1182 swImg->FetchTexel(swImg, i0, j0, 0, t00); 1183 } 1184 if (useBorderColor & (I1BIT | J0BIT)) { 1185 get_border_color(samp, img, t10); 1186 } 1187 else { 1188 swImg->FetchTexel(swImg, i1, j0, 0, t10); 1189 } 1190 if (useBorderColor & (I0BIT | J1BIT)) { 1191 get_border_color(samp, img, t01); 1192 } 1193 else { 1194 swImg->FetchTexel(swImg, i0, j1, 0, t01); 1195 } 1196 if (useBorderColor & (I1BIT | J1BIT)) { 1197 get_border_color(samp, img, t11); 1198 } 1199 else { 1200 swImg->FetchTexel(swImg, i1, j1, 0, t11); 1201 } 1202 1203 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); 1204 } 1205 1206 1207 /** 1208 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT. 1209 * We don't have to worry about the texture border. 1210 */ 1211 static inline void 1212 sample_2d_linear_repeat(struct gl_context *ctx, 1213 const struct gl_sampler_object *samp, 1214 const struct gl_texture_image *img, 1215 const GLfloat texcoord[4], 1216 GLfloat rgba[]) 1217 { 1218 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 1219 const GLint width = img->Width2; 1220 const GLint height = img->Height2; 1221 GLint i0, j0, i1, j1; 1222 GLfloat wi, wj; 1223 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ 1224 1225 (void) ctx; 1226 1227 ASSERT(samp->WrapS == GL_REPEAT); 1228 ASSERT(samp->WrapT == GL_REPEAT); 1229 ASSERT(img->Border == 0); 1230 ASSERT(swImg->_IsPowerOfTwo); 1231 1232 linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi); 1233 linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj); 1234 1235 swImg->FetchTexel(swImg, i0, j0, 0, t00); 1236 swImg->FetchTexel(swImg, i1, j0, 0, t10); 1237 swImg->FetchTexel(swImg, i0, j1, 0, t01); 1238 swImg->FetchTexel(swImg, i1, j1, 0, t11); 1239 1240 lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11); 1241 } 1242 1243 1244 static void 1245 sample_2d_nearest_mipmap_nearest(struct gl_context *ctx, 1246 const struct gl_sampler_object *samp, 1247 const struct gl_texture_object *tObj, 1248 GLuint n, const GLfloat texcoord[][4], 1249 const GLfloat lambda[], GLfloat rgba[][4]) 1250 { 1251 GLuint i; 1252 for (i = 0; i < n; i++) { 1253 GLint level = nearest_mipmap_level(tObj, lambda[i]); 1254 sample_2d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 1255 } 1256 } 1257 1258 1259 static void 1260 sample_2d_linear_mipmap_nearest(struct gl_context *ctx, 1261 const struct gl_sampler_object *samp, 1262 const struct gl_texture_object *tObj, 1263 GLuint n, const GLfloat texcoord[][4], 1264 const GLfloat lambda[], GLfloat rgba[][4]) 1265 { 1266 GLuint i; 1267 ASSERT(lambda != NULL); 1268 for (i = 0; i < n; i++) { 1269 GLint level = nearest_mipmap_level(tObj, lambda[i]); 1270 sample_2d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 1271 } 1272 } 1273 1274 1275 static void 1276 sample_2d_nearest_mipmap_linear(struct gl_context *ctx, 1277 const struct gl_sampler_object *samp, 1278 const struct gl_texture_object *tObj, 1279 GLuint n, const GLfloat texcoord[][4], 1280 const GLfloat lambda[], GLfloat rgba[][4]) 1281 { 1282 GLuint i; 1283 ASSERT(lambda != NULL); 1284 for (i = 0; i < n; i++) { 1285 GLint level = linear_mipmap_level(tObj, lambda[i]); 1286 if (level >= tObj->_MaxLevel) { 1287 sample_2d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 1288 texcoord[i], rgba[i]); 1289 } 1290 else { 1291 GLfloat t0[4], t1[4]; /* texels */ 1292 const GLfloat f = FRAC(lambda[i]); 1293 sample_2d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 1294 sample_2d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 1295 lerp_rgba(rgba[i], f, t0, t1); 1296 } 1297 } 1298 } 1299 1300 1301 static void 1302 sample_2d_linear_mipmap_linear( struct gl_context *ctx, 1303 const struct gl_sampler_object *samp, 1304 const struct gl_texture_object *tObj, 1305 GLuint n, const GLfloat texcoord[][4], 1306 const GLfloat lambda[], GLfloat rgba[][4] ) 1307 { 1308 GLuint i; 1309 ASSERT(lambda != NULL); 1310 for (i = 0; i < n; i++) { 1311 GLint level = linear_mipmap_level(tObj, lambda[i]); 1312 if (level >= tObj->_MaxLevel) { 1313 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 1314 texcoord[i], rgba[i]); 1315 } 1316 else { 1317 GLfloat t0[4], t1[4]; /* texels */ 1318 const GLfloat f = FRAC(lambda[i]); 1319 sample_2d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 1320 sample_2d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 1321 lerp_rgba(rgba[i], f, t0, t1); 1322 } 1323 } 1324 } 1325 1326 1327 static void 1328 sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, 1329 const struct gl_sampler_object *samp, 1330 const struct gl_texture_object *tObj, 1331 GLuint n, const GLfloat texcoord[][4], 1332 const GLfloat lambda[], GLfloat rgba[][4]) 1333 { 1334 GLuint i; 1335 ASSERT(lambda != NULL); 1336 ASSERT(samp->WrapS == GL_REPEAT); 1337 ASSERT(samp->WrapT == GL_REPEAT); 1338 for (i = 0; i < n; i++) { 1339 GLint level = linear_mipmap_level(tObj, lambda[i]); 1340 if (level >= tObj->_MaxLevel) { 1341 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 1342 texcoord[i], rgba[i]); 1343 } 1344 else { 1345 GLfloat t0[4], t1[4]; /* texels */ 1346 const GLfloat f = FRAC(lambda[i]); 1347 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level ], 1348 texcoord[i], t0); 1349 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level+1], 1350 texcoord[i], t1); 1351 lerp_rgba(rgba[i], f, t0, t1); 1352 } 1353 } 1354 } 1355 1356 1357 /** Sample 2D texture, nearest filtering for both min/magnification */ 1358 static void 1359 sample_nearest_2d(struct gl_context *ctx, 1360 const struct gl_sampler_object *samp, 1361 const struct gl_texture_object *tObj, GLuint n, 1362 const GLfloat texcoords[][4], 1363 const GLfloat lambda[], GLfloat rgba[][4]) 1364 { 1365 GLuint i; 1366 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 1367 (void) lambda; 1368 for (i = 0; i < n; i++) { 1369 sample_2d_nearest(ctx, samp, image, texcoords[i], rgba[i]); 1370 } 1371 } 1372 1373 1374 /** Sample 2D texture, linear filtering for both min/magnification */ 1375 static void 1376 sample_linear_2d(struct gl_context *ctx, 1377 const struct gl_sampler_object *samp, 1378 const struct gl_texture_object *tObj, GLuint n, 1379 const GLfloat texcoords[][4], 1380 const GLfloat lambda[], GLfloat rgba[][4]) 1381 { 1382 GLuint i; 1383 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 1384 const struct swrast_texture_image *swImg = swrast_texture_image_const(image); 1385 (void) lambda; 1386 if (samp->WrapS == GL_REPEAT && 1387 samp->WrapT == GL_REPEAT && 1388 swImg->_IsPowerOfTwo && 1389 image->Border == 0) { 1390 for (i = 0; i < n; i++) { 1391 sample_2d_linear_repeat(ctx, samp, image, texcoords[i], rgba[i]); 1392 } 1393 } 1394 else { 1395 for (i = 0; i < n; i++) { 1396 sample_2d_linear(ctx, samp, image, texcoords[i], rgba[i]); 1397 } 1398 } 1399 } 1400 1401 1402 /** 1403 * Optimized 2-D texture sampling: 1404 * S and T wrap mode == GL_REPEAT 1405 * GL_NEAREST min/mag filter 1406 * No border, 1407 * RowStride == Width, 1408 * Format = GL_RGB 1409 */ 1410 static void 1411 opt_sample_rgb_2d(struct gl_context *ctx, 1412 const struct gl_sampler_object *samp, 1413 const struct gl_texture_object *tObj, 1414 GLuint n, const GLfloat texcoords[][4], 1415 const GLfloat lambda[], GLfloat rgba[][4]) 1416 { 1417 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; 1418 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 1419 const GLfloat width = (GLfloat) img->Width; 1420 const GLfloat height = (GLfloat) img->Height; 1421 const GLint colMask = img->Width - 1; 1422 const GLint rowMask = img->Height - 1; 1423 const GLint shift = img->WidthLog2; 1424 GLuint k; 1425 (void) ctx; 1426 (void) lambda; 1427 ASSERT(samp->WrapS==GL_REPEAT); 1428 ASSERT(samp->WrapT==GL_REPEAT); 1429 ASSERT(img->Border==0); 1430 ASSERT(img->TexFormat == MESA_FORMAT_RGB888); 1431 ASSERT(swImg->_IsPowerOfTwo); 1432 (void) swImg; 1433 1434 for (k=0; k<n; k++) { 1435 GLint i = IFLOOR(texcoords[k][0] * width) & colMask; 1436 GLint j = IFLOOR(texcoords[k][1] * height) & rowMask; 1437 GLint pos = (j << shift) | i; 1438 GLubyte *texel = swImg->Map + 3 * pos; 1439 rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]); 1440 rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]); 1441 rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]); 1442 rgba[k][ACOMP] = 1.0F; 1443 } 1444 } 1445 1446 1447 /** 1448 * Optimized 2-D texture sampling: 1449 * S and T wrap mode == GL_REPEAT 1450 * GL_NEAREST min/mag filter 1451 * No border 1452 * RowStride == Width, 1453 * Format = GL_RGBA 1454 */ 1455 static void 1456 opt_sample_rgba_2d(struct gl_context *ctx, 1457 const struct gl_sampler_object *samp, 1458 const struct gl_texture_object *tObj, 1459 GLuint n, const GLfloat texcoords[][4], 1460 const GLfloat lambda[], GLfloat rgba[][4]) 1461 { 1462 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; 1463 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 1464 const GLfloat width = (GLfloat) img->Width; 1465 const GLfloat height = (GLfloat) img->Height; 1466 const GLint colMask = img->Width - 1; 1467 const GLint rowMask = img->Height - 1; 1468 const GLint shift = img->WidthLog2; 1469 GLuint i; 1470 (void) ctx; 1471 (void) lambda; 1472 ASSERT(samp->WrapS==GL_REPEAT); 1473 ASSERT(samp->WrapT==GL_REPEAT); 1474 ASSERT(img->Border==0); 1475 ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); 1476 ASSERT(swImg->_IsPowerOfTwo); 1477 (void) swImg; 1478 1479 for (i = 0; i < n; i++) { 1480 const GLint col = IFLOOR(texcoords[i][0] * width) & colMask; 1481 const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask; 1482 const GLint pos = (row << shift) | col; 1483 const GLuint texel = *((GLuint *) swImg->Map + pos); 1484 rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) ); 1485 rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff ); 1486 rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff ); 1487 rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff ); 1488 } 1489 } 1490 1491 1492 /** Sample 2D texture, using lambda to choose between min/magnification */ 1493 static void 1494 sample_lambda_2d(struct gl_context *ctx, 1495 const struct gl_sampler_object *samp, 1496 const struct gl_texture_object *tObj, 1497 GLuint n, const GLfloat texcoords[][4], 1498 const GLfloat lambda[], GLfloat rgba[][4]) 1499 { 1500 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; 1501 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg); 1502 GLuint minStart, minEnd; /* texels with minification */ 1503 GLuint magStart, magEnd; /* texels with magnification */ 1504 1505 const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT) 1506 && (samp->WrapT == GL_REPEAT) 1507 && (tImg->Border == 0 && (tImg->Width == swImg->RowStride)) 1508 && swImg->_IsPowerOfTwo; 1509 1510 ASSERT(lambda != NULL); 1511 compute_min_mag_ranges(samp, n, lambda, 1512 &minStart, &minEnd, &magStart, &magEnd); 1513 1514 if (minStart < minEnd) { 1515 /* do the minified texels */ 1516 const GLuint m = minEnd - minStart; 1517 switch (samp->MinFilter) { 1518 case GL_NEAREST: 1519 if (repeatNoBorderPOT) { 1520 switch (tImg->TexFormat) { 1521 case MESA_FORMAT_RGB888: 1522 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart, 1523 NULL, rgba + minStart); 1524 break; 1525 case MESA_FORMAT_RGBA8888: 1526 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart, 1527 NULL, rgba + minStart); 1528 break; 1529 default: 1530 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart, 1531 NULL, rgba + minStart ); 1532 } 1533 } 1534 else { 1535 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart, 1536 NULL, rgba + minStart); 1537 } 1538 break; 1539 case GL_LINEAR: 1540 sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart, 1541 NULL, rgba + minStart); 1542 break; 1543 case GL_NEAREST_MIPMAP_NEAREST: 1544 sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m, 1545 texcoords + minStart, 1546 lambda + minStart, rgba + minStart); 1547 break; 1548 case GL_LINEAR_MIPMAP_NEAREST: 1549 sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 1550 lambda + minStart, rgba + minStart); 1551 break; 1552 case GL_NEAREST_MIPMAP_LINEAR: 1553 sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 1554 lambda + minStart, rgba + minStart); 1555 break; 1556 case GL_LINEAR_MIPMAP_LINEAR: 1557 if (repeatNoBorderPOT) 1558 sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m, 1559 texcoords + minStart, lambda + minStart, rgba + minStart); 1560 else 1561 sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 1562 lambda + minStart, rgba + minStart); 1563 break; 1564 default: 1565 _mesa_problem(ctx, "Bad min filter in sample_2d_texture"); 1566 return; 1567 } 1568 } 1569 1570 if (magStart < magEnd) { 1571 /* do the magnified texels */ 1572 const GLuint m = magEnd - magStart; 1573 1574 switch (samp->MagFilter) { 1575 case GL_NEAREST: 1576 if (repeatNoBorderPOT) { 1577 switch (tImg->TexFormat) { 1578 case MESA_FORMAT_RGB888: 1579 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart, 1580 NULL, rgba + magStart); 1581 break; 1582 case MESA_FORMAT_RGBA8888: 1583 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart, 1584 NULL, rgba + magStart); 1585 break; 1586 default: 1587 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart, 1588 NULL, rgba + magStart ); 1589 } 1590 } 1591 else { 1592 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart, 1593 NULL, rgba + magStart); 1594 } 1595 break; 1596 case GL_LINEAR: 1597 sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart, 1598 NULL, rgba + magStart); 1599 break; 1600 default: 1601 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d"); 1602 break; 1603 } 1604 } 1605 } 1606 1607 1608 /* For anisotropic filtering */ 1609 #define WEIGHT_LUT_SIZE 1024 1610 1611 static GLfloat *weightLut = NULL; 1612 1613 /** 1614 * Creates the look-up table used to speed-up EWA sampling 1615 */ 1616 static void 1617 create_filter_table(void) 1618 { 1619 GLuint i; 1620 if (!weightLut) { 1621 weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat)); 1622 1623 for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { 1624 GLfloat alpha = 2; 1625 GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1); 1626 GLfloat weight = (GLfloat) exp(-alpha * r2); 1627 weightLut[i] = weight; 1628 } 1629 } 1630 } 1631 1632 1633 /** 1634 * Elliptical weighted average (EWA) filter for producing high quality 1635 * anisotropic filtered results. 1636 * Based on the Higher Quality Elliptical Weighted Avarage Filter 1637 * published by Paul S. Heckbert in his Master's Thesis 1638 * "Fundamentals of Texture Mapping and Image Warping" (1989) 1639 */ 1640 static void 1641 sample_2d_ewa(struct gl_context *ctx, 1642 const struct gl_sampler_object *samp, 1643 const struct gl_texture_object *tObj, 1644 const GLfloat texcoord[4], 1645 const GLfloat dudx, const GLfloat dvdx, 1646 const GLfloat dudy, const GLfloat dvdy, const GLint lod, 1647 GLfloat rgba[]) 1648 { 1649 GLint level = lod > 0 ? lod : 0; 1650 GLfloat scaling = 1.0 / (1 << level); 1651 const struct gl_texture_image *img = tObj->Image[0][level]; 1652 const struct gl_texture_image *mostDetailedImage = 1653 tObj->Image[0][tObj->BaseLevel]; 1654 const struct swrast_texture_image *swImg = 1655 swrast_texture_image_const(mostDetailedImage); 1656 GLfloat tex_u=-0.5 + texcoord[0] * swImg->WidthScale * scaling; 1657 GLfloat tex_v=-0.5 + texcoord[1] * swImg->HeightScale * scaling; 1658 1659 GLfloat ux = dudx * scaling; 1660 GLfloat vx = dvdx * scaling; 1661 GLfloat uy = dudy * scaling; 1662 GLfloat vy = dvdy * scaling; 1663 1664 /* compute ellipse coefficients to bound the region: 1665 * A*x*x + B*x*y + C*y*y = F. 1666 */ 1667 GLfloat A = vx*vx+vy*vy+1; 1668 GLfloat B = -2*(ux*vx+uy*vy); 1669 GLfloat C = ux*ux+uy*uy+1; 1670 GLfloat F = A*C-B*B/4.0; 1671 1672 /* check if it is an ellipse */ 1673 /* ASSERT(F > 0.0); */ 1674 1675 /* Compute the ellipse's (u,v) bounding box in texture space */ 1676 GLfloat d = -B*B+4.0*C*A; 1677 GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with */ 1678 GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */ 1679 1680 GLint u0 = floor(tex_u - box_u); 1681 GLint u1 = ceil (tex_u + box_u); 1682 GLint v0 = floor(tex_v - box_v); 1683 GLint v1 = ceil (tex_v + box_v); 1684 1685 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; 1686 GLfloat newCoord[2]; 1687 GLfloat den = 0.0F; 1688 GLfloat ddq; 1689 GLfloat U = u0 - tex_u; 1690 GLint v; 1691 1692 /* Scale ellipse formula to directly index the Filter Lookup Table. 1693 * i.e. scale so that F = WEIGHT_LUT_SIZE-1 1694 */ 1695 double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F; 1696 A *= formScale; 1697 B *= formScale; 1698 C *= formScale; 1699 /* F *= formScale; */ /* no need to scale F as we don't use it below here */ 1700 1701 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse 1702 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this 1703 * value, q, is less than F, we're inside the ellipse 1704 */ 1705 ddq = 2 * A; 1706 for (v = v0; v <= v1; ++v) { 1707 GLfloat V = v - tex_v; 1708 GLfloat dq = A * (2 * U + 1) + B * V; 1709 GLfloat q = (C * V + B * U) * V + A * U * U; 1710 1711 GLint u; 1712 for (u = u0; u <= u1; ++u) { 1713 /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */ 1714 if (q < WEIGHT_LUT_SIZE) { 1715 /* as a LUT is used, q must never be negative; 1716 * should not happen, though 1717 */ 1718 const GLint qClamped = q >= 0.0F ? q : 0; 1719 GLfloat weight = weightLut[qClamped]; 1720 1721 newCoord[0] = u / ((GLfloat) img->Width2); 1722 newCoord[1] = v / ((GLfloat) img->Height2); 1723 1724 sample_2d_nearest(ctx, samp, img, newCoord, rgba); 1725 num[0] += weight * rgba[0]; 1726 num[1] += weight * rgba[1]; 1727 num[2] += weight * rgba[2]; 1728 num[3] += weight * rgba[3]; 1729 1730 den += weight; 1731 } 1732 q += dq; 1733 dq += ddq; 1734 } 1735 } 1736 1737 if (den <= 0.0F) { 1738 /* Reaching this place would mean 1739 * that no pixels intersected the ellipse. 1740 * This should never happen because 1741 * the filter we use always 1742 * intersects at least one pixel. 1743 */ 1744 1745 /*rgba[0]=0; 1746 rgba[1]=0; 1747 rgba[2]=0; 1748 rgba[3]=0;*/ 1749 /* not enough pixels in resampling, resort to direct interpolation */ 1750 sample_2d_linear(ctx, samp, img, texcoord, rgba); 1751 return; 1752 } 1753 1754 rgba[0] = num[0] / den; 1755 rgba[1] = num[1] / den; 1756 rgba[2] = num[2] / den; 1757 rgba[3] = num[3] / den; 1758 } 1759 1760 1761 /** 1762 * Anisotropic filtering using footprint assembly as outlined in the 1763 * EXT_texture_filter_anisotropic spec: 1764 * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt 1765 * Faster than EWA but has less quality (more aliasing effects) 1766 */ 1767 static void 1768 sample_2d_footprint(struct gl_context *ctx, 1769 const struct gl_sampler_object *samp, 1770 const struct gl_texture_object *tObj, 1771 const GLfloat texcoord[4], 1772 const GLfloat dudx, const GLfloat dvdx, 1773 const GLfloat dudy, const GLfloat dvdy, const GLint lod, 1774 GLfloat rgba[]) 1775 { 1776 GLint level = lod > 0 ? lod : 0; 1777 GLfloat scaling = 1.0F / (1 << level); 1778 const struct gl_texture_image *img = tObj->Image[0][level]; 1779 1780 GLfloat ux = dudx * scaling; 1781 GLfloat vx = dvdx * scaling; 1782 GLfloat uy = dudy * scaling; 1783 GLfloat vy = dvdy * scaling; 1784 1785 GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */ 1786 GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */ 1787 1788 GLint numSamples; 1789 GLfloat ds; 1790 GLfloat dt; 1791 1792 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; 1793 GLfloat newCoord[2]; 1794 GLint s; 1795 1796 /* Calculate the per anisotropic sample offsets in s,t space. */ 1797 if (Px2 > Py2) { 1798 numSamples = ceil(SQRTF(Px2)); 1799 ds = ux / ((GLfloat) img->Width2); 1800 dt = vx / ((GLfloat) img->Height2); 1801 } 1802 else { 1803 numSamples = ceil(SQRTF(Py2)); 1804 ds = uy / ((GLfloat) img->Width2); 1805 dt = vy / ((GLfloat) img->Height2); 1806 } 1807 1808 for (s = 0; s<numSamples; s++) { 1809 newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5); 1810 newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5); 1811 1812 sample_2d_linear(ctx, samp, img, newCoord, rgba); 1813 num[0] += rgba[0]; 1814 num[1] += rgba[1]; 1815 num[2] += rgba[2]; 1816 num[3] += rgba[3]; 1817 } 1818 1819 rgba[0] = num[0] / numSamples; 1820 rgba[1] = num[1] / numSamples; 1821 rgba[2] = num[2] / numSamples; 1822 rgba[3] = num[3] / numSamples; 1823 } 1824 1825 1826 /** 1827 * Returns the index of the specified texture object in the 1828 * gl_context texture unit array. 1829 */ 1830 static inline GLuint 1831 texture_unit_index(const struct gl_context *ctx, 1832 const struct gl_texture_object *tObj) 1833 { 1834 const GLuint maxUnit 1835 = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1; 1836 GLuint u; 1837 1838 /* XXX CoordUnits vs. ImageUnits */ 1839 for (u = 0; u < maxUnit; u++) { 1840 if (ctx->Texture.Unit[u]._Current == tObj) 1841 break; /* found */ 1842 } 1843 if (u >= maxUnit) 1844 u = 0; /* not found, use 1st one; should never happen */ 1845 1846 return u; 1847 } 1848 1849 1850 /** 1851 * Sample 2D texture using an anisotropic filter. 1852 * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain 1853 * the lambda float array but a "hidden" SWspan struct which is required 1854 * by this function but is not available in the texture_sample_func signature. 1855 * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how 1856 * this function is called. 1857 */ 1858 static void 1859 sample_lambda_2d_aniso(struct gl_context *ctx, 1860 const struct gl_sampler_object *samp, 1861 const struct gl_texture_object *tObj, 1862 GLuint n, const GLfloat texcoords[][4], 1863 const GLfloat lambda_iso[], GLfloat rgba[][4]) 1864 { 1865 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; 1866 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg); 1867 const GLfloat maxEccentricity = 1868 samp->MaxAnisotropy * samp->MaxAnisotropy; 1869 1870 /* re-calculate the lambda values so that they are usable with anisotropic 1871 * filtering 1872 */ 1873 SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */ 1874 1875 /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span) 1876 * in swrast/s_span.c 1877 */ 1878 1879 /* find the texture unit index by looking up the current texture object 1880 * from the context list of available texture objects. 1881 */ 1882 const GLuint u = texture_unit_index(ctx, tObj); 1883 const GLuint attr = FRAG_ATTRIB_TEX0 + u; 1884 GLfloat texW, texH; 1885 1886 const GLfloat dsdx = span->attrStepX[attr][0]; 1887 const GLfloat dsdy = span->attrStepY[attr][0]; 1888 const GLfloat dtdx = span->attrStepX[attr][1]; 1889 const GLfloat dtdy = span->attrStepY[attr][1]; 1890 const GLfloat dqdx = span->attrStepX[attr][3]; 1891 const GLfloat dqdy = span->attrStepY[attr][3]; 1892 GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; 1893 GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; 1894 GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; 1895 1896 /* from swrast/s_texcombine.c _swrast_texture_span */ 1897 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; 1898 const GLboolean adjustLOD = 1899 (texUnit->LodBias + samp->LodBias != 0.0F) 1900 || (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0); 1901 1902 GLuint i; 1903 1904 /* on first access create the lookup table containing the filter weights. */ 1905 if (!weightLut) { 1906 create_filter_table(); 1907 } 1908 1909 texW = swImg->WidthScale; 1910 texH = swImg->HeightScale; 1911 1912 for (i = 0; i < n; i++) { 1913 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); 1914 1915 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ); 1916 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ); 1917 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ); 1918 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ); 1919 1920 /* note: instead of working with Px and Py, we will use the 1921 * squared length instead, to avoid sqrt. 1922 */ 1923 GLfloat Px2 = dudx * dudx + dvdx * dvdx; 1924 GLfloat Py2 = dudy * dudy + dvdy * dvdy; 1925 1926 GLfloat Pmax2; 1927 GLfloat Pmin2; 1928 GLfloat e; 1929 GLfloat lod; 1930 1931 s += dsdx; 1932 t += dtdx; 1933 q += dqdx; 1934 1935 if (Px2 < Py2) { 1936 Pmax2 = Py2; 1937 Pmin2 = Px2; 1938 } 1939 else { 1940 Pmax2 = Px2; 1941 Pmin2 = Py2; 1942 } 1943 1944 /* if the eccentricity of the ellipse is too big, scale up the shorter 1945 * of the two vectors to limit the maximum amount of work per pixel 1946 */ 1947 e = Pmax2 / Pmin2; 1948 if (e > maxEccentricity) { 1949 /* GLfloat s=e / maxEccentricity; 1950 minor[0] *= s; 1951 minor[1] *= s; 1952 Pmin2 *= s; */ 1953 Pmin2 = Pmax2 / maxEccentricity; 1954 } 1955 1956 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid 1957 * this since 0.5*log(x) = log(sqrt(x)) 1958 */ 1959 lod = 0.5 * LOG2(Pmin2); 1960 1961 if (adjustLOD) { 1962 /* from swrast/s_texcombine.c _swrast_texture_span */ 1963 if (texUnit->LodBias + samp->LodBias != 0.0F) { 1964 /* apply LOD bias, but don't clamp yet */ 1965 const GLfloat bias = 1966 CLAMP(texUnit->LodBias + samp->LodBias, 1967 -ctx->Const.MaxTextureLodBias, 1968 ctx->Const.MaxTextureLodBias); 1969 lod += bias; 1970 1971 if (samp->MinLod != -1000.0 || 1972 samp->MaxLod != 1000.0) { 1973 /* apply LOD clamping to lambda */ 1974 lod = CLAMP(lod, samp->MinLod, samp->MaxLod); 1975 } 1976 } 1977 } 1978 1979 /* If the ellipse covers the whole image, we can 1980 * simply return the average of the whole image. 1981 */ 1982 if (lod >= tObj->_MaxLevel) { 1983 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 1984 texcoords[i], rgba[i]); 1985 } 1986 else { 1987 /* don't bother interpolating between multiple LODs; it doesn't 1988 * seem to be worth the extra running time. 1989 */ 1990 sample_2d_ewa(ctx, samp, tObj, texcoords[i], 1991 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); 1992 1993 /* unused: */ 1994 (void) sample_2d_footprint; 1995 /* 1996 sample_2d_footprint(ctx, tObj, texcoords[i], 1997 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); 1998 */ 1999 } 2000 } 2001 } 2002 2003 2004 2005 /**********************************************************************/ 2006 /* 3-D Texture Sampling Functions */ 2007 /**********************************************************************/ 2008 2009 /** 2010 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. 2011 */ 2012 static inline void 2013 sample_3d_nearest(struct gl_context *ctx, 2014 const struct gl_sampler_object *samp, 2015 const struct gl_texture_image *img, 2016 const GLfloat texcoord[4], 2017 GLfloat rgba[4]) 2018 { 2019 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2020 const GLint width = img->Width2; /* without border, power of two */ 2021 const GLint height = img->Height2; /* without border, power of two */ 2022 const GLint depth = img->Depth2; /* without border, power of two */ 2023 GLint i, j, k; 2024 (void) ctx; 2025 2026 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 2027 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]); 2028 k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]); 2029 2030 if (i < 0 || i >= (GLint) img->Width || 2031 j < 0 || j >= (GLint) img->Height || 2032 k < 0 || k >= (GLint) img->Depth) { 2033 /* Need this test for GL_CLAMP_TO_BORDER mode */ 2034 get_border_color(samp, img, rgba); 2035 } 2036 else { 2037 swImg->FetchTexel(swImg, i, j, k, rgba); 2038 } 2039 } 2040 2041 2042 /** 2043 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. 2044 */ 2045 static void 2046 sample_3d_linear(struct gl_context *ctx, 2047 const struct gl_sampler_object *samp, 2048 const struct gl_texture_image *img, 2049 const GLfloat texcoord[4], 2050 GLfloat rgba[4]) 2051 { 2052 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2053 const GLint width = img->Width2; 2054 const GLint height = img->Height2; 2055 const GLint depth = img->Depth2; 2056 GLint i0, j0, k0, i1, j1, k1; 2057 GLbitfield useBorderColor = 0x0; 2058 GLfloat a, b, c; 2059 GLfloat t000[4], t010[4], t001[4], t011[4]; 2060 GLfloat t100[4], t110[4], t101[4], t111[4]; 2061 2062 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a); 2063 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b); 2064 linear_texel_locations(samp->WrapR, img, depth, texcoord[2], &k0, &k1, &c); 2065 2066 if (img->Border) { 2067 i0 += img->Border; 2068 i1 += img->Border; 2069 j0 += img->Border; 2070 j1 += img->Border; 2071 k0 += img->Border; 2072 k1 += img->Border; 2073 } 2074 else { 2075 /* check if sampling texture border color */ 2076 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 2077 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 2078 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; 2079 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; 2080 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; 2081 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; 2082 } 2083 2084 /* Fetch texels */ 2085 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { 2086 get_border_color(samp, img, t000); 2087 } 2088 else { 2089 swImg->FetchTexel(swImg, i0, j0, k0, t000); 2090 } 2091 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { 2092 get_border_color(samp, img, t100); 2093 } 2094 else { 2095 swImg->FetchTexel(swImg, i1, j0, k0, t100); 2096 } 2097 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { 2098 get_border_color(samp, img, t010); 2099 } 2100 else { 2101 swImg->FetchTexel(swImg, i0, j1, k0, t010); 2102 } 2103 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { 2104 get_border_color(samp, img, t110); 2105 } 2106 else { 2107 swImg->FetchTexel(swImg, i1, j1, k0, t110); 2108 } 2109 2110 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { 2111 get_border_color(samp, img, t001); 2112 } 2113 else { 2114 swImg->FetchTexel(swImg, i0, j0, k1, t001); 2115 } 2116 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { 2117 get_border_color(samp, img, t101); 2118 } 2119 else { 2120 swImg->FetchTexel(swImg, i1, j0, k1, t101); 2121 } 2122 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { 2123 get_border_color(samp, img, t011); 2124 } 2125 else { 2126 swImg->FetchTexel(swImg, i0, j1, k1, t011); 2127 } 2128 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { 2129 get_border_color(samp, img, t111); 2130 } 2131 else { 2132 swImg->FetchTexel(swImg, i1, j1, k1, t111); 2133 } 2134 2135 /* trilinear interpolation of samples */ 2136 lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111); 2137 } 2138 2139 2140 static void 2141 sample_3d_nearest_mipmap_nearest(struct gl_context *ctx, 2142 const struct gl_sampler_object *samp, 2143 const struct gl_texture_object *tObj, 2144 GLuint n, const GLfloat texcoord[][4], 2145 const GLfloat lambda[], GLfloat rgba[][4] ) 2146 { 2147 GLuint i; 2148 for (i = 0; i < n; i++) { 2149 GLint level = nearest_mipmap_level(tObj, lambda[i]); 2150 sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 2151 } 2152 } 2153 2154 2155 static void 2156 sample_3d_linear_mipmap_nearest(struct gl_context *ctx, 2157 const struct gl_sampler_object *samp, 2158 const struct gl_texture_object *tObj, 2159 GLuint n, const GLfloat texcoord[][4], 2160 const GLfloat lambda[], GLfloat rgba[][4]) 2161 { 2162 GLuint i; 2163 ASSERT(lambda != NULL); 2164 for (i = 0; i < n; i++) { 2165 GLint level = nearest_mipmap_level(tObj, lambda[i]); 2166 sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]); 2167 } 2168 } 2169 2170 2171 static void 2172 sample_3d_nearest_mipmap_linear(struct gl_context *ctx, 2173 const struct gl_sampler_object *samp, 2174 const struct gl_texture_object *tObj, 2175 GLuint n, const GLfloat texcoord[][4], 2176 const GLfloat lambda[], GLfloat rgba[][4]) 2177 { 2178 GLuint i; 2179 ASSERT(lambda != NULL); 2180 for (i = 0; i < n; i++) { 2181 GLint level = linear_mipmap_level(tObj, lambda[i]); 2182 if (level >= tObj->_MaxLevel) { 2183 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 2184 texcoord[i], rgba[i]); 2185 } 2186 else { 2187 GLfloat t0[4], t1[4]; /* texels */ 2188 const GLfloat f = FRAC(lambda[i]); 2189 sample_3d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 2190 sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 2191 lerp_rgba(rgba[i], f, t0, t1); 2192 } 2193 } 2194 } 2195 2196 2197 static void 2198 sample_3d_linear_mipmap_linear(struct gl_context *ctx, 2199 const struct gl_sampler_object *samp, 2200 const struct gl_texture_object *tObj, 2201 GLuint n, const GLfloat texcoord[][4], 2202 const GLfloat lambda[], GLfloat rgba[][4]) 2203 { 2204 GLuint i; 2205 ASSERT(lambda != NULL); 2206 for (i = 0; i < n; i++) { 2207 GLint level = linear_mipmap_level(tObj, lambda[i]); 2208 if (level >= tObj->_MaxLevel) { 2209 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 2210 texcoord[i], rgba[i]); 2211 } 2212 else { 2213 GLfloat t0[4], t1[4]; /* texels */ 2214 const GLfloat f = FRAC(lambda[i]); 2215 sample_3d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 2216 sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 2217 lerp_rgba(rgba[i], f, t0, t1); 2218 } 2219 } 2220 } 2221 2222 2223 /** Sample 3D texture, nearest filtering for both min/magnification */ 2224 static void 2225 sample_nearest_3d(struct gl_context *ctx, 2226 const struct gl_sampler_object *samp, 2227 const struct gl_texture_object *tObj, GLuint n, 2228 const GLfloat texcoords[][4], const GLfloat lambda[], 2229 GLfloat rgba[][4]) 2230 { 2231 GLuint i; 2232 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 2233 (void) lambda; 2234 for (i = 0; i < n; i++) { 2235 sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]); 2236 } 2237 } 2238 2239 2240 /** Sample 3D texture, linear filtering for both min/magnification */ 2241 static void 2242 sample_linear_3d(struct gl_context *ctx, 2243 const struct gl_sampler_object *samp, 2244 const struct gl_texture_object *tObj, GLuint n, 2245 const GLfloat texcoords[][4], 2246 const GLfloat lambda[], GLfloat rgba[][4]) 2247 { 2248 GLuint i; 2249 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 2250 (void) lambda; 2251 for (i = 0; i < n; i++) { 2252 sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]); 2253 } 2254 } 2255 2256 2257 /** Sample 3D texture, using lambda to choose between min/magnification */ 2258 static void 2259 sample_lambda_3d(struct gl_context *ctx, 2260 const struct gl_sampler_object *samp, 2261 const struct gl_texture_object *tObj, GLuint n, 2262 const GLfloat texcoords[][4], const GLfloat lambda[], 2263 GLfloat rgba[][4]) 2264 { 2265 GLuint minStart, minEnd; /* texels with minification */ 2266 GLuint magStart, magEnd; /* texels with magnification */ 2267 GLuint i; 2268 2269 ASSERT(lambda != NULL); 2270 compute_min_mag_ranges(samp, n, lambda, 2271 &minStart, &minEnd, &magStart, &magEnd); 2272 2273 if (minStart < minEnd) { 2274 /* do the minified texels */ 2275 GLuint m = minEnd - minStart; 2276 switch (samp->MinFilter) { 2277 case GL_NEAREST: 2278 for (i = minStart; i < minEnd; i++) 2279 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 2280 texcoords[i], rgba[i]); 2281 break; 2282 case GL_LINEAR: 2283 for (i = minStart; i < minEnd; i++) 2284 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 2285 texcoords[i], rgba[i]); 2286 break; 2287 case GL_NEAREST_MIPMAP_NEAREST: 2288 sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 2289 lambda + minStart, rgba + minStart); 2290 break; 2291 case GL_LINEAR_MIPMAP_NEAREST: 2292 sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 2293 lambda + minStart, rgba + minStart); 2294 break; 2295 case GL_NEAREST_MIPMAP_LINEAR: 2296 sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 2297 lambda + minStart, rgba + minStart); 2298 break; 2299 case GL_LINEAR_MIPMAP_LINEAR: 2300 sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 2301 lambda + minStart, rgba + minStart); 2302 break; 2303 default: 2304 _mesa_problem(ctx, "Bad min filter in sample_3d_texture"); 2305 return; 2306 } 2307 } 2308 2309 if (magStart < magEnd) { 2310 /* do the magnified texels */ 2311 switch (samp->MagFilter) { 2312 case GL_NEAREST: 2313 for (i = magStart; i < magEnd; i++) 2314 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 2315 texcoords[i], rgba[i]); 2316 break; 2317 case GL_LINEAR: 2318 for (i = magStart; i < magEnd; i++) 2319 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 2320 texcoords[i], rgba[i]); 2321 break; 2322 default: 2323 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture"); 2324 return; 2325 } 2326 } 2327 } 2328 2329 2330 /**********************************************************************/ 2331 /* Texture Cube Map Sampling Functions */ 2332 /**********************************************************************/ 2333 2334 /** 2335 * Choose one of six sides of a texture cube map given the texture 2336 * coord (rx,ry,rz). Return pointer to corresponding array of texture 2337 * images. 2338 */ 2339 static const struct gl_texture_image ** 2340 choose_cube_face(const struct gl_texture_object *texObj, 2341 const GLfloat texcoord[4], GLfloat newCoord[4]) 2342 { 2343 /* 2344 major axis 2345 direction target sc tc ma 2346 ---------- ------------------------------- --- --- --- 2347 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx 2348 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx 2349 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry 2350 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry 2351 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz 2352 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz 2353 */ 2354 const GLfloat rx = texcoord[0]; 2355 const GLfloat ry = texcoord[1]; 2356 const GLfloat rz = texcoord[2]; 2357 const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz); 2358 GLuint face; 2359 GLfloat sc, tc, ma; 2360 2361 if (arx >= ary && arx >= arz) { 2362 if (rx >= 0.0F) { 2363 face = FACE_POS_X; 2364 sc = -rz; 2365 tc = -ry; 2366 ma = arx; 2367 } 2368 else { 2369 face = FACE_NEG_X; 2370 sc = rz; 2371 tc = -ry; 2372 ma = arx; 2373 } 2374 } 2375 else if (ary >= arx && ary >= arz) { 2376 if (ry >= 0.0F) { 2377 face = FACE_POS_Y; 2378 sc = rx; 2379 tc = rz; 2380 ma = ary; 2381 } 2382 else { 2383 face = FACE_NEG_Y; 2384 sc = rx; 2385 tc = -rz; 2386 ma = ary; 2387 } 2388 } 2389 else { 2390 if (rz > 0.0F) { 2391 face = FACE_POS_Z; 2392 sc = rx; 2393 tc = -ry; 2394 ma = arz; 2395 } 2396 else { 2397 face = FACE_NEG_Z; 2398 sc = -rx; 2399 tc = -ry; 2400 ma = arz; 2401 } 2402 } 2403 2404 { 2405 const float ima = 1.0F / ma; 2406 newCoord[0] = ( sc * ima + 1.0F ) * 0.5F; 2407 newCoord[1] = ( tc * ima + 1.0F ) * 0.5F; 2408 } 2409 2410 return (const struct gl_texture_image **) texObj->Image[face]; 2411 } 2412 2413 2414 static void 2415 sample_nearest_cube(struct gl_context *ctx, 2416 const struct gl_sampler_object *samp, 2417 const struct gl_texture_object *tObj, GLuint n, 2418 const GLfloat texcoords[][4], const GLfloat lambda[], 2419 GLfloat rgba[][4]) 2420 { 2421 GLuint i; 2422 (void) lambda; 2423 for (i = 0; i < n; i++) { 2424 const struct gl_texture_image **images; 2425 GLfloat newCoord[4]; 2426 images = choose_cube_face(tObj, texcoords[i], newCoord); 2427 sample_2d_nearest(ctx, samp, images[tObj->BaseLevel], 2428 newCoord, rgba[i]); 2429 } 2430 if (is_depth_texture(tObj)) { 2431 for (i = 0; i < n; i++) { 2432 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2433 } 2434 } 2435 } 2436 2437 2438 static void 2439 sample_linear_cube(struct gl_context *ctx, 2440 const struct gl_sampler_object *samp, 2441 const struct gl_texture_object *tObj, GLuint n, 2442 const GLfloat texcoords[][4], 2443 const GLfloat lambda[], GLfloat rgba[][4]) 2444 { 2445 GLuint i; 2446 (void) lambda; 2447 for (i = 0; i < n; i++) { 2448 const struct gl_texture_image **images; 2449 GLfloat newCoord[4]; 2450 images = choose_cube_face(tObj, texcoords[i], newCoord); 2451 sample_2d_linear(ctx, samp, images[tObj->BaseLevel], 2452 newCoord, rgba[i]); 2453 } 2454 if (is_depth_texture(tObj)) { 2455 for (i = 0; i < n; i++) { 2456 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2457 } 2458 } 2459 } 2460 2461 2462 static void 2463 sample_cube_nearest_mipmap_nearest(struct gl_context *ctx, 2464 const struct gl_sampler_object *samp, 2465 const struct gl_texture_object *tObj, 2466 GLuint n, const GLfloat texcoord[][4], 2467 const GLfloat lambda[], GLfloat rgba[][4]) 2468 { 2469 GLuint i; 2470 ASSERT(lambda != NULL); 2471 for (i = 0; i < n; i++) { 2472 const struct gl_texture_image **images; 2473 GLfloat newCoord[4]; 2474 GLint level; 2475 images = choose_cube_face(tObj, texcoord[i], newCoord); 2476 2477 /* XXX we actually need to recompute lambda here based on the newCoords. 2478 * But we would need the texcoords of adjacent fragments to compute that 2479 * properly, and we don't have those here. 2480 * For now, do an approximation: subtracting 1 from the chosen mipmap 2481 * level seems to work in some test cases. 2482 * The same adjustment is done in the next few functions. 2483 */ 2484 level = nearest_mipmap_level(tObj, lambda[i]); 2485 level = MAX2(level - 1, 0); 2486 2487 sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]); 2488 } 2489 if (is_depth_texture(tObj)) { 2490 for (i = 0; i < n; i++) { 2491 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2492 } 2493 } 2494 } 2495 2496 2497 static void 2498 sample_cube_linear_mipmap_nearest(struct gl_context *ctx, 2499 const struct gl_sampler_object *samp, 2500 const struct gl_texture_object *tObj, 2501 GLuint n, const GLfloat texcoord[][4], 2502 const GLfloat lambda[], GLfloat rgba[][4]) 2503 { 2504 GLuint i; 2505 ASSERT(lambda != NULL); 2506 for (i = 0; i < n; i++) { 2507 const struct gl_texture_image **images; 2508 GLfloat newCoord[4]; 2509 GLint level = nearest_mipmap_level(tObj, lambda[i]); 2510 level = MAX2(level - 1, 0); /* see comment above */ 2511 images = choose_cube_face(tObj, texcoord[i], newCoord); 2512 sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]); 2513 } 2514 if (is_depth_texture(tObj)) { 2515 for (i = 0; i < n; i++) { 2516 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2517 } 2518 } 2519 } 2520 2521 2522 static void 2523 sample_cube_nearest_mipmap_linear(struct gl_context *ctx, 2524 const struct gl_sampler_object *samp, 2525 const struct gl_texture_object *tObj, 2526 GLuint n, const GLfloat texcoord[][4], 2527 const GLfloat lambda[], GLfloat rgba[][4]) 2528 { 2529 GLuint i; 2530 ASSERT(lambda != NULL); 2531 for (i = 0; i < n; i++) { 2532 const struct gl_texture_image **images; 2533 GLfloat newCoord[4]; 2534 GLint level = linear_mipmap_level(tObj, lambda[i]); 2535 level = MAX2(level - 1, 0); /* see comment above */ 2536 images = choose_cube_face(tObj, texcoord[i], newCoord); 2537 if (level >= tObj->_MaxLevel) { 2538 sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel], 2539 newCoord, rgba[i]); 2540 } 2541 else { 2542 GLfloat t0[4], t1[4]; /* texels */ 2543 const GLfloat f = FRAC(lambda[i]); 2544 sample_2d_nearest(ctx, samp, images[level ], newCoord, t0); 2545 sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1); 2546 lerp_rgba(rgba[i], f, t0, t1); 2547 } 2548 } 2549 if (is_depth_texture(tObj)) { 2550 for (i = 0; i < n; i++) { 2551 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2552 } 2553 } 2554 } 2555 2556 2557 static void 2558 sample_cube_linear_mipmap_linear(struct gl_context *ctx, 2559 const struct gl_sampler_object *samp, 2560 const struct gl_texture_object *tObj, 2561 GLuint n, const GLfloat texcoord[][4], 2562 const GLfloat lambda[], GLfloat rgba[][4]) 2563 { 2564 GLuint i; 2565 ASSERT(lambda != NULL); 2566 for (i = 0; i < n; i++) { 2567 const struct gl_texture_image **images; 2568 GLfloat newCoord[4]; 2569 GLint level = linear_mipmap_level(tObj, lambda[i]); 2570 level = MAX2(level - 1, 0); /* see comment above */ 2571 images = choose_cube_face(tObj, texcoord[i], newCoord); 2572 if (level >= tObj->_MaxLevel) { 2573 sample_2d_linear(ctx, samp, images[tObj->_MaxLevel], 2574 newCoord, rgba[i]); 2575 } 2576 else { 2577 GLfloat t0[4], t1[4]; 2578 const GLfloat f = FRAC(lambda[i]); 2579 sample_2d_linear(ctx, samp, images[level ], newCoord, t0); 2580 sample_2d_linear(ctx, samp, images[level+1], newCoord, t1); 2581 lerp_rgba(rgba[i], f, t0, t1); 2582 } 2583 } 2584 if (is_depth_texture(tObj)) { 2585 for (i = 0; i < n; i++) { 2586 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]); 2587 } 2588 } 2589 } 2590 2591 2592 /** Sample cube texture, using lambda to choose between min/magnification */ 2593 static void 2594 sample_lambda_cube(struct gl_context *ctx, 2595 const struct gl_sampler_object *samp, 2596 const struct gl_texture_object *tObj, GLuint n, 2597 const GLfloat texcoords[][4], const GLfloat lambda[], 2598 GLfloat rgba[][4]) 2599 { 2600 GLuint minStart, minEnd; /* texels with minification */ 2601 GLuint magStart, magEnd; /* texels with magnification */ 2602 2603 ASSERT(lambda != NULL); 2604 compute_min_mag_ranges(samp, n, lambda, 2605 &minStart, &minEnd, &magStart, &magEnd); 2606 2607 if (minStart < minEnd) { 2608 /* do the minified texels */ 2609 const GLuint m = minEnd - minStart; 2610 switch (samp->MinFilter) { 2611 case GL_NEAREST: 2612 sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart, 2613 lambda + minStart, rgba + minStart); 2614 break; 2615 case GL_LINEAR: 2616 sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart, 2617 lambda + minStart, rgba + minStart); 2618 break; 2619 case GL_NEAREST_MIPMAP_NEAREST: 2620 sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m, 2621 texcoords + minStart, 2622 lambda + minStart, rgba + minStart); 2623 break; 2624 case GL_LINEAR_MIPMAP_NEAREST: 2625 sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m, 2626 texcoords + minStart, 2627 lambda + minStart, rgba + minStart); 2628 break; 2629 case GL_NEAREST_MIPMAP_LINEAR: 2630 sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m, 2631 texcoords + minStart, 2632 lambda + minStart, rgba + minStart); 2633 break; 2634 case GL_LINEAR_MIPMAP_LINEAR: 2635 sample_cube_linear_mipmap_linear(ctx, samp, tObj, m, 2636 texcoords + minStart, 2637 lambda + minStart, rgba + minStart); 2638 break; 2639 default: 2640 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube"); 2641 break; 2642 } 2643 } 2644 2645 if (magStart < magEnd) { 2646 /* do the magnified texels */ 2647 const GLuint m = magEnd - magStart; 2648 switch (samp->MagFilter) { 2649 case GL_NEAREST: 2650 sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart, 2651 lambda + magStart, rgba + magStart); 2652 break; 2653 case GL_LINEAR: 2654 sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart, 2655 lambda + magStart, rgba + magStart); 2656 break; 2657 default: 2658 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube"); 2659 break; 2660 } 2661 } 2662 } 2663 2664 2665 /**********************************************************************/ 2666 /* Texture Rectangle Sampling Functions */ 2667 /**********************************************************************/ 2668 2669 2670 static void 2671 sample_nearest_rect(struct gl_context *ctx, 2672 const struct gl_sampler_object *samp, 2673 const struct gl_texture_object *tObj, GLuint n, 2674 const GLfloat texcoords[][4], const GLfloat lambda[], 2675 GLfloat rgba[][4]) 2676 { 2677 const struct gl_texture_image *img = tObj->Image[0][0]; 2678 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2679 const GLint width = img->Width; 2680 const GLint height = img->Height; 2681 GLuint i; 2682 2683 (void) ctx; 2684 (void) lambda; 2685 2686 ASSERT(samp->WrapS == GL_CLAMP || 2687 samp->WrapS == GL_CLAMP_TO_EDGE || 2688 samp->WrapS == GL_CLAMP_TO_BORDER); 2689 ASSERT(samp->WrapT == GL_CLAMP || 2690 samp->WrapT == GL_CLAMP_TO_EDGE || 2691 samp->WrapT == GL_CLAMP_TO_BORDER); 2692 2693 for (i = 0; i < n; i++) { 2694 GLint row, col; 2695 col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width); 2696 row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height); 2697 if (col < 0 || col >= width || row < 0 || row >= height) 2698 get_border_color(samp, img, rgba[i]); 2699 else 2700 swImg->FetchTexel(swImg, col, row, 0, rgba[i]); 2701 } 2702 } 2703 2704 2705 static void 2706 sample_linear_rect(struct gl_context *ctx, 2707 const struct gl_sampler_object *samp, 2708 const struct gl_texture_object *tObj, GLuint n, 2709 const GLfloat texcoords[][4], 2710 const GLfloat lambda[], GLfloat rgba[][4]) 2711 { 2712 const struct gl_texture_image *img = tObj->Image[0][0]; 2713 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2714 const GLint width = img->Width; 2715 const GLint height = img->Height; 2716 GLuint i; 2717 2718 (void) ctx; 2719 (void) lambda; 2720 2721 ASSERT(samp->WrapS == GL_CLAMP || 2722 samp->WrapS == GL_CLAMP_TO_EDGE || 2723 samp->WrapS == GL_CLAMP_TO_BORDER); 2724 ASSERT(samp->WrapT == GL_CLAMP || 2725 samp->WrapT == GL_CLAMP_TO_EDGE || 2726 samp->WrapT == GL_CLAMP_TO_BORDER); 2727 2728 for (i = 0; i < n; i++) { 2729 GLint i0, j0, i1, j1; 2730 GLfloat t00[4], t01[4], t10[4], t11[4]; 2731 GLfloat a, b; 2732 GLbitfield useBorderColor = 0x0; 2733 2734 clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width, 2735 &i0, &i1, &a); 2736 clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height, 2737 &j0, &j1, &b); 2738 2739 /* compute integer rows/columns */ 2740 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 2741 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 2742 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; 2743 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; 2744 2745 /* get four texel samples */ 2746 if (useBorderColor & (I0BIT | J0BIT)) 2747 get_border_color(samp, img, t00); 2748 else 2749 swImg->FetchTexel(swImg, i0, j0, 0, t00); 2750 2751 if (useBorderColor & (I1BIT | J0BIT)) 2752 get_border_color(samp, img, t10); 2753 else 2754 swImg->FetchTexel(swImg, i1, j0, 0, t10); 2755 2756 if (useBorderColor & (I0BIT | J1BIT)) 2757 get_border_color(samp, img, t01); 2758 else 2759 swImg->FetchTexel(swImg, i0, j1, 0, t01); 2760 2761 if (useBorderColor & (I1BIT | J1BIT)) 2762 get_border_color(samp, img, t11); 2763 else 2764 swImg->FetchTexel(swImg, i1, j1, 0, t11); 2765 2766 lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11); 2767 } 2768 } 2769 2770 2771 /** Sample Rect texture, using lambda to choose between min/magnification */ 2772 static void 2773 sample_lambda_rect(struct gl_context *ctx, 2774 const struct gl_sampler_object *samp, 2775 const struct gl_texture_object *tObj, GLuint n, 2776 const GLfloat texcoords[][4], const GLfloat lambda[], 2777 GLfloat rgba[][4]) 2778 { 2779 GLuint minStart, minEnd, magStart, magEnd; 2780 2781 /* We only need lambda to decide between minification and magnification. 2782 * There is no mipmapping with rectangular textures. 2783 */ 2784 compute_min_mag_ranges(samp, n, lambda, 2785 &minStart, &minEnd, &magStart, &magEnd); 2786 2787 if (minStart < minEnd) { 2788 if (samp->MinFilter == GL_NEAREST) { 2789 sample_nearest_rect(ctx, samp, tObj, minEnd - minStart, 2790 texcoords + minStart, NULL, rgba + minStart); 2791 } 2792 else { 2793 sample_linear_rect(ctx, samp, tObj, minEnd - minStart, 2794 texcoords + minStart, NULL, rgba + minStart); 2795 } 2796 } 2797 if (magStart < magEnd) { 2798 if (samp->MagFilter == GL_NEAREST) { 2799 sample_nearest_rect(ctx, samp, tObj, magEnd - magStart, 2800 texcoords + magStart, NULL, rgba + magStart); 2801 } 2802 else { 2803 sample_linear_rect(ctx, samp, tObj, magEnd - magStart, 2804 texcoords + magStart, NULL, rgba + magStart); 2805 } 2806 } 2807 } 2808 2809 2810 /**********************************************************************/ 2811 /* 2D Texture Array Sampling Functions */ 2812 /**********************************************************************/ 2813 2814 /** 2815 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. 2816 */ 2817 static void 2818 sample_2d_array_nearest(struct gl_context *ctx, 2819 const struct gl_sampler_object *samp, 2820 const struct gl_texture_image *img, 2821 const GLfloat texcoord[4], 2822 GLfloat rgba[4]) 2823 { 2824 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2825 const GLint width = img->Width2; /* without border, power of two */ 2826 const GLint height = img->Height2; /* without border, power of two */ 2827 const GLint depth = img->Depth; 2828 GLint i, j; 2829 GLint array; 2830 (void) ctx; 2831 2832 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 2833 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]); 2834 array = tex_array_slice(texcoord[2], depth); 2835 2836 if (i < 0 || i >= (GLint) img->Width || 2837 j < 0 || j >= (GLint) img->Height || 2838 array < 0 || array >= (GLint) img->Depth) { 2839 /* Need this test for GL_CLAMP_TO_BORDER mode */ 2840 get_border_color(samp, img, rgba); 2841 } 2842 else { 2843 swImg->FetchTexel(swImg, i, j, array, rgba); 2844 } 2845 } 2846 2847 2848 /** 2849 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. 2850 */ 2851 static void 2852 sample_2d_array_linear(struct gl_context *ctx, 2853 const struct gl_sampler_object *samp, 2854 const struct gl_texture_image *img, 2855 const GLfloat texcoord[4], 2856 GLfloat rgba[4]) 2857 { 2858 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 2859 const GLint width = img->Width2; 2860 const GLint height = img->Height2; 2861 const GLint depth = img->Depth; 2862 GLint i0, j0, i1, j1; 2863 GLint array; 2864 GLbitfield useBorderColor = 0x0; 2865 GLfloat a, b; 2866 GLfloat t00[4], t01[4], t10[4], t11[4]; 2867 2868 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a); 2869 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b); 2870 array = tex_array_slice(texcoord[2], depth); 2871 2872 if (array < 0 || array >= depth) { 2873 COPY_4V(rgba, samp->BorderColor.f); 2874 } 2875 else { 2876 if (img->Border) { 2877 i0 += img->Border; 2878 i1 += img->Border; 2879 j0 += img->Border; 2880 j1 += img->Border; 2881 } 2882 else { 2883 /* check if sampling texture border color */ 2884 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 2885 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 2886 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; 2887 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; 2888 } 2889 2890 /* Fetch texels */ 2891 if (useBorderColor & (I0BIT | J0BIT)) { 2892 get_border_color(samp, img, t00); 2893 } 2894 else { 2895 swImg->FetchTexel(swImg, i0, j0, array, t00); 2896 } 2897 if (useBorderColor & (I1BIT | J0BIT)) { 2898 get_border_color(samp, img, t10); 2899 } 2900 else { 2901 swImg->FetchTexel(swImg, i1, j0, array, t10); 2902 } 2903 if (useBorderColor & (I0BIT | J1BIT)) { 2904 get_border_color(samp, img, t01); 2905 } 2906 else { 2907 swImg->FetchTexel(swImg, i0, j1, array, t01); 2908 } 2909 if (useBorderColor & (I1BIT | J1BIT)) { 2910 get_border_color(samp, img, t11); 2911 } 2912 else { 2913 swImg->FetchTexel(swImg, i1, j1, array, t11); 2914 } 2915 2916 /* trilinear interpolation of samples */ 2917 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); 2918 } 2919 } 2920 2921 2922 static void 2923 sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx, 2924 const struct gl_sampler_object *samp, 2925 const struct gl_texture_object *tObj, 2926 GLuint n, const GLfloat texcoord[][4], 2927 const GLfloat lambda[], GLfloat rgba[][4]) 2928 { 2929 GLuint i; 2930 for (i = 0; i < n; i++) { 2931 GLint level = nearest_mipmap_level(tObj, lambda[i]); 2932 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], 2933 rgba[i]); 2934 } 2935 } 2936 2937 2938 static void 2939 sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx, 2940 const struct gl_sampler_object *samp, 2941 const struct gl_texture_object *tObj, 2942 GLuint n, const GLfloat texcoord[][4], 2943 const GLfloat lambda[], GLfloat rgba[][4]) 2944 { 2945 GLuint i; 2946 ASSERT(lambda != NULL); 2947 for (i = 0; i < n; i++) { 2948 GLint level = nearest_mipmap_level(tObj, lambda[i]); 2949 sample_2d_array_linear(ctx, samp, tObj->Image[0][level], 2950 texcoord[i], rgba[i]); 2951 } 2952 } 2953 2954 2955 static void 2956 sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx, 2957 const struct gl_sampler_object *samp, 2958 const struct gl_texture_object *tObj, 2959 GLuint n, const GLfloat texcoord[][4], 2960 const GLfloat lambda[], GLfloat rgba[][4]) 2961 { 2962 GLuint i; 2963 ASSERT(lambda != NULL); 2964 for (i = 0; i < n; i++) { 2965 GLint level = linear_mipmap_level(tObj, lambda[i]); 2966 if (level >= tObj->_MaxLevel) { 2967 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 2968 texcoord[i], rgba[i]); 2969 } 2970 else { 2971 GLfloat t0[4], t1[4]; /* texels */ 2972 const GLfloat f = FRAC(lambda[i]); 2973 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level ], 2974 texcoord[i], t0); 2975 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1], 2976 texcoord[i], t1); 2977 lerp_rgba(rgba[i], f, t0, t1); 2978 } 2979 } 2980 } 2981 2982 2983 static void 2984 sample_2d_array_linear_mipmap_linear(struct gl_context *ctx, 2985 const struct gl_sampler_object *samp, 2986 const struct gl_texture_object *tObj, 2987 GLuint n, const GLfloat texcoord[][4], 2988 const GLfloat lambda[], GLfloat rgba[][4]) 2989 { 2990 GLuint i; 2991 ASSERT(lambda != NULL); 2992 for (i = 0; i < n; i++) { 2993 GLint level = linear_mipmap_level(tObj, lambda[i]); 2994 if (level >= tObj->_MaxLevel) { 2995 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 2996 texcoord[i], rgba[i]); 2997 } 2998 else { 2999 GLfloat t0[4], t1[4]; /* texels */ 3000 const GLfloat f = FRAC(lambda[i]); 3001 sample_2d_array_linear(ctx, samp, tObj->Image[0][level ], 3002 texcoord[i], t0); 3003 sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1], 3004 texcoord[i], t1); 3005 lerp_rgba(rgba[i], f, t0, t1); 3006 } 3007 } 3008 } 3009 3010 3011 /** Sample 2D Array texture, nearest filtering for both min/magnification */ 3012 static void 3013 sample_nearest_2d_array(struct gl_context *ctx, 3014 const struct gl_sampler_object *samp, 3015 const struct gl_texture_object *tObj, GLuint n, 3016 const GLfloat texcoords[][4], const GLfloat lambda[], 3017 GLfloat rgba[][4]) 3018 { 3019 GLuint i; 3020 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 3021 (void) lambda; 3022 for (i = 0; i < n; i++) { 3023 sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]); 3024 } 3025 } 3026 3027 3028 3029 /** Sample 2D Array texture, linear filtering for both min/magnification */ 3030 static void 3031 sample_linear_2d_array(struct gl_context *ctx, 3032 const struct gl_sampler_object *samp, 3033 const struct gl_texture_object *tObj, GLuint n, 3034 const GLfloat texcoords[][4], 3035 const GLfloat lambda[], GLfloat rgba[][4]) 3036 { 3037 GLuint i; 3038 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 3039 (void) lambda; 3040 for (i = 0; i < n; i++) { 3041 sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]); 3042 } 3043 } 3044 3045 3046 /** Sample 2D Array texture, using lambda to choose between min/magnification */ 3047 static void 3048 sample_lambda_2d_array(struct gl_context *ctx, 3049 const struct gl_sampler_object *samp, 3050 const struct gl_texture_object *tObj, GLuint n, 3051 const GLfloat texcoords[][4], const GLfloat lambda[], 3052 GLfloat rgba[][4]) 3053 { 3054 GLuint minStart, minEnd; /* texels with minification */ 3055 GLuint magStart, magEnd; /* texels with magnification */ 3056 GLuint i; 3057 3058 ASSERT(lambda != NULL); 3059 compute_min_mag_ranges(samp, n, lambda, 3060 &minStart, &minEnd, &magStart, &magEnd); 3061 3062 if (minStart < minEnd) { 3063 /* do the minified texels */ 3064 GLuint m = minEnd - minStart; 3065 switch (samp->MinFilter) { 3066 case GL_NEAREST: 3067 for (i = minStart; i < minEnd; i++) 3068 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3069 texcoords[i], rgba[i]); 3070 break; 3071 case GL_LINEAR: 3072 for (i = minStart; i < minEnd; i++) 3073 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3074 texcoords[i], rgba[i]); 3075 break; 3076 case GL_NEAREST_MIPMAP_NEAREST: 3077 sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, 3078 texcoords + minStart, 3079 lambda + minStart, 3080 rgba + minStart); 3081 break; 3082 case GL_LINEAR_MIPMAP_NEAREST: 3083 sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m, 3084 texcoords + minStart, 3085 lambda + minStart, 3086 rgba + minStart); 3087 break; 3088 case GL_NEAREST_MIPMAP_LINEAR: 3089 sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m, 3090 texcoords + minStart, 3091 lambda + minStart, 3092 rgba + minStart); 3093 break; 3094 case GL_LINEAR_MIPMAP_LINEAR: 3095 sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m, 3096 texcoords + minStart, 3097 lambda + minStart, 3098 rgba + minStart); 3099 break; 3100 default: 3101 _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture"); 3102 return; 3103 } 3104 } 3105 3106 if (magStart < magEnd) { 3107 /* do the magnified texels */ 3108 switch (samp->MagFilter) { 3109 case GL_NEAREST: 3110 for (i = magStart; i < magEnd; i++) 3111 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3112 texcoords[i], rgba[i]); 3113 break; 3114 case GL_LINEAR: 3115 for (i = magStart; i < magEnd; i++) 3116 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3117 texcoords[i], rgba[i]); 3118 break; 3119 default: 3120 _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture"); 3121 return; 3122 } 3123 } 3124 } 3125 3126 3127 3128 3129 /**********************************************************************/ 3130 /* 1D Texture Array Sampling Functions */ 3131 /**********************************************************************/ 3132 3133 /** 3134 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. 3135 */ 3136 static void 3137 sample_1d_array_nearest(struct gl_context *ctx, 3138 const struct gl_sampler_object *samp, 3139 const struct gl_texture_image *img, 3140 const GLfloat texcoord[4], 3141 GLfloat rgba[4]) 3142 { 3143 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 3144 const GLint width = img->Width2; /* without border, power of two */ 3145 const GLint height = img->Height; 3146 GLint i; 3147 GLint array; 3148 (void) ctx; 3149 3150 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]); 3151 array = tex_array_slice(texcoord[1], height); 3152 3153 if (i < 0 || i >= (GLint) img->Width || 3154 array < 0 || array >= (GLint) img->Height) { 3155 /* Need this test for GL_CLAMP_TO_BORDER mode */ 3156 get_border_color(samp, img, rgba); 3157 } 3158 else { 3159 swImg->FetchTexel(swImg, i, array, 0, rgba); 3160 } 3161 } 3162 3163 3164 /** 3165 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. 3166 */ 3167 static void 3168 sample_1d_array_linear(struct gl_context *ctx, 3169 const struct gl_sampler_object *samp, 3170 const struct gl_texture_image *img, 3171 const GLfloat texcoord[4], 3172 GLfloat rgba[4]) 3173 { 3174 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 3175 const GLint width = img->Width2; 3176 const GLint height = img->Height; 3177 GLint i0, i1; 3178 GLint array; 3179 GLbitfield useBorderColor = 0x0; 3180 GLfloat a; 3181 GLfloat t0[4], t1[4]; 3182 3183 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a); 3184 array = tex_array_slice(texcoord[1], height); 3185 3186 if (img->Border) { 3187 i0 += img->Border; 3188 i1 += img->Border; 3189 } 3190 else { 3191 /* check if sampling texture border color */ 3192 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; 3193 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; 3194 } 3195 3196 if (array < 0 || array >= height) useBorderColor |= K0BIT; 3197 3198 /* Fetch texels */ 3199 if (useBorderColor & (I0BIT | K0BIT)) { 3200 get_border_color(samp, img, t0); 3201 } 3202 else { 3203 swImg->FetchTexel(swImg, i0, array, 0, t0); 3204 } 3205 if (useBorderColor & (I1BIT | K0BIT)) { 3206 get_border_color(samp, img, t1); 3207 } 3208 else { 3209 swImg->FetchTexel(swImg, i1, array, 0, t1); 3210 } 3211 3212 /* bilinear interpolation of samples */ 3213 lerp_rgba(rgba, a, t0, t1); 3214 } 3215 3216 3217 static void 3218 sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx, 3219 const struct gl_sampler_object *samp, 3220 const struct gl_texture_object *tObj, 3221 GLuint n, const GLfloat texcoord[][4], 3222 const GLfloat lambda[], GLfloat rgba[][4]) 3223 { 3224 GLuint i; 3225 for (i = 0; i < n; i++) { 3226 GLint level = nearest_mipmap_level(tObj, lambda[i]); 3227 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], 3228 rgba[i]); 3229 } 3230 } 3231 3232 3233 static void 3234 sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx, 3235 const struct gl_sampler_object *samp, 3236 const struct gl_texture_object *tObj, 3237 GLuint n, const GLfloat texcoord[][4], 3238 const GLfloat lambda[], GLfloat rgba[][4]) 3239 { 3240 GLuint i; 3241 ASSERT(lambda != NULL); 3242 for (i = 0; i < n; i++) { 3243 GLint level = nearest_mipmap_level(tObj, lambda[i]); 3244 sample_1d_array_linear(ctx, samp, tObj->Image[0][level], 3245 texcoord[i], rgba[i]); 3246 } 3247 } 3248 3249 3250 static void 3251 sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx, 3252 const struct gl_sampler_object *samp, 3253 const struct gl_texture_object *tObj, 3254 GLuint n, const GLfloat texcoord[][4], 3255 const GLfloat lambda[], GLfloat rgba[][4]) 3256 { 3257 GLuint i; 3258 ASSERT(lambda != NULL); 3259 for (i = 0; i < n; i++) { 3260 GLint level = linear_mipmap_level(tObj, lambda[i]); 3261 if (level >= tObj->_MaxLevel) { 3262 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 3263 texcoord[i], rgba[i]); 3264 } 3265 else { 3266 GLfloat t0[4], t1[4]; /* texels */ 3267 const GLfloat f = FRAC(lambda[i]); 3268 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 3269 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 3270 lerp_rgba(rgba[i], f, t0, t1); 3271 } 3272 } 3273 } 3274 3275 3276 static void 3277 sample_1d_array_linear_mipmap_linear(struct gl_context *ctx, 3278 const struct gl_sampler_object *samp, 3279 const struct gl_texture_object *tObj, 3280 GLuint n, const GLfloat texcoord[][4], 3281 const GLfloat lambda[], GLfloat rgba[][4]) 3282 { 3283 GLuint i; 3284 ASSERT(lambda != NULL); 3285 for (i = 0; i < n; i++) { 3286 GLint level = linear_mipmap_level(tObj, lambda[i]); 3287 if (level >= tObj->_MaxLevel) { 3288 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel], 3289 texcoord[i], rgba[i]); 3290 } 3291 else { 3292 GLfloat t0[4], t1[4]; /* texels */ 3293 const GLfloat f = FRAC(lambda[i]); 3294 sample_1d_array_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0); 3295 sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1); 3296 lerp_rgba(rgba[i], f, t0, t1); 3297 } 3298 } 3299 } 3300 3301 3302 /** Sample 1D Array texture, nearest filtering for both min/magnification */ 3303 static void 3304 sample_nearest_1d_array(struct gl_context *ctx, 3305 const struct gl_sampler_object *samp, 3306 const struct gl_texture_object *tObj, GLuint n, 3307 const GLfloat texcoords[][4], const GLfloat lambda[], 3308 GLfloat rgba[][4]) 3309 { 3310 GLuint i; 3311 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 3312 (void) lambda; 3313 for (i = 0; i < n; i++) { 3314 sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]); 3315 } 3316 } 3317 3318 3319 /** Sample 1D Array texture, linear filtering for both min/magnification */ 3320 static void 3321 sample_linear_1d_array(struct gl_context *ctx, 3322 const struct gl_sampler_object *samp, 3323 const struct gl_texture_object *tObj, GLuint n, 3324 const GLfloat texcoords[][4], 3325 const GLfloat lambda[], GLfloat rgba[][4]) 3326 { 3327 GLuint i; 3328 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; 3329 (void) lambda; 3330 for (i = 0; i < n; i++) { 3331 sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]); 3332 } 3333 } 3334 3335 3336 /** Sample 1D Array texture, using lambda to choose between min/magnification */ 3337 static void 3338 sample_lambda_1d_array(struct gl_context *ctx, 3339 const struct gl_sampler_object *samp, 3340 const struct gl_texture_object *tObj, GLuint n, 3341 const GLfloat texcoords[][4], const GLfloat lambda[], 3342 GLfloat rgba[][4]) 3343 { 3344 GLuint minStart, minEnd; /* texels with minification */ 3345 GLuint magStart, magEnd; /* texels with magnification */ 3346 GLuint i; 3347 3348 ASSERT(lambda != NULL); 3349 compute_min_mag_ranges(samp, n, lambda, 3350 &minStart, &minEnd, &magStart, &magEnd); 3351 3352 if (minStart < minEnd) { 3353 /* do the minified texels */ 3354 GLuint m = minEnd - minStart; 3355 switch (samp->MinFilter) { 3356 case GL_NEAREST: 3357 for (i = minStart; i < minEnd; i++) 3358 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3359 texcoords[i], rgba[i]); 3360 break; 3361 case GL_LINEAR: 3362 for (i = minStart; i < minEnd; i++) 3363 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3364 texcoords[i], rgba[i]); 3365 break; 3366 case GL_NEAREST_MIPMAP_NEAREST: 3367 sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart, 3368 lambda + minStart, rgba + minStart); 3369 break; 3370 case GL_LINEAR_MIPMAP_NEAREST: 3371 sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m, 3372 texcoords + minStart, 3373 lambda + minStart, 3374 rgba + minStart); 3375 break; 3376 case GL_NEAREST_MIPMAP_LINEAR: 3377 sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart, 3378 lambda + minStart, rgba + minStart); 3379 break; 3380 case GL_LINEAR_MIPMAP_LINEAR: 3381 sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m, 3382 texcoords + minStart, 3383 lambda + minStart, 3384 rgba + minStart); 3385 break; 3386 default: 3387 _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture"); 3388 return; 3389 } 3390 } 3391 3392 if (magStart < magEnd) { 3393 /* do the magnified texels */ 3394 switch (samp->MagFilter) { 3395 case GL_NEAREST: 3396 for (i = magStart; i < magEnd; i++) 3397 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3398 texcoords[i], rgba[i]); 3399 break; 3400 case GL_LINEAR: 3401 for (i = magStart; i < magEnd; i++) 3402 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel], 3403 texcoords[i], rgba[i]); 3404 break; 3405 default: 3406 _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture"); 3407 return; 3408 } 3409 } 3410 } 3411 3412 3413 /** 3414 * Compare texcoord against depth sample. Return 1.0 or 0.0 value. 3415 */ 3416 static inline GLfloat 3417 shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample) 3418 { 3419 switch (function) { 3420 case GL_LEQUAL: 3421 return (coord <= depthSample) ? 1.0F : 0.0F; 3422 case GL_GEQUAL: 3423 return (coord >= depthSample) ? 1.0F : 0.0F; 3424 case GL_LESS: 3425 return (coord < depthSample) ? 1.0F : 0.0F; 3426 case GL_GREATER: 3427 return (coord > depthSample) ? 1.0F : 0.0F; 3428 case GL_EQUAL: 3429 return (coord == depthSample) ? 1.0F : 0.0F; 3430 case GL_NOTEQUAL: 3431 return (coord != depthSample) ? 1.0F : 0.0F; 3432 case GL_ALWAYS: 3433 return 1.0F; 3434 case GL_NEVER: 3435 return 0.0F; 3436 case GL_NONE: 3437 return depthSample; 3438 default: 3439 _mesa_problem(NULL, "Bad compare func in shadow_compare"); 3440 return 0.0F; 3441 } 3442 } 3443 3444 3445 /** 3446 * Compare texcoord against four depth samples. 3447 */ 3448 static inline GLfloat 3449 shadow_compare4(GLenum function, GLfloat coord, 3450 GLfloat depth00, GLfloat depth01, 3451 GLfloat depth10, GLfloat depth11, 3452 GLfloat wi, GLfloat wj) 3453 { 3454 const GLfloat d = 0.25F; 3455 GLfloat luminance = 1.0F; 3456 3457 switch (function) { 3458 case GL_LEQUAL: 3459 if (coord > depth00) luminance -= d; 3460 if (coord > depth01) luminance -= d; 3461 if (coord > depth10) luminance -= d; 3462 if (coord > depth11) luminance -= d; 3463 return luminance; 3464 case GL_GEQUAL: 3465 if (coord < depth00) luminance -= d; 3466 if (coord < depth01) luminance -= d; 3467 if (coord < depth10) luminance -= d; 3468 if (coord < depth11) luminance -= d; 3469 return luminance; 3470 case GL_LESS: 3471 if (coord >= depth00) luminance -= d; 3472 if (coord >= depth01) luminance -= d; 3473 if (coord >= depth10) luminance -= d; 3474 if (coord >= depth11) luminance -= d; 3475 return luminance; 3476 case GL_GREATER: 3477 if (coord <= depth00) luminance -= d; 3478 if (coord <= depth01) luminance -= d; 3479 if (coord <= depth10) luminance -= d; 3480 if (coord <= depth11) luminance -= d; 3481 return luminance; 3482 case GL_EQUAL: 3483 if (coord != depth00) luminance -= d; 3484 if (coord != depth01) luminance -= d; 3485 if (coord != depth10) luminance -= d; 3486 if (coord != depth11) luminance -= d; 3487 return luminance; 3488 case GL_NOTEQUAL: 3489 if (coord == depth00) luminance -= d; 3490 if (coord == depth01) luminance -= d; 3491 if (coord == depth10) luminance -= d; 3492 if (coord == depth11) luminance -= d; 3493 return luminance; 3494 case GL_ALWAYS: 3495 return 1.0F; 3496 case GL_NEVER: 3497 return 0.0F; 3498 case GL_NONE: 3499 /* ordinary bilinear filtering */ 3500 return lerp_2d(wi, wj, depth00, depth10, depth01, depth11); 3501 default: 3502 _mesa_problem(NULL, "Bad compare func in sample_compare4"); 3503 return 0.0F; 3504 } 3505 } 3506 3507 3508 /** 3509 * Choose the mipmap level to use when sampling from a depth texture. 3510 */ 3511 static int 3512 choose_depth_texture_level(const struct gl_sampler_object *samp, 3513 const struct gl_texture_object *tObj, GLfloat lambda) 3514 { 3515 GLint level; 3516 3517 if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) { 3518 /* no mipmapping - use base level */ 3519 level = tObj->BaseLevel; 3520 } 3521 else { 3522 /* choose mipmap level */ 3523 lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod); 3524 level = (GLint) lambda; 3525 level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); 3526 } 3527 3528 return level; 3529 } 3530 3531 3532 /** 3533 * Sample a shadow/depth texture. This function is incomplete. It doesn't 3534 * check for minification vs. magnification, etc. 3535 */ 3536 static void 3537 sample_depth_texture( struct gl_context *ctx, 3538 const struct gl_sampler_object *samp, 3539 const struct gl_texture_object *tObj, GLuint n, 3540 const GLfloat texcoords[][4], const GLfloat lambda[], 3541 GLfloat texel[][4] ) 3542 { 3543 const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]); 3544 const struct gl_texture_image *img = tObj->Image[0][level]; 3545 const struct swrast_texture_image *swImg = swrast_texture_image_const(img); 3546 const GLint width = img->Width; 3547 const GLint height = img->Height; 3548 const GLint depth = img->Depth; 3549 const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT) 3550 ? 3 : 2; 3551 GLenum function; 3552 GLfloat result; 3553 3554 ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT || 3555 img->_BaseFormat == GL_DEPTH_STENCIL_EXT); 3556 3557 ASSERT(tObj->Target == GL_TEXTURE_1D || 3558 tObj->Target == GL_TEXTURE_2D || 3559 tObj->Target == GL_TEXTURE_RECTANGLE_NV || 3560 tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || 3561 tObj->Target == GL_TEXTURE_2D_ARRAY_EXT || 3562 tObj->Target == GL_TEXTURE_CUBE_MAP); 3563 3564 /* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */ 3565 3566 function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? 3567 samp->CompareFunc : GL_NONE; 3568 3569 if (samp->MagFilter == GL_NEAREST) { 3570 GLuint i; 3571 for (i = 0; i < n; i++) { 3572 GLfloat depthSample, depthRef; 3573 GLint col, row, slice; 3574 3575 nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice); 3576 3577 if (col >= 0 && row >= 0 && col < width && row < height && 3578 slice >= 0 && slice < depth) { 3579 swImg->FetchTexel(swImg, col, row, slice, &depthSample); 3580 } 3581 else { 3582 depthSample = samp->BorderColor.f[0]; 3583 } 3584 3585 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); 3586 3587 result = shadow_compare(function, depthRef, depthSample); 3588 3589 apply_depth_mode(tObj->DepthMode, result, texel[i]); 3590 } 3591 } 3592 else { 3593 GLuint i; 3594 ASSERT(samp->MagFilter == GL_LINEAR); 3595 for (i = 0; i < n; i++) { 3596 GLfloat depth00, depth01, depth10, depth11, depthRef; 3597 GLint i0, i1, j0, j1; 3598 GLint slice; 3599 GLfloat wi, wj; 3600 GLuint useBorderTexel; 3601 3602 linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice, 3603 &wi, &wj); 3604 3605 useBorderTexel = 0; 3606 if (img->Border) { 3607 i0 += img->Border; 3608 i1 += img->Border; 3609 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { 3610 j0 += img->Border; 3611 j1 += img->Border; 3612 } 3613 } 3614 else { 3615 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT; 3616 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT; 3617 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT; 3618 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT; 3619 } 3620 3621 if (slice < 0 || slice >= (GLint) depth) { 3622 depth00 = samp->BorderColor.f[0]; 3623 depth01 = samp->BorderColor.f[0]; 3624 depth10 = samp->BorderColor.f[0]; 3625 depth11 = samp->BorderColor.f[0]; 3626 } 3627 else { 3628 /* get four depth samples from the texture */ 3629 if (useBorderTexel & (I0BIT | J0BIT)) { 3630 depth00 = samp->BorderColor.f[0]; 3631 } 3632 else { 3633 swImg->FetchTexel(swImg, i0, j0, slice, &depth00); 3634 } 3635 if (useBorderTexel & (I1BIT | J0BIT)) { 3636 depth10 = samp->BorderColor.f[0]; 3637 } 3638 else { 3639 swImg->FetchTexel(swImg, i1, j0, slice, &depth10); 3640 } 3641 3642 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { 3643 if (useBorderTexel & (I0BIT | J1BIT)) { 3644 depth01 = samp->BorderColor.f[0]; 3645 } 3646 else { 3647 swImg->FetchTexel(swImg, i0, j1, slice, &depth01); 3648 } 3649 if (useBorderTexel & (I1BIT | J1BIT)) { 3650 depth11 = samp->BorderColor.f[0]; 3651 } 3652 else { 3653 swImg->FetchTexel(swImg, i1, j1, slice, &depth11); 3654 } 3655 } 3656 else { 3657 depth01 = depth00; 3658 depth11 = depth10; 3659 } 3660 } 3661 3662 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); 3663 3664 result = shadow_compare4(function, depthRef, 3665 depth00, depth01, depth10, depth11, 3666 wi, wj); 3667 3668 apply_depth_mode(tObj->DepthMode, result, texel[i]); 3669 } /* for */ 3670 } /* if filter */ 3671 } 3672 3673 3674 /** 3675 * We use this function when a texture object is in an "incomplete" state. 3676 * When a fragment program attempts to sample an incomplete texture we 3677 * return black (see issue 23 in GL_ARB_fragment_program spec). 3678 * Note: fragment programs don't observe the texture enable/disable flags. 3679 */ 3680 static void 3681 null_sample_func( struct gl_context *ctx, 3682 const struct gl_sampler_object *samp, 3683 const struct gl_texture_object *tObj, GLuint n, 3684 const GLfloat texcoords[][4], const GLfloat lambda[], 3685 GLfloat rgba[][4]) 3686 { 3687 GLuint i; 3688 (void) ctx; 3689 (void) tObj; 3690 (void) texcoords; 3691 (void) lambda; 3692 (void) samp; 3693 for (i = 0; i < n; i++) { 3694 rgba[i][RCOMP] = 0; 3695 rgba[i][GCOMP] = 0; 3696 rgba[i][BCOMP] = 0; 3697 rgba[i][ACOMP] = 1.0; 3698 } 3699 } 3700 3701 3702 /** 3703 * Choose the texture sampling function for the given texture object. 3704 */ 3705 texture_sample_func 3706 _swrast_choose_texture_sample_func( struct gl_context *ctx, 3707 const struct gl_texture_object *t, 3708 const struct gl_sampler_object *sampler) 3709 { 3710 if (!t || !_mesa_is_texture_complete(t, sampler)) { 3711 return &null_sample_func; 3712 } 3713 else { 3714 const GLboolean needLambda = 3715 (GLboolean) (sampler->MinFilter != sampler->MagFilter); 3716 3717 switch (t->Target) { 3718 case GL_TEXTURE_1D: 3719 if (is_depth_texture(t)) { 3720 return &sample_depth_texture; 3721 } 3722 else if (needLambda) { 3723 return &sample_lambda_1d; 3724 } 3725 else if (sampler->MinFilter == GL_LINEAR) { 3726 return &sample_linear_1d; 3727 } 3728 else { 3729 ASSERT(sampler->MinFilter == GL_NEAREST); 3730 return &sample_nearest_1d; 3731 } 3732 case GL_TEXTURE_2D: 3733 if (is_depth_texture(t)) { 3734 return &sample_depth_texture; 3735 } 3736 else if (needLambda) { 3737 /* Anisotropic filtering extension. Activated only if mipmaps are used */ 3738 if (sampler->MaxAnisotropy > 1.0 && 3739 sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) { 3740 return &sample_lambda_2d_aniso; 3741 } 3742 return &sample_lambda_2d; 3743 } 3744 else if (sampler->MinFilter == GL_LINEAR) { 3745 return &sample_linear_2d; 3746 } 3747 else { 3748 /* check for a few optimized cases */ 3749 const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; 3750 const struct swrast_texture_image *swImg = 3751 swrast_texture_image_const(img); 3752 texture_sample_func func; 3753 3754 ASSERT(sampler->MinFilter == GL_NEAREST); 3755 func = &sample_nearest_2d; 3756 if (sampler->WrapS == GL_REPEAT && 3757 sampler->WrapT == GL_REPEAT && 3758 swImg->_IsPowerOfTwo && 3759 img->Border == 0) { 3760 if (img->TexFormat == MESA_FORMAT_RGB888) 3761 func = &opt_sample_rgb_2d; 3762 else if (img->TexFormat == MESA_FORMAT_RGBA8888) 3763 func = &opt_sample_rgba_2d; 3764 } 3765 3766 return func; 3767 } 3768 case GL_TEXTURE_3D: 3769 if (needLambda) { 3770 return &sample_lambda_3d; 3771 } 3772 else if (sampler->MinFilter == GL_LINEAR) { 3773 return &sample_linear_3d; 3774 } 3775 else { 3776 ASSERT(sampler->MinFilter == GL_NEAREST); 3777 return &sample_nearest_3d; 3778 } 3779 case GL_TEXTURE_CUBE_MAP: 3780 if (needLambda) { 3781 return &sample_lambda_cube; 3782 } 3783 else if (sampler->MinFilter == GL_LINEAR) { 3784 return &sample_linear_cube; 3785 } 3786 else { 3787 ASSERT(sampler->MinFilter == GL_NEAREST); 3788 return &sample_nearest_cube; 3789 } 3790 case GL_TEXTURE_RECTANGLE_NV: 3791 if (is_depth_texture(t)) { 3792 return &sample_depth_texture; 3793 } 3794 else if (needLambda) { 3795 return &sample_lambda_rect; 3796 } 3797 else if (sampler->MinFilter == GL_LINEAR) { 3798 return &sample_linear_rect; 3799 } 3800 else { 3801 ASSERT(sampler->MinFilter == GL_NEAREST); 3802 return &sample_nearest_rect; 3803 } 3804 case GL_TEXTURE_1D_ARRAY_EXT: 3805 if (is_depth_texture(t)) { 3806 return &sample_depth_texture; 3807 } 3808 else if (needLambda) { 3809 return &sample_lambda_1d_array; 3810 } 3811 else if (sampler->MinFilter == GL_LINEAR) { 3812 return &sample_linear_1d_array; 3813 } 3814 else { 3815 ASSERT(sampler->MinFilter == GL_NEAREST); 3816 return &sample_nearest_1d_array; 3817 } 3818 case GL_TEXTURE_2D_ARRAY_EXT: 3819 if (is_depth_texture(t)) { 3820 return &sample_depth_texture; 3821 } 3822 else if (needLambda) { 3823 return &sample_lambda_2d_array; 3824 } 3825 else if (sampler->MinFilter == GL_LINEAR) { 3826 return &sample_linear_2d_array; 3827 } 3828 else { 3829 ASSERT(sampler->MinFilter == GL_NEAREST); 3830 return &sample_nearest_2d_array; 3831 } 3832 default: 3833 _mesa_problem(ctx, 3834 "invalid target in _swrast_choose_texture_sample_func"); 3835 return &null_sample_func; 3836 } 3837 } 3838 } 3839