From: Christoph Bumiller Date: Thu, 9 Dec 2010 11:08:25 +0000 (+0100) Subject: nvc0: support primitive restart X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5655f8d42d919270791588162399ac7a2c718733;p=mesa.git nvc0: support primitive restart --- 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"); } }