From 28271fd00dc5dd83f95b5cb890e0ab2c0ff6159d Mon Sep 17 00:00:00 2001 From: Christoph Bumiller Date: Tue, 18 Oct 2011 12:08:19 +0200 Subject: [PATCH] nvc0: add support for linear and buffer textures and RTs --- src/gallium/drivers/nv50/nv50_miptree.c | 10 --- src/gallium/drivers/nv50/nv50_resource.c | 62 ++++++++++++++++- src/gallium/drivers/nv50/nv50_resource.h | 7 +- src/gallium/drivers/nvc0/nvc0_miptree.c | 3 + src/gallium/drivers/nvc0/nvc0_resource.c | 14 +++- src/gallium/drivers/nvc0/nvc0_state_validate.c | 65 ++++++++++++------ src/gallium/drivers/nvc0/nvc0_surface.c | 93 ++++++++++++++++---------- src/gallium/drivers/nvc0/nvc0_tex.c | 41 +++++++++--- 8 files changed, 213 insertions(+), 82 deletions(-) diff --git a/src/gallium/drivers/nv50/nv50_miptree.c b/src/gallium/drivers/nv50/nv50_miptree.c index 47090e1..76b6059 100644 --- a/src/gallium/drivers/nv50/nv50_miptree.c +++ b/src/gallium/drivers/nv50/nv50_miptree.c @@ -424,13 +424,3 @@ nv50_miptree_surface_new(struct pipe_context *pipe, return &ns->base; } - -void -nv50_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps) -{ - struct nv50_surface *s = nv50_surface(ps); - - pipe_resource_reference(&ps->texture, NULL); - - FREE(s); -} diff --git a/src/gallium/drivers/nv50/nv50_resource.c b/src/gallium/drivers/nv50/nv50_resource.c index 1ae4d70..a66a6a0 100644 --- a/src/gallium/drivers/nv50/nv50_resource.c +++ b/src/gallium/drivers/nv50/nv50_resource.c @@ -1,8 +1,11 @@ #include "pipe/p_context.h" -#include "nv50_resource.h" +#include "util/u_inlines.h" +#include "util/u_format.h" + #include "nouveau/nouveau_screen.h" +#include "nv50_resource.h" static struct pipe_resource * nv50_resource_create(struct pipe_screen *screen, @@ -27,6 +30,59 @@ nv50_resource_from_handle(struct pipe_screen * screen, return nv50_miptree_from_handle(screen, templ, whandle); } +struct pipe_surface * +nv50_surface_from_buffer(struct pipe_context *pipe, + struct pipe_resource *pbuf, + const struct pipe_surface *templ) +{ + struct nv50_surface *sf = CALLOC_STRUCT(nv50_surface); + if (!sf) + return NULL; + + pipe_reference_init(&sf->base.reference, 1); + pipe_resource_reference(&sf->base.texture, pbuf); + + sf->base.format = templ->format; + sf->base.usage = templ->usage; + sf->base.u.buf.first_element = templ->u.buf.first_element; + sf->base.u.buf.last_element = templ->u.buf.last_element; + + sf->offset = + templ->u.buf.first_element * util_format_get_blocksize(sf->base.format); + + sf->offset &= ~0x7f; /* FIXME: RT_ADDRESS requires 128 byte alignment */ + + sf->width = templ->u.buf.last_element - templ->u.buf.first_element + 1; + sf->height = 1; + sf->depth = 1; + + sf->base.width = sf->width; + sf->base.height = sf->height; + + sf->base.context = pipe; + return &sf->base; +} + +static struct pipe_surface * +nv50_surface_create(struct pipe_context *pipe, + struct pipe_resource *pres, + const struct pipe_surface *templ) +{ + if (unlikely(pres->target == PIPE_BUFFER)) + return nv50_surface_from_buffer(pipe, pres, templ); + return nv50_miptree_surface_new(pipe, pres, templ); +} + +void +nv50_surface_destroy(struct pipe_context *pipe, struct pipe_surface *ps) +{ + struct nv50_surface *s = nv50_surface(ps); + + pipe_resource_reference(&ps->texture, NULL); + + FREE(s); +} + void nv50_init_resource_functions(struct pipe_context *pcontext) { @@ -36,8 +92,8 @@ nv50_init_resource_functions(struct pipe_context *pcontext) pcontext->transfer_unmap = u_transfer_unmap_vtbl; pcontext->transfer_destroy = u_transfer_destroy_vtbl; pcontext->transfer_inline_write = u_transfer_inline_write_vtbl; - pcontext->create_surface = nv50_miptree_surface_new; - pcontext->surface_destroy = nv50_miptree_surface_del; + pcontext->create_surface = nv50_surface_create; + pcontext->surface_destroy = nv50_surface_destroy; } void diff --git a/src/gallium/drivers/nv50/nv50_resource.h b/src/gallium/drivers/nv50/nv50_resource.h index 66d2120..50cc2af 100644 --- a/src/gallium/drivers/nv50/nv50_resource.h +++ b/src/gallium/drivers/nv50/nv50_resource.h @@ -129,7 +129,12 @@ struct nv50_surface * nv50_surface_from_miptree(struct nv50_miptree *mt, const struct pipe_surface *templ); +struct pipe_surface * +nv50_surface_from_buffer(struct pipe_context *pipe, + struct pipe_resource *pt, + const struct pipe_surface *templ); + void -nv50_miptree_surface_del(struct pipe_context *, struct pipe_surface *); +nv50_surface_destroy(struct pipe_context *, struct pipe_surface *); #endif /* __NV50_RESOURCE_H__ */ diff --git a/src/gallium/drivers/nvc0/nvc0_miptree.c b/src/gallium/drivers/nvc0/nvc0_miptree.c index 6cdc8ab..a9d2c85 100644 --- a/src/gallium/drivers/nvc0/nvc0_miptree.c +++ b/src/gallium/drivers/nvc0/nvc0_miptree.c @@ -149,6 +149,9 @@ nvc0_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed) if (mt->base.base.bind & PIPE_BIND_SCANOUT) tile_flags |= NOUVEAU_BO_TILE_SCANOUT; + if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR)) + tile_flags &= ~0xff00; + return tile_flags; } diff --git a/src/gallium/drivers/nvc0/nvc0_resource.c b/src/gallium/drivers/nvc0/nvc0_resource.c index a028972..e8d83ca 100644 --- a/src/gallium/drivers/nvc0/nvc0_resource.c +++ b/src/gallium/drivers/nvc0/nvc0_resource.c @@ -31,6 +31,16 @@ nvc0_resource_from_handle(struct pipe_screen * screen, } } +static struct pipe_surface * +nvc0_surface_create(struct pipe_context *pipe, + struct pipe_resource *pres, + const struct pipe_surface *templ) +{ + if (unlikely(pres->target == PIPE_BUFFER)) + return nv50_surface_from_buffer(pipe, pres, templ); + return nvc0_miptree_surface_new(pipe, pres, templ); +} + void nvc0_init_resource_functions(struct pipe_context *pcontext) { @@ -40,8 +50,8 @@ nvc0_init_resource_functions(struct pipe_context *pcontext) pcontext->transfer_unmap = u_transfer_unmap_vtbl; pcontext->transfer_destroy = u_transfer_destroy_vtbl; pcontext->transfer_inline_write = u_transfer_inline_write_vtbl; - pcontext->create_surface = nvc0_miptree_surface_new; - pcontext->surface_destroy = nv50_miptree_surface_del; + pcontext->create_surface = nvc0_surface_create; + pcontext->surface_destroy = nv50_surface_destroy; } void diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c index 5cf68c7..e60ed97 100644 --- a/src/gallium/drivers/nvc0/nvc0_state_validate.c +++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c @@ -73,33 +73,56 @@ nvc0_validate_fb(struct nvc0_context *nvc0) MARK_RING(chan, 9 * fb->nr_cbufs, 2 * fb->nr_cbufs); for (i = 0; i < fb->nr_cbufs; ++i) { - struct nv50_miptree *mt = nv50_miptree(fb->cbufs[i]->texture); struct nv50_surface *sf = nv50_surface(fb->cbufs[i]); - struct nouveau_bo *bo = mt->base.bo; - uint32_t offset = sf->offset; + struct nv04_resource *res = nv04_resource(sf->base.texture); + struct nouveau_bo *bo = res->bo; + uint32_t offset = sf->offset + res->offset; BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(i)), 9); - OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR); - OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR); - OUT_RING (chan, sf->width); - OUT_RING (chan, sf->height); - OUT_RING (chan, nvc0_format_table[sf->base.format].rt); - OUT_RING (chan, (mt->layout_3d << 16) | - mt->level[sf->base.u.tex.level].tile_mode); - OUT_RING (chan, sf->base.u.tex.first_layer + sf->depth); - OUT_RING (chan, mt->layer_stride >> 2); - OUT_RING (chan, sf->base.u.tex.first_layer); - - ms_mode = mt->ms_mode; - - if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING) + OUT_RELOCh(chan, res->bo, offset, res->domain | NOUVEAU_BO_RDWR); + OUT_RELOCl(chan, res->bo, offset, res->domain | NOUVEAU_BO_RDWR); + if (likely(nouveau_bo_tile_layout(bo))) { + struct nv50_miptree *mt = nv50_miptree(sf->base.texture); + + assert(sf->base.texture->target != PIPE_BUFFER); + + OUT_RING(chan, sf->width); + OUT_RING(chan, sf->height); + OUT_RING(chan, nvc0_format_table[sf->base.format].rt); + OUT_RING(chan, (mt->layout_3d << 16) | + mt->level[sf->base.u.tex.level].tile_mode); + OUT_RING(chan, sf->base.u.tex.first_layer + sf->depth); + OUT_RING(chan, mt->layer_stride >> 2); + OUT_RING(chan, sf->base.u.tex.first_layer); + + ms_mode = mt->ms_mode; + } else { + if (res->base.target == PIPE_BUFFER) { + OUT_RING(chan, 262144); + OUT_RING(chan, 1); + } else { + OUT_RING(chan, nv50_miptree(sf->base.texture)->level[0].pitch); + OUT_RING(chan, sf->height); + } + OUT_RING(chan, nvc0_format_table[sf->base.format].rt); + OUT_RING(chan, 1 << 12); + OUT_RING(chan, 1); + OUT_RING(chan, 0); + OUT_RING(chan, 0); + + nvc0_resource_fence(res, NOUVEAU_BO_WR); + + assert(!fb->zsbuf); + } + + if (res->status & NOUVEAU_BUFFER_STATUS_GPU_READING) serialize = TRUE; - mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; - mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING; + res->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; + res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING; /* only register for writing, otherwise we'd always serialize here */ - nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, &mt->base, - NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); + nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, res, + res->domain | NOUVEAU_BO_WR); } if (fb->zsbuf) { diff --git a/src/gallium/drivers/nvc0/nvc0_surface.c b/src/gallium/drivers/nvc0/nvc0_surface.c index 5c4e1aa..f807535 100644 --- a/src/gallium/drivers/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nvc0/nvc0_surface.c @@ -271,48 +271,69 @@ nvc0_clear_render_target(struct pipe_context *pipe, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { - struct nvc0_context *nv50 = nvc0_context(pipe); - struct nvc0_screen *screen = nv50->screen; - struct nouveau_channel *chan = screen->base.channel; - struct nv50_miptree *mt = nv50_miptree(dst->texture); - struct nv50_surface *sf = nv50_surface(dst); - struct nouveau_bo *bo = mt->base.bo; - unsigned z; + struct nvc0_context *nv50 = nvc0_context(pipe); + struct nvc0_screen *screen = nv50->screen; + struct nouveau_channel *chan = screen->base.channel; + struct nv50_surface *sf = nv50_surface(dst); + struct nv04_resource *res = nv04_resource(sf->base.texture); + unsigned z; - BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); - OUT_RINGf (chan, color->f[0]); - OUT_RINGf (chan, color->f[1]); - OUT_RINGf (chan, color->f[2]); - OUT_RINGf (chan, color->f[3]); + BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); + OUT_RINGf (chan, color->f[0]); + OUT_RINGf (chan, color->f[1]); + OUT_RINGf (chan, color->f[2]); + OUT_RINGf (chan, color->f[3]); - if (MARK_RING(chan, 18, 2)) - return; + if (MARK_RING(chan, 18, 2)) + return; - BEGIN_RING(chan, RING_3D(SCREEN_SCISSOR_HORIZ), 2); - OUT_RING (chan, ( width << 16) | dstx); - OUT_RING (chan, (height << 16) | dsty); + BEGIN_RING(chan, RING_3D(SCREEN_SCISSOR_HORIZ), 2); + OUT_RING (chan, ( width << 16) | dstx); + OUT_RING (chan, (height << 16) | dsty); + + BEGIN_RING(chan, RING_3D(RT_CONTROL), 1); + OUT_RING (chan, 1); + BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 9); + OUT_RESRCh(chan, res, sf->offset, NOUVEAU_BO_WR); + OUT_RESRCl(chan, res, sf->offset, NOUVEAU_BO_WR); + if (likely(nouveau_bo_tile_layout(res->bo))) { + struct nv50_miptree *mt = nv50_miptree(dst->texture); + + OUT_RING(chan, sf->width); + OUT_RING(chan, sf->height); + OUT_RING(chan, nvc0_format_table[dst->format].rt); + OUT_RING(chan, (mt->layout_3d << 16) | + mt->level[sf->base.u.tex.level].tile_mode); + OUT_RING(chan, dst->u.tex.first_layer + sf->depth); + OUT_RING(chan, mt->layer_stride >> 2); + OUT_RING(chan, dst->u.tex.first_layer); + } else { + if (res->base.target == PIPE_BUFFER) { + OUT_RING(chan, 262144); + OUT_RING(chan, 1); + } else { + OUT_RING(chan, nv50_miptree(&res->base)->level[0].pitch); + OUT_RING(chan, sf->height); + } + OUT_RING(chan, nvc0_format_table[sf->base.format].rt); + OUT_RING(chan, 1 << 12); + OUT_RING(chan, 1); + OUT_RING(chan, 0); + OUT_RING(chan, 0); - BEGIN_RING(chan, RING_3D(RT_CONTROL), 1); - OUT_RING (chan, 1); - BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 9); - OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); - OUT_RING (chan, sf->width); - OUT_RING (chan, sf->height); - OUT_RING (chan, nvc0_format_table[dst->format].rt); - OUT_RING (chan, (mt->layout_3d << 16) | - mt->level[sf->base.u.tex.level].tile_mode); - OUT_RING (chan, dst->u.tex.first_layer + sf->depth); - OUT_RING (chan, mt->layer_stride >> 2); - OUT_RING (chan, dst->u.tex.first_layer); + IMMED_RING(chan, RING_3D(ZETA_ENABLE), 0); - for (z = 0; z < sf->depth; ++z) { - BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); - OUT_RING (chan, 0x3c | - (z << NVC0_3D_CLEAR_BUFFERS_LAYER__SHIFT)); - } + /* tiled textures don't have to be fenced, they're not mapped directly */ + nvc0_resource_fence(res, NOUVEAU_BO_WR); + } - nv50->dirty |= NVC0_NEW_FRAMEBUFFER; + for (z = 0; z < sf->depth; ++z) { + BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); + OUT_RING (chan, 0x3c | + (z << NVC0_3D_CLEAR_BUFFERS_LAYER__SHIFT)); + } + + nv50->dirty |= NVC0_NEW_FRAMEBUFFER; } static void diff --git a/src/gallium/drivers/nvc0/nvc0_tex.c b/src/gallium/drivers/nvc0/nvc0_tex.c index a4573d7..0a1bc37 100644 --- a/src/gallium/drivers/nvc0/nvc0_tex.c +++ b/src/gallium/drivers/nvc0/nvc0_tex.c @@ -60,7 +60,7 @@ nvc0_create_sampler_view(struct pipe_context *pipe, uint32_t swz[4]; uint32_t depth; struct nv50_tic_entry *view; - struct nv50_miptree *mt = nv50_miptree(texture); + struct nv50_miptree *mt; boolean tex_int; view = MALLOC_STRUCT(nv50_tic_entry); @@ -104,6 +104,32 @@ nvc0_create_sampler_view(struct pipe_context *pipe, if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) tic[2] |= NV50_TIC_2_COLORSPACE_SRGB; + /* check for linear storage type */ + if (unlikely(!nouveau_bo_tile_layout(nv04_resource(texture)->bo))) { + if (texture->target == PIPE_BUFFER) { + tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_BUFFER; + tic[1] = /* address offset */ + view->pipe.u.buf.first_element * desc->block.bits / 8; + tic[3] = 0; + tic[4] = /* width */ + view->pipe.u.buf.last_element - view->pipe.u.buf.first_element + 1; + tic[5] = 0; + } else { + mt = nv50_miptree(texture); + /* must be 2D texture without mip maps */ + tic[2] |= NV50_TIC_2_LINEAR | NV50_TIC_2_TARGET_RECT; + if (texture->target != PIPE_TEXTURE_RECT) + tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; + tic[3] = mt->level[0].pitch; + tic[4] = mt->base.base.width0; + tic[5] = (1 << 16) | mt->base.base.height0; + } + tic[6] = + tic[7] = 0; + return &view->pipe; + } + mt = nv50_miptree(texture); + if (mt->base.base.target != PIPE_TEXTURE_RECT) tic[2] |= NV50_TIC_2_NORMALIZED_COORDS; @@ -147,9 +173,6 @@ nvc0_create_sampler_view(struct pipe_context *pipe, case PIPE_TEXTURE_2D_ARRAY: tic[2] |= NV50_TIC_2_TARGET_2D_ARRAY; break; - case PIPE_BUFFER: - tic[2] |= NV50_TIC_2_TARGET_BUFFER | NV50_TIC_2_LINEAR; - break; default: NOUVEAU_ERR("invalid texture target: %d\n", mt->base.base.target); return FALSE; @@ -196,10 +219,10 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s) OUT_RING (chan, (i << 1) | 0); continue; } - res = &nv50_miptree(tic->pipe.texture)->base; + res = nv04_resource(tic->pipe.texture); if (tic->id < 0) { - uint32_t offset = tic->tic[1]; + uint32_t offset = res->offset + tic->tic[1]; tic->id = nvc0_screen_tic_alloc(nvc0->screen, tic); @@ -214,8 +237,8 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s) OUT_RING (chan, 0x100111); BEGIN_RING_NI(chan, RING_MF(DATA), 8); OUT_RING (chan, tic->tic[0]); - OUT_RELOCl(chan, res->bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RELOC (chan, res->bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | + OUT_RELOCl(chan, res->bo, offset, res->domain | NOUVEAU_BO_RD); + OUT_RELOC (chan, res->bo, offset, res->domain | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH | NOUVEAU_BO_OR, tic->tic[2], tic->tic[2]); OUT_RINGp (chan, &tic->tic[3], 5); @@ -231,7 +254,7 @@ nvc0_validate_tic(struct nvc0_context *nvc0, int s) res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING; nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_TEXTURES, res, - NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); + res->domain | NOUVEAU_BO_RD); BEGIN_RING(chan, RING_3D(BIND_TIC(s)), 1); OUT_RING (chan, (tic->id << 9) | (i << 1) | 1); -- 2.7.4