nvc0: keep track of cb bindings per buffer, use for upload settings

CB updates to bound buffers need to go through the CB_DATA endpoints,
otherwise the shader may not notice that the updates happened.
Furthermore, these updates have to go in to the same address as the
bound buffer, otherwise, again, the shader may not notice updates.

So we keep track of all the places where a constbuf is bound, and
iterate over all of them when updating data. If a binding is found that
encompasses the region to be updated, then we use the settings of that
binding for the upload. Otherwise we upload as a regular data update.

This fixes piglit 'arb_uniform_buffer_object-rendering offset' as well
as blurriness in Witcher2.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91890
Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Cc: "11.0" <mesa-stable@lists.freedesktop.org>
This commit is contained in:
Ilia Mirkin 2015-09-09 03:17:38 -04:00
parent b828f7a27b
commit e50c01d5af
7 changed files with 58 additions and 12 deletions

View file

@ -206,8 +206,8 @@ nouveau_transfer_write(struct nouveau_context *nv, struct nouveau_transfer *tx,
nv->copy_data(nv, buf->bo, buf->offset + base, buf->domain, nv->copy_data(nv, buf->bo, buf->offset + base, buf->domain,
tx->bo, tx->offset + offset, NOUVEAU_BO_GART, size); tx->bo, tx->offset + offset, NOUVEAU_BO_GART, size);
else else
if ((buf->base.bind & PIPE_BIND_CONSTANT_BUFFER) && nv->push_cb && can_cb) if (nv->push_cb && can_cb)
nv->push_cb(nv, buf->bo, buf->domain, buf->offset, buf->base.width0, nv->push_cb(nv, buf,
base, size / 4, (const uint32_t *)data); base, size / 4, (const uint32_t *)data);
else else
nv->push_data(nv, buf->bo, buf->offset + base, buf->domain, size, data); nv->push_data(nv, buf->bo, buf->offset + base, buf->domain, size, data);

View file

@ -41,6 +41,8 @@ struct nv04_resource {
uint8_t status; uint8_t status;
uint8_t domain; uint8_t domain;
uint16_t cb_bindings[6]; /* per-shader per-slot bindings */
struct nouveau_fence *fence; struct nouveau_fence *fence;
struct nouveau_fence *fence_wr; struct nouveau_fence *fence_wr;

View file

@ -6,6 +6,8 @@
#define NOUVEAU_MAX_SCRATCH_BUFS 4 #define NOUVEAU_MAX_SCRATCH_BUFS 4
struct nv04_resource;
struct nouveau_context { struct nouveau_context {
struct pipe_context pipe; struct pipe_context pipe;
struct nouveau_screen *screen; struct nouveau_screen *screen;
@ -23,8 +25,7 @@ struct nouveau_context {
unsigned, const void *); unsigned, const void *);
/* base, size refer to the whole constant buffer */ /* base, size refer to the whole constant buffer */
void (*push_cb)(struct nouveau_context *, void (*push_cb)(struct nouveau_context *,
struct nouveau_bo *, unsigned domain, struct nv04_resource *,
unsigned base, unsigned size,
unsigned offset, unsigned words, const uint32_t *); unsigned offset, unsigned words, const uint32_t *);
/* @return: @ref reduced by nr of references found in context */ /* @return: @ref reduced by nr of references found in context */

View file

@ -299,7 +299,7 @@ nve4_p2mf_push_linear(struct nouveau_context *nv,
struct nouveau_bo *dst, unsigned offset, unsigned domain, struct nouveau_bo *dst, unsigned offset, unsigned domain,
unsigned size, const void *data); unsigned size, const void *data);
void void
nvc0_cb_push(struct nouveau_context *, nvc0_cb_bo_push(struct nouveau_context *,
struct nouveau_bo *bo, unsigned domain, struct nouveau_bo *bo, unsigned domain,
unsigned base, unsigned size, unsigned base, unsigned size,
unsigned offset, unsigned words, const uint32_t *data); unsigned offset, unsigned words, const uint32_t *data);

View file

@ -831,6 +831,8 @@ nvc0_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index,
} }
nvc0->constbuf_dirty[s] |= 1 << i; nvc0->constbuf_dirty[s] |= 1 << i;
if (nvc0->constbuf[s][i].u.buf)
nv04_resource(nvc0->constbuf[s][i].u.buf)->cb_bindings[s] &= ~(1 << i);
pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, res); pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, res);
nvc0->constbuf[s][i].user = (cb && cb->user_buffer) ? true : false; nvc0->constbuf[s][i].user = (cb && cb->user_buffer) ? true : false;

View file

@ -440,7 +440,7 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0)
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1);
PUSH_DATA (push, (0 << 4) | 1); PUSH_DATA (push, (0 << 4) | 1);
} }
nvc0_cb_push(&nvc0->base, bo, NV_VRAM_DOMAIN(&nvc0->screen->base), nvc0_cb_bo_push(&nvc0->base, bo, NV_VRAM_DOMAIN(&nvc0->screen->base),
base, nvc0->state.uniform_buffer_bound[s], base, nvc0->state.uniform_buffer_bound[s],
0, (size + 3) / 4, 0, (size + 3) / 4,
nvc0->constbuf[s][0].u.data); nvc0->constbuf[s][0].u.data);
@ -458,6 +458,7 @@ nvc0_constbufs_validate(struct nvc0_context *nvc0)
BCTX_REFN(nvc0->bufctx_3d, CB(s, i), res, RD); BCTX_REFN(nvc0->bufctx_3d, CB(s, i), res, RD);
nvc0->cb_dirty = 1; /* Force cache flush for UBO. */ nvc0->cb_dirty = 1; /* Force cache flush for UBO. */
res->cb_bindings[s] |= 1 << i;
} else { } else {
BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1); BEGIN_NVC0(push, NVC0_3D(CB_BIND(s)), 1);
PUSH_DATA (push, (i << 4) | 0); PUSH_DATA (push, (i << 4) | 0);

View file

@ -506,8 +506,45 @@ nvc0_miptree_transfer_unmap(struct pipe_context *pctx,
} }
/* This happens rather often with DTD9/st. */ /* This happens rather often with DTD9/st. */
void static void
nvc0_cb_push(struct nouveau_context *nv, nvc0_cb_push(struct nouveau_context *nv,
struct nv04_resource *res,
unsigned offset, unsigned words, const uint32_t *data)
{
struct nvc0_context *nvc0 = nvc0_context(&nv->pipe);
struct nvc0_constbuf *cb = NULL;
int s;
/* Go through all the constbuf binding points of this buffer and try to
* find one which contains the region to be updated.
*/
for (s = 0; s < 6 && !cb; s++) {
uint16_t bindings = res->cb_bindings[s];
while (bindings) {
int i = ffs(bindings) - 1;
uint32_t cb_offset = nvc0->constbuf[s][i].offset;
bindings &= ~(1 << i);
if (cb_offset <= offset &&
cb_offset + nvc0->constbuf[s][i].size >= offset + words * 4) {
cb = &nvc0->constbuf[s][i];
break;
}
}
}
if (cb) {
nvc0_cb_bo_push(nv, res->bo, res->domain,
res->offset + cb->offset, cb->size,
offset - cb->offset, words, data);
} else {
nv->push_data(nv, res->bo, res->offset + offset, res->domain,
words * 4, data);
}
}
void
nvc0_cb_bo_push(struct nouveau_context *nv,
struct nouveau_bo *bo, unsigned domain, struct nouveau_bo *bo, unsigned domain,
unsigned base, unsigned size, unsigned base, unsigned size,
unsigned offset, unsigned words, const uint32_t *data) unsigned offset, unsigned words, const uint32_t *data)
@ -520,6 +557,9 @@ nvc0_cb_push(struct nouveau_context *nv,
assert(!(offset & 3)); assert(!(offset & 3));
size = align(size, 0x100); size = align(size, 0x100);
assert(offset < size);
assert(offset + words * 4 <= size);
BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
PUSH_DATA (push, size); PUSH_DATA (push, size);
PUSH_DATAh(push, bo->offset + base); PUSH_DATAh(push, bo->offset + base);