diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.c b/src/gallium/drivers/nouveau/nouveau_buffer.c index 60d8e37a554..f822625af90 100644 --- a/src/gallium/drivers/nouveau/nouveau_buffer.c +++ b/src/gallium/drivers/nouveau/nouveau_buffer.c @@ -24,14 +24,19 @@ static INLINE boolean nouveau_buffer_allocate(struct nouveau_screen *screen, struct nv04_resource *buf, unsigned domain) { + uint32_t size = buf->base.width0; + + if (buf->base.bind & PIPE_BIND_CONSTANT_BUFFER) + size = align(size, 0x100); + if (domain == NOUVEAU_BO_VRAM) { - buf->mm = nouveau_mm_allocate(screen->mm_VRAM, buf->base.width0, + buf->mm = nouveau_mm_allocate(screen->mm_VRAM, size, &buf->bo, &buf->offset); if (!buf->bo) return nouveau_buffer_allocate(screen, buf, NOUVEAU_BO_GART); } else if (domain == NOUVEAU_BO_GART) { - buf->mm = nouveau_mm_allocate(screen->mm_GART, buf->base.width0, + buf->mm = nouveau_mm_allocate(screen->mm_GART, size, &buf->bo, &buf->offset); if (!buf->bo) return FALSE; @@ -129,8 +134,12 @@ nouveau_buffer_upload(struct nouveau_context *nv, struct nv04_resource *buf, uint32_t offset; if (size <= 192) { - nv->push_data(nv, buf->bo, buf->offset + start, buf->domain, - size, buf->data + start); + if (buf->base.bind & PIPE_BIND_CONSTANT_BUFFER) + nv->push_cb(nv, buf->bo, buf->domain, buf->offset, buf->base.width0, + start, size / 4, (const uint32_t *)(buf->data + start)); + else + nv->push_data(nv, buf->bo, buf->offset + start, buf->domain, + size, buf->data + start); return TRUE; } diff --git a/src/gallium/drivers/nouveau/nouveau_context.h b/src/gallium/drivers/nouveau/nouveau_context.h index 7b5f3f1ec39..92aea76b424 100644 --- a/src/gallium/drivers/nouveau/nouveau_context.h +++ b/src/gallium/drivers/nouveau/nouveau_context.h @@ -8,6 +8,7 @@ struct nouveau_context { struct nouveau_screen *screen; boolean vbo_dirty; + boolean cb_dirty; void (*copy_data)(struct nouveau_context *, struct nouveau_bo *dst, unsigned, unsigned, @@ -15,6 +16,11 @@ struct nouveau_context { void (*push_data)(struct nouveau_context *, struct nouveau_bo *dst, unsigned, unsigned, unsigned, const void *); + /* base, size refer to the whole constant buffer */ + void (*push_cb)(struct nouveau_context *, + struct nouveau_bo *, unsigned domain, + unsigned base, unsigned size, + unsigned offset, unsigned words, const uint32_t *); }; static INLINE struct nouveau_context * diff --git a/src/gallium/drivers/nv50/nv50_context.h b/src/gallium/drivers/nv50/nv50_context.h index edd79159e72..2bf634a8237 100644 --- a/src/gallium/drivers/nv50/nv50_context.h +++ b/src/gallium/drivers/nv50/nv50_context.h @@ -53,6 +53,7 @@ #define NV50_BUFCTX_TEXTURES 3 #define NV50_BUFCTX_COUNT 4 +#define NV50_CB_TMP 123 /* fixed constant buffer binding points - low indices for user's constbufs */ #define NV50_CB_PVP 124 #define NV50_CB_PGP 126 @@ -206,6 +207,11 @@ nv50_m2mf_copy_linear(struct nouveau_context *pipe, struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom, struct nouveau_bo *src, unsigned srcoff, unsigned srcdom, unsigned size); +void +nv50_cb_push(struct nouveau_context *nv, + struct nouveau_bo *bo, unsigned domain, + unsigned base, unsigned size, + unsigned offset, unsigned words, const uint32_t *data); /* nv50_vbo.c */ void nv50_draw_vbo(struct pipe_context *, const struct pipe_draw_info *); diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c index c86c417c071..6f860e73348 100644 --- a/src/gallium/drivers/nv50/nv50_transfer.c +++ b/src/gallium/drivers/nv50/nv50_transfer.c @@ -364,3 +364,36 @@ nv50_miptree_transfer_unmap(struct pipe_context *pctx, nouveau_bo_unmap(tx->rect[1].bo); } +void +nv50_cb_push(struct nouveau_context *nv, + struct nouveau_bo *bo, unsigned domain, + unsigned base, unsigned size, + unsigned offset, unsigned words, const uint32_t *data) +{ + struct nouveau_channel *chan = nv->screen->channel; + + assert(!(offset & 3)); + size = align(size, 0x100); + + while (words) { + unsigned nr; + + MARK_RING(chan, 24, 2); + nr = AVAIL_RING(chan); + nr = MIN2(nr - 7, words); + nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1); + + BEGIN_RING(chan, RING_3D(CB_DEF_ADDRESS_HIGH), 3); + OUT_RELOCh(chan, bo, base, domain | NOUVEAU_BO_WR); + OUT_RELOCl(chan, bo, base, domain | NOUVEAU_BO_WR); + OUT_RING (chan, (NV50_CB_TMP << 16) | (size & 0xffff)); + BEGIN_RING(chan, RING_3D(CB_ADDR), 1); + OUT_RING (chan, (offset << 6) | NV50_CB_TMP); + BEGIN_RING_NI(chan, RING_3D(CB_DATA(0)), nr); + OUT_RINGp (chan, data, nr); + + words -= nr; + data += nr; + offset += nr * 4; + } +} diff --git a/src/gallium/drivers/nvc0/nvc0_context.c b/src/gallium/drivers/nvc0/nvc0_context.c index d493d4b2a92..2927a0905bd 100644 --- a/src/gallium/drivers/nvc0/nvc0_context.c +++ b/src/gallium/drivers/nvc0/nvc0_context.c @@ -124,6 +124,7 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) nvc0->base.screen = &screen->base; nvc0->base.copy_data = nvc0_m2mf_copy_linear; nvc0->base.push_data = nvc0_m2mf_push_linear; + nvc0->base.push_cb = nvc0_cb_push; pipe->winsys = pipe_winsys; pipe->screen = pscreen; diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h index c46e7430f85..4435c1b4f3c 100644 --- a/src/gallium/drivers/nvc0/nvc0_context.h +++ b/src/gallium/drivers/nvc0/nvc0_context.h @@ -221,6 +221,11 @@ nvc0_m2mf_copy_linear(struct nouveau_context *nv, struct nouveau_bo *dst, unsigned dstoff, unsigned dstdom, struct nouveau_bo *src, unsigned srcoff, unsigned srcdom, unsigned size); +void +nvc0_cb_push(struct nouveau_context *, + struct nouveau_bo *bo, unsigned domain, + unsigned base, unsigned size, + unsigned offset, unsigned words, const uint32_t *data); /* nvc0_vbo.c */ void nvc0_draw_vbo(struct pipe_context *, const struct pipe_draw_info *); diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c index e60ed972455..1ec95b7f8b5 100644 --- a/src/gallium/drivers/nvc0/nvc0_state_validate.c +++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c @@ -340,7 +340,7 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0) while (nvc0->constbuf_dirty[s]) { unsigned base = 0; - unsigned offset = 0, words = 0; + unsigned words = 0; boolean rebind = TRUE; i = ffs(nvc0->constbuf_dirty[s]) - 1; @@ -356,7 +356,7 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0) } if (!nouveau_resource_mapped_by_gpu(&res->base)) { - if (i == 0) { + if (i == 0 && (res->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY)) { base = s << 16; bo = nvc0->screen->uniforms; @@ -365,19 +365,16 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0) else nvc0->state.uniform_buffer_bound[s] = align(res->base.width0, 0x100); + + words = res->base.width0 / 4; } else { + nouveau_buffer_migrate(&nvc0->base, res, NOUVEAU_BO_VRAM); bo = res->bo; + base = res->offset; } -#if 0 - nvc0_m2mf_push_linear(nvc0, bo, NOUVEAU_BO_VRAM, - base, res->base.width0, res->data); - BEGIN_RING(chan, RING_3D_(0x021c), 1); - OUT_RING (chan, 0x1111); -#else - words = res->base.width0 / 4; -#endif } else { bo = res->bo; + base = res->offset; if (i == 0) nvc0->state.uniform_buffer_bound[s] = 0; } @@ -396,27 +393,10 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0) OUT_RING (chan, (i << 4) | 1); } - while (words) { - unsigned nr = AVAIL_RING(chan); - - if (nr < 16) { - FIRE_RING(chan); - continue; - } - nr = MIN2(MIN2(nr - 6, words), NV04_PFIFO_MAX_PACKET_LEN - 1); - - MARK_RING (chan, nr + 5, 2); - BEGIN_RING(chan, RING_3D(CB_SIZE), 3); - OUT_RING (chan, align(res->base.width0, 0x100)); - OUT_RELOCh(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - OUT_RELOCl(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); - BEGIN_RING_1I(chan, RING_3D(CB_POS), nr + 1); - OUT_RING (chan, offset); - OUT_RINGp (chan, &res->data[offset], nr); - - offset += nr * 4; - words -= nr; - } + if (words) + nvc0_cb_push(&nvc0->base, + bo, NOUVEAU_BO_VRAM, base, res->base.width0, + 0, words, (const uint32_t *)res->data); } } } diff --git a/src/gallium/drivers/nvc0/nvc0_transfer.c b/src/gallium/drivers/nvc0/nvc0_transfer.c index 6404c8cc4ae..f16863733b7 100644 --- a/src/gallium/drivers/nvc0/nvc0_transfer.c +++ b/src/gallium/drivers/nvc0/nvc0_transfer.c @@ -365,3 +365,39 @@ nvc0_miptree_transfer_unmap(struct pipe_context *pctx, nouveau_bo_unmap(tx->rect[1].bo); } +void +nvc0_cb_push(struct nouveau_context *nv, + struct nouveau_bo *bo, unsigned domain, + unsigned base, unsigned size, + unsigned offset, unsigned words, const uint32_t *data) +{ + struct nouveau_channel *chan = nv->screen->channel; + + assert(!(offset & 3)); + size = align(size, 0x100); + + MARK_RING (chan, 16, 2); + BEGIN_RING(chan, RING_3D(CB_SIZE), 3); + OUT_RING (chan, size); + OUT_RELOCh(chan, bo, base, domain | NOUVEAU_BO_WR); + OUT_RELOCl(chan, bo, base, domain | NOUVEAU_BO_WR); + + while (words) { + unsigned nr = AVAIL_RING(chan); + nr = MIN2(nr, words); + nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1); + + BEGIN_RING_1I(chan, RING_3D(CB_POS), nr + 1); + OUT_RING (chan, offset); + OUT_RINGp (chan, data, nr); + + words -= nr; + data += nr; + offset += nr * 4; + + if (words) { + MARK_RING(chan, 6, 1); + nouveau_bo_validate(chan, bo, domain | NOUVEAU_BO_WR); + } + } +}