[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