nouveau: relocs are per-pushbuf, not per-channel
authorBen Skeggs <skeggsb@gmail.com>
Sun, 9 Dec 2007 10:44:46 +0000 (21:44 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Sun, 9 Dec 2007 10:44:46 +0000 (21:44 +1100)
src/mesa/drivers/dri/nouveau_winsys/nouveau_bo.c
src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c
src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
src/mesa/pipe/nouveau/nouveau_winsys.h

index f1981b977706460dad59c98e564c144fa40725c5..fd6d05b7fab1b66f1fe659fd33e0b991a77e6083 100644 (file)
@@ -232,47 +232,6 @@ nouveau_bo_unmap(struct nouveau_bo *userbo)
        userbo->map = NULL;
 }
 
-void
-nouveau_bo_emit_reloc(struct nouveau_channel *userchan, void *ptr,
-                     struct nouveau_bo *userbo, uint32_t data, uint32_t flags,
-                     uint32_t vor, uint32_t tor)
-{
-       struct nouveau_channel_priv *chan = nouveau_channel(userchan);
-       struct nouveau_bo_priv *bo = nouveau_bo(userbo);
-       struct nouveau_bo_reloc *r;
-       int i, on_list = 0;
-
-       for (i = 0; i < chan->nr_buffers; i++) {
-               if (chan->buffers[i].bo == bo) {
-                       on_list = 1;
-                       break;
-               }
-       }
-
-       if (i >= 128)
-               return;
-
-       if (on_list) {
-               chan->buffers[i].flags &= (flags | NOUVEAU_BO_RDWR);
-               chan->buffers[i].flags |= (flags & NOUVEAU_BO_RDWR);
-       } else {
-               chan->buffers[i].bo = bo;
-               chan->buffers[i].flags = flags;
-               chan->nr_buffers++;
-       }
-
-       if (chan->num_relocs >= chan->max_relocs)
-               FIRE_RING_CH(userchan);
-       r = &chan->relocs[chan->num_relocs++];
-
-       r->ptr = ptr;
-       r->bo = bo;
-       r->data = data;
-       r->flags = flags;
-       r->vor = vor;
-       r->tor = tor;
-}
-
 static int
 nouveau_bo_upload(struct nouveau_bo_priv *bo)
 {
@@ -280,35 +239,30 @@ nouveau_bo_upload(struct nouveau_bo_priv *bo)
        return 0;
 }
 
-void
-nouveau_bo_validate(struct nouveau_channel *userchan)
+int
+nouveau_bo_validate(struct nouveau_channel *chan, struct nouveau_bo *bo,
+                   uint32_t flags)
 {
-       struct nouveau_channel_priv *chan = nouveau_channel(userchan);
-       int i;
-
-       for (i = 0; i < chan->nr_buffers; i++) {
-               struct nouveau_bo_priv *bo = chan->buffers[i].bo;
-
-               if (!bo->drm.size) {
-                       nouveau_bo_realloc_gpu(bo, chan->buffers[i].flags,
-                                              bo->base.size);
-                       nouveau_bo_upload(bo);
-               } else
-               if (bo->user || bo->base.map)
-                       nouveau_bo_upload(bo);
-
-               if (!bo->user && !bo->base.map) {
-                       free(bo->sysmem);
-                       bo->sysmem = NULL;
-               }
+       struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+       if (!nvbo->drm.size) {
+               nouveau_bo_realloc_gpu(nvbo, flags, nvbo->base.size);
+               nouveau_bo_upload(nvbo);
+       } else
+       if (nvbo->user || nvbo->base.map)
+               nouveau_bo_upload(nvbo);
+
+       if (!nvbo->user && !nvbo->base.map) {
+               free(nvbo->sysmem);
+               nvbo->sysmem = NULL;
+       }
 
+       nvbo->base.offset = nvbo->drm.offset;
+       if (nvbo->drm.flags & NOUVEAU_MEM_AGP)
+               nvbo->base.flags = NOUVEAU_BO_GART;
+       else
+               nvbo->base.flags = NOUVEAU_BO_VRAM;
 
-               bo->base.offset = bo->drm.offset;
-               if (bo->drm.flags & NOUVEAU_MEM_AGP)
-                       bo->base.flags = NOUVEAU_BO_GART;
-               else
-                       bo->base.flags = NOUVEAU_BO_VRAM;
-       }
-       chan->nr_buffers = 0;
+       return 0;
 }
 
