[Mesa-dev] [PATCH] nouveau: emit and flush fence in fence_signalled if needed

Bryan Cain bryancain3 at gmail.com
Tue May 7 10:25:15 PDT 2013


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



More information about the mesa-dev mailing list