diff options
Diffstat (limited to 'src/gallium/drivers/softpipe/sp_tex_sample.c')
-rw-r--r-- | src/gallium/drivers/softpipe/sp_tex_sample.c | 991 |
1 files changed, 567 insertions, 424 deletions
diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c index 49250ec084..adbd0cb7f0 100644 --- a/src/gallium/drivers/softpipe/sp_tex_sample.c +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c @@ -2,6 +2,7 @@ * * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. + * Copyright 2008 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -33,17 +34,18 @@ */ #include "sp_context.h" -#include "sp_headers.h" +#include "sp_quad.h" #include "sp_surface.h" +#include "sp_texture.h" #include "sp_tex_sample.h" #include "sp_tile_cache.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" -#include "tgsi/tgsi_exec.h" #include "util/u_math.h" #include "util/u_memory.h" + /* * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes * see 1-pixel bands of improperly weighted linear-filtered textures. @@ -57,7 +59,11 @@ /** * Linear interpolation macro */ -#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) +static INLINE float +lerp(float a, float v0, float v1) +{ + return v0 + a * (v1 - v0); +} /** @@ -72,13 +78,28 @@ static INLINE float lerp_2d(float a, float b, float v00, float v10, float v01, float v11) { - const float temp0 = LERP(a, v00, v10); - const float temp1 = LERP(a, v01, v11); - return LERP(b, temp0, temp1); + const float temp0 = lerp(a, v00, v10); + const float temp1 = lerp(a, v01, v11); + return lerp(b, temp0, temp1); } /** + * As above, but 3D interpolation of 8 values. + */ +static INLINE float +lerp_3d(float a, float b, float c, + float v000, float v100, float v010, float v110, + float v001, float v101, float v011, float v111) +{ + const float temp0 = lerp_2d(a, b, v000, v100, v010, v110); + const float temp1 = lerp_2d(a, b, v001, v101, v011, v111); + return lerp(c, temp0, temp1); +} + + + +/** * If A is a signed integer, A % B doesn't give the right value for A < 0 * (in terms of texture repeat). Just casting to unsigned fixes that. */ @@ -86,250 +107,275 @@ lerp_2d(float a, float b, /** - * Apply texture coord wrapping mode and return integer texture index. + * Apply texture coord wrapping mode and return integer texture indexes + * for a vector of four texcoords (S or T or P). * \param wrapMode PIPE_TEX_WRAP_x - * \param s the texcoord + * \param s the incoming texcoords * \param size the texture image size + * \param icoord returns the integer texcoords * \return integer texture index */ -static INLINE int -nearest_texcoord(unsigned wrapMode, float s, unsigned size) +static INLINE void +nearest_texcoord_4(unsigned wrapMode, const float s[4], unsigned size, + int icoord[4]) { - int i; + uint ch; switch (wrapMode) { case PIPE_TEX_WRAP_REPEAT: /* s limited to [0,1) */ /* i limited to [0,size-1] */ - i = util_ifloor(s * size); - i = REMAINDER(i, size); - return i; + for (ch = 0; ch < 4; ch++) { + int i = util_ifloor(s[ch] * size); + icoord[ch] = REMAINDER(i, size); + } + return; case PIPE_TEX_WRAP_CLAMP: /* s limited to [0,1] */ /* i limited to [0,size-1] */ - if (s <= 0.0F) - i = 0; - else if (s >= 1.0F) - i = size - 1; - else - i = util_ifloor(s * size); - return i; + 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); + } + return; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: { /* 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; - if (s < min) - i = 0; - else if (s > max) - i = size - 1; - else - i = util_ifloor(s * size); + 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); + } } - return i; + return; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: { /* s limited to [min,max] */ /* i limited to [-1, size] */ const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - if (s <= min) - i = -1; - else if (s >= max) - i = size; - else - i = util_ifloor(s * size); + 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); + } } - return i; + return; case PIPE_TEX_WRAP_MIRROR_REPEAT: { const float min = 1.0F / (2.0F * size); const float max = 1.0F - min; - const int flr = util_ifloor(s); - float u; - if (flr & 1) - u = 1.0F - (s - (float) flr); - else - u = s - (float) flr; - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = util_ifloor(u * size); + for (ch = 0; ch < 4; ch++) { + const int flr = util_ifloor(s[ch]); + float u; + if (flr & 1) + u = 1.0F - (s[ch] - (float) flr); + else + u = s[ch] - (float) flr; + if (u < min) + icoord[ch] = 0; + else if (u > max) + icoord[ch] = size - 1; + else + icoord[ch] = util_ifloor(u * size); + } } - return i; + return; case PIPE_TEX_WRAP_MIRROR_CLAMP: - { + for (ch = 0; ch < 4; ch++) { /* s limited to [0,1] */ /* i limited to [0,size-1] */ - const float u = fabsf(s); + const float u = fabsf(s[ch]); if (u <= 0.0F) - i = 0; + icoord[ch] = 0; else if (u >= 1.0F) - i = size - 1; + icoord[ch] = size - 1; else - i = util_ifloor(u * size); + icoord[ch] = util_ifloor(u * size); } - return i; + return; case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: { /* 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; - const float u = fabsf(s); - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = util_ifloor(u * size); + 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); + } } - return i; + return; case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: { /* 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; - const float u = fabsf(s); - if (u < min) - i = -1; - else if (u > max) - i = size; - else - i = util_ifloor(u * size); + 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); + } } - return i; + return; default: assert(0); - return 0; } } /** - * Used to compute texel locations for linear sampling. + * Used to compute texel locations for linear sampling for four texcoords. * \param wrapMode PIPE_TEX_WRAP_x - * \param s the texcoord + * \param s the texcoords * \param size the texture image size - * \param i0 returns first texture index - * \param i1 returns second texture index (usually *i0 + 1) - * \param a returns blend factor/weight between texture indexes + * \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 */ static INLINE void -linear_texcoord(unsigned wrapMode, float s, unsigned size, - int *i0, int *i1, float *a) +linear_texcoord_4(unsigned wrapMode, const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) { - float u; + uint ch; + switch (wrapMode) { case PIPE_TEX_WRAP_REPEAT: - u = s * size - 0.5F; - *i0 = REMAINDER(util_ifloor(u), size); - *i1 = REMAINDER(*i0 + 1, size); - break; + for (ch = 0; ch < 4; ch++) { + float u = s[ch] * size - 0.5F; + icoord0[ch] = REMAINDER(util_ifloor(u), size); + icoord1[ch] = REMAINDER(icoord0[ch] + 1, size); + w[ch] = FRAC(u); + } + break;; case PIPE_TEX_WRAP_CLAMP: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (float) size; - else - u = s * size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; - break; + 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); + } + break;; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (float) size; - else - u = s * size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (int) size) - *i1 = size - 1; - break; + 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); + } + break;; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: { const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - if (s <= min) - u = min * size; - else if (s >= max) - u = max * size; - else - u = s * size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; + 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); + } } - break; + break;; case PIPE_TEX_WRAP_MIRROR_REPEAT: - { - const int flr = util_ifloor(s); + for (ch = 0; ch < 4; ch++) { + const int flr = util_ifloor(s[ch]); + float u; if (flr & 1) - u = 1.0F - (s - (float) flr); + u = 1.0F - (s[ch] - (float) flr); else - u = s - (float) flr; - u = (u * size) - 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (int) size) - *i1 = size - 1; + u = s[ch] - (float) flr; + 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); } - break; + break;; case PIPE_TEX_WRAP_MIRROR_CLAMP: - u = fabsf(s); - if (u >= 1.0F) - u = (float) size; - else - u *= size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; - break; + 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); + } + break;; case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: - u = fabsf(s); - if (u >= 1.0F) - u = (float) size; - else - u *= size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (int) size) - *i1 = size - 1; - break; + 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); + } + break;; case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: { const float min = -1.0F / (2.0F * size); const float max = 1.0F - min; - u = fabsf(s); - if (u <= min) - u = min * size; - else if (u >= max) - u = max * size; - else - u *= size; - u -= 0.5F; - *i0 = util_ifloor(u); - *i1 = *i0 + 1; + 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); + } } - break; + break;; default: assert(0); } - *a = FRAC(u); } @@ -337,21 +383,27 @@ linear_texcoord(unsigned wrapMode, float s, unsigned size, * For RECT textures / unnormalized texcoords * Only a subset of wrap modes supported. */ -static INLINE int -nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size) +static INLINE void +nearest_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size, + int icoord[4]) { - int i; + uint ch; switch (wrapMode) { case PIPE_TEX_WRAP_CLAMP: - i = util_ifloor(s); - return CLAMP(i, 0, (int) size-1); + for (ch = 0; ch < 4; ch++) { + int i = util_ifloor(s[ch]); + icoord[ch]= CLAMP(i, 0, (int) size-1); + } + return; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: /* fall-through */ case PIPE_TEX_WRAP_CLAMP_TO_BORDER: - return util_ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) ); + for (ch = 0; ch < 4; ch++) { + icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) ); + } + return; default: assert(0); - return 0; } } @@ -361,30 +413,36 @@ nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size) * Only a subset of wrap modes supported. */ static INLINE void -linear_texcoord_unnorm(unsigned wrapMode, float s, unsigned size, - int *i0, int *i1, float *a) +linear_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size, + int icoord0[4], int icoord1[4], float w[4]) { + uint ch; switch (wrapMode) { case PIPE_TEX_WRAP_CLAMP: - /* Not exactly what the spec says, but it matches NVIDIA output */ - s = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f); - *i0 = util_ifloor(s); - *i1 = *i0 + 1; - break; + 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); + } + return; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: /* fall-through */ case PIPE_TEX_WRAP_CLAMP_TO_BORDER: - s = CLAMP(s, 0.5F, (float) size - 0.5F); - s -= 0.5F; - *i0 = util_ifloor(s); - *i1 = *i0 + 1; - if (*i1 > (int) size - 1) - *i1 = size - 1; + 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); + } break; default: assert(0); } - *a = FRAC(s); } @@ -463,7 +521,8 @@ choose_cube_face(float rx, float ry, float rz, float *newS, float *newT) * This is only done for fragment shaders, not vertex shaders. */ static float -compute_lambda(struct tgsi_sampler *sampler, +compute_lambda(const struct pipe_texture *tex, + const struct pipe_sampler_state *sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], @@ -471,7 +530,7 @@ compute_lambda(struct tgsi_sampler *sampler, { float rho, lambda; - assert(sampler->state->normalized_coords); + assert(sampler->normalized_coords); assert(s); { @@ -479,7 +538,7 @@ compute_lambda(struct tgsi_sampler *sampler, float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT]; dsdx = fabsf(dsdx); dsdy = fabsf(dsdy); - rho = MAX2(dsdx, dsdy) * sampler->texture->width[0]; + rho = MAX2(dsdx, dsdy) * tex->width[0]; } if (t) { float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]; @@ -487,7 +546,7 @@ compute_lambda(struct tgsi_sampler *sampler, float max; dtdx = fabsf(dtdx); dtdy = fabsf(dtdy); - max = MAX2(dtdx, dtdy) * sampler->texture->height[0]; + max = MAX2(dtdx, dtdy) * tex->height[0]; rho = MAX2(rho, max); } if (p) { @@ -496,13 +555,13 @@ compute_lambda(struct tgsi_sampler *sampler, float max; dpdx = fabsf(dpdx); dpdy = fabsf(dpdy); - max = MAX2(dpdx, dpdy) * sampler->texture->depth[0]; + max = MAX2(dpdx, dpdy) * tex->depth[0]; rho = MAX2(rho, max); } lambda = util_fast_log2(rho); - lambda += lodbias + sampler->state->lod_bias; - lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod); + lambda += lodbias + sampler->lod_bias; + lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod); return lambda; } @@ -514,68 +573,74 @@ compute_lambda(struct tgsi_sampler *sampler, * 2. Determine if we're minifying or magnifying * 3. If minifying, choose mipmap levels * 4. Return image filter to use within mipmap images + * \param level0 Returns first mipmap level to sample from + * \param level1 Returns second mipmap level to sample from + * \param levelBlend Returns blend factor between levels, in [0,1] + * \param imgFilter Returns either the min or mag filter, depending on lambda */ static void -choose_mipmap_levels(struct tgsi_sampler *sampler, +choose_mipmap_levels(const struct pipe_texture *texture, + const struct pipe_sampler_state *sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, unsigned *level0, unsigned *level1, float *levelBlend, unsigned *imgFilter) { - if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { + if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { /* no mipmap selection needed */ - *level0 = *level1 = CLAMP((int) sampler->state->min_lod, - 0, (int) sampler->texture->last_level); + *level0 = *level1 = CLAMP((int) sampler->min_lod, + 0, (int) texture->last_level); - if (sampler->state->min_img_filter != sampler->state->mag_img_filter) { + if (sampler->min_img_filter != sampler->mag_img_filter) { /* non-mipmapped texture, but still need to determine if doing * minification or magnification. */ - float lambda = compute_lambda(sampler, s, t, p, lodbias); + float lambda = compute_lambda(texture, sampler, s, t, p, lodbias); if (lambda <= 0.0) { - *imgFilter = sampler->state->mag_img_filter; + *imgFilter = sampler->mag_img_filter; } else { - *imgFilter = sampler->state->min_img_filter; + *imgFilter = sampler->min_img_filter; } } else { - *imgFilter = sampler->state->mag_img_filter; + *imgFilter = sampler->mag_img_filter; } } else { float lambda; - if (1) + if (computeLambda) /* fragment shader */ - lambda = compute_lambda(sampler, s, t, p, lodbias); + lambda = compute_lambda(texture, sampler, s, t, p, lodbias); else /* vertex shader */ lambda = lodbias; /* not really a bias, but absolute LOD */ if (lambda <= 0.0) { /* XXX threshold depends on the filter */ /* magnifying */ - *imgFilter = sampler->state->mag_img_filter; + *imgFilter = sampler->mag_img_filter; *level0 = *level1 = 0; } else { /* minifying */ - *imgFilter = sampler->state->min_img_filter; + *imgFilter = sampler->min_img_filter; /* choose mipmap level(s) and compute the blend factor between them */ - if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { + if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { /* Nearest mipmap level */ const int lvl = (int) (lambda + 0.5); *level0 = - *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level); + *level1 = CLAMP(lvl, 0, (int) texture->last_level); } else { /* Linear interpolation between mipmap levels */ const int lvl = (int) lambda; - *level0 = CLAMP(lvl, 0, (int) sampler->texture->last_level); - *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level); + *level0 = CLAMP(lvl, 0, (int) texture->last_level); + *level1 = CLAMP(lvl + 1, 0, (int) texture->last_level); *levelBlend = FRAC(lambda); /* blending weight between levels */ } } @@ -598,23 +663,29 @@ choose_mipmap_levels(struct tgsi_sampler *sampler, * sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1... */ static void -get_texel(struct tgsi_sampler *sampler, +get_texel(const struct tgsi_sampler *tgsi_sampler, unsigned face, unsigned level, int x, int y, int z, float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j) { - if (x < 0 || x >= (int) sampler->texture->width[level] || - y < 0 || y >= (int) sampler->texture->height[level] || - z < 0 || z >= (int) sampler->texture->depth[level]) { - rgba[0][j] = sampler->state->border_color[0]; - rgba[1][j] = sampler->state->border_color[1]; - rgba[2][j] = sampler->state->border_color[2]; - rgba[3][j] = sampler->state->border_color[3]; + const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); + struct softpipe_context *sp = samp->sp; + const uint unit = samp->unit; + const struct pipe_texture *texture = sp->texture[unit]; + const struct pipe_sampler_state *sampler = sp->sampler[unit]; + + if (x < 0 || x >= (int) texture->width[level] || + y < 0 || y >= (int) texture->height[level] || + z < 0 || z >= (int) texture->depth[level]) { + rgba[0][j] = sampler->border_color[0]; + rgba[1][j] = sampler->border_color[1]; + rgba[2][j] = sampler->border_color[2]; + rgba[3][j] = sampler->border_color[3]; } else { const int tx = x % TILE_SIZE; const int ty = y % TILE_SIZE; const struct softpipe_cached_tile *tile - = sp_get_cached_tile_tex(sampler->pipe, sampler->cache, + = sp_get_cached_tile_tex(sp, samp->cache, x, y, z, face, level); rgba[0][j] = tile->data.color[ty][tx][0]; rgba[1][j] = tile->data.color[ty][tx][1]; @@ -624,7 +695,7 @@ get_texel(struct tgsi_sampler *sampler, { debug_printf("Get texel %f %f %f %f from %s\n", rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j], - pf_name(sampler->texture->format)); + pf_name(texture->format)); } } } @@ -682,103 +753,124 @@ shadow_compare(uint compare_func, * Could probably extend for 3D... */ static void -sp_get_samples_2d_common(struct tgsi_sampler *sampler, +sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE], const unsigned faces[4]) { - const uint compare_func = sampler->state->compare_func; + const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); + const struct softpipe_context *sp = samp->sp; + const uint unit = samp->unit; + const struct pipe_texture *texture = sp->texture[unit]; + const struct pipe_sampler_state *sampler = sp->sampler[unit]; + const uint compare_func = sampler->compare_func; unsigned level0, level1, j, imgFilter; int width, height; float levelBlend; - choose_mipmap_levels(sampler, s, t, p, lodbias, + choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias, &level0, &level1, &levelBlend, &imgFilter); - assert(sampler->state->normalized_coords); + assert(sampler->normalized_coords); - width = sampler->texture->width[level0]; - height = sampler->texture->height[level0]; + width = texture->width[level0]; + height = texture->height[level0]; assert(width > 0); switch (imgFilter) { case PIPE_TEX_FILTER_NEAREST: - for (j = 0; j < QUAD_SIZE; j++) { - int x = nearest_texcoord(sampler->state->wrap_s, s[j], width); - int y = nearest_texcoord(sampler->state->wrap_t, t[j], height); - get_texel(sampler, faces[j], level0, x, y, 0, rgba, j); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { - shadow_compare(compare_func, rgba, p, j); - } - - if (level0 != level1) { - /* get texels from second mipmap level and blend */ - float rgba2[4][4]; - unsigned c; - x = x / 2; - y = y / 2; - get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ - shadow_compare(compare_func, rgba2, p, j); + { + int x[4], y[4]; + nearest_texcoord_4(sampler->wrap_s, s, width, x); + nearest_texcoord_4(sampler->wrap_t, t, height, y); + + for (j = 0; j < QUAD_SIZE; j++) { + get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { + shadow_compare(compare_func, rgba, p, j); } - for (c = 0; c < NUM_CHANNELS; c++) { - rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]); + if (level0 != level1) { + /* get texels from second mipmap level and blend */ + float rgba2[4][4]; + unsigned c; + x[j] /= 2; + y[j] /= 2; + get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0, + rgba2, j); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ + shadow_compare(compare_func, rgba2, p, j); + } + + for (c = 0; c < NUM_CHANNELS; c++) { + rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); + } } } } break; case PIPE_TEX_FILTER_LINEAR: case PIPE_TEX_FILTER_ANISO: - for (j = 0; j < QUAD_SIZE; j++) { - float tx[4][4], a, b; - int x0, y0, x1, y1, c; - linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &a); - linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b); - get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0); - get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1); - get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2); - get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { - shadow_compare(compare_func, tx, p, 0); - shadow_compare(compare_func, tx, p, 1); - shadow_compare(compare_func, tx, p, 2); - shadow_compare(compare_func, tx, p, 3); - } - - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]); - } - - if (level0 != level1) { - /* get texels from second mipmap level and blend */ - float rgba2[4][4]; - x0 = x0 / 2; - y0 = y0 / 2; - x1 = x1 / 2; - y1 = y1 / 2; - get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0); - get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1); - get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2); - get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ + { + int x0[4], y0[4], x1[4], y1[4]; + float xw[4], yw[4]; /* weights */ + + linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); + linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); + + for (j = 0; j < QUAD_SIZE; j++) { + float tx[4][4]; /* texels */ + int c; + get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0); + get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1); + get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2); + get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { shadow_compare(compare_func, tx, p, 0); shadow_compare(compare_func, tx, p, 1); shadow_compare(compare_func, tx, p, 2); shadow_compare(compare_func, tx, p, 3); } + /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { - rgba2[c][j] = lerp_2d(a, b, - tx[c][0], tx[c][1], tx[c][2], tx[c][3]); + rgba[c][j] = lerp_2d(xw[j], yw[j], + tx[c][0], tx[c][1], + tx[c][2], tx[c][3]); } - for (c = 0; c < NUM_CHANNELS; c++) { - rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]); + if (level0 != level1) { + /* get texels from second mipmap level and blend */ + float rgba2[4][4]; + x0[j] /= 2; + y0[j] /= 2; + x1[j] /= 2; + y1[j] /= 2; + get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0); + get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1); + get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2); + get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ + shadow_compare(compare_func, tx, p, 0); + shadow_compare(compare_func, tx, p, 1); + shadow_compare(compare_func, tx, p, 2); + shadow_compare(compare_func, tx, p, 3); + } + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba2[c][j] = lerp_2d(xw[j], yw[j], + tx[c][0], tx[c][1], tx[c][2], tx[c][3]); + } + + for (c = 0; c < NUM_CHANNELS; c++) { + rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); + } } } } @@ -789,55 +881,65 @@ sp_get_samples_2d_common(struct tgsi_sampler *sampler, } -static void -sp_get_samples_1d(struct tgsi_sampler *sampler, +static INLINE void +sp_get_samples_1d(const struct tgsi_sampler *sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { static const unsigned faces[4] = {0, 0, 0, 0}; static const float tzero[4] = {0, 0, 0, 0}; - sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces); + sp_get_samples_2d_common(sampler, s, tzero, NULL, + computeLambda, lodbias, rgba, faces); } -static void -sp_get_samples_2d(struct tgsi_sampler *sampler, +static INLINE void +sp_get_samples_2d(const struct tgsi_sampler *sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { static const unsigned faces[4] = {0, 0, 0, 0}; - sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces); + sp_get_samples_2d_common(sampler, s, t, p, + computeLambda, lodbias, rgba, faces); } -static void -sp_get_samples_3d(struct tgsi_sampler *sampler, +static INLINE void +sp_get_samples_3d(const struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { + const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); + const struct softpipe_context *sp = samp->sp; + const uint unit = samp->unit; + const struct pipe_texture *texture = sp->texture[unit]; + const struct pipe_sampler_state *sampler = sp->sampler[unit]; /* get/map pipe_surfaces corresponding to 3D tex slices */ unsigned level0, level1, j, imgFilter; int width, height, depth; float levelBlend; const uint face = 0; - choose_mipmap_levels(sampler, s, t, p, lodbias, + choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias, &level0, &level1, &levelBlend, &imgFilter); - assert(sampler->state->normalized_coords); + assert(sampler->normalized_coords); - width = sampler->texture->width[level0]; - height = sampler->texture->height[level0]; - depth = sampler->texture->depth[level0]; + width = texture->width[level0]; + height = texture->height[level0]; + depth = texture->depth[level0]; assert(width > 0); assert(height > 0); @@ -845,89 +947,89 @@ sp_get_samples_3d(struct tgsi_sampler *sampler, switch (imgFilter) { case PIPE_TEX_FILTER_NEAREST: - for (j = 0; j < QUAD_SIZE; j++) { - int x = nearest_texcoord(sampler->state->wrap_s, s[j], width); - int y = nearest_texcoord(sampler->state->wrap_t, t[j], height); - int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth); - get_texel(sampler, face, level0, x, y, z, rgba, j); - - if (level0 != level1) { - /* get texels from second mipmap level and blend */ - float rgba2[4][4]; - unsigned c; - x /= 2; - y /= 2; - z /= 2; - get_texel(sampler, face, level1, x, y, z, rgba2, j); - for (c = 0; c < NUM_CHANNELS; c++) { - rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]); + { + int x[4], y[4], z[4]; + nearest_texcoord_4(sampler->wrap_s, s, width, x); + nearest_texcoord_4(sampler->wrap_t, t, height, y); + nearest_texcoord_4(sampler->wrap_r, p, depth, z); + for (j = 0; j < QUAD_SIZE; j++) { + get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j); + if (level0 != level1) { + /* get texels from second mipmap level and blend */ + float rgba2[4][4]; + unsigned c; + x[j] /= 2; + y[j] /= 2; + z[j] /= 2; + get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j); + for (c = 0; c < NUM_CHANNELS; c++) { + rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]); + } } } } break; case PIPE_TEX_FILTER_LINEAR: case PIPE_TEX_FILTER_ANISO: - for (j = 0; j < QUAD_SIZE; j++) { - float texel0[4][4], texel1[4][4]; - float xw, yw, zw; /* interpolation weights */ - int x0, x1, y0, y1, z0, z1, c; - linear_texcoord(sampler->state->wrap_s, s[j], width, &x0, &x1, &xw); - linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw); - linear_texcoord(sampler->state->wrap_r, p[j], depth, &z0, &z1, &zw); - get_texel(sampler, face, level0, x0, y0, z0, texel0, 0); - get_texel(sampler, face, level0, x1, y0, z0, texel0, 1); - get_texel(sampler, face, level0, x0, y1, z0, texel0, 2); - get_texel(sampler, face, level0, x1, y1, z0, texel0, 3); - get_texel(sampler, face, level0, x0, y0, z1, texel1, 0); - get_texel(sampler, face, level0, x1, y0, z1, texel1, 1); - get_texel(sampler, face, level0, x0, y1, z1, texel1, 2); - get_texel(sampler, face, level0, x1, y1, z1, texel1, 3); - - /* 3D lerp */ - for (c = 0; c < 4; c++) { - float ctemp0[4][4], ctemp1[4][4]; - ctemp0[c][j] = lerp_2d(xw, yw, - texel0[c][0], texel0[c][1], - texel0[c][2], texel0[c][3]); - ctemp1[c][j] = lerp_2d(xw, yw, - texel1[c][0], texel1[c][1], - texel1[c][2], texel1[c][3]); - rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]); - } - - if (level0 != level1) { - /* get texels from second mipmap level and blend */ - float rgba2[4][4]; - x0 /= 2; - y0 /= 2; - z0 /= 2; - x1 /= 2; - y1 /= 2; - z1 /= 2; - get_texel(sampler, face, level1, x0, y0, z0, texel0, 0); - get_texel(sampler, face, level1, x1, y0, z0, texel0, 1); - get_texel(sampler, face, level1, x0, y1, z0, texel0, 2); - get_texel(sampler, face, level1, x1, y1, z0, texel0, 3); - get_texel(sampler, face, level1, x0, y0, z1, texel1, 0); - get_texel(sampler, face, level1, x1, y0, z1, texel1, 1); - get_texel(sampler, face, level1, x0, y1, z1, texel1, 2); - get_texel(sampler, face, level1, x1, y1, z1, texel1, 3); - - /* 3D lerp */ + { + int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4]; + float xw[4], yw[4], zw[4]; /* interpolation weights */ + linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); + linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); + linear_texcoord_4(sampler->wrap_r, p, depth, z0, z1, zw); + + for (j = 0; j < QUAD_SIZE; j++) { + int c; + float tx0[4][4], tx1[4][4]; + get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0); + get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1); + get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2); + get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3); + get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0); + get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1); + get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2); + get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3); + + /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { - float ctemp0[4][4], ctemp1[4][4]; - ctemp0[c][j] = lerp_2d(xw, yw, - texel0[c][0], texel0[c][1], - texel0[c][2], texel0[c][3]); - ctemp1[c][j] = lerp_2d(xw, yw, - texel1[c][0], texel1[c][1], - texel1[c][2], texel1[c][3]); - rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]); + rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j], + tx0[c][0], tx0[c][1], + tx0[c][2], tx0[c][3], + tx1[c][0], tx1[c][1], + tx1[c][2], tx1[c][3]); } - /* blend mipmap levels */ - for (c = 0; c < NUM_CHANNELS; c++) { - rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]); + if (level0 != level1) { + /* get texels from second mipmap level and blend */ + float rgba2[4][4]; + x0[j] /= 2; + y0[j] /= 2; + z0[j] /= 2; + x1[j] /= 2; + y1[j] /= 2; + z1[j] /= 2; + get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0); + get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1); + get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2); + get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3); + get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0); + get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1); + get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2); + get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3); + + /* interpolate R, G, B, A */ + for (c = 0; c < 4; c++) { + rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j], + tx0[c][0], tx0[c][1], + tx0[c][2], tx0[c][3], + tx1[c][0], tx1[c][1], + tx1[c][2], tx1[c][3]); + } + + /* blend mipmap levels */ + for (c = 0; c < NUM_CHANNELS; c++) { + rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); + } } } } @@ -939,10 +1041,11 @@ sp_get_samples_3d(struct tgsi_sampler *sampler, static void -sp_get_samples_cube(struct tgsi_sampler *sampler, +sp_get_samples_cube(const struct tgsi_sampler *sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { @@ -951,67 +1054,80 @@ sp_get_samples_cube(struct tgsi_sampler *sampler, for (j = 0; j < QUAD_SIZE; j++) { faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j); } - sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces); + sp_get_samples_2d_common(sampler, ssss, tttt, NULL, + computeLambda, lodbias, rgba, faces); } static void -sp_get_samples_rect(struct tgsi_sampler *sampler, +sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { - //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces); - static const uint face = 0; - const uint compare_func = sampler->state->compare_func; + const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); + const struct softpipe_context *sp = samp->sp; + const uint unit = samp->unit; + const struct pipe_texture *texture = sp->texture[unit]; + const struct pipe_sampler_state *sampler = sp->sampler[unit]; + const uint face = 0; + const uint compare_func = sampler->compare_func; unsigned level0, level1, j, imgFilter; int width, height; float levelBlend; - choose_mipmap_levels(sampler, s, t, p, lodbias, + choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias, &level0, &level1, &levelBlend, &imgFilter); /* texture RECTS cannot be mipmapped */ assert(level0 == level1); - width = sampler->texture->width[level0]; - height = sampler->texture->height[level0]; + width = texture->width[level0]; + height = texture->height[level0]; assert(width > 0); switch (imgFilter) { case PIPE_TEX_FILTER_NEAREST: - for (j = 0; j < QUAD_SIZE; j++) { - int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width); - int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height); - get_texel(sampler, face, level0, x, y, 0, rgba, j); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { - shadow_compare(compare_func, rgba, p, j); + { + int x[4], y[4]; + nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x); + nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y); + for (j = 0; j < QUAD_SIZE; j++) { + get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { + shadow_compare(compare_func, rgba, p, j); + } } } break; case PIPE_TEX_FILTER_LINEAR: case PIPE_TEX_FILTER_ANISO: - for (j = 0; j < QUAD_SIZE; j++) { - float tx[4][4], a, b; - int x0, y0, x1, y1, c; - linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width, &x0, &x1, &a); - linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b); - get_texel(sampler, face, level0, x0, y0, 0, tx, 0); - get_texel(sampler, face, level0, x1, y0, 0, tx, 1); - get_texel(sampler, face, level0, x0, y1, 0, tx, 2); - get_texel(sampler, face, level0, x1, y1, 0, tx, 3); - if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { - shadow_compare(compare_func, tx, p, 0); - shadow_compare(compare_func, tx, p, 1); - shadow_compare(compare_func, tx, p, 2); - shadow_compare(compare_func, tx, p, 3); - } - - for (c = 0; c < 4; c++) { - rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]); + { + int x0[4], y0[4], x1[4], y1[4]; + float xw[4], yw[4]; /* weights */ + linear_texcoord_unnorm_4(sampler->wrap_s, s, width, x0, x1, xw); + linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw); + for (j = 0; j < QUAD_SIZE; j++) { + float tx[4][4]; /* texels */ + int c; + get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0); + get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1); + get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2); + get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3); + if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { + shadow_compare(compare_func, tx, p, 0); + shadow_compare(compare_func, tx, p, 1); + shadow_compare(compare_func, tx, p, 2); + shadow_compare(compare_func, tx, p, 3); + } + for (c = 0; c < 4; c++) { + rgba[c][j] = lerp_2d(xw[j], yw[j], + tx[c][0], tx[c][1], tx[c][2], tx[c][3]); + } } } break; @@ -1021,49 +1137,45 @@ sp_get_samples_rect(struct tgsi_sampler *sampler, } - - /** - * Called via tgsi_sampler::get_samples() - * Use the sampler's state setting to get a filtered RGBA value - * from the sampler's texture. - * - * XXX we can implement many versions of this function, each - * tightly coded for a specific combination of sampler state - * (nearest + repeat), (bilinear mipmap + clamp), etc. - * - * The update_samplers() function in st_atom_sampler.c could create - * a new tgsi_sampler object for each state combo it finds.... + * Common code for vertex/fragment program texture sampling. */ -void -sp_get_samples(struct tgsi_sampler *sampler, +static INLINE void +sp_get_samples(struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], + boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { - if (!sampler->texture) + const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); + const struct softpipe_context *sp = samp->sp; + const uint unit = samp->unit; + const struct pipe_texture *texture = sp->texture[unit]; + const struct pipe_sampler_state *sampler = sp->sampler[unit]; + + if (!texture) return; - switch (sampler->texture->target) { + switch (texture->target) { case PIPE_TEXTURE_1D: - assert(sampler->state->normalized_coords); - sp_get_samples_1d(sampler, s, t, p, lodbias, rgba); + assert(sampler->normalized_coords); + sp_get_samples_1d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba); break; case PIPE_TEXTURE_2D: - if (sampler->state->normalized_coords) - sp_get_samples_2d(sampler, s, t, p, lodbias, rgba); + if (sampler->normalized_coords) + sp_get_samples_2d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba); else - sp_get_samples_rect(sampler, s, t, p, lodbias, rgba); + sp_get_samples_rect(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba); break; case PIPE_TEXTURE_3D: - assert(sampler->state->normalized_coords); - sp_get_samples_3d(sampler, s, t, p, lodbias, rgba); + assert(sampler->normalized_coords); + sp_get_samples_3d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba); break; case PIPE_TEXTURE_CUBE: - assert(sampler->state->normalized_coords); - sp_get_samples_cube(sampler, s, t, p, lodbias, rgba); + assert(sampler->normalized_coords); + sp_get_samples_cube(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba); break; default: assert(0); @@ -1084,3 +1196,34 @@ sp_get_samples(struct tgsi_sampler *sampler, #endif } + +/** + * Called via tgsi_sampler::get_samples() when running a fragment shader. + * Get four filtered RGBA values from the sampler's texture. + */ +void +sp_get_samples_fragment(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + float lodbias, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + sp_get_samples(tgsi_sampler, s, t, p, TRUE, lodbias, rgba); +} + + +/** + * Called via tgsi_sampler::get_samples() when running a vertex shader. + * Get four filtered RGBA values from the sampler's texture. + */ +void +sp_get_samples_vertex(struct tgsi_sampler *tgsi_sampler, + const float s[QUAD_SIZE], + const float t[QUAD_SIZE], + const float p[QUAD_SIZE], + float lodbias, + float rgba[NUM_CHANNELS][QUAD_SIZE]) +{ + sp_get_samples(tgsi_sampler, s, t, p, FALSE, lodbias, rgba); +} |