From 192b7f20ebbe6e5ed7d7c8d8cb25ace019723689 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 24 Feb 2009 20:58:46 -0700 Subject: 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. --- src/gallium/drivers/cell/ppu/cell_context.h | 6 - src/gallium/drivers/cell/ppu/cell_fence.c | 12 +- src/gallium/drivers/cell/ppu/cell_state_emit.c | 18 +- src/gallium/drivers/cell/ppu/cell_texture.c | 332 ++++++++----------------- src/gallium/drivers/cell/ppu/cell_texture.h | 17 +- 5 files changed, 119 insertions(+), 266 deletions(-) diff --git a/src/gallium/drivers/cell/ppu/cell_context.h b/src/gallium/drivers/cell/ppu/cell_context.h index ca03dc15111..5c3188e7f9d 100644 --- a/src/gallium/drivers/cell/ppu/cell_context.h +++ b/src/gallium/drivers/cell/ppu/cell_context.h @@ -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 */ diff --git a/src/gallium/drivers/cell/ppu/cell_fence.c b/src/gallium/drivers/cell/ppu/cell_fence.c index 867b5dcaa09..32dbf5706c7 100644 --- a/src/gallium/drivers/cell/ppu/cell_fence.c +++ b/src/gallium/drivers/cell/ppu/cell_fence.c @@ -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); } } } diff --git a/src/gallium/drivers/cell/ppu/cell_state_emit.c b/src/gallium/drivers/cell/ppu/cell_state_emit.c index ff529fe22cb..9479c0898fd 100644 --- a/src/gallium/drivers/cell/ppu/cell_state_emit.c +++ b/src/gallium/drivers/cell/ppu/cell_state_emit.c @@ -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; diff --git a/src/gallium/drivers/cell/ppu/cell_texture.c b/src/gallium/drivers/cell/ppu/cell_texture.c index fa52e2cbea4..74724393f78 100644 --- a/src/gallium/drivers/cell/ppu/cell_texture.c +++ b/src/gallium/drivers/cell/ppu/cell_texture.c @@ -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 + size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size; + + ctrans->map = align_malloc(size, 16); + if (!ctrans->map) + return NULL; /* out of memory */ + + 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 { + // xxx fix + } } - - return map + cell_transfer(transfer)->offset + - transfer->y / transfer->block.height * transfer->stride + - transfer->x / transfer->block.width * transfer->block.size; + + 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_transfer_unmap(struct pipe_screen *screen, - struct pipe_transfer *transfer) + 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; + 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]; + + if (!ct->mapped) { + /* map now */ + ct->mapped = pipe_buffer_map(screen, ct->buffer, + PIPE_BUFFER_USAGE_CPU_READ); } -#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_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 { - return (void *) (map + surface->offset); + // xxx fix } } -} - - -static void -cell_surface_unmap(struct pipe_screen *screen, - struct pipe_surface *surface) -{ - struct cell_texture *ct = cell_texture(surface->texture); - - assert(ct); - pipe_buffer_unmap( screen, ct->buffer ); + 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; } diff --git a/src/gallium/drivers/cell/ppu/cell_texture.h b/src/gallium/drivers/cell/ppu/cell_texture.h index fc6486adbe6..3ffc0bfdb51 100644 --- a/src/gallium/drivers/cell/ppu/cell_texture.h +++ b/src/gallium/drivers/cell/ppu/cell_texture.h @@ -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; }; -- cgit v1.2.3