diff options
author | Ben Skeggs <skeggsb@beleth.(none)> | 2009-11-04 15:23:53 +1000 |
---|---|---|
committer | Ben Skeggs <skeggsb@beleth.(none)> | 2009-11-04 15:24:27 +1000 |
commit | f4c50630269df4201b89a538cbf8e11646f17d82 (patch) | |
tree | 750228abbb1af6d0d00a962d857530c9303460b9 | |
parent | a8bdf0e00c0653fd343fd7fd64b5f2e8437bb130 (diff) |
nouveau: modify api slightly to allow caller to handle reloc failures
Signed-off-by: Ben Skeggs <skeggsb@beleth.(none)>
-rw-r--r-- | libdrm/nouveau/nouveau_private.h | 3 | ||||
-rw-r--r-- | libdrm/nouveau/nouveau_pushbuf.c | 53 | ||||
-rw-r--r-- | libdrm/nouveau/nouveau_pushbuf.h | 53 |
3 files changed, 90 insertions, 19 deletions
diff --git a/libdrm/nouveau/nouveau_private.h b/libdrm/nouveau/nouveau_private.h index 743c8314..784afc91 100644 --- a/libdrm/nouveau/nouveau_private.h +++ b/libdrm/nouveau/nouveau_private.h @@ -52,6 +52,9 @@ struct nouveau_pushbuf_priv { unsigned *pushbuf; unsigned size; + unsigned marker; + unsigned marker_relocs; + struct drm_nouveau_gem_pushbuf_bo *buffers; unsigned nr_buffers; struct drm_nouveau_gem_pushbuf_reloc *relocs; diff --git a/libdrm/nouveau/nouveau_pushbuf.c b/libdrm/nouveau/nouveau_pushbuf.c index af181b2e..df43effc 100644 --- a/libdrm/nouveau/nouveau_pushbuf.c +++ b/libdrm/nouveau/nouveau_pushbuf.c @@ -67,7 +67,6 @@ nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr, if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) { fprintf(stderr, "too many relocs!!\n"); - assert(0); return -ENOMEM; } @@ -79,7 +78,6 @@ nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr, pbbo = nouveau_bo_emit_buffer(chan, bo); if (!pbbo) { fprintf(stderr, "buffer emit fail :(\n"); - assert(0); return -ENOMEM; } @@ -353,6 +351,57 @@ restart_push: if (chan->flush_notify) chan->flush_notify(chan); + nvpb->marker = 0; return ret; } +int +nouveau_pushbuf_marker_emit(struct nouveau_channel *chan, + unsigned wait_dwords, unsigned wait_relocs) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); + + if (AVAIL_RING(chan) < wait_dwords) + return nouveau_pushbuf_flush(chan, wait_dwords); + + if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS) + return nouveau_pushbuf_flush(chan, wait_dwords); + + nvpb->marker = nvpb->base.cur - nvpb->pushbuf; + nvpb->marker_relocs = nvpb->nr_relocs; + return 0; +} + +void +nouveau_pushbuf_marker_undo(struct nouveau_channel *chan) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf); + unsigned i; + + if (!nvpb->marker) + return; + + /* undo any relocs/buffers added to the list since last marker */ + for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) { + struct drm_nouveau_gem_pushbuf_reloc *r = &nvpb->relocs[i]; + struct drm_nouveau_gem_pushbuf_bo *pbbo = + &nvpb->buffers[r->bo_index]; + struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv; + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + if (--nvbo->pending_refcnt) + continue; + + nvbo->pending = NULL; + nouveau_bo_ref(NULL, &bo); + nvpb->nr_buffers--; + } + nvpb->nr_relocs = nvpb->marker_relocs; + + /* reset pushbuf back to last marker */ + nvpb->base.cur = nvpb->pushbuf + nvpb->marker; + nvpb->base.remaining = nvpb->size - nvpb->marker; + nvpb->marker = 0; +} + + diff --git a/libdrm/nouveau/nouveau_pushbuf.h b/libdrm/nouveau/nouveau_pushbuf.h index 3c746ed2..c7ac8c45 100644 --- a/libdrm/nouveau/nouveau_pushbuf.h +++ b/libdrm/nouveau/nouveau_pushbuf.h @@ -40,11 +40,30 @@ int nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min); int +nouveau_pushbuf_marker_emit(struct nouveau_channel *chan, + unsigned wait_dwords, unsigned wait_relocs); + +void +nouveau_pushbuf_marker_undo(struct nouveau_channel *chan); + +int nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr, struct nouveau_bo *, uint32_t data, uint32_t data2, uint32_t flags, uint32_t vor, uint32_t tor); /* Push buffer access macros */ +static __inline__ int +MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs) +{ + return nouveau_pushbuf_marker_emit(chan, dwords, relocs); +} + +static __inline__ void +MARK_UNDO(struct nouveau_channel *chan) +{ + nouveau_pushbuf_marker_undo(chan); +} + static __inline__ void OUT_RING(struct nouveau_channel *chan, unsigned data) { @@ -116,62 +135,62 @@ BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc) OUT_RING (chan, gr->handle); } -static __inline__ void +static __inline__ int OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned data, unsigned flags, unsigned vor, unsigned tor) { - nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, - data, 0, flags, vor, tor); + return nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, + data, 0, flags, vor, tor); } -static __inline__ void +static __inline__ int OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned data, unsigned data2, unsigned flags, unsigned vor, unsigned tor) { - nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, - data, data2, flags, vor, tor); + return nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo, + data, data2, flags, vor, tor); } /* Raw data + flags depending on FB/TT buffer */ -static __inline__ void +static __inline__ int OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned data, unsigned flags, unsigned vor, unsigned tor) { - OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor); + return OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor); } /* FB/TT object handle */ -static __inline__ void +static __inline__ int OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned flags) { - OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR, - chan->vram->handle, chan->gart->handle); + return OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR, + chan->vram->handle, chan->gart->handle); } /* Low 32-bits of offset */ -static __inline__ void +static __inline__ int OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned delta, unsigned flags) { - OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0); + return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0); } /* Low 32-bits of offset + GPU linear access range info */ -static __inline__ void +static __inline__ int OUT_RELOCr(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned delta, unsigned size, unsigned flags) { - OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0); + return OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0); } /* High 32-bits of offset */ -static __inline__ void +static __inline__ int OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo, unsigned delta, unsigned flags) { - OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0); + return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0); } #endif |