cell: overhaul cell teximage code

Updated to use the new pipe_transfer functions, etc.
Texturing is working again.  Though there's some bugs in mipmap texturing
but I believe those predate the pipe_transfer changes.
This commit is contained in:
Brian Paul
2009-02-24 20:58:46 -07:00
parent bd0370cd26
commit 192b7f20eb
5 changed files with 120 additions and 267 deletions
@@ -127,15 +127,9 @@ struct cell_context
struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
uint num_vertex_elements;
struct pipe_transfer *cbuf_transfer[PIPE_MAX_COLOR_BUFS];
struct pipe_transfer *zsbuf_transfer;
ubyte *cbuf_map[PIPE_MAX_COLOR_BUFS];
ubyte *zsbuf_map;
struct pipe_surface *tex_surf;
uint *tex_map;
uint dirty;
uint dirty_textures; /* bitmask of texture units */
uint dirty_samplers; /* bitmask of sampler units */
+4 -8
View File
@@ -153,16 +153,12 @@ cell_add_fenced_textures(struct cell_context *cell)
for (i = 0; i < cell->num_textures; i++) {
struct cell_texture *ct = cell->texture[i];
if (ct) {
uint level;
for (level = 0; level < CELL_MAX_TEXTURE_LEVELS; level++) {
if (ct->tiled_buffer[level]) {
#if 0
printf("Adding texture %p buffer %p to list\n",
ct, ct->tiled_buffer[level]);
printf("Adding texture %p buffer %p to list\n",
ct, ct->tiled_buffer[level]);
#endif
cell_add_buffer_to_list(cell, list, ct->tiled_buffer[level]);
}
}
if (ct->buffer)
cell_add_buffer_to_list(cell, list, ct->buffer);
}
}
}
+11 -7
View File
@@ -287,19 +287,23 @@ cell_emit_state(struct cell_context *cell)
for (i = 0;i < CELL_MAX_SAMPLERS; i++) {
if (cell->dirty_textures & (1 << i)) {
STATIC_ASSERT(sizeof(struct cell_command_texture) % 16 == 0);
struct cell_command_texture *texture
= (struct cell_command_texture *)cell_batch_alloc16(cell, sizeof(*texture));
struct cell_command_texture *texture =
(struct cell_command_texture *)
cell_batch_alloc16(cell, sizeof(*texture));
texture->opcode[0] = CELL_CMD_STATE_TEXTURE;
texture->unit = i;
if (cell->texture[i]) {
struct cell_texture *ct = cell->texture[i];
uint level;
for (level = 0; level < CELL_MAX_TEXTURE_LEVELS; level++) {
texture->start[level] = cell->texture[i]->tiled_mapped[level];
texture->width[level] = cell->texture[i]->base.width[level];
texture->height[level] = cell->texture[i]->base.height[level];
texture->depth[level] = cell->texture[i]->base.depth[level];
texture->start[level] = (ct->mapped +
ct->level_offset[level]);
texture->width[level] = ct->base.width[level];
texture->height[level] = ct->base.height[level];
texture->depth[level] = ct->base.depth[level];
}
texture->target = cell->texture[i]->base.target;
texture->target = ct->base.target;
}
else {
uint level;
+99 -235
View File
@@ -62,7 +62,7 @@ cell_texture_layout(struct cell_texture *ct)
ct->buffer_size = 0;
for ( level = 0 ; level <= pt->last_level ; level++ ) {
for (level = 0; level <= pt->last_level; level++) {
unsigned size;
unsigned w_tile, h_tile;
@@ -90,7 +90,7 @@ cell_texture_layout(struct cell_texture *ct)
ct->buffer_size += size;
width = minify(width);
width = minify(width);
height = minify(height);
depth = minify(depth);
}
@@ -131,33 +131,19 @@ cell_texture_release(struct pipe_screen *screen,
if (!*pt)
return;
/*
DBG("%s %p refcount will be %d\n",
__FUNCTION__, (void *) *pt, (*pt)->refcount - 1);
*/
if (--(*pt)->refcount <= 0) {
/* Delete this texture now.
* But note that the underlying pipe_buffer may linger...
*/
struct cell_texture *ct = cell_texture(*pt);
uint i;
/*
DBG("%s deleting %p\n", __FUNCTION__, (void *) ct);
*/
if (ct->mapped) {
pipe_buffer_unmap(screen, ct->buffer);
ct->mapped = NULL;
}
pipe_buffer_reference(screen, &ct->buffer, NULL);
for (i = 0; i < CELL_MAX_TEXTURE_LEVELS; i++) {
/* Unreference the tiled image buffer.
* It may not actually be deleted until a fence is hit.
*/
if (ct->tiled_buffer[i]) {
ct->tiled_mapped[i] = NULL;
pipe_buffer_reference(screen, &ct->tiled_buffer[i], NULL);
}
}
FREE(ct);
}
*pt = NULL;
@@ -294,107 +280,6 @@ untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst,
}
/**
* Convert linear texture image data to tiled format for SPU usage.
*/
static void
cell_twiddle_texture(struct pipe_screen *screen,
struct pipe_surface *surface)
{
#if 0 // XXX fix me
struct cell_texture *ct = cell_texture(surface->texture);
const uint level = surface->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 = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_READ);
const uint *src = (const uint *) map;
switch (ct->base.format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
case PIPE_FORMAT_B8G8R8A8_UNORM:
case PIPE_FORMAT_S8Z24_UNORM:
{
int numFaces = ct->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
int offset = bufWidth * bufHeight * 4 * surface->face;
uint *dst;
if (!ct->tiled_buffer[level]) {
/* allocate buffer for tiled data now */
struct pipe_winsys *ws = screen->winsys;
uint bytes = bufWidth * bufHeight * 4 * numFaces;
ct->tiled_buffer[level] =
ws->buffer_create(ws, 16, PIPE_BUFFER_USAGE_PIXEL, bytes);
/* and map it */
ct->tiled_mapped[level] =
ws->buffer_map(ws, ct->tiled_buffer[level],
PIPE_BUFFER_USAGE_GPU_READ);
}
dst = (uint *) ((ubyte *) ct->tiled_mapped[level] + offset);
twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst,
surface->stride, src);
}
break;
default:
printf("Cell: twiddle unsupported texture format %s\n",
pf_name(ct->base.format));
}
screen->surface_unmap(screen, surface);
#endif
}
/**
* Convert SPU tiled texture image data to linear format for app usage.
*/
static void
cell_untwiddle_texture(struct pipe_screen *screen,
struct pipe_surface *surface)
{
#if 0 // XXX fix me
struct cell_texture *ct = cell_texture(surface->texture);
const uint level = surface->level;
const uint texWidth = ct->base.width[level];
const uint texHeight = ct->base.height[level];
const void *map = screen->surface_map(screen, surface, PIPE_BUFFER_USAGE_CPU_READ);
const uint *src = (const uint *) ((const ubyte *) map + surface->offset);
switch (ct->base.format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
case PIPE_FORMAT_B8G8R8A8_UNORM:
case PIPE_FORMAT_S8Z24_UNORM:
{
int numFaces = ct->base.target == PIPE_TEXTURE_CUBE ? 6 : 1;
int offset = surface->stride * texHeight * 4 * surface->face;
uint *dst;
if (!ct->untiled_data[level]) {
ct->untiled_data[level] =
align_malloc(surface->stride * texHeight * 4 * numFaces, 16);
}
dst = (uint *) ((ubyte *) ct->untiled_data[level] + offset);
untwiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst,
surface->stride, src);
}
break;
default:
{
ct->untiled_data[level] = NULL;
printf("Cell: untwiddle unsupported texture format %s\n",
pf_name(ct->base.format));
}
}
screen->surface_unmap(screen, surface);
#endif
}
static struct pipe_surface *
cell_get_tex_surface(struct pipe_screen *screen,
struct pipe_texture *pt,
@@ -409,38 +294,25 @@ cell_get_tex_surface(struct pipe_screen *screen,
ps->refcount = 1;
pipe_texture_reference(&ps->texture, pt);
ps->format = pt->format;
//ps->block = pt->block;
ps->width = pt->width[level];
ps->height = pt->height[level];
//ps->nblocksx = pt->nblocksx[level];
//ps->nblocksy = pt->nblocksy[level];
//ps->stride = ct->stride[level];
ps->offset = ct->level_offset[level];
ps->usage = usage;
/* XXX may need to override usage flags (see sp_texture.c) */
pipe_texture_reference(&ps->texture, pt);
ps->usage = usage;
ps->face = face;
ps->level = level;
ps->zslice = zslice;
if (pt->target == PIPE_TEXTURE_CUBE || pt->target == PIPE_TEXTURE_3D) {
#if 0 // XXX fix me
ps->offset += ((pt->target == PIPE_TEXTURE_CUBE) ? face : zslice) *
ps->nblocksy *
ps->stride;
#endif
if (pt->target == PIPE_TEXTURE_CUBE) {
ps->offset += face * pt->nblocksy[level] * ct->stride[level];
}
else if (pt->target == PIPE_TEXTURE_3D) {
ps->offset += zslice * pt->nblocksy[level] * ct->stride[level];
}
else {
assert(face == 0);
assert(zslice == 0);
}
if (ps->usage & PIPE_BUFFER_USAGE_CPU_READ) {
/* convert from tiled to linear layout */
cell_untwiddle_texture(screen, ps);
}
}
return ps;
}
@@ -450,24 +322,8 @@ static void
cell_tex_surface_release(struct pipe_screen *screen,
struct pipe_surface **s)
{
struct cell_texture *ct = cell_texture((*s)->texture);
const uint level = (*s)->level;
struct pipe_surface *surf = *s;
if ((surf->usage & PIPE_BUFFER_USAGE_CPU_READ) && (ct->untiled_data[level]))
{
align_free(ct->untiled_data[level]);
ct->untiled_data[level] = NULL;
}
if ((ct->base.tex_usage & PIPE_TEXTURE_USAGE_SAMPLER) &&
(surf->usage & PIPE_BUFFER_USAGE_CPU_WRITE)) {
/* convert from linear to tiled layout */
cell_twiddle_texture(screen, surf);
}
/* XXX if done rendering to teximage, re-tile */
if (--surf->refcount == 0) {
pipe_texture_reference(&surf->texture, NULL);
FREE(surf);
@@ -476,6 +332,11 @@ cell_tex_surface_release(struct pipe_screen *screen,
}
/**
* Create new pipe_transfer object.
* This is used by the user to put tex data into a texture (and get it
* back out for glGetTexImage).
*/
static struct pipe_transfer *
cell_get_tex_transfer(struct pipe_screen *screen,
struct pipe_texture *texture,
@@ -485,14 +346,13 @@ cell_get_tex_transfer(struct pipe_screen *screen,
{
struct cell_texture *ct = cell_texture(texture);
struct cell_transfer *ctrans;
struct pipe_transfer *pt;
assert(texture);
assert(level <= texture->last_level);
ctrans = CALLOC_STRUCT(cell_transfer);
pt = &ctrans->base;
if (ctrans) {
struct pipe_transfer *pt = &ctrans->base;
pt->refcount = 1;
pipe_texture_reference(&pt->texture, texture);
pt->format = texture->format;
@@ -504,23 +364,26 @@ cell_get_tex_transfer(struct pipe_screen *screen,
pt->nblocksx = texture->nblocksx[level];
pt->nblocksy = texture->nblocksy[level];
pt->stride = ct->stride[level];
ctrans->offset = ct->level_offset[level];
pt->usage = usage;
pt->face = face;
pt->level = level;
pt->zslice = zslice;
if (texture->target == PIPE_TEXTURE_CUBE ||
texture->target == PIPE_TEXTURE_3D) {
ctrans->offset += ((texture->target == PIPE_TEXTURE_CUBE) ? face :
zslice) * pt->nblocksy * pt->stride;
ctrans->offset = ct->level_offset[level];
if (texture->target == PIPE_TEXTURE_CUBE) {
ctrans->offset += face * pt->nblocksy * pt->stride;
}
else if (texture->target == PIPE_TEXTURE_3D) {
ctrans->offset += zslice * pt->nblocksy * pt->stride;
}
else {
assert(face == 0);
assert(zslice == 0);
}
return pt;
}
return pt;
return NULL;
}
@@ -542,16 +405,23 @@ cell_tex_transfer_release(struct pipe_screen *screen,
}
/**
* Return pointer to texture image data in linear layout.
*/
static void *
cell_transfer_map( struct pipe_screen *screen,
struct pipe_transfer *transfer )
cell_transfer_map(struct pipe_screen *screen, struct pipe_transfer *transfer)
{
ubyte *map;
struct cell_texture *spt;
unsigned flags = 0;
struct cell_transfer *ctrans = cell_transfer(transfer);
struct pipe_texture *pt = transfer->texture;
struct cell_texture *ct = cell_texture(pt);
const uint level = ctrans->base.level;
const uint texWidth = pt->width[level];
const uint texHeight = pt->height[level];
const uint stride = ct->stride[level];
unsigned flags = 0x0;
unsigned size;
assert(transfer->texture);
spt = cell_texture(transfer->texture);
if (transfer->usage != PIPE_TRANSFER_READ) {
flags |= PIPE_BUFFER_USAGE_CPU_WRITE;
@@ -561,89 +431,82 @@ cell_transfer_map( struct pipe_screen *screen,
flags |= PIPE_BUFFER_USAGE_CPU_READ;
}
map = pipe_buffer_map(screen, spt->buffer, flags);
if (map == NULL)
return NULL;
if (!ct->mapped) {
/* map now */
ct->mapped = pipe_buffer_map(screen, ct->buffer, flags);
}
/* May want to different things here depending on read/write nature
* of the map:
/*
* Create a buffer of ordinary memory for the linear texture.
* This is the memory that the user will read/write.
*/
if (transfer->texture && transfer->usage != PIPE_TRANSFER_READ)
{
/* Do something to notify sharing contexts of a texture change.
* In cell, that would mean flushing the texture cache.
*/
#if 00
cell_screen(screen)->timestamp++;
#endif
}
return map + cell_transfer(transfer)->offset +
transfer->y / transfer->block.height * transfer->stride +
transfer->x / transfer->block.width * transfer->block.size;
}
size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size;
ctrans->map = align_malloc(size, 16);
if (!ctrans->map)
return NULL; /* out of memory */
static void
cell_transfer_unmap(struct pipe_screen *screen,
struct pipe_transfer *transfer)
{
struct cell_texture *spt;
assert(transfer->texture);
spt = cell_texture(transfer->texture);
pipe_buffer_unmap( screen, spt->buffer );
}
static void *
cell_surface_map(struct pipe_screen *screen,
struct pipe_surface *surface,
unsigned flags)
{
ubyte *map;
struct cell_texture *ct = cell_texture(surface->texture);
const uint level = surface->level;
assert(ct);
#if 0
if (flags & ~surface->usage) {
assert(0);
return NULL;
}
#endif
map = pipe_buffer_map( screen, ct->buffer, flags );
if (map == NULL) {
return NULL;
}
else {
if ((surface->usage & PIPE_BUFFER_USAGE_CPU_READ) &&
(ct->untiled_data[level])) {
return (void *) ((ubyte *) ct->untiled_data[level] + surface->offset);
if (transfer->usage & PIPE_TRANSFER_READ) {
/* need to untwiddle the texture to make a linear version */
const uint bpp = pf_get_size(ct->base.format);
if (bpp == 4) {
const uint *src = (uint *) (ct->mapped + ctrans->offset);
uint *dst = ctrans->map;
untwiddle_image_uint(texWidth, texHeight, TILE_SIZE,
dst, stride, src);
}
else {
return (void *) (map + surface->offset);
// xxx fix
}
}
return ctrans->map;
}
/**
* Called when user is done reading/writing texture data.
* If new data was written, this is where we convert the linear data
* to tiled data.
*/
static void
cell_surface_unmap(struct pipe_screen *screen,
struct pipe_surface *surface)
cell_transfer_unmap(struct pipe_screen *screen,
struct pipe_transfer *transfer)
{
struct cell_texture *ct = cell_texture(surface->texture);
struct cell_transfer *ctrans = cell_transfer(transfer);
struct pipe_texture *pt = transfer->texture;
struct cell_texture *ct = cell_texture(pt);
const uint level = ctrans->base.level;
const uint texWidth = pt->width[level];
const uint texHeight = pt->height[level];
const uint stride = ct->stride[level];
assert(ct);
if (!ct->mapped) {
/* map now */
ct->mapped = pipe_buffer_map(screen, ct->buffer,
PIPE_BUFFER_USAGE_CPU_READ);
}
pipe_buffer_unmap( screen, ct->buffer );
if (transfer->usage & PIPE_TRANSFER_WRITE) {
/* The user wrote new texture data into the mapped buffer.
* We need to convert the new linear data into the twiddled/tiled format.
*/
const uint bpp = pf_get_size(ct->base.format);
if (bpp == 4) {
const uint *src = ctrans->map;
uint *dst = (uint *) (ct->mapped + ctrans->offset);
twiddle_image_uint(texWidth, texHeight, TILE_SIZE, dst, stride, src);
}
else {
// xxx fix
}
}
align_free(ctrans->map);
ctrans->map = NULL;
}
void
cell_init_screen_texture_funcs(struct pipe_screen *screen)
{
@@ -655,6 +518,7 @@ cell_init_screen_texture_funcs(struct pipe_screen *screen)
screen->get_tex_transfer = cell_get_tex_transfer;
screen->tex_transfer_release = cell_tex_transfer_release;
screen->transfer_map = cell_transfer_map;
screen->transfer_unmap = cell_transfer_unmap;
}
+6 -11
View File
@@ -43,20 +43,14 @@ struct cell_texture
unsigned long level_offset[CELL_MAX_TEXTURE_LEVELS];
unsigned long stride[CELL_MAX_TEXTURE_LEVELS];
/* The data is held here:
*/
/** The tiled texture data is held in this buffer */
struct pipe_buffer *buffer;
unsigned long buffer_size;
/** Texture data in tiled layout is held here */
struct pipe_buffer *tiled_buffer[CELL_MAX_TEXTURE_LEVELS];
/** Mapped, tiled texture data */
void *tiled_mapped[CELL_MAX_TEXTURE_LEVELS];
struct pipe_transfer *transfer;
/** The original, linear texture data */
void *untiled_data[CELL_MAX_TEXTURE_LEVELS];
/** The buffer above, mapped. This is the memory from which the
* SPUs will fetch texels. This texture data is in the tiled layout.
*/
ubyte *mapped;
};
@@ -65,6 +59,7 @@ struct cell_transfer
struct pipe_transfer base;
unsigned long offset;
void *map;
};