diff options
author | Ben Skeggs <skeggsb@gmail.com> | 2008-05-30 00:38:07 +1000 |
---|---|---|
committer | Ben Skeggs <skeggsb@gmail.com> | 2008-05-30 10:54:33 +1000 |
commit | 524408f1a5b39c8c25a277e41e4eee54fd726b84 (patch) | |
tree | 465e450323b7cb778f16c8f5e35f592a911e5422 /src/gallium/winsys | |
parent | d0c0c0d1e67f92df8866e6218b868b3de954a5e1 (diff) |
nouveau: rework buffer validation a bit
Diffstat (limited to 'src/gallium/winsys')
-rw-r--r-- | src/gallium/winsys/dri/nouveau/nouveau_drmif.h | 20 | ||||
-rw-r--r-- | src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c | 109 |
2 files changed, 69 insertions, 60 deletions
diff --git a/src/gallium/winsys/dri/nouveau/nouveau_drmif.h b/src/gallium/winsys/dri/nouveau/nouveau_drmif.h index a31c9a514b..5829f649cd 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_drmif.h +++ b/src/gallium/winsys/dri/nouveau/nouveau_drmif.h @@ -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; diff --git a/src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c b/src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c index 78919bdee8..815046ba85 100644 --- a/src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c +++ b/src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c @@ -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; - - ret = nouveau_bo_validate(chan, bo, pbbo->flags); - assert (ret == 0); - - if (bo->offset == nouveau_bo(bo)->offset && - bo->flags == nouveau_bo(bo)->flags) { + 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; + + /* Validated, mem matches presumed, no relocation necessary */ + if (pbbo->handled & 2) { + if (!(pbbo->handled & 1)) + assert(0); + continue; + } - while ((r = ptr_to_pbrel(pbbo->relocs))) { - 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; - nouveau_bo_del(&bo); - nvpb->buffers = pbbo->next; - free(pbbo); - continue; + 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; } - 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); - } + /* 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_del(&bo); - nvpb->buffers = pbbo->next; - free(pbbo); + 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; |