X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fnouveau%2Fnouveau_fence.c;h=d14c59b2dd15d271a3e2bbd45863f0c14bb84569;hb=50e913b9c5d311334281da89b4e9969d48fd62b6;hp=18b15920185913b9a4849dbd01a46b7d1e32836d;hpb=8053c9208f30964d89dc4e262fdf2148f0664696;p=mesa.git diff --git a/src/gallium/drivers/nouveau/nouveau_fence.c b/src/gallium/drivers/nouveau/nouveau_fence.c index 18b15920185..d14c59b2dd1 100644 --- a/src/gallium/drivers/nouveau/nouveau_fence.c +++ b/src/gallium/drivers/nouveau/nouveau_fence.c @@ -23,14 +23,14 @@ #include "nouveau_screen.h" #include "nouveau_winsys.h" #include "nouveau_fence.h" +#include "util/os_time.h" #ifdef PIPE_OS_UNIX #include #endif bool -nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence, - bool emit) +nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence) { *fence = CALLOC_STRUCT(nouveau_fence); if (!*fence) @@ -40,9 +40,6 @@ nouveau_fence_new(struct nouveau_screen *screen, struct nouveau_fence **fence, (*fence)->ref = 1; LIST_INITHEAD(&(*fence)->work); - if (emit) - nouveau_fence_emit(*fence); - return true; } @@ -58,26 +55,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,18 +158,21 @@ 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); if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) { PUSH_SPACE(screen->pushbuf, 8); - nouveau_fence_emit(fence); + /* The space allocation might trigger a flush, which could emit the + * current fence. So check again. + */ + if (fence->state < NOUVEAU_FENCE_STATE_EMITTED) + nouveau_fence_emit(fence); } if (fence->state < NOUVEAU_FENCE_STATE_FLUSHED) @@ -202,11 +182,32 @@ 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 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(); - if (fence->state == NOUVEAU_FENCE_STATE_SIGNALLED) + 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, + "stalled %.3f ms waiting for fence", + (os_time_get_nano() - start) / 1000000.f); return true; + } if (!spins) NOUVEAU_DRV_STAT(screen, any_non_kernel_fence_sync_count, 1); spins++; @@ -214,6 +215,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", @@ -235,7 +238,7 @@ nouveau_fence_next(struct nouveau_screen *screen) nouveau_fence_ref(NULL, &screen->fence.current); - nouveau_fence_new(screen, &screen->fence.current, false); + nouveau_fence_new(screen, &screen->fence.current); } void @@ -245,3 +248,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; +}