index 64136775da06f09a6f1067877c3ef554b981fbb3..c4558e5573a2ac839cfd98a2910a26985a0c3be7 100644 (file)
@@ -85,11 +85,6 @@ nouveau_channel_alloc(struct nouveau_device *userdev, uint32_t fb_ctxdma,
                return ret;
        }
 
-       chan->max_relocs = chan->drm.cmdbuf_size / 4;
-       chan->num_relocs = 0;
-       chan->relocs =
-               malloc(sizeof(struct nouveau_bo_reloc) * chan->max_relocs);
-
        nouveau_dma_channel_init(&chan->base);
        nouveau_pushbuf_init(&chan->base);
 
@@ -115,9 +110,6 @@ nouveau_channel_free(struct nouveau_channel **userchan)
 
                FIRE_RING_CH(&chan->base);
 
-               if (chan->relocs)
-                       free(chan->relocs);
-
                nouveau_grobj_free(&chan->base.vram);
                nouveau_grobj_free(&chan->base.gart);
 
index 4f467406ddb7e094e2bd974e4fe95fcb37a56cd6..8af0b9d5cd3c1b1a4e1c36a7e84371998b167ad0 100644 (file)
@@ -94,6 +94,24 @@ nouveau_fence_wait(struct nouveau_fence **);
 extern void
 nouveau_fence_flush(struct nouveau_channel *);
 
+struct nouveau_pushbuf_reloc {
+       uint64_t next;
+       uint64_t handle;
+       uint32_t *ptr;
+       uint32_t flags;
+       uint32_t data;
+       uint32_t vor;
+       uint32_t tor;
+};
+
+struct nouveau_pushbuf_bo {
+       uint64_t next;
+       uint64_t handle;
+       uint64_t flags;
+       uint64_t relocs;
+       int nr_relocs;
+};
+
 struct nouveau_pushbuf {
        struct nouveau_channel *channel;
        unsigned remaining;
@@ -106,8 +124,17 @@ struct nouveau_pushbuf_priv {
 
        struct nouveau_resource *res;
        struct nouveau_fence *fence;
+
+       uint64_t buffers;
+       int nr_buffers;
 };
 #define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+#define pbbo_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_pbbo(h) ((struct nouveau_pushbuf_bo *)(unsigned long)(h))
+#define pbrel_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_pbrel(h) ((struct nouveau_pushbuf_reloc *)(unsigned long)(h))
+#define bo_to_ptr(o) ((uint64_t)(unsigned long)(o))
+#define ptr_to_bo(h) ((struct nouveau_bo_priv *)(unsigned long)(h))
 
 extern int
 nouveau_pushbuf_init(struct nouveau_channel *);
@@ -115,6 +142,11 @@ nouveau_pushbuf_init(struct nouveau_channel *);
 extern int
 nouveau_pushbuf_flush(struct nouveau_channel *);
 
+extern int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
+                          struct nouveau_bo *, uint32_t data, uint32_t flags,
+                          uint32_t vor, uint32_t tor);
+
 struct nouveau_channel_priv {
        struct nouveau_channel base;
 
@@ -142,16 +174,6 @@ struct nouveau_channel_priv {
                int push_free;
        } dma;
 
-       struct {
-               struct nouveau_bo_priv *bo;
-               uint32_t flags;
-       } buffers[128];
-       int nr_buffers;
-
-       struct nouveau_bo_reloc *relocs;
-       int num_relocs;
-       int max_relocs;
-
        struct nouveau_fence *fence_head;
        struct nouveau_fence *fence_tail;
        uint32_t fence_sequence;
@@ -222,14 +244,6 @@ struct nouveau_bo_priv {
 
        int refcount;
 };
-
-struct nouveau_bo_reloc {
-       struct nouveau_bo_priv *bo;
-       uint32_t *ptr;
-       uint32_t flags;
-       uint32_t data, vor, tor;
-};
-
 #define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
 
 extern int
@@ -261,13 +275,9 @@ nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
 extern void
 nouveau_bo_unmap(struct nouveau_bo *);
 
-extern void
-nouveau_bo_emit_reloc(struct nouveau_channel *chan, void *ptr,
-                     struct nouveau_bo *, uint32_t data, uint32_t flags,
-                     uint32_t vor, uint32_t tor);
-
-extern void
-nouveau_bo_validate(struct nouveau_channel *);
+extern int
+nouveau_bo_validate(struct nouveau_channel *, struct nouveau_bo *,
+                   uint32_t flags);
 
 extern int
 nouveau_resource_init(struct nouveau_resource **heap, int size);
index 2534a8ea6f96863364f2302946f17e238fcd97a0..1978edea02dd7a01626a08a3ba1241810b4c5ab3 100644 (file)
@@ -49,8 +49,8 @@
 } while(0)
 
 #define OUT_RELOC(bo,data,flags,vor,tor) do {                                  \
