summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Paul <brian.paul@tungstengraphics.com>2008-10-14 17:11:29 -0600
committerBrian Paul <brian.paul@tungstengraphics.com>2008-10-14 17:11:29 -0600
commit8f7c6b55ae962e30f32cfec9a14a652d3b5b5943 (patch)
treeaa457eab6b4c031888fdefd4f737d42b0e7ef248
parente0931e520a8d7cc5b4db8a4b887c5cf139b2647f (diff)
cell: support for cubemaps
Though, progs/demos/cubemap.c doesn't quite work right...
-rw-r--r--src/gallium/drivers/cell/common.h1
-rw-r--r--src/gallium/drivers/cell/ppu/cell_state_emit.c2
-rw-r--r--src/gallium/drivers/cell/ppu/cell_texture.c37
-rw-r--r--src/gallium/drivers/cell/spu/spu_command.c17
-rw-r--r--src/gallium/drivers/cell/spu/spu_funcs.c2
-rw-r--r--src/gallium/drivers/cell/spu/spu_main.h4
-rw-r--r--src/gallium/drivers/cell/spu/spu_texture.c171
-rw-r--r--src/gallium/drivers/cell/spu/spu_texture.h21
8 files changed, 214 insertions, 41 deletions
diff --git a/src/gallium/drivers/cell/common.h b/src/gallium/drivers/cell/common.h
index e4de9a551..c1e78f4db 100644
--- a/src/gallium/drivers/cell/common.h
+++ b/src/gallium/drivers/cell/common.h
@@ -251,6 +251,7 @@ struct cell_command_sampler
struct cell_command_texture
{
uint64_t opcode; /**< CELL_CMD_STATE_TEXTURE */
+ uint target; /**< PIPE_TEXTURE_x */
uint unit;
void *start[CELL_MAX_TEXTURE_LEVELS]; /**< Address in main memory */
ushort width[CELL_MAX_TEXTURE_LEVELS];
diff --git a/src/gallium/drivers/cell/ppu/cell_state_emit.c b/src/gallium/drivers/cell/ppu/cell_state_emit.c
index cae546b70..d4a867ffc 100644
--- a/src/gallium/drivers/cell/ppu/cell_state_emit.c
+++ b/src/gallium/drivers/cell/ppu/cell_state_emit.c
@@ -217,6 +217,7 @@ cell_emit_state(struct cell_context *cell)
texture->width[level] = cell->texture[i]->base.width[level];
texture->height[level] = cell->texture[i]->base.height[level];
}
+ texture->target = cell->texture[i]->base.target;
}
else {
uint level;
@@ -225,6 +226,7 @@ cell_emit_state(struct cell_context *cell)
texture->width[level] = 0;
texture->height[level] = 0;
}
+ texture->target = 0;
}
}
}
diff --git a/src/gallium/drivers/cell/ppu/cell_texture.c b/src/gallium/drivers/cell/ppu/cell_texture.c
index 4fd66bdea..4c92ef154 100644
--- a/src/gallium/drivers/cell/ppu/cell_texture.c
+++ b/src/gallium/drivers/cell/ppu/cell_texture.c
@@ -137,6 +137,7 @@ cell_texture_release(struct pipe_screen *screen,
*/
if (--(*pt)->refcount <= 0) {
struct cell_texture *ct = cell_texture(*pt);
+ uint i;
/*
DBG("%s deleting %p\n", __FUNCTION__, (void *) ct);
@@ -144,6 +145,12 @@ cell_texture_release(struct pipe_screen *screen,
pipe_buffer_reference(screen, &ct->buffer, NULL);
+ for (i = 0; i < CELL_MAX_TEXTURE_LEVELS; i++) {
+ if (ct->tiled_data[i]) {
+ FREE(ct->tiled_data[i]);
+ }
+ }
+
FREE(ct);
}
*pt = NULL;
@@ -204,27 +211,33 @@ static void
cell_twiddle_texture(struct pipe_screen *screen,
struct pipe_surface *surface)
{
- struct cell_texture *texture = cell_texture(surface->texture);
+ struct cell_texture *ct = cell_texture(surface->texture);
const uint level = surface->level;
- const uint texWidth = texture->base.width[level];
- const uint texHeight = texture->base.height[level];
+ const uint texWidth = ct->base.width[level];
+ const uint texHeight = ct->base.height[level];
const uint bufWidth = align(texWidth, TILE_SIZE);
const uint bufHeight = align(texHeight, TILE_SIZE);
const void *map = pipe_buffer_map(screen, surface->buffer,
PIPE_BUFFER_USAGE_CPU_READ);
const uint *src = (const uint *) ((const ubyte *) map + surface->offset);
- switch (texture->base.format) {
+ switch (ct->base.format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
- /* free old tiled data */
- if (texture->tiled_data[level]) {
- align_free(texture->tiled_data[level]);
+ {
+ int numFaces = ct->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
+ int offset = bufWidth * bufHeight * 4 * surface->face;
+ uint *dst;
+
+ if (!ct->tiled_data[level]) {
+ ct->tiled_data[level] =
+ align_malloc(bufWidth * bufHeight * 4 * numFaces, 16);
+ }
+
+ dst = (uint *) ((ubyte *) ct->tiled_data[level] + offset);
+
+ twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst,
+ surface->stride, src);
}
- /* alloc new tiled data */
- texture->tiled_data[level] = align_malloc(bufWidth * bufHeight * 4, 16);
- twiddle_image_uint(texWidth, texHeight, TILE_SIZE,
- texture->tiled_data[level],
- surface->stride, src);
break;
default:
printf("Cell: twiddle unsupported texture format\n");
diff --git a/src/gallium/drivers/cell/spu/spu_command.c b/src/gallium/drivers/cell/spu/spu_command.c
index b1efe97e7..c951fa6f3 100644
--- a/src/gallium/drivers/cell/spu/spu_command.c
+++ b/src/gallium/drivers/cell/spu/spu_command.c
@@ -301,7 +301,8 @@ cmd_state_framebuffer(const struct cell_command_framebuffer *cmd)
*/
static void
update_tex_masks(struct spu_texture *texture,
- const struct pipe_sampler_state *sampler)
+ const struct pipe_sampler_state *sampler,
+ uint unit)
{
uint i;
@@ -328,6 +329,11 @@ update_tex_masks(struct spu_texture *texture,
texture->level[i].scale_t = spu_splats(1.0f);
}
}
+
+ /* XXX temporary hack */
+ if (texture->target == PIPE_TEXTURE_CUBE) {
+ spu.sample_texture4[unit] = sample_texture4_cube;
+ }
}
@@ -378,7 +384,7 @@ cmd_state_sampler(const struct cell_command_sampler *sampler)
ASSERT(0);
}
- update_tex_masks(&spu.texture[unit], &spu.sampler[unit]);
+ update_tex_masks(&spu.texture[unit], &spu.sampler[unit], unit);
}
@@ -393,6 +399,7 @@ cmd_state_texture(const struct cell_command_texture *texture)
DEBUG_PRINTF("TEXTURE [%u]\n", texture->unit);
spu.texture[unit].max_level = 0;
+ spu.texture[unit].target = texture->target;
for (i = 0; i < CELL_MAX_TEXTURE_LEVELS; i++) {
uint width = texture->width[i];
@@ -408,6 +415,10 @@ cmd_state_texture(const struct cell_command_texture *texture)
spu.texture[unit].level[i].tiles_per_row =
(width + TILE_SIZE - 1) / TILE_SIZE;
+ spu.texture[unit].level[i].bytes_per_image =
+ 4 * ((width + TILE_SIZE - 1) & ~(TILE_SIZE-1))
+ * ((height + TILE_SIZE - 1) & ~(TILE_SIZE-1));
+
spu.texture[unit].level[i].max_s = spu_splats((int) width - 1);
spu.texture[unit].level[i].max_t = spu_splats((int) height - 1);
@@ -415,7 +426,7 @@ cmd_state_texture(const struct cell_command_texture *texture)
spu.texture[unit].max_level = i;
}
- update_tex_masks(&spu.texture[unit], &spu.sampler[unit]);
+ update_tex_masks(&spu.texture[unit], &spu.sampler[unit], unit);
//Debug=0;
}
diff --git a/src/gallium/drivers/cell/spu/spu_funcs.c b/src/gallium/drivers/cell/spu/spu_funcs.c
index 66b82f673..5c3ee305d 100644
--- a/src/gallium/drivers/cell/spu/spu_funcs.c
+++ b/src/gallium/drivers/cell/spu/spu_funcs.c
@@ -106,7 +106,7 @@ spu_txp(vector float s, vector float t, vector float r, vector float q,
unsigned unit)
{
struct vec_4x4 colors;
- spu.sample_texture4[unit](s, t, r, q, unit, 0, colors.v);
+ spu.sample_texture4[unit](s, t, r, q, unit, 0, 0, colors.v);
return colors;
}
diff --git a/src/gallium/drivers/cell/spu/spu_main.h b/src/gallium/drivers/cell/spu/spu_main.h
index 45c6f4ced..8781041bf 100644
--- a/src/gallium/drivers/cell/spu/spu_main.h
+++ b/src/gallium/drivers/cell/spu/spu_main.h
@@ -68,7 +68,7 @@ typedef void (*spu_sample_texture4_func)(vector float s,
vector float t,
vector float r,
vector float q,
- uint unit, uint level,
+ uint unit, uint level, uint face,
vector float colors[4]);
@@ -113,6 +113,7 @@ struct spu_texture_level
void *start;
ushort width, height;
ushort tiles_per_row;
+ uint bytes_per_image;
/** texcoord scale factors */
vector float scale_s, scale_t;
/** texcoord masks (if REPEAT then size-1, else ~0) */
@@ -126,6 +127,7 @@ struct spu_texture
{
struct spu_texture_level level[CELL_MAX_TEXTURE_LEVELS];
uint max_level;
+ uint target; /**< PIPE_TEXTURE_x */
} ALIGN16_ATTRIB;
diff --git a/src/gallium/drivers/cell/spu/spu_texture.c b/src/gallium/drivers/cell/spu/spu_texture.c
index b21c43a46..2570f02c7 100644
--- a/src/gallium/drivers/cell/spu/spu_texture.c
+++ b/src/gallium/drivers/cell/spu/spu_texture.c
@@ -48,6 +48,9 @@ invalidate_tex_cache(void)
uint bytes = 4 * spu.texture[unit].level[lvl].width
* spu.texture[unit].level[lvl].height;
+ if (spu.texture[unit].target == PIPE_TEXTURE_CUBE)
+ bytes *= 6;
+
spu_dcache_mark_dirty((unsigned) spu.texture[unit].level[lvl].start, bytes);
}
}
@@ -67,11 +70,11 @@ invalidate_tex_cache(void)
* a time.
*/
static void
-get_four_texels(uint unit, uint level, vec_int4 x, vec_int4 y,
+get_four_texels(uint unit, uint level, uint face, vec_int4 x, vec_int4 y,
vec_uint4 *texels)
{
const struct spu_texture_level *tlevel = &spu.texture[unit].level[level];
- const unsigned texture_ea = (uintptr_t) tlevel->start;
+ unsigned texture_ea = (uintptr_t) tlevel->start;
const vec_int4 tile_x = spu_rlmask(x, -5); /* tile_x = x / 32 */
const vec_int4 tile_y = spu_rlmask(y, -5); /* tile_y = y / 32 */
const qword offset_x = si_andi((qword) x, 0x1f); /* offset_x = x & 0x1f */
@@ -88,6 +91,8 @@ get_four_texels(uint unit, uint level, vec_int4 x, vec_int4 y,
vec_uint4 offset = (vec_uint4) si_a(tile_offset, texel_offset);
+ texture_ea = texture_ea + face * tlevel->bytes_per_image;
+
spu_dcache_fetch_unaligned((qword *) & texels[0],
texture_ea + spu_extract(offset, 0), 4);
spu_dcache_fetch_unaligned((qword *) & texels[1],
@@ -121,7 +126,8 @@ spu_clamp(vector signed int vec, vector signed int max)
void
sample_texture4_nearest(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4])
+ uint unit, uint level, uint face,
+ vector float colors[4])
{
const struct spu_texture_level *tlevel = &spu.texture[unit].level[level];
vector float ss = spu_mul(s, tlevel->scale_s);
@@ -138,7 +144,7 @@ sample_texture4_nearest(vector float s, vector float t,
is = spu_clamp(is, tlevel->max_s);
it = spu_clamp(it, tlevel->max_t);
- get_four_texels(unit, level, is, it, texels);
+ get_four_texels(unit, level, face, is, it, texels);
/* convert four packed ARGBA pixels to float RRRR,GGGG,BBBB,AAAA */
spu_unpack_A8R8G8B8_transpose4(texels, colors);
@@ -152,11 +158,14 @@ sample_texture4_nearest(vector float s, vector float t,
void
sample_texture4_bilinear(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4])
+ uint unit, uint level, uint face,
+ vector float colors[4])
{
const struct spu_texture_level *tlevel = &spu.texture[unit].level[level];
- vector float ss = spu_madd(s, tlevel->scale_s, spu_splats(-0.5f));
- vector float tt = spu_madd(t, tlevel->scale_t, spu_splats(-0.5f));
+ static const vector float half = {-0.5f, -0.5f, -0.5f, -0.5f};
+
+ vector float ss = spu_madd(s, tlevel->scale_s, half);
+ vector float tt = spu_madd(t, tlevel->scale_t, half);
vector signed int is0 = spu_convts(ss, 0);
vector signed int it0 = spu_convts(tt, 0);
@@ -179,10 +188,10 @@ sample_texture4_bilinear(vector float s, vector float t,
/* get packed int texels */
vector unsigned int texels[16];
- get_four_texels(unit, level, is0, it0, texels + 0); /* upper-left */
- get_four_texels(unit, level, is1, it0, texels + 4); /* upper-right */
- get_four_texels(unit, level, is0, it1, texels + 8); /* lower-left */
- get_four_texels(unit, level, is1, it1, texels + 12); /* lower-right */
+ get_four_texels(unit, level, face, is0, it0, texels + 0); /* upper-left */
+ get_four_texels(unit, level, face, is1, it0, texels + 4); /* upper-right */
+ get_four_texels(unit, level, face, is0, it1, texels + 8); /* lower-left */
+ get_four_texels(unit, level, face, is1, it1, texels + 12); /* lower-right */
/* XXX possibly rework following code to compute the weighted sample
* colors with integer arithmetic for fewer int->float conversions.
@@ -299,10 +308,12 @@ transpose(vector unsigned int *mOut0,
void
sample_texture4_bilinear_2(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4])
+ uint unit, uint level, uint face,
+ vector float colors[4])
{
const struct spu_texture_level *tlevel = &spu.texture[unit].level[level];
static const vector float half = {-0.5f, -0.5f, -0.5f, -0.5f};
+
/* Scale texcoords by size of texture, and add half pixel bias */
vector float ss = spu_madd(s, tlevel->scale_s, half);
vector float tt = spu_madd(t, tlevel->scale_t, half);
@@ -339,10 +350,10 @@ sample_texture4_bilinear_2(vector float s, vector float t,
/* get packed int texels */
vector unsigned int texels[16];
- get_four_texels(unit, level, is0, it0, texels + 0); /* upper-left */
- get_four_texels(unit, level, is1, it0, texels + 4); /* upper-right */
- get_four_texels(unit, level, is0, it1, texels + 8); /* lower-left */
- get_four_texels(unit, level, is1, it1, texels + 12); /* lower-right */
+ get_four_texels(unit, level, face, is0, it0, texels + 0); /* upper-left */
+ get_four_texels(unit, level, face, is1, it0, texels + 4); /* upper-right */
+ get_four_texels(unit, level, face, is0, it1, texels + 8); /* lower-left */
+ get_four_texels(unit, level, face, is1, it1, texels + 12); /* lower-right */
/* twiddle packed 32-bit BGRA pixels into RGBA as four unsigned ints */
{
@@ -433,7 +444,8 @@ compute_lambda(uint unit, vector float s, vector float t)
void
sample_texture4_lod(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level_ignored, vector float colors[4])
+ uint unit, uint level_ignored, uint face,
+ vector float colors[4])
{
/*
* Note that we're computing a lambda/lod here that's used for all
@@ -452,15 +464,136 @@ sample_texture4_lod(vector float s, vector float t,
if (lambda <= 0.0f) {
/* magnify */
- spu.mag_sample_texture4[unit](s, t, r, q, unit, 0, colors);
+ spu.mag_sample_texture4[unit](s, t, r, q, unit, 0, 0, colors);
}
else {
/* minify */
int level = (int) (lambda + 0.5f);
if (level > (int) spu.texture[unit].max_level)
level = spu.texture[unit].max_level;
- spu.min_sample_texture4[unit](s, t, r, q, unit, level, colors);
+ spu.min_sample_texture4[unit](s, t, r, q, unit, level, 0, colors);
/* XXX to do: mipmap level interpolation */
}
}
+
+/** XXX need a SIMD version of this */
+static unsigned
+choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
+{
+ /*
+ major axis
+ direction target sc tc ma
+ ---------- ------------------------------- --- --- ---
+ +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
+ -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
+ +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
+ -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
+ +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);
+ const float ary = fabsf(ry);
+ const float arz = fabsf(rz);
+ unsigned face;
+ float sc, tc, ma;
+
+ if (arx > ary && arx > arz) {
+ if (rx >= 0.0F) {
+ face = PIPE_TEX_FACE_POS_X;
+ sc = -rz;
+ tc = -ry;
+ ma = arx;
+ }
+ else {
+ face = PIPE_TEX_FACE_NEG_X;
+ sc = rz;
+ tc = -ry;
+ ma = arx;
+ }
+ }
+ else if (ary > arx && ary > arz) {
+ if (ry >= 0.0F) {
+ face = PIPE_TEX_FACE_POS_Y;
+ sc = rx;
+ tc = rz;
+ ma = ary;
+ }
+ else {
+ face = PIPE_TEX_FACE_NEG_Y;
+ sc = rx;
+ tc = -rz;
+ ma = ary;
+ }
+ }
+ else {
+ if (rz > 0.0F) {
+ face = PIPE_TEX_FACE_POS_Z;
+ sc = rx;
+ tc = -ry;
+ ma = arz;
+ }
+ else {
+ face = PIPE_TEX_FACE_NEG_Z;
+ sc = -rx;
+ tc = -ry;
+ ma = arz;
+ }
+ }
+
+ *newS = (sc / ma + 1.0F) * 0.5F;
+ *newT = (tc / ma + 1.0F) * 0.5F;
+
+ return face;
+}
+
+
+
+void
+sample_texture4_cube(vector float s, vector float t,
+ vector float r, vector float q,
+ uint unit, uint level, int face_ignored,
+ vector float colors[4])
+{
+ static const vector float zero = {0.0f, 0.0f, 0.0f, 0.0f};
+ uint p, faces[4];
+ float newS[4], newT[4];
+
+ /* Compute cube face referenced by the four sets of texcoords.
+ * XXX we should SIMD-ize this.
+ */
+ for (p = 0; p < 4; p++) {
+ float rx = spu_extract(s, p);
+ float ry = spu_extract(t, p);
+ float rz = spu_extract(r, p);
+ faces[p] = choose_cube_face(rx, ry, rz, &newS[p], &newT[p]);
+ }
+
+ if (faces[0] == faces[1] &&
+ faces[0] == faces[2] &&
+ faces[0] == faces[3]) {
+ /* GOOD! All four texcoords refer to the same cube face */
+ s = (vector float) {newS[0], newS[1], newS[2], newS[3]};
+ t = (vector float) {newT[0], newT[1], newT[2], newT[3]};
+ sample_texture4_nearest(s, t, zero, zero, unit, level, faces[0], colors);
+ }
+ else {
+ /* BAD! The four texcoords refer to different faces */
+ for (p = 0; p < 4; p++) {
+ vector float c[4];
+
+ sample_texture4_nearest(spu_splats(newS[p]), spu_splats(newT[p]),
+ zero, zero, unit, level, faces[p], c);
+
+ float red = spu_extract(c[0], p);
+ float green = spu_extract(c[1], p);
+ float blue = spu_extract(c[2], p);
+ float alpha = spu_extract(c[3], p);
+
+ colors[0] = spu_insert(red, colors[0], p);
+ colors[1] = spu_insert(green, colors[1], p);
+ colors[2] = spu_insert(blue, colors[2], p);
+ colors[3] = spu_insert(alpha, colors[3], p);
+ }
+ }
+}
diff --git a/src/gallium/drivers/cell/spu/spu_texture.h b/src/gallium/drivers/cell/spu/spu_texture.h
index ec06a50b4..08b891a4a 100644
--- a/src/gallium/drivers/cell/spu/spu_texture.h
+++ b/src/gallium/drivers/cell/spu/spu_texture.h
@@ -39,24 +39,35 @@ invalidate_tex_cache(void);
extern void
sample_texture4_nearest(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4]);
+ uint unit, uint level, uint face,
+ vector float colors[4]);
extern void
sample_texture4_bilinear(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4]);
+ uint unit, uint level, uint face,
+ vector float colors[4]);
extern void
sample_texture4_bilinear_2(vector float s, vector float t,
- vector float r, vector float q,
- uint unit, uint level, vector float colors[4]);
+ vector float r, vector float q,
+ uint unit, uint level, uint face,
+ vector float colors[4]);
extern void
sample_texture4_lod(vector float s, vector float t,
vector float r, vector float q,
- uint unit, uint level, vector float colors[4]);
+ uint unit, uint level, uint face,
+ vector float colors[4]);
+
+
+extern void
+sample_texture4_cube(vector float s, vector float t,
+ vector float r, vector float q,
+ uint unit, uint level_ignored, int face_ignored,
+ vector float colors[4]);
#endif /* SPU_TEXTURE_H */