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;
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;
nouveau_fence_trigger_work(fence);
}
+ nouveau_bo_ref(NULL, &fence->bo);
FREE(fence);
}
{
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);
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
struct nouveau_fence *next;
struct nouveau_screen *screen;
struct nouveau_context *context;
+ struct nouveau_bo *bo;
int state;
int ref;
uint32_t sequence;
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 *);
};
}
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;
(2 /* size */ << 18) | (7 /* subchan */ << 13));
PUSH_DATA (push, 0);
PUSH_DATA (push, *sequence);
+
+ nouveau_pushbuf_refn(push, &ref, 1);
}
static uint32_t
}
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;
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
}
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;
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