Mesa (master): nvc0: implement transform feedback state

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Sun Jan 30 00:27:13 UTC 2011


Module: Mesa
Branch: master
Commit: f8a7a0b6f30ff38b2743860cbc4caeab102c2c29
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f8a7a0b6f30ff38b2743860cbc4caeab102c2c29

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Sun Jan 30 01:24:56 2011 +0100

nvc0: implement transform feedback state

---

 src/gallium/drivers/nvc0/nvc0_3d.xml.h         |   20 ++++++-
 src/gallium/drivers/nvc0/nvc0_context.h        |    9 +++
 src/gallium/drivers/nvc0/nvc0_shader_state.c   |   58 ++++++++++++++++++-
 src/gallium/drivers/nvc0/nvc0_state.c          |   73 ++++++++++++++++++++++++
 src/gallium/drivers/nvc0/nvc0_state_validate.c |    3 +-
 src/gallium/drivers/nvc0/nvc0_stateobj.h       |    8 +-
 src/gallium/drivers/nvc0/nvc0_vbo.c            |   51 +----------------
 7 files changed, 163 insertions(+), 59 deletions(-)

diff --git a/src/gallium/drivers/nvc0/nvc0_3d.xml.h b/src/gallium/drivers/nvc0/nvc0_3d.xml.h
index af6526c..1a34313 100644
--- a/src/gallium/drivers/nvc0/nvc0_3d.xml.h
+++ b/src/gallium/drivers/nvc0/nvc0_3d.xml.h
@@ -84,6 +84,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define NVC0_3D_EARLY_FRAGMENT_TESTS				0x00000210
 
+#define NVC0_3D_MEM_BARRIER					0x0000021c
+#define NVC0_3D_MEM_BARRIER_UNK0				0x00000001
+#define NVC0_3D_MEM_BARRIER_UNK1				0x00000002
+#define NVC0_3D_MEM_BARRIER_UNK2				0x00000004
+#define NVC0_3D_MEM_BARRIER_UNK4				0x00000010
+#define NVC0_3D_MEM_BARRIER_UNK8				0x00000100
+#define NVC0_3D_MEM_BARRIER_UNK12				0x00001000
+
 #define NVC0_3D_TESS_MODE					0x00000320
 #define NVC0_3D_TESS_MODE_PRIM__MASK				0x0000000f
 #define NVC0_3D_TESS_MODE_PRIM__SHIFT				0
@@ -122,11 +130,17 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define NVC0_3D_TFB_PRIMITIVE_ID(i0)			       (0x00000390 + 0x20*(i0))
 
-#define NVC0_3D_TFB_UNK0700(i0)				       (0x00000700 + 0x10*(i0))
+#define NVC0_3D_TFB_UNK07X0(i0)				       (0x00000700 + 0x10*(i0))
+#define NVC0_3D_TFB_UNK07X0__ESIZE				0x00000010
+#define NVC0_3D_TFB_UNK07X0__LEN				0x00000004
 
 #define NVC0_3D_TFB_VARYING_COUNT(i0)			       (0x00000704 + 0x10*(i0))
+#define NVC0_3D_TFB_VARYING_COUNT__ESIZE			0x00000010
+#define NVC0_3D_TFB_VARYING_COUNT__LEN				0x00000004
 
 #define NVC0_3D_TFB_BUFFER_STRIDE(i0)			       (0x00000708 + 0x10*(i0))
+#define NVC0_3D_TFB_BUFFER_STRIDE__ESIZE			0x00000010
+#define NVC0_3D_TFB_BUFFER_STRIDE__LEN				0x00000004
 
 #define NVC0_3D_TFB_ENABLE					0x00000744
 
@@ -1157,9 +1171,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define NVC0_3D_VERT_COLOR_CLAMP_EN				0x00002600
 
-#define NVC0_3D_TFB_VARYING_LOCS(i0)			       (0x00002800 + 0x4*(i0))
+#define NVC0_3D_TFB_VARYING_LOCS(i0, i1)		       (0x00002800 + 0x80*(i0) + 0x4*(i1))
 #define NVC0_3D_TFB_VARYING_LOCS__ESIZE				0x00000004
-#define NVC0_3D_TFB_VARYING_LOCS__LEN				0x00000080
+#define NVC0_3D_TFB_VARYING_LOCS__LEN				0x00000020
 
 #define NVC0_3D_COLOR_MASK_BROADCAST				0x00003808
 
diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h
index 9411798..a082ad4 100644
--- a/src/gallium/drivers/nvc0/nvc0_context.h
+++ b/src/gallium/drivers/nvc0/nvc0_context.h
@@ -54,6 +54,8 @@
 #define NVC0_NEW_CONSTBUF     (1 << 18)
 #define NVC0_NEW_TEXTURES     (1 << 19)
 #define NVC0_NEW_SAMPLERS     (1 << 20)
+#define NVC0_NEW_TFB          (1 << 21)
+#define NVC0_NEW_TFB_BUFFERS  (1 << 22)
 
 #define NVC0_BUFCTX_CONSTANT 0
 #define NVC0_BUFCTX_FRAME    1
@@ -123,6 +125,11 @@ struct nvc0_context {
    boolean vbo_dirty;
    boolean vbo_push_hint;
 
+   struct nvc0_transform_feedback_state *tfb;
+   struct pipe_resource *tfbbuf[4];
+   unsigned num_tfbbufs;
+   unsigned tfb_offset[4];
+
    struct draw_context *draw;
 };
 
@@ -177,6 +184,8 @@ void nvc0_tevlprog_validate(struct nvc0_context *);
 void nvc0_gmtyprog_validate(struct nvc0_context *);
 void nvc0_fragprog_validate(struct nvc0_context *);
 
+void nvc0_tfb_validate(struct nvc0_context *);
+
 /* nvc0_state.c */
 extern void nvc0_init_state_functions(struct nvc0_context *);
 
diff --git a/src/gallium/drivers/nvc0/nvc0_shader_state.c b/src/gallium/drivers/nvc0/nvc0_shader_state.c
index 981b548..6336417 100644
--- a/src/gallium/drivers/nvc0/nvc0_shader_state.c
+++ b/src/gallium/drivers/nvc0/nvc0_shader_state.c
@@ -55,7 +55,7 @@ nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
                          prog->code_base + NVC0_SHADER_HEADER_SIZE,
                          prog->code_size, prog->code);
 
-   BEGIN_RING(nvc0->screen->base.channel, RING_3D_(0x021c), 1);
+   BEGIN_RING(nvc0->screen->base.channel, RING_3D(MEM_BARRIER), 1);
    OUT_RING  (nvc0->screen->base.channel, 0x1111);
 
    return TRUE;
@@ -178,3 +178,59 @@ nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1);
    OUT_RING  (chan, gp->max_gpr);   
 }
+
+/* It's *is* kind of shader related. We need to inspect the program
+ * to get the output locations right.
+ */
+void
+nvc0_tfb_validate(struct nvc0_context *nvc0)
+{
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
+   struct nvc0_program *vp;
+   struct nvc0_transform_feedback_state *tfb = nvc0->tfb;
+   int b;
+
+   BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
+   if (!tfb) {
+      OUT_RING(chan, 0);
+      return;
+   }
+   OUT_RING(chan, 1);
+
+   vp = nvc0->vertprog ? nvc0->vertprog : nvc0->gmtyprog;
+
+   for (b = 0; b < nvc0->num_tfbbufs; ++b) {
+      uint8_t idx, var[128];
+      int i, n;
+      struct nvc0_resource *buf = nvc0_resource(nvc0->tfbbuf[b]);
+
+      BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5);
+      OUT_RING  (chan, 1);
+      OUT_RESRCh(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
+      OUT_RESRCl(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
+      OUT_RING  (chan, buf->base.width0 - nvc0->tfb_offset[b]);
+      OUT_RING  (chan, 0); /* TFB_PRIMITIVE_ID <- offset ? */
+
+      if (!(nvc0->dirty & NVC0_NEW_TFB))
+         continue;
+
+      BEGIN_RING(chan, RING_3D(TFB_UNK07X0(b)), 3);
+      OUT_RING  (chan, 0);
+      OUT_RING  (chan, tfb->varying_count[b]);
+      OUT_RING  (chan, tfb->stride[b]);
+
+      n = b ? tfb->varying_count[b - 1] : 0;
+      i = 0;
+      for (; i < tfb->varying_count[b]; ++i) {
+         idx = tfb->varying_index[n + i];
+         var[i] = vp->vp.out_pos[idx >> 2] + (idx & 3);
+      }
+      for (; i & 3; ++i)
+         var[i] = 0;
+
+      BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4);
+      OUT_RINGp (chan, var, i / 4);
+   }
+   for (; b < 4; ++b)
+      IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0);
+}
diff --git a/src/gallium/drivers/nvc0/nvc0_state.c b/src/gallium/drivers/nvc0/nvc0_state.c
index c08f369..f6a7f82 100644
--- a/src/gallium/drivers/nvc0/nvc0_state.c
+++ b/src/gallium/drivers/nvc0/nvc0_state.c
@@ -808,6 +808,74 @@ nvc0_vertex_state_bind(struct pipe_context *pipe, void *hwcso)
     nvc0->dirty |= NVC0_NEW_VERTEX;
 }
 
