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