nouveau: use "indirect" push buffers
authorBen Skeggs <skeggsb@gmail.com>
Sun, 9 Dec 2007 09:38:08 +0000 (20:38 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Sun, 9 Dec 2007 09:38:08 +0000 (20:38 +1100)
src/mesa/drivers/dri/nouveau_winsys/Makefile
src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c [new file with mode: 0644]
src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c [new file with mode: 0644]
src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
src/mesa/pipe/nouveau/nouveau_resource.h [new file with mode: 0644]
src/mesa/pipe/nouveau/nouveau_winsys.h

index 9b8a33b725ce4e86e9117ebff1d857488052d801..fe9a9668b11f77919224e4db052f50d505b6f7aa 100644 (file)
@@ -17,9 +17,11 @@ DRIVER_SOURCES = \
        nouveau_context.c \
        nouveau_device.c \
        nouveau_dma.c \
+       nouveau_fence.c \
        nouveau_grobj.c \
        nouveau_lock.c \
        nouveau_notifier.c \
+       nouveau_pushbuf.c \
        nouveau_screen.c \
        nouveau_swapbuffers.c \
        nouveau_winsys.c \
index ef41020b7270ffcdbf583b4962c894e53d29042a..64136775da06f09a6f1067877c3ef554b981fbb3 100644 (file)
@@ -91,6 +91,7 @@ nouveau_channel_alloc(struct nouveau_device *userdev, uint32_t fb_ctxdma,
                malloc(sizeof(struct nouveau_bo_reloc) * chan->max_relocs);
 
        nouveau_dma_channel_init(&chan->base);
+       nouveau_pushbuf_init(&chan->base);
 
        *userchan = &chan->base;
        return 0;
index 7033ff7ae96cf436eed1b0368ea4a6dd73af00f3..cd59b7cc43631b86c1ff1a5cc1cd2835c5d0f099 100644 (file)
@@ -44,6 +44,7 @@ struct nouveau_context {
        struct nouveau_bo *reloc_head;
 
        /* Hardware context */
+       uint32_t                *pushbuf;
        struct nouveau_channel  *channel;
        struct nouveau_notifier *sync_notifier;
        struct nouveau_grobj    *NvNull;
@@ -98,4 +99,7 @@ extern void UNLOCK_HARDWARE(struct nouveau_context *);
 extern int nouveau_surface_init_nv04(struct nouveau_context *);
 extern int nouveau_surface_init_nv50(struct nouveau_context *);
 
+extern uint32_t *nouveau_pipe_dma_beginp(struct nouveau_grobj *, int, int);
+extern void nouveau_pipe_dma_kickoff(struct nouveau_channel *);
+
 #endif
index 6e123c44734a46d1d7c726dc0cf0efe43cf83025..6e32d739abc0ae640652423949d5be618b3f44c3 100644 (file)
@@ -141,35 +141,6 @@ nouveau_dma_kickoff(struct nouveau_channel *userchan)
        if (chan->dma.cur == chan->dma.put)
                return;
 
-       if (chan->num_relocs) {
-               nouveau_bo_validate(userchan);
-               
-               for (i = 0; i < chan->num_relocs; i++) {
-                       struct nouveau_bo_reloc *r = &chan->relocs[i];
-                       uint32_t push;
-
-                       if (r->flags & NOUVEAU_BO_LOW) {
-                               push = r->bo->base.offset + r->data;
-                       } else
-                       if (r->flags & NOUVEAU_BO_HIGH) {
-                               push = (r->bo->base.offset + r->data) >> 32;
-                       } else {
-                               push = r->data;
-                       }
-
-                       if (r->flags & NOUVEAU_BO_OR) {
-                               if (r->bo->base.flags & NOUVEAU_BO_VRAM)
-                                       push |= r->vor;
-                               else
-                                       push |= r->tor;
-                       }
-
-                       *r->ptr = push;
-               }
-
-               chan->num_relocs = 0;
-       }
-
 #ifdef NOUVEAU_DMA_DEBUG
        if (chan->dma.push_free) {
                NOUVEAU_ERR("Packet incomplete: %d left\n", chan->dma.push_free);
@@ -178,8 +149,20 @@ nouveau_dma_kickoff(struct nouveau_channel *userchan)
 #endif
 
 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
-       for (i = chan->dma.put; i < chan->dma.cur; i++)
-               NOUVEAU_MSG("0x%08x\n", chan->pushbuf[i]);
+       for (i = chan->dma.put; i < chan->dma.cur; i++) {
+               NOUVEAU_MSG("0x%08x 0x%08x\n", (i<<2)+chan->dma.base,
+                           chan->pushbuf[i]);
+               if ((chan->pushbuf[i] & 0xf0000000) == 0x20000000) {
+                       int n = (((chan->pushbuf[i] & 0x0fffffff) -
+                                 chan->dma.base) / 4);
+
+                       do {
+                               NOUVEAU_MSG("\t0x%08x 0x%08x\n",
+                                           (n<<2)+chan->dma.base,
+                                           chan->pushbuf[n]);
+                       } while ((chan->pushbuf[n++]&0xf0000000) != 0x20000000);
+               }
+       }
 #endif
 
        put_offset = (chan->dma.cur << 2) + chan->dma.base;
index df98890f8e21537988cd2159d8234151b166bc05..4f467406ddb7e094e2bd974e4fe95fcb37a56cd6 100644 (file)
@@ -32,6 +32,7 @@
 #include "pipe/nouveau/nouveau_grobj.h"
 #include "pipe/nouveau/nouveau_notifier.h"
 #include "pipe/nouveau/nouveau_bo.h"
+#include "pipe/nouveau/nouveau_resource.h"
 
 struct nouveau_device_priv {
        struct nouveau_device base;
@@ -59,6 +60,61 @@ nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
 extern int
 nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
 
+struct nouveau_fence {
+       struct nouveau_channel *channel;
+};
+
+struct nouveau_fence_priv {
+       struct nouveau_fence base;
+       int refcount;
+
+       struct nouveau_fence *next;
+
+       uint32_t sequence;
+       int emitted;
+       int signalled;
+};
+#define nouveau_fence(n) ((struct nouveau_fence_priv *)(n))
+
+extern int
+nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **);
+
+extern int
+nouveau_fence_ref(struct nouveau_fence *, struct nouveau_fence **);
+
+extern void
+nouveau_fence_del(struct nouveau_fence **);
+
+extern void
+nouveau_fence_emit(struct nouveau_fence *);
+
+extern int
+nouveau_fence_wait(struct nouveau_fence **);
+
+extern void
+nouveau_fence_flush(struct nouveau_channel *);
+
+struct nouveau_pushbuf {
+       struct nouveau_channel *channel;
+       unsigned remaining;
+       uint32_t *cur;
+};
+
+struct nouveau_pushbuf_priv {
+       struct nouveau_pushbuf base;
+       struct nouveau_pushbuf *next;
+
+       struct nouveau_resource *res;
+       struct nouveau_fence *fence;
+};
+#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+
+extern int
+nouveau_pushbuf_init(struct nouveau_channel *);
+
+extern int
+nouveau_pushbuf_flush(struct nouveau_channel *);
+
 struct nouveau_channel_priv {
        struct nouveau_channel base;
 
@@ -95,6 +151,14 @@ struct nouveau_channel_priv {
        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;
+
+       struct nouveau_resource *pb_heap;
+       struct nouveau_pushbuf *pb_head;
+       struct nouveau_pushbuf *pb_tail;
 };
 #define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
 
@@ -148,6 +212,8 @@ nouveau_notifier_wait_status(struct nouveau_notifier *, int id, int status,
 struct nouveau_bo_priv {
        struct nouveau_bo base;
 
+       struct nouveau_fence *fence;
+
        struct drm_nouveau_mem_alloc drm;
        void *map;
 
@@ -203,4 +269,14 @@ nouveau_bo_emit_reloc(struct nouveau_channel *chan, void *ptr,
 extern void
 nouveau_bo_validate(struct nouveau_channel *);
 
+extern int
+nouveau_resource_init(struct nouveau_resource **heap, int size);
+
+extern int
+nouveau_resource_alloc(struct nouveau_resource *heap, int size, void *priv,
+                      struct nouveau_resource **);
+
+extern void
+nouveau_resource_free(struct nouveau_resource **);
+
 #endif
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c
new file mode 100644 (file)
index 0000000..842b38f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+#include "nouveau_local.h"
+
+int
+nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **fence)
+{
+       struct nouveau_fence_priv *nvfence;
+
+       if (!chan || !fence || *fence)
+               return -EINVAL;
+       
+       nvfence = calloc(1, sizeof(struct nouveau_fence_priv));
+       if (!nvfence)
+               return -ENOMEM;
+       nvfence->base.channel = chan;
+       nvfence->refcount = 1;
+
+       *fence = &nvfence->base;
+       return 0;
+}
+
+int
+nouveau_fence_ref(struct nouveau_fence *ref, struct nouveau_fence **fence)
+{
+       struct nouveau_fence_priv *nvfence;
+
+       if (!ref || !fence || *fence)
+               return -EINVAL;
+       nvfence = nouveau_fence(ref);
+       nvfence->refcount++;
+
+       *fence = &nvfence->base;
+       return 0;
+}
+
+void
+nouveau_fence_del(struct nouveau_fence **fence)
+{
+       struct nouveau_fence_priv *nvfence;
+
+       if (!fence || !*fence)
+               return;
+       nvfence = nouveau_fence(*fence);
+       *fence = NULL;
+
+       if (--nvfence->refcount <= 0) {
+               if (nvfence->emitted && !nvfence->signalled)
+                       nouveau_fence_wait((void *)&nvfence);
+               free(nvfence);
+       }
+}
+
+void
+nouveau_fence_emit(struct nouveau_fence *fence)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(fence->channel);
+       struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
+
+       nvfence->emitted = 1;
+       nvfence->sequence = ++nvchan->fence_sequence;
+       if (nvfence->sequence == 0xffffffff)
+               NOUVEAU_ERR("AII wrap unhandled\n");
+
+       BEGIN_RING_CH(&nvchan->base, nvchan->subchannel[0].grobj, 0x50, 1);
+       OUT_RING_CH  (&nvchan->base, nvfence->sequence);
+
+       if (nvchan->fence_tail) {
+               nouveau_fence(nvchan->fence_tail)->next = fence;
+       } else {
+               nvchan->fence_head = fence;
+       }
+       nvchan->fence_tail = fence;
+}
+
+void
+nouveau_fence_flush(struct nouveau_channel *chan)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+       struct nouveau_fence_priv *nvfence = nouveau_fence(nvchan->fence_head);
+       uint32_t sequence = *nvchan->ref_cnt;
+
+       while (nvchan->fence_head && nvfence->sequence <= sequence) {
+               nvfence->signalled = 1;
+
+               nvchan->fence_head = nvfence->next;
+               if (nvchan->fence_head == NULL)
+                       nvchan->fence_tail = NULL;
+               nvfence = nouveau_fence(nvchan->fence_head);
+       }
+}
+
+int
+nouveau_fence_wait(struct nouveau_fence **fence)
+{
+       struct nouveau_fence_priv *nvfence;
+       
+       if (!fence || !*fence)
+               return -EINVAL;
+       nvfence = nouveau_fence(*fence);
+
+       if (nvfence->emitted) {
+               while (!nvfence->signalled)
+                       nouveau_fence_flush(nvfence->base.channel);
+       }
+       nouveau_fence_del(fence);
+
+       return 0;
+}
+
index 4ada5d014bfd4aec72c2801b7a4cc39fe7a32788..2534a8ea6f96863364f2302946f17e238fcd97a0 100644 (file)
 
 /* Push buffer access macros */
 #define BEGIN_RING(obj,mthd,size) do {                                         \
-       BEGIN_RING_CH(nv->channel, nv->obj, (mthd), (size));                   \
+       nv->pushbuf = nouveau_pipe_dma_beginp(nv->obj, (mthd), (size));        \
 } while(0)
 
 #define OUT_RING(data) do {                                                    \
-       OUT_RING_CH(nv->channel, (data));                                      \
+       (*nv->pushbuf++) = (data);                                             \
 } while(0)
 
 #define OUT_RINGp(src,size) do {                                               \
-       OUT_RINGp_CH(nv->channel, (src), (size));                              \
+       memcpy(nv->pushbuf, (src), (size)<<2);                                 \
+       nv->pushbuf += (size);                                                 \
 } while(0)
 
 #define OUT_RINGf(data) do {                                                   \
        OUT_RING(c.u);                                                         \
 } while(0)
 
-#define WAIT_RING(size) do {                                                   \
-       WAIT_RING_CH(nv->channel, (size));                                     \
-} while(0)
-
 #define FIRE_RING() do {                                                       \
