2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/imports.h"
30 #include "main/texformat.h"
32 #include "s_context.h"
33 #include "s_texfilter.h"
37 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
38 * see 1-pixel bands of improperly weighted linear-filtered textures.
39 * The tests/texwrap.c demo is a good test.
40 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
41 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
43 #define FRAC(f) ((f) - IFLOOR(f))
48 * Linear interpolation macro
50 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
54 * Do 2D/biliner interpolation of float values.
55 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
56 * a and b are the horizontal and vertical interpolants.
57 * It's important that this function is inlined when compiled with
58 * optimization! If we find that's not true on some systems, convert
62 lerp_2d(GLfloat a
, GLfloat b
,
63 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
65 const GLfloat temp0
= LERP(a
, v00
, v10
);
66 const GLfloat temp1
= LERP(a
, v01
, v11
);
67 return LERP(b
, temp0
, temp1
);
72 * Do 3D/trilinear interpolation of float values.
76 lerp_3d(GLfloat a
, GLfloat b
, GLfloat c
,
77 GLfloat v000
, GLfloat v100
, GLfloat v010
, GLfloat v110
,
78 GLfloat v001
, GLfloat v101
, GLfloat v011
, GLfloat v111
)
80 const GLfloat temp00
= LERP(a
, v000
, v100
);
81 const GLfloat temp10
= LERP(a
, v010
, v110
);
82 const GLfloat temp01
= LERP(a
, v001
, v101
);
83 const GLfloat temp11
= LERP(a
, v011
, v111
);
84 const GLfloat temp0
= LERP(b
, temp00
, temp10
);
85 const GLfloat temp1
= LERP(b
, temp01
, temp11
);
86 return LERP(c
, temp0
, temp1
);
91 * Do linear interpolation of colors.
94 lerp_rgba(GLfloat result
[4], GLfloat t
, const GLfloat a
[4], const GLfloat b
[4])
96 result
[0] = LERP(t
, a
[0], b
[0]);
97 result
[1] = LERP(t
, a
[1], b
[1]);
98 result
[2] = LERP(t
, a
[2], b
[2]);
99 result
[3] = LERP(t
, a
[3], b
[3]);
104 * Do bilinear interpolation of colors.
107 lerp_rgba_2d(GLfloat result
[4], GLfloat a
, GLfloat b
,
108 const GLfloat t00
[4], const GLfloat t10
[4],
109 const GLfloat t01
[4], const GLfloat t11
[4])
111 result
[0] = lerp_2d(a
, b
, t00
[0], t10
[0], t01
[0], t11
[0]);
112 result
[1] = lerp_2d(a
, b
, t00
[1], t10
[1], t01
[1], t11
[1]);
113 result
[2] = lerp_2d(a
, b
, t00
[2], t10
[2], t01
[2], t11
[2]);
114 result
[3] = lerp_2d(a
, b
, t00
[3], t10
[3], t01
[3], t11
[3]);
119 * Do trilinear interpolation of colors.
122 lerp_rgba_3d(GLfloat result
[4], GLfloat a
, GLfloat b
, GLfloat c
,
123 const GLfloat t000
[4], const GLfloat t100
[4],
124 const GLfloat t010
[4], const GLfloat t110
[4],
125 const GLfloat t001
[4], const GLfloat t101
[4],
126 const GLfloat t011
[4], const GLfloat t111
[4])
129 /* compiler should unroll these short loops */
130 for (k
= 0; k
< 4; k
++) {
131 result
[k
] = lerp_3d(a
, b
, c
, t000
[k
], t100
[k
], t010
[k
], t110
[k
],
132 t001
[k
], t101
[k
], t011
[k
], t111
[k
]);
138 * If A is a signed integer, A % B doesn't give the right value for A < 0
139 * (in terms of texture repeat). Just casting to unsigned fixes that.
141 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
145 * Used to compute texel locations for linear sampling.
147 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
148 * s = texcoord in [0,1]
149 * size = width (or height or depth) of texture
151 * i0, i1 = returns two nearest texel indexes
152 * weight = returns blend factor between texels
155 linear_texel_locations(GLenum wrapMode
,
156 const struct gl_texture_image
*img
,
157 GLint size
, GLfloat s
,
158 GLint
*i0
, GLint
*i1
, GLfloat
*weight
)
164 if (img
->_IsPowerOfTwo
) {
165 *i0
= IFLOOR(u
) & (size
- 1);
166 *i1
= (*i0
+ 1) & (size
- 1);
169 *i0
= REMAINDER(IFLOOR(u
), size
);
170 *i1
= REMAINDER(*i0
+ 1, size
);
173 case GL_CLAMP_TO_EDGE
:
185 if (*i1
>= (GLint
) size
)
188 case GL_CLAMP_TO_BORDER
:
190 const GLfloat min
= -1.0F
/ (2.0F
* size
);
191 const GLfloat max
= 1.0F
- min
;
203 case GL_MIRRORED_REPEAT
:
205 const GLint flr
= IFLOOR(s
);
207 u
= 1.0F
- (s
- (GLfloat
) flr
);
209 u
= s
- (GLfloat
) flr
;
210 u
= (u
* size
) - 0.5F
;
215 if (*i1
>= (GLint
) size
)
219 case GL_MIRROR_CLAMP_EXT
:
229 case GL_MIRROR_CLAMP_TO_EDGE_EXT
:
240 if (*i1
>= (GLint
) size
)
243 case GL_MIRROR_CLAMP_TO_BORDER_EXT
:
245 const GLfloat min
= -1.0F
/ (2.0F
* size
);
246 const GLfloat max
= 1.0F
- min
;
271 _mesa_problem(NULL
, "Bad wrap mode");
279 * Used to compute texel location for nearest sampling.
282 nearest_texel_location(GLenum wrapMode
,
283 const struct gl_texture_image
*img
,
284 GLint size
, GLfloat s
)
290 /* s limited to [0,1) */
291 /* i limited to [0,size-1] */
292 i
= IFLOOR(s
* size
);
293 if (img
->_IsPowerOfTwo
)
296 i
= REMAINDER(i
, size
);
298 case GL_CLAMP_TO_EDGE
:
300 /* s limited to [min,max] */
301 /* i limited to [0, size-1] */
302 const GLfloat min
= 1.0F
/ (2.0F
* size
);
303 const GLfloat max
= 1.0F
- min
;
309 i
= IFLOOR(s
* size
);
312 case GL_CLAMP_TO_BORDER
:
314 /* s limited to [min,max] */
315 /* i limited to [-1, size] */
316 const GLfloat min
= -1.0F
/ (2.0F
* size
);
317 const GLfloat max
= 1.0F
- min
;
323 i
= IFLOOR(s
* size
);
326 case GL_MIRRORED_REPEAT
:
328 const GLfloat min
= 1.0F
/ (2.0F
* size
);
329 const GLfloat max
= 1.0F
- min
;
330 const GLint flr
= IFLOOR(s
);
333 u
= 1.0F
- (s
- (GLfloat
) flr
);
335 u
= s
- (GLfloat
) flr
;
341 i
= IFLOOR(u
* size
);
344 case GL_MIRROR_CLAMP_EXT
:
346 /* s limited to [0,1] */
347 /* i limited to [0,size-1] */
348 const GLfloat u
= FABSF(s
);
354 i
= IFLOOR(u
* size
);
357 case GL_MIRROR_CLAMP_TO_EDGE_EXT
:
359 /* s limited to [min,max] */
360 /* i limited to [0, size-1] */
361 const GLfloat min
= 1.0F
/ (2.0F
* size
);
362 const GLfloat max
= 1.0F
- min
;
363 const GLfloat u
= FABSF(s
);
369 i
= IFLOOR(u
* size
);
372 case GL_MIRROR_CLAMP_TO_BORDER_EXT
:
374 /* s limited to [min,max] */
375 /* i limited to [0, size-1] */
376 const GLfloat min
= -1.0F
/ (2.0F
* size
);
377 const GLfloat max
= 1.0F
- min
;
378 const GLfloat u
= FABSF(s
);
384 i
= IFLOOR(u
* size
);
388 /* s limited to [0,1] */
389 /* i limited to [0,size-1] */
395 i
= IFLOOR(s
* size
);
398 _mesa_problem(NULL
, "Bad wrap mode");
404 /* Power of two image sizes only */
406 linear_repeat_texel_location(GLuint size
, GLfloat s
,
407 GLint
*i0
, GLint
*i1
, GLfloat
*weight
)
409 GLfloat u
= s
* size
- 0.5F
;
410 *i0
= IFLOOR(u
) & (size
- 1);
411 *i1
= (*i0
+ 1) & (size
- 1);
417 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
420 clamp_rect_coord_nearest(GLenum wrapMode
, GLfloat coord
, GLint max
)
424 return IFLOOR( CLAMP(coord
, 0.0F
, max
- 1) );
425 case GL_CLAMP_TO_EDGE
:
426 return IFLOOR( CLAMP(coord
, 0.5F
, max
- 0.5F
) );
427 case GL_CLAMP_TO_BORDER
:
428 return IFLOOR( CLAMP(coord
, -0.5F
, max
+ 0.5F
) );
430 _mesa_problem(NULL
, "bad wrapMode in clamp_rect_coord_nearest");
437 * As above, but GL_LINEAR filtering.
440 clamp_rect_coord_linear(GLenum wrapMode
, GLfloat coord
, GLint max
,
441 GLint
*i0out
, GLint
*i1out
, GLfloat
*weight
)
447 /* Not exactly what the spec says, but it matches NVIDIA output */
448 fcol
= CLAMP(coord
- 0.5F
, 0.0F
, max
- 1);
452 case GL_CLAMP_TO_EDGE
:
453 fcol
= CLAMP(coord
, 0.5F
, max
- 0.5F
);
460 case GL_CLAMP_TO_BORDER
:
461 fcol
= CLAMP(coord
, -0.5F
, max
+ 0.5F
);
467 _mesa_problem(NULL
, "bad wrapMode in clamp_rect_coord_linear");
473 *weight
= FRAC(fcol
);
478 * Compute slice/image to use for 1D or 2D array texture.
481 tex_array_slice(GLfloat coord
, GLsizei size
)
483 GLint slice
= IFLOOR(coord
+ 0.5f
);
484 slice
= CLAMP(slice
, 0, size
- 1);
490 * Compute nearest integer texcoords for given texobj and coordinate.
491 * NOTE: only used for depth texture sampling.
494 nearest_texcoord(const struct gl_texture_object
*texObj
,
496 const GLfloat texcoord
[4],
497 GLint
*i
, GLint
*j
, GLint
*k
)
499 const struct gl_texture_image
*img
= texObj
->Image
[0][level
];
500 const GLint width
= img
->Width
;
501 const GLint height
= img
->Height
;
502 const GLint depth
= img
->Depth
;
504 switch (texObj
->Target
) {
505 case GL_TEXTURE_RECTANGLE_ARB
:
506 *i
= clamp_rect_coord_nearest(texObj
->WrapS
, texcoord
[0], width
);
507 *j
= clamp_rect_coord_nearest(texObj
->WrapT
, texcoord
[1], height
);
511 *i
= nearest_texel_location(texObj
->WrapS
, img
, width
, texcoord
[0]);
516 *i
= nearest_texel_location(texObj
->WrapS
, img
, width
, texcoord
[0]);
517 *j
= nearest_texel_location(texObj
->WrapT
, img
, height
, texcoord
[1]);
520 case GL_TEXTURE_1D_ARRAY_EXT
:
521 *i
= nearest_texel_location(texObj
->WrapS
, img
, width
, texcoord
[0]);
522 *j
= tex_array_slice(texcoord
[1], height
);
525 case GL_TEXTURE_2D_ARRAY_EXT
:
526 *i
= nearest_texel_location(texObj
->WrapS
, img
, width
, texcoord
[0]);
527 *j
= nearest_texel_location(texObj
->WrapT
, img
, height
, texcoord
[1]);
528 *k
= tex_array_slice(texcoord
[2], depth
);
537 * Compute linear integer texcoords for given texobj and coordinate.
538 * NOTE: only used for depth texture sampling.
541 linear_texcoord(const struct gl_texture_object
*texObj
,
543 const GLfloat texcoord
[4],
544 GLint
*i0
, GLint
*i1
, GLint
*j0
, GLint
*j1
, GLint
*slice
,
545 GLfloat
*wi
, GLfloat
*wj
)
547 const struct gl_texture_image
*img
= texObj
->Image
[0][level
];
548 const GLint width
= img
->Width
;
549 const GLint height
= img
->Height
;
550 const GLint depth
= img
->Depth
;
552 switch (texObj
->Target
) {
553 case GL_TEXTURE_RECTANGLE_ARB
:
554 clamp_rect_coord_linear(texObj
->WrapS
, texcoord
[0],
556 clamp_rect_coord_linear(texObj
->WrapT
, texcoord
[1],
563 linear_texel_locations(texObj
->WrapS
, img
, width
,
564 texcoord
[0], i0
, i1
, wi
);
565 linear_texel_locations(texObj
->WrapT
, img
, height
,
566 texcoord
[1], j0
, j1
, wj
);
570 case GL_TEXTURE_1D_ARRAY_EXT
:
571 linear_texel_locations(texObj
->WrapS
, img
, width
,
572 texcoord
[0], i0
, i1
, wi
);
573 *j0
= tex_array_slice(texcoord
[1], height
);
578 case GL_TEXTURE_2D_ARRAY_EXT
:
579 linear_texel_locations(texObj
->WrapS
, img
, width
,
580 texcoord
[0], i0
, i1
, wi
);
581 linear_texel_locations(texObj
->WrapT
, img
, height
,
582 texcoord
[1], j0
, j1
, wj
);
583 *slice
= tex_array_slice(texcoord
[2], depth
);
594 * For linear interpolation between mipmap levels N and N+1, this function
598 linear_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
601 return tObj
->BaseLevel
;
602 else if (lambda
> tObj
->_MaxLambda
)
603 return (GLint
) (tObj
->BaseLevel
+ tObj
->_MaxLambda
);
605 return (GLint
) (tObj
->BaseLevel
+ lambda
);
610 * Compute the nearest mipmap level to take texels from.
613 nearest_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
619 else if (lambda
> tObj
->_MaxLambda
+ 0.4999F
)
620 l
= tObj
->_MaxLambda
+ 0.4999F
;
623 level
= (GLint
) (tObj
->BaseLevel
+ l
+ 0.5F
);
624 if (level
> tObj
->_MaxLevel
)
625 level
= tObj
->_MaxLevel
;
632 * Bitflags for texture border color sampling.
644 * The lambda[] array values are always monotonic. Either the whole span
645 * will be minified, magnified, or split between the two. This function
646 * determines the subranges in [0, n-1] that are to be minified or magnified.
649 compute_min_mag_ranges(const struct gl_texture_object
*tObj
,
650 GLuint n
, const GLfloat lambda
[],
651 GLuint
*minStart
, GLuint
*minEnd
,
652 GLuint
*magStart
, GLuint
*magEnd
)
654 GLfloat minMagThresh
;
656 /* we shouldn't be here if minfilter == magfilter */
657 ASSERT(tObj
->MinFilter
!= tObj
->MagFilter
);
659 /* This bit comes from the OpenGL spec: */
660 if (tObj
->MagFilter
== GL_LINEAR
661 && (tObj
->MinFilter
== GL_NEAREST_MIPMAP_NEAREST
||
662 tObj
->MinFilter
== GL_NEAREST_MIPMAP_LINEAR
)) {
670 /* DEBUG CODE: Verify that lambda[] is monotonic.
671 * We can't really use this because the inaccuracy in the LOG2 function
672 * causes this test to fail, yet the resulting texturing is correct.
676 printf("lambda delta = %g\n", lambda
[0] - lambda
[n
-1]);
677 if (lambda
[0] >= lambda
[n
-1]) { /* decreasing */
678 for (i
= 0; i
< n
- 1; i
++) {
679 ASSERT((GLint
) (lambda
[i
] * 10) >= (GLint
) (lambda
[i
+1] * 10));
682 else { /* increasing */
683 for (i
= 0; i
< n
- 1; i
++) {
684 ASSERT((GLint
) (lambda
[i
] * 10) <= (GLint
) (lambda
[i
+1] * 10));
690 if (lambda
[0] <= minMagThresh
&& (n
<= 1 || lambda
[n
-1] <= minMagThresh
)) {
691 /* magnification for whole span */
694 *minStart
= *minEnd
= 0;
696 else if (lambda
[0] > minMagThresh
&& (n
<=1 || lambda
[n
-1] > minMagThresh
)) {
697 /* minification for whole span */
700 *magStart
= *magEnd
= 0;
703 /* a mix of minification and magnification */
705 if (lambda
[0] > minMagThresh
) {
706 /* start with minification */
707 for (i
= 1; i
< n
; i
++) {
708 if (lambda
[i
] <= minMagThresh
)
717 /* start with magnification */
718 for (i
= 1; i
< n
; i
++) {
719 if (lambda
[i
] > minMagThresh
)
730 /* Verify the min/mag Start/End values
731 * We don't use this either (see above)
735 for (i
= 0; i
< n
; i
++) {
736 if (lambda
[i
] > minMagThresh
) {
738 ASSERT(i
>= *minStart
);
743 ASSERT(i
>= *magStart
);
753 * When we sample the border color, it must be interpreted according to
754 * the base texture format. Ex: if the texture base format it GL_ALPHA,
755 * we return (0,0,0,BorderAlpha).
758 get_border_color(const struct gl_texture_object
*tObj
,
759 const struct gl_texture_image
*img
,
762 switch (img
->_BaseFormat
) {
764 rgba
[0] = tObj
->BorderColor
.f
[0];
765 rgba
[1] = tObj
->BorderColor
.f
[1];
766 rgba
[2] = tObj
->BorderColor
.f
[2];
770 rgba
[0] = rgba
[1] = rgba
[2] = 0.0;
771 rgba
[3] = tObj
->BorderColor
.f
[3];
774 rgba
[0] = rgba
[1] = rgba
[2] = tObj
->BorderColor
.f
[0];
777 case GL_LUMINANCE_ALPHA
:
778 rgba
[0] = rgba
[1] = rgba
[2] = tObj
->BorderColor
.f
[0];
779 rgba
[3] = tObj
->BorderColor
.f
[3];
782 rgba
[0] = rgba
[1] = rgba
[2] = rgba
[3] = tObj
->BorderColor
.f
[0];
785 COPY_4V(rgba
, tObj
->BorderColor
.f
);
790 /**********************************************************************/
791 /* 1-D Texture Sampling Functions */
792 /**********************************************************************/
795 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
798 sample_1d_nearest(GLcontext
*ctx
,
799 const struct gl_texture_object
*tObj
,
800 const struct gl_texture_image
*img
,
801 const GLfloat texcoord
[4], GLfloat rgba
[4])
803 const GLint width
= img
->Width2
; /* without border, power of two */
805 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
806 /* skip over the border, if any */
808 if (i
< 0 || i
>= (GLint
) img
->Width
) {
809 /* Need this test for GL_CLAMP_TO_BORDER mode */
810 get_border_color(tObj
, img
, rgba
);
813 img
->FetchTexelf(img
, i
, 0, 0, rgba
);
819 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
822 sample_1d_linear(GLcontext
*ctx
,
823 const struct gl_texture_object
*tObj
,
824 const struct gl_texture_image
*img
,
825 const GLfloat texcoord
[4], GLfloat rgba
[4])
827 const GLint width
= img
->Width2
;
829 GLbitfield useBorderColor
= 0x0;
831 GLfloat t0
[4], t1
[4]; /* texels */
833 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
840 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
841 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
844 /* fetch texel colors */
845 if (useBorderColor
& I0BIT
) {
846 get_border_color(tObj
, img
, t0
);
849 img
->FetchTexelf(img
, i0
, 0, 0, t0
);
851 if (useBorderColor
& I1BIT
) {
852 get_border_color(tObj
, img
, t1
);
855 img
->FetchTexelf(img
, i1
, 0, 0, t1
);
858 lerp_rgba(rgba
, a
, t0
, t1
);
863 sample_1d_nearest_mipmap_nearest(GLcontext
*ctx
,
864 const struct gl_texture_object
*tObj
,
865 GLuint n
, const GLfloat texcoord
[][4],
866 const GLfloat lambda
[], GLfloat rgba
[][4])
869 ASSERT(lambda
!= NULL
);
870 for (i
= 0; i
< n
; i
++) {
871 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
872 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
878 sample_1d_linear_mipmap_nearest(GLcontext
*ctx
,
879 const struct gl_texture_object
*tObj
,
880 GLuint n
, const GLfloat texcoord
[][4],
881 const GLfloat lambda
[], GLfloat rgba
[][4])
884 ASSERT(lambda
!= NULL
);
885 for (i
= 0; i
< n
; i
++) {
886 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
887 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
893 sample_1d_nearest_mipmap_linear(GLcontext
*ctx
,
894 const struct gl_texture_object
*tObj
,
895 GLuint n
, const GLfloat texcoord
[][4],
896 const GLfloat lambda
[], GLfloat rgba
[][4])
899 ASSERT(lambda
!= NULL
);
900 for (i
= 0; i
< n
; i
++) {
901 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
902 if (level
>= tObj
->_MaxLevel
) {
903 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
904 texcoord
[i
], rgba
[i
]);
907 GLfloat t0
[4], t1
[4];
908 const GLfloat f
= FRAC(lambda
[i
]);
909 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
910 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
911 lerp_rgba(rgba
[i
], f
, t0
, t1
);
918 sample_1d_linear_mipmap_linear(GLcontext
*ctx
,
919 const struct gl_texture_object
*tObj
,
920 GLuint n
, const GLfloat texcoord
[][4],
921 const GLfloat lambda
[], GLfloat rgba
[][4])
924 ASSERT(lambda
!= NULL
);
925 for (i
= 0; i
< n
; i
++) {
926 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
927 if (level
>= tObj
->_MaxLevel
) {
928 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
929 texcoord
[i
], rgba
[i
]);
932 GLfloat t0
[4], t1
[4];
933 const GLfloat f
= FRAC(lambda
[i
]);
934 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
935 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
936 lerp_rgba(rgba
[i
], f
, t0
, t1
);
942 /** Sample 1D texture, nearest filtering for both min/magnification */
944 sample_nearest_1d( GLcontext
*ctx
,
945 const struct gl_texture_object
*tObj
, GLuint n
,
946 const GLfloat texcoords
[][4], const GLfloat lambda
[],
950 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
952 for (i
= 0; i
< n
; i
++) {
953 sample_1d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
958 /** Sample 1D texture, linear filtering for both min/magnification */
960 sample_linear_1d( GLcontext
*ctx
,
961 const struct gl_texture_object
*tObj
, GLuint n
,
962 const GLfloat texcoords
[][4], const GLfloat lambda
[],
966 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
968 for (i
= 0; i
< n
; i
++) {
969 sample_1d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
974 /** Sample 1D texture, using lambda to choose between min/magnification */
976 sample_lambda_1d( GLcontext
*ctx
,
977 const struct gl_texture_object
*tObj
, GLuint n
,
978 const GLfloat texcoords
[][4],
979 const GLfloat lambda
[], GLfloat rgba
[][4] )
981 GLuint minStart
, minEnd
; /* texels with minification */
982 GLuint magStart
, magEnd
; /* texels with magnification */
985 ASSERT(lambda
!= NULL
);
986 compute_min_mag_ranges(tObj
, n
, lambda
,
987 &minStart
, &minEnd
, &magStart
, &magEnd
);
989 if (minStart
< minEnd
) {
990 /* do the minified texels */
991 const GLuint m
= minEnd
- minStart
;
992 switch (tObj
->MinFilter
) {
994 for (i
= minStart
; i
< minEnd
; i
++)
995 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
996 texcoords
[i
], rgba
[i
]);
999 for (i
= minStart
; i
< minEnd
; i
++)
1000 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1001 texcoords
[i
], rgba
[i
]);
1003 case GL_NEAREST_MIPMAP_NEAREST
:
1004 sample_1d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1005 lambda
+ minStart
, rgba
+ minStart
);
1007 case GL_LINEAR_MIPMAP_NEAREST
:
1008 sample_1d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1009 lambda
+ minStart
, rgba
+ minStart
);
1011 case GL_NEAREST_MIPMAP_LINEAR
:
1012 sample_1d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1013 lambda
+ minStart
, rgba
+ minStart
);
1015 case GL_LINEAR_MIPMAP_LINEAR
:
1016 sample_1d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1017 lambda
+ minStart
, rgba
+ minStart
);
1020 _mesa_problem(ctx
, "Bad min filter in sample_1d_texture");
1025 if (magStart
< magEnd
) {
1026 /* do the magnified texels */
1027 switch (tObj
->MagFilter
) {
1029 for (i
= magStart
; i
< magEnd
; i
++)
1030 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1031 texcoords
[i
], rgba
[i
]);
1034 for (i
= magStart
; i
< magEnd
; i
++)
1035 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1036 texcoords
[i
], rgba
[i
]);
1039 _mesa_problem(ctx
, "Bad mag filter in sample_1d_texture");
1046 /**********************************************************************/
1047 /* 2-D Texture Sampling Functions */
1048 /**********************************************************************/
1052 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
1055 sample_2d_nearest(GLcontext
*ctx
,
1056 const struct gl_texture_object
*tObj
,
1057 const struct gl_texture_image
*img
,
1058 const GLfloat texcoord
[4],
1061 const GLint width
= img
->Width2
; /* without border, power of two */
1062 const GLint height
= img
->Height2
; /* without border, power of two */
1066 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
1067 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
1069 /* skip over the border, if any */
1073 if (i
< 0 || i
>= (GLint
) img
->Width
|| j
< 0 || j
>= (GLint
) img
->Height
) {
1074 /* Need this test for GL_CLAMP_TO_BORDER mode */
1075 get_border_color(tObj
, img
, rgba
);
1078 img
->FetchTexelf(img
, i
, j
, 0, rgba
);
1084 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
1085 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
1088 sample_2d_linear(GLcontext
*ctx
,
1089 const struct gl_texture_object
*tObj
,
1090 const struct gl_texture_image
*img
,
1091 const GLfloat texcoord
[4],
1094 const GLint width
= img
->Width2
;
1095 const GLint height
= img
->Height2
;
1096 GLint i0
, j0
, i1
, j1
;
1097 GLbitfield useBorderColor
= 0x0;
1099 GLfloat t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
1101 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
1102 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
1111 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1112 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1113 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1114 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1117 /* fetch four texel colors */
1118 if (useBorderColor
& (I0BIT
| J0BIT
)) {
1119 get_border_color(tObj
, img
, t00
);
1122 img
->FetchTexelf(img
, i0
, j0
, 0, t00
);
1124 if (useBorderColor
& (I1BIT
| J0BIT
)) {
1125 get_border_color(tObj
, img
, t10
);
1128 img
->FetchTexelf(img
, i1
, j0
, 0, t10
);
1130 if (useBorderColor
& (I0BIT
| J1BIT
)) {
1131 get_border_color(tObj
, img
, t01
);
1134 img
->FetchTexelf(img
, i0
, j1
, 0, t01
);
1136 if (useBorderColor
& (I1BIT
| J1BIT
)) {
1137 get_border_color(tObj
, img
, t11
);
1140 img
->FetchTexelf(img
, i1
, j1
, 0, t11
);
1143 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1148 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1149 * We don't have to worry about the texture border.
1152 sample_2d_linear_repeat(GLcontext
*ctx
,
1153 const struct gl_texture_object
*tObj
,
1154 const struct gl_texture_image
*img
,
1155 const GLfloat texcoord
[4],
1158 const GLint width
= img
->Width2
;
1159 const GLint height
= img
->Height2
;
1160 GLint i0
, j0
, i1
, j1
;
1162 GLfloat t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
1166 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1167 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1168 ASSERT(img
->Border
== 0);
1169 ASSERT(img
->_BaseFormat
!= GL_COLOR_INDEX
);
1170 ASSERT(img
->_IsPowerOfTwo
);
1172 linear_repeat_texel_location(width
, texcoord
[0], &i0
, &i1
, &wi
);
1173 linear_repeat_texel_location(height
, texcoord
[1], &j0
, &j1
, &wj
);
1175 img
->FetchTexelf(img
, i0
, j0
, 0, t00
);
1176 img
->FetchTexelf(img
, i1
, j0
, 0, t10
);
1177 img
->FetchTexelf(img
, i0
, j1
, 0, t01
);
1178 img
->FetchTexelf(img
, i1
, j1
, 0, t11
);
1180 lerp_rgba_2d(rgba
, wi
, wj
, t00
, t10
, t01
, t11
);
1185 sample_2d_nearest_mipmap_nearest(GLcontext
*ctx
,
1186 const struct gl_texture_object
*tObj
,
1187 GLuint n
, const GLfloat texcoord
[][4],
1188 const GLfloat lambda
[], GLfloat rgba
[][4])
1191 for (i
= 0; i
< n
; i
++) {
1192 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1193 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1199 sample_2d_linear_mipmap_nearest(GLcontext
*ctx
,
1200 const struct gl_texture_object
*tObj
,
1201 GLuint n
, const GLfloat texcoord
[][4],
1202 const GLfloat lambda
[], GLfloat rgba
[][4])
1205 ASSERT(lambda
!= NULL
);
1206 for (i
= 0; i
< n
; i
++) {
1207 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1208 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1214 sample_2d_nearest_mipmap_linear(GLcontext
*ctx
,
1215 const struct gl_texture_object
*tObj
,
1216 GLuint n
, const GLfloat texcoord
[][4],
1217 const GLfloat lambda
[], GLfloat rgba
[][4])
1220 ASSERT(lambda
!= NULL
);
1221 for (i
= 0; i
< n
; i
++) {
1222 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1223 if (level
>= tObj
->_MaxLevel
) {
1224 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1225 texcoord
[i
], rgba
[i
]);
1228 GLfloat t0
[4], t1
[4]; /* texels */
1229 const GLfloat f
= FRAC(lambda
[i
]);
1230 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1231 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1232 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1239 sample_2d_linear_mipmap_linear( GLcontext
*ctx
,
1240 const struct gl_texture_object
*tObj
,
1241 GLuint n
, const GLfloat texcoord
[][4],
1242 const GLfloat lambda
[], GLfloat rgba
[][4] )
1245 ASSERT(lambda
!= NULL
);
1246 for (i
= 0; i
< n
; i
++) {
1247 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1248 if (level
>= tObj
->_MaxLevel
) {
1249 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1250 texcoord
[i
], rgba
[i
]);
1253 GLfloat t0
[4], t1
[4]; /* texels */
1254 const GLfloat f
= FRAC(lambda
[i
]);
1255 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1256 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1257 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1264 sample_2d_linear_mipmap_linear_repeat(GLcontext
*ctx
,
1265 const struct gl_texture_object
*tObj
,
1266 GLuint n
, const GLfloat texcoord
[][4],
1267 const GLfloat lambda
[], GLfloat rgba
[][4])
1270 ASSERT(lambda
!= NULL
);
1271 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1272 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1273 for (i
= 0; i
< n
; i
++) {
1274 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1275 if (level
>= tObj
->_MaxLevel
) {
1276 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1277 texcoord
[i
], rgba
[i
]);
1280 GLfloat t0
[4], t1
[4]; /* texels */
1281 const GLfloat f
= FRAC(lambda
[i
]);
1282 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
],
1284 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
+1],
1286 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1292 /** Sample 2D texture, nearest filtering for both min/magnification */
1294 sample_nearest_2d(GLcontext
*ctx
,
1295 const struct gl_texture_object
*tObj
, GLuint n
,
1296 const GLfloat texcoords
[][4],
1297 const GLfloat lambda
[], GLfloat rgba
[][4])
1300 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1302 for (i
= 0; i
< n
; i
++) {
1303 sample_2d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1308 /** Sample 2D texture, linear filtering for both min/magnification */
1310 sample_linear_2d(GLcontext
*ctx
,
1311 const struct gl_texture_object
*tObj
, GLuint n
,
1312 const GLfloat texcoords
[][4],
1313 const GLfloat lambda
[], GLfloat rgba
[][4])
1316 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1318 if (tObj
->WrapS
== GL_REPEAT
&&
1319 tObj
->WrapT
== GL_REPEAT
&&
1320 image
->_IsPowerOfTwo
&&
1321 image
->Border
== 0) {
1322 for (i
= 0; i
< n
; i
++) {
1323 sample_2d_linear_repeat(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1327 for (i
= 0; i
< n
; i
++) {
1328 sample_2d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1335 * Optimized 2-D texture sampling:
1336 * S and T wrap mode == GL_REPEAT
1337 * GL_NEAREST min/mag filter
1339 * RowStride == Width,
1343 opt_sample_rgb_2d(GLcontext
*ctx
,
1344 const struct gl_texture_object
*tObj
,
1345 GLuint n
, const GLfloat texcoords
[][4],
1346 const GLfloat lambda
[], GLfloat rgba
[][4])
1348 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1349 const GLfloat width
= (GLfloat
) img
->Width
;
1350 const GLfloat height
= (GLfloat
) img
->Height
;
1351 const GLint colMask
= img
->Width
- 1;
1352 const GLint rowMask
= img
->Height
- 1;
1353 const GLint shift
= img
->WidthLog2
;
1357 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1358 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1359 ASSERT(img
->Border
==0);
1360 ASSERT(img
->TexFormat
== MESA_FORMAT_RGB888
);
1361 ASSERT(img
->_IsPowerOfTwo
);
1363 for (k
=0; k
<n
; k
++) {
1364 GLint i
= IFLOOR(texcoords
[k
][0] * width
) & colMask
;
1365 GLint j
= IFLOOR(texcoords
[k
][1] * height
) & rowMask
;
1366 GLint pos
= (j
<< shift
) | i
;
1367 GLubyte
*texel
= ((GLubyte
*) img
->Data
) + 3*pos
;
1368 rgba
[k
][RCOMP
] = UBYTE_TO_FLOAT(texel
[2]);
1369 rgba
[k
][GCOMP
] = UBYTE_TO_FLOAT(texel
[1]);
1370 rgba
[k
][BCOMP
] = UBYTE_TO_FLOAT(texel
[0]);
1376 * Optimized 2-D texture sampling:
1377 * S and T wrap mode == GL_REPEAT
1378 * GL_NEAREST min/mag filter
1380 * RowStride == Width,
1384 opt_sample_rgba_2d(GLcontext
*ctx
,
1385 const struct gl_texture_object
*tObj
,
1386 GLuint n
, const GLfloat texcoords
[][4],
1387 const GLfloat lambda
[], GLfloat rgba
[][4])
1389 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1390 const GLfloat width
= (GLfloat
) img
->Width
;
1391 const GLfloat height
= (GLfloat
) img
->Height
;
1392 const GLint colMask
= img
->Width
- 1;
1393 const GLint rowMask
= img
->Height
- 1;
1394 const GLint shift
= img
->WidthLog2
;
1398 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1399 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1400 ASSERT(img
->Border
==0);
1401 ASSERT(img
->TexFormat
== MESA_FORMAT_RGBA8888
);
1402 ASSERT(img
->_IsPowerOfTwo
);
1404 for (i
= 0; i
< n
; i
++) {
1405 const GLint col
= IFLOOR(texcoords
[i
][0] * width
) & colMask
;
1406 const GLint row
= IFLOOR(texcoords
[i
][1] * height
) & rowMask
;
1407 const GLint pos
= (row
<< shift
) | col
;
1408 const GLuint texel
= *((GLuint
*) img
->Data
+ pos
);
1409 rgba
[i
][RCOMP
] = UBYTE_TO_FLOAT( (texel
>> 24) );
1410 rgba
[i
][GCOMP
] = UBYTE_TO_FLOAT( (texel
>> 16) & 0xff );
1411 rgba
[i
][BCOMP
] = UBYTE_TO_FLOAT( (texel
>> 8) & 0xff );
1412 rgba
[i
][ACOMP
] = UBYTE_TO_FLOAT( (texel
) & 0xff );
1417 /** Sample 2D texture, using lambda to choose between min/magnification */
1419 sample_lambda_2d(GLcontext
*ctx
,
1420 const struct gl_texture_object
*tObj
,
1421 GLuint n
, const GLfloat texcoords
[][4],
1422 const GLfloat lambda
[], GLfloat rgba
[][4])
1424 const struct gl_texture_image
*tImg
= tObj
->Image
[0][tObj
->BaseLevel
];
1425 GLuint minStart
, minEnd
; /* texels with minification */
1426 GLuint magStart
, magEnd
; /* texels with magnification */
1428 const GLboolean repeatNoBorderPOT
= (tObj
->WrapS
== GL_REPEAT
)
1429 && (tObj
->WrapT
== GL_REPEAT
)
1430 && (tImg
->Border
== 0 && (tImg
->Width
== tImg
->RowStride
))
1431 && (tImg
->_BaseFormat
!= GL_COLOR_INDEX
)
1432 && tImg
->_IsPowerOfTwo
;
1434 ASSERT(lambda
!= NULL
);
1435 compute_min_mag_ranges(tObj
, n
, lambda
,
1436 &minStart
, &minEnd
, &magStart
, &magEnd
);
1438 if (minStart
< minEnd
) {
1439 /* do the minified texels */
1440 const GLuint m
= minEnd
- minStart
;
1441 switch (tObj
->MinFilter
) {
1443 if (repeatNoBorderPOT
) {
1444 switch (tImg
->TexFormat
) {
1445 case MESA_FORMAT_RGB888
:
1446 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1447 NULL
, rgba
+ minStart
);
1449 case MESA_FORMAT_RGBA8888
:
1450 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1451 NULL
, rgba
+ minStart
);
1454 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1455 NULL
, rgba
+ minStart
);
1459 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1460 NULL
, rgba
+ minStart
);
1464 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1465 NULL
, rgba
+ minStart
);
1467 case GL_NEAREST_MIPMAP_NEAREST
:
1468 sample_2d_nearest_mipmap_nearest(ctx
, tObj
, m
,
1469 texcoords
+ minStart
,
1470 lambda
+ minStart
, rgba
+ minStart
);
1472 case GL_LINEAR_MIPMAP_NEAREST
:
1473 sample_2d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1474 lambda
+ minStart
, rgba
+ minStart
);
1476 case GL_NEAREST_MIPMAP_LINEAR
:
1477 sample_2d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1478 lambda
+ minStart
, rgba
+ minStart
);
1480 case GL_LINEAR_MIPMAP_LINEAR
:
1481 if (repeatNoBorderPOT
)
1482 sample_2d_linear_mipmap_linear_repeat(ctx
, tObj
, m
,
1483 texcoords
+ minStart
, lambda
+ minStart
, rgba
+ minStart
);
1485 sample_2d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1486 lambda
+ minStart
, rgba
+ minStart
);
1489 _mesa_problem(ctx
, "Bad min filter in sample_2d_texture");
1494 if (magStart
< magEnd
) {
1495 /* do the magnified texels */
1496 const GLuint m
= magEnd
- magStart
;
1498 switch (tObj
->MagFilter
) {
1500 if (repeatNoBorderPOT
) {
1501 switch (tImg
->TexFormat
) {
1502 case MESA_FORMAT_RGB888
:
1503 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1504 NULL
, rgba
+ magStart
);
1506 case MESA_FORMAT_RGBA8888
:
1507 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1508 NULL
, rgba
+ magStart
);
1511 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1512 NULL
, rgba
+ magStart
);
1516 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1517 NULL
, rgba
+ magStart
);
1521 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1522 NULL
, rgba
+ magStart
);
1525 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_2d");
1532 /**********************************************************************/
1533 /* 3-D Texture Sampling Functions */
1534 /**********************************************************************/
1537 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1540 sample_3d_nearest(GLcontext
*ctx
,
1541 const struct gl_texture_object
*tObj
,
1542 const struct gl_texture_image
*img
,
1543 const GLfloat texcoord
[4],
1546 const GLint width
= img
->Width2
; /* without border, power of two */
1547 const GLint height
= img
->Height2
; /* without border, power of two */
1548 const GLint depth
= img
->Depth2
; /* without border, power of two */
1552 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
1553 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
1554 k
= nearest_texel_location(tObj
->WrapR
, img
, depth
, texcoord
[2]);
1556 if (i
< 0 || i
>= (GLint
) img
->Width
||
1557 j
< 0 || j
>= (GLint
) img
->Height
||
1558 k
< 0 || k
>= (GLint
) img
->Depth
) {
1559 /* Need this test for GL_CLAMP_TO_BORDER mode */
1560 get_border_color(tObj
, img
, rgba
);
1563 img
->FetchTexelf(img
, i
, j
, k
, rgba
);
1569 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1572 sample_3d_linear(GLcontext
*ctx
,
1573 const struct gl_texture_object
*tObj
,
1574 const struct gl_texture_image
*img
,
1575 const GLfloat texcoord
[4],
1578 const GLint width
= img
->Width2
;
1579 const GLint height
= img
->Height2
;
1580 const GLint depth
= img
->Depth2
;
1581 GLint i0
, j0
, k0
, i1
, j1
, k1
;
1582 GLbitfield useBorderColor
= 0x0;
1584 GLfloat t000
[4], t010
[4], t001
[4], t011
[4];
1585 GLfloat t100
[4], t110
[4], t101
[4], t111
[4];
1587 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
1588 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
1589 linear_texel_locations(tObj
->WrapR
, img
, depth
, texcoord
[2], &k0
, &k1
, &c
);
1600 /* check if sampling texture border color */
1601 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1602 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1603 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1604 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1605 if (k0
< 0 || k0
>= depth
) useBorderColor
|= K0BIT
;
1606 if (k1
< 0 || k1
>= depth
) useBorderColor
|= K1BIT
;
1610 if (useBorderColor
& (I0BIT
| J0BIT
| K0BIT
)) {
1611 get_border_color(tObj
, img
, t000
);
1614 img
->FetchTexelf(img
, i0
, j0
, k0
, t000
);
1616 if (useBorderColor
& (I1BIT
| J0BIT
| K0BIT
)) {
1617 get_border_color(tObj
, img
, t100
);
1620 img
->FetchTexelf(img
, i1
, j0
, k0
, t100
);
1622 if (useBorderColor
& (I0BIT
| J1BIT
| K0BIT
)) {
1623 get_border_color(tObj
, img
, t010
);
1626 img
->FetchTexelf(img
, i0
, j1
, k0
, t010
);
1628 if (useBorderColor
& (I1BIT
| J1BIT
| K0BIT
)) {
1629 get_border_color(tObj
, img
, t110
);
1632 img
->FetchTexelf(img
, i1
, j1
, k0
, t110
);
1635 if (useBorderColor
& (I0BIT
| J0BIT
| K1BIT
)) {
1636 get_border_color(tObj
, img
, t001
);
1639 img
->FetchTexelf(img
, i0
, j0
, k1
, t001
);
1641 if (useBorderColor
& (I1BIT
| J0BIT
| K1BIT
)) {
1642 get_border_color(tObj
, img
, t101
);
1645 img
->FetchTexelf(img
, i1
, j0
, k1
, t101
);
1647 if (useBorderColor
& (I0BIT
| J1BIT
| K1BIT
)) {
1648 get_border_color(tObj
, img
, t011
);
1651 img
->FetchTexelf(img
, i0
, j1
, k1
, t011
);
1653 if (useBorderColor
& (I1BIT
| J1BIT
| K1BIT
)) {
1654 get_border_color(tObj
, img
, t111
);
1657 img
->FetchTexelf(img
, i1
, j1
, k1
, t111
);
1660 /* trilinear interpolation of samples */
1661 lerp_rgba_3d(rgba
, a
, b
, c
, t000
, t100
, t010
, t110
, t001
, t101
, t011
, t111
);
1666 sample_3d_nearest_mipmap_nearest(GLcontext
*ctx
,
1667 const struct gl_texture_object
*tObj
,
1668 GLuint n
, const GLfloat texcoord
[][4],
1669 const GLfloat lambda
[], GLfloat rgba
[][4] )
1672 for (i
= 0; i
< n
; i
++) {
1673 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1674 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1680 sample_3d_linear_mipmap_nearest(GLcontext
*ctx
,
1681 const struct gl_texture_object
*tObj
,
1682 GLuint n
, const GLfloat texcoord
[][4],
1683 const GLfloat lambda
[], GLfloat rgba
[][4])
1686 ASSERT(lambda
!= NULL
);
1687 for (i
= 0; i
< n
; i
++) {
1688 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1689 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1695 sample_3d_nearest_mipmap_linear(GLcontext
*ctx
,
1696 const struct gl_texture_object
*tObj
,
1697 GLuint n
, const GLfloat texcoord
[][4],
1698 const GLfloat lambda
[], GLfloat rgba
[][4])
1701 ASSERT(lambda
!= NULL
);
1702 for (i
= 0; i
< n
; i
++) {
1703 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1704 if (level
>= tObj
->_MaxLevel
) {
1705 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1706 texcoord
[i
], rgba
[i
]);
1709 GLfloat t0
[4], t1
[4]; /* texels */
1710 const GLfloat f
= FRAC(lambda
[i
]);
1711 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1712 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1713 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1720 sample_3d_linear_mipmap_linear(GLcontext
*ctx
,
1721 const struct gl_texture_object
*tObj
,
1722 GLuint n
, const GLfloat texcoord
[][4],
1723 const GLfloat lambda
[], GLfloat rgba
[][4])
1726 ASSERT(lambda
!= NULL
);
1727 for (i
= 0; i
< n
; i
++) {
1728 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1729 if (level
>= tObj
->_MaxLevel
) {
1730 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1731 texcoord
[i
], rgba
[i
]);
1734 GLfloat t0
[4], t1
[4]; /* texels */
1735 const GLfloat f
= FRAC(lambda
[i
]);
1736 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1737 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1738 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1744 /** Sample 3D texture, nearest filtering for both min/magnification */
1746 sample_nearest_3d(GLcontext
*ctx
,
1747 const struct gl_texture_object
*tObj
, GLuint n
,
1748 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1752 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1754 for (i
= 0; i
< n
; i
++) {
1755 sample_3d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1760 /** Sample 3D texture, linear filtering for both min/magnification */
1762 sample_linear_3d(GLcontext
*ctx
,
1763 const struct gl_texture_object
*tObj
, GLuint n
,
1764 const GLfloat texcoords
[][4],
1765 const GLfloat lambda
[], GLfloat rgba
[][4])
1768 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1770 for (i
= 0; i
< n
; i
++) {
1771 sample_3d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1776 /** Sample 3D texture, using lambda to choose between min/magnification */
1778 sample_lambda_3d(GLcontext
*ctx
,
1779 const struct gl_texture_object
*tObj
, GLuint n
,
1780 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1783 GLuint minStart
, minEnd
; /* texels with minification */
1784 GLuint magStart
, magEnd
; /* texels with magnification */
1787 ASSERT(lambda
!= NULL
);
1788 compute_min_mag_ranges(tObj
, n
, lambda
,
1789 &minStart
, &minEnd
, &magStart
, &magEnd
);
1791 if (minStart
< minEnd
) {
1792 /* do the minified texels */
1793 GLuint m
= minEnd
- minStart
;
1794 switch (tObj
->MinFilter
) {
1796 for (i
= minStart
; i
< minEnd
; i
++)
1797 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1798 texcoords
[i
], rgba
[i
]);
1801 for (i
= minStart
; i
< minEnd
; i
++)
1802 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1803 texcoords
[i
], rgba
[i
]);
1805 case GL_NEAREST_MIPMAP_NEAREST
:
1806 sample_3d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1807 lambda
+ minStart
, rgba
+ minStart
);
1809 case GL_LINEAR_MIPMAP_NEAREST
:
1810 sample_3d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1811 lambda
+ minStart
, rgba
+ minStart
);
1813 case GL_NEAREST_MIPMAP_LINEAR
:
1814 sample_3d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1815 lambda
+ minStart
, rgba
+ minStart
);
1817 case GL_LINEAR_MIPMAP_LINEAR
:
1818 sample_3d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1819 lambda
+ minStart
, rgba
+ minStart
);
1822 _mesa_problem(ctx
, "Bad min filter in sample_3d_texture");
1827 if (magStart
< magEnd
) {
1828 /* do the magnified texels */
1829 switch (tObj
->MagFilter
) {
1831 for (i
= magStart
; i
< magEnd
; i
++)
1832 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1833 texcoords
[i
], rgba
[i
]);
1836 for (i
= magStart
; i
< magEnd
; i
++)
1837 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1838 texcoords
[i
], rgba
[i
]);
1841 _mesa_problem(ctx
, "Bad mag filter in sample_3d_texture");
1848 /**********************************************************************/
1849 /* Texture Cube Map Sampling Functions */
1850 /**********************************************************************/
1853 * Choose one of six sides of a texture cube map given the texture
1854 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1857 static const struct gl_texture_image
**
1858 choose_cube_face(const struct gl_texture_object
*texObj
,
1859 const GLfloat texcoord
[4], GLfloat newCoord
[4])
1863 direction target sc tc ma
1864 ---------- ------------------------------- --- --- ---
1865 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1866 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1867 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1868 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1869 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1870 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1872 const GLfloat rx
= texcoord
[0];
1873 const GLfloat ry
= texcoord
[1];
1874 const GLfloat rz
= texcoord
[2];
1875 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
1879 if (arx
>= ary
&& arx
>= arz
) {
1893 else if (ary
>= arx
&& ary
>= arz
) {
1923 const float ima
= 1.0F
/ ma
;
1924 newCoord
[0] = ( sc
* ima
+ 1.0F
) * 0.5F
;
1925 newCoord
[1] = ( tc
* ima
+ 1.0F
) * 0.5F
;
1928 return (const struct gl_texture_image
**) texObj
->Image
[face
];
1933 sample_nearest_cube(GLcontext
*ctx
,
1934 const struct gl_texture_object
*tObj
, GLuint n
,
1935 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1940 for (i
= 0; i
< n
; i
++) {
1941 const struct gl_texture_image
**images
;
1942 GLfloat newCoord
[4];
1943 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1944 sample_2d_nearest(ctx
, tObj
, images
[tObj
->BaseLevel
],
1951 sample_linear_cube(GLcontext
*ctx
,
1952 const struct gl_texture_object
*tObj
, GLuint n
,
1953 const GLfloat texcoords
[][4],
1954 const GLfloat lambda
[], GLfloat rgba
[][4])
1958 for (i
= 0; i
< n
; i
++) {
1959 const struct gl_texture_image
**images
;
1960 GLfloat newCoord
[4];
1961 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1962 sample_2d_linear(ctx
, tObj
, images
[tObj
->BaseLevel
],
1969 sample_cube_nearest_mipmap_nearest(GLcontext
*ctx
,
1970 const struct gl_texture_object
*tObj
,
1971 GLuint n
, const GLfloat texcoord
[][4],
1972 const GLfloat lambda
[], GLfloat rgba
[][4])
1975 ASSERT(lambda
!= NULL
);
1976 for (i
= 0; i
< n
; i
++) {
1977 const struct gl_texture_image
**images
;
1978 GLfloat newCoord
[4];
1980 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1982 /* XXX we actually need to recompute lambda here based on the newCoords.
1983 * But we would need the texcoords of adjacent fragments to compute that
1984 * properly, and we don't have those here.
1985 * For now, do an approximation: subtracting 1 from the chosen mipmap
1986 * level seems to work in some test cases.
1987 * The same adjustment is done in the next few functions.
1989 level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1990 level
= MAX2(level
- 1, 0);
1992 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1998 sample_cube_linear_mipmap_nearest(GLcontext
*ctx
,
1999 const struct gl_texture_object
*tObj
,
2000 GLuint n
, const GLfloat texcoord
[][4],
2001 const GLfloat lambda
[], GLfloat rgba
[][4])
2004 ASSERT(lambda
!= NULL
);
2005 for (i
= 0; i
< n
; i
++) {
2006 const struct gl_texture_image
**images
;
2007 GLfloat newCoord
[4];
2008 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2009 level
= MAX2(level
- 1, 0); /* see comment above */
2010 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
2011 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
2017 sample_cube_nearest_mipmap_linear(GLcontext
*ctx
,
2018 const struct gl_texture_object
*tObj
,
2019 GLuint n
, const GLfloat texcoord
[][4],
2020 const GLfloat lambda
[], GLfloat rgba
[][4])
2023 ASSERT(lambda
!= NULL
);
2024 for (i
= 0; i
< n
; i
++) {
2025 const struct gl_texture_image
**images
;
2026 GLfloat newCoord
[4];
2027 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2028 level
= MAX2(level
- 1, 0); /* see comment above */
2029 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
2030 if (level
>= tObj
->_MaxLevel
) {
2031 sample_2d_nearest(ctx
, tObj
, images
[tObj
->_MaxLevel
],
2035 GLfloat t0
[4], t1
[4]; /* texels */
2036 const GLfloat f
= FRAC(lambda
[i
]);
2037 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, t0
);
2038 sample_2d_nearest(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
2039 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2046 sample_cube_linear_mipmap_linear(GLcontext
*ctx
,
2047 const struct gl_texture_object
*tObj
,
2048 GLuint n
, const GLfloat texcoord
[][4],
2049 const GLfloat lambda
[], GLfloat rgba
[][4])
2052 ASSERT(lambda
!= NULL
);
2053 for (i
= 0; i
< n
; i
++) {
2054 const struct gl_texture_image
**images
;
2055 GLfloat newCoord
[4];
2056 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2057 level
= MAX2(level
- 1, 0); /* see comment above */
2058 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
2059 if (level
>= tObj
->_MaxLevel
) {
2060 sample_2d_linear(ctx
, tObj
, images
[tObj
->_MaxLevel
],
2064 GLfloat t0
[4], t1
[4];
2065 const GLfloat f
= FRAC(lambda
[i
]);
2066 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, t0
);
2067 sample_2d_linear(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
2068 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2074 /** Sample cube texture, using lambda to choose between min/magnification */
2076 sample_lambda_cube(GLcontext
*ctx
,
2077 const struct gl_texture_object
*tObj
, GLuint n
,
2078 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2081 GLuint minStart
, minEnd
; /* texels with minification */
2082 GLuint magStart
, magEnd
; /* texels with magnification */
2084 ASSERT(lambda
!= NULL
);
2085 compute_min_mag_ranges(tObj
, n
, lambda
,
2086 &minStart
, &minEnd
, &magStart
, &magEnd
);
2088 if (minStart
< minEnd
) {
2089 /* do the minified texels */
2090 const GLuint m
= minEnd
- minStart
;
2091 switch (tObj
->MinFilter
) {
2093 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
2094 lambda
+ minStart
, rgba
+ minStart
);
2097 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
2098 lambda
+ minStart
, rgba
+ minStart
);
2100 case GL_NEAREST_MIPMAP_NEAREST
:
2101 sample_cube_nearest_mipmap_nearest(ctx
, tObj
, m
,
2102 texcoords
+ minStart
,
2103 lambda
+ minStart
, rgba
+ minStart
);
2105 case GL_LINEAR_MIPMAP_NEAREST
:
2106 sample_cube_linear_mipmap_nearest(ctx
, tObj
, m
,
2107 texcoords
+ minStart
,
2108 lambda
+ minStart
, rgba
+ minStart
);
2110 case GL_NEAREST_MIPMAP_LINEAR
:
2111 sample_cube_nearest_mipmap_linear(ctx
, tObj
, m
,
2112 texcoords
+ minStart
,
2113 lambda
+ minStart
, rgba
+ minStart
);
2115 case GL_LINEAR_MIPMAP_LINEAR
:
2116 sample_cube_linear_mipmap_linear(ctx
, tObj
, m
,
2117 texcoords
+ minStart
,
2118 lambda
+ minStart
, rgba
+ minStart
);
2121 _mesa_problem(ctx
, "Bad min filter in sample_lambda_cube");
2125 if (magStart
< magEnd
) {
2126 /* do the magnified texels */
2127 const GLuint m
= magEnd
- magStart
;
2128 switch (tObj
->MagFilter
) {
2130 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2131 lambda
+ magStart
, rgba
+ magStart
);
2134 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2135 lambda
+ magStart
, rgba
+ magStart
);
2138 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_cube");
2144 /**********************************************************************/
2145 /* Texture Rectangle Sampling Functions */
2146 /**********************************************************************/
2150 sample_nearest_rect(GLcontext
*ctx
,
2151 const struct gl_texture_object
*tObj
, GLuint n
,
2152 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2155 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2156 const GLint width
= img
->Width
;
2157 const GLint height
= img
->Height
;
2163 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2164 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2165 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2166 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2167 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2168 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2169 ASSERT(img
->_BaseFormat
!= GL_COLOR_INDEX
);
2171 for (i
= 0; i
< n
; i
++) {
2173 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2174 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2175 if (col
< 0 || col
>= width
|| row
< 0 || row
>= height
)
2176 get_border_color(tObj
, img
, rgba
[i
]);
2178 img
->FetchTexelf(img
, col
, row
, 0, rgba
[i
]);
2184 sample_linear_rect(GLcontext
*ctx
,
2185 const struct gl_texture_object
*tObj
, GLuint n
,
2186 const GLfloat texcoords
[][4],
2187 const GLfloat lambda
[], GLfloat rgba
[][4])
2189 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2190 const GLint width
= img
->Width
;
2191 const GLint height
= img
->Height
;
2197 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2198 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2199 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2200 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2201 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2202 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2203 ASSERT(img
->_BaseFormat
!= GL_COLOR_INDEX
);
2205 for (i
= 0; i
< n
; i
++) {
2206 GLint i0
, j0
, i1
, j1
;
2207 GLfloat t00
[4], t01
[4], t10
[4], t11
[4];
2209 GLbitfield useBorderColor
= 0x0;
2211 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0], width
,
2213 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1], height
,
2216 /* compute integer rows/columns */
2217 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2218 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2219 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2220 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2222 /* get four texel samples */
2223 if (useBorderColor
& (I0BIT
| J0BIT
))
2224 get_border_color(tObj
, img
, t00
);
2226 img
->FetchTexelf(img
, i0
, j0
, 0, t00
);
2228 if (useBorderColor
& (I1BIT
| J0BIT
))
2229 get_border_color(tObj
, img
, t10
);
2231 img
->FetchTexelf(img
, i1
, j0
, 0, t10
);
2233 if (useBorderColor
& (I0BIT
| J1BIT
))
2234 get_border_color(tObj
, img
, t01
);
2236 img
->FetchTexelf(img
, i0
, j1
, 0, t01
);
2238 if (useBorderColor
& (I1BIT
| J1BIT
))
2239 get_border_color(tObj
, img
, t11
);
2241 img
->FetchTexelf(img
, i1
, j1
, 0, t11
);
2243 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2248 /** Sample Rect texture, using lambda to choose between min/magnification */
2250 sample_lambda_rect(GLcontext
*ctx
,
2251 const struct gl_texture_object
*tObj
, GLuint n
,
2252 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2255 GLuint minStart
, minEnd
, magStart
, magEnd
;
2257 /* We only need lambda to decide between minification and magnification.
2258 * There is no mipmapping with rectangular textures.
2260 compute_min_mag_ranges(tObj
, n
, lambda
,
2261 &minStart
, &minEnd
, &magStart
, &magEnd
);
2263 if (minStart
< minEnd
) {
2264 if (tObj
->MinFilter
== GL_NEAREST
) {
2265 sample_nearest_rect(ctx
, tObj
, minEnd
- minStart
,
2266 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2269 sample_linear_rect(ctx
, tObj
, minEnd
- minStart
,
2270 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2273 if (magStart
< magEnd
) {
2274 if (tObj
->MagFilter
== GL_NEAREST
) {
2275 sample_nearest_rect(ctx
, tObj
, magEnd
- magStart
,
2276 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2279 sample_linear_rect(ctx
, tObj
, magEnd
- magStart
,
2280 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2286 /**********************************************************************/
2287 /* 2D Texture Array Sampling Functions */
2288 /**********************************************************************/
2291 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2294 sample_2d_array_nearest(GLcontext
*ctx
,
2295 const struct gl_texture_object
*tObj
,
2296 const struct gl_texture_image
*img
,
2297 const GLfloat texcoord
[4],
2300 const GLint width
= img
->Width2
; /* without border, power of two */
2301 const GLint height
= img
->Height2
; /* without border, power of two */
2302 const GLint depth
= img
->Depth
;
2307 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2308 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
2309 array
= tex_array_slice(texcoord
[2], depth
);
2311 if (i
< 0 || i
>= (GLint
) img
->Width
||
2312 j
< 0 || j
>= (GLint
) img
->Height
||
2313 array
< 0 || array
>= (GLint
) img
->Depth
) {
2314 /* Need this test for GL_CLAMP_TO_BORDER mode */
2315 get_border_color(tObj
, img
, rgba
);
2318 img
->FetchTexelf(img
, i
, j
, array
, rgba
);
2324 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2327 sample_2d_array_linear(GLcontext
*ctx
,
2328 const struct gl_texture_object
*tObj
,
2329 const struct gl_texture_image
*img
,
2330 const GLfloat texcoord
[4],
2333 const GLint width
= img
->Width2
;
2334 const GLint height
= img
->Height2
;
2335 const GLint depth
= img
->Depth
;
2336 GLint i0
, j0
, i1
, j1
;
2338 GLbitfield useBorderColor
= 0x0;
2340 GLfloat t00
[4], t01
[4], t10
[4], t11
[4];
2342 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2343 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
2344 array
= tex_array_slice(texcoord
[2], depth
);
2346 if (array
< 0 || array
>= depth
) {
2347 COPY_4V(rgba
, tObj
->BorderColor
.f
);
2357 /* check if sampling texture border color */
2358 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2359 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2360 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2361 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2365 if (useBorderColor
& (I0BIT
| J0BIT
)) {
2366 get_border_color(tObj
, img
, t00
);
2369 img
->FetchTexelf(img
, i0
, j0
, array
, t00
);
2371 if (useBorderColor
& (I1BIT
| J0BIT
)) {
2372 get_border_color(tObj
, img
, t10
);
2375 img
->FetchTexelf(img
, i1
, j0
, array
, t10
);
2377 if (useBorderColor
& (I0BIT
| J1BIT
)) {
2378 get_border_color(tObj
, img
, t01
);
2381 img
->FetchTexelf(img
, i0
, j1
, array
, t01
);
2383 if (useBorderColor
& (I1BIT
| J1BIT
)) {
2384 get_border_color(tObj
, img
, t11
);
2387 img
->FetchTexelf(img
, i1
, j1
, array
, t11
);
2390 /* trilinear interpolation of samples */
2391 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
2397 sample_2d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2398 const struct gl_texture_object
*tObj
,
2399 GLuint n
, const GLfloat texcoord
[][4],
2400 const GLfloat lambda
[], GLfloat rgba
[][4])
2403 for (i
= 0; i
< n
; i
++) {
2404 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2405 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2412 sample_2d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2413 const struct gl_texture_object
*tObj
,
2414 GLuint n
, const GLfloat texcoord
[][4],
2415 const GLfloat lambda
[], GLfloat rgba
[][4])
2418 ASSERT(lambda
!= NULL
);
2419 for (i
= 0; i
< n
; i
++) {
2420 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2421 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2422 texcoord
[i
], rgba
[i
]);
2428 sample_2d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2429 const struct gl_texture_object
*tObj
,
2430 GLuint n
, const GLfloat texcoord
[][4],
2431 const GLfloat lambda
[], GLfloat rgba
[][4])
2434 ASSERT(lambda
!= NULL
);
2435 for (i
= 0; i
< n
; i
++) {
2436 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2437 if (level
>= tObj
->_MaxLevel
) {
2438 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2439 texcoord
[i
], rgba
[i
]);
2442 GLfloat t0
[4], t1
[4]; /* texels */
2443 const GLfloat f
= FRAC(lambda
[i
]);
2444 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
],
2446 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1],
2448 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2455 sample_2d_array_linear_mipmap_linear(GLcontext
*ctx
,
2456 const struct gl_texture_object
*tObj
,
2457 GLuint n
, const GLfloat texcoord
[][4],
2458 const GLfloat lambda
[], GLfloat rgba
[][4])
2461 ASSERT(lambda
!= NULL
);
2462 for (i
= 0; i
< n
; i
++) {
2463 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2464 if (level
>= tObj
->_MaxLevel
) {
2465 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2466 texcoord
[i
], rgba
[i
]);
2469 GLfloat t0
[4], t1
[4]; /* texels */
2470 const GLfloat f
= FRAC(lambda
[i
]);
2471 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2473 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1],
2475 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2481 /** Sample 2D Array texture, nearest filtering for both min/magnification */
2483 sample_nearest_2d_array(GLcontext
*ctx
,
2484 const struct gl_texture_object
*tObj
, GLuint n
,
2485 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2489 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2491 for (i
= 0; i
< n
; i
++) {
2492 sample_2d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2498 /** Sample 2D Array texture, linear filtering for both min/magnification */
2500 sample_linear_2d_array(GLcontext
*ctx
,
2501 const struct gl_texture_object
*tObj
, GLuint n
,
2502 const GLfloat texcoords
[][4],
2503 const GLfloat lambda
[], GLfloat rgba
[][4])
2506 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2508 for (i
= 0; i
< n
; i
++) {
2509 sample_2d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2514 /** Sample 2D Array texture, using lambda to choose between min/magnification */
2516 sample_lambda_2d_array(GLcontext
*ctx
,
2517 const struct gl_texture_object
*tObj
, GLuint n
,
2518 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2521 GLuint minStart
, minEnd
; /* texels with minification */
2522 GLuint magStart
, magEnd
; /* texels with magnification */
2525 ASSERT(lambda
!= NULL
);
2526 compute_min_mag_ranges(tObj
, n
, lambda
,
2527 &minStart
, &minEnd
, &magStart
, &magEnd
);
2529 if (minStart
< minEnd
) {
2530 /* do the minified texels */
2531 GLuint m
= minEnd
- minStart
;
2532 switch (tObj
->MinFilter
) {
2534 for (i
= minStart
; i
< minEnd
; i
++)
2535 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2536 texcoords
[i
], rgba
[i
]);
2539 for (i
= minStart
; i
< minEnd
; i
++)
2540 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2541 texcoords
[i
], rgba
[i
]);
2543 case GL_NEAREST_MIPMAP_NEAREST
:
2544 sample_2d_array_nearest_mipmap_nearest(ctx
, tObj
, m
,
2545 texcoords
+ minStart
,
2549 case GL_LINEAR_MIPMAP_NEAREST
:
2550 sample_2d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2551 texcoords
+ minStart
,
2555 case GL_NEAREST_MIPMAP_LINEAR
:
2556 sample_2d_array_nearest_mipmap_linear(ctx
, tObj
, m
,
2557 texcoords
+ minStart
,
2561 case GL_LINEAR_MIPMAP_LINEAR
:
2562 sample_2d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2563 texcoords
+ minStart
,
2568 _mesa_problem(ctx
, "Bad min filter in sample_2d_array_texture");
2573 if (magStart
< magEnd
) {
2574 /* do the magnified texels */
2575 switch (tObj
->MagFilter
) {
2577 for (i
= magStart
; i
< magEnd
; i
++)
2578 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2579 texcoords
[i
], rgba
[i
]);
2582 for (i
= magStart
; i
< magEnd
; i
++)
2583 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2584 texcoords
[i
], rgba
[i
]);
2587 _mesa_problem(ctx
, "Bad mag filter in sample_2d_array_texture");
2596 /**********************************************************************/
2597 /* 1D Texture Array Sampling Functions */
2598 /**********************************************************************/
2601 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2604 sample_1d_array_nearest(GLcontext
*ctx
,
2605 const struct gl_texture_object
*tObj
,
2606 const struct gl_texture_image
*img
,
2607 const GLfloat texcoord
[4],
2610 const GLint width
= img
->Width2
; /* without border, power of two */
2611 const GLint height
= img
->Height
;
2616 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2617 array
= tex_array_slice(texcoord
[1], height
);
2619 if (i
< 0 || i
>= (GLint
) img
->Width
||
2620 array
< 0 || array
>= (GLint
) img
->Height
) {
2621 /* Need this test for GL_CLAMP_TO_BORDER mode */
2622 get_border_color(tObj
, img
, rgba
);
2625 img
->FetchTexelf(img
, i
, array
, 0, rgba
);
2631 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2634 sample_1d_array_linear(GLcontext
*ctx
,
2635 const struct gl_texture_object
*tObj
,
2636 const struct gl_texture_image
*img
,
2637 const GLfloat texcoord
[4],
2640 const GLint width
= img
->Width2
;
2641 const GLint height
= img
->Height
;
2644 GLbitfield useBorderColor
= 0x0;
2646 GLfloat t0
[4], t1
[4];
2648 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2649 array
= tex_array_slice(texcoord
[1], height
);
2656 /* check if sampling texture border color */
2657 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2658 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2661 if (array
< 0 || array
>= height
) useBorderColor
|= K0BIT
;
2664 if (useBorderColor
& (I0BIT
| K0BIT
)) {
2665 get_border_color(tObj
, img
, t0
);
2668 img
->FetchTexelf(img
, i0
, array
, 0, t0
);
2670 if (useBorderColor
& (I1BIT
| K0BIT
)) {
2671 get_border_color(tObj
, img
, t1
);
2674 img
->FetchTexelf(img
, i1
, array
, 0, t1
);
2677 /* bilinear interpolation of samples */
2678 lerp_rgba(rgba
, a
, t0
, t1
);
2683 sample_1d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2684 const struct gl_texture_object
*tObj
,
2685 GLuint n
, const GLfloat texcoord
[][4],
2686 const GLfloat lambda
[], GLfloat rgba
[][4])
2689 for (i
= 0; i
< n
; i
++) {
2690 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2691 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2698 sample_1d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2699 const struct gl_texture_object
*tObj
,
2700 GLuint n
, const GLfloat texcoord
[][4],
2701 const GLfloat lambda
[], GLfloat rgba
[][4])
2704 ASSERT(lambda
!= NULL
);
2705 for (i
= 0; i
< n
; i
++) {
2706 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2707 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2708 texcoord
[i
], rgba
[i
]);
2714 sample_1d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2715 const struct gl_texture_object
*tObj
,
2716 GLuint n
, const GLfloat texcoord
[][4],
2717 const GLfloat lambda
[], GLfloat rgba
[][4])
2720 ASSERT(lambda
!= NULL
);
2721 for (i
= 0; i
< n
; i
++) {
2722 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2723 if (level
>= tObj
->_MaxLevel
) {
2724 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2725 texcoord
[i
], rgba
[i
]);
2728 GLfloat t0
[4], t1
[4]; /* texels */
2729 const GLfloat f
= FRAC(lambda
[i
]);
2730 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2731 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2732 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2739 sample_1d_array_linear_mipmap_linear(GLcontext
*ctx
,
2740 const struct gl_texture_object
*tObj
,
2741 GLuint n
, const GLfloat texcoord
[][4],
2742 const GLfloat lambda
[], GLfloat rgba
[][4])
2745 ASSERT(lambda
!= NULL
);
2746 for (i
= 0; i
< n
; i
++) {
2747 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2748 if (level
>= tObj
->_MaxLevel
) {
2749 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2750 texcoord
[i
], rgba
[i
]);
2753 GLfloat t0
[4], t1
[4]; /* texels */
2754 const GLfloat f
= FRAC(lambda
[i
]);
2755 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2756 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2757 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2763 /** Sample 1D Array texture, nearest filtering for both min/magnification */
2765 sample_nearest_1d_array(GLcontext
*ctx
,
2766 const struct gl_texture_object
*tObj
, GLuint n
,
2767 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2771 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2773 for (i
= 0; i
< n
; i
++) {
2774 sample_1d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2779 /** Sample 1D Array texture, linear filtering for both min/magnification */
2781 sample_linear_1d_array(GLcontext
*ctx
,
2782 const struct gl_texture_object
*tObj
, GLuint n
,
2783 const GLfloat texcoords
[][4],
2784 const GLfloat lambda
[], GLfloat rgba
[][4])
2787 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2789 for (i
= 0; i
< n
; i
++) {
2790 sample_1d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2795 /** Sample 1D Array texture, using lambda to choose between min/magnification */
2797 sample_lambda_1d_array(GLcontext
*ctx
,
2798 const struct gl_texture_object
*tObj
, GLuint n
,
2799 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2802 GLuint minStart
, minEnd
; /* texels with minification */
2803 GLuint magStart
, magEnd
; /* texels with magnification */
2806 ASSERT(lambda
!= NULL
);
2807 compute_min_mag_ranges(tObj
, n
, lambda
,
2808 &minStart
, &minEnd
, &magStart
, &magEnd
);
2810 if (minStart
< minEnd
) {
2811 /* do the minified texels */
2812 GLuint m
= minEnd
- minStart
;
2813 switch (tObj
->MinFilter
) {
2815 for (i
= minStart
; i
< minEnd
; i
++)
2816 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2817 texcoords
[i
], rgba
[i
]);
2820 for (i
= minStart
; i
< minEnd
; i
++)
2821 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2822 texcoords
[i
], rgba
[i
]);
2824 case GL_NEAREST_MIPMAP_NEAREST
:
2825 sample_1d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2826 lambda
+ minStart
, rgba
+ minStart
);
2828 case GL_LINEAR_MIPMAP_NEAREST
:
2829 sample_1d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2830 texcoords
+ minStart
,
2834 case GL_NEAREST_MIPMAP_LINEAR
:
2835 sample_1d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2836 lambda
+ minStart
, rgba
+ minStart
);
2838 case GL_LINEAR_MIPMAP_LINEAR
:
2839 sample_1d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2840 texcoords
+ minStart
,
2845 _mesa_problem(ctx
, "Bad min filter in sample_1d_array_texture");
2850 if (magStart
< magEnd
) {
2851 /* do the magnified texels */
2852 switch (tObj
->MagFilter
) {
2854 for (i
= magStart
; i
< magEnd
; i
++)
2855 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2856 texcoords
[i
], rgba
[i
]);
2859 for (i
= magStart
; i
< magEnd
; i
++)
2860 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2861 texcoords
[i
], rgba
[i
]);
2864 _mesa_problem(ctx
, "Bad mag filter in sample_1d_array_texture");
2872 * Compare texcoord against depth sample. Return 1.0 or the ambient value.
2874 static INLINE GLfloat
2875 shadow_compare(GLenum function
, GLfloat coord
, GLfloat depthSample
,
2880 return (coord
<= depthSample
) ? 1.0F
: ambient
;
2882 return (coord
>= depthSample
) ? 1.0F
: ambient
;
2884 return (coord
< depthSample
) ? 1.0F
: ambient
;
2886 return (coord
> depthSample
) ? 1.0F
: ambient
;
2888 return (coord
== depthSample
) ? 1.0F
: ambient
;
2890 return (coord
!= depthSample
) ? 1.0F
: ambient
;
2898 _mesa_problem(NULL
, "Bad compare func in shadow_compare");
2905 * Compare texcoord against four depth samples.
2907 static INLINE GLfloat
2908 shadow_compare4(GLenum function
, GLfloat coord
,
2909 GLfloat depth00
, GLfloat depth01
,
2910 GLfloat depth10
, GLfloat depth11
,
2911 GLfloat ambient
, GLfloat wi
, GLfloat wj
)
2913 const GLfloat d
= (1.0F
- (GLfloat
) ambient
) * 0.25F
;
2914 GLfloat luminance
= 1.0F
;
2918 if (depth00
<= coord
) luminance
-= d
;
2919 if (depth01
<= coord
) luminance
-= d
;
2920 if (depth10
<= coord
) luminance
-= d
;
2921 if (depth11
<= coord
) luminance
-= d
;
2924 if (depth00
>= coord
) luminance
-= d
;
2925 if (depth01
>= coord
) luminance
-= d
;
2926 if (depth10
>= coord
) luminance
-= d
;
2927 if (depth11
>= coord
) luminance
-= d
;
2930 if (depth00
< coord
) luminance
-= d
;
2931 if (depth01
< coord
) luminance
-= d
;
2932 if (depth10
< coord
) luminance
-= d
;
2933 if (depth11
< coord
) luminance
-= d
;
2936 if (depth00
> coord
) luminance
-= d
;
2937 if (depth01
> coord
) luminance
-= d
;
2938 if (depth10
> coord
) luminance
-= d
;
2939 if (depth11
> coord
) luminance
-= d
;
2942 if (depth00
== coord
) luminance
-= d
;
2943 if (depth01
== coord
) luminance
-= d
;
2944 if (depth10
== coord
) luminance
-= d
;
2945 if (depth11
== coord
) luminance
-= d
;
2948 if (depth00
!= coord
) luminance
-= d
;
2949 if (depth01
!= coord
) luminance
-= d
;
2950 if (depth10
!= coord
) luminance
-= d
;
2951 if (depth11
!= coord
) luminance
-= d
;
2958 /* ordinary bilinear filtering */
2959 return lerp_2d(wi
, wj
, depth00
, depth10
, depth01
, depth11
);
2961 _mesa_problem(NULL
, "Bad compare func in sample_depth_texture");
2968 * Choose the mipmap level to use when sampling from a depth texture.
2971 choose_depth_texture_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
2975 lambda
= CLAMP(lambda
, tObj
->MinLod
, tObj
->MaxLod
);
2977 level
= (GLint
) lambda
;
2979 level
= CLAMP(level
, tObj
->BaseLevel
, tObj
->_MaxLevel
);
2986 * Sample a shadow/depth texture. This function is incomplete. It doesn't
2987 * check for minification vs. magnification, etc.
2990 sample_depth_texture( GLcontext
*ctx
,
2991 const struct gl_texture_object
*tObj
, GLuint n
,
2992 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2993 GLfloat texel
[][4] )
2995 const GLint level
= choose_depth_texture_level(tObj
, lambda
[0]);
2996 const struct gl_texture_image
*img
= tObj
->Image
[0][level
];
2997 const GLint width
= img
->Width
;
2998 const GLint height
= img
->Height
;
2999 const GLint depth
= img
->Depth
;
3000 const GLuint compare_coord
= (tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
)
3006 ASSERT(img
->_BaseFormat
== GL_DEPTH_COMPONENT
||
3007 img
->_BaseFormat
== GL_DEPTH_STENCIL_EXT
);
3009 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
3010 tObj
->Target
== GL_TEXTURE_2D
||
3011 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
||
3012 tObj
->Target
== GL_TEXTURE_1D_ARRAY_EXT
||
3013 tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
);
3015 ambient
= tObj
->CompareFailValue
;
3017 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
3019 function
= (tObj
->CompareMode
== GL_COMPARE_R_TO_TEXTURE_ARB
) ?
3020 tObj
->CompareFunc
: GL_NONE
;
3022 if (tObj
->MagFilter
== GL_NEAREST
) {
3024 for (i
= 0; i
< n
; i
++) {
3025 GLfloat depthSample
;
3026 GLint col
, row
, slice
;
3028 nearest_texcoord(tObj
, level
, texcoords
[i
], &col
, &row
, &slice
);
3030 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
&&
3031 slice
>= 0 && slice
< depth
) {
3032 img
->FetchTexelf(img
, col
, row
, slice
, &depthSample
);
3035 depthSample
= tObj
->BorderColor
.f
[0];
3038 result
= shadow_compare(function
, texcoords
[i
][compare_coord
],
3039 depthSample
, ambient
);
3041 switch (tObj
->DepthMode
) {
3043 ASSIGN_4V(texel
[i
], result
, result
, result
, 1.0F
);
3046 ASSIGN_4V(texel
[i
], result
, result
, result
, result
);
3049 ASSIGN_4V(texel
[i
], 0.0F
, 0.0F
, 0.0F
, result
);
3052 _mesa_problem(ctx
, "Bad depth texture mode");
3058 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
3059 for (i
= 0; i
< n
; i
++) {
3060 GLfloat depth00
, depth01
, depth10
, depth11
;
3061 GLint i0
, i1
, j0
, j1
;
3064 GLuint useBorderTexel
;
3066 linear_texcoord(tObj
, level
, texcoords
[i
], &i0
, &i1
, &j0
, &j1
, &slice
,
3073 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3079 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
3080 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
3081 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
3082 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
3085 if (slice
< 0 || slice
>= (GLint
) depth
) {
3086 depth00
= tObj
->BorderColor
.f
[0];
3087 depth01
= tObj
->BorderColor
.f
[0];
3088 depth10
= tObj
->BorderColor
.f
[0];
3089 depth11
= tObj
->BorderColor
.f
[0];
3092 /* get four depth samples from the texture */
3093 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
3094 depth00
= tObj
->BorderColor
.f
[0];
3097 img
->FetchTexelf(img
, i0
, j0
, slice
, &depth00
);
3099 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
3100 depth10
= tObj
->BorderColor
.f
[0];
3103 img
->FetchTexelf(img
, i1
, j0
, slice
, &depth10
);
3106 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3107 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
3108 depth01
= tObj
->BorderColor
.f
[0];
3111 img
->FetchTexelf(img
, i0
, j1
, slice
, &depth01
);
3113 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
3114 depth11
= tObj
->BorderColor
.f
[0];
3117 img
->FetchTexelf(img
, i1
, j1
, slice
, &depth11
);
3126 result
= shadow_compare4(function
, texcoords
[i
][compare_coord
],
3127 depth00
, depth01
, depth10
, depth11
,
3130 switch (tObj
->DepthMode
) {
3132 ASSIGN_4V(texel
[i
], result
, result
, result
, 1.0F
);
3135 ASSIGN_4V(texel
[i
], result
, result
, result
, result
);
3138 ASSIGN_4V(texel
[i
], 0.0F
, 0.0F
, 0.0F
, result
);
3141 _mesa_problem(ctx
, "Bad depth texture mode");
3150 * We use this function when a texture object is in an "incomplete" state.
3151 * When a fragment program attempts to sample an incomplete texture we
3152 * return black (see issue 23 in GL_ARB_fragment_program spec).
3153 * Note: fragment programs don't observe the texture enable/disable flags.
3156 null_sample_func( GLcontext
*ctx
,
3157 const struct gl_texture_object
*tObj
, GLuint n
,
3158 const GLfloat texcoords
[][4], const GLfloat lambda
[],
3166 for (i
= 0; i
< n
; i
++) {
3170 rgba
[i
][ACOMP
] = 1.0;
3176 * Choose the texture sampling function for the given texture object.
3179 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
3180 const struct gl_texture_object
*t
)
3182 if (!t
|| !t
->_Complete
) {
3183 return &null_sample_func
;
3186 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
3187 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->_BaseFormat
;
3189 switch (t
->Target
) {
3191 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3192 return &sample_depth_texture
;
3194 else if (needLambda
) {
3195 return &sample_lambda_1d
;
3197 else if (t
->MinFilter
== GL_LINEAR
) {
3198 return &sample_linear_1d
;
3201 ASSERT(t
->MinFilter
== GL_NEAREST
);
3202 return &sample_nearest_1d
;
3205 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3206 return &sample_depth_texture
;
3208 else if (needLambda
) {
3209 return &sample_lambda_2d
;
3211 else if (t
->MinFilter
== GL_LINEAR
) {
3212 return &sample_linear_2d
;
3215 /* check for a few optimized cases */
3216 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
3217 ASSERT(t
->MinFilter
== GL_NEAREST
);
3218 if (t
->WrapS
== GL_REPEAT
&&
3219 t
->WrapT
== GL_REPEAT
&&
3220 img
->_IsPowerOfTwo
&&
3222 img
->TexFormat
== MESA_FORMAT_RGB888
) {
3223 return &opt_sample_rgb_2d
;
3225 else if (t
->WrapS
== GL_REPEAT
&&
3226 t
->WrapT
== GL_REPEAT
&&
3227 img
->_IsPowerOfTwo
&&
3229 img
->TexFormat
== MESA_FORMAT_RGBA8888
) {
3230 return &opt_sample_rgba_2d
;
3233 return &sample_nearest_2d
;
3238 return &sample_lambda_3d
;
3240 else if (t
->MinFilter
== GL_LINEAR
) {
3241 return &sample_linear_3d
;
3244 ASSERT(t
->MinFilter
== GL_NEAREST
);
3245 return &sample_nearest_3d
;
3247 case GL_TEXTURE_CUBE_MAP
:
3249 return &sample_lambda_cube
;
3251 else if (t
->MinFilter
== GL_LINEAR
) {
3252 return &sample_linear_cube
;
3255 ASSERT(t
->MinFilter
== GL_NEAREST
);
3256 return &sample_nearest_cube
;
3258 case GL_TEXTURE_RECTANGLE_NV
:
3259 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3260 return &sample_depth_texture
;
3262 else if (needLambda
) {
3263 return &sample_lambda_rect
;
3265 else if (t
->MinFilter
== GL_LINEAR
) {
3266 return &sample_linear_rect
;
3269 ASSERT(t
->MinFilter
== GL_NEAREST
);
3270 return &sample_nearest_rect
;
3272 case GL_TEXTURE_1D_ARRAY_EXT
:
3274 return &sample_lambda_1d_array
;
3276 else if (t
->MinFilter
== GL_LINEAR
) {
3277 return &sample_linear_1d_array
;
3280 ASSERT(t
->MinFilter
== GL_NEAREST
);
3281 return &sample_nearest_1d_array
;
3283 case GL_TEXTURE_2D_ARRAY_EXT
:
3285 return &sample_lambda_2d_array
;
3287 else if (t
->MinFilter
== GL_LINEAR
) {
3288 return &sample_linear_2d_array
;
3291 ASSERT(t
->MinFilter
== GL_NEAREST
);
3292 return &sample_nearest_2d_array
;
3296 "invalid target in _swrast_choose_texture_sample_func");
3297 return &null_sample_func
;