[PATCH 1/7] nv50: support conditional rendering

Christoph Bumiller e0425955 at student.tuwien.ac.at
Tue Jan 5 05:22:06 PST 2010


On get_query_result with wait == TRUE, we now flush
and then busy wait for the result to be written.
---
 src/gallium/drivers/nv50/nv50_query.c  |   94 +++++++++++++++++++++++---------
 src/gallium/drivers/nv50/nv50_screen.c |    6 ++-
 src/gallium/drivers/nv50/nv50_screen.h |    1 +
 3 files changed, 75 insertions(+), 26 deletions(-)

diff --git a/src/gallium/drivers/nv50/nv50_query.c b/src/gallium/drivers/nv50/nv50_query.c
index 5d9e182..e320cc6 100644
--- a/src/gallium/drivers/nv50/nv50_query.c
+++ b/src/gallium/drivers/nv50/nv50_query.c
@@ -27,6 +27,7 @@
 
 struct nv50_query {
 	struct nouveau_bo *bo;
+	int slot;
 	unsigned type;
 	boolean ready;
 	uint64_t result;
@@ -41,19 +42,23 @@ nv50_query(struct pipe_query *pipe)
 static struct pipe_query *
 nv50_query_create(struct pipe_context *pipe, unsigned type)
 {
-	struct nouveau_device *dev = nouveau_screen(pipe->screen)->device;
-	struct nv50_query *q = CALLOC_STRUCT(nv50_query);
-	int ret;
+	struct nv50_screen *screen = nv50_context(pipe)->screen;
+	struct nv50_query *q;
+	int slot;
 
-	assert (q->type == PIPE_QUERY_OCCLUSION_COUNTER);
-	q->type = type;
+	assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
 
-	ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP, 256,
-			     16, &q->bo);
-	if (ret) {
-		FREE(q);
+	slot = ffs(screen->notifier_slots) - 1;
+	if (slot < 0)
 		return NULL;
-	}
+
+	q = CALLOC_STRUCT(nv50_query);
+	if (!q)
+		return NULL;
+
+	screen->notifier_slots |= 1 << slot;
+	q->slot = slot;
+	q->type = type;
 
 	return (struct pipe_query *)q;
 }
@@ -61,10 +66,11 @@ nv50_query_create(struct pipe_context *pipe, unsigned type)
 static void
 nv50_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
 {
+	struct nv50_screen *screen = nv50_context(pipe)->screen;
 	struct nv50_query *q = nv50_query(pq);
 
 	if (q) {
-		nouveau_bo_ref(NULL, &q->bo);
+		screen->notifier_slots &= ~(1 << q->slot);
 		FREE(q);
 	}
 }
@@ -72,11 +78,14 @@ nv50_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
 static void
 nv50_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
 {
-	struct nv50_context *nv50 = nv50_context(pipe);
-	struct nouveau_channel *chan = nv50->screen->base.channel;
-	struct nouveau_grobj *tesla = nv50->screen->tesla;
+	struct nv50_screen *screen = nv50_context(pipe)->screen;
+	struct nouveau_channel *chan = screen->base.channel;
+	struct nouveau_grobj *tesla = screen->tesla;
 	struct nv50_query *q = nv50_query(pq);
 
+	nouveau_notifier_wr32(screen->sync, q->slot * 4 + 0, 0xff);
+	nouveau_notifier_wr32(screen->sync, q->slot * 4 + 1, 0xff);
+
 	BEGIN_RING(chan, tesla, NV50TCL_SAMPLECNT_RESET, 1);
 	OUT_RING  (chan, 1);
 	BEGIN_RING(chan, tesla, NV50TCL_SAMPLECNT_ENABLE, 1);
@@ -93,36 +102,70 @@ 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);
 
-	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);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, q->slot * 16);
 	OUT_RING  (chan, 0x00000000);
 	OUT_RING  (chan, 0x0100f002);
