diff options
Diffstat (limited to 'src/gallium/drivers/cell/ppu/cell_texture.c')
-rw-r--r-- | src/gallium/drivers/cell/ppu/cell_texture.c | 587 |
1 files changed, 430 insertions, 157 deletions
diff --git a/src/gallium/drivers/cell/ppu/cell_texture.c b/src/gallium/drivers/cell/ppu/cell_texture.c index b6590dfb86..fa52e2cbea 100644 --- a/src/gallium/drivers/cell/ppu/cell_texture.c +++ b/src/gallium/drivers/cell/ppu/cell_texture.c @@ -28,12 +28,13 @@ * Authors: * Keith Whitwell <keith@tungstengraphics.com> * Michel Dänzer <michel@tungstengraphics.com> + * Brian Paul */ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "pipe/p_winsys.h" +#include "pipe/internal/p_winsys_screen.h" #include "util/u_math.h" #include "util/u_memory.h" @@ -42,30 +43,31 @@ #include "cell_texture.h" -/* Simple, maximally packed layout. - */ -static unsigned minify( unsigned d ) +static unsigned +minify(unsigned d) { return MAX2(1, d>>1); } static void -cell_texture_layout(struct cell_texture * spt) +cell_texture_layout(struct cell_texture *ct) { - struct pipe_texture *pt = &spt->base; + struct pipe_texture *pt = &ct->base; unsigned level; unsigned width = pt->width[0]; unsigned height = pt->height[0]; unsigned depth = pt->depth[0]; - spt->buffer_size = 0; + ct->buffer_size = 0; for ( level = 0 ; level <= pt->last_level ; level++ ) { unsigned size; unsigned w_tile, h_tile; + assert(level < CELL_MAX_TEXTURE_LEVELS); + /* width, height, rounded up to tile size */ w_tile = align(width, TILE_SIZE); h_tile = align(height, TILE_SIZE); @@ -76,9 +78,9 @@ cell_texture_layout(struct cell_texture * spt) pt->nblocksx[level] = pf_get_nblocksx(&pt->block, w_tile); pt->nblocksy[level] = pf_get_nblocksy(&pt->block, h_tile); - spt->stride[level] = pt->nblocksx[level] * pt->block.size; + ct->stride[level] = pt->nblocksx[level] * pt->block.size; - spt->level_offset[level] = spt->buffer_size; + ct->level_offset[level] = ct->buffer_size; size = pt->nblocksx[level] * pt->nblocksy[level] * pt->block.size; if (pt->target == PIPE_TEXTURE_CUBE) @@ -86,7 +88,7 @@ cell_texture_layout(struct cell_texture * spt) else size *= depth; - spt->buffer_size += size; + ct->buffer_size += size; width = minify(width); height = minify(height); @@ -100,26 +102,25 @@ cell_texture_create(struct pipe_screen *screen, const struct pipe_texture *templat) { struct pipe_winsys *ws = screen->winsys; - struct cell_texture *spt = CALLOC_STRUCT(cell_texture); - if (!spt) + struct cell_texture *ct = CALLOC_STRUCT(cell_texture); + if (!ct) return NULL; - spt->base = *templat; - spt->base.refcount = 1; - spt->base.screen = screen; + ct->base = *templat; + ct->base.refcount = 1; + ct->base.screen = screen; - cell_texture_layout(spt); + cell_texture_layout(ct); - spt->buffer = ws->buffer_create(ws, 32, - PIPE_BUFFER_USAGE_PIXEL, - spt->buffer_size); + ct->buffer = ws->buffer_create(ws, 32, PIPE_BUFFER_USAGE_PIXEL, + ct->buffer_size); - if (!spt->buffer) { - FREE(spt); + if (!ct->buffer) { + FREE(ct); return NULL; } - return &spt->base; + return &ct->base; } @@ -135,244 +136,514 @@ cell_texture_release(struct pipe_screen *screen, __FUNCTION__, (void *) *pt, (*pt)->refcount - 1); */ if (--(*pt)->refcount <= 0) { - struct cell_texture *spt = cell_texture(*pt); + /* 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 *) spt); + DBG("%s deleting %p\n", __FUNCTION__, (void *) ct); */ - pipe_buffer_reference(screen, &spt->buffer, 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(spt); + FREE(ct); } *pt = NULL; } -#if 0 + +/** + * Convert image from linear layout to tiled layout. 4-byte pixels. + */ static void -cell_texture_update(struct pipe_context *pipe, struct pipe_texture *texture, - uint face, uint levelsMask) +twiddle_image_uint(uint w, uint h, uint tile_size, uint *dst, + uint src_stride, const uint *src) { - /* XXX TO DO: re-tile the texture data ... */ + const uint tile_size2 = tile_size * tile_size; + const uint h_t = (h + tile_size - 1) / tile_size; + const uint w_t = (w + tile_size - 1) / tile_size; -} -#endif + uint it, jt; /* tile counters */ + uint i, j; /* intra-tile counters */ + src_stride /= 4; /* convert from bytes to pixels */ -static struct pipe_surface * -cell_get_tex_surface(struct pipe_screen *screen, - struct pipe_texture *pt, - unsigned face, unsigned level, unsigned zslice, - unsigned usage) -{ - struct pipe_winsys *ws = screen->winsys; - struct cell_texture *spt = cell_texture(pt); - struct pipe_surface *ps; + /* loop over dest tiles */ + for (it = 0; it < h_t; it++) { + for (jt = 0; jt < w_t; jt++) { + /* start of dest tile: */ + uint *tdst = dst + (it * w_t + jt) * tile_size2; - ps = ws->surface_alloc(ws); - if (ps) { - assert(ps->refcount); - assert(ps->winsys); - winsys_buffer_reference(ws, &ps->buffer, spt->buffer); - 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 = spt->stride[level]; - ps->offset = spt->level_offset[level]; - ps->usage = usage; + /* compute size of this tile (may be smaller than tile_size) */ + /* XXX note: a compiler bug was found here. That's why the code + * looks as it does. + */ + uint tile_width = w - jt * tile_size; + tile_width = MIN2(tile_width, tile_size); + uint tile_height = h - it * tile_size; + tile_height = MIN2(tile_height, tile_size); - /* XXX may need to override usage flags (see sp_texture.c) */ + /* loop over texels in the tile */ + for (i = 0; i < tile_height; i++) { + for (j = 0; j < tile_width; j++) { + const uint srci = it * tile_size + i; + const uint srcj = jt * tile_size + j; + ASSERT(srci < h); + ASSERT(srcj < w); + tdst[i * tile_size + j] = src[srci * src_stride + srcj]; + } + } + } + } +} - pipe_texture_reference(&ps->texture, pt); - ps->face = face; - ps->level = level; - ps->zslice = zslice; - if (pt->target == PIPE_TEXTURE_CUBE || pt->target == PIPE_TEXTURE_3D) { - ps->offset += ((pt->target == PIPE_TEXTURE_CUBE) ? face : zslice) * - ps->nblocksy * - ps->stride; - } - else { - assert(face == 0); - assert(zslice == 0); +/** + * For Cell. Basically, rearrange the pixels/quads from this layout: + * +--+--+--+--+ + * |p0|p1|p2|p3|.... + * +--+--+--+--+ + * + * to this layout: + * +--+--+ + * |p0|p1|.... + * +--+--+ + * |p2|p3| + * +--+--+ + */ +static void +twiddle_tile(const uint *tileIn, uint *tileOut) +{ + int y, x; + + for (y = 0; y < TILE_SIZE; y+=2) { + for (x = 0; x < TILE_SIZE; x+=2) { + int k = 4 * (y/2 * TILE_SIZE/2 + x/2); + tileOut[y * TILE_SIZE + (x + 0)] = tileIn[k]; + tileOut[y * TILE_SIZE + (x + 1)] = tileIn[k+1]; + tileOut[(y + 1) * TILE_SIZE + (x + 0)] = tileIn[k+2]; + tileOut[(y + 1) * TILE_SIZE + (x + 1)] = tileIn[k+3]; } } - return ps; } - /** - * Copy tile data from linear layout to tiled layout. - * XXX this should be rolled into the future surface-creation code. - * XXX also need "untile" code... + * Convert image from tiled layout to linear layout. 4-byte pixels. */ static void -tile_copy_data(uint w, uint h, uint tile_size, uint *dst, const uint *src) +untwiddle_image_uint(uint w, uint h, uint tile_size, uint *dst, + uint dst_stride, const uint *src) { const uint tile_size2 = tile_size * tile_size; - const uint h_t = h / tile_size, w_t = w / tile_size; - + const uint h_t = (h + tile_size - 1) / tile_size; + const uint w_t = (w + tile_size - 1) / tile_size; + uint *tile_buf; uint it, jt; /* tile counters */ uint i, j; /* intra-tile counters */ - /* loop over dest tiles */ + dst_stride /= 4; /* convert from bytes to pixels */ + + tile_buf = align_malloc(tile_size * tile_size * 4, 16); + + /* loop over src tiles */ for (it = 0; it < h_t; it++) { for (jt = 0; jt < w_t; jt++) { - /* start of dest tile: */ - uint *tdst = dst + (it * w_t + jt) * tile_size2; + /* start of src tile: */ + const uint *tsrc = src + (it * w_t + jt) * tile_size2; + + twiddle_tile(tsrc, tile_buf); + tsrc = tile_buf; + + /* compute size of this tile (may be smaller than tile_size) */ + /* XXX note: a compiler bug was found here. That's why the code + * looks as it does. + */ + uint tile_width = w - jt * tile_size; + tile_width = MIN2(tile_width, tile_size); + uint tile_height = h - it * tile_size; + tile_height = MIN2(tile_height, tile_size); + /* loop over texels in the tile */ - for (i = 0; i < tile_size; i++) { - for (j = 0; j < tile_size; j++) { - const uint srci = it * tile_size + i; - const uint srcj = jt * tile_size + j; - *tdst++ = src[srci * w + srcj]; + for (i = 0; i < tile_height; i++) { + for (j = 0; j < tile_width; j++) { + uint dsti = it * tile_size + i; + uint dstj = jt * tile_size + j; + ASSERT(dsti < h); + ASSERT(dstj < w); + dst[dsti * dst_stride + dstj] = tsrc[i * tile_size + j]; } } } } -} + align_free(tile_buf); +} /** * Convert linear texture image data to tiled format for SPU usage. - * XXX recast this in terms of pipe_surfaces (aka texture views). */ static void -cell_tile_texture(struct cell_context *cell, - struct cell_texture *texture) +cell_twiddle_texture(struct pipe_screen *screen, + struct pipe_surface *surface) { - struct pipe_screen *screen = cell->pipe.screen; - uint face = 0, level = 0, zslice = 0; - struct pipe_surface *surf; - const uint w = texture->base.width[0], h = texture->base.height[0]; - const uint *src; - - /* temporary restrictions: */ - assert(w >= TILE_SIZE); - assert(h >= TILE_SIZE); - assert(w % TILE_SIZE == 0); - assert(h % TILE_SIZE == 0); - - surf = screen->get_tex_surface(screen, &texture->base, face, level, zslice, - PIPE_BUFFER_USAGE_CPU_WRITE); - ASSERT(surf); - - src = (const uint *) pipe_surface_map(surf, PIPE_BUFFER_USAGE_CPU_WRITE); - - if (texture->tiled_data) { - align_free(texture->tiled_data); +#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)); } - texture->tiled_data = align_malloc(w * h * 4, 16); - tile_copy_data(w, h, TILE_SIZE, texture->tiled_data, src); + screen->surface_unmap(screen, surface); +#endif +} + - pipe_surface_unmap(surf); +/** + * 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); + } - pipe_surface_reference(&surf, NULL); + 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 } -void -cell_update_texture_mapping(struct cell_context *cell) +static struct pipe_surface * +cell_get_tex_surface(struct pipe_screen *screen, + struct pipe_texture *pt, + unsigned face, unsigned level, unsigned zslice, + unsigned usage) { -#if 0 - uint face = 0, level = 0, zslice = 0; + struct cell_texture *ct = cell_texture(pt); + struct pipe_surface *ps; + + ps = CALLOC_STRUCT(pipe_surface); + if (ps) { + 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->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 - uint i; + } + else { + assert(face == 0); + assert(zslice == 0); + } - for (i = 0; i < CELL_MAX_SAMPLERS; i++) { - if (cell->texture[i]) - cell_tile_texture(cell, cell->texture[i]); + if (ps->usage & PIPE_BUFFER_USAGE_CPU_READ) { + /* convert from tiled to linear layout */ + cell_untwiddle_texture(screen, ps); + } } + return ps; +} -#if 0 - if (cell->tex_surf && cell->tex_map) { - pipe_surface_unmap(cell->tex_surf); - cell->tex_map = NULL; + +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; } - /* XXX free old surface */ + 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); + } - cell->tex_surf = cell_get_tex_surface(&cell->pipe, - &cell->texture[0]->base, - face, level, zslice); + /* XXX if done rendering to teximage, re-tile */ - cell->tex_map = pipe_surface_map(cell->tex_surf); -#endif + if (--surf->refcount == 0) { + pipe_texture_reference(&surf->texture, NULL); + FREE(surf); + } + *s = NULL; +} + + +static struct pipe_transfer * +cell_get_tex_transfer(struct pipe_screen *screen, + struct pipe_texture *texture, + unsigned face, unsigned level, unsigned zslice, + enum pipe_transfer_usage usage, + unsigned x, unsigned y, unsigned w, unsigned h) +{ + 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) { + pt->refcount = 1; + pipe_texture_reference(&pt->texture, texture); + pt->format = texture->format; + pt->block = texture->block; + pt->x = x; + pt->y = y; + pt->width = w; + pt->height = h; + 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; + } + else { + assert(face == 0); + assert(zslice == 0); + } + } + return pt; } static void -cell_tex_surface_release(struct pipe_screen *screen, - struct pipe_surface **s) +cell_tex_transfer_release(struct pipe_screen *screen, + struct pipe_transfer **t) { + struct cell_transfer *transfer = cell_transfer(*t); /* Effectively do the texture_update work here - if texture images * needed post-processing to put them into hardware layout, this is - * where it would happen. For softpipe, nothing to do. + * where it would happen. For cell, nothing to do. */ - assert ((*s)->texture); - pipe_texture_reference(&(*s)->texture, NULL); - - screen->winsys->surface_release(screen->winsys, s); + assert (transfer->base.texture); + if (--transfer->base.refcount == 0) { + pipe_texture_reference(&transfer->base.texture, NULL); + FREE(transfer); + } + *t = NULL; } static void * -cell_surface_map( struct pipe_screen *screen, - struct pipe_surface *surface, - unsigned flags ) +cell_transfer_map( struct pipe_screen *screen, + struct pipe_transfer *transfer ) { ubyte *map; + struct cell_texture *spt; + unsigned flags = 0; - if (flags & ~surface->usage) { - assert(0); - return NULL; + assert(transfer->texture); + spt = cell_texture(transfer->texture); + + if (transfer->usage != PIPE_TRANSFER_READ) { + flags |= PIPE_BUFFER_USAGE_CPU_WRITE; } - map = pipe_buffer_map( screen, surface->buffer, flags ); + if (transfer->usage != PIPE_TRANSFER_WRITE) { + flags |= PIPE_BUFFER_USAGE_CPU_READ; + } + + map = pipe_buffer_map(screen, spt->buffer, flags); if (map == NULL) return NULL; /* May want to different things here depending on read/write nature * of the map: */ - if (surface->texture && - (flags & PIPE_BUFFER_USAGE_CPU_WRITE)) + if (transfer->texture && transfer->usage != PIPE_TRANSFER_READ) { /* Do something to notify sharing contexts of a texture change. - * In softpipe, that would mean flushing the texture cache. + * In cell, that would mean flushing the texture cache. */ -#if 0 +#if 00 cell_screen(screen)->timestamp++; #endif } - return map + surface->offset; + return map + cell_transfer(transfer)->offset + + transfer->y / transfer->block.height * transfer->stride + + transfer->x / transfer->block.width * transfer->block.size; } static void -cell_surface_unmap(struct pipe_screen *screen, - struct pipe_surface *surface) +cell_transfer_unmap(struct pipe_screen *screen, + struct pipe_transfer *transfer) { - pipe_buffer_unmap( screen, surface->buffer ); + struct cell_texture *spt; + + assert(transfer->texture); + spt = cell_texture(transfer->texture); + + pipe_buffer_unmap( screen, spt->buffer ); } -void -cell_init_texture_functions(struct cell_context *cell) +static void * +cell_surface_map(struct pipe_screen *screen, + struct pipe_surface *surface, + unsigned flags) { - /*cell->pipe.texture_update = cell_texture_update;*/ + 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); + } + else { + return (void *) (map + surface->offset); + } + } } +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 ); +} + + + void cell_init_screen_texture_funcs(struct pipe_screen *screen) { @@ -382,6 +653,8 @@ cell_init_screen_texture_funcs(struct pipe_screen *screen) screen->get_tex_surface = cell_get_tex_surface; screen->tex_surface_release = cell_tex_surface_release; - screen->surface_map = cell_surface_map; - screen->surface_unmap = cell_surface_unmap; + 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; } |