#include "sp_tile_cache.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
-#include "pipe/p_util.h"
-#include "tgsi/exec/tgsi_exec.h"
+#include "tgsi/tgsi_exec.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
/*
* Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
* Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
*/
-#define FRAC(f) ((f) - ifloor(f))
+#define FRAC(f) ((f) - util_ifloor(f))
/**
case PIPE_TEX_WRAP_REPEAT:
/* s limited to [0,1) */
/* i limited to [0,size-1] */
- i = ifloor(s * size);
+ i = util_ifloor(s * size);
i = REMAINDER(i, size);
return i;
case PIPE_TEX_WRAP_CLAMP:
else if (s >= 1.0F)
i = size - 1;
else
- i = ifloor(s * size);
+ i = util_ifloor(s * size);
return i;
case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
{
else if (s > max)
i = size - 1;
else
- i = ifloor(s * size);
+ i = util_ifloor(s * size);
}
return i;
case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
else if (s >= max)
i = size;
else
- i = ifloor(s * size);
+ i = util_ifloor(s * size);
}
return i;
case PIPE_TEX_WRAP_MIRROR_REPEAT:
{
const float min = 1.0F / (2.0F * size);
const float max = 1.0F - min;
- const int flr = ifloor(s);
+ const int flr = util_ifloor(s);
float u;
if (flr & 1)
u = 1.0F - (s - (float) flr);
else if (u > max)
i = size - 1;
else
- i = ifloor(u * size);
+ i = util_ifloor(u * size);
}
return i;
case PIPE_TEX_WRAP_MIRROR_CLAMP:
{
/* s limited to [0,1] */
/* i limited to [0,size-1] */
- const float u = FABSF(s);
+ const float u = fabsf(s);
if (u <= 0.0F)
i = 0;
else if (u >= 1.0F)
i = size - 1;
else
- i = ifloor(u * size);
+ i = util_ifloor(u * size);
}
return i;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
/* 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);
+ const float u = fabsf(s);
if (u < min)
i = 0;
else if (u > max)
i = size - 1;
else
- i = ifloor(u * size);
+ i = util_ifloor(u * size);
}
return i;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
/* 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);
+ const float u = fabsf(s);
if (u < min)
i = -1;
else if (u > max)
i = size;
else
- i = ifloor(u * size);
+ i = util_ifloor(u * size);
}
return i;
default:
switch (wrapMode) {
case PIPE_TEX_WRAP_REPEAT:
u = s * size - 0.5F;
- *i0 = REMAINDER(ifloor(u), size);
+ *i0 = REMAINDER(util_ifloor(u), size);
*i1 = REMAINDER(*i0 + 1, size);
break;
case PIPE_TEX_WRAP_CLAMP:
else
u = s * size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
break;
case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
else
u = s * size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
else
u = s * size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
}
break;
case PIPE_TEX_WRAP_MIRROR_REPEAT:
{
- const int flr = ifloor(s);
+ const int flr = util_ifloor(s);
if (flr & 1)
u = 1.0F - (s - (float) flr);
else
u = s - (float) flr;
u = (u * size) - 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
}
break;
case PIPE_TEX_WRAP_MIRROR_CLAMP:
- u = FABSF(s);
+ u = fabsf(s);
if (u >= 1.0F)
u = (float) size;
else
u *= size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
break;
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
- u = FABSF(s);
+ u = fabsf(s);
if (u >= 1.0F)
u = (float) size;
else
u *= size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
{
const float min = -1.0F / (2.0F * size);
const float max = 1.0F - min;
- u = FABSF(s);
+ u = fabsf(s);
if (u <= min)
u = min * size;
else if (u >= max)
else
u *= size;
u -= 0.5F;
- *i0 = ifloor(u);
+ *i0 = util_ifloor(u);
*i1 = *i0 + 1;
}
break;
}
+/**
+ * For RECT textures / unnormalized texcoords
+ * Only a subset of wrap modes supported.
+ */
+static INLINE int
+nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size)
+{
+ int i;
+ switch (wrapMode) {
+ case PIPE_TEX_WRAP_CLAMP:
+ i = util_ifloor(s);
+ return CLAMP(i, 0, (int) size-1);
+ 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) );
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+/**
+ * For RECT textures / unnormalized texcoords.
+ * 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)
+{
+ 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;
+ 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;
+ break;
+ default:
+ assert(0);
+ }
+ *a = FRAC(s);
+}
+
+
static unsigned
choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
{
+rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
-rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
*/
- const float arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
+ const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
unsigned face;
float sc, tc, ma;
{
float rho, lambda;
+ assert(sampler->state->normalized_coords);
+
assert(s);
{
float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
float dsdy = s[QUAD_TOP_LEFT] - s[QUAD_BOTTOM_LEFT];
- dsdx = FABSF(dsdx);
- dsdy = FABSF(dsdy);
- rho = MAX2(dsdx, dsdy);
- if (sampler->state->normalized_coords)
- rho *= sampler->texture->width[0];
+ dsdx = fabsf(dsdx);
+ dsdy = fabsf(dsdy);
+ rho = MAX2(dsdx, dsdy) * sampler->texture->width[0];
}
if (t) {
float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
float dtdy = t[QUAD_TOP_LEFT] - t[QUAD_BOTTOM_LEFT];
float max;
- dtdx = FABSF(dtdx);
- dtdy = FABSF(dtdy);
- max = MAX2(dtdx, dtdy);
- if (sampler->state->normalized_coords)
- max *= sampler->texture->height[0];
+ dtdx = fabsf(dtdx);
+ dtdy = fabsf(dtdy);
+ max = MAX2(dtdx, dtdy) * sampler->texture->height[0];
rho = MAX2(rho, max);
}
if (p) {
float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
float dpdy = p[QUAD_TOP_LEFT] - p[QUAD_BOTTOM_LEFT];
float max;
- dpdx = FABSF(dpdx);
- dpdy = FABSF(dpdy);
- max = MAX2(dpdx, dpdy);
- if (sampler->state->normalized_coords)
- max *= sampler->texture->depth[0];
+ dpdx = fabsf(dpdx);
+ dpdy = fabsf(dpdy);
+ max = MAX2(dpdx, dpdy) * sampler->texture->depth[0];
rho = MAX2(rho, max);
}
- lambda = LOG2(rho);
+ lambda = util_fast_log2(rho);
lambda += lodbias + sampler->state->lod_bias;
lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
{
if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
/* no mipmap selection needed */
- *imgFilter = sampler->state->mag_img_filter;
- *level0 = *level1 = (int) sampler->state->min_lod;
+ *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
+ 0, (int) sampler->texture->last_level);
if (sampler->state->min_img_filter != sampler->state->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);
- if (lambda < 0.5) { /* XXX this may need tweaking... */
+ if (lambda <= 0.0) {
*imgFilter = sampler->state->mag_img_filter;
}
else {
*imgFilter = sampler->state->min_img_filter;
}
}
+ else {
+ *imgFilter = sampler->state->mag_img_filter;
+ }
}
else {
float lambda;
/* vertex shader */
lambda = lodbias; /* not really a bias, but absolute LOD */
- if (lambda < 0.0) { /* XXX threshold depends on the filter */
+ if (lambda <= 0.0) { /* XXX threshold depends on the filter */
/* magnifying */
*imgFilter = sampler->state->mag_img_filter;
*level0 = *level1 = 0;
unsigned face, unsigned level, int x, int y, int z,
float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
{
- 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,
- x, y, z, face, level);
- rgba[0][j] = tile->data.color[ty][tx][0];
- rgba[1][j] = tile->data.color[ty][tx][1];
- rgba[2][j] = tile->data.color[ty][tx][2];
- rgba[3][j] = tile->data.color[ty][tx][3];
+ 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];
+ }
+ 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,
+ x, y, z, face, level);
+ rgba[0][j] = tile->data.color[ty][tx][0];
+ rgba[1][j] = tile->data.color[ty][tx][1];
+ rgba[2][j] = tile->data.color[ty][tx][2];
+ rgba[3][j] = tile->data.color[ty][tx][3];
+ if (0)
+ {
+ 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));
+ }
+ }
}
k = 0;
break;
default:
+ k = 0;
assert(0);
+ break;
}
rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
choose_mipmap_levels(sampler, s, t, p, lodbias,
&level0, &level1, &levelBlend, &imgFilter);
- if (sampler->state->normalized_coords) {
- width = sampler->texture->width[level0];
- height = sampler->texture->height[level0];
- }
- else {
- width = height = 1;
- }
+ assert(sampler->state->normalized_coords);
+
+ width = sampler->texture->width[level0];
+ height = sampler->texture->height[level0];
assert(width > 0);
}
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;
choose_mipmap_levels(sampler, s, t, p, lodbias,
&level0, &level1, &levelBlend, &imgFilter);
- if (sampler->state->normalized_coords) {
- width = sampler->texture->width[level0];
- height = sampler->texture->height[level0];
- depth = sampler->texture->depth[level0];
- }
- else {
- width = height = depth = 1;
- }
+ assert(sampler->state->normalized_coords);
+
+ width = sampler->texture->width[level0];
+ height = sampler->texture->height[level0];
+ depth = sampler->texture->depth[level0];
assert(width > 0);
assert(height > 0);
}
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 */
}
+static void
+sp_get_samples_rect(struct tgsi_sampler *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_2d_common(sampler, s, t, p, lodbias, rgba, faces);
+ static const uint face = 0;
+ const uint compare_func = sampler->state->compare_func;
+ unsigned level0, level1, j, imgFilter;
+ int width, height;
+ float levelBlend;
+
+ choose_mipmap_levels(sampler, s, t, p, lodbias,
+ &level0, &level1, &levelBlend, &imgFilter);
+
+ /* texture RECTS cannot be mipmapped */
+ assert(level0 == level1);
+
+ width = sampler->texture->width[level0];
+ height = sampler->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);
+ }
+ }
+ 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]);
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+
+
/**
* Called via tgsi_sampler::get_samples()
* Use the sampler's state setting to get a filtered RGBA value
switch (sampler->texture->target) {
case PIPE_TEXTURE_1D:
+ assert(sampler->state->normalized_coords);
sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
break;
case PIPE_TEXTURE_2D:
- sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
+ if (sampler->state->normalized_coords)
+ sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
+ else
+ sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
break;
case PIPE_TEXTURE_3D:
+ assert(sampler->state->normalized_coords);
sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
break;
case PIPE_TEXTURE_CUBE:
+ assert(sampler->state->normalized_coords);
sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
break;
default:
assert(0);
}
+
+#if 0 /* DEBUG */
+ {
+ int i;
+ printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
+ for (i = 0; i < 4; i++) {
+ printf("Frag %d: %f %f %f %f\n", i,
+ rgba[0][i],
+ rgba[1][i],
+ rgba[2][i],
+ rgba[3][i]);
+ }
+ }
+#endif
}