summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Skeggs <skeggsb@gmail.com>2007-12-09 20:38:08 +1100
committerBen Skeggs <skeggsb@gmail.com>2007-12-09 20:38:08 +1100
commit62bbf8db873716c56ca089dbba59d1d3980563b5 (patch)
treecc06a01ad33039183fd616ee2f0e3e1072883943 /src
parentb8965bee404cb36ccd97ac089fbd3ffc63268080 (diff)
nouveau: use "indirect" push buffers
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/Makefile2
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c1
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h4
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c45
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h76
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c135
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h18
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c177
-rw-r--r--src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c34
-rw-r--r--src/mesa/pipe/nouveau/nouveau_resource.h37
-rw-r--r--src/mesa/pipe/nouveau/nouveau_winsys.h12
11 files changed, 474 insertions, 67 deletions
diff --git a/src/mesa/drivers/dri/nouveau_winsys/Makefile b/src/mesa/drivers/dri/nouveau_winsys/Makefile
index 9b8a33b725..fe9a9668b1 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/Makefile
+++ b/src/mesa/drivers/dri/nouveau_winsys/Makefile
@@ -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 \
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
index ef41020b72..64136775da 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_channel.c
@@ -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;
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
index 7033ff7ae9..cd59b7cc43 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_context.h
@@ -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
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
index 6e123c4473..6e32d739ab 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_dma.c
@@ -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;
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
index df98890f8e..4f467406dd 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_drmif.h
@@ -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
index 0000000000..842b38f913
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_fence.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
index 4ada5d014b..2534a8ea6f 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_local.h
@@ -26,15 +26,16 @@
/* 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 { \
@@ -43,18 +44,13 @@
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
index 0000000000..75d41d6c14
--- /dev/null
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_pushbuf.c
@@ -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;
+}
+
diff --git a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
index 6ef81ccb86..77d9e710db 100644
--- a/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
+++ b/src/mesa/drivers/dri/nouveau_winsys/nouveau_winsys.c
@@ -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
index 0000000000..1af7961d30
--- /dev/null
+++ b/src/mesa/pipe/nouveau/nouveau_resource.h
@@ -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
diff --git a/src/mesa/pipe/nouveau/nouveau_winsys.h b/src/mesa/pipe/nouveau/nouveau_winsys.h
index a274e23af5..ce1744c2ee 100644
--- a/src/mesa/pipe/nouveau/nouveau_winsys.h
+++ b/src/mesa/pipe/nouveau/nouveau_winsys.h
@@ -10,17 +10,7 @@
#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;