diff options
author | Marcin Slusarz <[email protected]> | 2011-10-08 23:05:25 +0200 |
---|---|---|
committer | Marcin Slusarz <[email protected]> | 2011-10-09 14:49:30 +0200 |
commit | 9849f366cbfd781ebeca725058029b70c96836f9 (patch) | |
tree | c7a300247b7b31e49d926b502e8e9b7cb0dd88c0 /src/gallium/drivers/nouveau/nouveau_fence.c | |
parent | 0110aa09e5898987ee86586e438ac571075eba3a (diff) |
nouveau: fix fence hang
If there is not enough space in pushbuffer for fence emission
(nouveau_fence_emit -> nv50_screen_fence_emit -> MARK_RING),
the pushbuffer is flushed, which through flush_notify ->
nv50_default_flush_notify -> nouveau_fence_update marks currently
emitting fence as flushed. But actual emission is done after this mark.
So later when there is a need to wait on this fence and pushbuffer
was not flushed in between, fence wait will never finish causing
application to hang.
To fix this, introduce new fence state between AVAILABLE and EMITTED,
set it before emission and handle it everywhere.
Additionally obtain fence sequence numbers after possible flush in
MARK_RING, because we want to emit fences in correct order.
Reviewed-by: Christoph Bumiller <[email protected]>
Note: This is a candidate for the 7.11 branch.
Diffstat (limited to 'src/gallium/drivers/nouveau/nouveau_fence.c')
-rw-r--r-- | src/gallium/drivers/nouveau/nouveau_fence.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c b/src/gallium/drivers/nouveau/nouveau_fence.c index 26e4775b12d..a2fcafef4a7 100644 --- a/src/gallium/drivers/nouveau/nouveau_fence.c +++ b/src/gallium/drivers/nouveau/nouveau_fence.c @@ -86,12 +86,10 @@ nouveau_fence_emit(struct nouveau_fence *fence) { struct nouveau_screen *screen = fence->screen; - fence->sequence = ++screen->fence.sequence; - assert(fence->state == NOUVEAU_FENCE_STATE_AVAILABLE); /* set this now, so that if fence.emit triggers a flush we don't recurse */ - fence->state = NOUVEAU_FENCE_STATE_EMITTED; + fence->state = NOUVEAU_FENCE_STATE_EMITTING; ++fence->ref; @@ -102,7 +100,10 @@ nouveau_fence_emit(struct nouveau_fence *fence) screen->fence.tail = fence; - screen->fence.emit(&screen->base, fence->sequence); + screen->fence.emit(&screen->base, &fence->sequence); + + assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING); + fence->state = NOUVEAU_FENCE_STATE_EMITTED; } void @@ -162,7 +163,8 @@ nouveau_fence_update(struct nouveau_screen *screen, boolean flushed) if (flushed) { for (fence = next; fence; fence = fence->next) - fence->state = NOUVEAU_FENCE_STATE_FLUSHED; + if (fence->state == NOUVEAU_FENCE_STATE_EMITTED) + fence->state = NOUVEAU_FENCE_STATE_FLUSHED; } } @@ -185,6 +187,9 @@ nouveau_fence_wait(struct nouveau_fence *fence) struct nouveau_screen *screen = fence->screen; uint32_t spins = 0; + /* wtf, someone is waiting on a fence in flush_notify handler? */ + assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING); + if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) { nouveau_fence_emit(fence); @@ -216,7 +221,7 @@ nouveau_fence_wait(struct nouveau_fence *fence) void nouveau_fence_next(struct nouveau_screen *screen) { - if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTED) + if (screen->fence.current->state < NOUVEAU_FENCE_STATE_EMITTING) nouveau_fence_emit(screen->fence.current); nouveau_fence_ref(NULL, &screen->fence.current); |