The Mesa state tracker expects us to emit the fence even if it doesn't call fence_finish. Notably, this occurs when glClientWaitSync is called with timeout 0.
Fixes Portal and Left 4 Dead 2, which were both stalling on startup by repeatedly calling glClientWaitSync with timeout 0 while waiting for commands to complete. --- src/gallium/drivers/nouveau/nouveau_fence.c | 36 ++++++++++++++++++--------- src/gallium/drivers/nouveau/nouveau_fence.h | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c b/src/gallium/drivers/nouveau/nouveau_fence.c index dea146c..722be01 100644 --- a/src/gallium/drivers/nouveau/nouveau_fence.c +++ b/src/gallium/drivers/nouveau/nouveau_fence.c @@ -167,6 +167,25 @@ nouveau_fence_update(struct nouveau_screen *screen, boolean flushed) } } +boolean +nouveau_fence_ensure_flushed(struct nouveau_fence *fence) +{ + struct nouveau_screen *screen = fence->screen; + + if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) { + nouveau_fence_emit(fence); + + if (fence == screen->fence.current) + nouveau_fence_new(screen, &screen->fence.current, FALSE); + } + if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED) { + if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel)) + return FALSE; + } + + return TRUE; +} + #define NOUVEAU_FENCE_MAX_SPINS (1 << 31) boolean @@ -174,8 +193,9 @@ nouveau_fence_signalled(struct nouveau_fence *fence) { struct nouveau_screen *screen = fence->screen; - if (fence->state >= NOUVEAU_FENCE_STATE_EMITTED) - nouveau_fence_update(screen, FALSE); + if (!nouveau_fence_ensure_flushed(fence)) + return FALSE; + nouveau_fence_update(screen, FALSE); return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED; } @@ -189,16 +209,8 @@ nouveau_fence_wait(struct nouveau_fence *fence) /* 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); - - if (fence == screen->fence.current) - nouveau_fence_new(screen, &screen->fence.current, FALSE); - } - if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED) { - if (nouveau_pushbuf_kick(screen->pushbuf, screen->pushbuf->channel)) - return FALSE; - } + if (!nouveau_fence_ensure_flushed(fence)) + return FALSE; do { nouveau_fence_update(screen, FALSE); diff --git a/src/gallium/drivers/nouveau/nouveau_fence.h b/src/gallium/drivers/nouveau/nouveau_fence.h index 3984a9a..d497c7f 100644 --- a/src/gallium/drivers/nouveau/nouveau_fence.h +++ b/src/gallium/drivers/nouveau/nouveau_fence.h @@ -34,6 +34,7 @@ boolean nouveau_fence_new(struct nouveau_screen *, struct nouveau_fence **, boolean nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *); void nouveau_fence_update(struct nouveau_screen *, boolean flushed); void nouveau_fence_next(struct nouveau_screen *); +boolean nouveau_fence_ensure_flushed(struct nouveau_fence *); boolean nouveau_fence_wait(struct nouveau_fence *); boolean nouveau_fence_signalled(struct nouveau_fence *); -- 1.7.9.5 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev