summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Bumiller <[email protected]>2010-12-09 12:08:25 +0100
committerChristoph Bumiller <[email protected]>2010-12-09 12:08:25 +0100
commit5655f8d42d919270791588162399ac7a2c718733 (patch)
treeb21c4ba42fc71f0654147b977e5b710f2db91557
parent548967f9faef8b4f3713e20c29b85cea3149e91d (diff)
nvc0: support primitive restart
-rw-r--r--src/gallium/drivers/nvc0/nvc0_context.h1
-rw-r--r--src/gallium/drivers/nvc0/nvc0_push.c99
-rw-r--r--src/gallium/drivers/nvc0/nvc0_screen.c2
-rw-r--r--src/gallium/drivers/nvc0/nvc0_vbo.c49
4 files changed, 123 insertions, 28 deletions
diff --git a/src/gallium/drivers/nvc0/nvc0_context.h b/src/gallium/drivers/nvc0/nvc0_context.h
index 0d884459f33..1b2f96429b8 100644
--- a/src/gallium/drivers/nvc0/nvc0_context.h
+++ b/src/gallium/drivers/nvc0/nvc0_context.h
@@ -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];
diff --git a/src/gallium/drivers/nvc0/nvc0_push.c b/src/gallium/drivers/nvc0/nvc0_push.c
index d201f310cc5..8b8fe610e2d 100644
--- a/src/gallium/drivers/nvc0/nvc0_push.c
+++ b/src/gallium/drivers/nvc0/nvc0_push.c
@@ -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)
diff --git a/src/gallium/drivers/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c
index 9768de96f5c..616a9903371 100644
--- a/src/gallium/drivers/nvc0/nvc0_screen.c
+++ b/src/gallium/drivers/nvc0/nvc0_screen.c
@@ -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;
diff --git a/src/gallium/drivers/nvc0/nvc0_vbo.c b/src/gallium/drivers/nvc0/nvc0_vbo.c
index 1fc842238f3..9fa1ad42ad3 100644
--- a/src/gallium/drivers/nvc0/nvc0_vbo.c
+++ b/src/gallium/drivers/nvc0/nvc0_vbo.c
@@ -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");
}
}