-	FIRE_RING (chan);
+
+	BEGIN_RING(chan, tesla, NV50TCL_SAMPLECNT_ENABLE, 1);
+	OUT_RING  (chan, 0);
 }
 
 static boolean
 nv50_query_result(struct pipe_context *pipe, struct pipe_query *pq,
 		  boolean wait, uint64_t *result)
 {
+	struct nv50_screen *screen = nv50_context(pipe)->screen;
+	struct nouveau_channel *chan = screen->base.channel;
 	struct nv50_query *q = nv50_query(pq);
-	int ret;
 
 	if (!q->ready) {
-		ret = nouveau_bo_map(q->bo, NOUVEAU_BO_RD |
-				     wait ? 0 : NOUVEAU_BO_NOWAIT);
-		if (ret)
-			return false;
-		q->result = ((uint32_t *)q->bo->map)[1];
+		int pos = q->slot * 16;
+
+		if (nouveau_notifier_rd32(screen->sync, pos)) {
+			if (!wait)
+				return false;
+			FIRE_RING(chan);
+		}
+		while (nouveau_notifier_rd32(screen->sync, pos));
+
+		q->result = nouveau_notifier_rd32(screen->sync, pos + 1);
 		q->ready = TRUE;
-		nouveau_bo_unmap(q->bo);
 	}
 
 	*result = q->result;
 	return q->ready;
 }
 
+static void
+nv50_render_condition(struct pipe_context *pipe,
+		      struct pipe_query *pq, uint mode)
+{
+	struct nv50_screen *screen = nv50_context(pipe)->screen;
+	struct nouveau_channel *chan = screen->base.channel;
+	struct nouveau_grobj *tesla = screen->tesla;
+	struct nv50_query *q = nv50_query(pq);
+
+	if (q) {
+		if (mode == PIPE_RENDER_COND_WAIT ||
+		    mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
+			BEGIN_RING(chan, tesla, 0x60, 3);
+			OUT_RING  (chan, screen->sync->handle);
+			OUT_RING  (chan, q->slot * 16);
+			OUT_RING  (chan, 0);
+		}
+
+		BEGIN_RING(chan, tesla, NV50TCL_COND_ADDRESS_HIGH, 3);
+		OUT_RING  (chan, 0);
+		OUT_RING  (chan, q->slot * 16);
+		OUT_RING  (chan, NV50TCL_COND_MODE_RES);
+	} else {
+		BEGIN_RING(chan, tesla, NV50TCL_COND_MODE, 1);
+		OUT_RING  (chan, NV50TCL_COND_MODE_ALWAYS);
+	}
+}
+
 void
 nv50_init_query_functions(struct nv50_context *nv50)
 {
@@ -131,4 +174,5 @@ nv50_init_query_functions(struct nv50_context *nv50)
 	nv50->pipe.begin_query = nv50_query_begin;
 	nv50->pipe.end_query = nv50_query_end;
 	nv50->pipe.get_query_result = nv50_query_result;
+	nv50->pipe.render_condition = nv50_render_condition;
 }
diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c
index 7e039ea..d7bc3cd 100644
--- a/src/gallium/drivers/nv50/nv50_screen.c
+++ b/src/gallium/drivers/nv50/nv50_screen.c
@@ -276,12 +276,13 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
 	BIND_RING(chan, screen->tesla, 3);
 
 	/* Sync notifier */
-	ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync);
+	ret = nouveau_notifier_alloc(chan, 0xbeef0301, 16, &screen->sync);
 	if (ret) {
 		NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
 		nv50_screen_destroy(pscreen);
 		return NULL;
 	}
+	screen->notifier_slots = 0x3; /* mark first 2 slots as reserved */
 
 	/* Static M2MF init */
 	so = so_new(32, 0);
@@ -322,6 +323,9 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
 				     NV50TCL_DMA_COLOR__SIZE);
 	for (i = 0; i < NV50TCL_DMA_COLOR__SIZE; i++)
 		so_data(so, chan->vram->handle);
+	so_method(so, screen->tesla, NV50TCL_DMA_QUERY, 1);
+	so_data  (so, screen->sync->handle);
+
 	so_method(so, screen->tesla, NV50TCL_RT_CONTROL, 1);
 	so_data  (so, 1);
 
diff --git a/src/gallium/drivers/nv50/nv50_screen.h b/src/gallium/drivers/nv50/nv50_screen.h
index 61e24a5..7a66e11 100644
--- a/src/gallium/drivers/nv50/nv50_screen.h
+++ b/src/gallium/drivers/nv50/nv50_screen.h
@@ -14,6 +14,7 @@ struct nv50_screen {
 	struct nouveau_grobj *eng2d;
 	struct nouveau_grobj *m2mf;
 	struct nouveau_notifier *sync;
+	uint32_t notifier_slots;
 
 	struct nouveau_bo *constbuf_misc[1];
 	struct nouveau_bo *constbuf_parm[2];
-- 
1.6.4.4


--------------060703070100030003060000
Content-Type: text/plain;
 name="0001-nouveau-add-nouveau_notifier_rd32-wr32.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="0001-nouveau-add-nouveau_notifier_rd32-wr32.patch"



More information about the Nouveau mailing list