mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-02-03 06:30:24 +01:00
nouveau: add callbacks for signalled fences
This commit is contained in:
parent
9ba3890c6f
commit
7d8368790f
3 changed files with 72 additions and 55 deletions
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue