2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/imports.h"
30 #include "main/texobj.h"
31 #include "main/samplerobj.h"
33 #include "s_context.h"
34 #include "s_texfilter.h"
38 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
39 * see 1-pixel bands of improperly weighted linear-filtered textures.
40 * The tests/texwrap.c demo is a good test.
41 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
42 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
44 #define FRAC(f) ((f) - IFLOOR(f))
49 * Linear interpolation macro
51 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
55 * Do 2D/biliner interpolation of float values.
56 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
57 * a and b are the horizontal and vertical interpolants.
58 * It's important that this function is inlined when compiled with
59 * optimization! If we find that's not true on some systems, convert
63 lerp_2d(GLfloat a, GLfloat b,
64 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
66 const GLfloat temp0 = LERP(a, v00, v10);
67 const GLfloat temp1 = LERP(a, v01, v11);
68 return LERP(b, temp0, temp1);
73 * Do 3D/trilinear interpolation of float values.
77 lerp_3d(GLfloat a, GLfloat b, GLfloat c,
78 GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110,
79 GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111)
81 const GLfloat temp00 = LERP(a, v000, v100);
82 const GLfloat temp10 = LERP(a, v010, v110);
83 const GLfloat temp01 = LERP(a, v001, v101);
84 const GLfloat temp11 = LERP(a, v011, v111);
85 const GLfloat temp0 = LERP(b, temp00, temp10);
86 const GLfloat temp1 = LERP(b, temp01, temp11);
87 return LERP(c, temp0, temp1);
92 * Do linear interpolation of colors.
95 lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4])
97 result[0] = LERP(t, a[0], b[0]);
98 result[1] = LERP(t, a[1], b[1]);
99 result[2] = LERP(t, a[2], b[2]);
100 result[3] = LERP(t, a[3], b[3]);
105 * Do bilinear interpolation of colors.
108 lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b,
109 const GLfloat t00[4], const GLfloat t10[4],
110 const GLfloat t01[4], const GLfloat t11[4])
112 result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]);
113 result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]);
114 result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]);
115 result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);
120 * Do trilinear interpolation of colors.
123 lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c,
124 const GLfloat t000[4], const GLfloat t100[4],
125 const GLfloat t010[4], const GLfloat t110[4],
126 const GLfloat t001[4], const GLfloat t101[4],
127 const GLfloat t011[4], const GLfloat t111[4])
130 /* compiler should unroll these short loops */
131 for (k = 0; k < 4; k++) {
132 result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k],
133 t001[k], t101[k], t011[k], t111[k]);
139 * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the
140 * right results for A<0. Casting to A to be unsigned only works if B
141 * is a power of two. Adding a bias to A (which is a multiple of B)
142 * avoids the problems with A < 0 (for reasonable A) without using a
145 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
149 * Used to compute texel locations for linear sampling.
151 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
152 * s = texcoord in [0,1]
153 * size = width (or height or depth) of texture
155 * i0, i1 = returns two nearest texel indexes
156 * weight = returns blend factor between texels
159 linear_texel_locations(GLenum wrapMode,
160 const struct gl_texture_image *img,
161 GLint size, GLfloat s,
162 GLint *i0, GLint *i1, GLfloat *weight)
164 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
169 if (swImg->_IsPowerOfTwo) {
170 *i0 = IFLOOR(u) & (size - 1);
171 *i1 = (*i0 + 1) & (size - 1);
174 *i0 = REMAINDER(IFLOOR(u), size);
175 *i1 = REMAINDER(*i0 + 1, size);
178 case GL_CLAMP_TO_EDGE:
190 if (*i1 >= (GLint) size)
193 case GL_CLAMP_TO_BORDER:
195 const GLfloat min = -1.0F / (2.0F * size);
196 const GLfloat max = 1.0F - min;
208 case GL_MIRRORED_REPEAT:
210 const GLint flr = IFLOOR(s);
212 u = 1.0F - (s - (GLfloat) flr);
214 u = s - (GLfloat) flr;
215 u = (u * size) - 0.5F;
220 if (*i1 >= (GLint) size)
224 case GL_MIRROR_CLAMP_EXT:
234 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
245 if (*i1 >= (GLint) size)
248 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
250 const GLfloat min = -1.0F / (2.0F * size);
251 const GLfloat max = 1.0F - min;
276 _mesa_problem(NULL, "Bad wrap mode");
285 * Used to compute texel location for nearest sampling.
288 nearest_texel_location(GLenum wrapMode,
289 const struct gl_texture_image *img,
290 GLint size, GLfloat s)
292 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
297 /* s limited to [0,1) */
298 /* i limited to [0,size-1] */
299 i = IFLOOR(s * size);
300 if (swImg->_IsPowerOfTwo)
303 i = REMAINDER(i, size);
305 case GL_CLAMP_TO_EDGE:
307 /* s limited to [min,max] */
308 /* i limited to [0, size-1] */
309 const GLfloat min = 1.0F / (2.0F * size);
310 const GLfloat max = 1.0F - min;
316 i = IFLOOR(s * size);
319 case GL_CLAMP_TO_BORDER:
321 /* s limited to [min,max] */
322 /* i limited to [-1, size] */
323 const GLfloat min = -1.0F / (2.0F * size);
324 const GLfloat max = 1.0F - min;
330 i = IFLOOR(s * size);
333 case GL_MIRRORED_REPEAT:
335 const GLfloat min = 1.0F / (2.0F * size);
336 const GLfloat max = 1.0F - min;
337 const GLint flr = IFLOOR(s);
340 u = 1.0F - (s - (GLfloat) flr);
342 u = s - (GLfloat) flr;
348 i = IFLOOR(u * size);
351 case GL_MIRROR_CLAMP_EXT:
353 /* s limited to [0,1] */
354 /* i limited to [0,size-1] */
355 const GLfloat u = FABSF(s);
361 i = IFLOOR(u * size);
364 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
366 /* s limited to [min,max] */
367 /* i limited to [0, size-1] */
368 const GLfloat min = 1.0F / (2.0F * size);
369 const GLfloat max = 1.0F - min;
370 const GLfloat u = FABSF(s);
376 i = IFLOOR(u * size);
379 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
381 /* s limited to [min,max] */
382 /* i limited to [0, size-1] */
383 const GLfloat min = -1.0F / (2.0F * size);
384 const GLfloat max = 1.0F - min;
385 const GLfloat u = FABSF(s);
391 i = IFLOOR(u * size);
395 /* s limited to [0,1] */
396 /* i limited to [0,size-1] */
402 i = IFLOOR(s * size);
405 _mesa_problem(NULL, "Bad wrap mode");
411 /* Power of two image sizes only */
413 linear_repeat_texel_location(GLuint size, GLfloat s,
414 GLint *i0, GLint *i1, GLfloat *weight)
416 GLfloat u = s * size - 0.5F;
417 *i0 = IFLOOR(u) & (size - 1);
418 *i1 = (*i0 + 1) & (size - 1);
424 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
427 clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
431 return IFLOOR( CLAMP(coord, 0.0F, max - 1) );
432 case GL_CLAMP_TO_EDGE:
433 return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) );
434 case GL_CLAMP_TO_BORDER:
435 return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) );
437 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest");
444 * As above, but GL_LINEAR filtering.
447 clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
448 GLint *i0out, GLint *i1out, GLfloat *weight)
454 /* Not exactly what the spec says, but it matches NVIDIA output */
455 fcol = CLAMP(coord - 0.5F, 0.0F, max - 1);
459 case GL_CLAMP_TO_EDGE:
460 fcol = CLAMP(coord, 0.5F, max - 0.5F);
467 case GL_CLAMP_TO_BORDER:
468 fcol = CLAMP(coord, -0.5F, max + 0.5F);
474 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear");
481 *weight = FRAC(fcol);
486 * Compute slice/image to use for 1D or 2D array texture.
489 tex_array_slice(GLfloat coord, GLsizei size)
491 GLint slice = IFLOOR(coord + 0.5f);
492 slice = CLAMP(slice, 0, size - 1);
498 * Compute nearest integer texcoords for given texobj and coordinate.
499 * NOTE: only used for depth texture sampling.
502 nearest_texcoord(const struct gl_sampler_object *samp,
503 const struct gl_texture_object *texObj,
505 const GLfloat texcoord[4],
506 GLint *i, GLint *j, GLint *k)
508 const struct gl_texture_image *img = texObj->Image[0][level];
509 const GLint width = img->Width;
510 const GLint height = img->Height;
511 const GLint depth = img->Depth;
513 switch (texObj->Target) {
514 case GL_TEXTURE_RECTANGLE_ARB:
515 *i = clamp_rect_coord_nearest(samp->WrapS, texcoord[0], width);
516 *j = clamp_rect_coord_nearest(samp->WrapT, texcoord[1], height);
520 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
525 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
526 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
529 case GL_TEXTURE_1D_ARRAY_EXT:
530 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
531 *j = tex_array_slice(texcoord[1], height);
534 case GL_TEXTURE_2D_ARRAY_EXT:
535 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
536 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
537 *k = tex_array_slice(texcoord[2], depth);
547 * Compute linear integer texcoords for given texobj and coordinate.
548 * NOTE: only used for depth texture sampling.
551 linear_texcoord(const struct gl_sampler_object *samp,
552 const struct gl_texture_object *texObj,
554 const GLfloat texcoord[4],
555 GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice,
556 GLfloat *wi, GLfloat *wj)
558 const struct gl_texture_image *img = texObj->Image[0][level];
559 const GLint width = img->Width;
560 const GLint height = img->Height;
561 const GLint depth = img->Depth;
563 switch (texObj->Target) {
564 case GL_TEXTURE_RECTANGLE_ARB:
565 clamp_rect_coord_linear(samp->WrapS, texcoord[0],
567 clamp_rect_coord_linear(samp->WrapT, texcoord[1],
574 linear_texel_locations(samp->WrapS, img, width,
575 texcoord[0], i0, i1, wi);
576 linear_texel_locations(samp->WrapT, img, height,
577 texcoord[1], j0, j1, wj);
581 case GL_TEXTURE_1D_ARRAY_EXT:
582 linear_texel_locations(samp->WrapS, img, width,
583 texcoord[0], i0, i1, wi);
584 *j0 = tex_array_slice(texcoord[1], height);
589 case GL_TEXTURE_2D_ARRAY_EXT:
590 linear_texel_locations(samp->WrapS, img, width,
591 texcoord[0], i0, i1, wi);
592 linear_texel_locations(samp->WrapT, img, height,
593 texcoord[1], j0, j1, wj);
594 *slice = tex_array_slice(texcoord[2], depth);
606 * For linear interpolation between mipmap levels N and N+1, this function
610 linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
613 return tObj->BaseLevel;
614 else if (lambda > tObj->_MaxLambda)
615 return (GLint) (tObj->BaseLevel + tObj->_MaxLambda);
617 return (GLint) (tObj->BaseLevel + lambda);
622 * Compute the nearest mipmap level to take texels from.
625 nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
631 else if (lambda > tObj->_MaxLambda + 0.4999F)
632 l = tObj->_MaxLambda + 0.4999F;
635 level = (GLint) (tObj->BaseLevel + l + 0.5F);
636 if (level > tObj->_MaxLevel)
637 level = tObj->_MaxLevel;
644 * Bitflags for texture border color sampling.
656 * The lambda[] array values are always monotonic. Either the whole span
657 * will be minified, magnified, or split between the two. This function
658 * determines the subranges in [0, n-1] that are to be minified or magnified.
661 compute_min_mag_ranges(const struct gl_sampler_object *samp,
662 GLuint n, const GLfloat lambda[],
663 GLuint *minStart, GLuint *minEnd,
664 GLuint *magStart, GLuint *magEnd)
666 GLfloat minMagThresh;
668 /* we shouldn't be here if minfilter == magfilter */
669 ASSERT(samp->MinFilter != samp->MagFilter);
671 /* This bit comes from the OpenGL spec: */
672 if (samp->MagFilter == GL_LINEAR
673 && (samp->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
674 samp->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
682 /* DEBUG CODE: Verify that lambda[] is monotonic.
683 * We can't really use this because the inaccuracy in the LOG2 function
684 * causes this test to fail, yet the resulting texturing is correct.
688 printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
689 if (lambda[0] >= lambda[n-1]) { /* decreasing */
690 for (i = 0; i < n - 1; i++) {
691 ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
694 else { /* increasing */
695 for (i = 0; i < n - 1; i++) {
696 ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
702 if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
703 /* magnification for whole span */
706 *minStart = *minEnd = 0;
708 else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
709 /* minification for whole span */
712 *magStart = *magEnd = 0;
715 /* a mix of minification and magnification */
717 if (lambda[0] > minMagThresh) {
718 /* start with minification */
719 for (i = 1; i < n; i++) {
720 if (lambda[i] <= minMagThresh)
729 /* start with magnification */
730 for (i = 1; i < n; i++) {
731 if (lambda[i] > minMagThresh)
742 /* Verify the min/mag Start/End values
743 * We don't use this either (see above)
747 for (i = 0; i < n; i++) {
748 if (lambda[i] > minMagThresh) {
750 ASSERT(i >= *minStart);
755 ASSERT(i >= *magStart);
765 * When we sample the border color, it must be interpreted according to
766 * the base texture format. Ex: if the texture base format it GL_ALPHA,
767 * we return (0,0,0,BorderAlpha).
770 get_border_color(const struct gl_sampler_object *samp,
771 const struct gl_texture_image *img,
774 switch (img->_BaseFormat) {
776 rgba[0] = samp->BorderColor.f[0];
777 rgba[1] = samp->BorderColor.f[1];
778 rgba[2] = samp->BorderColor.f[2];
782 rgba[0] = rgba[1] = rgba[2] = 0.0;
783 rgba[3] = samp->BorderColor.f[3];
786 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
789 case GL_LUMINANCE_ALPHA:
790 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
791 rgba[3] = samp->BorderColor.f[3];
794 rgba[0] = rgba[1] = rgba[2] = rgba[3] = samp->BorderColor.f[0];
797 COPY_4V(rgba, samp->BorderColor.f);
804 * Put z into texel according to GL_DEPTH_MODE.
807 apply_depth_mode(GLenum depthMode, GLfloat z, GLfloat texel[4])
811 ASSIGN_4V(texel, z, z, z, 1.0F);
814 ASSIGN_4V(texel, z, z, z, z);
817 ASSIGN_4V(texel, 0.0F, 0.0F, 0.0F, z);
820 ASSIGN_4V(texel, z, 0.0F, 0.0F, 1.0F);
823 _mesa_problem(NULL, "Bad depth texture mode");
829 * Is the given texture a depth (or depth/stencil) texture?
832 is_depth_texture(const struct gl_texture_object *tObj)
834 GLenum format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
835 return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT;
839 /**********************************************************************/
840 /* 1-D Texture Sampling Functions */
841 /**********************************************************************/
844 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
847 sample_1d_nearest(struct gl_context *ctx,
848 const struct gl_sampler_object *samp,
849 const struct gl_texture_image *img,
850 const GLfloat texcoord[4], GLfloat rgba[4])
852 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
853 const GLint width = img->Width2; /* without border, power of two */
855 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
856 /* skip over the border, if any */
858 if (i < 0 || i >= (GLint) img->Width) {
859 /* Need this test for GL_CLAMP_TO_BORDER mode */
860 get_border_color(samp, img, rgba);
863 swImg->FetchTexel(swImg, i, 0, 0, rgba);
869 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
872 sample_1d_linear(struct gl_context *ctx,
873 const struct gl_sampler_object *samp,
874 const struct gl_texture_image *img,
875 const GLfloat texcoord[4], GLfloat rgba[4])
877 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
878 const GLint width = img->Width2;
880 GLbitfield useBorderColor = 0x0;
882 GLfloat t0[4], t1[4]; /* texels */
884 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
891 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
892 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
895 /* fetch texel colors */
896 if (useBorderColor & I0BIT) {
897 get_border_color(samp, img, t0);
900 swImg->FetchTexel(swImg, i0, 0, 0, t0);
902 if (useBorderColor & I1BIT) {
903 get_border_color(samp, img, t1);
906 swImg->FetchTexel(swImg, i1, 0, 0, t1);
909 lerp_rgba(rgba, a, t0, t1);
914 sample_1d_nearest_mipmap_nearest(struct gl_context *ctx,
915 const struct gl_sampler_object *samp,
916 const struct gl_texture_object *tObj,
917 GLuint n, const GLfloat texcoord[][4],
918 const GLfloat lambda[], GLfloat rgba[][4])
921 ASSERT(lambda != NULL);
922 for (i = 0; i < n; i++) {
923 GLint level = nearest_mipmap_level(tObj, lambda[i]);
924 sample_1d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
930 sample_1d_linear_mipmap_nearest(struct gl_context *ctx,
931 const struct gl_sampler_object *samp,
932 const struct gl_texture_object *tObj,
933 GLuint n, const GLfloat texcoord[][4],
934 const GLfloat lambda[], GLfloat rgba[][4])
937 ASSERT(lambda != NULL);
938 for (i = 0; i < n; i++) {
939 GLint level = nearest_mipmap_level(tObj, lambda[i]);
940 sample_1d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
946 sample_1d_nearest_mipmap_linear(struct gl_context *ctx,
947 const struct gl_sampler_object *samp,
948 const struct gl_texture_object *tObj,
949 GLuint n, const GLfloat texcoord[][4],
950 const GLfloat lambda[], GLfloat rgba[][4])
953 ASSERT(lambda != NULL);
954 for (i = 0; i < n; i++) {
955 GLint level = linear_mipmap_level(tObj, lambda[i]);
956 if (level >= tObj->_MaxLevel) {
957 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
958 texcoord[i], rgba[i]);
961 GLfloat t0[4], t1[4];
962 const GLfloat f = FRAC(lambda[i]);
963 sample_1d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
964 sample_1d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
965 lerp_rgba(rgba[i], f, t0, t1);
972 sample_1d_linear_mipmap_linear(struct gl_context *ctx,
973 const struct gl_sampler_object *samp,
974 const struct gl_texture_object *tObj,
975 GLuint n, const GLfloat texcoord[][4],
976 const GLfloat lambda[], GLfloat rgba[][4])
979 ASSERT(lambda != NULL);
980 for (i = 0; i < n; i++) {
981 GLint level = linear_mipmap_level(tObj, lambda[i]);
982 if (level >= tObj->_MaxLevel) {
983 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
984 texcoord[i], rgba[i]);
987 GLfloat t0[4], t1[4];
988 const GLfloat f = FRAC(lambda[i]);
989 sample_1d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
990 sample_1d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
991 lerp_rgba(rgba[i], f, t0, t1);
997 /** Sample 1D texture, nearest filtering for both min/magnification */
999 sample_nearest_1d( struct gl_context *ctx,
1000 const struct gl_sampler_object *samp,
1001 const struct gl_texture_object *tObj, GLuint n,
1002 const GLfloat texcoords[][4], const GLfloat lambda[],
1006 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1008 for (i = 0; i < n; i++) {
1009 sample_1d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
1014 /** Sample 1D texture, linear filtering for both min/magnification */
1016 sample_linear_1d( struct gl_context *ctx,
1017 const struct gl_sampler_object *samp,
1018 const struct gl_texture_object *tObj, GLuint n,
1019 const GLfloat texcoords[][4], const GLfloat lambda[],
1023 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1025 for (i = 0; i < n; i++) {
1026 sample_1d_linear(ctx, samp, image, texcoords[i], rgba[i]);
1031 /** Sample 1D texture, using lambda to choose between min/magnification */
1033 sample_lambda_1d( struct gl_context *ctx,
1034 const struct gl_sampler_object *samp,
1035 const struct gl_texture_object *tObj, GLuint n,
1036 const GLfloat texcoords[][4],
1037 const GLfloat lambda[], GLfloat rgba[][4] )
1039 GLuint minStart, minEnd; /* texels with minification */
1040 GLuint magStart, magEnd; /* texels with magnification */
1043 ASSERT(lambda != NULL);
1044 compute_min_mag_ranges(samp, n, lambda,
1045 &minStart, &minEnd, &magStart, &magEnd);
1047 if (minStart < minEnd) {
1048 /* do the minified texels */
1049 const GLuint m = minEnd - minStart;
1050 switch (samp->MinFilter) {
1052 for (i = minStart; i < minEnd; i++)
1053 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
1054 texcoords[i], rgba[i]);
1057 for (i = minStart; i < minEnd; i++)
1058 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
1059 texcoords[i], rgba[i]);
1061 case GL_NEAREST_MIPMAP_NEAREST:
1062 sample_1d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1063 lambda + minStart, rgba + minStart);
1065 case GL_LINEAR_MIPMAP_NEAREST:
1066 sample_1d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1067 lambda + minStart, rgba + minStart);
1069 case GL_NEAREST_MIPMAP_LINEAR:
1070 sample_1d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1071 lambda + minStart, rgba + minStart);
1073 case GL_LINEAR_MIPMAP_LINEAR:
1074 sample_1d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1075 lambda + minStart, rgba + minStart);
1078 _mesa_problem(ctx, "Bad min filter in sample_1d_texture");
1083 if (magStart < magEnd) {
1084 /* do the magnified texels */
1085 switch (samp->MagFilter) {
1087 for (i = magStart; i < magEnd; i++)
1088 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
1089 texcoords[i], rgba[i]);
1092 for (i = magStart; i < magEnd; i++)
1093 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
1094 texcoords[i], rgba[i]);
1097 _mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
1104 /**********************************************************************/
1105 /* 2-D Texture Sampling Functions */
1106 /**********************************************************************/
1110 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
1113 sample_2d_nearest(struct gl_context *ctx,
1114 const struct gl_sampler_object *samp,
1115 const struct gl_texture_image *img,
1116 const GLfloat texcoord[4],
1119 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1120 const GLint width = img->Width2; /* without border, power of two */
1121 const GLint height = img->Height2; /* without border, power of two */
1125 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
1126 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
1128 /* skip over the border, if any */
1132 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
1133 /* Need this test for GL_CLAMP_TO_BORDER mode */
1134 get_border_color(samp, img, rgba);
1137 swImg->FetchTexel(swImg, i, j, 0, rgba);
1143 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
1144 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
1147 sample_2d_linear(struct gl_context *ctx,
1148 const struct gl_sampler_object *samp,
1149 const struct gl_texture_image *img,
1150 const GLfloat texcoord[4],
1153 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1154 const GLint width = img->Width2;
1155 const GLint height = img->Height2;
1156 GLint i0, j0, i1, j1;
1157 GLbitfield useBorderColor = 0x0;
1159 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1161 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
1162 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
1171 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1172 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1173 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1174 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1177 /* fetch four texel colors */
1178 if (useBorderColor & (I0BIT | J0BIT)) {
1179 get_border_color(samp, img, t00);
1182 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1184 if (useBorderColor & (I1BIT | J0BIT)) {
1185 get_border_color(samp, img, t10);
1188 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1190 if (useBorderColor & (I0BIT | J1BIT)) {
1191 get_border_color(samp, img, t01);
1194 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1196 if (useBorderColor & (I1BIT | J1BIT)) {
1197 get_border_color(samp, img, t11);
1200 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1203 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
1208 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1209 * We don't have to worry about the texture border.
1212 sample_2d_linear_repeat(struct gl_context *ctx,
1213 const struct gl_sampler_object *samp,
1214 const struct gl_texture_image *img,
1215 const GLfloat texcoord[4],
1218 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1219 const GLint width = img->Width2;
1220 const GLint height = img->Height2;
1221 GLint i0, j0, i1, j1;
1223 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1227 ASSERT(samp->WrapS == GL_REPEAT);
1228 ASSERT(samp->WrapT == GL_REPEAT);
1229 ASSERT(img->Border == 0);
1230 ASSERT(swImg->_IsPowerOfTwo);
1232 linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi);
1233 linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj);
1235 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1236 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1237 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1238 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1240 lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11);
1245 sample_2d_nearest_mipmap_nearest(struct gl_context *ctx,
1246 const struct gl_sampler_object *samp,
1247 const struct gl_texture_object *tObj,
1248 GLuint n, const GLfloat texcoord[][4],
1249 const GLfloat lambda[], GLfloat rgba[][4])
1252 for (i = 0; i < n; i++) {
1253 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1254 sample_2d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
1260 sample_2d_linear_mipmap_nearest(struct gl_context *ctx,
1261 const struct gl_sampler_object *samp,
1262 const struct gl_texture_object *tObj,
1263 GLuint n, const GLfloat texcoord[][4],
1264 const GLfloat lambda[], GLfloat rgba[][4])
1267 ASSERT(lambda != NULL);
1268 for (i = 0; i < n; i++) {
1269 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1270 sample_2d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
1276 sample_2d_nearest_mipmap_linear(struct gl_context *ctx,
1277 const struct gl_sampler_object *samp,
1278 const struct gl_texture_object *tObj,
1279 GLuint n, const GLfloat texcoord[][4],
1280 const GLfloat lambda[], GLfloat rgba[][4])
1283 ASSERT(lambda != NULL);
1284 for (i = 0; i < n; i++) {
1285 GLint level = linear_mipmap_level(tObj, lambda[i]);
1286 if (level >= tObj->_MaxLevel) {
1287 sample_2d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1288 texcoord[i], rgba[i]);
1291 GLfloat t0[4], t1[4]; /* texels */
1292 const GLfloat f = FRAC(lambda[i]);
1293 sample_2d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
1294 sample_2d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
1295 lerp_rgba(rgba[i], f, t0, t1);
1302 sample_2d_linear_mipmap_linear( struct gl_context *ctx,
1303 const struct gl_sampler_object *samp,
1304 const struct gl_texture_object *tObj,
1305 GLuint n, const GLfloat texcoord[][4],
1306 const GLfloat lambda[], GLfloat rgba[][4] )
1309 ASSERT(lambda != NULL);
1310 for (i = 0; i < n; i++) {
1311 GLint level = linear_mipmap_level(tObj, lambda[i]);
1312 if (level >= tObj->_MaxLevel) {
1313 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1314 texcoord[i], rgba[i]);
1317 GLfloat t0[4], t1[4]; /* texels */
1318 const GLfloat f = FRAC(lambda[i]);
1319 sample_2d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
1320 sample_2d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
1321 lerp_rgba(rgba[i], f, t0, t1);
1328 sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx,
1329 const struct gl_sampler_object *samp,
1330 const struct gl_texture_object *tObj,
1331 GLuint n, const GLfloat texcoord[][4],
1332 const GLfloat lambda[], GLfloat rgba[][4])
1335 ASSERT(lambda != NULL);
1336 ASSERT(samp->WrapS == GL_REPEAT);
1337 ASSERT(samp->WrapT == GL_REPEAT);
1338 for (i = 0; i < n; i++) {
1339 GLint level = linear_mipmap_level(tObj, lambda[i]);
1340 if (level >= tObj->_MaxLevel) {
1341 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1342 texcoord[i], rgba[i]);
1345 GLfloat t0[4], t1[4]; /* texels */
1346 const GLfloat f = FRAC(lambda[i]);
1347 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level ],
1349 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level+1],
1351 lerp_rgba(rgba[i], f, t0, t1);
1357 /** Sample 2D texture, nearest filtering for both min/magnification */
1359 sample_nearest_2d(struct gl_context *ctx,
1360 const struct gl_sampler_object *samp,
1361 const struct gl_texture_object *tObj, GLuint n,
1362 const GLfloat texcoords[][4],
1363 const GLfloat lambda[], GLfloat rgba[][4])
1366 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1368 for (i = 0; i < n; i++) {
1369 sample_2d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
1374 /** Sample 2D texture, linear filtering for both min/magnification */
1376 sample_linear_2d(struct gl_context *ctx,
1377 const struct gl_sampler_object *samp,
1378 const struct gl_texture_object *tObj, GLuint n,
1379 const GLfloat texcoords[][4],
1380 const GLfloat lambda[], GLfloat rgba[][4])
1383 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1384 const struct swrast_texture_image *swImg = swrast_texture_image_const(image);
1386 if (samp->WrapS == GL_REPEAT &&
1387 samp->WrapT == GL_REPEAT &&
1388 swImg->_IsPowerOfTwo &&
1389 image->Border == 0) {
1390 for (i = 0; i < n; i++) {
1391 sample_2d_linear_repeat(ctx, samp, image, texcoords[i], rgba[i]);
1395 for (i = 0; i < n; i++) {
1396 sample_2d_linear(ctx, samp, image, texcoords[i], rgba[i]);
1403 * Optimized 2-D texture sampling:
1404 * S and T wrap mode == GL_REPEAT
1405 * GL_NEAREST min/mag filter
1407 * RowStride == Width,
1411 opt_sample_rgb_2d(struct gl_context *ctx,
1412 const struct gl_sampler_object *samp,
1413 const struct gl_texture_object *tObj,
1414 GLuint n, const GLfloat texcoords[][4],
1415 const GLfloat lambda[], GLfloat rgba[][4])
1417 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1418 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1419 const GLfloat width = (GLfloat) img->Width;
1420 const GLfloat height = (GLfloat) img->Height;
1421 const GLint colMask = img->Width - 1;
1422 const GLint rowMask = img->Height - 1;
1423 const GLint shift = img->WidthLog2;
1427 ASSERT(samp->WrapS==GL_REPEAT);
1428 ASSERT(samp->WrapT==GL_REPEAT);
1429 ASSERT(img->Border==0);
1430 ASSERT(img->TexFormat == MESA_FORMAT_RGB888);
1431 ASSERT(swImg->_IsPowerOfTwo);
1434 for (k=0; k<n; k++) {
1435 GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
1436 GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
1437 GLint pos = (j << shift) | i;
1438 GLubyte *texel = (GLubyte *) swImg->ImageSlices[0] + 3 * pos;
1439 rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
1440 rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
1441 rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
1442 rgba[k][ACOMP] = 1.0F;
1448 * Optimized 2-D texture sampling:
1449 * S and T wrap mode == GL_REPEAT
1450 * GL_NEAREST min/mag filter
1452 * RowStride == Width,
1456 opt_sample_rgba_2d(struct gl_context *ctx,
1457 const struct gl_sampler_object *samp,
1458 const struct gl_texture_object *tObj,
1459 GLuint n, const GLfloat texcoords[][4],
1460 const GLfloat lambda[], GLfloat rgba[][4])
1462 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1463 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1464 const GLfloat width = (GLfloat) img->Width;
1465 const GLfloat height = (GLfloat) img->Height;
1466 const GLint colMask = img->Width - 1;
1467 const GLint rowMask = img->Height - 1;
1468 const GLint shift = img->WidthLog2;
1472 ASSERT(samp->WrapS==GL_REPEAT);
1473 ASSERT(samp->WrapT==GL_REPEAT);
1474 ASSERT(img->Border==0);
1475 ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888);
1476 ASSERT(swImg->_IsPowerOfTwo);
1479 for (i = 0; i < n; i++) {
1480 const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
1481 const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
1482 const GLint pos = (row << shift) | col;
1483 const GLuint texel = *((GLuint *) swImg->ImageSlices[0] + pos);
1484 rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) );
1485 rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
1486 rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff );
1487 rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff );
1492 /** Sample 2D texture, using lambda to choose between min/magnification */
1494 sample_lambda_2d(struct gl_context *ctx,
1495 const struct gl_sampler_object *samp,
1496 const struct gl_texture_object *tObj,
1497 GLuint n, const GLfloat texcoords[][4],
1498 const GLfloat lambda[], GLfloat rgba[][4])
1500 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1501 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1502 GLuint minStart, minEnd; /* texels with minification */
1503 GLuint magStart, magEnd; /* texels with magnification */
1505 const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT)
1506 && (samp->WrapT == GL_REPEAT)
1507 && (tImg->Border == 0)
1508 && (_mesa_format_row_stride(tImg->TexFormat, tImg->Width) ==
1510 && swImg->_IsPowerOfTwo;
1512 ASSERT(lambda != NULL);
1513 compute_min_mag_ranges(samp, n, lambda,
1514 &minStart, &minEnd, &magStart, &magEnd);
1516 if (minStart < minEnd) {
1517 /* do the minified texels */
1518 const GLuint m = minEnd - minStart;
1519 switch (samp->MinFilter) {
1521 if (repeatNoBorderPOT) {
1522 switch (tImg->TexFormat) {
1523 case MESA_FORMAT_RGB888:
1524 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart,
1525 NULL, rgba + minStart);
1527 case MESA_FORMAT_RGBA8888:
1528 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart,
1529 NULL, rgba + minStart);
1532 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1533 NULL, rgba + minStart );
1537 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1538 NULL, rgba + minStart);
1542 sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart,
1543 NULL, rgba + minStart);
1545 case GL_NEAREST_MIPMAP_NEAREST:
1546 sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m,
1547 texcoords + minStart,
1548 lambda + minStart, rgba + minStart);
1550 case GL_LINEAR_MIPMAP_NEAREST:
1551 sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1552 lambda + minStart, rgba + minStart);
1554 case GL_NEAREST_MIPMAP_LINEAR:
1555 sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1556 lambda + minStart, rgba + minStart);
1558 case GL_LINEAR_MIPMAP_LINEAR:
1559 if (repeatNoBorderPOT)
1560 sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m,
1561 texcoords + minStart, lambda + minStart, rgba + minStart);
1563 sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1564 lambda + minStart, rgba + minStart);
1567 _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1572 if (magStart < magEnd) {
1573 /* do the magnified texels */
1574 const GLuint m = magEnd - magStart;
1576 switch (samp->MagFilter) {
1578 if (repeatNoBorderPOT) {
1579 switch (tImg->TexFormat) {
1580 case MESA_FORMAT_RGB888:
1581 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart,
1582 NULL, rgba + magStart);
1584 case MESA_FORMAT_RGBA8888:
1585 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart,
1586 NULL, rgba + magStart);
1589 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1590 NULL, rgba + magStart );
1594 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1595 NULL, rgba + magStart);
1599 sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart,
1600 NULL, rgba + magStart);
1603 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1610 /* For anisotropic filtering */
1611 #define WEIGHT_LUT_SIZE 1024
1613 static GLfloat *weightLut = NULL;
1616 * Creates the look-up table used to speed-up EWA sampling
1619 create_filter_table(void)
1623 weightLut = malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
1625 for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
1627 GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
1628 GLfloat weight = (GLfloat) exp(-alpha * r2);
1629 weightLut[i] = weight;
1636 * Elliptical weighted average (EWA) filter for producing high quality
1637 * anisotropic filtered results.
1638 * Based on the Higher Quality Elliptical Weighted Avarage Filter
1639 * published by Paul S. Heckbert in his Master's Thesis
1640 * "Fundamentals of Texture Mapping and Image Warping" (1989)
1643 sample_2d_ewa(struct gl_context *ctx,
1644 const struct gl_sampler_object *samp,
1645 const struct gl_texture_object *tObj,
1646 const GLfloat texcoord[4],
1647 const GLfloat dudx, const GLfloat dvdx,
1648 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1651 GLint level = lod > 0 ? lod : 0;
1652 GLfloat scaling = 1.0f / (1 << level);
1653 const struct gl_texture_image *img = tObj->Image[0][level];
1654 const struct gl_texture_image *mostDetailedImage =
1655 tObj->Image[0][tObj->BaseLevel];
1656 const struct swrast_texture_image *swImg =
1657 swrast_texture_image_const(mostDetailedImage);
1658 GLfloat tex_u = -0.5f + texcoord[0] * swImg->WidthScale * scaling;
1659 GLfloat tex_v = -0.5f + texcoord[1] * swImg->HeightScale * scaling;
1661 GLfloat ux = dudx * scaling;
1662 GLfloat vx = dvdx * scaling;
1663 GLfloat uy = dudy * scaling;
1664 GLfloat vy = dvdy * scaling;
1666 /* compute ellipse coefficients to bound the region:
1667 * A*x*x + B*x*y + C*y*y = F.
1669 GLfloat A = vx*vx+vy*vy+1;
1670 GLfloat B = -2*(ux*vx+uy*vy);
1671 GLfloat C = ux*ux+uy*uy+1;
1672 GLfloat F = A*C-B*B/4.0f;
1674 /* check if it is an ellipse */
1675 /* ASSERT(F > 0.0); */
1677 /* Compute the ellipse's (u,v) bounding box in texture space */
1678 GLfloat d = -B*B+4.0f*C*A;
1679 GLfloat box_u = 2.0f / d * sqrtf(d*C*F); /* box_u -> half of bbox with */
1680 GLfloat box_v = 2.0f / d * sqrtf(A*d*F); /* box_v -> half of bbox height */
1682 GLint u0 = (GLint) floorf(tex_u - box_u);
1683 GLint u1 = (GLint) ceilf (tex_u + box_u);
1684 GLint v0 = (GLint) floorf(tex_v - box_v);
1685 GLint v1 = (GLint) ceilf (tex_v + box_v);
1687 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1688 GLfloat newCoord[2];
1691 GLfloat U = u0 - tex_u;
1694 /* Scale ellipse formula to directly index the Filter Lookup Table.
1695 * i.e. scale so that F = WEIGHT_LUT_SIZE-1
1697 GLfloat formScale = (GLfloat) (WEIGHT_LUT_SIZE - 1) / F;
1701 /* F *= formScale; */ /* no need to scale F as we don't use it below here */
1703 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
1704 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
1705 * value, q, is less than F, we're inside the ellipse
1708 for (v = v0; v <= v1; ++v) {
1709 GLfloat V = v - tex_v;
1710 GLfloat dq = A * (2 * U + 1) + B * V;
1711 GLfloat q = (C * V + B * U) * V + A * U * U;
1714 for (u = u0; u <= u1; ++u) {
1715 /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
1716 if (q < WEIGHT_LUT_SIZE) {
1717 /* as a LUT is used, q must never be negative;
1718 * should not happen, though
1720 const GLint qClamped = q >= 0.0F ? (GLint) q : 0;
1721 GLfloat weight = weightLut[qClamped];
1723 newCoord[0] = u / ((GLfloat) img->Width2);
1724 newCoord[1] = v / ((GLfloat) img->Height2);
1726 sample_2d_nearest(ctx, samp, img, newCoord, rgba);
1727 num[0] += weight * rgba[0];
1728 num[1] += weight * rgba[1];
1729 num[2] += weight * rgba[2];
1730 num[3] += weight * rgba[3];
1740 /* Reaching this place would mean
1741 * that no pixels intersected the ellipse.
1742 * This should never happen because
1743 * the filter we use always
1744 * intersects at least one pixel.
1751 /* not enough pixels in resampling, resort to direct interpolation */
1752 sample_2d_linear(ctx, samp, img, texcoord, rgba);
1756 rgba[0] = num[0] / den;
1757 rgba[1] = num[1] / den;
1758 rgba[2] = num[2] / den;
1759 rgba[3] = num[3] / den;
1764 * Anisotropic filtering using footprint assembly as outlined in the
1765 * EXT_texture_filter_anisotropic spec:
1766 * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
1767 * Faster than EWA but has less quality (more aliasing effects)
1770 sample_2d_footprint(struct gl_context *ctx,
1771 const struct gl_sampler_object *samp,
1772 const struct gl_texture_object *tObj,
1773 const GLfloat texcoord[4],
1774 const GLfloat dudx, const GLfloat dvdx,
1775 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1778 GLint level = lod > 0 ? lod : 0;
1779 GLfloat scaling = 1.0F / (1 << level);
1780 const struct gl_texture_image *img = tObj->Image[0][level];
1782 GLfloat ux = dudx * scaling;
1783 GLfloat vx = dvdx * scaling;
1784 GLfloat uy = dudy * scaling;
1785 GLfloat vy = dvdy * scaling;
1787 GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
1788 GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
1794 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1795 GLfloat newCoord[2];
1798 /* Calculate the per anisotropic sample offsets in s,t space. */
1800 numSamples = (GLint) ceilf(sqrtf(Px2));
1801 ds = ux / ((GLfloat) img->Width2);
1802 dt = vx / ((GLfloat) img->Height2);
1805 numSamples = (GLint) ceilf(sqrtf(Py2));
1806 ds = uy / ((GLfloat) img->Width2);
1807 dt = vy / ((GLfloat) img->Height2);
1810 for (s = 0; s<numSamples; s++) {
1811 newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
1812 newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
1814 sample_2d_linear(ctx, samp, img, newCoord, rgba);
1821 rgba[0] = num[0] / numSamples;
1822 rgba[1] = num[1] / numSamples;
1823 rgba[2] = num[2] / numSamples;
1824 rgba[3] = num[3] / numSamples;
1829 * Returns the index of the specified texture object in the
1830 * gl_context texture unit array.
1832 static inline GLuint
1833 texture_unit_index(const struct gl_context *ctx,
1834 const struct gl_texture_object *tObj)
1836 const GLuint maxUnit
1837 = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
1840 /* XXX CoordUnits vs. ImageUnits */
1841 for (u = 0; u < maxUnit; u++) {
1842 if (ctx->Texture.Unit[u]._Current == tObj)
1846 u = 0; /* not found, use 1st one; should never happen */
1853 * Sample 2D texture using an anisotropic filter.
1854 * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
1855 * the lambda float array but a "hidden" SWspan struct which is required
1856 * by this function but is not available in the texture_sample_func signature.
1857 * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
1858 * this function is called.
1861 sample_lambda_2d_aniso(struct gl_context *ctx,
1862 const struct gl_sampler_object *samp,
1863 const struct gl_texture_object *tObj,
1864 GLuint n, const GLfloat texcoords[][4],
1865 const GLfloat lambda_iso[], GLfloat rgba[][4])
1867 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1868 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1869 const GLfloat maxEccentricity =
1870 samp->MaxAnisotropy * samp->MaxAnisotropy;
1872 /* re-calculate the lambda values so that they are usable with anisotropic
1875 SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
1877 /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
1878 * in swrast/s_span.c
1881 /* find the texture unit index by looking up the current texture object
1882 * from the context list of available texture objects.
1884 const GLuint u = texture_unit_index(ctx, tObj);
1885 const GLuint attr = VARYING_SLOT_TEX0 + u;
1888 const GLfloat dsdx = span->attrStepX[attr][0];
1889 const GLfloat dsdy = span->attrStepY[attr][0];
1890 const GLfloat dtdx = span->attrStepX[attr][1];
1891 const GLfloat dtdy = span->attrStepY[attr][1];
1892 const GLfloat dqdx = span->attrStepX[attr][3];
1893 const GLfloat dqdy = span->attrStepY[attr][3];
1894 GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
1895 GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
1896 GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
1898 /* from swrast/s_texcombine.c _swrast_texture_span */
1899 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
1900 const GLboolean adjustLOD =
1901 (texUnit->LodBias + samp->LodBias != 0.0F)
1902 || (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0);
1906 /* on first access create the lookup table containing the filter weights. */
1908 create_filter_table();
1911 texW = swImg->WidthScale;
1912 texH = swImg->HeightScale;
1914 for (i = 0; i < n; i++) {
1915 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
1917 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
1918 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
1919 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
1920 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
1922 /* note: instead of working with Px and Py, we will use the
1923 * squared length instead, to avoid sqrt.
1925 GLfloat Px2 = dudx * dudx + dvdx * dvdx;
1926 GLfloat Py2 = dudy * dudy + dvdy * dvdy;
1946 /* if the eccentricity of the ellipse is too big, scale up the shorter
1947 * of the two vectors to limit the maximum amount of work per pixel
1950 if (e > maxEccentricity) {
1951 /* GLfloat s=e / maxEccentricity;
1955 Pmin2 = Pmax2 / maxEccentricity;
1958 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
1959 * this since 0.5*log(x) = log(sqrt(x))
1961 lod = 0.5f * LOG2(Pmin2);
1964 /* from swrast/s_texcombine.c _swrast_texture_span */
1965 if (texUnit->LodBias + samp->LodBias != 0.0F) {
1966 /* apply LOD bias, but don't clamp yet */
1967 const GLfloat bias =
1968 CLAMP(texUnit->LodBias + samp->LodBias,
1969 -ctx->Const.MaxTextureLodBias,
1970 ctx->Const.MaxTextureLodBias);
1973 if (samp->MinLod != -1000.0 ||
1974 samp->MaxLod != 1000.0) {
1975 /* apply LOD clamping to lambda */
1976 lod = CLAMP(lod, samp->MinLod, samp->MaxLod);
1981 /* If the ellipse covers the whole image, we can
1982 * simply return the average of the whole image.
1984 if (lod >= tObj->_MaxLevel) {
1985 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1986 texcoords[i], rgba[i]);
1989 /* don't bother interpolating between multiple LODs; it doesn't
1990 * seem to be worth the extra running time.
1992 sample_2d_ewa(ctx, samp, tObj, texcoords[i],
1993 dudx, dvdx, dudy, dvdy, (GLint) floorf(lod), rgba[i]);
1996 (void) sample_2d_footprint;
1998 sample_2d_footprint(ctx, tObj, texcoords[i],
1999 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
2007 /**********************************************************************/
2008 /* 3-D Texture Sampling Functions */
2009 /**********************************************************************/
2012 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2015 sample_3d_nearest(struct gl_context *ctx,
2016 const struct gl_sampler_object *samp,
2017 const struct gl_texture_image *img,
2018 const GLfloat texcoord[4],
2021 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2022 const GLint width = img->Width2; /* without border, power of two */
2023 const GLint height = img->Height2; /* without border, power of two */
2024 const GLint depth = img->Depth2; /* without border, power of two */
2028 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2029 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2030 k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]);
2032 if (i < 0 || i >= (GLint) img->Width ||
2033 j < 0 || j >= (GLint) img->Height ||
2034 k < 0 || k >= (GLint) img->Depth) {
2035 /* Need this test for GL_CLAMP_TO_BORDER mode */
2036 get_border_color(samp, img, rgba);
2039 swImg->FetchTexel(swImg, i, j, k, rgba);
2045 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2048 sample_3d_linear(struct gl_context *ctx,
2049 const struct gl_sampler_object *samp,
2050 const struct gl_texture_image *img,
2051 const GLfloat texcoord[4],
2054 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2055 const GLint width = img->Width2;
2056 const GLint height = img->Height2;
2057 const GLint depth = img->Depth2;
2058 GLint i0, j0, k0, i1, j1, k1;
2059 GLbitfield useBorderColor = 0x0;
2061 GLfloat t000[4], t010[4], t001[4], t011[4];
2062 GLfloat t100[4], t110[4], t101[4], t111[4];
2064 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2065 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2066 linear_texel_locations(samp->WrapR, img, depth, texcoord[2], &k0, &k1, &c);
2077 /* check if sampling texture border color */
2078 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2079 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2080 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2081 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2082 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
2083 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
2087 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
2088 get_border_color(samp, img, t000);
2091 swImg->FetchTexel(swImg, i0, j0, k0, t000);
2093 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
2094 get_border_color(samp, img, t100);
2097 swImg->FetchTexel(swImg, i1, j0, k0, t100);
2099 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
2100 get_border_color(samp, img, t010);
2103 swImg->FetchTexel(swImg, i0, j1, k0, t010);
2105 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
2106 get_border_color(samp, img, t110);
2109 swImg->FetchTexel(swImg, i1, j1, k0, t110);
2112 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
2113 get_border_color(samp, img, t001);
2116 swImg->FetchTexel(swImg, i0, j0, k1, t001);
2118 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
2119 get_border_color(samp, img, t101);
2122 swImg->FetchTexel(swImg, i1, j0, k1, t101);
2124 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
2125 get_border_color(samp, img, t011);
2128 swImg->FetchTexel(swImg, i0, j1, k1, t011);
2130 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
2131 get_border_color(samp, img, t111);
2134 swImg->FetchTexel(swImg, i1, j1, k1, t111);
2137 /* trilinear interpolation of samples */
2138 lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
2143 sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
2144 const struct gl_sampler_object *samp,
2145 const struct gl_texture_object *tObj,
2146 GLuint n, const GLfloat texcoord[][4],
2147 const GLfloat lambda[], GLfloat rgba[][4] )
2150 for (i = 0; i < n; i++) {
2151 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2152 sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2158 sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
2159 const struct gl_sampler_object *samp,
2160 const struct gl_texture_object *tObj,
2161 GLuint n, const GLfloat texcoord[][4],
2162 const GLfloat lambda[], GLfloat rgba[][4])
2165 ASSERT(lambda != NULL);
2166 for (i = 0; i < n; i++) {
2167 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2168 sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2174 sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
2175 const struct gl_sampler_object *samp,
2176 const struct gl_texture_object *tObj,
2177 GLuint n, const GLfloat texcoord[][4],
2178 const GLfloat lambda[], GLfloat rgba[][4])
2181 ASSERT(lambda != NULL);
2182 for (i = 0; i < n; i++) {
2183 GLint level = linear_mipmap_level(tObj, lambda[i]);
2184 if (level >= tObj->_MaxLevel) {
2185 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2186 texcoord[i], rgba[i]);
2189 GLfloat t0[4], t1[4]; /* texels */
2190 const GLfloat f = FRAC(lambda[i]);
2191 sample_3d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
2192 sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2193 lerp_rgba(rgba[i], f, t0, t1);
2200 sample_3d_linear_mipmap_linear(struct gl_context *ctx,
2201 const struct gl_sampler_object *samp,
2202 const struct gl_texture_object *tObj,
2203 GLuint n, const GLfloat texcoord[][4],
2204 const GLfloat lambda[], GLfloat rgba[][4])
2207 ASSERT(lambda != NULL);
2208 for (i = 0; i < n; i++) {
2209 GLint level = linear_mipmap_level(tObj, lambda[i]);
2210 if (level >= tObj->_MaxLevel) {
2211 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2212 texcoord[i], rgba[i]);
2215 GLfloat t0[4], t1[4]; /* texels */
2216 const GLfloat f = FRAC(lambda[i]);
2217 sample_3d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
2218 sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2219 lerp_rgba(rgba[i], f, t0, t1);
2225 /** Sample 3D texture, nearest filtering for both min/magnification */
2227 sample_nearest_3d(struct gl_context *ctx,
2228 const struct gl_sampler_object *samp,
2229 const struct gl_texture_object *tObj, GLuint n,
2230 const GLfloat texcoords[][4], const GLfloat lambda[],
2234 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2236 for (i = 0; i < n; i++) {
2237 sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
2242 /** Sample 3D texture, linear filtering for both min/magnification */
2244 sample_linear_3d(struct gl_context *ctx,
2245 const struct gl_sampler_object *samp,
2246 const struct gl_texture_object *tObj, GLuint n,
2247 const GLfloat texcoords[][4],
2248 const GLfloat lambda[], GLfloat rgba[][4])
2251 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
2253 for (i = 0; i < n; i++) {
2254 sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]);
2259 /** Sample 3D texture, using lambda to choose between min/magnification */
2261 sample_lambda_3d(struct gl_context *ctx,
2262 const struct gl_sampler_object *samp,
2263 const struct gl_texture_object *tObj, GLuint n,
2264 const GLfloat texcoords[][4], const GLfloat lambda[],
2267 GLuint minStart, minEnd; /* texels with minification */
2268 GLuint magStart, magEnd; /* texels with magnification */
2271 ASSERT(lambda != NULL);
2272 compute_min_mag_ranges(samp, n, lambda,
2273 &minStart, &minEnd, &magStart, &magEnd);
2275 if (minStart < minEnd) {
2276 /* do the minified texels */
2277 GLuint m = minEnd - minStart;
2278 switch (samp->MinFilter) {
2280 for (i = minStart; i < minEnd; i++)
2281 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2282 texcoords[i], rgba[i]);
2285 for (i = minStart; i < minEnd; i++)
2286 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2287 texcoords[i], rgba[i]);
2289 case GL_NEAREST_MIPMAP_NEAREST:
2290 sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2291 lambda + minStart, rgba + minStart);
2293 case GL_LINEAR_MIPMAP_NEAREST:
2294 sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2295 lambda + minStart, rgba + minStart);
2297 case GL_NEAREST_MIPMAP_LINEAR:
2298 sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2299 lambda + minStart, rgba + minStart);
2301 case GL_LINEAR_MIPMAP_LINEAR:
2302 sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2303 lambda + minStart, rgba + minStart);
2306 _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
2311 if (magStart < magEnd) {
2312 /* do the magnified texels */
2313 switch (samp->MagFilter) {
2315 for (i = magStart; i < magEnd; i++)
2316 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2317 texcoords[i], rgba[i]);
2320 for (i = magStart; i < magEnd; i++)
2321 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
2322 texcoords[i], rgba[i]);
2325 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
2332 /**********************************************************************/
2333 /* Texture Cube Map Sampling Functions */
2334 /**********************************************************************/
2337 * Choose one of six sides of a texture cube map given the texture
2338 * coord (rx,ry,rz). Return pointer to corresponding array of texture
2341 static const struct gl_texture_image **
2342 choose_cube_face(const struct gl_texture_object *texObj,
2343 const GLfloat texcoord[4], GLfloat newCoord[4])
2347 direction target sc tc ma
2348 ---------- ------------------------------- --- --- ---
2349 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
2350 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
2351 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
2352 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
2353 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
2354 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
2356 const GLfloat rx = texcoord[0];
2357 const GLfloat ry = texcoord[1];
2358 const GLfloat rz = texcoord[2];
2359 const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
2363 if (arx >= ary && arx >= arz) {
2377 else if (ary >= arx && ary >= arz) {
2407 const float ima = 1.0F / ma;
2408 newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
2409 newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
2412 return (const struct gl_texture_image **) texObj->Image[face];
2417 sample_nearest_cube(struct gl_context *ctx,
2418 const struct gl_sampler_object *samp,
2419 const struct gl_texture_object *tObj, GLuint n,
2420 const GLfloat texcoords[][4], const GLfloat lambda[],
2425 for (i = 0; i < n; i++) {
2426 const struct gl_texture_image **images;
2427 GLfloat newCoord[4];
2428 images = choose_cube_face(tObj, texcoords[i], newCoord);
2429 sample_2d_nearest(ctx, samp, images[tObj->BaseLevel],
2432 if (is_depth_texture(tObj)) {
2433 for (i = 0; i < n; i++) {
2434 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2441 sample_linear_cube(struct gl_context *ctx,
2442 const struct gl_sampler_object *samp,
2443 const struct gl_texture_object *tObj, GLuint n,
2444 const GLfloat texcoords[][4],
2445 const GLfloat lambda[], GLfloat rgba[][4])
2449 for (i = 0; i < n; i++) {
2450 const struct gl_texture_image **images;
2451 GLfloat newCoord[4];
2452 images = choose_cube_face(tObj, texcoords[i], newCoord);
2453 sample_2d_linear(ctx, samp, images[tObj->BaseLevel],
2456 if (is_depth_texture(tObj)) {
2457 for (i = 0; i < n; i++) {
2458 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2465 sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
2466 const struct gl_sampler_object *samp,
2467 const struct gl_texture_object *tObj,
2468 GLuint n, const GLfloat texcoord[][4],
2469 const GLfloat lambda[], GLfloat rgba[][4])
2472 ASSERT(lambda != NULL);
2473 for (i = 0; i < n; i++) {
2474 const struct gl_texture_image **images;
2475 GLfloat newCoord[4];
2477 images = choose_cube_face(tObj, texcoord[i], newCoord);
2479 /* XXX we actually need to recompute lambda here based on the newCoords.
2480 * But we would need the texcoords of adjacent fragments to compute that
2481 * properly, and we don't have those here.
2482 * For now, do an approximation: subtracting 1 from the chosen mipmap
2483 * level seems to work in some test cases.
2484 * The same adjustment is done in the next few functions.
2486 level = nearest_mipmap_level(tObj, lambda[i]);
2487 level = MAX2(level - 1, 0);
2489 sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]);
2491 if (is_depth_texture(tObj)) {
2492 for (i = 0; i < n; i++) {
2493 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2500 sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
2501 const struct gl_sampler_object *samp,
2502 const struct gl_texture_object *tObj,
2503 GLuint n, const GLfloat texcoord[][4],
2504 const GLfloat lambda[], GLfloat rgba[][4])
2507 ASSERT(lambda != NULL);
2508 for (i = 0; i < n; i++) {
2509 const struct gl_texture_image **images;
2510 GLfloat newCoord[4];
2511 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2512 level = MAX2(level - 1, 0); /* see comment above */
2513 images = choose_cube_face(tObj, texcoord[i], newCoord);
2514 sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]);
2516 if (is_depth_texture(tObj)) {
2517 for (i = 0; i < n; i++) {
2518 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2525 sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
2526 const struct gl_sampler_object *samp,
2527 const struct gl_texture_object *tObj,
2528 GLuint n, const GLfloat texcoord[][4],
2529 const GLfloat lambda[], GLfloat rgba[][4])
2532 ASSERT(lambda != NULL);
2533 for (i = 0; i < n; i++) {
2534 const struct gl_texture_image **images;
2535 GLfloat newCoord[4];
2536 GLint level = linear_mipmap_level(tObj, lambda[i]);
2537 level = MAX2(level - 1, 0); /* see comment above */
2538 images = choose_cube_face(tObj, texcoord[i], newCoord);
2539 if (level >= tObj->_MaxLevel) {
2540 sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel],
2544 GLfloat t0[4], t1[4]; /* texels */
2545 const GLfloat f = FRAC(lambda[i]);
2546 sample_2d_nearest(ctx, samp, images[level ], newCoord, t0);
2547 sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1);
2548 lerp_rgba(rgba[i], f, t0, t1);
2551 if (is_depth_texture(tObj)) {
2552 for (i = 0; i < n; i++) {
2553 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2560 sample_cube_linear_mipmap_linear(struct gl_context *ctx,
2561 const struct gl_sampler_object *samp,
2562 const struct gl_texture_object *tObj,
2563 GLuint n, const GLfloat texcoord[][4],
2564 const GLfloat lambda[], GLfloat rgba[][4])
2567 ASSERT(lambda != NULL);
2568 for (i = 0; i < n; i++) {
2569 const struct gl_texture_image **images;
2570 GLfloat newCoord[4];
2571 GLint level = linear_mipmap_level(tObj, lambda[i]);
2572 level = MAX2(level - 1, 0); /* see comment above */
2573 images = choose_cube_face(tObj, texcoord[i], newCoord);
2574 if (level >= tObj->_MaxLevel) {
2575 sample_2d_linear(ctx, samp, images[tObj->_MaxLevel],
2579 GLfloat t0[4], t1[4];
2580 const GLfloat f = FRAC(lambda[i]);
2581 sample_2d_linear(ctx, samp, images[level ], newCoord, t0);
2582 sample_2d_linear(ctx, samp, images[level+1], newCoord, t1);
2583 lerp_rgba(rgba[i], f, t0, t1);
2586 if (is_depth_texture(tObj)) {
2587 for (i = 0; i < n; i++) {
2588 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2594 /** Sample cube texture, using lambda to choose between min/magnification */
2596 sample_lambda_cube(struct gl_context *ctx,
2597 const struct gl_sampler_object *samp,
2598 const struct gl_texture_object *tObj, GLuint n,
2599 const GLfloat texcoords[][4], const GLfloat lambda[],
2602 GLuint minStart, minEnd; /* texels with minification */
2603 GLuint magStart, magEnd; /* texels with magnification */
2605 ASSERT(lambda != NULL);
2606 compute_min_mag_ranges(samp, n, lambda,
2607 &minStart, &minEnd, &magStart, &magEnd);
2609 if (minStart < minEnd) {
2610 /* do the minified texels */
2611 const GLuint m = minEnd - minStart;
2612 switch (samp->MinFilter) {
2614 sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart,
2615 lambda + minStart, rgba + minStart);
2618 sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart,
2619 lambda + minStart, rgba + minStart);
2621 case GL_NEAREST_MIPMAP_NEAREST:
2622 sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m,
2623 texcoords + minStart,
2624 lambda + minStart, rgba + minStart);
2626 case GL_LINEAR_MIPMAP_NEAREST:
2627 sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m,
2628 texcoords + minStart,
2629 lambda + minStart, rgba + minStart);
2631 case GL_NEAREST_MIPMAP_LINEAR:
2632 sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m,
2633 texcoords + minStart,
2634 lambda + minStart, rgba + minStart);
2636 case GL_LINEAR_MIPMAP_LINEAR:
2637 sample_cube_linear_mipmap_linear(ctx, samp, tObj, m,
2638 texcoords + minStart,
2639 lambda + minStart, rgba + minStart);
2642 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2647 if (magStart < magEnd) {
2648 /* do the magnified texels */
2649 const GLuint m = magEnd - magStart;
2650 switch (samp->MagFilter) {
2652 sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart,
2653 lambda + magStart, rgba + magStart);
2656 sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart,
2657 lambda + magStart, rgba + magStart);
2660 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2667 /**********************************************************************/
2668 /* Texture Rectangle Sampling Functions */
2669 /**********************************************************************/
2673 sample_nearest_rect(struct gl_context *ctx,
2674 const struct gl_sampler_object *samp,
2675 const struct gl_texture_object *tObj, GLuint n,
2676 const GLfloat texcoords[][4], const GLfloat lambda[],
2679 const struct gl_texture_image *img = tObj->Image[0][0];
2680 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2681 const GLint width = img->Width;
2682 const GLint height = img->Height;
2688 ASSERT(samp->WrapS == GL_CLAMP ||
2689 samp->WrapS == GL_CLAMP_TO_EDGE ||
2690 samp->WrapS == GL_CLAMP_TO_BORDER);
2691 ASSERT(samp->WrapT == GL_CLAMP ||
2692 samp->WrapT == GL_CLAMP_TO_EDGE ||
2693 samp->WrapT == GL_CLAMP_TO_BORDER);
2695 for (i = 0; i < n; i++) {
2697 col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width);
2698 row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height);
2699 if (col < 0 || col >= width || row < 0 || row >= height)
2700 get_border_color(samp, img, rgba[i]);
2702 swImg->FetchTexel(swImg, col, row, 0, rgba[i]);
2708 sample_linear_rect(struct gl_context *ctx,
2709 const struct gl_sampler_object *samp,
2710 const struct gl_texture_object *tObj, GLuint n,
2711 const GLfloat texcoords[][4],
2712 const GLfloat lambda[], GLfloat rgba[][4])
2714 const struct gl_texture_image *img = tObj->Image[0][0];
2715 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2716 const GLint width = img->Width;
2717 const GLint height = img->Height;
2723 ASSERT(samp->WrapS == GL_CLAMP ||
2724 samp->WrapS == GL_CLAMP_TO_EDGE ||
2725 samp->WrapS == GL_CLAMP_TO_BORDER);
2726 ASSERT(samp->WrapT == GL_CLAMP ||
2727 samp->WrapT == GL_CLAMP_TO_EDGE ||
2728 samp->WrapT == GL_CLAMP_TO_BORDER);
2730 for (i = 0; i < n; i++) {
2731 GLint i0, j0, i1, j1;
2732 GLfloat t00[4], t01[4], t10[4], t11[4];
2734 GLbitfield useBorderColor = 0x0;
2736 clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width,
2738 clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height,
2741 /* compute integer rows/columns */
2742 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2743 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2744 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2745 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2747 /* get four texel samples */
2748 if (useBorderColor & (I0BIT | J0BIT))
2749 get_border_color(samp, img, t00);
2751 swImg->FetchTexel(swImg, i0, j0, 0, t00);
2753 if (useBorderColor & (I1BIT | J0BIT))
2754 get_border_color(samp, img, t10);
2756 swImg->FetchTexel(swImg, i1, j0, 0, t10);
2758 if (useBorderColor & (I0BIT | J1BIT))
2759 get_border_color(samp, img, t01);
2761 swImg->FetchTexel(swImg, i0, j1, 0, t01);
2763 if (useBorderColor & (I1BIT | J1BIT))
2764 get_border_color(samp, img, t11);
2766 swImg->FetchTexel(swImg, i1, j1, 0, t11);
2768 lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
2773 /** Sample Rect texture, using lambda to choose between min/magnification */
2775 sample_lambda_rect(struct gl_context *ctx,
2776 const struct gl_sampler_object *samp,
2777 const struct gl_texture_object *tObj, GLuint n,
2778 const GLfloat texcoords[][4], const GLfloat lambda[],
2781 GLuint minStart, minEnd, magStart, magEnd;
2783 /* We only need lambda to decide between minification and magnification.
2784 * There is no mipmapping with rectangular textures.
2786 compute_min_mag_ranges(samp, n, lambda,
2787 &minStart, &minEnd, &magStart, &magEnd);
2789 if (minStart < minEnd) {
2790 if (samp->MinFilter == GL_NEAREST) {
2791 sample_nearest_rect(ctx, samp, tObj, minEnd - minStart,
2792 texcoords + minStart, NULL, rgba + minStart);
2795 sample_linear_rect(ctx, samp, tObj, minEnd - minStart,
2796 texcoords + minStart, NULL, rgba + minStart);
2799 if (magStart < magEnd) {
2800 if (samp->MagFilter == GL_NEAREST) {
2801 sample_nearest_rect(ctx, samp, tObj, magEnd - magStart,
2802 texcoords + magStart, NULL, rgba + magStart);
2805 sample_linear_rect(ctx, samp, tObj, magEnd - magStart,
2806 texcoords + magStart, NULL, rgba + magStart);
2812 /**********************************************************************/
2813 /* 2D Texture Array Sampling Functions */
2814 /**********************************************************************/
2817 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2820 sample_2d_array_nearest(struct gl_context *ctx,
2821 const struct gl_sampler_object *samp,
2822 const struct gl_texture_image *img,
2823 const GLfloat texcoord[4],
2826 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2827 const GLint width = img->Width2; /* without border, power of two */
2828 const GLint height = img->Height2; /* without border, power of two */
2829 const GLint depth = img->Depth;
2834 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2835 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2836 array = tex_array_slice(texcoord[2], depth);
2838 if (i < 0 || i >= (GLint) img->Width ||
2839 j < 0 || j >= (GLint) img->Height ||
2840 array < 0 || array >= (GLint) img->Depth) {
2841 /* Need this test for GL_CLAMP_TO_BORDER mode */
2842 get_border_color(samp, img, rgba);
2845 swImg->FetchTexel(swImg, i, j, array, rgba);
2851 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2854 sample_2d_array_linear(struct gl_context *ctx,
2855 const struct gl_sampler_object *samp,
2856 const struct gl_texture_image *img,
2857 const GLfloat texcoord[4],
2860 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2861 const GLint width = img->Width2;
2862 const GLint height = img->Height2;
2863 const GLint depth = img->Depth;
2864 GLint i0, j0, i1, j1;
2866 GLbitfield useBorderColor = 0x0;
2868 GLfloat t00[4], t01[4], t10[4], t11[4];
2870 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2871 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2872 array = tex_array_slice(texcoord[2], depth);
2874 if (array < 0 || array >= depth) {
2875 COPY_4V(rgba, samp->BorderColor.f);
2885 /* check if sampling texture border color */
2886 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2887 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2888 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2889 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2893 if (useBorderColor & (I0BIT | J0BIT)) {
2894 get_border_color(samp, img, t00);
2897 swImg->FetchTexel(swImg, i0, j0, array, t00);
2899 if (useBorderColor & (I1BIT | J0BIT)) {
2900 get_border_color(samp, img, t10);
2903 swImg->FetchTexel(swImg, i1, j0, array, t10);
2905 if (useBorderColor & (I0BIT | J1BIT)) {
2906 get_border_color(samp, img, t01);
2909 swImg->FetchTexel(swImg, i0, j1, array, t01);
2911 if (useBorderColor & (I1BIT | J1BIT)) {
2912 get_border_color(samp, img, t11);
2915 swImg->FetchTexel(swImg, i1, j1, array, t11);
2918 /* trilinear interpolation of samples */
2919 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
2925 sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx,
2926 const struct gl_sampler_object *samp,
2927 const struct gl_texture_object *tObj,
2928 GLuint n, const GLfloat texcoord[][4],
2929 const GLfloat lambda[], GLfloat rgba[][4])
2932 for (i = 0; i < n; i++) {
2933 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2934 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
2941 sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx,
2942 const struct gl_sampler_object *samp,
2943 const struct gl_texture_object *tObj,
2944 GLuint n, const GLfloat texcoord[][4],
2945 const GLfloat lambda[], GLfloat rgba[][4])
2948 ASSERT(lambda != NULL);
2949 for (i = 0; i < n; i++) {
2950 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2951 sample_2d_array_linear(ctx, samp, tObj->Image[0][level],
2952 texcoord[i], rgba[i]);
2958 sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx,
2959 const struct gl_sampler_object *samp,
2960 const struct gl_texture_object *tObj,
2961 GLuint n, const GLfloat texcoord[][4],
2962 const GLfloat lambda[], GLfloat rgba[][4])
2965 ASSERT(lambda != NULL);
2966 for (i = 0; i < n; i++) {
2967 GLint level = linear_mipmap_level(tObj, lambda[i]);
2968 if (level >= tObj->_MaxLevel) {
2969 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2970 texcoord[i], rgba[i]);
2973 GLfloat t0[4], t1[4]; /* texels */
2974 const GLfloat f = FRAC(lambda[i]);
2975 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level ],
2977 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1],
2979 lerp_rgba(rgba[i], f, t0, t1);
2986 sample_2d_array_linear_mipmap_linear(struct gl_context *ctx,
2987 const struct gl_sampler_object *samp,
2988 const struct gl_texture_object *tObj,
2989 GLuint n, const GLfloat texcoord[][4],
2990 const GLfloat lambda[], GLfloat rgba[][4])
2993 ASSERT(lambda != NULL);
2994 for (i = 0; i < n; i++) {
2995 GLint level = linear_mipmap_level(tObj, lambda[i]);
2996 if (level >= tObj->_MaxLevel) {
2997 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2998 texcoord[i], rgba[i]);
3001 GLfloat t0[4], t1[4]; /* texels */
3002 const GLfloat f = FRAC(lambda[i]);
3003 sample_2d_array_linear(ctx, samp, tObj->Image[0][level ],
3005 sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1],
3007 lerp_rgba(rgba[i], f, t0, t1);
3013 /** Sample 2D Array texture, nearest filtering for both min/magnification */
3015 sample_nearest_2d_array(struct gl_context *ctx,
3016 const struct gl_sampler_object *samp,
3017 const struct gl_texture_object *tObj, GLuint n,
3018 const GLfloat texcoords[][4], const GLfloat lambda[],
3022 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3024 for (i = 0; i < n; i++) {
3025 sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3031 /** Sample 2D Array texture, linear filtering for both min/magnification */
3033 sample_linear_2d_array(struct gl_context *ctx,
3034 const struct gl_sampler_object *samp,
3035 const struct gl_texture_object *tObj, GLuint n,
3036 const GLfloat texcoords[][4],
3037 const GLfloat lambda[], GLfloat rgba[][4])
3040 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3042 for (i = 0; i < n; i++) {
3043 sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3048 /** Sample 2D Array texture, using lambda to choose between min/magnification */
3050 sample_lambda_2d_array(struct gl_context *ctx,
3051 const struct gl_sampler_object *samp,
3052 const struct gl_texture_object *tObj, GLuint n,
3053 const GLfloat texcoords[][4], const GLfloat lambda[],
3056 GLuint minStart, minEnd; /* texels with minification */
3057 GLuint magStart, magEnd; /* texels with magnification */
3060 ASSERT(lambda != NULL);
3061 compute_min_mag_ranges(samp, n, lambda,
3062 &minStart, &minEnd, &magStart, &magEnd);
3064 if (minStart < minEnd) {
3065 /* do the minified texels */
3066 GLuint m = minEnd - minStart;
3067 switch (samp->MinFilter) {
3069 for (i = minStart; i < minEnd; i++)
3070 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3071 texcoords[i], rgba[i]);
3074 for (i = minStart; i < minEnd; i++)
3075 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3076 texcoords[i], rgba[i]);
3078 case GL_NEAREST_MIPMAP_NEAREST:
3079 sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m,
3080 texcoords + minStart,
3084 case GL_LINEAR_MIPMAP_NEAREST:
3085 sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3086 texcoords + minStart,
3090 case GL_NEAREST_MIPMAP_LINEAR:
3091 sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m,
3092 texcoords + minStart,
3096 case GL_LINEAR_MIPMAP_LINEAR:
3097 sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3098 texcoords + minStart,
3103 _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
3108 if (magStart < magEnd) {
3109 /* do the magnified texels */
3110 switch (samp->MagFilter) {
3112 for (i = magStart; i < magEnd; i++)
3113 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3114 texcoords[i], rgba[i]);
3117 for (i = magStart; i < magEnd; i++)
3118 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3119 texcoords[i], rgba[i]);
3122 _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
3131 /**********************************************************************/
3132 /* 1D Texture Array Sampling Functions */
3133 /**********************************************************************/
3136 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
3139 sample_1d_array_nearest(struct gl_context *ctx,
3140 const struct gl_sampler_object *samp,
3141 const struct gl_texture_image *img,
3142 const GLfloat texcoord[4],
3145 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3146 const GLint width = img->Width2; /* without border, power of two */
3147 const GLint height = img->Height;
3152 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
3153 array = tex_array_slice(texcoord[1], height);
3155 if (i < 0 || i >= (GLint) img->Width ||
3156 array < 0 || array >= (GLint) img->Height) {
3157 /* Need this test for GL_CLAMP_TO_BORDER mode */
3158 get_border_color(samp, img, rgba);
3161 swImg->FetchTexel(swImg, i, array, 0, rgba);
3167 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
3170 sample_1d_array_linear(struct gl_context *ctx,
3171 const struct gl_sampler_object *samp,
3172 const struct gl_texture_image *img,
3173 const GLfloat texcoord[4],
3176 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3177 const GLint width = img->Width2;
3178 const GLint height = img->Height;
3181 GLbitfield useBorderColor = 0x0;
3183 GLfloat t0[4], t1[4];
3185 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
3186 array = tex_array_slice(texcoord[1], height);
3193 /* check if sampling texture border color */
3194 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
3195 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
3198 if (array < 0 || array >= height) useBorderColor |= K0BIT;
3201 if (useBorderColor & (I0BIT | K0BIT)) {
3202 get_border_color(samp, img, t0);
3205 swImg->FetchTexel(swImg, i0, array, 0, t0);
3207 if (useBorderColor & (I1BIT | K0BIT)) {
3208 get_border_color(samp, img, t1);
3211 swImg->FetchTexel(swImg, i1, array, 0, t1);
3214 /* bilinear interpolation of samples */
3215 lerp_rgba(rgba, a, t0, t1);
3220 sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx,
3221 const struct gl_sampler_object *samp,
3222 const struct gl_texture_object *tObj,
3223 GLuint n, const GLfloat texcoord[][4],
3224 const GLfloat lambda[], GLfloat rgba[][4])
3227 for (i = 0; i < n; i++) {
3228 GLint level = nearest_mipmap_level(tObj, lambda[i]);
3229 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
3236 sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx,
3237 const struct gl_sampler_object *samp,
3238 const struct gl_texture_object *tObj,
3239 GLuint n, const GLfloat texcoord[][4],
3240 const GLfloat lambda[], GLfloat rgba[][4])
3243 ASSERT(lambda != NULL);
3244 for (i = 0; i < n; i++) {
3245 GLint level = nearest_mipmap_level(tObj, lambda[i]);
3246 sample_1d_array_linear(ctx, samp, tObj->Image[0][level],
3247 texcoord[i], rgba[i]);
3253 sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx,
3254 const struct gl_sampler_object *samp,
3255 const struct gl_texture_object *tObj,
3256 GLuint n, const GLfloat texcoord[][4],
3257 const GLfloat lambda[], GLfloat rgba[][4])
3260 ASSERT(lambda != NULL);
3261 for (i = 0; i < n; i++) {
3262 GLint level = linear_mipmap_level(tObj, lambda[i]);
3263 if (level >= tObj->_MaxLevel) {
3264 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3265 texcoord[i], rgba[i]);
3268 GLfloat t0[4], t1[4]; /* texels */
3269 const GLfloat f = FRAC(lambda[i]);
3270 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
3271 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3272 lerp_rgba(rgba[i], f, t0, t1);
3279 sample_1d_array_linear_mipmap_linear(struct gl_context *ctx,
3280 const struct gl_sampler_object *samp,
3281 const struct gl_texture_object *tObj,
3282 GLuint n, const GLfloat texcoord[][4],
3283 const GLfloat lambda[], GLfloat rgba[][4])
3286 ASSERT(lambda != NULL);
3287 for (i = 0; i < n; i++) {
3288 GLint level = linear_mipmap_level(tObj, lambda[i]);
3289 if (level >= tObj->_MaxLevel) {
3290 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3291 texcoord[i], rgba[i]);
3294 GLfloat t0[4], t1[4]; /* texels */
3295 const GLfloat f = FRAC(lambda[i]);
3296 sample_1d_array_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
3297 sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3298 lerp_rgba(rgba[i], f, t0, t1);
3304 /** Sample 1D Array texture, nearest filtering for both min/magnification */
3306 sample_nearest_1d_array(struct gl_context *ctx,
3307 const struct gl_sampler_object *samp,
3308 const struct gl_texture_object *tObj, GLuint n,
3309 const GLfloat texcoords[][4], const GLfloat lambda[],
3313 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3315 for (i = 0; i < n; i++) {
3316 sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3321 /** Sample 1D Array texture, linear filtering for both min/magnification */
3323 sample_linear_1d_array(struct gl_context *ctx,
3324 const struct gl_sampler_object *samp,
3325 const struct gl_texture_object *tObj, GLuint n,
3326 const GLfloat texcoords[][4],
3327 const GLfloat lambda[], GLfloat rgba[][4])
3330 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
3332 for (i = 0; i < n; i++) {
3333 sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3338 /** Sample 1D Array texture, using lambda to choose between min/magnification */
3340 sample_lambda_1d_array(struct gl_context *ctx,
3341 const struct gl_sampler_object *samp,
3342 const struct gl_texture_object *tObj, GLuint n,
3343 const GLfloat texcoords[][4], const GLfloat lambda[],
3346 GLuint minStart, minEnd; /* texels with minification */
3347 GLuint magStart, magEnd; /* texels with magnification */
3350 ASSERT(lambda != NULL);
3351 compute_min_mag_ranges(samp, n, lambda,
3352 &minStart, &minEnd, &magStart, &magEnd);
3354 if (minStart < minEnd) {
3355 /* do the minified texels */
3356 GLuint m = minEnd - minStart;
3357 switch (samp->MinFilter) {
3359 for (i = minStart; i < minEnd; i++)
3360 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3361 texcoords[i], rgba[i]);
3364 for (i = minStart; i < minEnd; i++)
3365 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3366 texcoords[i], rgba[i]);
3368 case GL_NEAREST_MIPMAP_NEAREST:
3369 sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
3370 lambda + minStart, rgba + minStart);
3372 case GL_LINEAR_MIPMAP_NEAREST:
3373 sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3374 texcoords + minStart,
3378 case GL_NEAREST_MIPMAP_LINEAR:
3379 sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
3380 lambda + minStart, rgba + minStart);
3382 case GL_LINEAR_MIPMAP_LINEAR:
3383 sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3384 texcoords + minStart,
3389 _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
3394 if (magStart < magEnd) {
3395 /* do the magnified texels */
3396 switch (samp->MagFilter) {
3398 for (i = magStart; i < magEnd; i++)
3399 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3400 texcoords[i], rgba[i]);
3403 for (i = magStart; i < magEnd; i++)
3404 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->BaseLevel],
3405 texcoords[i], rgba[i]);
3408 _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
3416 * Compare texcoord against depth sample. Return 1.0 or 0.0 value.
3418 static inline GLfloat
3419 shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample)
3423 return (coord <= depthSample) ? 1.0F : 0.0F;
3425 return (coord >= depthSample) ? 1.0F : 0.0F;
3427 return (coord < depthSample) ? 1.0F : 0.0F;
3429 return (coord > depthSample) ? 1.0F : 0.0F;
3431 return (coord == depthSample) ? 1.0F : 0.0F;
3433 return (coord != depthSample) ? 1.0F : 0.0F;
3441 _mesa_problem(NULL, "Bad compare func in shadow_compare");
3448 * Compare texcoord against four depth samples.
3450 static inline GLfloat
3451 shadow_compare4(GLenum function, GLfloat coord,
3452 GLfloat depth00, GLfloat depth01,
3453 GLfloat depth10, GLfloat depth11,
3454 GLfloat wi, GLfloat wj)
3456 const GLfloat d = 0.25F;
3457 GLfloat luminance = 1.0F;
3461 if (coord > depth00) luminance -= d;
3462 if (coord > depth01) luminance -= d;
3463 if (coord > depth10) luminance -= d;
3464 if (coord > depth11) luminance -= d;
3467 if (coord < depth00) luminance -= d;
3468 if (coord < depth01) luminance -= d;
3469 if (coord < depth10) luminance -= d;
3470 if (coord < depth11) luminance -= d;
3473 if (coord >= depth00) luminance -= d;
3474 if (coord >= depth01) luminance -= d;
3475 if (coord >= depth10) luminance -= d;
3476 if (coord >= depth11) luminance -= d;
3479 if (coord <= depth00) luminance -= d;
3480 if (coord <= depth01) luminance -= d;
3481 if (coord <= depth10) luminance -= d;
3482 if (coord <= depth11) luminance -= d;
3485 if (coord != depth00) luminance -= d;
3486 if (coord != depth01) luminance -= d;
3487 if (coord != depth10) luminance -= d;
3488 if (coord != depth11) luminance -= d;
3491 if (coord == depth00) luminance -= d;
3492 if (coord == depth01) luminance -= d;
3493 if (coord == depth10) luminance -= d;
3494 if (coord == depth11) luminance -= d;
3501 /* ordinary bilinear filtering */
3502 return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
3504 _mesa_problem(NULL, "Bad compare func in sample_compare4");
3511 * Choose the mipmap level to use when sampling from a depth texture.
3514 choose_depth_texture_level(const struct gl_sampler_object *samp,
3515 const struct gl_texture_object *tObj, GLfloat lambda)
3519 if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) {
3520 /* no mipmapping - use base level */
3521 level = tObj->BaseLevel;
3524 /* choose mipmap level */
3525 lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
3526 level = (GLint) lambda;
3527 level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel);
3535 * Sample a shadow/depth texture. This function is incomplete. It doesn't
3536 * check for minification vs. magnification, etc.
3539 sample_depth_texture( struct gl_context *ctx,
3540 const struct gl_sampler_object *samp,
3541 const struct gl_texture_object *tObj, GLuint n,
3542 const GLfloat texcoords[][4], const GLfloat lambda[],
3543 GLfloat texel[][4] )
3545 const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]);
3546 const struct gl_texture_image *img = tObj->Image[0][level];
3547 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3548 const GLint width = img->Width;
3549 const GLint height = img->Height;
3550 const GLint depth = img->Depth;
3551 const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
3556 ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT ||
3557 img->_BaseFormat == GL_DEPTH_STENCIL_EXT);
3559 ASSERT(tObj->Target == GL_TEXTURE_1D ||
3560 tObj->Target == GL_TEXTURE_2D ||
3561 tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
3562 tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
3563 tObj->Target == GL_TEXTURE_2D_ARRAY_EXT ||
3564 tObj->Target == GL_TEXTURE_CUBE_MAP);
3566 /* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */
3568 function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ?
3569 samp->CompareFunc : GL_NONE;
3571 if (samp->MagFilter == GL_NEAREST) {
3573 for (i = 0; i < n; i++) {
3574 GLfloat depthSample, depthRef;
3575 GLint col, row, slice;
3577 nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice);
3579 if (col >= 0 && row >= 0 && col < width && row < height &&
3580 slice >= 0 && slice < depth) {
3581 swImg->FetchTexel(swImg, col, row, slice, &depthSample);
3584 depthSample = samp->BorderColor.f[0];
3587 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3589 result = shadow_compare(function, depthRef, depthSample);
3591 apply_depth_mode(tObj->DepthMode, result, texel[i]);
3596 ASSERT(samp->MagFilter == GL_LINEAR);
3597 for (i = 0; i < n; i++) {
3598 GLfloat depth00, depth01, depth10, depth11, depthRef;
3599 GLint i0, i1, j0, j1;
3602 GLuint useBorderTexel;
3604 linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice,
3611 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3617 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
3618 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
3619 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
3620 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
3623 if (slice < 0 || slice >= (GLint) depth) {
3624 depth00 = samp->BorderColor.f[0];
3625 depth01 = samp->BorderColor.f[0];
3626 depth10 = samp->BorderColor.f[0];
3627 depth11 = samp->BorderColor.f[0];
3630 /* get four depth samples from the texture */
3631 if (useBorderTexel & (I0BIT | J0BIT)) {
3632 depth00 = samp->BorderColor.f[0];
3635 swImg->FetchTexel(swImg, i0, j0, slice, &depth00);
3637 if (useBorderTexel & (I1BIT | J0BIT)) {
3638 depth10 = samp->BorderColor.f[0];
3641 swImg->FetchTexel(swImg, i1, j0, slice, &depth10);
3644 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3645 if (useBorderTexel & (I0BIT | J1BIT)) {
3646 depth01 = samp->BorderColor.f[0];
3649 swImg->FetchTexel(swImg, i0, j1, slice, &depth01);
3651 if (useBorderTexel & (I1BIT | J1BIT)) {
3652 depth11 = samp->BorderColor.f[0];
3655 swImg->FetchTexel(swImg, i1, j1, slice, &depth11);
3664 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3666 result = shadow_compare4(function, depthRef,
3667 depth00, depth01, depth10, depth11,
3670 apply_depth_mode(tObj->DepthMode, result, texel[i]);
3677 * We use this function when a texture object is in an "incomplete" state.
3678 * When a fragment program attempts to sample an incomplete texture we
3679 * return black (see issue 23 in GL_ARB_fragment_program spec).
3680 * Note: fragment programs don't observe the texture enable/disable flags.
3683 null_sample_func( struct gl_context *ctx,
3684 const struct gl_sampler_object *samp,
3685 const struct gl_texture_object *tObj, GLuint n,
3686 const GLfloat texcoords[][4], const GLfloat lambda[],
3695 for (i = 0; i < n; i++) {
3699 rgba[i][ACOMP] = 1.0;
3705 * Choose the texture sampling function for the given texture object.
3708 _swrast_choose_texture_sample_func( struct gl_context *ctx,
3709 const struct gl_texture_object *t,
3710 const struct gl_sampler_object *sampler)
3712 if (!t || !_mesa_is_texture_complete(t, sampler)) {
3713 return &null_sample_func;
3716 const GLboolean needLambda =
3717 (GLboolean) (sampler->MinFilter != sampler->MagFilter);
3719 switch (t->Target) {
3721 if (is_depth_texture(t)) {
3722 return &sample_depth_texture;
3724 else if (needLambda) {
3725 return &sample_lambda_1d;
3727 else if (sampler->MinFilter == GL_LINEAR) {
3728 return &sample_linear_1d;
3731 ASSERT(sampler->MinFilter == GL_NEAREST);
3732 return &sample_nearest_1d;
3735 if (is_depth_texture(t)) {
3736 return &sample_depth_texture;
3738 else if (needLambda) {
3739 /* Anisotropic filtering extension. Activated only if mipmaps are used */
3740 if (sampler->MaxAnisotropy > 1.0 &&
3741 sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
3742 return &sample_lambda_2d_aniso;
3744 return &sample_lambda_2d;
3746 else if (sampler->MinFilter == GL_LINEAR) {
3747 return &sample_linear_2d;
3750 /* check for a few optimized cases */
3751 const struct gl_texture_image *img = t->Image[0][t->BaseLevel];
3752 const struct swrast_texture_image *swImg =
3753 swrast_texture_image_const(img);
3754 texture_sample_func func;
3756 ASSERT(sampler->MinFilter == GL_NEAREST);
3757 func = &sample_nearest_2d;
3758 if (sampler->WrapS == GL_REPEAT &&
3759 sampler->WrapT == GL_REPEAT &&
3760 swImg->_IsPowerOfTwo &&
3762 if (img->TexFormat == MESA_FORMAT_RGB888)
3763 func = &opt_sample_rgb_2d;
3764 else if (img->TexFormat == MESA_FORMAT_RGBA8888)
3765 func = &opt_sample_rgba_2d;
3772 return &sample_lambda_3d;
3774 else if (sampler->MinFilter == GL_LINEAR) {
3775 return &sample_linear_3d;
3778 ASSERT(sampler->MinFilter == GL_NEAREST);
3779 return &sample_nearest_3d;
3781 case GL_TEXTURE_CUBE_MAP:
3783 return &sample_lambda_cube;
3785 else if (sampler->MinFilter == GL_LINEAR) {
3786 return &sample_linear_cube;
3789 ASSERT(sampler->MinFilter == GL_NEAREST);
3790 return &sample_nearest_cube;
3792 case GL_TEXTURE_RECTANGLE_NV:
3793 if (is_depth_texture(t)) {
3794 return &sample_depth_texture;
3796 else if (needLambda) {
3797 return &sample_lambda_rect;
3799 else if (sampler->MinFilter == GL_LINEAR) {
3800 return &sample_linear_rect;
3803 ASSERT(sampler->MinFilter == GL_NEAREST);
3804 return &sample_nearest_rect;
3806 case GL_TEXTURE_1D_ARRAY_EXT:
3807 if (is_depth_texture(t)) {
3808 return &sample_depth_texture;
3810 else if (needLambda) {
3811 return &sample_lambda_1d_array;
3813 else if (sampler->MinFilter == GL_LINEAR) {
3814 return &sample_linear_1d_array;
3817 ASSERT(sampler->MinFilter == GL_NEAREST);
3818 return &sample_nearest_1d_array;
3820 case GL_TEXTURE_2D_ARRAY_EXT:
3821 if (is_depth_texture(t)) {
3822 return &sample_depth_texture;
3824 else if (needLambda) {
3825 return &sample_lambda_2d_array;
3827 else if (sampler->MinFilter == GL_LINEAR) {
3828 return &sample_linear_2d_array;
3831 ASSERT(sampler->MinFilter == GL_NEAREST);
3832 return &sample_nearest_2d_array;
3836 "invalid target in _swrast_choose_texture_sample_func");
3837 return &null_sample_func;