-       FIRE_RING_CH(nv->channel);                                             \
+       nouveau_pipe_dma_kickoff(nv->channel);                                 \
 } while(0)
 
 #define OUT_RELOC(bo,data,flags,vor,tor) do {                                  \
-       struct nouveau_channel_priv *chan = nouveau_channel(nv->channel);      \
-       nouveau_bo_emit_reloc(nv->channel, &chan->pushbuf[chan->dma.cur],      \
-                             (void*)(bo), (data), (flags), (vor), (tor));     \
+       nouveau_bo_emit_reloc(nv->channel, nv->pushbuf, (void*)(bo), (data),   \
+                             (flags), (vor), (tor));                          \
        OUT_RING(0);                                                           \
 } while(0)
 
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c
new file mode 100644 (file)
index 0000000..75d41d6
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_dma.h"
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *chan)
+{
+       struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+
+       if (!nvchan)
+               return -EINVAL;
+
+       /* Everything except first 4KiB of the push buffer is managed by us */
+       if (nouveau_resource_init(&nvchan->pb_heap,
+                                 nvchan->drm.cmdbuf_size - 4096))
+               return -EINVAL;
+
+       /* Shrink master ring to 4KiB */
+       assert(nvchan->dma.cur <= (4096/4));
+       nvchan->dma.max = (4096 / 4) - 2;
+       nvchan->dma.free = nvchan->dma.max - nvchan->dma.cur;
+
+       return 0;
+}
+
+/* This would be our TTM "superioctl" */
+int
+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;
+
+       if (!nvpb)
+               goto out_realloc;
+
+       if (nvpb->base.remaining == nvpb->res->size / 4)
+               return 0;
+
+       ret = nouveau_fence_new(chan, &nvpb->fence);
+       if (ret)
+               return ret;
+
+       /* Validate buffers */
+       nouveau_bo_validate(chan);
+
+       /* Apply relocations */
+       if (nvchan->num_relocs) {               
+               for (i = 0; i < nvchan->num_relocs; i++) {
+                       struct nouveau_bo_reloc *r = &nvchan->relocs[i];
+                       uint32_t push;
+
+                       if (r->flags & NOUVEAU_BO_LOW) {
+                               push = r->bo->base.offset + r->data;
+                       } else
+                       if (r->flags & NOUVEAU_BO_HIGH) {
+                               push = (r->bo->base.offset + r->data) >> 32;
+                       } else {
+                               push = r->data;
+                       }
+
+                       if (r->flags & NOUVEAU_BO_OR) {
+                               if (r->bo->base.flags & NOUVEAU_BO_VRAM)
+                                       push |= r->vor;
+                               else
+                                       push |= r->tor;
+                       }
+
+                       *r->ptr = push;
+               }
+
+               nvchan->num_relocs = 0;
+       }
+
+       /* Emit JMP to indirect pushbuf */
+       if (nvchan->dma.free < 1)
+               WAIT_RING_CH(chan, 1);
+       nvchan->dma.free -= 1;
+       OUT_RING_CH(chan, 0x20000000 | (nvpb->res->start + 4096));
+
+       /* Add JMP back to master pushbuf from indirect pushbuf */
+       (*nvpb->base.cur++) =
+               0x20000000 | ((nvchan->dma.cur << 2) + nvchan->dma.base);
+
+       /* Fence */
+       nouveau_fence_emit(nvpb->fence);
+
+       /* Kickoff */
+       FIRE_RING_CH(chan);
+
+       /* Allocate space for next push buffer */
+out_realloc:
+       nvpb = calloc(1, sizeof(struct nouveau_pushbuf_priv));
+       if (!nvpb)
+               return -ENOMEM;
+
+       if (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, NULL, &nvpb->res)) {
+               struct nouveau_pushbuf_priv *e;
+               int nr = 0;
+
+               /* Update fences */
+               nouveau_fence_flush(chan);
+
+               /* Free any push buffers that have already been executed */
+               e = nouveau_pushbuf(nvchan->pb_head);
+               while (e && e->fence) {
+                       if (!e->fence || !nouveau_fence(e->fence)->signalled)
+                               break;
+                       nouveau_fence_del(&e->fence);
+                       nouveau_resource_free(&e->res);
+                       nr++;
+
+                       nvchan->pb_head = e->next;
+                       if (nvchan->pb_head == NULL)
+                               nvchan->pb_tail = NULL;
+                       free(e);
+                       e = nouveau_pushbuf(nvchan->pb_head);
+               }
+
+               /* We didn't free any buffers above.  As a last resort, busy
+                * wait on the oldest buffer becoming available.
+                */
+               if (!nr) {
+                       e = nouveau_pushbuf(nvchan->pb_head);
+                       nouveau_fence_wait(&e->fence);
+                       nouveau_resource_free(&e->res);
+
+                       nvchan->pb_head = e->next;
+                       if (nvchan->pb_head == NULL)
+                               nvchan->pb_tail = NULL;
+                       free(e);
+               }
+
+               if (nouveau_resource_alloc(nvchan->pb_heap, 0x2000, nvpb,
+                                          &nvpb->res))
+                       assert(0);
+       }
+
+       nvpb->base.channel = chan;
+       nvpb->base.remaining = nvpb->res->size / 4;
+       nvpb->base.cur = &nvchan->pushbuf[(nvpb->res->start + 4096)/4];
+
+       if (nvchan->pb_tail) {
+               nouveau_pushbuf(nvchan->pb_tail)->next = & nvpb->base;
+       } else {
+               nvchan->pb_head = &nvpb->base;
+       }
+       nvchan->pb_tail = &nvpb->base;
+
+       return 0;
+}
+
index 6ef81ccb86ab25d7c7ca11f8eb9530c64849d174..77d9e710dbe7d4d55eee6437bb83f3a62bc5625b 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "pipe/nouveau/nouveau_winsys.h"
 
