diff options
author | Ben Skeggs <[email protected]> | 2009-02-20 09:32:47 +1000 |
---|---|---|
committer | Ben Skeggs <[email protected]> | 2009-02-20 09:43:24 +1000 |
commit | 63a3a3762c8e1a67666d36b35fdb0ada8e4b7d08 (patch) | |
tree | d44240582f82712c446a1116afcc15d47b30ef7a /src/gallium/drivers/nv50 | |
parent | 9c9fcc83c03c8f944236a892d96305e98f0bffdd (diff) |
nv50: rework for texture_transfer changes
Diffstat (limited to 'src/gallium/drivers/nv50')
-rw-r--r-- | src/gallium/drivers/nv50/Makefile | 1 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_context.h | 8 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_miptree.c | 119 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_screen.c | 19 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_screen.h | 3 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_surface.c | 26 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_tex.c | 9 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_transfer.c | 216 |
8 files changed, 244 insertions, 157 deletions
diff --git a/src/gallium/drivers/nv50/Makefile b/src/gallium/drivers/nv50/Makefile index be30400c039..48244dbbac7 100644 --- a/src/gallium/drivers/nv50/Makefile +++ b/src/gallium/drivers/nv50/Makefile @@ -15,6 +15,7 @@ DRIVER_SOURCES = \ nv50_state_validate.c \ nv50_surface.c \ nv50_tex.c \ + nv50_transfer.c \ nv50_vbo.c C_SOURCES = \ diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h index 1e9d45cb340..313e435e7a5 100644 --- a/src/gallium/drivers/nv50/nv50_context.h +++ b/src/gallium/drivers/nv50/nv50_context.h @@ -64,10 +64,8 @@ struct nv50_rasterizer_stateobj { }; struct nv50_miptree_level { - struct pipe_buffer **image; int *image_offset; - unsigned image_dirty_cpu[512/32]; - unsigned image_dirty_gpu[512/32]; + unsigned pitch; }; struct nv50_miptree { @@ -200,8 +198,4 @@ extern boolean nv50_state_validate(struct nv50_context *nv50); /* nv50_tex.c */ extern void nv50_tex_validate(struct nv50_context *); -/* nv50_miptree.c */ -extern void nv50_miptree_sync(struct pipe_screen *, struct nv50_miptree *, - unsigned level, unsigned image); - #endif diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c index 91091d53f57..24a68b7235f 100644 --- a/src/gallium/drivers/nv50/nv50_miptree.c +++ b/src/gallium/drivers/nv50/nv50_miptree.c @@ -72,7 +72,7 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp) pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height); lvl->image_offset = CALLOC(mt->image_nr, sizeof(int)); - lvl->image = CALLOC(mt->image_nr, sizeof(struct pipe_buffer *)); + lvl->pitch = align(pt->width[l] * pt->block.size, 64); width = MAX2(1, width >> 1); height = MAX2(1, height >> 1); @@ -88,7 +88,6 @@ nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp) size = align(size, 64); size *= align(pt->height[l], 8) * pt->block.size; - lvl->image[i] = ws->buffer_create(ws, 256, 0, size); lvl->image_offset[i] = mt->total_size; mt->total_size += size; @@ -123,30 +122,13 @@ nv50_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt, mt->base.refcount = 1; mt->base.screen = pscreen; mt->image_nr = 1; + mt->level[0].pitch = *stride; mt->level[0].image_offset = CALLOC(1, sizeof(unsigned)); pipe_buffer_reference(pscreen, &mt->buffer, pb); return &mt->base; } -static INLINE void -mark_dirty(uint32_t *flags, unsigned image) -{ - flags[image / 32] |= (1 << (image % 32)); -} - -static INLINE void -mark_clean(uint32_t *flags, unsigned image) -{ - flags[image / 32] &= ~(1 << (image % 32)); -} - -static INLINE int -is_dirty(uint32_t *flags, unsigned image) -{ - return !!(flags[image / 32] & (1 << (image % 32))); -} - static void nv50_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt) { @@ -162,79 +144,6 @@ nv50_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt) } } -void -nv50_miptree_sync(struct pipe_screen *pscreen, struct nv50_miptree *mt, - unsigned level, unsigned image) -{ - struct nv50_screen *nvscreen = nv50_screen(pscreen); - struct nv50_miptree_level *lvl = &mt->level[level]; - struct pipe_surface *dst, *src; - unsigned face = 0, zslice = 0; - - if (!is_dirty(lvl->image_dirty_cpu, image)) - return; - - if (mt->base.target == PIPE_TEXTURE_CUBE) - face = image; - else - if (mt->base.target == PIPE_TEXTURE_3D) - zslice = image; - - /* Mark as clean already - so we don't continually call this function - * trying to get a GPU_WRITE pipe_surface! - */ - mark_clean(lvl->image_dirty_cpu, image); - - /* Pretend we're doing CPU access so we get the backing pipe_surface - * and not a view into the larger miptree. - */ - src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, - PIPE_BUFFER_USAGE_CPU_READ); - - /* Pretend we're only reading with the GPU so surface doesn't get marked - * as dirtied by the GPU. - */ - dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, - PIPE_BUFFER_USAGE_GPU_READ); - - nv50_surface_do_copy(nvscreen, dst, 0, 0, src, 0, 0, dst->width, dst->height); - - pscreen->tex_surface_release(pscreen, &dst); - pscreen->tex_surface_release(pscreen, &src); -} - -/* The reverse of the above */ -static void -nv50_miptree_sync_cpu(struct pipe_screen *pscreen, struct nv50_miptree *mt, - unsigned level, unsigned image) -{ - struct nv50_screen *nvscreen = nv50_screen(pscreen); - struct nv50_miptree_level *lvl = &mt->level[level]; - struct pipe_surface *dst, *src; - unsigned face = 0, zslice = 0; - - if (!is_dirty(lvl->image_dirty_gpu, image)) - return; - - if (mt->base.target == PIPE_TEXTURE_CUBE) - face = image; - else - if (mt->base.target == PIPE_TEXTURE_3D) - zslice = image; - - mark_clean(lvl->image_dirty_gpu, image); - - src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, - PIPE_BUFFER_USAGE_GPU_READ); - dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, - PIPE_BUFFER_USAGE_CPU_READ); - - nv50_surface_do_copy(nvscreen, dst, 0, 0, src, 0, 0, dst->width, dst->height); - - pscreen->tex_surface_release(pscreen, &dst); - pscreen->tex_surface_release(pscreen, &src); -} - static struct pipe_surface * nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt, unsigned face, unsigned level, unsigned zslice, @@ -260,35 +169,13 @@ nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_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 = ps->width * ps->block.size; ps->usage = flags; ps->status = PIPE_SURFACE_STATUS_DEFINED; ps->refcount = 1; ps->face = face; ps->level = level; ps->zslice = zslice; - - if (flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) { - assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE)); - nv50_miptree_sync_cpu(pscreen, mt, level, img); - - ps->offset = 0; - pipe_texture_reference(&ps->texture, pt); - - if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) - mark_dirty(lvl->image_dirty_cpu, img); - } else { - nv50_miptree_sync(pscreen, mt, level, img); - - ps->offset = lvl->image_offset[img]; - pipe_texture_reference(&ps->texture, pt); - - if (flags & PIPE_BUFFER_USAGE_GPU_WRITE) - mark_dirty(lvl->image_dirty_gpu, img); - } + ps->offset = lvl->image_offset[img]; return ps; } diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c index 58d7a621a80..ee24405d36d 100644 --- a/src/gallium/drivers/nv50/nv50_screen.c +++ b/src/gallium/drivers/nv50/nv50_screen.c @@ -173,6 +173,14 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) return NULL; screen->nvws = nvws; + /* DMA engine object */ + ret = nvws->grobj_alloc(nvws, 0x5039, &screen->m2mf); + if (ret) { + NOUVEAU_ERR("Error creating M2MF object: %d\n", ret); + nv50_screen_destroy(&screen->pipe); + return NULL; + } + /* 2D object */ ret = nvws->grobj_alloc(nvws, NV50_2D, &screen->eng2d); if (ret) { @@ -226,6 +234,15 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) return NULL; } + /* Static M2MF init */ + so = so_new(32, 0); + so_method(so, screen->m2mf, 0x0180, 3); + so_data (so, screen->sync->handle); + so_data (so, screen->nvws->channel->vram->handle); + so_data (so, screen->nvws->channel->vram->handle); + so_emit(nvws, so); + so_ref (NULL, &so); + /* Static 2D init */ so = so_new(64, 0); so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4); @@ -348,7 +365,7 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws) screen->pipe.is_format_supported = nv50_screen_is_format_supported; nv50_screen_init_miptree_functions(&screen->pipe); - nv50_surface_init_screen_functions(&screen->pipe); + nv50_transfer_init_screen_functions(&screen->pipe); u_simple_screen_init(&screen->pipe); return &screen->pipe; diff --git a/src/gallium/drivers/nv50/nv50_screen.h b/src/gallium/drivers/nv50/nv50_screen.h index c888ca071c8..db567aaac89 100644 --- a/src/gallium/drivers/nv50/nv50_screen.h +++ b/src/gallium/drivers/nv50/nv50_screen.h @@ -12,6 +12,7 @@ struct nv50_screen { struct nouveau_grobj *tesla; struct nouveau_grobj *eng2d; + struct nouveau_grobj *m2mf; struct nouveau_notifier *sync; struct pipe_buffer *constbuf; @@ -29,6 +30,6 @@ nv50_screen(struct pipe_screen *screen) return (struct nv50_screen *)screen; } -void nv50_surface_init_screen_functions(struct pipe_screen *); +void nv50_transfer_init_screen_functions(struct pipe_screen *); #endif diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c index f2dd2eb30be..b0936518b03 100644 --- a/src/gallium/drivers/nv50/nv50_surface.c +++ b/src/gallium/drivers/nv50/nv50_surface.c @@ -51,6 +51,7 @@ nv50_format(enum pipe_format format) static int nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) { + struct nv50_miptree *mt = nv50_miptree(ps->texture); struct nouveau_channel *chan = screen->nvws->channel; struct nouveau_grobj *eng2d = screen->eng2d; struct nouveau_bo *bo; @@ -70,7 +71,7 @@ nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) OUT_RING (chan, format); OUT_RING (chan, 1); BEGIN_RING(chan, eng2d, mthd + 0x14, 5); - OUT_RING (chan, ps->stride); + OUT_RING (chan, mt->level[0].pitch); OUT_RING (chan, ps->width); OUT_RING (chan, ps->height); OUT_RELOCh(chan, bo, ps->offset, flags); @@ -197,23 +198,6 @@ nv50_surface_fill(struct pipe_context *pipe, struct pipe_surface *dest, OUT_RING (chan, height); } -static void * -nv50_surface_map(struct pipe_screen *screen, struct pipe_surface *ps, - unsigned flags ) -{ - struct pipe_winsys *ws = screen->winsys; - - return ws->buffer_map(ws, nv50_surface_buffer(ps), flags); -} - -static void -nv50_surface_unmap(struct pipe_screen *pscreen, struct pipe_surface *ps) -{ - struct pipe_winsys *ws = pscreen->winsys; - - ws->buffer_unmap(ws, nv50_surface_buffer(ps)); -} - void nv50_init_surface_functions(struct nv50_context *nv50) { @@ -221,10 +205,4 @@ nv50_init_surface_functions(struct nv50_context *nv50) nv50->pipe.surface_fill = nv50_surface_fill; } -void -nv50_surface_init_screen_functions(struct pipe_screen *pscreen) -{ - pscreen->surface_map = nv50_surface_map; - pscreen->surface_unmap = nv50_surface_unmap; -} diff --git a/src/gallium/drivers/nv50/nv50_tex.c b/src/gallium/drivers/nv50/nv50_tex.c index 675f9b20cbc..31bf59675ec 100644 --- a/src/gallium/drivers/nv50/nv50_tex.c +++ b/src/gallium/drivers/nv50/nv50_tex.c @@ -135,7 +135,7 @@ nv50_tex_validate(struct nv50_context *nv50) { struct nouveau_grobj *tesla = nv50->screen->tesla; struct nouveau_stateobj *so; - int unit, level, image; + int unit; so = so_new(nv50->miptree_nr * 8 + 3, nv50->miptree_nr * 2); so_method(so, tesla, 0x0f00, 1); @@ -144,13 +144,6 @@ nv50_tex_validate(struct nv50_context *nv50) for (unit = 0; unit < nv50->miptree_nr; unit++) { struct nv50_miptree *mt = nv50->miptree[unit]; - for (level = 0; level <= mt->base.last_level; level++) { - for (image = 0; image < mt->image_nr; image++) { - nv50_miptree_sync(&nv50->screen->pipe, mt, - level, image); - } - } - if (nv50_tex_construct(so, mt)) { NOUVEAU_ERR("failed tex validate\n"); so_ref(NULL, &so); diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c new file mode 100644 index 00000000000..b025e5df0c5 --- /dev/null +++ b/src/gallium/drivers/nv50/nv50_transfer.c @@ -0,0 +1,216 @@ + +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" + +#include "nv50_context.h" + +struct nv50_transfer { + struct pipe_transfer base; + struct pipe_buffer *buffer; + struct nv50_miptree_level *level; + int level_pitch; + int level_width; + int level_height; + int level_x; + int level_y; +}; + +static void +nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, struct pipe_buffer *src, + int src_pitch, int sx, int sy, int sw, int sh, + struct pipe_buffer *dst, int dst_pitch, int dx, int dy, + int dw, int dh, int cpp, int width, int height, + unsigned src_reloc, unsigned dst_reloc) +{ + struct nv50_screen *screen = nv50_screen(pscreen); + struct nouveau_winsys *nvws = screen->nvws; + struct nouveau_channel *chan = nvws->channel; + struct nouveau_grobj *m2mf = screen->m2mf; + struct nouveau_bo *src_bo = nvws->get_bo(src); + struct nouveau_bo *dst_bo = nvws->get_bo(dst); + unsigned src_offset = 0, dst_offset = 0; + + src_reloc |= NOUVEAU_BO_RD; + dst_reloc |= NOUVEAU_BO_WR; + + WAIT_RING (chan, 14); + + if (!src_bo->tiled) { + BEGIN_RING(chan, m2mf, 0x0200, 1); + OUT_RING (chan, 1); + BEGIN_RING(chan, m2mf, 0x0314, 1); + OUT_RING (chan, src_pitch); + src_offset = (sy * src_pitch) + (sx * cpp); + } else { + BEGIN_RING(chan, m2mf, 0x0200, 6); + OUT_RING (chan, 0); + OUT_RING (chan, 0); + OUT_RING (chan, sw * cpp); + OUT_RING (chan, sh); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + } + + if (!dst_bo->tiled) { + BEGIN_RING(chan, m2mf, 0x021c, 1); + OUT_RING (chan, 1); + BEGIN_RING(chan, m2mf, 0x0318, 1); + OUT_RING (chan, dst_pitch); + dst_offset = (dy * dst_pitch) + (dx * cpp); + } else { + BEGIN_RING(chan, m2mf, 0x021c, 6); + OUT_RING (chan, 0); + OUT_RING (chan, 0); + OUT_RING (chan, dw * cpp); + OUT_RING (chan, dh); + OUT_RING (chan, 1); + OUT_RING (chan, 0); + } + + while (height) { + int line_count = height > 2047 ? 2047 : height; + + WAIT_RING (chan, 15); + BEGIN_RING(chan, m2mf, 0x0238, 2); + OUT_RELOCh(chan, src_bo, src_offset, src_reloc); + OUT_RELOCh(chan, dst_bo, dst_offset, dst_reloc); + BEGIN_RING(chan, m2mf, 0x030c, 2); + OUT_RELOCl(chan, src_bo, src_offset, src_reloc); + OUT_RELOCl(chan, dst_bo, dst_offset, dst_reloc); + if (src_bo->tiled) { + BEGIN_RING(chan, m2mf, 0x0218, 1); + OUT_RING (chan, (dy << 16) | sx); + } else { + src_offset += (line_count * src_pitch); + } + if (dst_bo->tiled) { + BEGIN_RING(chan, m2mf, 0x0234, 1); + OUT_RING (chan, (sy << 16) | dx); + } else { + dst_offset += (line_count * dst_pitch); + } + BEGIN_RING(chan, m2mf, 0x031c, 4); + OUT_RING (chan, width * cpp); + OUT_RING (chan, line_count); + OUT_RING (chan, 0x00000101); + OUT_RING (chan, 0); + FIRE_RING (chan); + + height -= line_count; + sy += line_count; + dy += line_count; + } +} + +static struct pipe_transfer * +nv50_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 nv50_miptree *mt = nv50_miptree(pt); + struct nv50_miptree_level *lvl = &mt->level[level]; + struct nv50_transfer *tx; + unsigned image = 0; + + if (pt->target == PIPE_TEXTURE_CUBE) + image = face; + else + if (pt->target == PIPE_TEXTURE_3D) + image = zslice; + + tx = CALLOC_STRUCT(nv50_transfer); + if (!tx) + return NULL; + + tx->base.refcount = 1; + pipe_texture_reference(&tx->base.texture, pt); + tx->base.format = pt->format; + 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 = (w * pt->block.size); + tx->base.usage = usage; + + tx->level = lvl; + tx->level_pitch = lvl->pitch; + tx->level_width = mt->base.width[level]; + tx->level_height = mt->base.height[level]; + tx->level_x = x; + tx->level_y = y; + tx->buffer = + pipe_buffer_create(pscreen, 0, NOUVEAU_BUFFER_USAGE_TRANSFER, + w * tx->base.block.size * h); + + if (usage != PIPE_TRANSFER_WRITE) { + nv50_transfer_rect_m2mf(pscreen, mt->buffer, tx->level_pitch, + x, y, tx->level_width, tx->level_height, + tx->buffer, tx->base.stride, 0, 0, + tx->base.width, tx->base.height, + tx->base.block.size, w, h, + NOUVEAU_BO_VRAM | NOUVEAU_BO_GART, + NOUVEAU_BO_GART); + } + + return &tx->base; +} + +static void +nv50_transfer_del(struct pipe_screen *pscreen, struct pipe_transfer **pptx) +{ + struct pipe_transfer *ptx = *pptx; + struct nv50_transfer *tx = (struct nv50_transfer *)ptx; + + *pptx = NULL; + if (--ptx->refcount) + return; + + pipe_buffer_reference(pscreen, &tx->buffer, NULL); + pipe_texture_reference(&ptx->texture, NULL); + FREE(ptx); +} + +static void * +nv50_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv50_transfer *tx = (struct nv50_transfer *)ptx; + unsigned flags = 0; + + if (ptx->usage & PIPE_TRANSFER_WRITE) + flags |= PIPE_BUFFER_USAGE_CPU_WRITE; + if (ptx->usage & PIPE_TRANSFER_READ) + flags |= PIPE_BUFFER_USAGE_CPU_READ; + + return pipe_buffer_map(pscreen, tx->buffer, flags); +} + +static void +nv50_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx) +{ + struct nv50_transfer *tx = (struct nv50_transfer *)ptx; + struct nv50_miptree *mt = nv50_miptree(ptx->texture); + + if (ptx->usage != PIPE_TRANSFER_READ) { + nv50_transfer_rect_m2mf(pscreen, tx->buffer, tx->base.stride, + 0, 0, tx->base.width, tx->base.height, + mt->buffer, tx->level_pitch, + tx->level_x, tx->level_y, + tx->level_width, tx->level_height, + tx->base.block.size, tx->base.width, + tx->base.height, NOUVEAU_BO_GART, + NOUVEAU_BO_VRAM | NOUVEAU_BO_GART); + } + + pipe_buffer_unmap(pscreen, mt->buffer); +} + +void +nv50_transfer_init_screen_functions(struct pipe_screen *pscreen) +{ + pscreen->get_tex_transfer = nv50_transfer_new; + pscreen->tex_transfer_release = nv50_transfer_del; + pscreen->transfer_map = nv50_transfer_map; + pscreen->transfer_unmap = nv50_transfer_unmap; +} |