#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/u_format.h"
+#include "util/u_split_prim.h"
#include "nv50_context.h"
-
-#define NV50_USING_LOATHED_EDGEFLAG(ctx) ((ctx)->vertprog->cfg.edgeflag_in < 16)
-
-static INLINE unsigned
-nv50_prim(unsigned mode)
-{
- switch (mode) {
- case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
- case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
- case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
- case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
- case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
- case PIPE_PRIM_TRIANGLE_STRIP:
- return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
- case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
- case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
- case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
- case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
- case PIPE_PRIM_LINES_ADJACENCY:
- return NV50TCL_VERTEX_BEGIN_LINES_ADJACENCY;
- case PIPE_PRIM_LINE_STRIP_ADJACENCY:
- return NV50TCL_VERTEX_BEGIN_LINE_STRIP_ADJACENCY;
- case PIPE_PRIM_TRIANGLES_ADJACENCY:
- return NV50TCL_VERTEX_BEGIN_TRIANGLES_ADJACENCY;
- case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
- return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP_ADJACENCY;
- default:
- break;
- }
-
- NOUVEAU_ERR("invalid primitive type %d\n", mode);
- return NV50TCL_VERTEX_BEGIN_POINTS;
-}
+#include "nv50_resource.h"
static INLINE uint32_t
nv50_vbo_type_to_hw(enum pipe_format format)
if (a[i].divisor) {
vb = &nv50->vtxbuf[ve->vertex_buffer_index];
- a[i].bo = nouveau_bo(vb->buffer);
+ a[i].bo = nv50_resource(vb->buffer)->bo;
a[i].stride = vb->stride;
a[i].step = first % a[i].divisor;
a[i].delta = vb->buffer_offset + ve->src_offset +
}
}
-void
+static void
nv50_draw_arrays_instanced(struct pipe_context *pipe,
unsigned mode, unsigned start, unsigned count,
unsigned startInstance, unsigned instanceCount)
if (!nv50_state_validate(nv50, 10 + 16*3))
return;
+ if (nv50->vbo_fifo) {
+ nv50_push_elements_instanced(pipe, NULL, 0, 0, mode, start,
+ count, startInstance,
+ instanceCount);
+ return;
+ }
+
BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
OUT_RING (chan, NV50_CB_AUX | (24 << 8));
OUT_RING (chan, startInstance);
}
}
-void
-nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
- unsigned count)
-{
- nv50_draw_arrays_instanced(pipe, mode, start, count, 0, 1);
-}
+struct inline_ctx {
+ struct nv50_context *nv50;
+ void *map;
+};
-static INLINE boolean
-nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map,
- unsigned start, unsigned count)
+static void
+inline_elt08(void *priv, unsigned start, unsigned count)
{
- struct nouveau_channel *chan = nv50->screen->tesla->channel;
- struct nouveau_grobj *tesla = nv50->screen->tesla;
-
- map += start;
+ struct inline_ctx *ctx = priv;
+ struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
+ struct nouveau_channel *chan = tesla->channel;
+ uint8_t *map = (uint8_t *)ctx->map + start;
if (count & 1) {
BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
OUT_RING (chan, map[0]);
map++;
- count--;
+ count &= ~1;
}
- while (count) {
- unsigned nr = count > 2046 ? 2046 : count;
- int i;
-
- BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
- for (i = 0; i < nr; i += 2)
- OUT_RING (chan, (map[i + 1] << 16) | map[i]);
+ count >>= 1;
+ if (!count)
+ return;
- count -= nr;
- map += nr;
+ BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
+ while (count--) {
+ OUT_RING(chan, (map[1] << 16) | map[0]);
+ map += 2;
}
- return TRUE;
}
-static INLINE boolean
-nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map,
- unsigned start, unsigned count)
+static void
+inline_elt16(void *priv, unsigned start, unsigned count)
{
- struct nouveau_channel *chan = nv50->screen->tesla->channel;
- struct nouveau_grobj *tesla = nv50->screen->tesla;
-
- map += start;
+ struct inline_ctx *ctx = priv;
+ struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
+ struct nouveau_channel *chan = tesla->channel;
+ uint16_t *map = (uint16_t *)ctx->map + start;
if (count & 1) {
BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
OUT_RING (chan, map[0]);
+ count &= ~1;
map++;
- count--;
}
- while (count) {
- unsigned nr = count > 2046 ? 2046 : count;
- int i;
-
- BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
- for (i = 0; i < nr; i += 2)
- OUT_RING (chan, (map[i + 1] << 16) | map[i]);
+ count >>= 1;
+ if (!count)
+ return;
- count -= nr;
- map += nr;
+ BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
+ while (count--) {
+ OUT_RING(chan, (map[1] << 16) | map[0]);
+ map += 2;
}
- return TRUE;
}
-static INLINE boolean
-nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint32_t *map,
- unsigned start, unsigned count)
+static void
+inline_elt32(void *priv, unsigned start, unsigned count)
{
- struct nouveau_channel *chan = nv50->screen->tesla->channel;
- struct nouveau_grobj *tesla = nv50->screen->tesla;
-
- map += start;
+ struct inline_ctx *ctx = priv;
+ struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
+ struct nouveau_channel *chan = tesla->channel;
- while (count) {
- unsigned nr = count > 2047 ? 2047 : count;
+ BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, count);
+ OUT_RINGp (chan, (uint32_t *)ctx->map + start, count);
+}
- BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, nr);
- OUT_RINGp (chan, map, nr);
+static void
+inline_edgeflag(void *priv, boolean enabled)
+{
+ struct inline_ctx *ctx = priv;
+ struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
+ struct nouveau_channel *chan = tesla->channel;
- count -= nr;
- map += nr;
- }
- return TRUE;
+ BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
+ OUT_RING (chan, enabled ? 1 : 0);
}
static void
nv50_draw_elements_inline(struct pipe_context *pipe,
- struct pipe_buffer *indexBuffer, unsigned indexSize,
+ struct pipe_resource *indexBuffer, unsigned indexSize,
unsigned mode, unsigned start, unsigned count,
unsigned startInstance, unsigned instanceCount)
{
- struct pipe_screen *pscreen = pipe->screen;
struct nv50_context *nv50 = nv50_context(pipe);
struct nouveau_channel *chan = nv50->screen->tesla->channel;
struct nouveau_grobj *tesla = nv50->screen->tesla;
+ struct pipe_transfer *transfer;
struct instance a[16];
- unsigned prim = nv50_prim(mode);
- void *map;
-
- map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
- assert(map);
- if (!map)
+ struct inline_ctx ctx;
+ struct util_split_prim s;
+ boolean nzi = FALSE;
+ unsigned overhead;
+
+ overhead = 16*3; /* potential instance adjustments */
+ overhead += 4; /* Begin()/End() */
+ overhead += 4; /* potential edgeflag disable/reenable */
+ overhead += 3; /* potentially 3 VTX_ELT_U16/U32 packet headers */
+
+ s.priv = &ctx;
+ if (indexSize == 1)
+ s.emit = inline_elt08;
+ else
+ if (indexSize == 2)
+ s.emit = inline_elt16;
+ else
+ s.emit = inline_elt32;
+ s.edge = inline_edgeflag;
+
+ ctx.nv50 = nv50;
+ ctx.map = pipe_buffer_map(pipe, indexBuffer, PIPE_TRANSFER_READ, &transfer);
+ assert(ctx.map);
+ if (!ctx.map)
return;
instance_init(nv50, a, startInstance);
- if (!nv50_state_validate(nv50, 0))
+ if (!nv50_state_validate(nv50, overhead + 6 + 3))
return;
BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
OUT_RING (chan, NV50_CB_AUX | (24 << 8));
OUT_RING (chan, startInstance);
while (instanceCount--) {
- if (AVAIL_RING(chan) < (7 + 16*3)) {
- FIRE_RING(chan);
- if (!nv50_state_validate(nv50, 0)) {
- assert(0);
- return;
+ unsigned max_verts;
+ boolean done;
+
+ util_split_prim_init(&s, mode, start, count);
+ do {
+ if (AVAIL_RING(chan) < (overhead + 6)) {
+ FIRE_RING(chan);
+ if (!nv50_state_validate(nv50, (overhead + 6))) {
+ assert(0);
+ return;
+ }
}
- }
- instance_step(nv50, a);
- BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
- OUT_RING (chan, prim);
- switch (indexSize) {
- case 1:
- nv50_draw_elements_inline_u08(nv50, map, start, count);
- break;
- case 2:
- nv50_draw_elements_inline_u16(nv50, map, start, count);
- break;
- case 4:
- nv50_draw_elements_inline_u32(nv50, map, start, count);
- break;
- default:
- assert(0);
- break;
- }
- BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
- OUT_RING (chan, 0);
+ max_verts = AVAIL_RING(chan) - overhead;
+ if (max_verts > 2047)
+ max_verts = 2047;
+ if (indexSize != 4)
+ max_verts <<= 1;
+ instance_step(nv50, a);
+
+ 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);
- prim |= (1 << 28);
+ nzi = TRUE;
}
- pipe_buffer_unmap(pscreen, indexBuffer);
+ pipe_buffer_unmap(pipe, indexBuffer, transfer);
}
-void
+static void
nv50_draw_elements_instanced(struct pipe_context *pipe,
- struct pipe_buffer *indexBuffer,
- unsigned indexSize,
+ struct pipe_resource *indexBuffer,
+ unsigned indexSize, int indexBias,
unsigned mode, unsigned start, unsigned count,
unsigned startInstance, unsigned instanceCount)
{
struct instance a[16];
unsigned prim = nv50_prim(mode);
- if (indexSize == 1) {
+ instance_init(nv50, a, startInstance);
+ if (!nv50_state_validate(nv50, 13 + 16*3))
+ return;
+
+ if (nv50->vbo_fifo) {
+ nv50_push_elements_instanced(pipe, indexBuffer, indexSize,
+ indexBias, mode, start, count,
+ startInstance, instanceCount);
+ return;
+ }
+
+ /* indices are uint32 internally, so large indexBias means negative */
+ BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_BASE, 1);
+ OUT_RING (chan, indexBias);
+
+ if (!nv50_resource_mapped_by_gpu(indexBuffer) || indexSize == 1) {
nv50_draw_elements_inline(pipe, indexBuffer, indexSize,
mode, start, count, startInstance,
instanceCount);
return;
}
- instance_init(nv50, a, startInstance);
- if (!nv50_state_validate(nv50, 13 + 16*3))
- return;
-
BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
OUT_RING (chan, NV50_CB_AUX | (24 << 8));
OUT_RING (chan, startInstance);
if (indexSize == 4) {
BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32 | 0x30000, 0);
OUT_RING (chan, count);
- nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
+ nouveau_pushbuf_submit(chan,
+ nv50_resource(indexBuffer)->bo,
start << 2, count << 2);
} else
if (indexSize == 2) {
OUT_RING (chan, ((start & 1) << 31) | count);
BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16 | 0x30000, 0);
OUT_RING (chan, dwords);
- nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
+ nouveau_pushbuf_submit(chan,
+ nv50_resource(indexBuffer)->bo,
vb_start << 1, dwords << 2);
BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
OUT_RING (chan, 0);
}
void
-nv50_draw_elements(struct pipe_context *pipe,
- struct pipe_buffer *indexBuffer, unsigned indexSize,
- unsigned mode, unsigned start, unsigned count)
+nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
{
- nv50_draw_elements_instanced(pipe, indexBuffer, indexSize,
- mode, start, count, 0, 1);
+ struct nv50_context *nv50 = nv50_context(pipe);
+
+ if (info->indexed && nv50->idxbuf.buffer) {
+ unsigned offset;
+
+ assert(nv50->idxbuf.offset % nv50->idxbuf.index_size == 0);
+ offset = nv50->idxbuf.offset / nv50->idxbuf.index_size;
+
+ nv50_draw_elements_instanced(pipe,
+ nv50->idxbuf.buffer,
+ nv50->idxbuf.index_size,
+ info->index_bias,
+ info->mode,
+ info->start + offset,
+ info->count,
+ info->start_instance,
+ info->instance_count);
+ }
+ else {
+ nv50_draw_arrays_instanced(pipe,
+ info->mode,
+ info->start,
+ info->count,
+ info->start_instance,
+ info->instance_count);
+ }
}
static INLINE boolean
{
struct nouveau_stateobj *so;
struct nouveau_grobj *tesla = nv50->screen->tesla;
- struct nouveau_bo *bo = nouveau_bo(vb->buffer);
+ struct nouveau_bo *bo = nv50_resource(vb->buffer)->bo;
float v[4];
int ret;
unsigned nr_components = util_format_get_nr_components(ve->src_format);
if (nv50->vtxbuf_nr == 0)
return NULL;
- assert(!NV50_USING_LOATHED_EDGEFLAG(nv50));
+ nv50->vbo_fifo = 0;
+ if (nv50->screen->force_push ||
+ nv50->vertprog->cfg.edgeflag_in < 16)
+ nv50->vbo_fifo = 0xffff;
+
+ for (i = 0; i < nv50->vtxbuf_nr; i++) {
+ if (nv50->vtxbuf[i].stride &&
+ !nv50_resource_mapped_by_gpu(nv50->vtxbuf[i].buffer))
+ nv50->vbo_fifo = 0xffff;
+ }
n_ve = MAX2(nv50->vtxelt->num_elements, nv50->state.vtxelt_nr);
struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
struct pipe_vertex_buffer *vb =
&nv50->vtxbuf[ve->vertex_buffer_index];
- struct nouveau_bo *bo = nouveau_bo(vb->buffer);
+ struct nouveau_bo *bo = nv50_resource(vb->buffer)->bo;
uint32_t hw = nv50->vtxelt->hw[i];
if (!vb->stride &&
nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
so_data(vtxfmt, hw | (1 << 4));
+ so_method(vtxbuf, tesla,
+ NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
+ so_data (vtxbuf, 0);
+
+ nv50->vbo_fifo &= ~(1 << i);
+ continue;
+ }
+
+ if (nv50->vbo_fifo) {
+ so_data (vtxfmt, hw | (ve->instance_divisor ? (1 << 4) : i));
so_method(vtxbuf, tesla,
NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
so_data (vtxbuf, 0);
/* vertex array limits */
so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
- so_reloc (vtxbuf, bo, vb->buffer->size - 1,
+ so_reloc (vtxbuf, bo, vb->buffer->width0 - 1,
NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
NOUVEAU_BO_HIGH, 0, 0);
- so_reloc (vtxbuf, bo, vb->buffer->size - 1,
+ so_reloc (vtxbuf, bo, vb->buffer->width0 - 1,
NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
NOUVEAU_BO_LOW, 0, 0);
}