-static int
+int
 nouveau_resource_init(struct nouveau_resource **heap, int size)
 {
        struct nouveau_resource *r;
@@ -20,7 +20,7 @@ nouveau_resource_init(struct nouveau_resource **heap, int size)
        return 0;
 }
 
-static int
+int
 nouveau_resource_alloc(struct nouveau_resource *heap, int size, void *priv,
                       struct nouveau_resource **res)
 {
@@ -58,7 +58,7 @@ nouveau_resource_alloc(struct nouveau_resource *heap, int size, void *priv,
        return 1;
 }
 
-static void
+void
 nouveau_resource_free(struct nouveau_resource **res)
 {
        struct nouveau_resource *r;
@@ -108,25 +108,31 @@ nouveau_pipe_grobj_alloc(struct nouveau_winsys *nvws, int grclass,
                                   grclass, grobj);
 }
 
-static uint32_t *
+uint32_t *
 nouveau_pipe_dma_beginp(struct nouveau_grobj *grobj, int mthd, int size)
 {
-       struct nouveau_channel_priv *chan = nouveau_channel(grobj->channel);
+       struct nouveau_channel_priv *nvchan = nouveau_channel(grobj->channel);
        uint32_t *pushbuf;
 
-       BEGIN_RING_CH(&chan->base, grobj, mthd, size);
-       pushbuf = &chan->pushbuf[chan->dma.cur];
-       chan->dma.cur += size;
-#ifdef NOUVEAU_DMA_DEBUG
-       chan->dma.push_free -= size;
-#endif
+       if (!nvchan->pb_tail || nvchan->pb_tail->remaining < (size + 1))
+               nouveau_pushbuf_flush(grobj->channel);
+
+       if (grobj->bound == NOUVEAU_GROBJ_UNBOUND)
+               nouveau_dma_subc_bind(grobj);
+       nvchan->subchannel[grobj->subc].seq = nvchan->subc_sequence++;
+
+       pushbuf = nvchan->pb_tail->cur;
+       nvchan->pb_tail->cur += (size + 1);
+       nvchan->pb_tail->remaining -= (size + 1);
+
+       (*pushbuf++) = ((grobj->subc << 13) | (size << 18) | mthd);
        return pushbuf;
 }
 
-static void
-nouveau_pipe_dma_kickoff(struct nouveau_channel *userchan)
+void
+nouveau_pipe_dma_kickoff(struct nouveau_channel *chan)
 {
-       FIRE_RING_CH(userchan);
+       nouveau_pushbuf_flush(chan);
 }
 
 static int
diff --git a/src/mesa/pipe/nouveau/nouveau_resource.h b/src/mesa/pipe/nouveau/nouveau_resource.h
new file mode 100644 (file)
index 0000000..1af7961
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_RESOURCE_H__
+#define __NOUVEAU_RESOURCE_H__
+
+struct nouveau_resource {
+       struct nouveau_resource *prev;
+       struct nouveau_resource *next;
+
+       int in_use;
+       void *priv;
+
+       unsigned int start;
+       unsigned int size;
+};
+
+#endif
index a274e23af5f20af1c0f3ffeac2050ffa0f4402ae..ce1744c2eecd76f10410940bfd93183c9cefaa84 100644 (file)
 #include "pipe/nouveau/nouveau_class.h"
 #include "pipe/nouveau/nouveau_grobj.h"
 #include "pipe/nouveau/nouveau_notifier.h"
-
-struct nouveau_resource {
-       struct nouveau_resource *prev;
-       struct nouveau_resource *next;
-
-       boolean in_use;
-       void *priv;
-
-       uint start;
-       uint size;
-};
+#include "pipe/nouveau/nouveau_resource.h"
 
 struct nouveau_winsys {
        struct nouveau_context *nv;