-       nouveau_bo_emit_reloc(nv->channel, nv->pushbuf, (void*)(bo), (data),   \
-                             (flags), (vor), (tor));                          \
+       nouveau_pushbuf_emit_reloc(nv->channel, nv->pushbuf, (void*)(bo),      \
+                                  (data), (flags), (vor), (tor));             \
        OUT_RING(0);                                                           \
 } while(0)
 
index 75d41d6c147bc942fa2423223da99010ebd05046..4a964cb82b581f7384d1826f689d0a8127aa35b8 100644 (file)
@@ -54,7 +54,8 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan)
 {
        struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
        struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(nvchan->pb_tail);
-       int i, ret;
+       struct nouveau_pushbuf_bo *pbbo;
+       int ret;
 
        if (!nvpb)
                goto out_realloc;
@@ -66,36 +67,42 @@ nouveau_pushbuf_flush(struct nouveau_channel *chan)
        if (ret)
                return ret;
 
-       /* Validate buffers */
-       nouveau_bo_validate(chan);
+       /* Validate buffers + apply relocations */
+       while ((pbbo = ptr_to_pbbo(nvpb->buffers))) {
+               struct nouveau_pushbuf_reloc *r;
+               struct nouveau_bo *bo = &ptr_to_bo(pbbo->handle)->base;
 
-       /* Apply relocations */
-       if (nvchan->num_relocs) {               
-               for (i = 0; i < nvchan->num_relocs; i++) {
-                       struct nouveau_bo_reloc *r = &nvchan->relocs[i];
+               ret = nouveau_bo_validate(chan, bo, pbbo->flags);
+               assert (ret == 0);
+
+               while ((r = ptr_to_pbrel(pbbo->relocs))) {
                        uint32_t push;
 
                        if (r->flags & NOUVEAU_BO_LOW) {
-                               push = r->bo->base.offset + r->data;
+                               push = bo->offset + r->data;
                        } else
                        if (r->flags & NOUVEAU_BO_HIGH) {
-                               push = (r->bo->base.offset + r->data) >> 32;
+                               push = (bo->offset + r->data) >> 32;
                        } else {
                                push = r->data;
                        }
 
                        if (r->flags & NOUVEAU_BO_OR) {
-                               if (r->bo->base.flags & NOUVEAU_BO_VRAM)
+                               if (bo->flags & NOUVEAU_BO_VRAM)
                                        push |= r->vor;
                                else
                                        push |= r->tor;
                        }
 
                        *r->ptr = push;
+                       pbbo->relocs = r->next;
+                       free(r);
                }
 
-               nvchan->num_relocs = 0;
+               nvpb->buffers = pbbo->next;
+               free(pbbo);
        }
+       nvpb->nr_buffers = 0;
 
        /* Emit JMP to indirect pushbuf */
        if (nvchan->dma.free < 1)
@@ -175,3 +182,61 @@ out_realloc:
        return 0;
 }
 
+static struct nouveau_pushbuf_bo *
+nouveau_pushbuf_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(nvchan->pb_tail);
+       struct nouveau_pushbuf_bo *pbbo = ptr_to_pbbo(nvpb->buffers);
+
+       while (pbbo) {
+               if (pbbo->handle == bo->handle)
+                       return pbbo;
+               pbbo = ptr_to_pbbo(pbbo->next);
+       }
+
+       pbbo = malloc(sizeof(struct nouveau_pushbuf_bo));
+       pbbo->next = nvpb->buffers;
+       nvpb->buffers = pbbo_to_ptr(pbbo);
+       nvpb->nr_buffers++;
+
+       pbbo->handle = bo_to_ptr(bo);
+       pbbo->flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART;
+       pbbo->relocs = 0;
+       pbbo->nr_relocs = 0;
+       return pbbo;
+}
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
+                          struct nouveau_bo *bo, uint32_t data, uint32_t flags,
+                          uint32_t vor, uint32_t tor)
+{
+       struct nouveau_pushbuf_bo *pbbo;
+       struct nouveau_pushbuf_reloc *r;
+
+       if (!chan)
+               return -EINVAL;
+
+       pbbo = nouveau_pushbuf_emit_buffer(chan, bo);
+       if (!pbbo)
+               return -EFAULT;
+
+       r = malloc(sizeof(struct nouveau_pushbuf_reloc));
+       r->next = pbbo->relocs;
+       pbbo->relocs = pbrel_to_ptr(r);
+       pbbo->nr_relocs++;
+
+       pbbo->flags |= (flags & NOUVEAU_BO_RDWR);
+       pbbo->flags &= (flags | NOUVEAU_BO_RDWR);
+
+       r->handle = bo_to_ptr(r);
+       r->ptr = ptr;
+       r->flags = flags;
+       r->data = data;
+       r->vor = vor;
+       r->tor = tor;
+
+       return 0;
+}
+
index 77d9e710dbe7d4d55eee6437bb83f3a62bc5625b..9919272ebe160d5bbb7720d2a725533aa38967af 100644 (file)
@@ -204,7 +204,7 @@ nouveau_pipe_create(struct nouveau_context *nv)
        nvws->res_free          = nouveau_resource_free;
 
        nvws->begin_ring        = nouveau_pipe_dma_beginp;
-       nvws->out_reloc         = nouveau_bo_emit_reloc;
+       nvws->out_reloc         = nouveau_pushbuf_emit_reloc;
        nvws->fire_ring         = nouveau_pipe_dma_kickoff;
 
        nvws->grobj_alloc       = nouveau_pipe_grobj_alloc;
index ce1744c2eecd76f10410940bfd93183c9cefaa84..4525f7113c26afd2a309a36ff4e8fbf4b3ba1b9b 100644 (file)
@@ -25,7 +25,7 @@ struct nouveau_winsys {
        /*XXX: this is crappy, and bound to be slow.. however, it's nice and
         *     simple, it'll do for the moment*/
        uint32_t *(*begin_ring)(struct nouveau_grobj *, int mthd, int size);
-       void      (*out_reloc)(struct nouveau_channel *, void *ptr,
+       int       (*out_reloc)(struct nouveau_channel *, void *ptr,
                               struct nouveau_bo *, uint32_t data,
                               uint32_t flags, uint32_t vor, uint32_t tor);
        void      (*fire_ring)(struct nouveau_channel *);