+static void *
+nvc0_tfb_state_create(struct pipe_context *pipe,
+                      const struct pipe_stream_output_state *pso)
+{
+   struct nvc0_transform_feedback_state *so;
+   int n = 0;
+   int i, c, b;
+
+   so = MALLOC(sizeof(*so) + pso->num_outputs * 4 * sizeof(uint8_t));
+   if (!so)
+      return NULL;
+
+   for (b = 0; b < 4; ++b) {
+      for (i = 0; i < pso->num_outputs; ++i) {
+         if (pso->output_buffer[i] != b)
+            continue;
+         for (c = 0; c < 4; ++c) {
+            if (!(pso->register_mask[i] & (1 << c)))
+               continue;
+            so->varying_count[b]++;
+            so->varying_index[n++] = (pso->register_index[i] << 2) | c;
+         }
+      }
+      so->stride[b] = so->varying_count[b] * 4;
+   }
+   if (pso->stride)
+      so->stride[0] = pso->stride;
+
+   return so;
+}
+
+static void
+nvc0_tfb_state_delete(struct pipe_context *pipe, void *hwcso)
+{
+   FREE(hwcso);
+}
+
+static void
+nvc0_tfb_state_bind(struct pipe_context *pipe, void *hwcso)
+{
+   nvc0_context(pipe)->tfb = hwcso;
+   nvc0_context(pipe)->dirty |= NVC0_NEW_TFB;
+}
+
+static void
+nvc0_set_transform_feedback_buffers(struct pipe_context *pipe,
+                                    struct pipe_resource **buffers,
+                                    int *offsets,
+                                    int num_buffers)
+{
+   struct nvc0_context *nvc0 = nvc0_context(pipe);
+   int i;
+
+   assert(num_buffers >= 0 && num_buffers <= 4); /* why signed ? */
+
+   for (i = 0; i < num_buffers; ++i) {
+       assert(offsets[i] >= 0);
+       nvc0->tfb_offset[i] = offsets[i];
+       pipe_resource_reference(&nvc0->tfbbuf[i], buffers[i]);
+   }
+   for (; i < nvc0->num_tfbbufs; ++i)
+      pipe_resource_reference(&nvc0->tfbbuf[i], NULL);
+
+   nvc0->num_tfbbufs = num_buffers;
+
+   nvc0->dirty |= NVC0_NEW_TFB_BUFFERS;
+}
+
 void
 nvc0_init_state_functions(struct nvc0_context *nvc0)
 {
@@ -861,5 +929,10 @@ nvc0_init_state_functions(struct nvc0_context *nvc0)
 
     nvc0->pipe.set_vertex_buffers = nvc0_set_vertex_buffers;
     nvc0->pipe.set_index_buffer = nvc0_set_index_buffer;
+
+    nvc0->pipe.create_stream_output_state = nvc0_tfb_state_create;
+    nvc0->pipe.delete_stream_output_state = nvc0_tfb_state_delete;
+    nvc0->pipe.bind_stream_output_state = nvc0_tfb_state_bind;
+    nvc0->pipe.set_stream_output_buffers = nvc0_set_transform_feedback_buffers;
 }
 
diff --git a/src/gallium/drivers/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nvc0/nvc0_state_validate.c
index 6419011..7406f6c 100644
--- a/src/gallium/drivers/nvc0/nvc0_state_validate.c
+++ b/src/gallium/drivers/nvc0/nvc0_state_validate.c
@@ -436,7 +436,8 @@ static struct state_validate {
     { nvc0_constbufs_validate,     NVC0_NEW_CONSTBUF },
     { nvc0_validate_textures,      NVC0_NEW_TEXTURES },
     { nvc0_validate_samplers,      NVC0_NEW_SAMPLERS },
-    { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS }
+    { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS },
+    { nvc0_tfb_validate,           NVC0_NEW_TFB | NVC0_NEW_TFB_BUFFERS }
 };
 #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
 
