X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fsoftpipe%2Fsp_tex_sample.c;h=ab032902aeceda34274bdab730ec101c57e7da8f;hb=18ef8f83b2586de037df7e578d88cbfb6e764012;hp=f7309480bb93a994184f651fac6b57bb1a07ea7f;hpb=b82db9a3c0a1b96d8eb5d0d78aecaf0ab331431a;p=mesa.git diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c index f7309480bb9..ab032902aec 100644 --- a/src/gallium/drivers/softpipe/sp_tex_sample.c +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c @@ -38,6 +38,7 @@ #include "pipe/p_defines.h" #include "pipe/p_shader_tokens.h" #include "util/u_math.h" +#include "util/u_format.h" #include "util/u_memory.h" #include "sp_quad.h" /* only for #define QUAD_* tokens */ #include "sp_tex_sample.h" @@ -129,313 +130,263 @@ repeat(int coord, unsigned size) * \return integer texture index */ static void -wrap_nearest_repeat(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_repeat(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [0,1) */ /* i limited to [0,size-1] */ - for (ch = 0; ch < 4; ch++) { - int i = util_ifloor(s[ch] * size); - icoord[ch] = repeat(i, size); - } + int i = util_ifloor(s * size); + *icoord = repeat(i, size); } static void -wrap_nearest_clamp(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_clamp(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [0,1] */ /* i limited to [0,size-1] */ - for (ch = 0; ch < 4; ch++) { - if (s[ch] <= 0.0F) - icoord[ch] = 0; - else if (s[ch] >= 1.0F) - icoord[ch] = size - 1; - else - icoord[ch] = util_ifloor(s[ch] * size); - } + if (s <= 0.0F) + *icoord = 0; + else if (s >= 1.0F) + *icoord = size - 1; + else + *icoord = util_ifloor(s * size); } static void -wrap_nearest_clamp_to_edge(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_clamp_to_edge(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [min,max] */ /* i limited to [0, size-1] */ const float min = 1.0F / (2.0F * size); const float max = 1.0F - min; - for (ch = 0; ch < 4; ch++) { - if (s[ch] < min) - icoord[ch] = 0; - else if (s[ch] > max) - icoord[ch] = size - 1; - else - icoord[ch] = util_ifloor(s[ch] * size); - } + if (s < min) + *icoord = 0; + else if (s > max) + *icoord = size - 1; + else + *icoord = util_ifloor(s * size); } static void -wrap_nearest_clamp_to_border(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_clamp_to_border(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [min,max] */ /* i limited to [-1, size] */ const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - for (ch = 0; ch < 4; ch++) { - if (s[ch] <= min) - icoord[ch] = -1; - else if (s[ch] >= max) - icoord[ch] = size; - else - icoord[ch] = util_ifloor(s[ch] * size); - } + if (s <= min) + *icoord = -1; + else if (s >= max) + *icoord = size; + else + *icoord = util_ifloor(s * size); } static void -wrap_nearest_mirror_repeat(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_mirror_repeat(float s, unsigned size, int *icoord) { - uint ch; const float min = 1.0F / (2.0F * size); const float max = 1.0F - min; - for (ch = 0; ch < 4; ch++) { - const int flr = util_ifloor(s[ch]); - float u = frac(s[ch]); - if (flr & 1) - u = 1.0F - u; - if (u < min) - icoord[ch] = 0; - else if (u > max) - icoord[ch] = size - 1; - else - icoord[ch] = util_ifloor(u * size); - } + const int flr = util_ifloor(s); + float u = frac(s); + if (flr & 1) + u = 1.0F - u; + if (u < min) + *icoord = 0; + else if (u > max) + *icoord = size - 1; + else + *icoord = util_ifloor(u * size); } static void -wrap_nearest_mirror_clamp(const float s[4], unsigned size, int icoord[4]) -{ - uint ch; - for (ch = 0; ch < 4; ch++) { - /* s limited to [0,1] */ - /* i limited to [0,size-1] */ - const float u = fabsf(s[ch]); - if (u <= 0.0F) - icoord[ch] = 0; - else if (u >= 1.0F) - icoord[ch] = size - 1; - else - icoord[ch] = util_ifloor(u * size); - } +wrap_nearest_mirror_clamp(float s, unsigned size, int *icoord) +{ + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + const float u = fabsf(s); + if (u <= 0.0F) + *icoord = 0; + else if (u >= 1.0F) + *icoord = size - 1; + else + *icoord = util_ifloor(u * size); } static void -wrap_nearest_mirror_clamp_to_edge(const float s[4], unsigned size, - int icoord[4]) +wrap_nearest_mirror_clamp_to_edge(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [min,max] */ /* i limited to [0, size-1] */ const float min = 1.0F / (2.0F * size); const float max = 1.0F - min; - for (ch = 0; ch < 4; ch++) { - const float u = fabsf(s[ch]); - if (u < min) - icoord[ch] = 0; - else if (u > max) - icoord[ch] = size - 1; - else - icoord[ch] = util_ifloor(u * size); - } + const float u = fabsf(s); + if (u < min) + *icoord = 0; + else if (u > max) + *icoord = size - 1; + else + *icoord = util_ifloor(u * size); } static void -wrap_nearest_mirror_clamp_to_border(const float s[4], unsigned size, - int icoord[4]) +wrap_nearest_mirror_clamp_to_border(float s, unsigned size, int *icoord) { - uint ch; /* s limited to [min,max] */ /* i limited to [0, size-1] */ const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - for (ch = 0; ch < 4; ch++) { - const float u = fabsf(s[ch]); - if (u < min) - icoord[ch] = -1; - else if (u > max) - icoord[ch] = size; - else - icoord[ch] = util_ifloor(u * size); - } + const float u = fabsf(s); + if (u < min) + *icoord = -1; + else if (u > max) + *icoord = size; + else + *icoord = util_ifloor(u * size); } /** - * Used to compute texel locations for linear sampling for four texcoords. + * Used to compute texel locations for linear sampling * \param wrapMode PIPE_TEX_WRAP_x - * \param s the texcoords + * \param s the texcoord * \param size the texture image size - * \param icoord0 returns first texture indexes - * \param icoord1 returns second texture indexes (usually icoord0 + 1) - * \param w returns blend factor/weight between texture indexes - * \param icoord returns the computed integer texture coords + * \param icoord0 returns first texture index + * \param icoord1 returns second texture index (usually icoord0 + 1) + * \param w returns blend factor/weight between texture indices + * \param icoord returns the computed integer texture coord */ static void -wrap_linear_repeat(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_repeat(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = s[ch] * size - 0.5F; - icoord0[ch] = repeat(util_ifloor(u), size); - icoord1[ch] = repeat(icoord0[ch] + 1, size); - w[ch] = frac(u); - } + float u = s * size - 0.5F; + *icoord0 = repeat(util_ifloor(u), size); + *icoord1 = repeat(*icoord0 + 1, size); + *w = frac(u); } static void -wrap_linear_clamp(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_clamp(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = CLAMP(s[ch], 0.0F, 1.0F); - u = u * size - 0.5f; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - w[ch] = frac(u); - } + float u = CLAMP(s, 0.0F, 1.0F); + u = u * size - 0.5f; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + *w = frac(u); } static void -wrap_linear_clamp_to_edge(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_clamp_to_edge(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = CLAMP(s[ch], 0.0F, 1.0F); - u = u * size - 0.5f; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - if (icoord0[ch] < 0) - icoord0[ch] = 0; - if (icoord1[ch] >= (int) size) - icoord1[ch] = size - 1; - w[ch] = frac(u); - } + float u = CLAMP(s, 0.0F, 1.0F); + u = u * size - 0.5f; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + if (*icoord0 < 0) + *icoord0 = 0; + if (*icoord1 >= (int) size) + *icoord1 = size - 1; + *w = frac(u); } static void -wrap_linear_clamp_to_border(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_clamp_to_border(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = CLAMP(s[ch], min, max); - u = u * size - 0.5f; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - w[ch] = frac(u); - } + float u = CLAMP(s, min, max); + u = u * size - 0.5f; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + *w = frac(u); } static void -wrap_linear_mirror_repeat(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_mirror_repeat(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - const int flr = util_ifloor(s[ch]); - float u = frac(s[ch]); - if (flr & 1) - u = 1.0F - u; - u = u * size - 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - if (icoord0[ch] < 0) - icoord0[ch] = 0; - if (icoord1[ch] >= (int) size) - icoord1[ch] = size - 1; - w[ch] = frac(u); - } + const int flr = util_ifloor(s); + float u = frac(s); + if (flr & 1) + u = 1.0F - u; + u = u * size - 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + if (*icoord0 < 0) + *icoord0 = 0; + if (*icoord1 >= (int) size) + *icoord1 = size - 1; + *w = frac(u); } static void -wrap_linear_mirror_clamp(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) -{ - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = fabsf(s[ch]); - if (u >= 1.0F) - u = (float) size; - else - u *= size; - u -= 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - w[ch] = frac(u); - } +wrap_linear_mirror_clamp(float s, unsigned size, + int *icoord0, int *icoord1, float *w) +{ + float u = fabsf(s); + if (u >= 1.0F) + u = (float) size; + else + u *= size; + u -= 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + *w = frac(u); } static void -wrap_linear_mirror_clamp_to_edge(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) -{ - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = fabsf(s[ch]); - if (u >= 1.0F) - u = (float) size; - else - u *= size; - u -= 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - if (icoord0[ch] < 0) - icoord0[ch] = 0; - if (icoord1[ch] >= (int) size) - icoord1[ch] = size - 1; - w[ch] = frac(u); - } +wrap_linear_mirror_clamp_to_edge(float s, unsigned size, + int *icoord0, int *icoord1, float *w) +{ + float u = fabsf(s); + if (u >= 1.0F) + u = (float) size; + else + u *= size; + u -= 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + if (*icoord0 < 0) + *icoord0 = 0; + if (*icoord1 >= (int) size) + *icoord1 = size - 1; + *w = frac(u); } static void -wrap_linear_mirror_clamp_to_border(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_mirror_clamp_to_border(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = fabsf(s[ch]); - if (u <= min) - u = min * size; - else if (u >= max) - u = max * size; - else - u *= size; - u -= 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - w[ch] = frac(u); - } + float u = fabsf(s); + if (u <= min) + u = min * size; + else if (u >= max) + u = max * size; + else + u *= size; + u -= 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + *w = frac(u); } @@ -443,13 +394,10 @@ wrap_linear_mirror_clamp_to_border(const float s[4], unsigned size, * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords. */ static void -wrap_nearest_unorm_clamp(const float s[4], unsigned size, int icoord[4]) +wrap_nearest_unorm_clamp(float s, unsigned size, int *icoord) { - uint ch; - for (ch = 0; ch < 4; ch++) { - int i = util_ifloor(s[ch]); - icoord[ch]= CLAMP(i, 0, (int) size-1); - } + int i = util_ifloor(s); + *icoord = CLAMP(i, 0, (int) size-1); } @@ -457,13 +405,9 @@ wrap_nearest_unorm_clamp(const float s[4], unsigned size, int icoord[4]) * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords. */ static void -wrap_nearest_unorm_clamp_to_border(const float s[4], unsigned size, - int icoord[4]) +wrap_nearest_unorm_clamp_to_border(float s, unsigned size, int *icoord) { - uint ch; - for (ch = 0; ch < 4; ch++) { - icoord[ch]= util_ifloor( CLAMP(s[ch], -0.5F, (float) size + 0.5F) ); - } + *icoord = util_ifloor( CLAMP(s, -0.5F, (float) size + 0.5F) ); } @@ -471,13 +415,9 @@ wrap_nearest_unorm_clamp_to_border(const float s[4], unsigned size, * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords. */ static void -wrap_nearest_unorm_clamp_to_edge(const float s[4], unsigned size, - int icoord[4]) +wrap_nearest_unorm_clamp_to_edge(float s, unsigned size, int *icoord) { - uint ch; - for (ch = 0; ch < 4; ch++) { - icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) ); - } + *icoord = util_ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) ); } @@ -485,17 +425,14 @@ wrap_nearest_unorm_clamp_to_edge(const float s[4], unsigned size, * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords. */ static void -wrap_linear_unorm_clamp(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_unorm_clamp(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - /* Not exactly what the spec says, but it matches NVIDIA output */ - float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f); - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - w[ch] = frac(u); - } + /* Not exactly what the spec says, but it matches NVIDIA output */ + float u = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f); + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + *w = frac(u); } @@ -503,19 +440,16 @@ wrap_linear_unorm_clamp(const float s[4], unsigned size, * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords. */ static void -wrap_linear_unorm_clamp_to_border(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_unorm_clamp_to_border(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = CLAMP(s[ch], -0.5F, (float) size + 0.5F); - u -= 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - if (icoord1[ch] > (int) size - 1) - icoord1[ch] = size - 1; - w[ch] = frac(u); - } + float u = CLAMP(s, -0.5F, (float) size + 0.5F); + u -= 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + if (*icoord1 > (int) size - 1) + *icoord1 = size - 1; + *w = frac(u); } @@ -523,19 +457,16 @@ wrap_linear_unorm_clamp_to_border(const float s[4], unsigned size, * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords. */ static void -wrap_linear_unorm_clamp_to_edge(const float s[4], unsigned size, - int icoord0[4], int icoord1[4], float w[4]) +wrap_linear_unorm_clamp_to_edge(float s, unsigned size, + int *icoord0, int *icoord1, float *w) { - uint ch; - for (ch = 0; ch < 4; ch++) { - float u = CLAMP(s[ch], +0.5F, (float) size - 0.5F); - u -= 0.5F; - icoord0[ch] = util_ifloor(u); - icoord1[ch] = icoord0[ch] + 1; - if (icoord1[ch] > (int) size - 1) - icoord1[ch] = size - 1; - w[ch] = frac(u); - } + float u = CLAMP(s, +0.5F, (float) size - 0.5F); + u -= 0.5F; + *icoord0 = util_ifloor(u); + *icoord1 = *icoord0 + 1; + if (*icoord1 > (int) size - 1) + *icoord1 = size - 1; + *w = frac(u); } @@ -543,13 +474,10 @@ wrap_linear_unorm_clamp_to_edge(const float s[4], unsigned size, * Do coordinate to array index conversion. For array textures. */ static INLINE void -wrap_array_layer(const float coord[4], unsigned size, int layer[4]) +wrap_array_layer(float coord, unsigned size, int *layer) { - uint ch; - for (ch = 0; ch < 4; ch++) { - int c = util_ifloor(coord[ch] + 0.5F); - layer[ch] = CLAMP(c, 0, size - 1); - } + int c = util_ifloor(coord + 0.5F); + *layer = CLAMP(c, 0, size - 1); } @@ -559,9 +487,9 @@ wrap_array_layer(const float coord[4], unsigned size, int layer[4]) */ static float compute_lambda_1d(const struct sp_sampler_variant *samp, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE]) + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE]) { const struct pipe_resource *texture = samp->view->texture; float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); @@ -574,9 +502,9 @@ compute_lambda_1d(const struct sp_sampler_variant *samp, static float compute_lambda_2d(const struct sp_sampler_variant *samp, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE]) + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE]) { const struct pipe_resource *texture = samp->view->texture; float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); @@ -593,9 +521,9 @@ compute_lambda_2d(const struct sp_sampler_variant *samp, static float compute_lambda_3d(const struct sp_sampler_variant *samp, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE]) + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE]) { const struct pipe_resource *texture = samp->view->texture; float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]); @@ -622,9 +550,9 @@ compute_lambda_3d(const struct sp_sampler_variant *samp, */ static float compute_lambda_vert(const struct sp_sampler_variant *samp, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE]) + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE]) { return 0.0f; } @@ -640,7 +568,7 @@ compute_lambda_vert(const struct sp_sampler_variant *samp, * \param rgba the quad to put the texel/color into * * XXX maybe move this into sp_tex_tile_cache.c and merge with the - * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1... + * sp_get_cached_tile_tex() function. */ @@ -672,13 +600,116 @@ get_texel_2d(const struct sp_sampler_variant *samp, if (x < 0 || x >= (int) u_minify(texture->width0, level) || y < 0 || y >= (int) u_minify(texture->height0, level)) { - return samp->sampler->border_color; + return samp->sampler->border_color.f; } else { return get_texel_2d_no_border( samp, addr, x, y ); } } +/* + * seamless cubemap neighbour array. + * this array is used to find the adjacent face in each of 4 directions, + * left, right, up, down. (or -x, +x, -y, +y). + */ +static const unsigned face_array[PIPE_TEX_FACE_MAX][4] = { + /* pos X first then neg X is Z different, Y the same */ + /* PIPE_TEX_FACE_POS_X,*/ + { PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z, + PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, + /* PIPE_TEX_FACE_NEG_X */ + { PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z, + PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, + + /* pos Y first then neg Y is X different, X the same */ + /* PIPE_TEX_FACE_POS_Y */ + { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z }, + + /* PIPE_TEX_FACE_NEG_Y */ + { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z }, + + /* pos Z first then neg Y is X different, X the same */ + /* PIPE_TEX_FACE_POS_Z */ + { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }, + + /* PIPE_TEX_FACE_NEG_Z */ + { PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X, + PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y } +}; + +static INLINE unsigned +get_next_face(unsigned face, int x, int y) +{ + int idx = 0; + + if (x == 0 && y == 0) + return face; + if (x == -1) + idx = 0; + else if (x == 1) + idx = 1; + else if (y == -1) + idx = 2; + else if (y == 1) + idx = 3; + + return face_array[face][idx]; +} + +static INLINE const float * +get_texel_cube_seamless(const struct sp_sampler_variant *samp, + union tex_tile_address addr, int x, int y, + float *corner) +{ + const struct pipe_resource *texture = samp->view->texture; + unsigned level = addr.bits.level; + unsigned face = addr.bits.face; + int new_x, new_y; + int max_x, max_y; + int c; + + max_x = (int) u_minify(texture->width0, level); + max_y = (int) u_minify(texture->height0, level); + new_x = x; + new_y = y; + + /* the corner case */ + if ((x < 0 || x >= max_x) && + (y < 0 || y >= max_y)) { + const float *c1, *c2, *c3; + int fx = x < 0 ? 0 : max_x - 1; + int fy = y < 0 ? 0 : max_y - 1; + c1 = get_texel_2d_no_border( samp, addr, fx, fy); + addr.bits.face = get_next_face(face, (x < 0) ? -1 : 1, 0); + c2 = get_texel_2d_no_border( samp, addr, (x < 0) ? max_x - 1 : 0, fy); + addr.bits.face = get_next_face(face, 0, (y < 0) ? -1 : 1); + c3 = get_texel_2d_no_border( samp, addr, fx, (y < 0) ? max_y - 1 : 0); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + corner[c] = CLAMP((c1[c] + c2[c] + c3[c]), 0.0F, 1.0F) / 3; + + return corner; + } + /* change the face */ + if (x < 0) { + new_x = max_x - 1; + face = get_next_face(face, -1, 0); + } else if (x >= max_x) { + new_x = 0; + face = get_next_face(face, 1, 0); + } else if (y < 0) { + new_y = max_y - 1; + face = get_next_face(face, 0, -1); + } else if (y >= max_y) { + new_y = 0; + face = get_next_face(face, 0, 1); + } + + addr.bits.face = face; + return get_texel_2d_no_border( samp, addr, new_x, new_y ); +} /* Gather a quad of adjacent texels within a tile: */ @@ -766,7 +797,7 @@ get_texel_3d(const struct sp_sampler_variant *samp, if (x < 0 || x >= (int) u_minify(texture->width0, level) || y < 0 || y >= (int) u_minify(texture->height0, level) || z < 0 || z >= (int) u_minify(texture->depth0, level)) { - return samp->sampler->border_color; + return samp->sampler->border_color.f; } else { return get_texel_3d_no_border( samp, addr, x, y, z ); @@ -783,7 +814,7 @@ get_texel_1d_array(const struct sp_sampler_variant *samp, unsigned level = addr.bits.level; if (x < 0 || x >= (int) u_minify(texture->width0, level)) { - return samp->sampler->border_color; + return samp->sampler->border_color.f; } else { return get_texel_2d_no_border(samp, addr, x, y); @@ -799,11 +830,12 @@ get_texel_2d_array(const struct sp_sampler_variant *samp, const struct pipe_resource *texture = samp->view->texture; unsigned level = addr.bits.level; - assert(layer < texture->array_size); + assert(layer < (int) texture->array_size); + assert(layer >= 0); if (x < 0 || x >= (int) u_minify(texture->width0, level) || y < 0 || y >= (int) u_minify(texture->height0, level)) { - return samp->sampler->border_color; + return samp->sampler->border_color.f; } else { return get_texel_3d_no_border(samp, addr, x, y, layer); @@ -811,6 +843,25 @@ get_texel_2d_array(const struct sp_sampler_variant *samp, } +/* Get texel pointer for cube array texture */ +static INLINE const float * +get_texel_cube_array(const struct sp_sampler_variant *samp, + union tex_tile_address addr, int x, int y, int layer) +{ + const struct pipe_resource *texture = samp->view->texture; + unsigned level = addr.bits.level; + + assert(layer < (int) texture->array_size); + assert(layer >= 0); + + if (x < 0 || x >= (int) u_minify(texture->width0, level) || + y < 0 || y >= (int) u_minify(texture->height0, level)) { + return samp->sampler->border_color.f; + } + else { + return get_texel_3d_no_border(samp, addr, x, y, layer); + } +} /** * Given the logbase2 of a mipmap's base level size and a mipmap level, * return the size (in texels) of that mipmap level. @@ -826,7 +877,16 @@ pot_level_size(unsigned base_pot, unsigned level) static void -print_sample(const char *function, float rgba[NUM_CHANNELS][QUAD_SIZE]) +print_sample(const char *function, const float *rgba) +{ + debug_printf("%s %g %g %g %g\n", + function, + rgba[0], rgba[TGSI_NUM_CHANNELS], rgba[2*TGSI_NUM_CHANNELS], rgba[3*TGSI_NUM_CHANNELS]); +} + + +static void +print_sample_4(const char *function, float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { debug_printf("%s %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n", function, @@ -836,64 +896,59 @@ print_sample(const char *function, float rgba[NUM_CHANNELS][QUAD_SIZE]) rgba[0][3], rgba[1][3], rgba[2][3], rgba[3][3]); } - /* Some image-filter fastpaths: */ static INLINE void img_filter_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); - unsigned j; - unsigned level = samp->level; unsigned xpot = pot_level_size(samp->xpot, level); unsigned ypot = pot_level_size(samp->ypot, level); unsigned xmax = (xpot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, xpot) - 1; */ unsigned ymax = (ypot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, ypot) - 1; */ union tex_tile_address addr; + int c; - addr.value = 0; - addr.bits.level = samp->level; - - for (j = 0; j < QUAD_SIZE; j++) { - int c; + float u = s * xpot - 0.5F; + float v = t * ypot - 0.5F; - float u = s[j] * xpot - 0.5F; - float v = t[j] * ypot - 0.5F; + int uflr = util_ifloor(u); + int vflr = util_ifloor(v); - int uflr = util_ifloor(u); - int vflr = util_ifloor(v); + float xw = u - (float)uflr; + float yw = v - (float)vflr; - float xw = u - (float)uflr; - float yw = v - (float)vflr; + int x0 = uflr & (xpot - 1); + int y0 = vflr & (ypot - 1); - int x0 = uflr & (xpot - 1); - int y0 = vflr & (ypot - 1); - - const float *tx[4]; + const float *tx[4]; - /* Can we fetch all four at once: - */ - if (x0 < xmax && y0 < ymax) { - get_texel_quad_2d_no_border_single_tile(samp, addr, x0, y0, tx); - } - else { - unsigned x1 = (x0 + 1) & (xpot - 1); - unsigned y1 = (y0 + 1) & (ypot - 1); - get_texel_quad_2d_no_border(samp, addr, x0, y0, x1, y1, tx); - } + addr.value = 0; + addr.bits.level = level; - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(xw, yw, - tx[0][c], tx[1][c], - tx[2][c], tx[3][c]); - } + /* Can we fetch all four at once: + */ + if (x0 < xmax && y0 < ymax) { + get_texel_quad_2d_no_border_single_tile(samp, addr, x0, y0, tx); + } + else { + unsigned x1 = (x0 + 1) & (xpot - 1); + unsigned y1 = (y0 + 1) & (ypot - 1); + get_texel_quad_2d_no_border(samp, addr, x0, y0, x1, y1, tx); + } + + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) { + rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, + tx[0][c], tx[1][c], + tx[2][c], tx[3][c]); } if (DEBUG_TEX) { @@ -904,41 +959,36 @@ img_filter_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler, static INLINE void img_filter_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_QUAD_SIZE]) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); - unsigned j; - unsigned level = samp->level; unsigned xpot = pot_level_size(samp->xpot, level); unsigned ypot = pot_level_size(samp->ypot, level); + const float *out; union tex_tile_address addr; + int c; - addr.value = 0; - addr.bits.level = samp->level; - - for (j = 0; j < QUAD_SIZE; j++) { - int c; + float u = s * xpot; + float v = t * ypot; - float u = s[j] * xpot; - float v = t[j] * ypot; + int uflr = util_ifloor(u); + int vflr = util_ifloor(v); - int uflr = util_ifloor(u); - int vflr = util_ifloor(v); + int x0 = uflr & (xpot - 1); + int y0 = vflr & (ypot - 1); - int x0 = uflr & (xpot - 1); - int y0 = vflr & (ypot - 1); + addr.value = 0; + addr.bits.level = level; - const float *out = get_texel_2d_no_border(samp, addr, x0, y0); - - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_2d_no_border(samp, addr, x0, y0); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -948,50 +998,44 @@ img_filter_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler, static INLINE void img_filter_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_QUAD_SIZE]) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); - unsigned j; - unsigned level = samp->level; unsigned xpot = pot_level_size(samp->xpot, level); unsigned ypot = pot_level_size(samp->ypot, level); union tex_tile_address addr; + int c; - addr.value = 0; - addr.bits.level = samp->level; - - for (j = 0; j < QUAD_SIZE; j++) { - int c; - - float u = s[j] * xpot; - float v = t[j] * ypot; - - int x0, y0; - const float *out; + float u = s * xpot; + float v = t * ypot; - x0 = util_ifloor(u); - if (x0 < 0) - x0 = 0; - else if (x0 > xpot - 1) - x0 = xpot - 1; + int x0, y0; + const float *out; - y0 = util_ifloor(v); - if (y0 < 0) - y0 = 0; - else if (y0 > ypot - 1) - y0 = ypot - 1; - - out = get_texel_2d_no_border(samp, addr, x0, y0); - - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + addr.value = 0; + addr.bits.level = level; + + x0 = util_ifloor(u); + if (x0 < 0) + x0 = 0; + else if (x0 > xpot - 1) + x0 = xpot - 1; + + y0 = util_ifloor(v); + if (y0 < 0) + y0 = 0; + else if (y0 > ypot - 1) + y0 = ypot - 1; + + out = get_texel_2d_no_border(samp, addr, x0, y0); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -1001,37 +1045,34 @@ img_filter_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler, static void img_filter_1d_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], - enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float s, + float t, + float p, + unsigned level, + unsigned face_id, + enum tgsi_sampler_control control, + float rgba[TGSI_QUAD_SIZE]) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width; - int x[4]; + int x; union tex_tile_address addr; + const float *out; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); + width = u_minify(texture->width0, level); assert(width > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->nearest_texcoord_s(s, width, x); + samp->nearest_texcoord_s(s, width, &x); - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_2d(samp, addr, x[j], 0); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_2d(samp, addr, x, 0); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -1041,38 +1082,35 @@ img_filter_1d_nearest(struct tgsi_sampler *tgsi_sampler, static void img_filter_1d_array_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width; - int x[4], layer[4]; + int x, layer; union tex_tile_address addr; + const float *out; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); + width = u_minify(texture->width0, level); assert(width > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->nearest_texcoord_s(s, width, x); - wrap_array_layer(t, texture->array_size, layer); + samp->nearest_texcoord_s(s, width, &x); + wrap_array_layer(t, texture->array_size, &layer); - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_1d_array(samp, addr, x[j], layer[j]); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_1d_array(samp, addr, x, layer); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -1082,41 +1120,37 @@ img_filter_1d_array_nearest(struct tgsi_sampler *tgsi_sampler, static void img_filter_2d_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height; - int x[4], y[4]; + int x, y; union tex_tile_address addr; + const float *out; + int c; - - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->nearest_texcoord_s(s, width, x); - samp->nearest_texcoord_t(t, height, y); + samp->nearest_texcoord_s(s, width, &x); + samp->nearest_texcoord_t(t, height, &y); - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_2d(samp, addr, x[j], y[j]); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_2d(samp, addr, x, y); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -1126,41 +1160,38 @@ img_filter_2d_nearest(struct tgsi_sampler *tgsi_sampler, static void img_filter_2d_array_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height; - int x[4], y[4], layer[4]; + int x, y, layer; union tex_tile_address addr; + const float *out; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->nearest_texcoord_s(s, width, x); - samp->nearest_texcoord_t(t, height, y); - wrap_array_layer(p, texture->array_size, layer); + samp->nearest_texcoord_s(s, width, &x); + samp->nearest_texcoord_t(t, height, &y); + wrap_array_layer(p, texture->array_size, &layer); - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_2d_array(samp, addr, x[j], y[j], layer[j]); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_2d_array(samp, addr, x, y, layer); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); @@ -1178,370 +1209,453 @@ face(union tex_tile_address addr, unsigned face ) static void img_filter_cube_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - const unsigned *faces = samp->faces; /* zero when not cube-mapping */ - unsigned level0, j; int width, height; - int x[4], y[4]; + int x, y; union tex_tile_address addr; + const float *out; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; - - samp->nearest_texcoord_s(s, width, x); - samp->nearest_texcoord_t(t, height, y); + addr.bits.level = level; - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_2d(samp, face(addr, faces[j]), x[j], y[j]); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } + /* + * If NEAREST filtering is done within a miplevel, always apply wrap + * mode CLAMP_TO_EDGE. + */ + if (samp->sampler->seamless_cube_map) { + wrap_nearest_clamp_to_edge(s, width, &x); + wrap_nearest_clamp_to_edge(t, height, &y); + } else { + samp->nearest_texcoord_s(s, width, &x); + samp->nearest_texcoord_t(t, height, &y); } + out = get_texel_2d(samp, face(addr, face_id), x, y); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; + if (DEBUG_TEX) { print_sample(__FUNCTION__, rgba); } } +static void +img_filter_cube_array_nearest(struct tgsi_sampler *tgsi_sampler, + float s, + float t, + float p, + unsigned level, + unsigned face_id, + enum tgsi_sampler_control control, + float *rgba) +{ + const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + const struct pipe_resource *texture = samp->view->texture; + int width, height; + int x, y, layer; + union tex_tile_address addr; + const float *out; + int c; + + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = level; + + samp->nearest_texcoord_s(s, width, &x); + samp->nearest_texcoord_t(t, height, &y); + wrap_array_layer(p, texture->array_size, &layer); + + out = get_texel_cube_array(samp, addr, x, y, layer * 6 + face_id); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; + + if (DEBUG_TEX) { + print_sample(__FUNCTION__, rgba); + } +} static void img_filter_3d_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height, depth; - int x[4], y[4], z[4]; + int x, y, z; union tex_tile_address addr; + const float *out; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); - depth = u_minify(texture->depth0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); + depth = u_minify(texture->depth0, level); assert(width > 0); assert(height > 0); assert(depth > 0); - samp->nearest_texcoord_s(s, width, x); - samp->nearest_texcoord_t(t, height, y); - samp->nearest_texcoord_p(p, depth, z); + samp->nearest_texcoord_s(s, width, &x); + samp->nearest_texcoord_t(t, height, &y); + samp->nearest_texcoord_p(p, depth, &z); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - for (j = 0; j < QUAD_SIZE; j++) { - const float *out = get_texel_3d(samp, addr, x[j], y[j], z[j]); - int c; - for (c = 0; c < 4; c++) { - rgba[c][j] = out[c]; - } - } + out = get_texel_3d(samp, addr, x, y, z); + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = out[c]; } static void img_filter_1d_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width; - int x0[4], x1[4]; - float xw[4]; /* weights */ + int x0, x1; + float xw; /* weights */ union tex_tile_address addr; + const float *tx0, *tx1; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); + width = u_minify(texture->width0, level); assert(width > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->linear_texcoord_s(s, width, x0, x1, xw); + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); - for (j = 0; j < QUAD_SIZE; j++) { - const float *tx0 = get_texel_2d(samp, addr, x0[j], 0); - const float *tx1 = get_texel_2d(samp, addr, x1[j], 0); - int c; + tx0 = get_texel_2d(samp, addr, x0, 0); + tx1 = get_texel_2d(samp, addr, x1, 0); - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp(xw[j], tx0[c], tx1[c]); - } - } + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); } static void img_filter_1d_array_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width; - int x0[4], x1[4], layer[4]; - float xw[4]; /* weights */ + int x0, x1, layer; + float xw; /* weights */ union tex_tile_address addr; + const float *tx0, *tx1; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); + width = u_minify(texture->width0, level); assert(width > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->linear_texcoord_s(s, width, x0, x1, xw); - wrap_array_layer(t, texture->array_size, layer); + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + wrap_array_layer(t, texture->array_size, &layer); - for (j = 0; j < QUAD_SIZE; j++) { - const float *tx0 = get_texel_1d_array(samp, addr, x0[j], layer[j]); - const float *tx1 = get_texel_1d_array(samp, addr, x1[j], layer[j]); - int c; + tx0 = get_texel_1d_array(samp, addr, x0, layer); + tx1 = get_texel_1d_array(samp, addr, x1, layer); - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp(xw[j], tx0[c], tx1[c]); - } - } + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]); } static void img_filter_2d_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height; - int x0[4], y0[4], x1[4], y1[4]; - float xw[4], yw[4]; /* weights */ + int x0, y0, x1, y1; + float xw, yw; /* weights */ union tex_tile_address addr; + const float *tx0, *tx1, *tx2, *tx3; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->linear_texcoord_s(s, width, x0, x1, xw); - samp->linear_texcoord_t(t, height, y0, y1, yw); + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + samp->linear_texcoord_t(t, height, &y0, &y1, &yw); - for (j = 0; j < QUAD_SIZE; j++) { - const float *tx0 = get_texel_2d(samp, addr, x0[j], y0[j]); - const float *tx1 = get_texel_2d(samp, addr, x1[j], y0[j]); - const float *tx2 = get_texel_2d(samp, addr, x0[j], y1[j]); - const float *tx3 = get_texel_2d(samp, addr, x1[j], y1[j]); - int c; + tx0 = get_texel_2d(samp, addr, x0, y0); + tx1 = get_texel_2d(samp, addr, x1, y0); + tx2 = get_texel_2d(samp, addr, x0, y1); + tx3 = get_texel_2d(samp, addr, x1, y1); - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(xw[j], yw[j], - tx0[c], tx1[c], - tx2[c], tx3[c]); - } - } + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, + tx0[c], tx1[c], + tx2[c], tx3[c]); } static void img_filter_2d_array_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height; - int x0[4], y0[4], x1[4], y1[4], layer[4]; - float xw[4], yw[4]; /* weights */ + int x0, y0, x1, y1, layer; + float xw, yw; /* weights */ union tex_tile_address addr; + const float *tx0, *tx1, *tx2, *tx3; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->linear_texcoord_s(s, width, x0, x1, xw); - samp->linear_texcoord_t(t, height, y0, y1, yw); - wrap_array_layer(p, texture->array_size, layer); + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + samp->linear_texcoord_t(t, height, &y0, &y1, &yw); + wrap_array_layer(p, texture->array_size, &layer); - for (j = 0; j < QUAD_SIZE; j++) { - const float *tx0 = get_texel_2d_array(samp, addr, x0[j], y0[j], layer[j]); - const float *tx1 = get_texel_2d_array(samp, addr, x1[j], y0[j], layer[j]); - const float *tx2 = get_texel_2d_array(samp, addr, x0[j], y1[j], layer[j]); - const float *tx3 = get_texel_2d_array(samp, addr, x1[j], y1[j], layer[j]); - int c; + tx0 = get_texel_2d_array(samp, addr, x0, y0, layer); + tx1 = get_texel_2d_array(samp, addr, x1, y0, layer); + tx2 = get_texel_2d_array(samp, addr, x0, y1, layer); + tx3 = get_texel_2d_array(samp, addr, x1, y1, layer); - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(xw[j], yw[j], - tx0[c], tx1[c], - tx2[c], tx3[c]); - } - } + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, + tx0[c], tx1[c], + tx2[c], tx3[c]); } static void img_filter_cube_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - const unsigned *faces = samp->faces; /* zero when not cube-mapping */ - unsigned level0, j; int width, height; - int x0[4], y0[4], x1[4], y1[4]; - float xw[4], yw[4]; /* weights */ - union tex_tile_address addr; + int x0, y0, x1, y1; + float xw, yw; /* weights */ + union tex_tile_address addr, addrj; + const float *tx0, *tx1, *tx2, *tx3; + float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE], corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE]; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); assert(width > 0); assert(height > 0); addr.value = 0; - addr.bits.level = samp->level; + addr.bits.level = level; - samp->linear_texcoord_s(s, width, x0, x1, xw); - samp->linear_texcoord_t(t, height, y0, y1, yw); + /* + * For seamless if LINEAR filtering is done within a miplevel, + * always apply wrap mode CLAMP_TO_BORDER. + */ + if (samp->sampler->seamless_cube_map) { + wrap_linear_clamp_to_border(s, width, &x0, &x1, &xw); + wrap_linear_clamp_to_border(t, height, &y0, &y1, &yw); + } else { + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + samp->linear_texcoord_t(t, height, &y0, &y1, &yw); + } - for (j = 0; j < QUAD_SIZE; j++) { - union tex_tile_address addrj = face(addr, faces[j]); - const float *tx0 = get_texel_2d(samp, addrj, x0[j], y0[j]); - const float *tx1 = get_texel_2d(samp, addrj, x1[j], y0[j]); - const float *tx2 = get_texel_2d(samp, addrj, x0[j], y1[j]); - const float *tx3 = get_texel_2d(samp, addrj, x1[j], y1[j]); - int c; + addrj = face(addr, face_id); - /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(xw[j], yw[j], - tx0[c], tx1[c], - tx2[c], tx3[c]); - } + if (samp->sampler->seamless_cube_map) { + tx0 = get_texel_cube_seamless(samp, addrj, x0, y0, corner0); + tx1 = get_texel_cube_seamless(samp, addrj, x1, y0, corner1); + tx2 = get_texel_cube_seamless(samp, addrj, x0, y1, corner2); + tx3 = get_texel_cube_seamless(samp, addrj, x1, y1, corner3); + } else { + tx0 = get_texel_2d(samp, addrj, x0, y0); + tx1 = get_texel_2d(samp, addrj, x1, y0); + tx2 = get_texel_2d(samp, addrj, x0, y1); + tx3 = get_texel_2d(samp, addrj, x1, y1); } + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, + tx0[c], tx1[c], + tx2[c], tx3[c]); } +static void +img_filter_cube_array_linear(struct tgsi_sampler *tgsi_sampler, + float s, + float t, + float p, + unsigned level, + unsigned face_id, + enum tgsi_sampler_control control, + float *rgba) +{ + const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + const struct pipe_resource *texture = samp->view->texture; + int width, height; + int x0, y0, x1, y1, layer; + float xw, yw; /* weights */ + union tex_tile_address addr; + const float *tx0, *tx1, *tx2, *tx3; + int c; + + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); + + assert(width > 0); + assert(height > 0); + + addr.value = 0; + addr.bits.level = level; + + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + samp->linear_texcoord_t(t, height, &y0, &y1, &yw); + wrap_array_layer(p, texture->array_size, &layer); + + tx0 = get_texel_cube_array(samp, addr, x0, y0, layer * 6 + face_id); + tx1 = get_texel_cube_array(samp, addr, x1, y0, layer * 6 + face_id); + tx2 = get_texel_cube_array(samp, addr, x0, y1, layer * 6 + face_id); + tx3 = get_texel_cube_array(samp, addr, x1, y1, layer * 6 + face_id); + + /* interpolate R, G, B, A */ + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw, + tx0[c], tx1[c], + tx2[c], tx3[c]); +} + static void img_filter_3d_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + float s, + float t, + float p, + unsigned level, + unsigned face_id, enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float *rgba) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0, j; int width, height, depth; - int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4]; - float xw[4], yw[4], zw[4]; /* interpolation weights */ + int x0, x1, y0, y1, z0, z1; + float xw, yw, zw; /* interpolation weights */ union tex_tile_address addr; + const float *tx00, *tx01, *tx02, *tx03, *tx10, *tx11, *tx12, *tx13; + int c; - level0 = samp->level; - width = u_minify(texture->width0, level0); - height = u_minify(texture->height0, level0); - depth = u_minify(texture->depth0, level0); + width = u_minify(texture->width0, level); + height = u_minify(texture->height0, level); + depth = u_minify(texture->depth0, level); addr.value = 0; - addr.bits.level = level0; + addr.bits.level = level; assert(width > 0); assert(height > 0); assert(depth > 0); - samp->linear_texcoord_s(s, width, x0, x1, xw); - samp->linear_texcoord_t(t, height, y0, y1, yw); - samp->linear_texcoord_p(p, depth, z0, z1, zw); + samp->linear_texcoord_s(s, width, &x0, &x1, &xw); + samp->linear_texcoord_t(t, height, &y0, &y1, &yw); + samp->linear_texcoord_p(p, depth, &z0, &z1, &zw); - for (j = 0; j < QUAD_SIZE; j++) { - int c; - const float *tx00 = get_texel_3d(samp, addr, x0[j], y0[j], z0[j]); - const float *tx01 = get_texel_3d(samp, addr, x1[j], y0[j], z0[j]); - const float *tx02 = get_texel_3d(samp, addr, x0[j], y1[j], z0[j]); - const float *tx03 = get_texel_3d(samp, addr, x1[j], y1[j], z0[j]); + tx00 = get_texel_3d(samp, addr, x0, y0, z0); + tx01 = get_texel_3d(samp, addr, x1, y0, z0); + tx02 = get_texel_3d(samp, addr, x0, y1, z0); + tx03 = get_texel_3d(samp, addr, x1, y1, z0); - const float *tx10 = get_texel_3d(samp, addr, x0[j], y0[j], z1[j]); - const float *tx11 = get_texel_3d(samp, addr, x1[j], y0[j], z1[j]); - const float *tx12 = get_texel_3d(samp, addr, x0[j], y1[j], z1[j]); - const float *tx13 = get_texel_3d(samp, addr, x1[j], y1[j], z1[j]); + tx10 = get_texel_3d(samp, addr, x0, y0, z1); + tx11 = get_texel_3d(samp, addr, x1, y0, z1); + tx12 = get_texel_3d(samp, addr, x0, y1, z1); + tx13 = get_texel_3d(samp, addr, x1, y1, z1); /* interpolate R, G, B, A */ - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j], - tx00[c], tx01[c], - tx02[c], tx03[c], - tx10[c], tx11[c], - tx12[c], tx13[c]); - } - } + for (c = 0; c < TGSI_QUAD_SIZE; c++) + rgba[TGSI_NUM_CHANNELS*c] = lerp_3d(xw, yw, zw, + tx00[c], tx01[c], + tx02[c], tx03[c], + tx10[c], tx11[c], + tx12[c], tx13[c]); } @@ -1551,12 +1665,12 @@ img_filter_3d_linear(struct tgsi_sampler *tgsi_sampler, static INLINE void compute_lod(const struct pipe_sampler_state *sampler, const float biased_lambda, - const float lodbias[QUAD_SIZE], - float lod[QUAD_SIZE]) + const float lodbias[TGSI_QUAD_SIZE], + float lod[TGSI_QUAD_SIZE]) { uint i; - for (i = 0; i < QUAD_SIZE; i++) { + for (i = 0; i < TGSI_QUAD_SIZE; i++) { lod[i] = biased_lambda + lodbias[i]; lod[i] = CLAMP(lod[i], sampler->min_lod, sampler->max_lod); } @@ -1565,62 +1679,60 @@ compute_lod(const struct pipe_sampler_state *sampler, static void mip_filter_linear(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - int level0; - float lambda; - float lod[QUAD_SIZE]; + int j; + float lod[TGSI_QUAD_SIZE]; if (control == tgsi_sampler_lod_bias) { - lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; - compute_lod(samp->sampler, lambda, c0, lod); + float lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + compute_lod(samp->sampler, lambda, c1, lod); + else + compute_lod(samp->sampler, lambda, c0, lod); } else { assert(control == tgsi_sampler_lod_explicit); - memcpy(lod, c0, sizeof(lod)); + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + memcpy(lod, c1, sizeof(lod)); + else + memcpy(lod, c0, sizeof(lod)); + } - /* XXX: Take into account all lod values. - */ - lambda = lod[0]; - level0 = samp->view->u.tex.first_level + (int)lambda; + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int level0 = samp->view->u.tex.first_level + (int)lod[j]; - if (lambda < 0.0) { - samp->level = samp->view->u.tex.first_level; - samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); - } - else if (level0 >= texture->last_level) { - samp->level = texture->last_level; - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); - } - else { - float levelBlend = frac(lambda); - float rgba0[4][4]; - float rgba1[4][4]; - int c,j; + if (lod[j] < 0.0) + samp->mag_img_filter(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); - samp->level = level0; - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba0); + else if (level0 >= texture->last_level) + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], texture->last_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); - samp->level = level0+1; - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba1); + else { + float levelBlend = frac(lod[j]); + float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; + int c; + + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], level0, samp->faces[j], tgsi_sampler_lod_bias, &rgbax[0][0]); + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], level0+1, samp->faces[j], tgsi_sampler_lod_bias, &rgbax[0][1]); - for (j = 0; j < QUAD_SIZE; j++) { for (c = 0; c < 4; c++) { - rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]); + rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); } } } if (DEBUG_TEX) { - print_sample(__FUNCTION__, rgba); + print_sample_4(__FUNCTION__, rgba); } } @@ -1632,83 +1744,108 @@ mip_filter_linear(struct tgsi_sampler *tgsi_sampler, */ static void mip_filter_nearest(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - float lambda; - float lod[QUAD_SIZE]; + float lod[TGSI_QUAD_SIZE]; + int j; if (control == tgsi_sampler_lod_bias) { - lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; - compute_lod(samp->sampler, lambda, c0, lod); + float lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + compute_lod(samp->sampler, lambda, c1, lod); + else + compute_lod(samp->sampler, lambda, c0, lod); } else { assert(control == tgsi_sampler_lod_explicit); - memcpy(lod, c0, sizeof(lod)); + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + memcpy(lod, c1, sizeof(lod)); + else + memcpy(lod, c0, sizeof(lod)); } - /* XXX: Take into account all lod values. - */ - lambda = lod[0]; - - if (lambda < 0.0) { - samp->level = samp->view->u.tex.first_level; - samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); - } - else { - samp->level = samp->view->u.tex.first_level + (int)(lambda + 0.5F) ; - samp->level = MIN2(samp->level, (int)texture->last_level); - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + if (lod[j] < 0.0) + samp->mag_img_filter(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); + else { + float level = samp->view->u.tex.first_level + (int)(lod[j] + 0.5F) ; + level = MIN2(level, (int)texture->last_level); + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); + } } if (DEBUG_TEX) { - print_sample(__FUNCTION__, rgba); + print_sample_4(__FUNCTION__, rgba); } } static void mip_filter_none(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); - float lambda; - float lod[QUAD_SIZE]; + float lod[TGSI_QUAD_SIZE]; + int j; if (control == tgsi_sampler_lod_bias) { - lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; - compute_lod(samp->sampler, lambda, c0, lod); + float lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + compute_lod(samp->sampler, lambda, c1, lod); + else + compute_lod(samp->sampler, lambda, c0, lod); } else { assert(control == tgsi_sampler_lod_explicit); - memcpy(lod, c0, sizeof(lod)); + if (samp->key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) + memcpy(lod, c1, sizeof(lod)); + else + memcpy(lod, c0, sizeof(lod)); } - /* XXX: Take into account all lod values. - */ - lambda = lod[0]; - - samp->level = samp->view->u.tex.first_level; - if (lambda < 0.0) { - samp->mag_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); - } - else { - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + if (lod[j] < 0.0) { + samp->mag_img_filter(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); + } + else { + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); + } } } +static void +mip_filter_none_no_filter_select(struct tgsi_sampler *tgsi_sampler, + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) +{ + struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + int j; + + for (j = 0; j < TGSI_QUAD_SIZE; j++) + samp->mag_img_filter(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); +} + + /* For anisotropic filtering */ #define WEIGHT_LUT_SIZE 1024 @@ -1722,7 +1859,7 @@ create_filter_table(void) { unsigned i; if (!weightLut) { - weightLut = (float *) malloc(WEIGHT_LUT_SIZE * sizeof(float)); + weightLut = (float *) MALLOC(WEIGHT_LUT_SIZE * sizeof(float)); for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { float alpha = 2; @@ -1737,25 +1874,26 @@ create_filter_table(void) /** * Elliptical weighted average (EWA) filter for producing high quality * anisotropic filtered results. - * Based on the Higher Quality Elliptical Weighted Avarage Filter + * Based on the Higher Quality Elliptical Weighted Average Filter * published by Paul S. Heckbert in his Master's Thesis * "Fundamentals of Texture Mapping and Image Warping" (1989) */ static void img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + unsigned level, enum tgsi_sampler_control control, const float dudx, const float dvdx, const float dudy, const float dvdy, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - unsigned level0 = samp->level > 0 ? samp->level : 0; + // ??? Won't the image filters blow up if level is negative? + unsigned level0 = level > 0 ? level : 0; float scaling = 1.0 / (1 << level0); int width = u_minify(texture->width0, level0); int height = u_minify(texture->height0, level0); @@ -1781,15 +1919,15 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, float box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with */ float box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */ - float rgba_temp[NUM_CHANNELS][QUAD_SIZE]; - float s_buffer[QUAD_SIZE]; - float t_buffer[QUAD_SIZE]; - float weight_buffer[QUAD_SIZE]; + float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; + float s_buffer[TGSI_QUAD_SIZE]; + float t_buffer[TGSI_QUAD_SIZE]; + float weight_buffer[TGSI_QUAD_SIZE]; unsigned buffer_next; int j; - float den;// = 0.0F; + float den; /* = 0.0F; */ float ddq; - float U;// = u0 - tex_u; + float U; /* = u0 - tex_u; */ int v; /* Scale ellipse formula to directly index the Filter Lookup Table. @@ -1805,12 +1943,12 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, * also the same. Note that texel/image access can only be performed using * a quad, i.e. it is not possible to get the pixel value for a single * tex coord. In order to have a better performance, the access is buffered - * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is full, - * then the pixel values are read from the image. + * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is + * full, then the pixel values are read from the image. */ ddq = 2 * A; - for (j = 0; j < QUAD_SIZE; j++) { + for (j = 0; j < TGSI_QUAD_SIZE; j++) { /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse * and incrementally update the value of Ax^2+Bxy*Cy^2; when this * value, q, is less than F, we're inside the ellipse @@ -1834,7 +1972,9 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, int u; for (u = u0; u <= u1; ++u) { - /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */ + /* Note that the ellipse has been pre-scaled so F = + * WEIGHT_LUT_SIZE - 1 + */ if (q < WEIGHT_LUT_SIZE) { /* as a LUT is used, q must never be negative; * should not happen, though @@ -1847,16 +1987,16 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, t_buffer[buffer_next] = v / ((float) height); buffer_next++; - if (buffer_next == QUAD_SIZE) { + if (buffer_next == TGSI_QUAD_SIZE) { /* 4 texel coords are in the buffer -> read it now */ unsigned jj; /* it is assumed that samp->min_img_filter is set to * img_filter_2d_nearest or one of the * accelerated img_filter_2d_nearest_XXX functions. */ - samp->min_img_filter(tgsi_sampler, s_buffer, t_buffer, p, NULL, - tgsi_sampler_lod_bias, rgba_temp); for (jj = 0; jj < buffer_next; jj++) { + samp->min_img_filter(tgsi_sampler, s_buffer[jj], t_buffer[jj], p[jj], level, samp->faces[j], + tgsi_sampler_lod_bias, &rgba_temp[0][jj]); num[0] += weight_buffer[jj] * rgba_temp[0][jj]; num[1] += weight_buffer[jj] * rgba_temp[1][jj]; num[2] += weight_buffer[jj] * rgba_temp[2][jj]; @@ -1873,10 +2013,8 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, } } - /* if the tex coord buffer contains unread values, we will read them now. - * Note that in most cases we have to read more pixel values than required, - * however, as the img_filter_2d_nearest function(s) does not have a count - * parameter, we need to read the whole quad and ignore the unused values + /* if the tex coord buffer contains unread values, we will read + * them now. */ if (buffer_next > 0) { unsigned jj; @@ -1884,9 +2022,9 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, * img_filter_2d_nearest or one of the * accelerated img_filter_2d_nearest_XXX functions. */ - samp->min_img_filter(tgsi_sampler, s_buffer, t_buffer, p, NULL, - tgsi_sampler_lod_bias, rgba_temp); for (jj = 0; jj < buffer_next; jj++) { + samp->min_img_filter(tgsi_sampler, s_buffer[jj], t_buffer[jj], p[jj], level, samp->faces[j], + tgsi_sampler_lod_bias, &rgba_temp[0][jj]); num[0] += weight_buffer[jj] * rgba_temp[0][jj]; num[1] += weight_buffer[jj] * rgba_temp[1][jj]; num[2] += weight_buffer[jj] * rgba_temp[2][jj]; @@ -1895,11 +2033,9 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, } if (den <= 0.0F) { - /* Reaching this place would mean - * that no pixels intersected the ellipse. - * This should never happen because - * the filter we use always - * intersects at least one pixel. + /* Reaching this place would mean that no pixels intersected + * the ellipse. This should never happen because the filter + * we use always intersects at least one pixel. */ /*rgba[0]=0; @@ -1907,7 +2043,8 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, rgba[2]=0; rgba[3]=0;*/ /* not enough pixels in resampling, resort to direct interpolation */ - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba_temp); + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], level, samp->faces[j], + tgsi_sampler_lod_bias, &rgba_temp[0][j]); den = 1; num[0] = rgba_temp[0][j]; num[1] = rgba_temp[1][j]; @@ -1928,18 +2065,19 @@ img_filter_2d_ewa(struct tgsi_sampler *tgsi_sampler, */ static void mip_filter_linear_aniso(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; int level0; float lambda; - float lod[QUAD_SIZE]; + float lod[TGSI_QUAD_SIZE]; float s_to_u = u_minify(texture->width0, samp->view->u.tex.first_level); float t_to_v = u_minify(texture->height0, samp->view->u.tex.first_level); @@ -2002,25 +2140,24 @@ mip_filter_linear_aniso(struct tgsi_sampler *tgsi_sampler, * simply return the average of the whole image. */ if (level0 >= (int) texture->last_level) { - samp->level = texture->last_level; - samp->min_img_filter(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); + int j; + for (j = 0; j < TGSI_QUAD_SIZE; j++) + samp->min_img_filter(tgsi_sampler, s[j], t[j], p[j], texture->last_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); } else { /* don't bother interpolating between multiple LODs; it doesn't * seem to be worth the extra running time. */ - samp->level = level0; - img_filter_2d_ewa(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, + img_filter_2d_ewa(tgsi_sampler, s, t, p, level0, tgsi_sampler_lod_bias, dudx, dvdx, dudy, dvdy, rgba); } if (DEBUG_TEX) { - print_sample(__FUNCTION__, rgba); + print_sample_4(__FUNCTION__, rgba); } } - /** * Specialized version of mip_filter_linear with hard-wired calls to * 2d lambda calculation and 2d_linear_repeat_POT img filters. @@ -2028,18 +2165,19 @@ mip_filter_linear_aniso(struct tgsi_sampler *tgsi_sampler, static void mip_filter_linear_2d_linear_repeat_POT( struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_resource *texture = samp->view->texture; - int level0; + int j; float lambda; - float lod[QUAD_SIZE]; + float lod[TGSI_QUAD_SIZE]; if (control == tgsi_sampler_lod_bias) { lambda = samp->compute_lambda(samp, s, t, p) + samp->sampler->lod_bias; @@ -2050,58 +2188,49 @@ mip_filter_linear_2d_linear_repeat_POT( memcpy(lod, c0, sizeof(lod)); } - /* XXX: Take into account all lod values. - */ - lambda = lod[0]; - level0 = samp->view->u.tex.first_level + (int)lambda; - - /* Catches both negative and large values of level0: - */ - if ((unsigned)level0 >= texture->last_level) { - if (level0 < 0) - samp->level = samp->view->u.tex.first_level; - else - samp->level = texture->last_level; + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int level0 = samp->view->u.tex.first_level + (int)lod[j]; - img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba); - } - else { - float levelBlend = frac(lambda); - float rgba0[4][4]; - float rgba1[4][4]; - int c,j; + /* Catches both negative and large values of level0: + */ + if ((unsigned)level0 >= texture->last_level) { + if (level0 < 0) + img_filter_2d_linear_repeat_POT(tgsi_sampler, s[j], t[j], p[j], samp->view->u.tex.first_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); + else + img_filter_2d_linear_repeat_POT(tgsi_sampler, s[j], t[j], p[j], samp->view->texture->last_level, samp->faces[j], tgsi_sampler_lod_bias, &rgba[0][j]); - samp->level = level0; - img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba0); + } + else { + float levelBlend = frac(lod[j]); + float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; + int c; - samp->level = level0+1; - img_filter_2d_linear_repeat_POT(tgsi_sampler, s, t, p, NULL, tgsi_sampler_lod_bias, rgba1); + img_filter_2d_linear_repeat_POT(tgsi_sampler, s[j], t[j], p[j], level0, samp->faces[j], tgsi_sampler_lod_bias, &rgbax[0][0]); + img_filter_2d_linear_repeat_POT(tgsi_sampler, s[j], t[j], p[j], level0+1, samp->faces[j], tgsi_sampler_lod_bias, &rgbax[0][1]); - for (j = 0; j < QUAD_SIZE; j++) { - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]); - } + for (c = 0; c < TGSI_NUM_CHANNELS; c++) + rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]); } } if (DEBUG_TEX) { - print_sample(__FUNCTION__, rgba); + print_sample_4(__FUNCTION__, rgba); } } - /** * Do shadow/depth comparisons. */ static void sample_compare(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); const struct pipe_sampler_state *sampler = samp->sampler; @@ -2109,19 +2238,32 @@ sample_compare(struct tgsi_sampler *tgsi_sampler, float val; float pc0, pc1, pc2, pc3; - samp->mip_filter(tgsi_sampler, s, t, p, c0, control, rgba); + samp->mip_filter(tgsi_sampler, s, t, p, c0, c1, control, rgba); /** * Compare texcoord 'p' (aka R) against texture value 'rgba[0]' + * for 2D Array texture we need to use the 'c0' (aka Q). * When we sampled the depth texture, the depth value was put into all * RGBA channels. We look at the red channel here. */ - pc0 = CLAMP(p[0], 0.0F, 1.0F); - pc1 = CLAMP(p[1], 0.0F, 1.0F); - pc2 = CLAMP(p[2], 0.0F, 1.0F); - pc3 = CLAMP(p[3], 0.0F, 1.0F); - + if (samp->view->texture->target == PIPE_TEXTURE_2D_ARRAY || + samp->view->texture->target == PIPE_TEXTURE_CUBE) { + pc0 = CLAMP(c0[0], 0.0F, 1.0F); + pc1 = CLAMP(c0[1], 0.0F, 1.0F); + pc2 = CLAMP(c0[2], 0.0F, 1.0F); + pc3 = CLAMP(c0[3], 0.0F, 1.0F); + } else if (samp->view->texture->target == PIPE_TEXTURE_CUBE_ARRAY) { + pc0 = CLAMP(c1[0], 0.0F, 1.0F); + pc1 = CLAMP(c1[1], 0.0F, 1.0F); + pc2 = CLAMP(c1[2], 0.0F, 1.0F); + pc3 = CLAMP(c1[3], 0.0F, 1.0F); + } else { + pc0 = CLAMP(p[0], 0.0F, 1.0F); + pc1 = CLAMP(p[1], 0.0F, 1.0F); + pc2 = CLAMP(p[2], 0.0F, 1.0F); + pc3 = CLAMP(p[3], 0.0F, 1.0F); + } /* compare four texcoords vs. four texture samples */ switch (sampler->compare_func) { case PIPE_FUNC_LESS: @@ -2172,13 +2314,22 @@ sample_compare(struct tgsi_sampler *tgsi_sampler, break; } - /* convert four pass/fail values to an intensity in [0,1] */ - val = 0.25F * (k0 + k1 + k2 + k3); + if (sampler->mag_img_filter == PIPE_TEX_FILTER_LINEAR) { + /* convert four pass/fail values to an intensity in [0,1] */ + val = 0.25F * (k0 + k1 + k2 + k3); - /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ - for (j = 0; j < 4; j++) { - rgba[0][j] = rgba[1][j] = rgba[2][j] = val; - rgba[3][j] = 1.0F; + /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */ + for (j = 0; j < 4; j++) { + rgba[0][j] = rgba[1][j] = rgba[2][j] = val; + rgba[3][j] = 1.0F; + } + } else { + for (j = 0; j < 4; j++) { + rgba[0][j] = k0; + rgba[1][j] = k1; + rgba[2][j] = k2; + rgba[3][j] = 1.0F; + } } } @@ -2189,17 +2340,27 @@ sample_compare(struct tgsi_sampler *tgsi_sampler, */ static void sample_cube(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); unsigned j; float ssss[4], tttt[4]; + /* Not actually used, but the intermediate steps that do the + * dereferencing don't know it. + */ + static float pppp[4] = { 0, 0, 0, 0 }; + + pppp[0] = c0[0]; + pppp[1] = c0[1]; + pppp[2] = c0[2]; + pppp[3] = c0[3]; /* major axis direction target sc tc ma @@ -2234,7 +2395,7 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, if (arx >= ary && arx >= arz) { float sign = (rx >= 0.0F) ? 1.0F : -1.0F; uint face = (rx >= 0.0F) ? PIPE_TEX_FACE_POS_X : PIPE_TEX_FACE_NEG_X; - for (j = 0; j < QUAD_SIZE; j++) { + for (j = 0; j < TGSI_QUAD_SIZE; j++) { const float ima = -0.5F / fabsf(s[j]); ssss[j] = sign * p[j] * ima + 0.5F; tttt[j] = t[j] * ima + 0.5F; @@ -2244,7 +2405,7 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, else if (ary >= arx && ary >= arz) { float sign = (ry >= 0.0F) ? 1.0F : -1.0F; uint face = (ry >= 0.0F) ? PIPE_TEX_FACE_POS_Y : PIPE_TEX_FACE_NEG_Y; - for (j = 0; j < QUAD_SIZE; j++) { + for (j = 0; j < TGSI_QUAD_SIZE; j++) { const float ima = -0.5F / fabsf(t[j]); ssss[j] = -s[j] * ima + 0.5F; tttt[j] = sign * -p[j] * ima + 0.5F; @@ -2254,7 +2415,7 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, else { float sign = (rz >= 0.0F) ? 1.0F : -1.0F; uint face = (rz >= 0.0F) ? PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z; - for (j = 0; j < QUAD_SIZE; j++) { + for (j = 0; j < TGSI_QUAD_SIZE; j++) { const float ima = -0.5F / fabsf(p[j]); ssss[j] = sign * -s[j] * ima + 0.5F; tttt[j] = t[j] * ima + 0.5F; @@ -2267,91 +2428,102 @@ sample_cube(struct tgsi_sampler *tgsi_sampler, * is not active, this will point somewhere deeper into the * pipeline, eg. to mip_filter or even img_filter. */ - samp->compare(tgsi_sampler, ssss, tttt, NULL, c0, control, rgba); + samp->compare(tgsi_sampler, ssss, tttt, pppp, c0, c1, control, rgba); } static void -sample_swizzle(struct tgsi_sampler *tgsi_sampler, - const float s[QUAD_SIZE], - const float t[QUAD_SIZE], - const float p[QUAD_SIZE], - const float c0[QUAD_SIZE], - enum tgsi_sampler_control control, - float rgba[NUM_CHANNELS][QUAD_SIZE]) +do_swizzling(const struct sp_sampler_variant *samp, + float in[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE], + float out[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) { - struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); - float rgba_temp[NUM_CHANNELS][QUAD_SIZE]; + int j; const unsigned swizzle_r = samp->key.bits.swizzle_r; const unsigned swizzle_g = samp->key.bits.swizzle_g; const unsigned swizzle_b = samp->key.bits.swizzle_b; const unsigned swizzle_a = samp->key.bits.swizzle_a; - unsigned j; - - samp->sample_target(tgsi_sampler, s, t, p, c0, control, rgba_temp); switch (swizzle_r) { case PIPE_SWIZZLE_ZERO: for (j = 0; j < 4; j++) - rgba[0][j] = 0.0f; + out[0][j] = 0.0f; break; case PIPE_SWIZZLE_ONE: for (j = 0; j < 4; j++) - rgba[0][j] = 1.0f; + out[0][j] = 1.0f; break; default: assert(swizzle_r < 4); for (j = 0; j < 4; j++) - rgba[0][j] = rgba_temp[swizzle_r][j]; + out[0][j] = in[swizzle_r][j]; } switch (swizzle_g) { case PIPE_SWIZZLE_ZERO: for (j = 0; j < 4; j++) - rgba[1][j] = 0.0f; + out[1][j] = 0.0f; break; case PIPE_SWIZZLE_ONE: for (j = 0; j < 4; j++) - rgba[1][j] = 1.0f; + out[1][j] = 1.0f; break; default: assert(swizzle_g < 4); for (j = 0; j < 4; j++) - rgba[1][j] = rgba_temp[swizzle_g][j]; + out[1][j] = in[swizzle_g][j]; } switch (swizzle_b) { case PIPE_SWIZZLE_ZERO: for (j = 0; j < 4; j++) - rgba[2][j] = 0.0f; + out[2][j] = 0.0f; break; case PIPE_SWIZZLE_ONE: for (j = 0; j < 4; j++) - rgba[2][j] = 1.0f; + out[2][j] = 1.0f; break; default: assert(swizzle_b < 4); for (j = 0; j < 4; j++) - rgba[2][j] = rgba_temp[swizzle_b][j]; + out[2][j] = in[swizzle_b][j]; } switch (swizzle_a) { case PIPE_SWIZZLE_ZERO: for (j = 0; j < 4; j++) - rgba[3][j] = 0.0f; + out[3][j] = 0.0f; break; case PIPE_SWIZZLE_ONE: for (j = 0; j < 4; j++) - rgba[3][j] = 1.0f; + out[3][j] = 1.0f; break; default: assert(swizzle_a < 4); for (j = 0; j < 4; j++) - rgba[3][j] = rgba_temp[swizzle_a][j]; + out[3][j] = in[swizzle_a][j]; } } +static void +sample_swizzle(struct tgsi_sampler *tgsi_sampler, + const float s[TGSI_QUAD_SIZE], + const float t[TGSI_QUAD_SIZE], + const float p[TGSI_QUAD_SIZE], + const float c0[TGSI_QUAD_SIZE], + const float c1[TGSI_QUAD_SIZE], + enum tgsi_sampler_control control, + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) +{ + struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; + + samp->sample_target(tgsi_sampler, s, t, p, c0, c1, control, rgba_temp); + + do_swizzling(samp, rgba_temp, rgba); +} + + static wrap_nearest_func get_nearest_unorm_wrap(unsigned mode) { @@ -2440,6 +2612,19 @@ get_linear_wrap(unsigned mode) } +/** + * Is swizzling needed for the given state key? + */ +static INLINE bool +any_swizzle(union sp_sampler_key key) +{ + return (key.bits.swizzle_r != PIPE_SWIZZLE_RED || + key.bits.swizzle_g != PIPE_SWIZZLE_GREEN || + key.bits.swizzle_b != PIPE_SWIZZLE_BLUE || + key.bits.swizzle_a != PIPE_SWIZZLE_ALPHA); +} + + static compute_lambda_func get_lambda_func(const union sp_sampler_key key) { @@ -2447,6 +2632,7 @@ get_lambda_func(const union sp_sampler_key key) return compute_lambda_vert; switch (key.bits.target) { + case PIPE_BUFFER: case PIPE_TEXTURE_1D: case PIPE_TEXTURE_1D_ARRAY: return compute_lambda_1d; @@ -2454,6 +2640,7 @@ get_lambda_func(const union sp_sampler_key key) case PIPE_TEXTURE_2D_ARRAY: case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_CUBE: + case PIPE_TEXTURE_CUBE_ARRAY: return compute_lambda_2d; case PIPE_TEXTURE_3D: return compute_lambda_3d; @@ -2464,12 +2651,13 @@ get_lambda_func(const union sp_sampler_key key) } -static filter_func +static img_filter_func get_img_filter(const union sp_sampler_key key, unsigned filter, const struct pipe_sampler_state *sampler) { switch (key.bits.target) { + case PIPE_BUFFER: case PIPE_TEXTURE_1D: if (filter == PIPE_TEX_FILTER_NEAREST) return img_filter_1d_nearest; @@ -2529,6 +2717,12 @@ get_img_filter(const union sp_sampler_key key, else return img_filter_cube_linear; break; + case PIPE_TEXTURE_CUBE_ARRAY: + if (filter == PIPE_TEX_FILTER_NEAREST) + return img_filter_cube_array_nearest; + else + return img_filter_cube_array_linear; + break; case PIPE_TEXTURE_3D: if (filter == PIPE_TEX_FILTER_NEAREST) return img_filter_3d_nearest; @@ -2556,7 +2750,6 @@ sp_sampler_variant_bind_view( struct sp_sampler_variant *samp, samp->cache = tex_cache; samp->xpot = util_logbase2( texture->width0 ); samp->ypot = util_logbase2( texture->height0 ); - samp->level = view->u.tex.first_level; } @@ -2567,6 +2760,153 @@ sp_sampler_variant_destroy( struct sp_sampler_variant *samp ) } +static void +sample_get_dims(struct tgsi_sampler *tgsi_sampler, int level, + int dims[4]) +{ + struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + const struct pipe_sampler_view *view = samp->view; + const struct pipe_resource *texture = view->texture; + + /* undefined according to EXT_gpu_program */ + level += view->u.tex.first_level; + if (level > view->u.tex.last_level) + return; + + dims[0] = u_minify(texture->width0, level); + + switch(texture->target) { + case PIPE_TEXTURE_1D_ARRAY: + dims[1] = texture->array_size; + /* fallthrough */ + case PIPE_TEXTURE_1D: + return; + case PIPE_TEXTURE_2D_ARRAY: + dims[2] = texture->array_size; + /* fallthrough */ + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_CUBE: + case PIPE_TEXTURE_RECT: + dims[1] = u_minify(texture->height0, level); + return; + case PIPE_TEXTURE_3D: + dims[1] = u_minify(texture->height0, level); + dims[2] = u_minify(texture->depth0, level); + return; + case PIPE_TEXTURE_CUBE_ARRAY: + dims[1] = u_minify(texture->height0, level); + dims[2] = texture->array_size / 6; + break; + case PIPE_BUFFER: + dims[0] /= util_format_get_blocksize(view->format); + return; + default: + assert(!"unexpected texture target in sample_get_dims()"); + return; + } +} + +/** + * This function is only used for getting unfiltered texels via the + * TXF opcode. The GL spec says that out-of-bounds texel fetches + * produce undefined results. Instead of crashing, lets just clamp + * coords to the texture image size. + */ +static void +sample_get_texels(struct tgsi_sampler *tgsi_sampler, + const int v_i[TGSI_QUAD_SIZE], + const int v_j[TGSI_QUAD_SIZE], + const int v_k[TGSI_QUAD_SIZE], + const int lod[TGSI_QUAD_SIZE], + const int8_t offset[3], + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) +{ + const struct sp_sampler_variant *samp = sp_sampler_variant(tgsi_sampler); + union tex_tile_address addr; + const struct pipe_resource *texture = samp->view->texture; + int j, c; + const float *tx; + const bool need_swizzle = any_swizzle(samp->key); + int width, height, depth, layers; + + addr.value = 0; + /* TODO write a better test for LOD */ + addr.bits.level = lod[0]; + + width = u_minify(texture->width0, addr.bits.level); + height = u_minify(texture->height0, addr.bits.level); + depth = u_minify(texture->depth0, addr.bits.level); + layers = texture->array_size; + + switch(texture->target) { + case PIPE_BUFFER: + case PIPE_TEXTURE_1D: + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int x = CLAMP(v_i[j] + offset[0], 0, width - 1); + tx = get_texel_2d(samp, addr, x, 0); + for (c = 0; c < 4; c++) { + rgba[c][j] = tx[c]; + } + } + break; + case PIPE_TEXTURE_1D_ARRAY: + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int x = CLAMP(v_i[j] + offset[0], 0, width - 1); + int y = CLAMP(v_j[j], 0, layers - 1); + tx = get_texel_1d_array(samp, addr, x, y); + for (c = 0; c < 4; c++) { + rgba[c][j] = tx[c]; + } + } + break; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int x = CLAMP(v_i[j] + offset[0], 0, width - 1); + int y = CLAMP(v_j[j] + offset[1], 0, height - 1); + tx = get_texel_2d(samp, addr, x, y); + for (c = 0; c < 4; c++) { + rgba[c][j] = tx[c]; + } + } + break; + case PIPE_TEXTURE_2D_ARRAY: + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int x = CLAMP(v_i[j] + offset[0], 0, width - 1); + int y = CLAMP(v_j[j] + offset[1], 0, height - 1); + int layer = CLAMP(v_k[j], 0, layers - 1); + tx = get_texel_2d_array(samp, addr, x, y, layer); + for (c = 0; c < 4; c++) { + rgba[c][j] = tx[c]; + } + } + break; + case PIPE_TEXTURE_3D: + for (j = 0; j < TGSI_QUAD_SIZE; j++) { + int x = CLAMP(v_i[j] + offset[0], 0, width - 1); + int y = CLAMP(v_j[j] + offset[1], 0, height - 1); + int z = CLAMP(v_k[j] + offset[2], 0, depth - 1); + + tx = get_texel_3d(samp, addr, x, y, z); + for (c = 0; c < 4; c++) { + rgba[c][j] = tx[c]; + } + } + break; + case PIPE_TEXTURE_CUBE: /* TXF can't work on CUBE according to spec */ + default: + assert(!"Unknown or CUBE texture type in TXF processing\n"); + break; + } + + if (need_swizzle) { + float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; + memcpy(rgba_temp, rgba, sizeof(rgba_temp)); + do_swizzling(samp, rgba_temp, rgba); + } +} + + /** * Create a sampler variant for a given set of non-orthogonal state. */ @@ -2612,7 +2952,7 @@ sp_create_sampler_variant( const struct pipe_sampler_state *sampler, switch (sampler->min_mip_filter) { case PIPE_TEX_MIPFILTER_NONE: if (sampler->min_img_filter == sampler->mag_img_filter) - samp->mip_filter = samp->min_img_filter; + samp->mip_filter = mip_filter_none_no_filter_select; else samp->mip_filter = mip_filter_none; break; @@ -2667,7 +3007,7 @@ sp_create_sampler_variant( const struct pipe_sampler_state *sampler, samp->compare = samp->mip_filter; } - if (key.bits.target == PIPE_TEXTURE_CUBE) { + if (key.bits.target == PIPE_TEXTURE_CUBE || key.bits.target == PIPE_TEXTURE_CUBE_ARRAY) { samp->sample_target = sample_cube; } else { @@ -2682,15 +3022,14 @@ sp_create_sampler_variant( const struct pipe_sampler_state *sampler, samp->sample_target = samp->compare; } - if (key.bits.swizzle_r != PIPE_SWIZZLE_RED || - key.bits.swizzle_g != PIPE_SWIZZLE_GREEN || - key.bits.swizzle_b != PIPE_SWIZZLE_BLUE || - key.bits.swizzle_a != PIPE_SWIZZLE_ALPHA) { + if (any_swizzle(key)) { samp->base.get_samples = sample_swizzle; } else { samp->base.get_samples = samp->sample_target; } + samp->base.get_dims = sample_get_dims; + samp->base.get_texel = sample_get_texels; return samp; }