File U_nouveau-avoid-queueing-too-much-work-onto-a-single-fence.patch of Package Mesa.openSUSE_Leap_42.1_Update
From: Ilia Mirkin <imirkin@alum.mit.edu>
Date: Fri Nov 6 00:44:10 2015 -0500
Subject: [PATCH]nouveau: avoid queueing too much work onto a single fence
Patch-mainline: Upstream
Git-commit: 53cbb11707a502a31bb9f0380d730840245ee9b2
Git-repo: git://anongit.freedesktop.org/mesa/mesa
References: boo#977047
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@alum.mit.edu>
Signed-off-by: Max Staudt <mstaudt@suse.de>
---
src/gallium/drivers/nouveau/nouveau_fence.c | 66 ++++++++++++++++++-----------
src/gallium/drivers/nouveau/nouveau_fence.h | 1 +
2 files changed, 42 insertions(+), 25 deletions(-)
diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c b/src/gallium/drivers/nouveau/nouveau_fence.c
index 21cf2b9..18a4b6e 100644
--- a/src/gallium/drivers/nouveau/nouveau_fence.c
+++ b/src/gallium/drivers/nouveau/nouveau_fence.c
@@ -58,26 +58,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)
{
@@ -181,11 +161,10 @@ nouveau_fence_signalled(struct nouveau_fence *fence)
return fence->state == NOUVEAU_FENCE_STATE_SIGNALLED;
}
-bool
-nouveau_fence_wait(struct nouveau_fence *fence)
+static bool
+nouveau_fence_kick(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);
@@ -206,9 +185,21 @@ nouveau_fence_wait(struct nouveau_fence *fence)
if (fence == screen->fence.current)
nouveau_fence_next(screen);
- do {
- nouveau_fence_update(screen, false);
+ nouveau_fence_update(screen, false);
+ return true;
+}
+
+bool
+nouveau_fence_wait(struct nouveau_fence *fence)
+{
+ struct nouveau_screen *screen = fence->screen;
+ uint32_t spins = 0;
+
+ if (!nouveau_fence_kick(fence))
+ return false;
+
+ do {
if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED)
return true;
if (!spins)
@@ -218,6 +209,8 @@ nouveau_fence_wait(struct nouveau_fence *fence)
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",
@@ -249,3 +242,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 2efcab2..c5904e9 100644
--- a/src/gallium/drivers/nouveau/nouveau_fence.h
+++ b/src/gallium/drivers/nouveau/nouveau_fence.h
@@ -23,6 +23,7 @@ struct nouveau_fence {
int state;
int ref;
uint32_t sequence;
+ uint32_t work_count;
struct list_head work;
};