Maarten Maathuis
2009-Dec-13 15:07 UTC
[Nouveau] [PATCH] nouveau: avoid running out of relocs (attempt 5)
- Added flush notify functions for NV30 and NV40.
- NV30 and NV40 need testing (check for regressions).
---
src/gallium/drivers/nouveau/nouveau_stateobj.h | 47 +++++++++++++++++++-----
src/gallium/drivers/nv04/nv04_surface_2d.c | 9 +++--
src/gallium/drivers/nv30/nv30_context.c | 3 ++
src/gallium/drivers/nv30/nv30_context.h | 1 +
src/gallium/drivers/nv30/nv30_state_emit.c | 10 +++++-
src/gallium/drivers/nv40/nv40_context.c | 3 ++
src/gallium/drivers/nv40/nv40_context.h | 1 +
src/gallium/drivers/nv40/nv40_state_emit.c | 10 +++++-
src/gallium/drivers/nv50/nv50_query.c | 2 +-
src/gallium/drivers/nv50/nv50_surface.c | 2 +
src/gallium/drivers/nv50/nv50_transfer.c | 4 +-
11 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/src/gallium/drivers/nouveau/nouveau_stateobj.h
b/src/gallium/drivers/nouveau/nouveau_stateobj.h
index 62990f9..de045ef 100644
--- a/src/gallium/drivers/nouveau/nouveau_stateobj.h
+++ b/src/gallium/drivers/nouveau/nouveau_stateobj.h
@@ -112,19 +112,29 @@ so_emit(struct nouveau_channel *chan, struct
nouveau_stateobj *so)
{
struct nouveau_pushbuf *pb = chan->pushbuf;
unsigned nr, i;
+ int ret = 0;
nr = so->cur - so->push;
- if (pb->remaining < nr)
- nouveau_pushbuf_flush(chan, nr);
+ /* This will flush if we need space.
+ * We don't actually need the marker.
+ */
+ if ((ret = nouveau_pushbuf_marker_emit(chan, nr, so->cur_reloc))) {
+ debug_printf("so_emit failed marker emit with error %d\n", ret);
+ 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];
- 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);
+ pb->remaining += nr;
+ return;
+ }
}
pb->cur += nr;
}
@@ -134,26 +144,43 @@ so_emit_reloc_markers(struct nouveau_channel *chan, struct
nouveau_stateobj *so)
{
struct nouveau_pushbuf *pb = chan->pushbuf;
unsigned i;
+ int ret = 0;
if (!so)
return;
i = so->cur_reloc << 1;
- if (pb->remaining < i)
- nouveau_pushbuf_flush(chan, i);
+ /* This will flush if we need space.
+ * We don't actually need the marker.
+ */
+ if ((ret = nouveau_pushbuf_marker_emit(chan, i, i))) {
+ debug_printf("so_emit_reloc_markers failed marker emit with \
+ error %d\n", ret);
+ return;
+ }
pb->remaining -= i;
for (i = 0; i < so->cur_reloc; i++) {
struct nouveau_stateobj_reloc *r = &so->reloc[i];
- 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);
+ pb->remaining += i;
+ return;
+ }
+ 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);
+ pb->remaining += i;
+ return;
+ }
}
}
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_context.c
b/src/gallium/drivers/nv30/nv30_context.c
index d8300fd..46a821a 100644
--- a/src/gallium/drivers/nv30/nv30_context.c
+++ b/src/gallium/drivers/nv30/nv30_context.c
@@ -58,6 +58,9 @@ nv30_create(struct pipe_screen *pscreen, unsigned pctx_id)
nv30->pipe.is_texture_referenced = nouveau_is_texture_referenced;
nv30->pipe.is_buffer_referenced = nouveau_is_buffer_referenced;
+ screen->base.channel->user_private = nv30;
+ screen->base.channel->flush_notify = nv30_state_flush_notify;
+
nv30_init_query_functions(nv30);
nv30_init_surface_functions(nv30);
nv30_init_state_functions(nv30);
diff --git a/src/gallium/drivers/nv30/nv30_context.h
b/src/gallium/drivers/nv30/nv30_context.h
index 8d49366..6f44b1c 100644
--- a/src/gallium/drivers/nv30/nv30_context.h
+++ b/src/gallium/drivers/nv30/nv30_context.h
@@ -184,6 +184,7 @@ extern void nv30_fragtex_bind(struct nv30_context *);
/* nv30_state.c and friends */
extern boolean nv30_state_validate(struct nv30_context *nv30);
extern void nv30_state_emit(struct nv30_context *nv30);
+extern void nv30_state_flush_notify(struct nouveau_channel *chan);
extern struct nv30_state_entry nv30_state_rasterizer;
extern struct nv30_state_entry nv30_state_scissor;
extern struct nv30_state_entry nv30_state_stipple;
diff --git a/src/gallium/drivers/nv30/nv30_state_emit.c
b/src/gallium/drivers/nv30/nv30_state_emit.c
index 621b884..ac52d94 100644
--- a/src/gallium/drivers/nv30/nv30_state_emit.c
+++ b/src/gallium/drivers/nv30/nv30_state_emit.c
@@ -41,7 +41,7 @@ nv30_state_emit(struct nv30_context *nv30)
struct nouveau_channel *chan = nv30->screen->base.channel;
struct nv30_state *state = &nv30->state;
struct nv30_screen *screen = nv30->screen;
- unsigned i, samplers;
+ unsigned i;
uint64_t states;
if (nv30->pctx_id != screen->cur_pctx) {
@@ -63,6 +63,14 @@ nv30_state_emit(struct nv30_context *nv30)
}
state->dirty = 0;
+}
+
+void
+nv30_state_flush_notify(struct nouveau_channel *chan)
+{
+ struct nv30_context *nv30 = chan->user_private;
+ struct nv30_state *state = &nv30->state;
+ unsigned i, samplers;
so_emit_reloc_markers(chan, state->hw[NV30_STATE_FB]);
for (i = 0, samplers = state->fp_samplers; i < 16 && samplers;
i++) {
diff --git a/src/gallium/drivers/nv40/nv40_context.c
b/src/gallium/drivers/nv40/nv40_context.c
index 7f00827..eb9cce4 100644
--- a/src/gallium/drivers/nv40/nv40_context.c
+++ b/src/gallium/drivers/nv40/nv40_context.c
@@ -58,6 +58,9 @@ nv40_create(struct pipe_screen *pscreen, unsigned pctx_id)
nv40->pipe.is_texture_referenced = nouveau_is_texture_referenced;
nv40->pipe.is_buffer_referenced = nouveau_is_buffer_referenced;
+ screen->base.channel->user_private = nv40;
+ screen->base.channel->flush_notify = nv40_state_flush_notify;
+
nv40_init_query_functions(nv40);
nv40_init_surface_functions(nv40);
nv40_init_state_functions(nv40);
diff --git a/src/gallium/drivers/nv40/nv40_context.h
b/src/gallium/drivers/nv40/nv40_context.h
index a3d5941..cf33b64 100644
--- a/src/gallium/drivers/nv40/nv40_context.h
+++ b/src/gallium/drivers/nv40/nv40_context.h
@@ -204,6 +204,7 @@ extern void nv40_fragtex_bind(struct nv40_context *);
extern boolean nv40_state_validate(struct nv40_context *nv40);
extern boolean nv40_state_validate_swtnl(struct nv40_context *nv40);
extern void nv40_state_emit(struct nv40_context *nv40);
+extern void nv40_state_flush_notify(struct nouveau_channel *chan);
extern struct nv40_state_entry nv40_state_rasterizer;
extern struct nv40_state_entry nv40_state_scissor;
extern struct nv40_state_entry nv40_state_stipple;
diff --git a/src/gallium/drivers/nv40/nv40_state_emit.c
b/src/gallium/drivers/nv40/nv40_state_emit.c
index 1986929..ba0fbcb 100644
--- a/src/gallium/drivers/nv40/nv40_state_emit.c
+++ b/src/gallium/drivers/nv40/nv40_state_emit.c
@@ -57,7 +57,7 @@ nv40_state_emit(struct nv40_context *nv40)
struct nouveau_channel *chan = nv40->screen->base.channel;
struct nv40_state *state = &nv40->state;
struct nv40_screen *screen = nv40->screen;
- unsigned i, samplers;
+ unsigned i;
uint64_t states;
if (nv40->pctx_id != screen->cur_pctx) {
@@ -87,6 +87,14 @@ nv40_state_emit(struct nv40_context *nv40)
}
state->dirty = 0;
+}
+
+void
+nv40_state_flush_notify(struct nouveau_channel *chan)
+{
+ struct nv40_context *nv40 = chan->user_private;
+ struct nv40_state *state = &nv40->state;
+ unsigned i, samplers;
so_emit_reloc_markers(chan, state->hw[NV40_STATE_FB]);
for (i = 0, samplers = state->fp_samplers; i < 16 && samplers;
i++) {
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_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.4
Patrice Mandin
2009-Dec-13 20:06 UTC
[Nouveau] [PATCH] nouveau: avoid running out of relocs (attempt 5)
Le Sun, 13 Dec 2009 16:07:37 +0100 Maarten Maathuis <madman2003 at gmail.com> a ?crit:> - Added flush notify functions for NV30 and NV40. > - NV30 and NV40 need testing (check for regressions).Just tested for NV30, no visible regression, just a minor performance penalty. So it's OK for me. Timedemo with ioquake3: mesa git head: 1260 frames 31.5 seconds 40.0 fps 9.0/25.0/50.0/8.0 ms 1260 frames 31.4 seconds 40.1 fps 9.0/24.9/50.0/7.9 ms with your patch, outofreloc.diff: 1260 frames 32.7 seconds 38.5 fps 9.0/26.0/52.0/8.2 ms 1260 frames 32.6 seconds 38.7 fps 9.0/25.8/51.0/8.1 ms -- Patrice Mandin WWW: http://pmandin.atari.org/ Programmeur Linux, Atari Sp?cialit?: D?veloppement, jeux
Xavier
2009-Dec-13 20:34 UTC
[Nouveau] [PATCH] nouveau: avoid running out of relocs (attempt 5)
On Sun, Dec 13, 2009 at 4:07 PM, Maarten Maathuis <madman2003 at gmail.com> wrote:> - Added flush notify functions for NV30 and NV40. > - NV30 and NV40 need testing (check for regressions). > ---Tested on NV35. No obvious regressions on xmoto and teeworlds (I didn't benchmark though, but the perf felt similar). I was wondering, is there any practical testsuite for this kind of regression testing ? It would be cool to just run a set of tests known to work on nv30 for example, and getting automatically a summary of the results. Then run again after a patch and compare. Any suggestions that get close to that are welcome :)
Christoph Bumiller
2009-Dec-14 16:51 UTC
[Nouveau] [PATCH] nouveau: avoid running out of relocs (attempt 5)
On 13.12.2009 16:07, Maarten Maathuis wrote:> - Added flush notify functions for NV30 and NV40. > - NV30 and NV40 need testing (check for regressions). > --- > > @@ -112,19 +112,29 @@ so_emit(struct nouveau_channel *chan, struct nouveau_stateobj *so) > { > struct nouveau_pushbuf *pb = chan->pushbuf; > unsigned nr, i; > + int ret = 0; > > nr = so->cur - so->push; > - if (pb->remaining < nr) > - nouveau_pushbuf_flush(chan, nr); > + /* This will flush if we need space. > + * We don't actually need the marker. > + */ > + if ((ret = nouveau_pushbuf_marker_emit(chan, nr, so->cur_reloc))) { > + debug_printf("so_emit failed marker emit with error %d\n", ret); > + return; > + } > pb->remaining -= nr; > >I'm not sure why flushing mid-frame would be bad as Ben said. After all, if there's lots of stuff done during a frame, we will inevitably flush at some point ...> - 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); >Now these debug_printf "will probably give you unwanted" "extra space the way they are" As for the interesting part, the too many relocs I got in vegastrike (and which would need a LOT of NOPs) are gone and nothing else seems to be broken. At some point we'll probably want to know if buffer relocation succeeded or not I guess, and fallback to software on failure. But that still doesn't have a high priority for me personally. Christoph
Seemingly Similar Threads
- [PATCH] nouveau: avoid running out of relocs (attempt 4)
- [PATCH] nouveau: avoid running out of relocs (attempt 3)
- [PATCH 1/2] nv30-nv40: Rewrite primitive splitting and emission
- [PATCH] nv04-nv40: Rewrite and unify miptree and transfer code (v2)
- [PATCH] nv30-nv40: support unlimited queries (v2)