diff options
Diffstat (limited to 'src/gallium/drivers/llvmpipe/lp_texture.c')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_texture.c | 443 |
1 files changed, 269 insertions, 174 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c index 7f45635542..61210de890 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.c +++ b/src/gallium/drivers/llvmpipe/lp_texture.c @@ -37,12 +37,15 @@ #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_transfer.h" #include "lp_context.h" #include "lp_screen.h" +#include "lp_flush.h" #include "lp_texture.h" +#include "lp_setup.h" #include "lp_tile_size.h" -#include "lp_winsys.h" +#include "state_tracker/sw_winsys.h" /** @@ -50,10 +53,10 @@ * Simple, maximally packed layout. */ static boolean -llvmpipe_texture_layout(struct llvmpipe_screen *screen, - struct llvmpipe_texture *lpt) +llvmpipe_resource_layout(struct llvmpipe_screen *screen, + struct llvmpipe_resource *lpt) { - struct pipe_texture *pt = &lpt->base; + struct pipe_resource *pt = &lpt->base; unsigned level; unsigned width = pt->width0; unsigned height = pt->height0; @@ -91,9 +94,9 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen, static boolean llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, - struct llvmpipe_texture *lpt) + struct llvmpipe_resource *lpt) { - struct llvmpipe_winsys *winsys = screen->winsys; + struct sw_winsys *winsys = screen->winsys; /* Round up the surface size to a multiple of the tile size to * avoid tile clipping. @@ -102,6 +105,7 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, unsigned height = align(lpt->base.height0, TILE_SIZE); lpt->dt = winsys->displaytarget_create(winsys, + lpt->base.bind, lpt->base.format, width, height, 16, @@ -111,12 +115,12 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, } -static struct pipe_texture * -llvmpipe_texture_create(struct pipe_screen *_screen, - const struct pipe_texture *templat) +static struct pipe_resource * +llvmpipe_resource_create(struct pipe_screen *_screen, + const struct pipe_resource *templat) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); - struct llvmpipe_texture *lpt = CALLOC_STRUCT(llvmpipe_texture); + struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource); if (!lpt) return NULL; @@ -124,16 +128,17 @@ llvmpipe_texture_create(struct pipe_screen *_screen, pipe_reference_init(&lpt->base.reference, 1); lpt->base.screen = &screen->base; - if (lpt->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | - PIPE_TEXTURE_USAGE_PRIMARY)) { + if (lpt->base.bind & (PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_SCANOUT | + PIPE_BIND_SHARED)) { if (!llvmpipe_displaytarget_layout(screen, lpt)) goto fail; } else { - if (!llvmpipe_texture_layout(screen, lpt)) + if (!llvmpipe_resource_layout(screen, lpt)) goto fail; } - + return &lpt->base; fail: @@ -142,70 +147,164 @@ llvmpipe_texture_create(struct pipe_screen *_screen, } -static struct pipe_texture * -llvmpipe_texture_blanket(struct pipe_screen * screen, - const struct pipe_texture *base, - const unsigned *stride, - struct pipe_buffer *buffer) +static void +llvmpipe_resource_destroy(struct pipe_screen *pscreen, + struct pipe_resource *pt) { - /* FIXME */ -#if 0 - struct llvmpipe_texture *lpt; - assert(screen); - - /* Only supports one type */ - if (base->target != PIPE_TEXTURE_2D || - base->last_level != 0 || - base->depth0 != 1) { - return NULL; + struct llvmpipe_screen *screen = llvmpipe_screen(pscreen); + struct llvmpipe_resource *lpt = llvmpipe_resource(pt); + + if (lpt->dt) { + /* display target */ + struct sw_winsys *winsys = screen->winsys; + winsys->displaytarget_destroy(winsys, lpt->dt); + } + else if (!lpt->userBuffer) { + /* regular texture */ + align_free(lpt->data); + } + + FREE(lpt); +} + + +/** + * Map a texture. Without any synchronization. + */ +void * +llvmpipe_resource_map(struct pipe_resource *texture, + unsigned usage, + unsigned face, + unsigned level, + unsigned zslice) +{ + struct llvmpipe_resource *lpt = llvmpipe_resource(texture); + uint8_t *map; + + if (lpt->dt) { + /* display target */ + struct llvmpipe_screen *screen = llvmpipe_screen(texture->screen); + struct sw_winsys *winsys = screen->winsys; + + assert(face == 0); + assert(level == 0); + assert(zslice == 0); + + /* FIXME: keep map count? */ + map = winsys->displaytarget_map(winsys, lpt->dt, usage); + } + else { + /* regular texture */ + unsigned offset; + unsigned stride; + + map = lpt->data; + + assert(level < LP_MAX_TEXTURE_2D_LEVELS); + + offset = lpt->level_offset[level]; + stride = lpt->stride[level]; + + /* XXX shouldn't that rather be + tex_height = align(u_minify(texture->height0, level), 2) + to account for alignment done in llvmpipe_resource_layout ? + */ + if (texture->target == PIPE_TEXTURE_CUBE) { + unsigned tex_height = u_minify(texture->height0, level); + offset += face * util_format_get_nblocksy(texture->format, tex_height) * stride; + } + else if (texture->target == PIPE_TEXTURE_3D) { + unsigned tex_height = u_minify(texture->height0, level); + offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * stride; + } + else { + assert(face == 0); + assert(zslice == 0); + } + + map += offset; } - lpt = CALLOC_STRUCT(llvmpipe_texture); + return map; +} + + +/** + * Unmap a texture. Without any synchronization. + */ +void +llvmpipe_resource_unmap(struct pipe_resource *texture, + unsigned face, + unsigned level, + unsigned zslice) +{ + struct llvmpipe_resource *lpt = llvmpipe_resource(texture); + + if (lpt->dt) { + /* display target */ + struct llvmpipe_screen *lp_screen = llvmpipe_screen(texture->screen); + struct sw_winsys *winsys = lp_screen->winsys; + + assert(face == 0); + assert(level == 0); + assert(zslice == 0); + + winsys->displaytarget_unmap(winsys, lpt->dt); + } +} + + +static struct pipe_resource * +llvmpipe_resource_from_handle(struct pipe_screen *screen, + const struct pipe_resource *template, + struct winsys_handle *whandle) +{ + struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; + struct llvmpipe_resource *lpt = CALLOC_STRUCT(llvmpipe_resource); if (!lpt) return NULL; - lpt->base = *base; + lpt->base = *template; pipe_reference_init(&lpt->base.reference, 1); lpt->base.screen = screen; - lpt->stride[0] = stride[0]; - pipe_buffer_reference(&lpt->buffer, buffer); + lpt->dt = winsys->displaytarget_from_handle(winsys, + template, + whandle, + &lpt->stride[0]); + if (!lpt->dt) + goto fail; return &lpt->base; -#else - debug_printf("llvmpipe_texture_blanket() not implemented!"); + + fail: + FREE(lpt); return NULL; -#endif } -static void -llvmpipe_texture_destroy(struct pipe_texture *pt) +static boolean +llvmpipe_resource_get_handle(struct pipe_screen *screen, + struct pipe_resource *pt, + struct winsys_handle *whandle) { - struct llvmpipe_screen *screen = llvmpipe_screen(pt->screen); - struct llvmpipe_texture *lpt = llvmpipe_texture(pt); + struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; + struct llvmpipe_resource *lpt = llvmpipe_resource(pt); - if (lpt->dt) { - /* display target */ - struct llvmpipe_winsys *winsys = screen->winsys; - winsys->displaytarget_destroy(winsys, lpt->dt); - } - else { - /* regular texture */ - align_free(lpt->data); - } + assert(lpt->dt); + if (!lpt->dt) + return FALSE; - FREE(lpt); + return winsys->displaytarget_get_handle(winsys, lpt->dt, whandle); } static struct pipe_surface * llvmpipe_get_tex_surface(struct pipe_screen *screen, - struct pipe_texture *pt, + struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned usage) { - struct llvmpipe_texture *lpt = llvmpipe_texture(pt); struct pipe_surface *ps; assert(level <= pt->last_level); @@ -213,53 +312,15 @@ llvmpipe_get_tex_surface(struct pipe_screen *screen, ps = CALLOC_STRUCT(pipe_surface); if (ps) { pipe_reference_init(&ps->reference, 1); - pipe_texture_reference(&ps->texture, pt); + pipe_resource_reference(&ps->texture, pt); ps->format = pt->format; ps->width = u_minify(pt->width0, level); ps->height = u_minify(pt->height0, level); - ps->offset = lpt->level_offset[level]; ps->usage = usage; - /* Because we are llvmpipe, anything that the state tracker - * thought was going to be done with the GPU will actually get - * done with the CPU. Let's adjust the flags to take that into - * account. - */ - if (ps->usage & PIPE_BUFFER_USAGE_GPU_WRITE) { - /* GPU_WRITE means "render" and that can involve reads (blending) */ - ps->usage |= PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_CPU_READ; - } - - if (ps->usage & PIPE_BUFFER_USAGE_GPU_READ) - ps->usage |= PIPE_BUFFER_USAGE_CPU_READ; - - if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE | - PIPE_BUFFER_USAGE_GPU_WRITE)) { - /* Mark the surface as dirty. */ - lpt->timestamp++; - llvmpipe_screen(screen)->timestamp++; - } - ps->face = face; ps->level = level; ps->zslice = zslice; - - /* XXX shouldn't that rather be - tex_height = align(ps->height, 2); - to account for alignment done in llvmpipe_texture_layout ? - */ - if (pt->target == PIPE_TEXTURE_CUBE) { - unsigned tex_height = ps->height; - ps->offset += face * util_format_get_nblocksy(pt->format, tex_height) * lpt->stride[level]; - } - else if (pt->target == PIPE_TEXTURE_3D) { - unsigned tex_height = ps->height; - ps->offset += zslice * util_format_get_nblocksy(pt->format, tex_height) * lpt->stride[level]; - } - else { - assert(face == 0); - assert(zslice == 0); - } } return ps; } @@ -273,56 +334,33 @@ llvmpipe_tex_surface_destroy(struct pipe_surface *surf) * where it would happen. For llvmpipe, nothing to do. */ assert(surf->texture); - pipe_texture_reference(&surf->texture, NULL); + pipe_resource_reference(&surf->texture, NULL); FREE(surf); } static struct pipe_transfer * -llvmpipe_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) +llvmpipe_get_transfer(struct pipe_context *pipe, + struct pipe_resource *resource, + struct pipe_subresource sr, + unsigned usage, + const struct pipe_box *box) { - struct llvmpipe_texture *lptex = llvmpipe_texture(texture); + struct llvmpipe_resource *lptex = llvmpipe_resource(resource); struct llvmpipe_transfer *lpt; - assert(texture); - assert(level <= texture->last_level); + assert(resource); + assert(sr.level <= resource->last_level); lpt = CALLOC_STRUCT(llvmpipe_transfer); if (lpt) { struct pipe_transfer *pt = &lpt->base; - pipe_texture_reference(&pt->texture, texture); - pt->x = x; - pt->y = y; - pt->width = align(w, TILE_SIZE); - pt->height = align(h, TILE_SIZE); - pt->stride = lptex->stride[level]; + pipe_resource_reference(&pt->resource, resource); + pt->box = *box; + pt->sr = sr; + pt->stride = lptex->stride[sr.level]; pt->usage = usage; - pt->face = face; - pt->level = level; - pt->zslice = zslice; - lpt->offset = lptex->level_offset[level]; - - /* XXX shouldn't that rather be - tex_height = align(u_minify(texture->height0, level), 2) - to account for alignment done in llvmpipe_texture_layout ? - */ - if (texture->target == PIPE_TEXTURE_CUBE) { - unsigned tex_height = u_minify(texture->height0, level); - lpt->offset += face * util_format_get_nblocksy(texture->format, tex_height) * pt->stride; - } - else if (texture->target == PIPE_TEXTURE_3D) { - unsigned tex_height = u_minify(texture->height0, level); - lpt->offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * pt->stride; - } - else { - assert(face == 0); - assert(zslice == 0); - } return pt; } return NULL; @@ -330,92 +368,149 @@ llvmpipe_get_tex_transfer(struct pipe_screen *screen, static void -llvmpipe_tex_transfer_destroy(struct pipe_transfer *transfer) +llvmpipe_transfer_destroy(struct pipe_context *pipe, + struct pipe_transfer *transfer) { /* 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 llvmpipe, nothing to do. */ - assert (transfer->texture); - pipe_texture_reference(&transfer->texture, NULL); + assert (transfer->resource); + pipe_resource_reference(&transfer->resource, NULL); FREE(transfer); } static void * -llvmpipe_transfer_map( struct pipe_screen *_screen, +llvmpipe_transfer_map( struct pipe_context *pipe, struct pipe_transfer *transfer ) { - struct llvmpipe_screen *screen = llvmpipe_screen(_screen); - ubyte *map, *xfer_map; - struct llvmpipe_texture *lpt; + struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); + ubyte *map; + struct llvmpipe_resource *lpt; enum pipe_format format; - assert(transfer->texture); - lpt = llvmpipe_texture(transfer->texture); + assert(transfer->resource); + lpt = llvmpipe_resource(transfer->resource); format = lpt->base.format; - if (lpt->dt) { - /* display target */ - struct llvmpipe_winsys *winsys = screen->winsys; - - map = winsys->displaytarget_map(winsys, lpt->dt, - pipe_transfer_buffer_flags(transfer)); - if (map == NULL) - return NULL; - } - else { - /* regular texture */ - map = lpt->data; - } + /* + * Transfers, like other pipe operations, must happen in order, so flush the + * context if necessary. + */ + llvmpipe_flush_texture(pipe, + transfer->resource, + transfer->sr.face, + transfer->sr.level, + 0, /* flush_flags */ + !(transfer->usage & PIPE_TRANSFER_WRITE), /* read_only */ + TRUE, /* cpu_access */ + FALSE); /* do_not_flush */ + + map = llvmpipe_resource_map(transfer->resource, + transfer->usage, + transfer->sr.face, + transfer->sr.level, + transfer->box.z); /* May want to different things here depending on read/write nature * of the map: */ - if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE)) { + if (transfer->usage & PIPE_TRANSFER_WRITE) { /* Do something to notify sharing contexts of a texture change. */ screen->timestamp++; } - xfer_map = map + llvmpipe_transfer(transfer)->offset + - transfer->y / util_format_get_blockheight(format) * transfer->stride + - transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); - /*printf("map = %p xfer map = %p\n", map, xfer_map);*/ - return xfer_map; + map += + transfer->box.y / util_format_get_blockheight(format) * transfer->stride + + transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); + + return map; } static void -llvmpipe_transfer_unmap(struct pipe_screen *screen, - struct pipe_transfer *transfer) +llvmpipe_transfer_unmap(struct pipe_context *pipe, + struct pipe_transfer *transfer) { - struct llvmpipe_screen *lp_screen = llvmpipe_screen(screen); - struct llvmpipe_texture *lpt; + assert(transfer->resource); - assert(transfer->texture); - lpt = llvmpipe_texture(transfer->texture); + llvmpipe_resource_unmap(transfer->resource, + transfer->sr.face, + transfer->sr.level, + transfer->box.z); +} - if (lpt->dt) { - /* display target */ - struct llvmpipe_winsys *winsys = lp_screen->winsys; - winsys->displaytarget_unmap(winsys, lpt->dt); - } +static unsigned int +llvmpipe_is_resource_referenced( struct pipe_context *pipe, + struct pipe_resource *presource, + unsigned face, unsigned level) +{ + struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); + + if (presource->target == PIPE_BUFFER) + return PIPE_UNREFERENCED; + + return lp_setup_is_resource_referenced(llvmpipe->setup, presource); +} + + + +/** + * Create buffer which wraps user-space data. + */ +static struct pipe_resource * +llvmpipe_user_buffer_create(struct pipe_screen *screen, + void *ptr, + unsigned bytes, + unsigned bind_flags) +{ + struct llvmpipe_resource *buffer; + + buffer = CALLOC_STRUCT(llvmpipe_resource); + if(!buffer) + return NULL; + + pipe_reference_init(&buffer->base.reference, 1); + buffer->base.screen = screen; + buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */ + buffer->base.bind = bind_flags; + buffer->base._usage = PIPE_USAGE_IMMUTABLE; + buffer->base.flags = 0; + buffer->base.width0 = bytes; + buffer->base.height0 = 1; + buffer->base.depth0 = 1; + buffer->userBuffer = TRUE; + buffer->data = ptr; + + return &buffer->base; } void -llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen) +llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen) { - screen->texture_create = llvmpipe_texture_create; - screen->texture_blanket = llvmpipe_texture_blanket; - screen->texture_destroy = llvmpipe_texture_destroy; + screen->resource_create = llvmpipe_resource_create; + screen->resource_destroy = llvmpipe_resource_destroy; + screen->resource_from_handle = llvmpipe_resource_from_handle; + screen->resource_get_handle = llvmpipe_resource_get_handle; + screen->user_buffer_create = llvmpipe_user_buffer_create; screen->get_tex_surface = llvmpipe_get_tex_surface; screen->tex_surface_destroy = llvmpipe_tex_surface_destroy; +} + - screen->get_tex_transfer = llvmpipe_get_tex_transfer; - screen->tex_transfer_destroy = llvmpipe_tex_transfer_destroy; - screen->transfer_map = llvmpipe_transfer_map; - screen->transfer_unmap = llvmpipe_transfer_unmap; +void +llvmpipe_init_context_resource_funcs(struct pipe_context *pipe) +{ + pipe->get_transfer = llvmpipe_get_transfer; + pipe->transfer_destroy = llvmpipe_transfer_destroy; + pipe->transfer_map = llvmpipe_transfer_map; + pipe->transfer_unmap = llvmpipe_transfer_unmap; + pipe->is_resource_referenced = llvmpipe_is_resource_referenced; + + pipe->transfer_flush_region = u_default_transfer_flush_region; + pipe->transfer_inline_write = u_default_transfer_inline_write; } |