diff --git a/src/gallium/drivers/nvc0/nvc0_stateobj.h b/src/gallium/drivers/nvc0/nvc0_stateobj.h
index 6c8028a..752e927 100644
--- a/src/gallium/drivers/nvc0/nvc0_stateobj.h
+++ b/src/gallium/drivers/nvc0/nvc0_stateobj.h
@@ -69,14 +69,14 @@ struct nvc0_vertex_stateobj {
    uint32_t instance_bufs;
    unsigned vtx_size;
    unsigned vtx_per_packet_max;
-   struct nvc0_vertex_element element[1];
+   struct nvc0_vertex_element element[0];
 };
 
 /* will have to lookup index -> location qualifier from nvc0_program */
-struct nvc0_tfb_state {
-   uint8_t varying_count[4];
+struct nvc0_transform_feedback_state {
    uint32_t stride[4];
-   uint8_t varying_indices[1];
+   uint8_t varying_count[4];
+   uint8_t varying_index[0];
 };
 
 #endif
diff --git a/src/gallium/drivers/nvc0/nvc0_vbo.c b/src/gallium/drivers/nvc0/nvc0_vbo.c
index 486909c..aa5decf 100644
--- a/src/gallium/drivers/nvc0/nvc0_vbo.c
+++ b/src/gallium/drivers/nvc0/nvc0_vbo.c
@@ -54,7 +54,7 @@ nvc0_vertex_state_create(struct pipe_context *pipe,
     assert(num_elements);
 
     so = MALLOC(sizeof(*so) +
-                (num_elements - 1) * sizeof(struct nvc0_vertex_element));
+                num_elements * sizeof(struct nvc0_vertex_element));
     if (!so)
         return NULL;
     so->num_elements = num_elements;
@@ -351,55 +351,6 @@ nvc0_draw_vbo_flush_notify(struct nouveau_channel *chan)
    nvc0_bufctx_emit_relocs(nvc0);
 }
 
-#if 0
-static struct nouveau_bo *
-nvc0_tfb_setup(struct nvc0_context *nvc0)
-{
-   struct nouveau_channel *chan = nvc0->screen->base.channel;
-   struct nouveau_bo *tfb = NULL;
-   int ret, i;
-
-   ret = nouveau_bo_new(nvc0->screen->base.device,
-                        NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096, &tfb);
-   if (ret)
-      return NULL;
-
-   ret = nouveau_bo_map(tfb, NOUVEAU_BO_WR);
-   if (ret)
-      return NULL;
-   memset(tfb->map, 0xee, 8 * 4 * 3);
-   nouveau_bo_unmap(tfb);
-
-   BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
-   OUT_RING  (chan, 1);
-   BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(0)), 5);
-   OUT_RING  (chan, 1);
-   OUT_RELOCh(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
-   OUT_RELOCl(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
-   OUT_RING  (chan, tfb->size);
-   OUT_RING  (chan, 0); /* TFB_PRIMITIVE_ID(0) */
-   BEGIN_RING(chan, RING_3D(TFB_UNK0700(0)), 3);
-   OUT_RING  (chan, 0);
-   OUT_RING  (chan, 8); /* TFB_VARYING_COUNT(0) */
-   OUT_RING  (chan, 32); /* TFB_BUFFER_STRIDE(0) */
-   BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(0)), 2);
-   OUT_RING  (chan, 0x1f1e1d1c);
-   OUT_RING  (chan, 0xa3a2a1a0);
-   for (i = 1; i < 4; ++i) {
-      BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(i)), 1);
-      OUT_RING  (chan, 0);
-   }
-   BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
-   OUT_RING  (chan, 1);
-   BEGIN_RING(chan, RING_3D_(0x135c), 1);
-   OUT_RING  (chan, 1);
-   BEGIN_RING(chan, RING_3D_(0x135c), 1);
-   OUT_RING  (chan, 0);
-
-   return tfb;
-}
-#endif
-
 static void
 nvc0_draw_arrays(struct nvc0_context *nvc0,
                  unsigned mode, unsigned start, unsigned count,




More information about the mesa-commit mailing list