Maarten Maathuis
2009-Dec-05 14:36 UTC
[Nouveau] [PATCH] nouveau: avoid running out of relocs (attempt 3)
- NV30 and NV40 need testing. - I'll take better naming suggestions for so_get_push_reloc(). --- src/gallium/drivers/nouveau/nouveau_stateobj.h | 49 +++++++++++++++++++----- src/gallium/drivers/nv04/nv04_surface_2d.c | 9 +++- src/gallium/drivers/nv30/nv30_state_emit.c | 26 ++++++++++++ src/gallium/drivers/nv40/nv40_state_emit.c | 30 ++++++++++++++ src/gallium/drivers/nv50/nv50_query.c | 2 +- src/gallium/drivers/nv50/nv50_state_validate.c | 39 +++++++++++++++++++ src/gallium/drivers/nv50/nv50_surface.c | 2 + src/gallium/drivers/nv50/nv50_transfer.c | 4 +- 8 files changed, 145 insertions(+), 16 deletions(-) diff --git a/src/gallium/drivers/nouveau/nouveau_stateobj.h b/src/gallium/drivers/nouveau/nouveau_stateobj.h index b595405..576fc95 100644 --- a/src/gallium/drivers/nouveau/nouveau_stateobj.h +++ b/src/gallium/drivers/nouveau/nouveau_stateobj.h @@ -107,28 +107,48 @@ so_dump(struct nouveau_stateobj *so) } static INLINE void +so_get_push_reloc(struct nouveau_stateobj *so, int *push, int *reloc) +{ + *push += so->cur - so->push; + *reloc += so->cur_reloc; +} + +static INLINE void so_emit(struct nouveau_channel *chan, struct nouveau_stateobj *so) { struct nouveau_pushbuf *pb = chan->pushbuf; unsigned nr, i; nr = so->cur - so->push; - if (pb->remaining < nr) - nouveau_pushbuf_flush(chan, nr); + if (pb->remaining < nr) { + debug_printf("so_emit ran out of space\n"); + return; + } pb->remaining -= nr; memcpy(pb->cur, so->push, nr * 4); for (i = 0; i < so->cur_reloc; i++) { struct nouveau_stateobj_reloc *r = &so->reloc[i]; + int ret = 0; - nouveau_pushbuf_emit_reloc(chan, pb->cur + r->offset, + if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur + r->offset, r->bo, r->data, 0, r->flags, - r->vor, r->tor); + r->vor, r->tor))) { + debug_printf("so_emit failed reloc with error %d\n", ret); + return; + } } pb->cur += nr; } static INLINE void +so_get_push_reloc_markers(struct nouveau_stateobj *so, int *push, int *reloc) +{ + *push += (so->cur_reloc << 1); + *reloc += (so->cur_reloc << 1); +} + +static INLINE void so_emit_reloc_markers(struct nouveau_channel *chan, struct nouveau_stateobj *so) { struct nouveau_pushbuf *pb = chan->pushbuf; @@ -138,21 +158,30 @@ so_emit_reloc_markers(struct nouveau_channel *chan, struct nouveau_stateobj *so) return; i = so->cur_reloc << 1; - if (pb->remaining < i) - nouveau_pushbuf_flush(chan, i); + if (pb->remaining < i) { + debug_printf("so_emit_reloc_markers ran out of space\n"); + return; + } pb->remaining -= i; for (i = 0; i < so->cur_reloc; i++) { struct nouveau_stateobj_reloc *r = &so->reloc[i]; + int ret = 0; - nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo, r->packet, 0, + if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo, r->packet, 0, (r->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RDWR)) | - NOUVEAU_BO_DUMMY, 0, 0); - nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo, r->data, 0, + NOUVEAU_BO_DUMMY, 0, 0))) { + debug_printf("so_emit_reloc_markers failed reloc \ + with error %d\n", ret); + } + if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo, r->data, 0, r->flags | NOUVEAU_BO_DUMMY, - r->vor, r->tor); + r->vor, r->tor))) { + debug_printf("so_emit_reloc_markers failed reloc \ + with error %d\n", ret); + } } } diff --git a/src/gallium/drivers/nv04/nv04_surface_2d.c b/src/gallium/drivers/nv04/nv04_surface_2d.c index 932893e..3020806 100644 --- a/src/gallium/drivers/nv04/nv04_surface_2d.c +++ b/src/gallium/drivers/nv04/nv04_surface_2d.c @@ -133,6 +133,9 @@ nv04_surface_copy_swizzle(struct nv04_surface_2d *ctx, assert(sub_w == w || util_is_pot(sub_w)); assert(sub_h == h || util_is_pot(sub_h)); + MARK_RING (chan, 8 + ((w+sub_w)/sub_w)*((h+sub_h)/sub_h)*17, 2 + + ((w+sub_w)/sub_w)*((h+sub_h)/sub_h)*2); + BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1); OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); @@ -202,7 +205,7 @@ nv04_surface_copy_m2mf(struct nv04_surface_2d *ctx, unsigned src_offset = src->offset + sy * src_pitch + sx * pf_get_blocksize(src->texture->format); - WAIT_RING (chan, 3 + ((h / 2047) + 1) * 9); + MARK_RING (chan, 3 + ((h / 2047) + 1) * 9, 2 + ((h / 2047) + 1) * 2); BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2); OUT_RELOCo(chan, src_bo, NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); @@ -250,7 +253,7 @@ nv04_surface_copy_blit(struct nv04_surface_2d *ctx, struct pipe_surface *dst, if (format < 0) return 1; - WAIT_RING (chan, 12); + MARK_RING (chan, 12, 4); BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); OUT_RELOCo(chan, src_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); @@ -315,7 +318,7 @@ nv04_surface_fill(struct nv04_surface_2d *ctx, struct pipe_surface *dst, gdirect_format = nv04_rect_format(dst->format); assert(gdirect_format >= 0); - WAIT_RING (chan, 16); + MARK_RING (chan, 16, 4); BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2); OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCo(chan, dst_bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); diff --git a/src/gallium/drivers/nv30/nv30_state_emit.c b/src/gallium/drivers/nv30/nv30_state_emit.c index 621b884..1cee89d 100644 --- a/src/gallium/drivers/nv30/nv30_state_emit.c +++ b/src/gallium/drivers/nv30/nv30_state_emit.c @@ -43,6 +43,7 @@ nv30_state_emit(struct nv30_context *nv30) struct nv30_screen *screen = nv30->screen; unsigned i, samplers; uint64_t states; + int push = 0, reloc = 0; if (nv30->pctx_id != screen->cur_pctx) { for (i = 0; i < NV30_STATE_MAX; i++) { @@ -53,6 +54,31 @@ nv30_state_emit(struct nv30_context *nv30) screen->cur_pctx = nv30->pctx_id; } + /* Find out if we have enough space in pushbuffer. */ + for (i = 0, states = state->dirty; states; i++) { + if (!(states & (1ULL << i))) + continue; + if (state->hw[i]) + so_get_push_reloc(nv30->screen->state[i], &push, &reloc); + } + + so_get_push_reloc_markers(state->hw[NV30_STATE_FB], &push, &reloc); + for (i = 0, samplers = state->fp_samplers; i < 16 && samplers; i++) { + if (!(samplers & (1 << i))) + continue; + so_get_push_reloc_markers(state->hw[NV30_STATE_FRAGTEX0+i], + &push, &reloc); + } + + so_get_push_reloc_markers(state->hw[NV30_STATE_FRAGPROG], + &push, &reloc); + if (state->hw[NV30_STATE_VTXBUF] /*&& nv30->render_mode == HW*/) + so_get_push_reloc_markers(state->hw[NV30_STATE_VTXBUF], + &push, &reloc); + + /* Will flush if necessary. */ + MARK_RING (chan, push, reloc); + for (i = 0, states = state->dirty; states; i++) { if (!(states & (1ULL << i))) continue; diff --git a/src/gallium/drivers/nv40/nv40_state_emit.c b/src/gallium/drivers/nv40/nv40_state_emit.c index 1986929..45a0ea1 100644 --- a/src/gallium/drivers/nv40/nv40_state_emit.c +++ b/src/gallium/drivers/nv40/nv40_state_emit.c @@ -59,6 +59,7 @@ nv40_state_emit(struct nv40_context *nv40) struct nv40_screen *screen = nv40->screen; unsigned i, samplers; uint64_t states; + int push = 0, reloc = 0; if (nv40->pctx_id != screen->cur_pctx) { for (i = 0; i < NV40_STATE_MAX; i++) { @@ -69,6 +70,35 @@ nv40_state_emit(struct nv40_context *nv40) screen->cur_pctx = nv40->pctx_id; } + /* Find out if we have enough space in pushbuffer. */ + for (i = 0, states = state->dirty; states; i++) { + if (!(states & (1ULL << i))) + continue; + if (state->hw[i]) + so_get_push_reloc(nv40->screen->state[i], &push, &reloc); + } + + if (state->dirty & ((1ULL << NV40_STATE_FRAGPROG) | + (1ULL << NV40_STATE_FRAGTEX0))) + push += 4; + + so_get_push_reloc_markers(state->hw[NV40_STATE_FB], &push, &reloc); + for (i = 0, samplers = state->fp_samplers; i < 16 && samplers; i++) { + if (!(samplers & (1 << i))) + continue; + so_get_push_reloc_markers(state->hw[NV40_STATE_FRAGTEX0+i], + &push, &reloc); + } + + so_get_push_reloc_markers(state->hw[NV40_STATE_FRAGPROG], + &push, &reloc); + if (state->hw[NV40_STATE_VTXBUF] && nv40->render_mode == HW) + so_get_push_reloc_markers(state->hw[NV40_STATE_VTXBUF], + &push, &reloc); + + /* Will flush if necessary. */ + MARK_RING (chan, push, reloc); + for (i = 0, states = state->dirty; states; i++) { if (!(states & (1ULL << i))) continue; diff --git a/src/gallium/drivers/nv50/nv50_query.c b/src/gallium/drivers/nv50/nv50_query.c index 5305c93..268c982 100644 --- a/src/gallium/drivers/nv50/nv50_query.c +++ b/src/gallium/drivers/nv50/nv50_query.c @@ -93,7 +93,7 @@ nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq) struct nouveau_grobj *tesla = nv50->screen->tesla; struct nv50_query *q = nv50_query(pq); - WAIT_RING (chan, 5); + MARK_RING (chan, 5, 2); /* flush on lack of space or relocs */ BEGIN_RING(chan, tesla, NV50TCL_QUERY_ADDRESS_HIGH, 4); OUT_RELOCh(chan, q->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); OUT_RELOCl(chan, q->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); diff --git a/src/gallium/drivers/nv50/nv50_state_validate.c b/src/gallium/drivers/nv50/nv50_state_validate.c index c871aca..c42a666 100644 --- a/src/gallium/drivers/nv50/nv50_state_validate.c +++ b/src/gallium/drivers/nv50/nv50_state_validate.c @@ -160,6 +160,7 @@ nv50_state_emit(struct nv50_context *nv50) { struct nv50_screen *screen = nv50->screen; struct nouveau_channel *chan = screen->base.channel; + int push = 0, reloc = 0; if (nv50->pctx_id != screen->cur_pctx) { if (nv50->state.fb) @@ -191,6 +192,44 @@ nv50_state_emit(struct nv50_context *nv50) screen->cur_pctx = nv50->pctx_id; } + /* Find out how much space we need in the pushbuffer. */ + if (nv50->state.dirty & NV50_NEW_FRAMEBUFFER) + so_get_push_reloc(nv50->state.fb, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_BLEND) + so_get_push_reloc(nv50->state.blend, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_ZSA) + so_get_push_reloc(nv50->state.zsa, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_VERTPROG) + so_get_push_reloc(nv50->state.vertprog, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_FRAGPROG) + so_get_push_reloc(nv50->state.fragprog, &push, &reloc); + if (nv50->state.dirty & (NV50_NEW_FRAGPROG | NV50_NEW_VERTPROG | + NV50_NEW_RASTERIZER)) + so_get_push_reloc(nv50->state.programs, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_RASTERIZER) + so_get_push_reloc(nv50->state.rast, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_BLEND_COLOUR) + so_get_push_reloc(nv50->state.blend_colour, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_STIPPLE) + so_get_push_reloc(nv50->state.stipple, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_SCISSOR) + so_get_push_reloc(nv50->state.scissor, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_VIEWPORT) + so_get_push_reloc(nv50->state.viewport, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_SAMPLER) + so_get_push_reloc(nv50->state.tsc_upload, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_TEXTURE) + so_get_push_reloc(nv50->state.tic_upload, &push, &reloc); + if (nv50->state.dirty & NV50_NEW_ARRAYS) { + so_get_push_reloc(nv50->state.vtxfmt, &push, &reloc); + so_get_push_reloc(nv50->state.vtxbuf, &push, &reloc); + if (nv50->state.vtxattr) + so_get_push_reloc(nv50->state.vtxattr, &push, &reloc); + } + + /* Flush if needed. */ + MARK_RING(chan, push, reloc); + if (nv50->state.dirty & NV50_NEW_FRAMEBUFFER) so_emit(chan, nv50->state.fb); if (nv50->state.dirty & NV50_NEW_BLEND) diff --git a/src/gallium/drivers/nv50/nv50_surface.c b/src/gallium/drivers/nv50/nv50_surface.c index 6bf6f77..79655fc 100644 --- a/src/gallium/drivers/nv50/nv50_surface.c +++ b/src/gallium/drivers/nv50/nv50_surface.c @@ -62,6 +62,7 @@ nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) return 1; if (!bo->tile_flags) { + MARK_RING (chan, 9, 2); /* flush on lack of space or relocs */ BEGIN_RING(chan, eng2d, mthd, 2); OUT_RING (chan, format); OUT_RING (chan, 1); @@ -72,6 +73,7 @@ nv50_surface_set(struct nv50_screen *screen, struct pipe_surface *ps, int dst) OUT_RELOCh(chan, bo, ps->offset, flags); OUT_RELOCl(chan, bo, ps->offset, flags); } else { + MARK_RING (chan, 11, 2); /* flush on lack of space or relocs */ BEGIN_RING(chan, eng2d, mthd, 5); OUT_RING (chan, format); OUT_RING (chan, 0); diff --git a/src/gallium/drivers/nv50/nv50_transfer.c b/src/gallium/drivers/nv50/nv50_transfer.c index 4705f96..1b6c8d6 100644 --- a/src/gallium/drivers/nv50/nv50_transfer.c +++ b/src/gallium/drivers/nv50/nv50_transfer.c @@ -81,7 +81,7 @@ nv50_transfer_rect_m2mf(struct pipe_screen *pscreen, while (height) { int line_count = height > 2047 ? 2047 : height; - WAIT_RING (chan, 15); + MARK_RING (chan, 15, 4); /* flush on lack of space or relocs */ BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH, 2); OUT_RELOCh(chan, src_bo, src_offset, src_reloc); @@ -282,7 +282,7 @@ nv50_upload_sifc(struct nv50_context *nv50, reloc |= NOUVEAU_BO_WR; - WAIT_RING (chan, 32); + MARK_RING (chan, 32, 2); /* flush on lack of space or relocs */ if (bo->tile_flags) { BEGIN_RING(chan, eng2d, NV50_2D_DST_FORMAT, 5); -- 1.6.5.3
Reasonably Related Threads
- [PATCH] nouveau: avoid running out of relocs (attempt 5)
- [PATCH] nouveau: avoid running out of relocs (attempt 4)
- [PATCH 1/2] nv30-nv40: Rewrite primitive splitting and emission
- [PATCH] Fix surface_fill alpha
- [PATCH 1/2] nv50: don't emit reloc markers after a referenced vtxbuf is mapped