diff options
Diffstat (limited to 'src/gallium/drivers/nvfx/nvfx_transfer.c')
-rw-r--r-- | src/gallium/drivers/nvfx/nvfx_transfer.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/gallium/drivers/nvfx/nvfx_transfer.c b/src/gallium/drivers/nvfx/nvfx_transfer.c new file mode 100644 index 00000000000..b2ef27cf579 --- /dev/null +++ b/src/gallium/drivers/nvfx/nvfx_transfer.c @@ -0,0 +1,205 @@ +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_math.h" +#include "nouveau/nouveau_winsys.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_resource *pt, unsigned width, unsigned height, + unsigned bind, + struct pipe_resource *template) +{ + memset(template, 0, sizeof(struct pipe_resource)); + 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->bind = bind; + template->usage = PIPE_USAGE_DYNAMIC; + template->flags = NVFX_RESOURCE_FLAG_LINEAR; +} + + +static unsigned nvfx_transfer_bind_flags( unsigned transfer_usage ) +{ + unsigned bind = 0; + + if (transfer_usage & PIPE_TRANSFER_WRITE) + bind |= PIPE_BIND_BLIT_SOURCE; + + if (transfer_usage & PIPE_TRANSFER_READ) + bind |= PIPE_BIND_BLIT_DESTINATION; + + return bind; +} + +struct pipe_transfer * +nvfx_miptree_transfer_new(struct pipe_context *pipe, + struct pipe_resource *pt, + struct pipe_subresource sr, + unsigned usage, + const struct pipe_box *box) +{ + struct pipe_screen *pscreen = pipe->screen; + struct nvfx_miptree *mt = (struct nvfx_miptree *)pt; + struct nvfx_transfer *tx; + struct pipe_resource tx_tex_template, *tx_tex; + static int no_transfer = -1; + unsigned bind = nvfx_transfer_bind_flags(usage); + if(no_transfer < 0) + no_transfer = debug_get_bool_option("NOUVEAU_NO_TRANSFER", FALSE); + + + tx = CALLOC_STRUCT(nvfx_transfer); + if (!tx) + return NULL; + + /* Don't handle 3D transfers yet. + */ + assert(box->depth == 1); + + pipe_resource_reference(&tx->base.resource, pt); + tx->base.sr = sr; + tx->base.usage = usage; + tx->base.box = *box; + tx->base.stride = mt->level[sr.level].pitch; + + /* Direct access to texture */ + if ((pt->usage == PIPE_USAGE_DYNAMIC || + no_transfer) && + pt->flags & NVFX_RESOURCE_FLAG_LINEAR) + { + tx->direct = true; + + /* XXX: just call the internal nvfx function. + */ + tx->surface = pscreen->get_tex_surface(pscreen, pt, + sr.face, sr.level, + box->z, + bind); + return &tx->base; + } + + tx->direct = false; + + nvfx_compatible_transfer_tex(pt, box->width, box->height, bind, &tx_tex_template); + + tx_tex = pscreen->resource_create(pscreen, &tx_tex_template); + if (!tx_tex) + { + FREE(tx); + return NULL; + } + + tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch; + + tx->surface = pscreen->get_tex_surface(pscreen, tx_tex, + 0, 0, 0, + bind); + + pipe_resource_reference(&tx_tex, NULL); + + if (!tx->surface) + { + pipe_surface_reference(&tx->surface, NULL); + FREE(tx); + return NULL; + } + + if (usage & PIPE_TRANSFER_READ) { + struct nvfx_screen *nvscreen = nvfx_screen(pscreen); + struct pipe_surface *src; + + src = pscreen->get_tex_surface(pscreen, pt, + sr.face, sr.level, box->z, + PIPE_BIND_BLIT_SOURCE); + + /* 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, + box->x, box->y, + box->width, box->height); + + pipe_surface_reference(&src, NULL); + } + + return &tx->base; +} + +void +nvfx_miptree_transfer_del(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 = pipe->screen; + struct nvfx_screen *nvscreen = nvfx_screen(pscreen); + struct pipe_surface *dst; + + dst = pscreen->get_tex_surface(pscreen, + ptx->resource, + ptx->sr.face, + ptx->sr.level, + ptx->box.z, + PIPE_BIND_BLIT_DESTINATION); + + /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ + nvscreen->eng2d->copy(nvscreen->eng2d, + dst, ptx->box.x, ptx->box.y, + tx->surface, 0, 0, + ptx->box.width, ptx->box.height); + + pipe_surface_reference(&dst, NULL); + } + + pipe_surface_reference(&tx->surface, NULL); + pipe_resource_reference(&ptx->resource, NULL); + FREE(ptx); +} + +void * +nvfx_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx) +{ + struct pipe_screen *pscreen = pipe->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; + uint8_t *map = nouveau_screen_bo_map(pscreen, mt->base.bo, + nouveau_screen_transfer_flags(ptx->usage)); + + if(!tx->direct) + return map + ns->base.offset; + else + return (map + ns->base.offset + + ptx->box.y * ns->pitch + + ptx->box.x * util_format_get_blocksize(ptx->resource->format)); +} + +void +nvfx_miptree_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx) +{ + struct pipe_screen *pscreen = pipe->screen; + struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx; + struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture; + + nouveau_screen_bo_unmap(pscreen, mt->base.bo); +} |