nvc0: support primitive restart
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Thu, 9 Dec 2010 11:08:25 +0000 (12:08 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Thu, 9 Dec 2010 11:08:25 +0000 (12:08 +0100)
src/gallium/drivers/nvc0/nvc0_context.h
src/gallium/drivers/nvc0/nvc0_push.c
src/gallium/drivers/nvc0/nvc0_screen.c
src/gallium/drivers/nvc0/nvc0_vbo.c

index 0d884459f33bb18fade7f0fc6bbd9b4bb187293c..1b2f96429b89c7e96adc66c1ef05e6553d66d510 100644 (file)
@@ -73,6 +73,7 @@ struct nvc0_context {
    struct {
       uint32_t instance_bits;
       uint32_t instance_base;
+      boolean prim_restart;
       uint8_t num_vtxbufs;
       uint8_t num_vtxelts;
       uint8_t num_textures[5];
index d201f310cc5764b592106477c068fff02298e862..8b8fe610e2df165f013a61df494d8effbabf25d5 100644 (file)
@@ -14,17 +14,50 @@ struct push_context {
    struct nouveau_channel *chan;
 
    void *idxbuf;
-   int32_t idxbias;
 
    float edgeflag;
-   int edgeflat_attr;
+   int edgeflag_attr;
 
-   uint32_t vertex_size;
+   uint32_t vertex_words;
    uint32_t packet_vertex_limit;
 
    struct translate *translate;
+
+   boolean primitive_restart;
+   uint32_t prim;
+   uint32_t restart_index;
 };
 
+static INLINE unsigned
+prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
+{
+   unsigned i;
+   for (i = 0; i < push; ++i)
+      if (elts[i] == index)
+         break;
+   return i;
+}
+
+static INLINE unsigned
+prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
+{
+   unsigned i;
+   for (i = 0; i < push; ++i)
+      if (elts[i] == index)
+         break;
+   return i;
+}
+
+static INLINE unsigned
+prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
+{
+   unsigned i;
+   for (i = 0; i < push; ++i)
+      if (elts[i] == index)
+         break;
+   return i;
+}
+
 static void
 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
 {
@@ -32,14 +65,27 @@ emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
 
    while (count) {
       unsigned push = MIN2(count, ctx->packet_vertex_limit);
-      unsigned size = ctx->vertex_size * push;
+      unsigned size, nr;
+
+      nr = push;
+      if (ctx->primitive_restart)
+         nr = prim_restart_search_i08(elts, push, ctx->restart_index);
+
+      size = ctx->vertex_words * nr;
 
       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
 
       ctx->translate->run_elts8(ctx->translate, elts, push, 0, ctx->chan->cur);
+
       ctx->chan->cur += size;
       count -= push;
       elts += push;
+
+      if (nr != push) {
+         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
+         OUT_RING  (ctx->chan, 0);
+         OUT_RING  (ctx->chan, ctx->prim);
+      }
    }
 }
 
@@ -50,14 +96,27 @@ emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
 
    while (count) {
       unsigned push = MIN2(count, ctx->packet_vertex_limit);
-      unsigned size = ctx->vertex_size * push;
+      unsigned size, nr;
+
+      nr = push;
+      if (ctx->primitive_restart)
+         nr = prim_restart_search_i16(elts, push, ctx->restart_index);
+
+      size = ctx->vertex_words * nr;
 
       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
 
       ctx->translate->run_elts16(ctx->translate, elts, push, 0, ctx->chan->cur);
+
       ctx->chan->cur += size;
       count -= push;
       elts += push;
+
+      if (nr != push) {
+         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
+         OUT_RING  (ctx->chan, 0);
+         OUT_RING  (ctx->chan, ctx->prim);
+      }
    }
 }
 
@@ -68,14 +127,27 @@ emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
 
    while (count) {
       unsigned push = MIN2(count, ctx->packet_vertex_limit);
-      unsigned size = ctx->vertex_size * push;
+      unsigned size, nr;
+
+      nr = push;
+      if (ctx->primitive_restart)
+         nr = prim_restart_search_i32(elts, push, ctx->restart_index);
+
+      size = ctx->vertex_words * nr;
 
       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
 
       ctx->translate->run_elts(ctx->translate, elts, push, 0, ctx->chan->cur);
+
       ctx->chan->cur += size;
       count -= push;
       elts += push;
+
+      if (nr != push) {
+         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
+         OUT_RING  (ctx->chan, 0);
+         OUT_RING  (ctx->chan, ctx->prim);
+      }
    }
 }
 
@@ -84,7 +156,7 @@ emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
 {
    while (count) {
       unsigned push = MIN2(count, ctx->packet_vertex_limit);
-      unsigned size = ctx->vertex_size * push;
+      unsigned size = ctx->vertex_words * push;
 
       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
 
@@ -131,13 +203,12 @@ nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
    struct push_context ctx;
    struct pipe_transfer *transfer = NULL;
    unsigned i, index_size;
-   unsigned prim = nvc0_prim_gl(info->mode);
    unsigned inst = info->instance_count;
 
    ctx.chan = nvc0->screen->base.channel;
    ctx.translate = nvc0->vertex->translate;
    ctx.packet_vertex_limit = nvc0->vertex->vtx_per_packet_max;
-   ctx.vertex_size = nvc0->vertex->vtx_size;
+   ctx.vertex_words = nvc0->vertex->vtx_size;
 
    for (i = 0; i < nvc0->num_vtxbufs; ++i) {
       uint8_t *data;
@@ -159,14 +230,20 @@ nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
       if (!ctx.idxbuf)
          return;
       index_size = nvc0->idxbuf.index_size;
+      ctx.primitive_restart = info->primitive_restart;
+      ctx.restart_index = info->restart_index;
    } else {
       ctx.idxbuf = NULL;
       index_size = 0;
+      ctx.primitive_restart = FALSE;
+      ctx.restart_index = 0;
    }
 
+   ctx.prim = nvc0_prim_gl(info->mode);
+
    while (inst--) {
       BEGIN_RING(ctx.chan, RING_3D(VERTEX_BEGIN_GL), 1);
-      OUT_RING  (ctx.chan, prim);
+      OUT_RING  (ctx.chan, ctx.prim);
       switch (index_size) {
       case 0:
          emit_vertices_seq(&ctx, info->start, info->count);
@@ -186,7 +263,7 @@ nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
       }
       INLIN_RING(ctx.chan, RING_3D(VERTEX_END_GL), 0);
 
-      prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
+      ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    }
 
    if (info->indexed)
index 9768de96f5c63485477de60b8fa7a8fa91d7a8ba..616a990337171fb42c19184524ec17fef076ba6c 100644 (file)
@@ -110,7 +110,7 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_SHADER_STENCIL_EXPORT:
       return 0;
    case PIPE_CAP_PRIMITIVE_RESTART:
-      return 0;
+      return 1;
    default:
       NOUVEAU_ERR("unknown PIPE_CAP %d\n", param);
       return 0;
index 1fc842238f312510081187e3b7a063a956b7a12f..9fa1ad42ad30f6ba9424b6e63e5a52b6c8b43562 100644 (file)
@@ -287,7 +287,7 @@ nvc0_tfb_setup(struct nvc0_context *nvc0)
 static void
 nvc0_draw_arrays(struct nvc0_context *nvc0,
                  unsigned mode, unsigned start, unsigned count,
-                 unsigned start_instance, unsigned instance_count)
+                 unsigned instance_count)
 {
    struct nouveau_channel *chan = nvc0->screen->base.channel;
    unsigned prim;
@@ -297,12 +297,6 @@ nvc0_draw_arrays(struct nvc0_context *nvc0,
 
    prim = nvc0_prim_gl(mode);
 
-   if (nvc0->state.instance_base != start_instance) {
-      nvc0->state.instance_base = start_instance;
-      BEGIN_RING(chan, RING_3D(VB_INSTANCE_BASE), 1);
-      OUT_RING  (chan, start_instance);
-   }
-
    while (instance_count--) {
       BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
       OUT_RING  (chan, prim);
@@ -386,7 +380,7 @@ nvc0_draw_elements_inline_u32(struct nouveau_channel *chan, uint32_t *map,
 static void
 nvc0_draw_elements(struct nvc0_context *nvc0,
                    unsigned mode, unsigned start, unsigned count,
-                   unsigned start_instance, unsigned instance_count,
+                   unsigned instance_count,
                    unsigned index_size, int index_bias)
 {
    struct nouveau_channel *chan = nvc0->screen->base.channel;
@@ -423,6 +417,8 @@ nvc0_draw_elements(struct nvc0_context *nvc0,
       }
       BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1);
       OUT_RING  (chan, 0);
+
+      prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    }
 
    chan->flush_notify = NULL;
@@ -432,31 +428,52 @@ void
 nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
 {
    struct nvc0_context *nvc0 = nvc0_context(pipe);
+   struct nouveau_channel *chan = nvc0->screen->base.channel;
 
    nvc0_state_validate(nvc0);
 
+   if (nvc0->state.instance_base != info->start_instance) {
+      nvc0->state.instance_base = info->start_instance;
+      BEGIN_RING(chan, RING_3D(VB_INSTANCE_BASE), 1);
+      OUT_RING  (chan, info->start_instance);
+   }
+
    if (nvc0->vbo_fifo) {
       nvc0_push_vbo(nvc0, info);
       return;
    }
 
    if (nvc0->vbo_dirty) {
-      BEGIN_RING(nvc0->screen->base.channel, RING_3D_(0x142c), 1);
-      OUT_RING  (nvc0->screen->base.channel, 0);
+      BEGIN_RING(chan, RING_3D_(0x142c), 1);
+      OUT_RING  (chan, 0);
       nvc0->vbo_dirty = FALSE;
    }
 
    if (!info->indexed) {
       nvc0_draw_arrays(nvc0,
                        info->mode, info->start, info->count,
-                       info->start_instance, info->instance_count);
-   } else
-   if (nvc0->idxbuf.buffer) {
+                       info->instance_count);
+   } else {
+      assert(nvc0->idxbuf.buffer);
+
+      if (info->primitive_restart != nvc0->state.prim_restart) {
+         if (info->primitive_restart) {
+            BEGIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 2);
+            OUT_RING  (chan, 1);
+            OUT_RING  (chan, info->restart_index);
+         } else {
+            INLIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 0);
+         }
+         nvc0->state.prim_restart = info->primitive_restart;
+      } else
+      if (info->primitive_restart) {
+         BEGIN_RING(chan, RING_3D(PRIM_RESTART_INDEX), 1);
+         OUT_RING  (chan, info->restart_index);
+      }
+
       nvc0_draw_elements(nvc0,
                          info->mode, info->start, info->count,
-                         info->start_instance, info->instance_count,
+                         info->instance_count,
                          nvc0->idxbuf.index_size, info->index_bias);
-   } else {
-      NOUVEAU_ERR("draw_indexed: no index buffer\n");
    }
 }