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 | |
| parent | 9ba3890c6f35701df5c7ea94cfac9954e9cbec2e (diff) | |
nouveau: add callbacks for signalled fences
| -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;  } | 
