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