Mesa (master): nouveau: avoid queueing too much work onto a single fence

Ilia Mirkin imirkin at kemper.freedesktop.org
Sun Nov 8 00:03:21 UTC 2015


Module: Mesa
Branch: master
Commit: 53cbb11707a502a31bb9f0380d730840245ee9b2
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=53cbb11707a502a31bb9f0380d730840245ee9b2

Author: Ilia Mirkin <imirkin at alum.mit.edu>
Date:   Fri Nov  6 00:44:10 2015 -0500

nouveau: avoid queueing too much work onto a single fence

Force the fence to get kicked off, which won't actually wait for its
completion, but any additional work will be put onto a fresh list.

This fixes crashes in teximage-colors --benchmark with too many active
maps.

Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>

---

 src/gallium/drivers/nouveau/nouveau_fence.c |   68 +++++++++++++++++----------
 src/gallium/drivers/nouveau/nouveau_fence.h |    1 +
 2 files changed, 43 insertions(+), 26 deletions(-)

diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c b/src/gallium/drivers/nouveau/nouveau_fence.c
index d3a3406..691553a 100644
--- a/src/gallium/drivers/nouveau/nouveau_fence.c
+++ b/src/gallium/drivers/nouveau/nouveau_fence.c
@@ -59,26 +59,6 @@ nouveau_fence_trigger_work(struct nouveau_fence *fence)
    }
 }
 
-bool
-nouveau_fence_work(struct nouveau_fence *fence,
-                   void (*func)(void *), void *data)
-{
-   struct nouveau_fence_work *work;
-
-   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
-      func(data);
-      return true;
-   }
-
-   work = CALLOC_STRUCT(nouveau_fence_work);
-   if (!work)
-      return false;
-   work->func = func;
-   work->data = data;
-   LIST_ADD(&work->list, &fence->work);
-   return true;
-}
-
 void
 nouveau_fence_emit(struct nouveau_fence *fence)
 {
@@ -182,12 +162,10 @@ nouveau_fence_signalled(struct nouveau_fence *fence)
    return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
 }
 
-bool
-nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debug)
+static bool
+nouveau_fence_kick(struct nouveau_fence *fence)
 {
    struct nouveau_screen *screen = fence->screen;
-   uint32_t spins = 0;
-   int64_t start = 0;
 
    /* wtf, someone is waiting on a fence in flush_notify handler? */
    assert(fence->state != NOUVEAU_FENCE_STATE_EMITTING);
@@ -208,12 +186,25 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debu
    if (fence == screen->fence.current)
       nouveau_fence_next(screen);
 
+   nouveau_fence_update(screen, false);
+
+   return true;
+}
+
+bool
+nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debug)
+{
+   struct nouveau_screen *screen = fence->screen;
+   uint32_t spins = 0;
+   int64_t start = 0;
+
    if (debug && debug->debug_message)
       start = os_time_get_nano();
 
-   do {
-      nouveau_fence_update(screen, false);
+   if (!nouveau_fence_kick(fence))
+      return false;
 
+   do {
       if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
          if (debug && debug->debug_message)
             pipe_debug_message(debug, PERF_INFO,
@@ -228,6 +219,8 @@ nouveau_fence_wait(struct nouveau_fence *fence, struct pipe_debug_callback *debu
       if (!(spins % 8)) /* donate a few cycles */
          sched_yield();
 #endif
+
+      nouveau_fence_update(screen, false);
    } while (spins < NOUVEAU_FENCE_MAX_SPINS);
 
    debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
@@ -259,3 +252,26 @@ nouveau_fence_unref_bo(void *data)
 
    nouveau_bo_ref(NULL, &bo);
 }
+
+bool
+nouveau_fence_work(struct nouveau_fence *fence,
+                   void (*func)(void *), void *data)
+{
+   struct nouveau_fence_work *work;
+
+   if (!fence || fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
+      func(data);
+      return true;
+   }
+
+   work = CALLOC_STRUCT(nouveau_fence_work);
+   if (!work)
+      return false;
+   work->func = func;
+   work->data = data;
+   LIST_ADD(&work->list, &fence->work);
+   p_atomic_inc(&fence->work_count);
+   if (fence->work_count > 64)
+      nouveau_fence_kick(fence);
+   return true;
+}
diff --git a/src/gallium/drivers/nouveau/nouveau_fence.h b/src/gallium/drivers/nouveau/nouveau_fence.h
index 0fa9d02..f10016d 100644
--- a/src/gallium/drivers/nouveau/nouveau_fence.h
+++ b/src/gallium/drivers/nouveau/nouveau_fence.h
@@ -25,6 +25,7 @@ struct nouveau_fence {
    int state;
    int ref;
    uint32_t sequence;
+   uint32_t work_count;
    struct list_head work;
 };
 




More information about the mesa-commit mailing list