From a0dc286b5fecec1ede014cb5702368a60cbb22bc Mon Sep 17 00:00:00 2001 From: Younes Manton Date: Wed, 25 Feb 2009 12:55:26 -0500 Subject: nouveau: nv04-nv40 texture transfer. --- src/gallium/drivers/nv30/Makefile | 1 + src/gallium/drivers/nv30/nv30_miptree.c | 56 ++++----- src/gallium/drivers/nv30/nv30_screen.c | 80 +----------- src/gallium/drivers/nv30/nv30_screen.h | 3 + src/gallium/drivers/nv30/nv30_state.h | 3 - src/gallium/drivers/nv30/nv30_state_fb.c | 28 ++--- src/gallium/drivers/nv30/nv30_transfer.c | 201 +++++++++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 128 deletions(-) create mode 100644 src/gallium/drivers/nv30/nv30_transfer.c (limited to 'src/gallium/drivers/nv30') diff --git a/src/gallium/drivers/nv30/Makefile b/src/gallium/drivers/nv30/Makefile index 4c29e2eab3..364c80d8f3 100644 --- a/src/gallium/drivers/nv30/Makefile +++ b/src/gallium/drivers/nv30/Makefile @@ -22,6 +22,7 @@ C_SOURCES = \ nv30_state_viewport.c \ nv30_state_zsa.c \ nv30_surface.c \ + nv30_transfer.c \ nv30_vbo.c \ nv30_vertprog.c diff --git a/src/gallium/drivers/nv30/nv30_miptree.c b/src/gallium/drivers/nv30/nv30_miptree.c index b11ed8c24e..ec0a8b8438 100644 --- a/src/gallium/drivers/nv30/nv30_miptree.c +++ b/src/gallium/drivers/nv30/nv30_miptree.c @@ -69,6 +69,8 @@ nv30_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt) { struct pipe_winsys *ws = pscreen->winsys; struct nv30_miptree *mt; + unsigned buf_usage = PIPE_BUFFER_USAGE_PIXEL | + NOUVEAU_BUFFER_USAGE_TEXTURE; mt = MALLOC(sizeof(struct nv30_miptree)); if (!mt) @@ -76,8 +78,6 @@ nv30_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt) mt->base = *pt; mt->base.refcount = 1; mt->base.screen = pscreen; - mt->shadow_tex = NULL; - mt->shadow_surface = NULL; /* Swizzled textures must be POT */ if (pt->width[0] & (pt->width[0] - 1) || @@ -107,11 +107,12 @@ nv30_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *pt) } } + if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC) + buf_usage |= PIPE_BUFFER_USAGE_CPU_READ_WRITE; + nv30_miptree_layout(mt); - mt->buffer = ws->buffer_create(ws, 256, - PIPE_BUFFER_USAGE_PIXEL | - NOUVEAU_BUFFER_USAGE_TEXTURE, + mt->buffer = ws->buffer_create(ws, 256, buf_usage, mt->total_size); if (!mt->buffer) { FREE(mt); @@ -163,12 +164,6 @@ nv30_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt) FREE(mt->level[l].image_offset); } - if (mt->shadow_tex) { - if (mt->shadow_surface) - pscreen->tex_surface_release(pscreen, &mt->shadow_surface); - nv30_miptree_release(pscreen, &mt->shadow_tex); - } - FREE(mt); } @@ -178,36 +173,33 @@ nv30_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt, unsigned flags) { struct nv30_miptree *nv30mt = (struct nv30_miptree *)pt; - struct pipe_surface *ps; + struct nv04_surface *ns; - ps = CALLOC_STRUCT(pipe_surface); - if (!ps) + ns = CALLOC_STRUCT(nv04_surface); + if (!ns) return NULL; - pipe_texture_reference(&ps->texture, pt); - ps->format = pt->format; - ps->width = pt->width[level]; - ps->height = pt->height[level]; - ps->block = pt->block; - ps->nblocksx = pt->nblocksx[level]; - ps->nblocksy = pt->nblocksy[level]; - ps->stride = nv30mt->level[level].pitch; - ps->usage = flags; - ps->status = PIPE_SURFACE_STATUS_DEFINED; - ps->refcount = 1; - ps->face = face; - ps->level = level; - ps->zslice = zslice; + pipe_texture_reference(&ns->base.texture, pt); + ns->base.format = pt->format; + ns->base.width = pt->width[level]; + ns->base.height = pt->height[level]; + ns->base.usage = flags; + ns->base.status = PIPE_SURFACE_STATUS_DEFINED; + ns->base.refcount = 1; + ns->base.face = face; + ns->base.level = level; + ns->base.zslice = zslice; + ns->pitch = nv30mt->level[level].pitch; if (pt->target == PIPE_TEXTURE_CUBE) { - ps->offset = nv30mt->level[level].image_offset[face]; + ns->base.offset = nv30mt->level[level].image_offset[face]; } else if (pt->target == PIPE_TEXTURE_3D) { - ps->offset = nv30mt->level[level].image_offset[zslice]; + ns->base.offset = nv30mt->level[level].image_offset[zslice]; } else { - ps->offset = nv30mt->level[level].image_offset[0]; + ns->base.offset = nv30mt->level[level].image_offset[0]; } - return ps; + return &ns->base; } static void diff --git a/src/gallium/drivers/nv30/nv30_screen.c b/src/gallium/drivers/nv30/nv30_screen.c index c97a73f0b1..d395c5e1b7 100644 --- a/src/gallium/drivers/nv30/nv30_screen.c +++ b/src/gallium/drivers/nv30/nv30_screen.c @@ -135,82 +135,6 @@ nv30_surface_buffer(struct pipe_surface *surf) return mt->buffer; } -static void * -nv30_surface_map(struct pipe_screen *screen, struct pipe_surface *surface, - unsigned flags ) -{ - struct pipe_winsys *ws = screen->winsys; - struct pipe_surface *surface_to_map; - void *map; - - if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { - struct nv30_miptree *mt = (struct nv30_miptree *)surface->texture; - - if (!mt->shadow_tex) { - unsigned old_tex_usage = surface->texture->tex_usage; - surface->texture->tex_usage = NOUVEAU_TEXTURE_USAGE_LINEAR | - PIPE_TEXTURE_USAGE_DYNAMIC; - mt->shadow_tex = screen->texture_create(screen, surface->texture); - surface->texture->tex_usage = old_tex_usage; - - assert(mt->shadow_tex->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR); - } - - mt->shadow_surface = screen->get_tex_surface - ( - screen, mt->shadow_tex, - surface->face, surface->level, surface->zslice, - surface->usage - ); - - surface_to_map = mt->shadow_surface; - } - else - surface_to_map = surface; - - assert(surface_to_map); - - map = ws->buffer_map(ws, nv30_surface_buffer(surface_to_map), flags); - if (!map) - return NULL; - - return map + surface_to_map->offset; -} - -static void -nv30_surface_unmap(struct pipe_screen *screen, struct pipe_surface *surface) -{ - struct pipe_winsys *ws = screen->winsys; - struct pipe_surface *surface_to_unmap; - - /* TODO: Copy from shadow just before push buffer is flushed instead. - There are probably some programs that map/unmap excessively - before rendering. */ - if (!(surface->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { - struct nv30_miptree *mt = (struct nv30_miptree *)surface->texture; - - assert(mt->shadow_tex); - - surface_to_unmap = mt->shadow_surface; - } - else - surface_to_unmap = surface; - - assert(surface_to_unmap); - - ws->buffer_unmap(ws, nv30_surface_buffer(surface_to_unmap)); - - if (surface_to_unmap != surface) { - struct nv30_screen *nvscreen = nv30_screen(screen); - - nvscreen->eng2d->copy(nvscreen->eng2d, surface, 0, 0, - surface_to_unmap, 0, 0, - surface->width, surface->height); - - screen->tex_surface_release(screen, &surface_to_unmap); - } -} - static void nv30_screen_destroy(struct pipe_screen *pscreen) { @@ -391,10 +315,8 @@ nv30_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) screen->pipe.is_format_supported = nv30_screen_surface_format_supported; - screen->pipe.surface_map = nv30_surface_map; - screen->pipe.surface_unmap = nv30_surface_unmap; - nv30_screen_init_miptree_functions(&screen->pipe); + nv30_screen_init_transfer_functions(&screen->pipe); u_simple_screen_init(&screen->pipe); return &screen->pipe; diff --git a/src/gallium/drivers/nv30/nv30_screen.h b/src/gallium/drivers/nv30/nv30_screen.h index b11e470f94..8e36883975 100644 --- a/src/gallium/drivers/nv30/nv30_screen.h +++ b/src/gallium/drivers/nv30/nv30_screen.h @@ -34,4 +34,7 @@ nv30_screen(struct pipe_screen *screen) return (struct nv30_screen *)screen; } +void +nv30_screen_init_transfer_functions(struct pipe_screen *pscreen); + #endif diff --git a/src/gallium/drivers/nv30/nv30_state.h b/src/gallium/drivers/nv30/nv30_state.h index 2023278e37..e6f23bf166 100644 --- a/src/gallium/drivers/nv30/nv30_state.h +++ b/src/gallium/drivers/nv30/nv30_state.h @@ -76,9 +76,6 @@ struct nv30_miptree { struct pipe_buffer *buffer; uint total_size; - struct pipe_texture *shadow_tex; - struct pipe_surface *shadow_surface; - struct { uint pitch; uint *image_offset; diff --git a/src/gallium/drivers/nv30/nv30_state_fb.c b/src/gallium/drivers/nv30/nv30_state_fb.c index 77368cb205..ee0326011c 100644 --- a/src/gallium/drivers/nv30/nv30_state_fb.c +++ b/src/gallium/drivers/nv30/nv30_state_fb.c @@ -5,7 +5,7 @@ static boolean nv30_state_framebuffer_validate(struct nv30_context *nv30) { struct pipe_framebuffer_state *fb = &nv30->framebuffer; - struct pipe_surface *rt[2], *zeta = NULL; + struct nv04_surface *rt[2], *zeta = NULL; uint32_t rt_enable, rt_format; int i, colour_format = 0, zeta_format = 0; struct nouveau_stateobj *so = so_new(64, 10); @@ -21,7 +21,7 @@ nv30_state_framebuffer_validate(struct nv30_context *nv30) } else { colour_format = fb->cbufs[i]->format; rt_enable |= (NV34TCL_RT_ENABLE_COLOR0 << i); - rt[i] = fb->cbufs[i]; + rt[i] = (struct nv04_surface *)fb->cbufs[i]; } } @@ -30,13 +30,13 @@ nv30_state_framebuffer_validate(struct nv30_context *nv30) if (fb->zsbuf) { zeta_format = fb->zsbuf->format; - zeta = fb->zsbuf; + zeta = (struct nv04_surface *)fb->zsbuf; } - if (!(rt[0]->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { + if (!(rt[0]->base.texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)) { assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); for (i = 1; i < fb->nr_cbufs; i++) - assert(!(rt[i]->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)); + assert(!(rt[i]->base.texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)); /* FIXME: NV34TCL_RT_FORMAT_LOG2_[WIDTH/HEIGHT] */ rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | @@ -71,44 +71,44 @@ nv30_state_framebuffer_validate(struct nv30_context *nv30) } if (rt_enable & NV34TCL_RT_ENABLE_COLOR0) { - uint32_t pitch = rt[0]->stride; + uint32_t pitch = rt[0]->pitch; if (zeta) { - pitch |= (zeta->stride << 16); + pitch |= (zeta->pitch << 16); } else { pitch |= (pitch << 16); } - nv30mt = (struct nv30_miptree *)rt[0]->texture; + nv30mt = (struct nv30_miptree *)rt[0]->base.texture; so_method(so, nv30->screen->rankine, NV34TCL_DMA_COLOR0, 1); so_reloc (so, nv30mt->buffer, 0, rt_flags | NOUVEAU_BO_OR, nv30->nvws->channel->vram->handle, nv30->nvws->channel->gart->handle); so_method(so, nv30->screen->rankine, NV34TCL_COLOR0_PITCH, 2); so_data (so, pitch); - so_reloc (so, nv30mt->buffer, rt[0]->offset, rt_flags | + so_reloc (so, nv30mt->buffer, rt[0]->base.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); } if (rt_enable & NV34TCL_RT_ENABLE_COLOR1) { - nv30mt = (struct nv30_miptree *)rt[1]->texture; + nv30mt = (struct nv30_miptree *)rt[1]->base.texture; so_method(so, nv30->screen->rankine, NV34TCL_DMA_COLOR1, 1); so_reloc (so, nv30mt->buffer, 0, rt_flags | NOUVEAU_BO_OR, nv30->nvws->channel->vram->handle, nv30->nvws->channel->gart->handle); so_method(so, nv30->screen->rankine, NV34TCL_COLOR1_OFFSET, 2); - so_reloc (so, nv30mt->buffer, rt[1]->offset, rt_flags | + so_reloc (so, nv30mt->buffer, rt[1]->base.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); - so_data (so, rt[1]->stride); + so_data (so, rt[1]->pitch); } if (zeta_format) { - nv30mt = (struct nv30_miptree *)zeta->texture; + nv30mt = (struct nv30_miptree *)zeta->base.texture; so_method(so, nv30->screen->rankine, NV34TCL_DMA_ZETA, 1); so_reloc (so, nv30mt->buffer, 0, rt_flags | NOUVEAU_BO_OR, nv30->nvws->channel->vram->handle, nv30->nvws->channel->gart->handle); so_method(so, nv30->screen->rankine, NV34TCL_ZETA_OFFSET, 1); - so_reloc (so, nv30mt->buffer, zeta->offset, rt_flags | + so_reloc (so, nv30mt->buffer, zeta->base.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); /* TODO: allocate LMA depth buffer */ } diff --git a/src/gallium/drivers/nv30/nv30_transfer.c b/src/gallium/drivers/nv30/nv30_transfer.c new file mode 100644 index 0000000000..df4dc4b1f6 --- /dev/null +++ b/src/gallium/drivers/nv30/nv30_transfer.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include "nv30_context.h" +#include "nv30_screen.h" +#include "nv30_state.h" + +struct nv30_transfer { + struct pipe_transfer base; + struct pipe_surface *surface; + bool direct; +}; + +static unsigned nv30_usage_tx_to_buf(unsigned tx_usage) +{ + switch (tx_usage) { + case PIPE_TRANSFER_READ: + return PIPE_BUFFER_USAGE_CPU_READ; + case PIPE_TRANSFER_WRITE: + return PIPE_BUFFER_USAGE_CPU_WRITE; + case PIPE_TRANSFER_READ_WRITE: + return PIPE_BUFFER_USAGE_CPU_READ_WRITE; + default: + assert(0); + } + + return -1; +} + +static void +nv30_compatible_transfer_tex(struct pipe_texture *pt, unsigned level, + struct pipe_texture *template) +{ + memset(template, 0, sizeof(struct pipe_texture)); + template->target = pt->target; + template->format = pt->format; + template->width[0] = pt->width[level]; + template->height[0] = pt->height[level]; + template->depth[0] = 1; + template->block = pt->block; + template->nblocksx[0] = pt->nblocksx[level]; + template->nblocksy[0] = pt->nblocksx[level]; + template->last_level = 0; + template->compressed = pt->compressed; + template->nr_samples = pt->nr_samples; + + template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC | + NOUVEAU_TEXTURE_USAGE_LINEAR; +} + +static struct pipe_transfer * +nv30_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt, + unsigned face, unsigned level, unsigned zslice, + enum pipe_transfer_usage usage, + unsigned x, unsigned y, unsigned w, unsigned h) +{ + struct nv30_miptree *mt = (struct nv30_miptree *)pt; + struct nv30_transfer *tx; + struct pipe_texture tx_tex_template, *tx_tex; + + tx = CALLOC_STRUCT(nv30_transfer); + if (!tx) + return NULL; + + tx->base.refcount = 1; + pipe_texture_reference(&tx->base.texture, pt); + tx->base.format = pt->format; + tx->base.x = x; + tx->base.y = y; + tx->base.width = w; + tx->base.height = h; + tx->base.block = pt->block; + tx->base.nblocksx = pt->nblocksx[level]; + tx->base.nblocksy = pt->nblocksy[level]; + 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) + { + tx->direct = true; + tx->surface = pscreen->get_tex_surface(pscreen, pt, + face, level, zslice, + nv30_usage_tx_to_buf(usage)); + return &tx->base; + } + + tx->direct = false; + + nv30_compatible_transfer_tex(pt, level, &tx_tex_template); + + tx_tex = pscreen->texture_create(pscreen, &tx_tex_template); + if (!tx_tex) + { + FREE(tx); + return NULL; + } + + tx->surface = pscreen->get_tex_surface(pscreen, tx_tex, + face, level, zslice, + nv30_usage_tx_to_buf(usage)); + + pipe_texture_reference(&tx_tex, NULL); + + if (!tx->surface) + { + pipe_surface_reference(&tx->surface, NULL); + FREE(tx); + return NULL; + } + + if (usage != PIPE_TRANSFER_WRITE) { + struct nv30_screen *nvscreen = nv30_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, 0, 0, + src->width, src->height); + + pipe_surface_reference(&src, NULL); + } + + return &tx->base; +} + +static void +nv30_transfer_del(struct pipe_screen *pscreen, struct pipe_transfer **pptx) +{ + struct pipe_transfer *ptx = *pptx; + struct nv30_transfer *tx = (struct nv30_transfer *)ptx; + + if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) { + struct nv30_screen *nvscreen = nv30_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); + + /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */ + nvscreen->eng2d->copy(nvscreen->eng2d, + dst, 0, 0, + tx->surface, 0, 0, + dst->width, dst->height); + + pipe_surface_reference(&dst, NULL); + } + + *pptx = NULL; + if (--ptx->refcount) + return; + + pipe_surface_reference(&tx->surface, NULL); + pipe_texture_reference(&ptx->texture, NULL); + FREE(ptx); +} + +static void * +nv30_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv30_transfer *tx = (struct nv30_transfer *)ptx; + struct nv04_surface *ns = (struct nv04_surface *)tx->surface; + struct nv30_miptree *mt = (struct nv30_miptree *)tx->surface->texture; + void *map = pipe_buffer_map(pscreen, mt->buffer, + nv30_usage_tx_to_buf(ptx->usage)); + + return map + ns->base.offset + + ptx->y * ns->pitch + ptx->x * ptx->block.size; +} + +static void +nv30_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv30_transfer *tx = (struct nv30_transfer *)ptx; + struct nv30_miptree *mt = (struct nv30_miptree *)tx->surface->texture; + + pipe_buffer_unmap(pscreen, mt->buffer); +} + +void +nv30_screen_init_transfer_functions(struct pipe_screen *pscreen) +{ + pscreen->get_tex_transfer = nv30_transfer_new; + pscreen->tex_transfer_release = nv30_transfer_del; + pscreen->transfer_map = nv30_transfer_map; + pscreen->transfer_unmap = nv30_transfer_unmap; +} -- cgit v1.2.3