nvc0: implement transform feedback state
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sun, 30 Jan 2011 00:24:56 +0000 (01:24 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sun, 30 Jan 2011 00:25:41 +0000 (01:25 +0100)
src/gallium/drivers/nvc0/nvc0_3d.xml.h
src/gallium/drivers/nvc0/nvc0_context.h
src/gallium/drivers/nvc0/nvc0_shader_state.c
src/gallium/drivers/nvc0/nvc0_state.c
src/gallium/drivers/nvc0/nvc0_state_validate.c
src/gallium/drivers/nvc0/nvc0_stateobj.h
src/gallium/drivers/nvc0/nvc0_vbo.c

index af6526c8759464a317098f7d00c287bec50d5f0f..1a34313912cead988fc6aace55c6e8cd9fa09dd8 100644 (file)
@@ -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
 
index 94117988e5081dfc09e386e06eaf17d19ef03f9e..a082ad4575c399949befe2518c2e471d6a20fa48 100644 (file)
@@ -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 *);
 
index 981b5488d088be36110265a5990c9d0403fb3859..633641713dcbda9ec5a7640ba78002ba9fdd65f8 100644 (file)
@@ -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);
+}
index c08f3693f5ea45c6b57a0c0e98712e7bb8929f9d..f6a7f824d5863b363351d63493998d87e41425b8 100644 (file)
@@ -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;
 }
 
index 6419011132acbde65482d4bdddfb69173d9f520e..7406f6c7917da4a973ed08da0016292793006e2a 100644 (file)
@@ -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]))
 
index 6c8028aba13a0d5c3cf6b542ffc53ceccec32ded..752e927e2aa62003499afbee26e4eaca39f76851 100644 (file)
@@ -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
index 486909c1eb04fcc7c73c7191f9fae7fd131cd153..aa5decfc23312ab6c78a310969164ff8874a8f91 100644 (file)
@@ -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,