X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fnvfx%2Fnvfx_transfer.c;h=cc4b51ec1f8db06f16c62a317b1d980de03ee7c3;hb=56503fd13847ae5072af761ac69b923323e053f8;hp=409b354d5823f6dde7370297ec08a34f44ad8533;hpb=182c42c8da6edfa66819eef02f4dea310c1f68d7;p=mesa.git diff --git a/src/gallium/drivers/nvfx/nvfx_transfer.c b/src/gallium/drivers/nvfx/nvfx_transfer.c index 409b354d582..cc4b51ec1f8 100644 --- a/src/gallium/drivers/nvfx/nvfx_transfer.c +++ b/src/gallium/drivers/nvfx/nvfx_transfer.c @@ -4,179 +4,218 @@ #include "util/u_format.h" #include "util/u_memory.h" #include "util/u_math.h" -#include "nouveau/nouveau_winsys.h" +#include "util/u_staging.h" #include "nvfx_context.h" #include "nvfx_screen.h" #include "nvfx_state.h" +#include "nvfx_resource.h" +#include "nvfx_transfer.h" -struct nvfx_transfer { - struct pipe_transfer base; - struct pipe_surface *surface; - boolean direct; -}; - -static void -nvfx_compatible_transfer_tex(struct pipe_texture *pt, unsigned width, unsigned height, - struct pipe_texture *template) +struct nvfx_staging_transfer { - memset(template, 0, sizeof(struct pipe_texture)); - template->target = pt->target; - template->format = pt->format; - template->width0 = width; - template->height0 = height; - template->depth0 = 1; - template->last_level = 0; - template->nr_samples = pt->nr_samples; - - template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC | - NOUVEAU_TEXTURE_USAGE_LINEAR; -} + struct util_staging_transfer base; + + unsigned offset; + unsigned map_count; +}; -static struct pipe_transfer * -nvfx_transfer_new(struct pipe_context *pcontext, struct pipe_texture *pt, - unsigned face, unsigned level, unsigned zslice, - enum pipe_transfer_usage usage, - unsigned x, unsigned y, unsigned w, unsigned h) +struct pipe_transfer * +nvfx_transfer_new(struct pipe_context *pipe, + struct pipe_resource *pt, + unsigned level, + unsigned usage, + const struct pipe_box *box) { - struct pipe_screen *pscreen = pcontext->screen; - struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; - struct nvfx_transfer *tx; - struct pipe_texture tx_tex_template, *tx_tex; - - tx = CALLOC_STRUCT(nvfx_transfer); - if (!tx) - return NULL; - - pipe_texture_reference(&tx->base.texture, pt); - tx->base.x = x; - tx->base.y = y; - tx->base.width = w; - tx->base.height = h; - tx->base.stride = mt->level[level].pitch; - tx->base.usage = usage; - tx->base.face = face; - tx->base.level = level; - tx->base.zslice = zslice; - - /* Direct access to texture */ - if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC || - debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) && - pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR) + if((usage & (PIPE_TRANSFER_UNSYNCHRONIZED | PIPE_TRANSFER_DONTBLOCK)) == PIPE_TRANSFER_DONTBLOCK) + { + struct nouveau_bo* bo = ((struct nvfx_resource*)pt)->bo; + if(bo && nouveau_bo_busy(bo, NOUVEAU_BO_WR)) + return NULL; + } + + if(pt->target == PIPE_BUFFER) { - tx->direct = true; - tx->surface = pscreen->get_tex_surface(pscreen, pt, - face, level, zslice, - pipe_transfer_buffer_flags(&tx->base)); - return &tx->base; - } + // it would be nice if we could avoid all this ridiculous overhead... + struct pipe_transfer* tx; + struct nvfx_buffer* buffer = nvfx_buffer(pt); + + tx = CALLOC_STRUCT(pipe_transfer); + if (!tx) + return NULL; - tx->direct = false; + pipe_resource_reference(&tx->resource, pt); + tx->level = level; + tx->usage = usage; + tx->box = *box; - nvfx_compatible_transfer_tex(pt, w, h, &tx_tex_template); + tx->layer_stride = tx->stride = util_format_get_stride(pt->format, box->width); + tx->data = buffer->data + util_format_get_stride(pt->format, box->x); - tx_tex = pscreen->texture_create(pscreen, &tx_tex_template); - if (!tx_tex) + return tx; + } + else { - FREE(tx); - return NULL; + struct nvfx_staging_transfer* tx; + boolean direct = !nvfx_resource_on_gpu(pt) && pt->flags & NVFX_RESOURCE_FLAG_LINEAR; + + tx = CALLOC_STRUCT(nvfx_staging_transfer); + if(!tx) + return NULL; + + util_staging_transfer_init(pipe, pt, level, usage, box, direct, &tx->base); + + if(direct) + { + tx->base.base.stride = nvfx_subresource_pitch(pt, level); + tx->base.base.layer_stride = tx->base.base.stride * u_minify(pt->height0, level); + tx->offset = nvfx_subresource_offset(pt, box->z, level, box->z) + + util_format_get_2d_size(pt->format, tx->base.base.stride, box->y) + + util_format_get_stride(pt->format, box->x); + } + else + { + tx->base.base.stride = nvfx_subresource_pitch(tx->base.staging_resource, 0); + tx->base.base.layer_stride = tx->base.base.stride * tx->base.staging_resource->height0; + tx->offset = 0; + } + + assert(tx->base.base.stride); + + return &tx->base.base; } +} - tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch; - - tx->surface = pscreen->get_tex_surface(pscreen, tx_tex, - 0, 0, 0, - pipe_transfer_buffer_flags(&tx->base)); - - pipe_texture_reference(&tx_tex, NULL); - - if (!tx->surface) +static void nvfx_buffer_dirty_interval(struct nvfx_buffer* buffer, unsigned begin, unsigned size, boolean unsynchronized) +{ + struct nvfx_screen* screen = nvfx_screen(buffer->base.base.screen); + buffer->last_update_static = buffer->bytes_to_draw_until_static < 0; + if(buffer->dirty_begin == buffer->dirty_end) { - pipe_surface_reference(&tx->surface, NULL); - FREE(tx); - return NULL; + buffer->dirty_begin = begin; + buffer->dirty_end = begin + size; + buffer->dirty_unsynchronized = unsynchronized; + } + else + { + buffer->dirty_begin = MIN2(buffer->dirty_begin, begin); + buffer->dirty_end = MAX2(buffer->dirty_end, begin + size); + buffer->dirty_unsynchronized &= unsynchronized; } - if (usage & PIPE_TRANSFER_READ) { - struct nvfx_screen *nvscreen = nvfx_screen(pscreen); - struct pipe_surface *src; - - src = pscreen->get_tex_surface(pscreen, pt, - face, level, zslice, - PIPE_BUFFER_USAGE_GPU_READ); - - /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ - /* TODO: Check if SIFM can un-swizzle */ - nvscreen->eng2d->copy(nvscreen->eng2d, - tx->surface, 0, 0, - src, x, y, - w, h); - - pipe_surface_reference(&src, NULL); + if(unsynchronized) + { + // TODO: revisit this, it doesn't seem quite right + //printf("UNSYNC UPDATE %p %u %u\n", buffer, begin, size); + buffer->bytes_to_draw_until_static += size * screen->static_reuse_threshold; } + else + buffer->bytes_to_draw_until_static = buffer->size * screen->static_reuse_threshold; +} - return &tx->base; +static void nvfx_transfer_flush_region( struct pipe_context *pipe, + struct pipe_transfer *ptx, + const struct pipe_box *box) +{ + if(ptx->resource->target == PIPE_BUFFER && (ptx->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) + { + struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource); + nvfx_buffer_dirty_interval(buffer, + (uint8_t*)ptx->data - buffer->data + util_format_get_stride(buffer->base.base.format, box->x), + util_format_get_stride(buffer->base.base.format, box->width), + !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED)); + } } static void -nvfx_transfer_del(struct pipe_context *pcontext, - struct pipe_transfer *ptx) +nvfx_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *ptx) { - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - - if (!tx->direct && (ptx->usage & PIPE_TRANSFER_WRITE)) { - struct pipe_screen *pscreen = pcontext->screen; - struct nvfx_screen *nvscreen = nvfx_screen(pscreen); - struct pipe_surface *dst; - - dst = pscreen->get_tex_surface(pscreen, ptx->texture, - ptx->face, ptx->level, ptx->zslice, - PIPE_BUFFER_USAGE_GPU_WRITE | NOUVEAU_BUFFER_USAGE_NO_RENDER); - - /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ - nvscreen->eng2d->copy(nvscreen->eng2d, - dst, tx->base.x, tx->base.y, - tx->surface, 0, 0, - tx->base.width, tx->base.height); - - pipe_surface_reference(&dst, NULL); + if(ptx->resource->target == PIPE_BUFFER) + { + struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource); + if((ptx->usage & (PIPE_TRANSFER_WRITE | PIPE_TRANSFER_FLUSH_EXPLICIT)) == PIPE_TRANSFER_WRITE) + nvfx_buffer_dirty_interval(buffer, + (uint8_t*)ptx->data - buffer->data, + ptx->stride, + !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED)); + pipe_resource_reference(&ptx->resource, 0); + FREE(ptx); } + else + { + struct nouveau_channel* chan = nvfx_context(pipe)->screen->base.channel; + util_staging_transfer_destroy(pipe, ptx); - pipe_surface_reference(&tx->surface, NULL); - pipe_texture_reference(&ptx->texture, NULL); - FREE(ptx); + FIRE_RING(chan); + } } -static void * -nvfx_transfer_map(struct pipe_context *pcontext, struct pipe_transfer *ptx) +void * +nvfx_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx) { - struct pipe_screen *pscreen = pcontext->screen; - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - struct nv04_surface *ns = (struct nv04_surface *)tx->surface; - struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture; - void *map = pipe_buffer_map(pscreen, mt->buffer, - pipe_transfer_buffer_flags(ptx)); - - if(!tx->direct) - return map + ns->base.offset; + if(ptx->resource->target == PIPE_BUFFER) + return ptx->data; else - return map + ns->base.offset + ptx->y * ns->pitch + ptx->x * util_format_get_blocksize(ptx->texture->format); + { + struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx; + if(!ptx->data) + { + struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource; + uint8_t *map = nouveau_screen_bo_map(pipe->screen, mt->base.bo, nouveau_screen_transfer_flags(ptx->usage)); + ptx->data = map + tx->offset; + } + + ++tx->map_count; + return ptx->data; + } } -static void -nvfx_transfer_unmap(struct pipe_context *pcontext, struct pipe_transfer *ptx) +void +nvfx_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx) { - struct pipe_screen *pscreen = pcontext->screen; - struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; - struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture; + if(ptx->resource->target != PIPE_BUFFER) + { + struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx; + struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource; + + if(!--tx->map_count) + { + nouveau_screen_bo_unmap(pipe->screen, mt->base.bo); + ptx->data = 0; + } + } +} - pipe_buffer_unmap(pscreen, mt->buffer); +static void nvfx_transfer_inline_write( struct pipe_context *pipe, + struct pipe_resource *pr, + unsigned level, + unsigned usage, + const struct pipe_box *box, + const void *data, + unsigned stride, + unsigned slice_stride) +{ + if(pr->target != PIPE_BUFFER) + { + u_default_transfer_inline_write(pipe, pr, level, usage, box, data, stride, slice_stride); + } + else + { + struct nvfx_buffer* buffer = nvfx_buffer(pr); + unsigned begin = util_format_get_stride(pr->format, box->x); + unsigned size = util_format_get_stride(pr->format, box->width); + memcpy(buffer->data + begin, data, size); + nvfx_buffer_dirty_interval(buffer, begin, size, + !!(pr->flags & PIPE_TRANSFER_UNSYNCHRONIZED)); + } } void -nvfx_init_transfer_functions(struct nvfx_context *nvfx) +nvfx_init_transfer_functions(struct pipe_context *pipe) { - nvfx->pipe.get_tex_transfer = nvfx_transfer_new; - nvfx->pipe.tex_transfer_destroy = nvfx_transfer_del; - nvfx->pipe.transfer_map = nvfx_transfer_map; - nvfx->pipe.transfer_unmap = nvfx_transfer_unmap; + pipe->get_transfer = nvfx_transfer_new; + pipe->transfer_map = nvfx_transfer_map; + pipe->transfer_flush_region = nvfx_transfer_flush_region; + pipe->transfer_unmap = nvfx_transfer_unmap; + pipe->transfer_destroy = nvfx_transfer_destroy; + pipe->transfer_inline_write = nvfx_transfer_inline_write; }