nouveau: add callbacks for signalled fences

This commit is contained in:
Ben Skeggs 2007-12-10 13:19:47 +11:00
parent 9ba3890c6f
commit 7d8368790f
3 changed files with 72 additions and 55 deletions

View file

@ -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 *);

View file

@ -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);
}
}

View file

@ -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;
}