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