+
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/u_format.h"
-#include "util/u_split_prim.h"
+#include "translate/translate.h"
#include "nv50_context.h"
#include "nv50_resource.h"
-struct push_context {
- struct nv50_context *nv50;
+#include "nv50_3d.xml.h"
- unsigned vtx_size;
+struct push_context {
+ struct nouveau_pushbuf *push;
void *idxbuf;
- int32_t idxbias;
- unsigned idxsize;
float edgeflag;
int edgeflag_attr;
- struct {
- void *map;
- unsigned stride;
- unsigned divisor;
- unsigned step;
- void (*push)(struct nouveau_channel *, void *);
- } attr[16];
- unsigned attr_nr;
+ uint32_t vertex_words;
+ uint32_t packet_vertex_limit;
+
+ struct translate *translate;
+
+ boolean primitive_restart;
+ uint32_t prim;
+ uint32_t restart_index;
+ uint32_t instance_id;
};
-static void
-emit_b32_1(struct nouveau_channel *chan, void *data)
+static INLINE unsigned
+prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
{
- uint32_t *v = data;
-
- OUT_RING(chan, v[0]);
+ unsigned i;
+ for (i = 0; i < push; ++i)
+ if (elts[i] == index)
+ break;
+ return i;
}
-static void
-emit_b32_2(struct nouveau_channel *chan, void *data)
+static INLINE unsigned
+prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
{
- uint32_t *v = data;
-
- OUT_RING(chan, v[0]);
- OUT_RING(chan, v[1]);
+ unsigned i;
+ for (i = 0; i < push; ++i)
+ if (elts[i] == index)
+ break;
+ return i;
}
-static void
-emit_b32_3(struct nouveau_channel *chan, void *data)
+static INLINE unsigned
+prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
{
- uint32_t *v = data;
-
- OUT_RING(chan, v[0]);
- OUT_RING(chan, v[1]);
- OUT_RING(chan, v[2]);
+ unsigned i;
+ for (i = 0; i < push; ++i)
+ if (elts[i] == index)
+ break;
+ return i;
}
static void
-emit_b32_4(struct nouveau_channel *chan, void *data)
+emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
{
- uint32_t *v = data;
+ uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
- OUT_RING(chan, v[0]);
- OUT_RING(chan, v[1]);
- OUT_RING(chan, v[2]);
- OUT_RING(chan, v[3]);
-}
+ while (count) {
+ unsigned push = MIN2(count, ctx->packet_vertex_limit);
+ unsigned size, nr;
-static void
-emit_b16_1(struct nouveau_channel *chan, void *data)
-{
- uint16_t *v = data;
+ nr = push;
+ if (ctx->primitive_restart)
+ nr = prim_restart_search_i08(elts, push, ctx->restart_index);
- OUT_RING(chan, v[0]);
-}
+ size = ctx->vertex_words * nr;
-static void
-emit_b16_3(struct nouveau_channel *chan, void *data)
-{
- uint16_t *v = data;
+ BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
- OUT_RING(chan, (v[1] << 16) | v[0]);
- OUT_RING(chan, v[2]);
-}
+ ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id,
+ ctx->push->cur);
-static void
-emit_b08_1(struct nouveau_channel *chan, void *data)
-{
- uint8_t *v = data;
+ ctx->push->cur += size;
+ count -= nr;
+ elts += nr;
- OUT_RING(chan, v[0]);
+ if (nr != push) {
+ count--;
+ elts++;
+ BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
+ PUSH_DATA (ctx->push, ctx->restart_index);
+ }
+ }
}
static void
-emit_b08_3(struct nouveau_channel *chan, void *data)
+emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
{
- uint8_t *v = data;
+ uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
- OUT_RING(chan, (v[2] << 16) | (v[1] << 8) | v[0]);
-}
+ while (count) {
+ unsigned push = MIN2(count, ctx->packet_vertex_limit);
+ unsigned size, nr;
-static INLINE void
-emit_vertex(struct push_context *ctx, unsigned n)
-{
- struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
- struct nouveau_channel *chan = tesla->channel;
- int i;
-
- if (ctx->edgeflag_attr < 16) {
- float *edgeflag = (uint8_t *)ctx->attr[ctx->edgeflag_attr].map +
- ctx->attr[ctx->edgeflag_attr].stride * n;
-
- if (*edgeflag != ctx->edgeflag) {
- BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
- OUT_RING (chan, *edgeflag ? 1 : 0);
- ctx->edgeflag = *edgeflag;
- }
- }
+ nr = push;
+ if (ctx->primitive_restart)
+ nr = prim_restart_search_i16(elts, push, ctx->restart_index);
- BEGIN_RING_NI(chan, tesla, NV50TCL_VERTEX_DATA, ctx->vtx_size);
- for (i = 0; i < ctx->attr_nr; i++)
- ctx->attr[i].push(chan,
- (uint8_t *)ctx->attr[i].map + ctx->attr[i].stride * n);
-}
+ size = ctx->vertex_words * nr;
-static void
-emit_edgeflag(void *priv, boolean enabled)
-{
- struct push_context *ctx = priv;
- struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
- struct nouveau_channel *chan = tesla->channel;
+ BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
- BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
- OUT_RING (chan, enabled ? 1 : 0);
-}
+ ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id,
+ ctx->push->cur);
-static void
-emit_elt08(void *priv, unsigned start, unsigned count)
-{
- struct push_context *ctx = priv;
- uint8_t *idxbuf = ctx->idxbuf;
+ ctx->push->cur += size;
+ count -= nr;
+ elts += nr;
- while (count--)
- emit_vertex(ctx, idxbuf[start++]);
+ if (nr != push) {
+ count--;
+ elts++;
+ BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
+ PUSH_DATA (ctx->push, ctx->restart_index);
+ }
+ }
}
static void
-emit_elt08_biased(void *priv, unsigned start, unsigned count)
+emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
{
- struct push_context *ctx = priv;
- uint8_t *idxbuf = ctx->idxbuf;
+ uint32_t *elts = (uint32_t *)ctx->idxbuf + start;
- while (count--)
- emit_vertex(ctx, idxbuf[start++] + ctx->idxbias);
-}
+ while (count) {
+ unsigned push = MIN2(count, ctx->packet_vertex_limit);
+ unsigned size, nr;
-static void
-emit_elt16(void *priv, unsigned start, unsigned count)
-{
- struct push_context *ctx = priv;
- uint16_t *idxbuf = ctx->idxbuf;
+ nr = push;
+ if (ctx->primitive_restart)
+ nr = prim_restart_search_i32(elts, push, ctx->restart_index);
- while (count--)
- emit_vertex(ctx, idxbuf[start++]);
-}
+ size = ctx->vertex_words * nr;
-static void
-emit_elt16_biased(void *priv, unsigned start, unsigned count)
-{
- struct push_context *ctx = priv;
- uint16_t *idxbuf = ctx->idxbuf;
+ BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
- while (count--)
- emit_vertex(ctx, idxbuf[start++] + ctx->idxbias);
-}
+ ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id,
+ ctx->push->cur);
-static void
-emit_elt32(void *priv, unsigned start, unsigned count)
-{
- struct push_context *ctx = priv;
- uint32_t *idxbuf = ctx->idxbuf;
+ ctx->push->cur += size;
+ count -= nr;
+ elts += nr;
- while (count--)
- emit_vertex(ctx, idxbuf[start++]);
+ if (nr != push) {
+ count--;
+ elts++;
+ BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
+ PUSH_DATA (ctx->push, ctx->restart_index);
+ }
+ }
}
static void
-emit_elt32_biased(void *priv, unsigned start, unsigned count)
+emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
{
- struct push_context *ctx = priv;
- uint32_t *idxbuf = ctx->idxbuf;
+ while (count) {
+ unsigned push = MIN2(count, ctx->packet_vertex_limit);
+ unsigned size = ctx->vertex_words * push;
+
+ BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
- while (count--)
- emit_vertex(ctx, idxbuf[start++] + ctx->idxbias);
+ ctx->translate->run(ctx->translate, start, push, ctx->instance_id,
+ ctx->push->cur);
+ ctx->push->cur += size;
+ count -= push;
+ start += push;
+ }
}
-static void
-emit_verts(void *priv, unsigned start, unsigned count)
+
+#define NV50_PRIM_GL_CASE(n) \
+ case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
+
+static INLINE unsigned
+nv50_prim_gl(unsigned prim)
{
- while (count--)
- emit_vertex(priv, start++);
+ switch (prim) {
+ NV50_PRIM_GL_CASE(POINTS);
+ NV50_PRIM_GL_CASE(LINES);
+ NV50_PRIM_GL_CASE(LINE_LOOP);
+ NV50_PRIM_GL_CASE(LINE_STRIP);
+ NV50_PRIM_GL_CASE(TRIANGLES);
+ NV50_PRIM_GL_CASE(TRIANGLE_STRIP);
+ NV50_PRIM_GL_CASE(TRIANGLE_FAN);
+ NV50_PRIM_GL_CASE(QUADS);
+ NV50_PRIM_GL_CASE(QUAD_STRIP);
+ NV50_PRIM_GL_CASE(POLYGON);
+ NV50_PRIM_GL_CASE(LINES_ADJACENCY);
+ NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
+ NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
+ NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
+ /*
+ NV50_PRIM_GL_CASE(PATCHES); */
+ default:
+ return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
+ break;
+ }
}
void
-nv50_push_elements_instanced(struct pipe_context *pipe,
- struct pipe_resource *idxbuf,
- unsigned idxsize, int idxbias,
- unsigned mode, unsigned start, unsigned count,
- unsigned i_start, unsigned i_count)
+nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info)
{
- struct nv50_context *nv50 = nv50_context(pipe);
- struct nouveau_grobj *tesla = nv50->screen->tesla;
- struct nouveau_channel *chan = tesla->channel;
struct push_context ctx;
- const unsigned p_overhead = 4 + /* begin/end */
- 4; /* potential edgeflag enable/disable */
- const unsigned v_overhead = 1 + /* VERTEX_DATA packet header */
- 2; /* potential edgeflag modification */
- struct util_split_prim s;
- unsigned vtx_size;
- boolean nzi = FALSE;
- int i;
-
- ctx.nv50 = nv50;
- ctx.attr_nr = 0;
- ctx.idxbuf = NULL;
- ctx.vtx_size = 0;
- ctx.edgeflag = 0.5f;
- ctx.edgeflag_attr = nv50->vertprog->cfg.edgeflag_in;
-
- /* map vertex buffers, determine vertex size */
- for (i = 0; i < nv50->vtxelt->num_elements; i++) {
- struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
- struct pipe_vertex_buffer *vb = &nv50->vtxbuf[ve->vertex_buffer_index];
- struct nouveau_bo *bo = nv50_resource(vb->buffer)->bo;
- unsigned size, nr_components, n;
-
- if (!(nv50->vbo_fifo & (1 << i)))
- continue;
- n = ctx.attr_nr++;
-
- if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) {
- assert(bo->map);
+ unsigned i, index_size;
+ unsigned inst = info->instance_count;
+ boolean apply_bias = info->indexed && info->index_bias;
+
+ ctx.push = nv50->base.pushbuf;
+ ctx.translate = nv50->vertex->translate;
+ ctx.packet_vertex_limit = nv50->vertex->packet_vertex_limit;
+ ctx.vertex_words = nv50->vertex->vertex_size;
+
+ for (i = 0; i < nv50->num_vtxbufs; ++i) {
+ uint8_t *data;
+ struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
+ struct nv04_resource *res = nv04_resource(vb->buffer);
+
+ data = nouveau_resource_map_offset(&nv50->base, res,
+ vb->buffer_offset, NOUVEAU_BO_RD);
+
+ if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
+ data += info->index_bias * vb->stride;
+
+ ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
+ }
+
+ if (info->indexed) {
+ ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
+ nv04_resource(nv50->idxbuf.buffer),
+ nv50->idxbuf.offset, NOUVEAU_BO_RD);
+ if (!ctx.idxbuf)
return;
- }
- ctx.attr[n].map = (uint8_t *)bo->map + vb->buffer_offset + ve->src_offset;
- nouveau_bo_unmap(bo);
-
- ctx.attr[n].stride = vb->stride;
- ctx.attr[n].divisor = ve->instance_divisor;
- if (ctx.attr[n].divisor) {
- ctx.attr[n].step = i_start % ve->instance_divisor;
- ctx.attr[n].map = (uint8_t *)ctx.attr[n].map + i_start * vb->stride;
- }
+ index_size = nv50->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.instance_id = info->start_instance;
+ ctx.prim = nv50_prim_gl(info->mode);
- size = util_format_get_component_bits(ve->src_format,
- UTIL_FORMAT_COLORSPACE_RGB, 0);
- nr_components = util_format_get_nr_components(ve->src_format);
- switch (size) {
- case 8:
- switch (nr_components) {
- case 1: ctx.attr[n].push = emit_b08_1; break;
- case 2: ctx.attr[n].push = emit_b16_1; break;
- case 3: ctx.attr[n].push = emit_b08_3; break;
- case 4: ctx.attr[n].push = emit_b32_1; break;
- }
- ctx.vtx_size++;
+ if (info->primitive_restart) {
+ BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2);
+ PUSH_DATA (ctx.push, 1);
+ PUSH_DATA (ctx.push, info->restart_index);
+ } else
+ if (nv50->state.prim_restart) {
+ BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1);
+ PUSH_DATA (ctx.push, 0);
+ }
+ nv50->state.prim_restart = info->primitive_restart;
+
+ while (inst--) {
+ BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1);
+ PUSH_DATA (ctx.push, ctx.prim);
+ switch (index_size) {
+ case 0:
+ emit_vertices_seq(&ctx, info->start, info->count);
+ break;
+ case 1:
+ emit_vertices_i08(&ctx, info->start, info->count);
break;
- case 16:
- switch (nr_components) {
- case 1: ctx.attr[n].push = emit_b16_1; break;
- case 2: ctx.attr[n].push = emit_b32_1; break;
- case 3: ctx.attr[n].push = emit_b16_3; break;
- case 4: ctx.attr[n].push = emit_b32_2; break;
- }
- ctx.vtx_size += (nr_components + 1) >> 1;
+ case 2:
+ emit_vertices_i16(&ctx, info->start, info->count);
break;
- case 32:
- switch (nr_components) {
- case 1: ctx.attr[n].push = emit_b32_1; break;
- case 2: ctx.attr[n].push = emit_b32_2; break;
- case 3: ctx.attr[n].push = emit_b32_3; break;
- case 4: ctx.attr[n].push = emit_b32_4; break;
- }
- ctx.vtx_size += nr_components;
+ case 4:
+ emit_vertices_i32(&ctx, info->start, info->count);
break;
default:
assert(0);
- return;
+ break;
}
- }
- vtx_size = ctx.vtx_size + v_overhead;
+ BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1);
+ PUSH_DATA (ctx.push, 0);
- /* map index buffer, if present */
- if (idxbuf) {
- struct nouveau_bo *bo = nv50_resource(idxbuf)->bo;
-
- if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) {
- assert(bo->map);
- return;
- }
- ctx.idxbuf = bo->map;
- ctx.idxbias = idxbias;
- ctx.idxsize = idxsize;
- nouveau_bo_unmap(bo);
+ ctx.instance_id++;
+ ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
}
- s.priv = &ctx;
- s.edge = emit_edgeflag;
- if (idxbuf) {
- if (idxsize == 1)
- s.emit = idxbias ? emit_elt08_biased : emit_elt08;
- else
- if (idxsize == 2)
- s.emit = idxbias ? emit_elt16_biased : emit_elt16;
- else
- s.emit = idxbias ? emit_elt32_biased : emit_elt32;
- } else
- s.emit = emit_verts;
-
- /* per-instance loop */
- BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
- OUT_RING (chan, NV50_CB_AUX | (24 << 8));
- OUT_RING (chan, i_start);
- while (i_count--) {
- unsigned max_verts;
- boolean done;
-
- for (i = 0; i < ctx.attr_nr; i++) {
- if (!ctx.attr[i].divisor ||
- ctx.attr[i].divisor != ++ctx.attr[i].step)
- continue;
- ctx.attr[i].step = 0;
- ctx.attr[i].map = (uint8_t *)ctx.attr[i].map + ctx.attr[i].stride;
- }
+ if (info->indexed)
+ nouveau_resource_unmap(nv04_resource(nv50->idxbuf.buffer));
- util_split_prim_init(&s, mode, start, count);
- do {
- if (AVAIL_RING(chan) < p_overhead + (6 * vtx_size)) {
- FIRE_RING(chan);
- if (!nv50_state_validate(nv50, p_overhead + (6 * vtx_size))) {
- assert(0);
- return;
- }
- }
-
- max_verts = AVAIL_RING(chan);
- max_verts -= p_overhead;
- max_verts /= vtx_size;
-
- BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
- OUT_RING (chan, nv50_prim(s.mode) | (nzi ? (1 << 28) : 0));
- done = util_split_prim_next(&s, max_verts);
- BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
- OUT_RING (chan, 0);
- } while (!done);
-
- nzi = TRUE;
- }
+ for (i = 0; i < nv50->num_vtxbufs; ++i)
+ nouveau_resource_unmap(nv04_resource(nv50->vtxbuf[i].buffer));
}