diff options
author | Ben Skeggs <skeggsb@gmail.com> | 2007-12-10 13:19:47 +1100 |
---|---|---|
committer | Ben Skeggs <skeggsb@gmail.com> | 2007-12-10 13:19:47 +1100 |
commit | 7d8368790fabc19e51add0fd9f1d1f85b7803cdf (patch) | |
tree | 2d12e4526511da06a65024800eec4903a732d0e1 /src/mesa/drivers | |
parent | 9ba3890c6f35701df5c7ea94cfac9954e9cbec2e (diff) |
nouveau: add callbacks for signalled fences
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h | 9 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c | 46 | ||||
-rw-r--r-- | src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c | 72 |
3 files changed, 72 insertions, 55 deletions
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h index 1c2a2c12cf..6d6633fac3 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h @@ -64,11 +64,18 @@ struct nouveau_fence { struct nouveau_channel *channel; }; +struct nouveau_fence_cb { + struct nouveau_fence_cb *next; + void (*func)(void *); + void *priv; +}; + struct nouveau_fence_priv { struct nouveau_fence base; int refcount; struct nouveau_fence *next; + struct nouveau_fence_cb *signal_cb; uint32_t sequence; int emitted; @@ -85,6 +92,8 @@ nouveau_fence_ref(struct nouveau_fence *, struct nouveau_fence **); extern void nouveau_fence_del(struct nouveau_fence **); +extern int +nouveau_fence_signal_cb(struct nouveau_fence *, void (*)(void *), void *); extern void nouveau_fence_emit(struct nouveau_fence *); diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c index 842b38f913..7861b6f84d 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c @@ -76,6 +76,27 @@ nouveau_fence_del(struct nouveau_fence **fence) } } +int +nouveau_fence_signal_cb(struct nouveau_fence *fence, void (*func)(void *), + void *priv) +{ + struct nouveau_fence_priv *nvfence = nouveau_fence(fence); + struct nouveau_fence_cb *cb; + + if (!nvfence || !func) + return -EINVAL; + + cb = malloc(sizeof(struct nouveau_fence_cb)); + if (!cb) + return -ENOMEM; + + cb->func = func; + cb->priv = priv; + cb->next = nvfence->signal_cb; + nvfence->signal_cb = cb; + return 0; +} + void nouveau_fence_emit(struct nouveau_fence *fence) { @@ -102,16 +123,33 @@ void nouveau_fence_flush(struct nouveau_channel *chan) { struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_fence_priv *nvfence = nouveau_fence(nvchan->fence_head); uint32_t sequence = *nvchan->ref_cnt; - while (nvchan->fence_head && nvfence->sequence <= sequence) { - nvfence->signalled = 1; + while (nvchan->fence_head) { + struct nouveau_fence *fence = NULL; + struct nouveau_fence_priv *nvfence; + + nouveau_fence_ref(nvchan->fence_head, &fence); + nvfence = nouveau_fence(nvchan->fence_head); + + if (nvfence->sequence > sequence) { + nouveau_fence_del(&fence); + break; + } nvchan->fence_head = nvfence->next; if (nvchan->fence_head == NULL) nvchan->fence_tail = NULL; - nvfence = nouveau_fence(nvchan->fence_head); + nvfence->signalled = 1; + + while (nvfence->signal_cb) { + struct nouveau_fence_cb *cb = nvfence->signal_cb; + nvfence->signal_cb = cb->next; + cb->func(cb->priv); + free(cb); + } + + nouveau_fence_del(&fence); } } diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c index 551889f94c..a922300ff5 100644 --- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c +++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c @@ -48,6 +48,16 @@ nouveau_pushbuf_init(struct nouveau_channel *chan) return 0; } +static void +nouveau_pushbuf_fence_signalled(void *priv) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(priv); + + nouveau_fence_del(&nvpb->fence); + nouveau_resource_free(&nvpb->res); + free(nvpb); +} + /* This would be our TTM "superioctl" */ int nouveau_pushbuf_flush(struct nouveau_channel *chan) @@ -64,6 +74,7 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan) if (nvpb->base.remaining == nvpb->res->size / 4) return 0; + nvchan->pb_tail = NULL; ret = nouveau_fence_new(chan, &fence); if (ret) @@ -124,76 +135,35 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan) /* Fence */ nvpb->fence = fence; + nouveau_fence_signal_cb(nvpb->fence, nouveau_pushbuf_fence_signalled, + nvpb); nouveau_fence_emit(nvpb->fence); /* Kickoff */ FIRE_RING_CH(chan); + if (sync_hack) { + struct nouveau_fence *f = NULL; + nouveau_fence_ref(nvpb->fence, &f); + nouveau_fence_wait(&f); + } + /* Allocate space for next push buffer */ out_realloc: nvpb = calloc(1, sizeof(struct nouveau_pushbuf_priv)); if (!nvpb) return -ENOMEM; - if (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, NULL, &nvpb->res)) { - struct nouveau_pushbuf_priv *e; - int nr = 0; - - /* Update fences */ + while (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, NULL, + &nvpb->res)) { nouveau_fence_flush(chan); - - /* Free any push buffers that have already been executed */ - e = nouveau_pushbuf(nvchan->pb_head); - while (e && e->fence) { - if (!e->fence || !nouveau_fence(e->fence)->signalled) - break; - nouveau_fence_del(&e->fence); - nouveau_resource_free(&e->res); - nr++; - - nvchan->pb_head = e->next; - if (nvchan->pb_head == NULL) - nvchan->pb_tail = NULL; - free(e); - e = nouveau_pushbuf(nvchan->pb_head); - } - - /* We didn't free any buffers above. As a last resort, busy - * wait on the oldest buffer becoming available. - */ - if (!nr) { - e = nouveau_pushbuf(nvchan->pb_head); - nouveau_fence_wait(&e->fence); - nouveau_resource_free(&e->res); - - nvchan->pb_head = e->next; - if (nvchan->pb_head == NULL) - nvchan->pb_tail = NULL; - free(e); - } - - if (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, nvpb, - &nvpb->res)) - assert(0); } nvpb->base.channel = chan; nvpb->base.remaining = nvpb->res->size / 4; nvpb->base.cur = &nvchan->pushbuf[nvpb->res->start/4]; - - if (nvchan->pb_tail) { - nouveau_pushbuf(nvchan->pb_tail)->next = &nvpb->base; - } else { - nvchan->pb_head = &nvpb->base; - } nvchan->pb_tail = &nvpb->base; - if (sync_hack) { - struct nouveau_fence *f = NULL; - nouveau_fence_ref(nvpb->fence, &f); - nouveau_fence_wait(&f); - } - return 0; } |