uint32_t vertex_size;
uint32_t restart_index;
+ uint32_t start_instance;
uint32_t instance_id;
- boolean prim_restart;
- boolean need_vertex_id;
+ bool prim_restart;
+ bool need_vertex_id;
struct {
- boolean enabled;
- boolean value;
+ bool enabled;
+ bool value;
+ uint8_t width;
unsigned stride;
const uint8_t *data;
} edgeflag;
ctx->translate = nvc0->vertex->translate;
ctx->vertex_size = nvc0->vertex->size;
+ ctx->instance_id = 0;
ctx->need_vertex_id =
nvc0->vertprog->vp.need_vertex_id && (nvc0->vertex->num_elements < 32);
- ctx->edgeflag.value = TRUE;
+ ctx->edgeflag.value = true;
ctx->edgeflag.enabled = nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS;
/* silence warnings */
ctx->edgeflag.data = NULL;
ctx->edgeflag.stride = 0;
+ ctx->edgeflag.width = 0;
}
-static INLINE void
+static inline void
nvc0_vertex_configure_translate(struct nvc0_context *nvc0, int32_t index_bias)
{
struct translate *translate = nvc0->vertex->translate;
const uint8_t *map;
const struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
- if (likely(!vb->buffer))
- map = (const uint8_t *)vb->user_buffer;
- else
+ if (likely(vb->is_user_buffer))
+ map = (const uint8_t *)vb->buffer.user;
+ else {
+ if (!vb->buffer.resource)
+ continue;
+
map = nouveau_resource_map_offset(&nvc0->base,
- nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD);
+ nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
+ }
if (index_bias && !unlikely(nvc0->vertex->instance_bufs & (1 << i)))
map += (intptr_t)index_bias * vb->stride;
}
}
-static INLINE void
-nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0)
+static inline void
+nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0,
+ const struct pipe_draw_info *info)
{
- if (nvc0->idxbuf.buffer) {
- struct nv04_resource *buf = nv04_resource(nvc0->idxbuf.buffer);
- ctx->idxbuf = nouveau_resource_map_offset(&nvc0->base,
- buf, nvc0->idxbuf.offset, NOUVEAU_BO_RD);
+ if (!info->has_user_indices) {
+ struct nv04_resource *buf = nv04_resource(info->index.resource);
+ ctx->idxbuf = nouveau_resource_map_offset(
+ &nvc0->base, buf, 0, NOUVEAU_BO_RD);
} else {
- ctx->idxbuf = nvc0->idxbuf.user_buffer;
+ ctx->idxbuf = info->index.user;
}
}
-static INLINE void
+static inline void
nvc0_push_map_edgeflag(struct push_context *ctx, struct nvc0_context *nvc0,
int32_t index_bias)
{
unsigned attr = nvc0->vertprog->vp.edgeflag;
struct pipe_vertex_element *ve = &nvc0->vertex->element[attr].pipe;
struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];
- struct nv04_resource *buf = nv04_resource(vb->buffer);
- unsigned offset = vb->buffer_offset + ve->src_offset;
+ struct nv04_resource *buf = nv04_resource(vb->buffer.resource);
ctx->edgeflag.stride = vb->stride;
- ctx->edgeflag.data = nouveau_resource_map_offset(&nvc0->base,
+ ctx->edgeflag.width = util_format_get_blocksize(ve->src_format);
+ if (!vb->is_user_buffer) {
+ unsigned offset = vb->buffer_offset + ve->src_offset;
+ ctx->edgeflag.data = nouveau_resource_map_offset(&nvc0->base,
buf, offset, NOUVEAU_BO_RD);
+ } else {
+ ctx->edgeflag.data = (const uint8_t *)vb->buffer.user + ve->src_offset;
+ }
+
if (index_bias)
ctx->edgeflag.data += (intptr_t)index_bias * vb->stride;
}
-static INLINE unsigned
+static inline unsigned
prim_restart_search_i08(const uint8_t *elts, unsigned push, uint8_t index)
{
unsigned i;
return i;
}
-static INLINE unsigned
+static inline unsigned
prim_restart_search_i16(const uint16_t *elts, unsigned push, uint16_t index)
{
unsigned i;
return i;
}
-static INLINE unsigned
+static inline unsigned
prim_restart_search_i32(const uint32_t *elts, unsigned push, uint32_t index)
{
unsigned i;
return i;
}
-static INLINE boolean
-ef_value(const struct push_context *ctx, uint32_t index)
+static inline bool
+ef_value_8(const struct push_context *ctx, uint32_t index)
+{
+ uint8_t *pf = (uint8_t *)&ctx->edgeflag.data[index * ctx->edgeflag.stride];
+ return !!*pf;
+}
+
+static inline bool
+ef_value_32(const struct push_context *ctx, uint32_t index)
{
- float *pf = (float *)&ctx->edgeflag.data[index * ctx->edgeflag.stride];
- return *pf ? TRUE : FALSE;
+ uint32_t *pf = (uint32_t *)&ctx->edgeflag.data[index * ctx->edgeflag.stride];
+ return !!*pf;
}
-static INLINE boolean
+static inline bool
ef_toggle(struct push_context *ctx)
{
ctx->edgeflag.value = !ctx->edgeflag.value;
return ctx->edgeflag.value;
}
-static INLINE unsigned
+static inline unsigned
ef_toggle_search_i08(struct push_context *ctx, const uint8_t *elts, unsigned n)
{
unsigned i;
- for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i);
+ bool ef = ctx->edgeflag.value;
+ if (ctx->edgeflag.width == 1)
+ for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
+ else
+ for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
return i;
}
-static INLINE unsigned
+static inline unsigned
ef_toggle_search_i16(struct push_context *ctx, const uint16_t *elts, unsigned n)
{
unsigned i;
- for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i);
+ bool ef = ctx->edgeflag.value;
+ if (ctx->edgeflag.width == 1)
+ for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
+ else
+ for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
return i;
}
-static INLINE unsigned
+static inline unsigned
ef_toggle_search_i32(struct push_context *ctx, const uint32_t *elts, unsigned n)
{
unsigned i;
- for (i = 0; i < n && ef_value(ctx, elts[i]) == ctx->edgeflag.value; ++i);
+ bool ef = ctx->edgeflag.value;
+ if (ctx->edgeflag.width == 1)
+ for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
+ else
+ for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
return i;
}
-static INLINE unsigned
+static inline unsigned
ef_toggle_search_seq(struct push_context *ctx, unsigned start, unsigned n)
{
unsigned i;
- for (i = 0; i < n && ef_value(ctx, start++) == ctx->edgeflag.value; ++i);
+ bool ef = ctx->edgeflag.value;
+ if (ctx->edgeflag.width == 1)
+ for (i = 0; i < n && ef_value_8(ctx, start++) == ef; ++i);
+ else
+ for (i = 0; i < n && ef_value_32(ctx, start++) == ef; ++i);
return i;
}
-static INLINE void *
+static inline void *
nvc0_push_setup_vertex_array(struct nvc0_context *nvc0, const unsigned count)
{
struct nouveau_pushbuf *push = nvc0->base.pushbuf;
PUSH_DATAh(push, va + size - 1);
PUSH_DATA (push, va + size - 1);
- BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
+ BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
bo);
nouveau_pushbuf_validate(push);
if (unlikely(ctx->prim_restart))
nR = prim_restart_search_i08(elts, nR, ctx->restart_index);
- translate->run_elts8(translate, elts, nR, 0, ctx->instance_id, ctx->dest);
+ translate->run_elts8(translate, elts, nR,
+ ctx->start_instance, ctx->instance_id, ctx->dest);
count -= nR;
ctx->dest += nR * ctx->vertex_size;
}
if (count) {
BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
- PUSH_DATA (push, ctx->restart_index);
+ PUSH_DATA (push, 0xffffffff);
++elts;
ctx->dest += ctx->vertex_size;
++pos;
if (unlikely(ctx->prim_restart))
nR = prim_restart_search_i16(elts, nR, ctx->restart_index);
- translate->run_elts16(translate, elts, nR, 0, ctx->instance_id, ctx->dest);
+ translate->run_elts16(translate, elts, nR,
+ ctx->start_instance, ctx->instance_id, ctx->dest);
count -= nR;
ctx->dest += nR * ctx->vertex_size;
}
if (count) {
BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
- PUSH_DATA (push, ctx->restart_index);
+ PUSH_DATA (push, 0xffffffff);
++elts;
ctx->dest += ctx->vertex_size;
++pos;
if (unlikely(ctx->prim_restart))
nR = prim_restart_search_i32(elts, nR, ctx->restart_index);
- translate->run_elts(translate, elts, nR, 0, ctx->instance_id, ctx->dest);
+ translate->run_elts(translate, elts, nR,
+ ctx->start_instance, ctx->instance_id, ctx->dest);
count -= nR;
ctx->dest += nR * ctx->vertex_size;
}
if (count) {
BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
- PUSH_DATA (push, ctx->restart_index);
+ PUSH_DATA (push, 0xffffffff);
++elts;
ctx->dest += ctx->vertex_size;
++pos;
struct translate *translate = ctx->translate;
unsigned pos = 0;
- translate->run(translate, start, count, 0, ctx->instance_id, ctx->dest);
+ /* XXX: This will read the data corresponding to the primitive restart index,
+ * maybe we should avoid that ?
+ */
+ translate->run(translate, start, count,
+ ctx->start_instance, ctx->instance_id, ctx->dest);
do {
unsigned nr = count;
#define NVC0_PRIM_GL_CASE(n) \
case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
-static INLINE unsigned
+static inline unsigned
nvc0_prim_gl(unsigned prim)
{
switch (prim) {
NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
- /*
- NVC0_PRIM_GL_CASE(PATCHES); */
+ NVC0_PRIM_GL_CASE(PATCHES);
default:
return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
}
}
+typedef struct {
+ uint32_t count;
+ uint32_t primCount;
+ uint32_t first;
+ uint32_t baseInstance;
+} DrawArraysIndirectCommand;
+
+typedef struct {
+ uint32_t count;
+ uint32_t primCount;
+ uint32_t firstIndex;
+ int32_t baseVertex;
+ uint32_t baseInstance;
+} DrawElementsIndirectCommand;
+
+void
+nvc0_push_vbo_indirect(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
+{
+ /* The strategy here is to just read the commands from the indirect buffer
+ * and do the draws. This is suboptimal, but will only happen in the case
+ * that conversion is required for FIXED or DOUBLE inputs.
+ */
+ struct nvc0_screen *screen = nvc0->screen;
+ struct nouveau_pushbuf *push = nvc0->base.pushbuf;
+ struct nv04_resource *buf = nv04_resource(info->indirect->buffer);
+ struct nv04_resource *buf_count = nv04_resource(info->indirect->indirect_draw_count);
+ unsigned i;
+
+ unsigned draw_count = info->indirect->draw_count;
+ if (buf_count) {
+ uint32_t *count = nouveau_resource_map_offset(
+ &nvc0->base, buf_count, info->indirect->indirect_draw_count_offset,
+ NOUVEAU_BO_RD);
+ draw_count = *count;
+ }
+
+ uint8_t *buf_data = nouveau_resource_map_offset(
+ &nvc0->base, buf, info->indirect->offset, NOUVEAU_BO_RD);
+ struct pipe_draw_info single = *info;
+ single.indirect = NULL;
+ for (i = 0; i < draw_count; i++, buf_data += info->indirect->stride) {
+ if (info->index_size) {
+ DrawElementsIndirectCommand *cmd = (void *)buf_data;
+ single.start = info->start + cmd->firstIndex;
+ single.count = cmd->count;
+ single.start_instance = cmd->baseInstance;
+ single.instance_count = cmd->primCount;
+ single.index_bias = cmd->baseVertex;
+ } else {
+ DrawArraysIndirectCommand *cmd = (void *)buf_data;
+ single.start = cmd->first;
+ single.count = cmd->count;
+ single.start_instance = cmd->baseInstance;
+ single.instance_count = cmd->primCount;
+ }
+
+ if (nvc0->vertprog->vp.need_draw_parameters) {
+ PUSH_SPACE(push, 9);
+ BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
+ PUSH_DATA (push, NVC0_CB_AUX_SIZE);
+ PUSH_DATAh(push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));
+ PUSH_DATA (push, screen->uniform_bo->offset + NVC0_CB_AUX_INFO(0));
+ BEGIN_1IC0(push, NVC0_3D(CB_POS), 1 + 3);
+ PUSH_DATA (push, NVC0_CB_AUX_DRAW_INFO);
+ PUSH_DATA (push, single.index_bias);
+ PUSH_DATA (push, single.start_instance);
+ PUSH_DATA (push, single.drawid + i);
+ }
+
+ nvc0_push_vbo(nvc0, &single);
+ }
+
+ nouveau_resource_unmap(buf);
+ if (buf_count)
+ nouveau_resource_unmap(buf_count);
+}
+
void
nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
{
nvc0_vertex_configure_translate(nvc0, info->index_bias);
+ if (nvc0->state.index_bias) {
+ /* this is already taken care of by translate */
+ IMMED_NVC0(ctx.push, NVC0_3D(VB_ELEMENT_BASE), 0);
+ nvc0->state.index_bias = 0;
+ }
+
if (unlikely(ctx.edgeflag.enabled))
nvc0_push_map_edgeflag(&ctx, nvc0, info->index_bias);
ctx.prim_restart = info->primitive_restart;
ctx.restart_index = info->restart_index;
- if (info->indexed) {
- nvc0_push_map_idxbuf(&ctx, nvc0);
- index_size = nvc0->idxbuf.index_size;
-
- if (info->primitive_restart) {
- BEGIN_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 2);
- PUSH_DATA (ctx.push, 1);
- PUSH_DATA (ctx.push, info->restart_index);
- } else
- if (nvc0->state.prim_restart) {
- IMMED_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 0);
- }
- nvc0->state.prim_restart = info->primitive_restart;
+ if (info->primitive_restart) {
+ /* NOTE: I hope we won't ever need that last index (~0).
+ * If we do, we have to disable primitive restart here always and
+ * use END,BEGIN to restart. (XXX: would that affect PrimitiveID ?)
+ * We could also deactive PRIM_RESTART_WITH_DRAW_ARRAYS temporarily,
+ * and add manual restart to disp_vertices_seq.
+ */
+ BEGIN_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 2);
+ PUSH_DATA (ctx.push, 1);
+ PUSH_DATA (ctx.push, info->index_size ? 0xffffffff : info->restart_index);
+ } else
+ if (nvc0->state.prim_restart) {
+ IMMED_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 0);
+ }
+ nvc0->state.prim_restart = info->primitive_restart;
+
+ if (info->index_size) {
+ nvc0_push_map_idxbuf(&ctx, nvc0, info);
+ index_size = info->index_size;
} else {
if (unlikely(info->count_from_stream_output)) {
struct pipe_context *pipe = &nvc0->base.pipe;
struct nvc0_so_target *targ;
targ = nvc0_so_target(info->count_from_stream_output);
- pipe->get_query_result(pipe, targ->pq, TRUE, (void *)&vert_count);
+ pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
vert_count /= targ->stride;
}
ctx.idxbuf = NULL; /* shut up warnings */
index_size = 0;
}
- ctx.instance_id = info->start_instance;
+ ctx.start_instance = info->start_instance;
prim = nvc0_prim_gl(info->mode);
do {
if (unlikely(ctx.need_vertex_id))
nvc0_push_upload_vertex_ids(&ctx, nvc0, info);
- IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
+ if (nvc0->screen->eng3d->oclass < GM107_3D_CLASS)
+ IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_BEGIN_GL), 1);
PUSH_DATA (ctx.push, prim);
switch (index_size) {
prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
++ctx.instance_id;
}
- nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX_TMP);
+ nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX_TMP);
nouveau_scratch_done(&nvc0->base);
} while (inst_count);
IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 0);
}
- if (info->indexed)
- nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
+ if (info->index_size && !info->has_user_indices)
+ nouveau_resource_unmap(nv04_resource(info->index.resource));
for (i = 0; i < nvc0->num_vtxbufs; ++i)
- nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
+ nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer.resource));
NOUVEAU_DRV_STAT(&nvc0->screen->base, draw_calls_fallback_count, 1);
}
-static INLINE void
+static inline void
copy_indices_u8(uint32_t *dst, const uint8_t *elts, uint32_t bias, unsigned n)
{
unsigned i;
dst[i] = elts[i] + bias;
}
-static INLINE void
+static inline void
copy_indices_u16(uint32_t *dst, const uint16_t *elts, uint32_t bias, unsigned n)
{
unsigned i;
dst[i] = elts[i] + bias;
}
-static INLINE void
+static inline void
copy_indices_u32(uint32_t *dst, const uint32_t *elts, uint32_t bias, unsigned n)
{
unsigned i;
uint64_t va;
uint32_t *data;
uint32_t format;
- unsigned index_size = nvc0->idxbuf.index_size;
+ unsigned index_size = info->index_size;
unsigned i;
unsigned a = nvc0->vertex->num_elements;
data = (uint32_t *)nouveau_scratch_get(&nvc0->base,
info->count * index_size, &va, &bo);
- BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
+ BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
bo);
nouveau_pushbuf_validate(push);
- if (info->indexed) {
+ if (info->index_size) {
if (!info->index_bias) {
memcpy(data, ctx->idxbuf, info->count * index_size);
} else {
- switch (nvc0->idxbuf.index_size) {
+ switch (info->index_size) {
case 1:
copy_indices_u8(data, ctx->idxbuf, info->index_bias, info->count);
break;