- struct nouveau_grobj *tesla = nv50->screen->tesla;
- struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
- unsigned i, n_ve;
-
- /* don't validate if Gallium took away our buffers */
- if (nv50->vtxbuf_nr == 0)
- return NULL;
-
- nv50->vbo_fifo = 0;
- if (nv50->screen->force_push ||
- nv50->vertprog->vp.edgeflag < 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);
-
- vtxattr = NULL;
- vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt->num_elements * 4);
- vtxfmt = so_new(1, n_ve, 0);
- so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
-
- 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;
- 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);
- continue;
- }
-
- so_data(vtxfmt, hw | i);
-
- so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
- so_data (vtxbuf, 0x20000000 |
- (ve->instance_divisor ? 0 : vb->stride));
- so_reloc (vtxbuf, bo, vb->buffer_offset +
- ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
- NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
- so_reloc (vtxbuf, bo, vb->buffer_offset +
- ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
- NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
-
- /* vertex array limits */
- so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
- 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->width0 - 1,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
- NOUVEAU_BO_LOW, 0, 0);
- }
- for (; i < n_ve; ++i) {
- so_data (vtxfmt, 0x7e080010);
-
- so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
- so_data (vtxbuf, 0);
- }
- nv50->state.vtxelt_nr = nv50->vtxelt->num_elements;
-
- so_ref (vtxbuf, &nv50->state.vtxbuf);
- so_ref (vtxattr, &nv50->state.vtxattr);
- so_ref (NULL, &vtxbuf);
- so_ref (NULL, &vtxattr);
- return vtxfmt;
+ struct nouveau_channel *chan = nv50->screen->base.channel;
+ void *data;
+ unsigned prim;
+ const unsigned index_size = nv50->idxbuf.index_size;
+
+ chan->flush_notify = nv50_draw_vbo_flush_notify;
+ chan->user_private = nv50;
+
+ prim = nv50_prim_gl(mode);
+
+ if (index_bias != nv50->state.index_bias) {
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_BASE), 1);
+ OUT_RING (chan, index_bias);
+ nv50->state.index_bias = index_bias;
+ }
+
+ if (nouveau_resource_mapped_by_gpu(nv50->idxbuf.buffer)) {
+ struct nv04_resource *res = nv04_resource(nv50->idxbuf.buffer);
+
+ start += nv50->idxbuf.offset >> (index_size >> 1);
+
+ nouveau_buffer_adjust_score(&nv50->base, res, 1);
+
+ while (instance_count--) {
+ BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
+ OUT_RING (chan, mode);
+
+ switch (index_size) {
+ case 4:
+ {
+ WAIT_RING (chan, 2);
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32) | 0x30000, 0);
+ OUT_RING (chan, count);
+ nouveau_pushbuf_submit(chan, res->bo, res->offset + start * 4,
+ count * 4);
+ }
+ break;
+ case 2:
+ {
+ unsigned pb_start = (start & ~1);
+ unsigned pb_words = (((start + count + 1) & ~1) - pb_start) >> 1;
+
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16_SETUP), 1);
+ OUT_RING (chan, (start << 31) | count);
+ WAIT_RING (chan, 2);
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16) | 0x30000, 0);
+ OUT_RING (chan, pb_words);
+ nouveau_pushbuf_submit(chan, res->bo, res->offset + pb_start * 2,
+ pb_words * 4);
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U16_SETUP), 1);
+ OUT_RING (chan, 0);
+ break;
+ }
+ case 1:
+ {
+ unsigned pb_start = (start & ~3);
+ unsigned pb_words = (((start + count + 3) & ~3) - pb_start) >> 1;
+
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8_SETUP), 1);
+ OUT_RING (chan, (start << 30) | count);
+ WAIT_RING (chan, 2);
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8) | 0x30000, 0);
+ OUT_RING (chan, pb_words);
+ nouveau_pushbuf_submit(chan, res->bo, res->offset + pb_start,
+ pb_words * 4);
+ BEGIN_RING(chan, RING_3D(VB_ELEMENT_U8_SETUP), 1);
+ OUT_RING (chan, 0);
+ break;
+ }
+ default:
+ assert(0);
+ return;
+ }
+ BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1);
+ OUT_RING (chan, 0);
+
+ nv50_resource_fence(res, NOUVEAU_BO_RD);
+
+ mode |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
+ }
+ } else {
+ data = nouveau_resource_map_offset(&nv50->base,
+ nv04_resource(nv50->idxbuf.buffer),
+ nv50->idxbuf.offset, NOUVEAU_BO_RD);
+ if (!data)
+ return;
+
+ while (instance_count--) {
+ BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
+ OUT_RING (chan, prim);
+ switch (index_size) {
+ case 1:
+ nv50_draw_elements_inline_u08(chan, data, start, count);
+ break;
+ case 2:
+ nv50_draw_elements_inline_u16(chan, data, start, count);
+ break;
+ case 4:
+ if (shorten)
+ nv50_draw_elements_inline_u32_short(chan, data, start, count);
+ else
+ nv50_draw_elements_inline_u32(chan, data, start, count);
+ break;
+ default:
+ assert(0);
+ return;
+ }
+ BEGIN_RING(chan, RING_3D(VERTEX_END_GL), 1);
+ OUT_RING (chan, 0);
+
+ prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
+ }
+ }
+
+ chan->flush_notify = nv50_default_flush_notify;