nvc0: improve userspace fencing

Before, there were situations in which we never checked the fences
for completion (some loading screens for example) and thus never
released memory.
This commit is contained in:
Christoph Bumiller 2011-02-20 17:57:47 +01:00
parent 410a13c5ce
commit a6ea37da4b
6 changed files with 46 additions and 26 deletions

View file

@ -47,15 +47,12 @@ nvc0_flush(struct pipe_context *pipe, unsigned flags,
OUT_RING (chan, 0);
}
if (fence) {
nvc0_screen_fence_new(nvc0->screen, (struct nvc0_fence **)fence, TRUE);
}
if (fence)
nvc0_fence_reference((struct nvc0_fence **)fence,
nvc0->screen->fence.current);
if (flags & (PIPE_FLUSH_SWAPBUFFERS | PIPE_FLUSH_FRAME)) {
if (flags & (PIPE_FLUSH_SWAPBUFFERS | PIPE_FLUSH_FRAME))
FIRE_RING(chan);
nvc0_screen_fence_next(nvc0->screen);
}
}
static void
@ -71,6 +68,16 @@ nvc0_destroy(struct pipe_context *pipe)
FREE(nvc0);
}
void
nvc0_default_flush_notify(struct nouveau_channel *chan)
{
struct nvc0_context *nvc0 = chan->user_private;
nvc0_screen_fence_update(nvc0->screen, TRUE);
nvc0_screen_fence_next(nvc0->screen);
}
struct pipe_context *
nvc0_create(struct pipe_screen *pscreen, void *priv)
{
@ -95,6 +102,7 @@ nvc0_create(struct pipe_screen *pscreen, void *priv)
nvc0->pipe.flush = nvc0_flush;
screen->base.channel->user_private = nvc0;
screen->base.channel->flush_notify = nvc0_default_flush_notify;
nvc0_init_query_functions(nvc0);
nvc0_init_surface_functions(nvc0);

View file

@ -156,6 +156,8 @@ nvc0_surface(struct pipe_surface *ps)
/* nvc0_context.c */
struct pipe_context *nvc0_create(struct pipe_screen *, void *);
void nvc0_default_flush_notify(struct nouveau_channel *);
void nvc0_bufctx_emit_relocs(struct nvc0_context *);
void nvc0_bufctx_add_resident(struct nvc0_context *, int ctx,
struct nvc0_resource *, uint32_t flags);

View file

@ -84,7 +84,8 @@ nvc0_fence_del(struct nvc0_fence *fence)
struct nvc0_fence *it;
struct nvc0_screen *screen = fence->screen;
if (fence->state == NVC0_FENCE_STATE_EMITTED) {
if (fence->state == NVC0_FENCE_STATE_EMITTED ||
fence->state == NVC0_FENCE_STATE_FLUSHED) {
if (fence == screen->fence.head) {
screen->fence.head = fence->next;
if (!screen->fence.head)
@ -119,8 +120,8 @@ nvc0_fence_trigger_release_buffers(struct nvc0_fence *fence)
fence->buffers = NULL;
}
static void
nvc0_screen_fence_update(struct nvc0_screen *screen)
void
nvc0_screen_fence_update(struct nvc0_screen *screen, boolean flushed)
{
struct nvc0_fence *fence;
struct nvc0_fence *next = NULL;
@ -147,38 +148,43 @@ nvc0_screen_fence_update(struct nvc0_screen *screen)
screen->fence.head = next;
if (!next)
screen->fence.tail = NULL;
}
#define NVC0_FENCE_MAX_SPINS (1 << 17)
if (flushed) {
for (fence = next; fence; fence = fence->next)
fence->state = NVC0_FENCE_STATE_FLUSHED;
}
}
boolean
nvc0_fence_signalled(struct nvc0_fence *fence)
{
struct nvc0_screen *screen = fence->screen;
if (fence->state == NVC0_FENCE_STATE_EMITTED)
nvc0_screen_fence_update(screen);
if (fence->state >= NVC0_FENCE_STATE_EMITTED)
nvc0_screen_fence_update(screen, FALSE);
return fence->state == NVC0_FENCE_STATE_SIGNALLED;
}
#define NVC0_FENCE_MAX_SPINS (1 << 31)
boolean
nvc0_fence_wait(struct nvc0_fence *fence)
{
struct nvc0_screen *screen = fence->screen;
int spins = 0;
uint32_t spins = 0;
if (fence->state == NVC0_FENCE_STATE_AVAILABLE) {
if (fence->state < NVC0_FENCE_STATE_EMITTED) {
nvc0_fence_emit(fence);
FIRE_RING(screen->base.channel);
if (fence == screen->fence.current)
nvc0_screen_fence_new(screen, &screen->fence.current, FALSE);
}
if (fence->state < NVC0_FENCE_STATE_FLUSHED)
FIRE_RING(screen->base.channel);
do {
nvc0_screen_fence_update(screen);
nvc0_screen_fence_update(screen, FALSE);
if (fence->state == NVC0_FENCE_STATE_SIGNALLED)
return TRUE;
@ -189,8 +195,9 @@ nvc0_fence_wait(struct nvc0_fence *fence)
#endif
} while (spins < NVC0_FENCE_MAX_SPINS);
if (spins > 9000)
NOUVEAU_ERR("fence %x: been spinning too long\n", fence->sequence);
debug_printf("Wait on fence %u (ack = %u, next = %u) timed out !\n",
fence->sequence,
screen->fence.sequence_ack, screen->fence.sequence);
return FALSE;
}
@ -200,5 +207,4 @@ nvc0_screen_fence_next(struct nvc0_screen *screen)
{
nvc0_fence_emit(screen->fence.current);
nvc0_screen_fence_new(screen, &screen->fence.current, FALSE);
nvc0_screen_fence_update(screen);
}

View file

@ -7,7 +7,8 @@
#define NVC0_FENCE_STATE_AVAILABLE 0
#define NVC0_FENCE_STATE_EMITTED 1
#define NVC0_FENCE_STATE_SIGNALLED 2
#define NVC0_FENCE_STATE_FLUSHED 2
#define NVC0_FENCE_STATE_SIGNALLED 3
struct nvc0_mm_allocation;

View file

@ -138,9 +138,10 @@ nvc0_resource_validate(struct nvc0_resource *res, uint32_t flags)
boolean
nvc0_screen_fence_new(struct nvc0_screen *, struct nvc0_fence **, boolean emit);
void
nvc0_screen_fence_next(struct nvc0_screen *);
void
nvc0_screen_fence_update(struct nvc0_screen *, boolean flushed);
static INLINE boolean
nvc0_screen_fence_emit(struct nvc0_screen *screen)

View file

@ -371,6 +371,8 @@ nvc0_draw_vbo_flush_notify(struct nouveau_channel *chan)
{
struct nvc0_context *nvc0 = chan->user_private;
nvc0_screen_fence_update(nvc0->screen, TRUE);
nvc0_bufctx_emit_relocs(nvc0);
}
@ -398,7 +400,7 @@ nvc0_draw_arrays(struct nvc0_context *nvc0,
prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
}
chan->flush_notify = NULL;
chan->flush_notify = nvc0_default_flush_notify;
}
static void
@ -568,7 +570,7 @@ nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten,
}
}
chan->flush_notify = NULL;
chan->flush_notify = nvc0_default_flush_notify;
}
void