浏览代码

nouveau: add callbacks for signalled fences

tags/mesa_20090313
Ben Skeggs 17 年前
父节点
当前提交
7d8368790f

+ 9
- 0
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 *);


+ 42
- 4
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);
}
}


+ 21
- 51
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;
}


正在加载...
取消
保存