nouveau: rework buffer validation a bit

This commit is contained in:
Ben Skeggs 2008-05-30 00:38:07 +10:00
parent d0c0c0d1e6
commit 524408f1a5
2 changed files with 69 additions and 60 deletions

View file

@ -107,7 +107,7 @@ extern void
nouveau_fence_flush(struct nouveau_channel *);
struct nouveau_pushbuf_reloc {
uint64_t next;
struct nouveau_pushbuf_bo *pbbo;
uint32_t *ptr;
uint32_t flags;
uint32_t data;
@ -116,13 +116,14 @@ struct nouveau_pushbuf_reloc {
};
struct nouveau_pushbuf_bo {
uint64_t next;
uint64_t handle;
uint64_t flags;
uint64_t relocs;
int nr_relocs;
struct nouveau_channel *channel;
struct nouveau_bo *bo;
unsigned flags;
unsigned handled;
};
#define NOUVEAU_PUSHBUF_MAX_BUFFERS 1024
#define NOUVEAU_PUSHBUF_MAX_RELOCS 1024
struct nouveau_pushbuf_priv {
struct nouveau_pushbuf base;
@ -132,8 +133,10 @@ struct nouveau_pushbuf_priv {
unsigned start;
unsigned size;
uint64_t buffers;
int nr_buffers;
struct nouveau_pushbuf_bo *buffers;
unsigned nr_buffers;
struct nouveau_pushbuf_reloc *relocs;
unsigned nr_relocs;
};
#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
@ -242,6 +245,7 @@ nouveau_notifier_wait_status(struct nouveau_notifier *, int id, int status,
struct nouveau_bo_priv {
struct nouveau_bo base;
struct nouveau_pushbuf_bo *pending;
struct nouveau_fence *fence;
struct nouveau_fence *wr_fence;

View file

@ -97,6 +97,10 @@ nouveau_pushbuf_init(struct nouveau_channel *chan)
nouveau_pushbuf_space(chan, 0);
chan->pushbuf = &nvchan->pb.base;
nvchan->pb.buffers = calloc(NOUVEAU_PUSHBUF_MAX_BUFFERS,
sizeof(struct nouveau_pushbuf_bo));
nvchan->pb.relocs = calloc(NOUVEAU_PUSHBUF_MAX_RELOCS,
sizeof(struct nouveau_pushbuf_reloc));
return 0;
}
@ -131,8 +135,7 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
struct nouveau_pushbuf_bo *pbbo;
int ret;
int ret, i;
if (nvpb->base.remaining == nvpb->size)
return 0;
@ -150,38 +153,47 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
/* Validate buffers + apply relocations */
nvchan->user_charge = 0;
while ((pbbo = ptr_to_pbbo(nvpb->buffers))) {
struct nouveau_pushbuf_reloc *r;
struct nouveau_bo *bo = &ptr_to_bo(pbbo->handle)->base;
for (i = 0; i < nvpb->nr_relocs; i++) {
struct nouveau_pushbuf_reloc *r = &nvpb->relocs[i];
struct nouveau_pushbuf_bo *pbbo = r->pbbo;
struct nouveau_bo *bo = pbbo->bo;
ret = nouveau_bo_validate(chan, bo, pbbo->flags);
assert (ret == 0);
if (bo->offset == nouveau_bo(bo)->offset &&
bo->flags == nouveau_bo(bo)->flags) {
while ((r = ptr_to_pbrel(pbbo->relocs))) {
pbbo->relocs = r->next;
free(r);
}
nouveau_bo_del(&bo);
nvpb->buffers = pbbo->next;
free(pbbo);
/* Validated, mem matches presumed, no relocation necessary */
if (pbbo->handled & 2) {
if (!(pbbo->handled & 1))
assert(0);
continue;
}
bo->offset = nouveau_bo(bo)->offset;
bo->flags = nouveau_bo(bo)->flags;
while ((r = ptr_to_pbrel(pbbo->relocs))) {
*r->ptr = nouveau_pushbuf_calc_reloc(bo, r);
pbbo->relocs = r->next;
free(r);
/* Not yet validated, do it now */
if (!(pbbo->handled & 1)) {
ret = nouveau_bo_validate(chan, bo, pbbo->flags);
if (ret) {
assert(0);
return ret;
}
pbbo->handled |= 1;
if (bo->offset == nouveau_bo(bo)->offset &&
bo->flags == nouveau_bo(bo)->flags) {
pbbo->handled |= 2;
continue;
}
bo->offset = nouveau_bo(bo)->offset;
bo->flags = nouveau_bo(bo)->flags;
}
nouveau_bo_del(&bo);
nvpb->buffers = pbbo->next;
free(pbbo);
/* Apply the relocation */
*r->ptr = nouveau_pushbuf_calc_reloc(bo, r);
}
nvpb->nr_relocs = 0;
/* Dereference all buffers on validate list */
for (i = 0; i < nvpb->nr_buffers; i++) {
struct nouveau_pushbuf_bo *pbbo = &nvpb->buffers[i];
nouveau_bo(pbbo->bo)->pending = NULL;
nouveau_bo_del(&pbbo->bo);
}
nvpb->nr_buffers = 0;
@ -206,25 +218,21 @@ static struct nouveau_pushbuf_bo *
nouveau_pushbuf_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
{
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
struct nouveau_pushbuf_bo *pbbo = ptr_to_pbbo(nvpb->buffers);
struct nouveau_bo *ref = NULL;
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
struct nouveau_pushbuf_bo *pbbo;
while (pbbo) {
if (pbbo->handle == bo->handle)
return pbbo;
pbbo = ptr_to_pbbo(pbbo->next);
}
if (nvbo->pending)
return nvbo->pending;
pbbo = malloc(sizeof(struct nouveau_pushbuf_bo));
pbbo->next = nvpb->buffers;
nvpb->buffers = pbbo_to_ptr(pbbo);
nvpb->nr_buffers++;
if (nvpb->nr_buffers >= NOUVEAU_PUSHBUF_MAX_BUFFERS)
return NULL;
pbbo = nvpb->buffers + nvpb->nr_buffers++;
nvbo->pending = pbbo;
nouveau_bo_ref(bo->device, bo->handle, &ref);
pbbo->handle = bo_to_ptr(ref);
nouveau_bo_ref(bo->device, bo->handle, &pbbo->bo);
pbbo->channel = chan;
pbbo->flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
pbbo->relocs = 0;
pbbo->nr_relocs = 0;
pbbo->handled = 0;
return pbbo;
}
@ -233,24 +241,21 @@ nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
struct nouveau_bo *bo, uint32_t data, uint32_t flags,
uint32_t vor, uint32_t tor)
{
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
struct nouveau_pushbuf_bo *pbbo;
struct nouveau_pushbuf_reloc *r;
if (!chan)
return -EINVAL;
if (nvpb->nr_relocs >= NOUVEAU_PUSHBUF_MAX_RELOCS)
return -ENOMEM;
pbbo = nouveau_pushbuf_emit_buffer(chan, bo);
if (!pbbo)
return -EFAULT;
r = malloc(sizeof(struct nouveau_pushbuf_reloc));
r->next = pbbo->relocs;
pbbo->relocs = pbrel_to_ptr(r);
pbbo->nr_relocs++;
return -ENOMEM;
pbbo->flags |= (flags & NOUVEAU_BO_RDWR);
pbbo->flags &= (flags | NOUVEAU_BO_RDWR);
r = nvpb->relocs + nvpb->nr_relocs++;
r->pbbo = pbbo;
r->ptr = ptr;
r->flags = flags;
r->data = data;