summaryrefslogtreecommitdiff
path: root/src/gallium/winsys
diff options
context:
space:
mode:
authorBen Skeggs <skeggsb@gmail.com>2008-05-30 00:38:07 +1000
committerBen Skeggs <skeggsb@gmail.com>2008-05-30 10:54:33 +1000
commit524408f1a5b39c8c25a277e41e4eee54fd726b84 (patch)
tree465e450323b7cb778f16c8f5e35f592a911e5422 /src/gallium/winsys
parentd0c0c0d1e67f92df8866e6218b868b3de954a5e1 (diff)
nouveau: rework buffer validation a bit
Diffstat (limited to 'src/gallium/winsys')
-rw-r--r--src/gallium/winsys/dri/nouveau/nouveau_drmif.h20
-rw-r--r--src/gallium/winsys/dri/nouveau/nouveau_pushbuf.c109
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;