nouveau: eliminate busy waiting on fences

Signed-off-by: Karol Herbst <kherbst@redhat.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Emma Anholt <emma@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19543>
This commit is contained in:
Karol Herbst 2022-11-05 11:49:11 +01:00 committed by Marge Bot
parent 8f2680871d
commit b3aae9c556
5 changed files with 41 additions and 25 deletions

View file

@ -40,6 +40,12 @@ nouveau_fence_new(struct nouveau_context *nv, struct nouveau_fence **fence)
if (!*fence)
return false;
int ret = nouveau_bo_new(nv->screen->device, NOUVEAU_BO_GART, 0x1000, 0x1000, NULL, &(*fence)->bo);
if (ret) {
FREE(*fence);
return false;
}
(*fence)->screen = nv->screen;
(*fence)->context = nv;
(*fence)->ref = 1;
@ -86,7 +92,7 @@ _nouveau_fence_emit(struct nouveau_fence *fence)
fence_list->tail = fence;
fence_list->emit(&fence->context->pipe, &fence->sequence);
fence_list->emit(&fence->context->pipe, &fence->sequence, fence->bo);
assert(fence->state == NOUVEAU_FENCE_STATE_EMITTING);
fence->state = NOUVEAU_FENCE_STATE_EMITTED;
@ -119,6 +125,7 @@ nouveau_fence_del(struct nouveau_fence *fence)
nouveau_fence_trigger_work(fence);
}
nouveau_bo_ref(NULL, &fence->bo);
FREE(fence);
}
@ -239,7 +246,6 @@ _nouveau_fence_wait(struct nouveau_fence *fence, struct util_debug_callback *deb
{
struct nouveau_screen *screen = fence->screen;
struct nouveau_fence_list *fence_list = &screen->fence;
uint32_t spins = 0;
int64_t start = 0;
simple_mtx_assert_locked(&fence_list->lock);
@ -250,30 +256,27 @@ _nouveau_fence_wait(struct nouveau_fence *fence, struct util_debug_callback *deb
if (!nouveau_fence_kick(fence))
return false;
do {
if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) {
if (debug && debug->debug_message)
util_debug_message(debug, PERF_INFO,
"stalled %.3f ms waiting for fence",
(os_time_get_nano() - start) / 1000000.f);
return true;
if (fence->state < NOUVEAU_FENCE_STATE_SIGNALLED) {
NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1);
int ret = nouveau_bo_wait(fence->bo, NOUVEAU_BO_RDWR, screen->client);
if (ret) {
debug_printf("Wait on fence %u (ack = %u, next = %u) errored with %s !\n",
fence->sequence,
fence_list->sequence_ack, fence_list->sequence, strerror(ret));
return false;
}
if (!spins)
NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1);
spins++;
#if DETECT_OS_UNIX
if (!(spins % 8)) /* donate a few cycles */
sched_yield();
#endif
_nouveau_fence_update(screen, false);
} while (spins < NOUVEAU_FENCE_MAX_SPINS);
if (fence->state != NOUVEAU_FENCE_STATE_SIGNALLED)
return false;
debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
fence->sequence,
fence_list->sequence_ack, fence_list->sequence);
if (debug && debug->debug_message)
util_debug_message(debug, PERF_INFO,
"stalled %.3f ms waiting for fence",
(os_time_get_nano() - start) / 1000000.f);
}
return false;
return true;
}
void

View file

@ -24,6 +24,7 @@ struct nouveau_fence {
struct nouveau_fence *next;
struct nouveau_screen *screen;
struct nouveau_context *context;
struct nouveau_bo *bo;
int state;
int ref;
uint32_t sequence;
@ -37,7 +38,7 @@ struct nouveau_fence_list {
uint32_t sequence;
uint32_t sequence_ack;
simple_mtx_t lock;
void (*emit)(struct pipe_context *, uint32_t *sequence);
void (*emit)(struct pipe_context *, uint32_t *sequence, struct nouveau_bo *wait);
uint32_t (*update)(struct pipe_screen *);
};

View file

@ -510,11 +510,13 @@ nv30_screen_get_compiler_options(struct pipe_screen *pscreen,
}
static void
nv30_screen_fence_emit(struct pipe_context *pcontext, uint32_t *sequence)
nv30_screen_fence_emit(struct pipe_context *pcontext, uint32_t *sequence,
struct nouveau_bo *wait)
{
struct nv30_context *nv30 = nv30_context(pcontext);
struct nv30_screen *screen = nv30->screen;
struct nouveau_pushbuf *push = nv30->base.pushbuf;
struct nouveau_pushbuf_refn ref = { wait, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR };
*sequence = ++screen->base.fence.sequence;
@ -523,6 +525,8 @@ nv30_screen_fence_emit(struct pipe_context *pcontext, uint32_t *sequence)
(2 /* size */ << 18) | (7 /* subchan */ << 13));
PUSH_DATA (push, 0);
PUSH_DATA (push, *sequence);
nouveau_pushbuf_refn(push, &ref, 1);
}
static uint32_t

View file

@ -512,11 +512,13 @@ nv50_screen_destroy(struct pipe_screen *pscreen)
}
static void
nv50_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence)
nv50_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence,
struct nouveau_bo *wait)
{
struct nv50_context *nv50 = nv50_context(pcontext);
struct nv50_screen *screen = nv50->screen;
struct nouveau_pushbuf *push = nv50->base.pushbuf;
struct nouveau_pushbuf_refn ref = { wait, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR };
/* we need to do it after possible flush in MARK_RING */
*sequence = ++screen->base.fence.sequence;
@ -532,6 +534,8 @@ nv50_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence)
NV50_3D_QUERY_GET_TYPE_QUERY |
NV50_3D_QUERY_GET_QUERY_SELECT_ZERO |
NV50_3D_QUERY_GET_SHORT);
nouveau_pushbuf_refn(push, &ref, 1);
}
static u32

View file

@ -756,11 +756,13 @@ nvc0_magic_3d_init(struct nouveau_pushbuf *push, uint16_t obj_class)
}
static void
nvc0_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence)
nvc0_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence,
struct nouveau_bo *wait)
{
struct nvc0_context *nvc0 = nvc0_context(pcontext);
struct nvc0_screen *screen = nvc0->screen;
struct nouveau_pushbuf *push = nvc0->base.pushbuf;
struct nouveau_pushbuf_refn ref = { wait, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR };
/* we need to do it after possible flush in MARK_RING */
*sequence = ++screen->base.fence.sequence;
@ -772,6 +774,8 @@ nvc0_screen_fence_emit(struct pipe_context *pcontext, u32 *sequence)
PUSH_DATA (push, *sequence);
PUSH_DATA (push, NVC0_3D_QUERY_GET_FENCE | NVC0_3D_QUERY_GET_SHORT |
(0xf << NVC0_3D_QUERY_GET_UNIT__SHIFT));
nouveau_pushbuf_refn(push, &ref, 1);
}
static u32