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