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/nv04/Makefile | 1 + src/gallium/drivers/nv04/nv04_miptree.c | 47 +++---- src/gallium/drivers/nv04/nv04_screen.c | 26 +--- src/gallium/drivers/nv04/nv04_screen.h | 3 + src/gallium/drivers/nv04/nv04_state.h | 3 - src/gallium/drivers/nv04/nv04_state_emit.c | 17 ++- src/gallium/drivers/nv04/nv04_surface_2d.c | 43 +++--- src/gallium/drivers/nv04/nv04_surface_2d.h | 5 + src/gallium/drivers/nv04/nv04_transfer.c | 201 +++++++++++++++++++++++++++++ 9 files changed, 266 insertions(+), 80 deletions(-) create mode 100644 src/gallium/drivers/nv04/nv04_transfer.c (limited to 'src/gallium/drivers/nv04') diff --git a/src/gallium/drivers/nv04/Makefile b/src/gallium/drivers/nv04/Makefile index cf9deea8519..7c14bacb1de 100644 --- a/src/gallium/drivers/nv04/Makefile +++ b/src/gallium/drivers/nv04/Makefile @@ -15,6 +15,7 @@ C_SOURCES = \ nv04_state.c \ nv04_state_emit.c \ nv04_surface.c \ + nv04_transfer.c \ nv04_vbo.c include ../../Makefile.template diff --git a/src/gallium/drivers/nv04/nv04_miptree.c b/src/gallium/drivers/nv04/nv04_miptree.c index 993c5ef5dd2..9acd613e2e4 100644 --- a/src/gallium/drivers/nv04/nv04_miptree.c +++ b/src/gallium/drivers/nv04/nv04_miptree.c @@ -50,8 +50,6 @@ nv04_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; //mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR; @@ -111,12 +109,6 @@ nv04_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt) FREE(mt->level[l].image_offset); } - if (mt->shadow_tex) { - assert(mt->shadow_surface); - pscreen->tex_surface_release(pscreen, &mt->shadow_surface); - nv04_miptree_release(pscreen, &mt->shadow_tex); - } - FREE(mt); } @@ -126,29 +118,26 @@ nv04_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt, unsigned flags) { struct nv04_miptree *nv04mt = (struct nv04_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 = nv04mt->level[level].pitch; - ps->usage = flags; - ps->status = PIPE_SURFACE_STATUS_DEFINED; - ps->refcount = 1; - ps->face = face; - ps->level = level; - ps->zslice = zslice; - - ps->offset = nv04mt->level[level].image_offset; - - return ps; + 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 = nv04mt->level[level].pitch; + + ns->base.offset = nv04mt->level[level].image_offset; + + return &ns->base; } static void diff --git a/src/gallium/drivers/nv04/nv04_screen.c b/src/gallium/drivers/nv04/nv04_screen.c index 9ef38bc244c..f9f6d974264 100644 --- a/src/gallium/drivers/nv04/nv04_screen.c +++ b/src/gallium/drivers/nv04/nv04_screen.c @@ -119,28 +119,6 @@ nv04_screen_is_format_supported(struct pipe_screen *screen, return FALSE; } -static void * -nv04_surface_map(struct pipe_screen *screen, struct pipe_surface *surface, - unsigned flags ) -{ - void *map; - struct nv04_miptree *nv04mt = (struct nv04_miptree *)surface->texture; - - map = pipe_buffer_map(screen, nv04mt->buffer, flags); - if (!map) - return NULL; - - return map + surface->offset; -} - -static void -nv04_surface_unmap(struct pipe_screen *screen, struct pipe_surface *surface) -{ - struct nv04_miptree *nv04mt = (struct nv04_miptree *)surface->texture; - - pipe_buffer_unmap(screen, nv04mt->buffer); -} - static void nv04_screen_destroy(struct pipe_screen *pscreen) { @@ -226,10 +204,8 @@ nv04_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) screen->pipe.is_format_supported = nv04_screen_is_format_supported; - screen->pipe.surface_map = nv04_surface_map; - screen->pipe.surface_unmap = nv04_surface_unmap; - nv04_screen_init_miptree_functions(&screen->pipe); + nv04_screen_init_transfer_functions(&screen->pipe); u_simple_screen_init(&screen->pipe); return &screen->pipe; diff --git a/src/gallium/drivers/nv04/nv04_screen.h b/src/gallium/drivers/nv04/nv04_screen.h index 540aec907bf..ee6fb6db44a 100644 --- a/src/gallium/drivers/nv04/nv04_screen.h +++ b/src/gallium/drivers/nv04/nv04_screen.h @@ -24,4 +24,7 @@ nv04_screen(struct pipe_screen *screen) return (struct nv04_screen *)screen; } +void +nv04_screen_init_transfer_functions(struct pipe_screen *pscreen); + #endif diff --git a/src/gallium/drivers/nv04/nv04_state.h b/src/gallium/drivers/nv04/nv04_state.h index 15d4685ec1a..0d51439e3ff 100644 --- a/src/gallium/drivers/nv04/nv04_state.h +++ b/src/gallium/drivers/nv04/nv04_state.h @@ -35,9 +35,6 @@ struct nv04_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/nv04/nv04_state_emit.c b/src/gallium/drivers/nv04/nv04_state_emit.c index bd8ef1adbff..eb2c1c57c67 100644 --- a/src/gallium/drivers/nv04/nv04_state_emit.c +++ b/src/gallium/drivers/nv04/nv04_state_emit.c @@ -93,7 +93,7 @@ static void nv04_emit_sampler(struct nv04_context *nv04, int unit) static void nv04_state_emit_framebuffer(struct nv04_context* nv04) { struct pipe_framebuffer_state* fb = nv04->framebuffer; - struct pipe_surface *rt, *zeta; + struct nv04_surface *rt, *zeta; uint32_t rt_format, w, h; int colour_format = 0, zeta_format = 0; struct nv04_miptree *nv04mt = 0; @@ -101,7 +101,7 @@ static void nv04_state_emit_framebuffer(struct nv04_context* nv04) w = fb->cbufs[0]->width; h = fb->cbufs[0]->height; colour_format = fb->cbufs[0]->format; - rt = fb->cbufs[0]; + rt = (struct nv04_surface *)fb->cbufs[0]; if (fb->zsbuf) { if (colour_format) { @@ -113,7 +113,7 @@ static void nv04_state_emit_framebuffer(struct nv04_context* nv04) } zeta_format = fb->zsbuf->format; - zeta = fb->zsbuf; + zeta = (struct nv04_surface *)fb->zsbuf; } switch (colour_format) { @@ -131,13 +131,13 @@ static void nv04_state_emit_framebuffer(struct nv04_context* nv04) BEGIN_RING(context_surfaces_3d, NV04_CONTEXT_SURFACES_3D_FORMAT, 1); OUT_RING(rt_format); - nv04mt = (struct nv04_miptree *)rt->texture; + nv04mt = (struct nv04_miptree *)rt->base.texture; /* FIXME pitches have to be aligned ! */ BEGIN_RING(context_surfaces_3d, NV04_CONTEXT_SURFACES_3D_PITCH, 2); - OUT_RING(rt->stride|(zeta->stride<<16)); + OUT_RING(rt->pitch|(zeta->pitch<<16)); OUT_RELOCl(nv04mt->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); if (fb->zsbuf) { - nv04mt = (struct nv04_miptree *)zeta->texture; + nv04mt = (struct nv04_miptree *)zeta->base.texture; BEGIN_RING(context_surfaces_3d, NV04_CONTEXT_SURFACES_3D_OFFSET_ZETA, 1); OUT_RELOCl(nv04mt->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); } @@ -202,8 +202,11 @@ nv04_emit_hw_state(struct nv04_context *nv04) */ /* Render target */ + unsigned rt_pitch = ((struct nv04_surface *)nv04->rt)->pitch; + unsigned zeta_pitch = ((struct nv04_surface *)nv04->zeta)->pitch; + BEGIN_RING(context_surfaces_3d, NV04_CONTEXT_SURFACES_3D_PITCH, 2); - OUT_RING(nv04->rt->stride|(nv04->zeta->stride<<16)); + OUT_RING(rt_pitch|(zeta_pitch<<16)); OUT_RELOCl(nv04->rt, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); if (nv04->zeta) { BEGIN_RING(context_surfaces_3d, NV04_CONTEXT_SURFACES_3D_OFFSET_ZETA, 1); diff --git a/src/gallium/drivers/nv04/nv04_surface_2d.c b/src/gallium/drivers/nv04/nv04_surface_2d.c index 230cfd17dd9..e8fd3166ab8 100644 --- a/src/gallium/drivers/nv04/nv04_surface_2d.c +++ b/src/gallium/drivers/nv04/nv04_surface_2d.c @@ -101,6 +101,7 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, struct nouveau_grobj *sifm = ctx->sifm; struct nouveau_bo *src_bo = ctx->nvws->get_bo(ctx->buf(src)); struct nouveau_bo *dst_bo = ctx->nvws->get_bo(ctx->buf(dst)); + const unsigned src_pitch = ((struct nv04_surface *)src)->pitch; const unsigned max_w = 1024; const unsigned max_h = 1024; const unsigned sub_w = w > max_w ? max_w : w; @@ -110,6 +111,8 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, /* POT or GTFO */ assert(!(w & (w - 1)) && !(h & (h - 1))); + /* That's the way she likes it */ + assert(src_pitch == ((struct nv04_surface *)dst)->pitch); BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1); OUT_RELOCo(chan, dst_bo, @@ -130,7 +133,7 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, for (cx = 0; cx < w; cx += sub_w) { BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET, 1); OUT_RELOCl(chan, dst_bo, dst->offset + nv04_swizzle_bits(cx, cy) * - dst->block.size, NOUVEAU_BO_GART | + dst->texture->block.size, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9); @@ -146,11 +149,11 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SIZE, 4); OUT_RING (chan, sub_h << 16 | sub_w); - OUT_RING (chan, src->stride | + OUT_RING (chan, src_pitch | NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER | NV04_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE); - OUT_RELOCl(chan, src_bo, src->offset + cy * src->stride + - cx * src->block.size, NOUVEAU_BO_GART | + OUT_RELOCl(chan, src_bo, src->offset + cy * src_pitch + + cx * src->texture->block.size, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); OUT_RING (chan, 0); } @@ -168,10 +171,12 @@ nv04_surface_copy_m2mf(struct nv04_surface_2d *ctx, struct nouveau_grobj *m2mf = ctx->m2mf; struct nouveau_bo *src_bo = ctx->nvws->get_bo(ctx->buf(src)); struct nouveau_bo *dst_bo = ctx->nvws->get_bo(ctx->buf(dst)); - unsigned dst_offset, src_offset; - - dst_offset = dst->offset + (dy * dst->stride) + (dx * dst->block.size); - src_offset = src->offset + (sy * src->stride) + (sx * src->block.size); + unsigned src_pitch = ((struct nv04_surface *)src)->pitch; + unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; + unsigned dst_offset = dst->offset + dy * dst_pitch + + dx * dst->texture->block.size; + unsigned src_offset = src->offset + sy * src_pitch + + sx * src->texture->block.size; WAIT_RING (chan, 3 + ((h / 2047) + 1) * 9); BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2); @@ -188,16 +193,16 @@ nv04_surface_copy_m2mf(struct nv04_surface_2d *ctx, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD); OUT_RELOCl(chan, dst_bo, dst_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR); - OUT_RING (chan, src->stride); - OUT_RING (chan, dst->stride); - OUT_RING (chan, w * src->block.size); + OUT_RING (chan, src_pitch); + OUT_RING (chan, dst_pitch); + OUT_RING (chan, w * src->texture->block.size); OUT_RING (chan, count); OUT_RING (chan, 0x0101); OUT_RING (chan, 0); h -= count; - src_offset += src->stride * count; - dst_offset += dst->stride * count; + src_offset += src_pitch * count; + dst_offset += dst_pitch * count; } return 0; @@ -213,6 +218,8 @@ nv04_surface_copy_blit(struct nv04_surface_2d *ctx, struct pipe_surface *dst, struct nouveau_grobj *blit = ctx->blit; struct nouveau_bo *src_bo = ctx->nvws->get_bo(ctx->buf(src)); struct nouveau_bo *dst_bo = ctx->nvws->get_bo(ctx->buf(dst)); + unsigned src_pitch = ((struct nv04_surface *)src)->pitch; + unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; int format; format = nv04_surface_format(dst->format); @@ -225,7 +232,7 @@ nv04_surface_copy_blit(struct nv04_surface_2d *ctx, struct pipe_surface *dst, OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); OUT_RING (chan, format); - OUT_RING (chan, (dst->stride << 16) | src->stride); + OUT_RING (chan, (dst_pitch << 16) | src_pitch); OUT_RELOCl(chan, src_bo, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); @@ -242,6 +249,8 @@ nv04_surface_copy(struct nv04_surface_2d *ctx, struct pipe_surface *dst, int dx, int dy, struct pipe_surface *src, int sx, int sy, int w, int h) { + unsigned src_pitch = ((struct nv04_surface *)src)->pitch; + unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; int src_linear = src->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR; int dst_linear = dst->texture->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR; @@ -257,7 +266,8 @@ nv04_surface_copy(struct nv04_surface_2d *ctx, struct pipe_surface *dst, * to NV_MEMORY_TO_MEMORY_FORMAT in this case. */ if ((src->offset & 63) || (dst->offset & 63) || - (src->stride & 63) || (dst->stride & 63)) { + (src_pitch & 63) || (dst_pitch & 63) || + debug_get_bool_option("NOUVEAU_NO_COPYBLIT", FALSE)) { nv04_surface_copy_m2mf(ctx, dst, dx, dy, src, sx, sy, w, h); return; } @@ -273,6 +283,7 @@ nv04_surface_fill(struct nv04_surface_2d *ctx, struct pipe_surface *dst, struct nouveau_grobj *surf2d = ctx->surf2d; struct nouveau_grobj *rect = ctx->rect; struct nouveau_bo *dst_bo = ctx->nvws->get_bo(ctx->buf(dst)); + unsigned dst_pitch = ((struct nv04_surface *)dst)->pitch; int cs2d_format, gdirect_format; cs2d_format = nv04_surface_format(dst->format); @@ -287,7 +298,7 @@ nv04_surface_fill(struct nv04_surface_2d *ctx, struct pipe_surface *dst, OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4); OUT_RING (chan, cs2d_format); - OUT_RING (chan, (dst->stride << 16) | dst->stride); + OUT_RING (chan, (dst_pitch << 16) | dst_pitch); OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, dst_bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); diff --git a/src/gallium/drivers/nv04/nv04_surface_2d.h b/src/gallium/drivers/nv04/nv04_surface_2d.h index 21b8f869606..82ce7189c8b 100644 --- a/src/gallium/drivers/nv04/nv04_surface_2d.h +++ b/src/gallium/drivers/nv04/nv04_surface_2d.h @@ -1,6 +1,11 @@ #ifndef __NV04_SURFACE_2D_H__ #define __NV04_SURFACE_2D_H__ +struct nv04_surface { + struct pipe_surface base; + unsigned pitch; +}; + struct nv04_surface_2d { struct nouveau_winsys *nvws; struct nouveau_notifier *ntfy; diff --git a/src/gallium/drivers/nv04/nv04_transfer.c b/src/gallium/drivers/nv04/nv04_transfer.c new file mode 100644 index 00000000000..314d2045f76 --- /dev/null +++ b/src/gallium/drivers/nv04/nv04_transfer.c @@ -0,0 +1,201 @@ +#include +#include +#include +#include +#include +#include "nv04_context.h" +#include "nv04_screen.h" +#include "nv04_state.h" + +struct nv04_transfer { + struct pipe_transfer base; + struct pipe_surface *surface; + bool direct; +}; + +static unsigned nv04_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 +nv04_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 * +nv04_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 nv04_miptree *mt = (struct nv04_miptree *)pt; + struct nv04_transfer *tx; + struct pipe_texture tx_tex_template, *tx_tex; + + tx = CALLOC_STRUCT(nv04_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, + nv04_usage_tx_to_buf(usage)); + return &tx->base; + } + + tx->direct = false; + + nv04_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, + nv04_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 nv04_screen *nvscreen = nv04_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 +nv04_transfer_del(struct pipe_screen *pscreen, struct pipe_transfer **pptx) +{ + struct pipe_transfer *ptx = *pptx; + struct nv04_transfer *tx = (struct nv04_transfer *)ptx; + + if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) { + struct nv04_screen *nvscreen = nv04_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 * +nv04_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv04_transfer *tx = (struct nv04_transfer *)ptx; + struct nv04_surface *ns = (struct nv04_surface *)tx->surface; + struct nv04_miptree *mt = (struct nv04_miptree *)tx->surface->texture; + void *map = pipe_buffer_map(pscreen, mt->buffer, + nv04_usage_tx_to_buf(ptx->usage)); + + return map + ns->base.offset + + ptx->y * ns->pitch + ptx->x * ptx->block.size; +} + +static void +nv04_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv04_transfer *tx = (struct nv04_transfer *)ptx; + struct nv04_miptree *mt = (struct nv04_miptree *)tx->surface->texture; + + pipe_buffer_unmap(pscreen, mt->buffer); +} + +void +nv04_screen_init_transfer_functions(struct pipe_screen *pscreen) +{ + pscreen->get_tex_transfer = nv04_transfer_new; + pscreen->tex_transfer_release = nv04_transfer_del; + pscreen->transfer_map = nv04_transfer_map; + pscreen->transfer_unmap = nv04_transfer_unmap; +} -- cgit v1.2.3