summaryrefslogtreecommitdiff
path: root/src/mesa/drivers
diff options
context:
space:
mode:
authorBen Skeggs <skeggsb@gmail.com>2007-12-10 13:19:47 +1100
committerBen Skeggs <skeggsb@gmail.com>2007-12-10 13:19:47 +1100
commit7d8368790fabc19e51add0fd9f1d1f85b7803cdf (patch)
tree2d12e4526511da06a65024800eec4903a732d0e1 /src/mesa/drivers
parent9ba3890c6f35701df5c7ea94cfac9954e9cbec2e (diff)
nouveau: add callbacks for signalled fences
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h9
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c46
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c72
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;
}