nv30: Emit vertex buffer objects using state objects
authorPatrice Mandin <pmandin@caramail.com>
Sat, 12 Jul 2008 11:16:47 +0000 (13:16 +0200)
committerPatrice Mandin <pmandin@caramail.com>
Sat, 12 Jul 2008 11:16:47 +0000 (13:16 +0200)
src/gallium/drivers/nv30/nv30_context.h
src/gallium/drivers/nv30/nv30_screen.c
src/gallium/drivers/nv30/nv30_state.c
src/gallium/drivers/nv30/nv30_state_emit.c
src/gallium/drivers/nv30/nv30_vbo.c

index 2e7b62a69a35d04f3a2968503e903236c5b43763..823b34a7c3b3eb2abb7a3aaf7688eda6b83b999f 100644 (file)
@@ -128,20 +128,17 @@ struct nv30_context {
        struct pipe_blend_color blend_colour;
        struct pipe_viewport_state viewport;
        struct pipe_framebuffer_state framebuffer;
+       struct pipe_buffer *idxbuf;
+       unsigned idxbuf_format;
        struct nv30_sampler_state *tex_sampler[PIPE_MAX_SAMPLERS];
        struct nv30_miptree *tex_miptree[PIPE_MAX_SAMPLERS];
        unsigned nr_samplers;
        unsigned nr_textures;
        unsigned dirty_samplers;
-
-       unsigned vb_enable;
-       struct {
-               struct pipe_buffer *buffer;
-               unsigned delta;
-       } vb[16];
-
-       struct pipe_vertex_buffer  vtxbuf[PIPE_MAX_ATTRIBS];
+       struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS];
+       unsigned vtxbuf_nr;
        struct pipe_vertex_element vtxelt[PIPE_MAX_ATTRIBS];
+       unsigned vtxelt_nr;
        const unsigned *edgeflags;
 };
 
@@ -193,6 +190,7 @@ extern struct nv30_state_entry nv30_state_zsa;
 extern struct nv30_state_entry nv30_state_viewport;
 extern struct nv30_state_entry nv30_state_framebuffer;
 extern struct nv30_state_entry nv30_state_fragtex;
+extern struct nv30_state_entry nv30_state_vbo;
 
 /* nv30_vbo.c */
 extern boolean nv30_draw_arrays(struct pipe_context *, unsigned mode,
index 9c576369891dbb74b3e25d91f245a779ead2d88b..de5590af1467d9cbcfbdba5756a1c5a8ad9cbe47 100644 (file)
@@ -57,7 +57,7 @@ nv30_screen_get_param(struct pipe_screen *pscreen, int param)
                return 13;
        case NOUVEAU_CAP_HW_VTXBUF:
        case NOUVEAU_CAP_HW_IDXBUF:
-               return 0;
+               return 1;
        default:
                NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param);
                return 0;
index 4fe1def74d63b6910a0578e9369cfe7afe4d9510..4d6303ebc28c9a2fc0a501c374a2bdbfbae039a1 100644 (file)
@@ -644,7 +644,10 @@ nv30_set_vertex_buffers(struct pipe_context *pipe, unsigned count,
        struct nv30_context *nv30 = nv30_context(pipe);
 
        memcpy(nv30->vtxbuf, vb, sizeof(*vb) * count);
+       nv30->vtxbuf_nr = count;
+
        nv30->dirty |= NV30_NEW_ARRAYS;
+       /*nv30->draw_dirty |= NV30_NEW_ARRAYS;*/
 }
 
 static void
@@ -654,7 +657,10 @@ nv30_set_vertex_elements(struct pipe_context *pipe, unsigned count,
        struct nv30_context *nv30 = nv30_context(pipe);
 
        memcpy(nv30->vtxelt, ve, sizeof(*ve) * count);
+       nv30->vtxelt_nr = count;
+
        nv30->dirty |= NV30_NEW_ARRAYS;
+       /*nv30->draw_dirty |= NV30_NEW_ARRAYS;*/
 }
 
 static void
index 1e69a6a6e268d71cdd949e7d8fcdf69c9bf93254..40fed621b24037062bc1b0858eb0f73af9bea877 100644 (file)
@@ -13,6 +13,7 @@ static struct nv30_state_entry *render_states[] = {
        &nv30_state_blend_colour,
        &nv30_state_zsa,
        &nv30_state_viewport,
+       &nv30_state_vbo,
        NULL
 };
 
@@ -39,10 +40,7 @@ nv30_state_do_validate(struct nv30_context *nv30,
 
                states++;
        }
-
-/*     TODO: uncomment when finished converting
        nv30->dirty = 0;
-*/
 }
 
 void
@@ -71,6 +69,8 @@ nv30_state_emit(struct nv30_context *nv30)
                states &= ~(1ULL << i);
        }
 
+       state->dirty = 0;
+
        so_emit_reloc_markers(nv30->nvws, state->hw[NV30_STATE_FB]);
        for (i = 0, samplers = state->fp_samplers; i < 16 && samplers; i++) {
                if (!(samplers & (1 << i)))
@@ -80,6 +80,8 @@ nv30_state_emit(struct nv30_context *nv30)
                samplers &= ~(1ULL << i);
        }
        so_emit_reloc_markers(nv30->nvws, state->hw[NV30_STATE_FRAGPROG]);
+       if (state->hw[NV30_STATE_VTXBUF] /*&& nv30->render_mode == HW*/)
+               so_emit_reloc_markers(nv30->nvws, state->hw[NV30_STATE_VTXBUF]);
 }
 
 boolean
index 0f82adfee0480e10d0f185af90e9a7933d060d52..d930557f6bbe4da8443bc5441a3b4899b1f59a89 100644 (file)
 
 #include "nouveau/nouveau_channel.h"
 #include "nouveau/nouveau_pushbuf.h"
+#include "nouveau/nouveau_util.h"
+
+#define FORCE_SWTNL 0
 
 static INLINE int
-nv30_vbo_ncomp(uint format)
+nv30_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
 {
-       int ncomp = 0;
+       char fs[128];
+
+       switch (pipe) {
+       case PIPE_FORMAT_R32_FLOAT:
+       case PIPE_FORMAT_R32G32_FLOAT:
+       case PIPE_FORMAT_R32G32B32_FLOAT:
+       case PIPE_FORMAT_R32G32B32A32_FLOAT:
+               *fmt = NV34TCL_VTXFMT_TYPE_FLOAT;
+               break;
+       case PIPE_FORMAT_R8_UNORM:
+       case PIPE_FORMAT_R8G8_UNORM:
+       case PIPE_FORMAT_R8G8B8_UNORM:
+       case PIPE_FORMAT_R8G8B8A8_UNORM:
+               *fmt = NV34TCL_VTXFMT_TYPE_UBYTE;
+               break;
+       case PIPE_FORMAT_R16_SSCALED:
+       case PIPE_FORMAT_R16G16_SSCALED:
+       case PIPE_FORMAT_R16G16B16_SSCALED:
+       case PIPE_FORMAT_R16G16B16A16_SSCALED:
+               *fmt = NV34TCL_VTXFMT_TYPE_USHORT;
+               break;
+       default:
+               pf_sprint_name(fs, pipe);
+               NOUVEAU_ERR("Unknown format %s\n", fs);
+               return 1;
+       }
 
-       if (pf_size_x(format)) ncomp++;
-       if (pf_size_y(format)) ncomp++;
-       if (pf_size_z(format)) ncomp++;
-       if (pf_size_w(format)) ncomp++;
+       switch (pipe) {
+       case PIPE_FORMAT_R8_UNORM:
+       case PIPE_FORMAT_R32_FLOAT:
+       case PIPE_FORMAT_R16_SSCALED:
+               *ncomp = 1;
+               break;
+       case PIPE_FORMAT_R8G8_UNORM:
+       case PIPE_FORMAT_R32G32_FLOAT:
+       case PIPE_FORMAT_R16G16_SSCALED:
+               *ncomp = 2;
+               break;
+       case PIPE_FORMAT_R8G8B8_UNORM:
+       case PIPE_FORMAT_R32G32B32_FLOAT:
+       case PIPE_FORMAT_R16G16B16_SSCALED:
+               *ncomp = 3;
+               break;
+       case PIPE_FORMAT_R8G8B8A8_UNORM:
+       case PIPE_FORMAT_R32G32B32A32_FLOAT:
+       case PIPE_FORMAT_R16G16B16A16_SSCALED:
+               *ncomp = 4;
+               break;
+       default:
+               pf_sprint_name(fs, pipe);
+               NOUVEAU_ERR("Unknown format %s\n", fs);
+               return 1;
+       }
 
-       return ncomp;
+       return 0;
 }
 
-static INLINE int
-nv30_vbo_type(uint format)
+static boolean
+nv30_vbo_set_idxbuf(struct nv30_context *nv30, struct pipe_buffer *ib,
+                   unsigned ib_size)
 {
-       switch (pf_type(format)) {
-       case PIPE_FORMAT_TYPE_FLOAT:
-               return NV34TCL_VTXFMT_TYPE_FLOAT;
-       case PIPE_FORMAT_TYPE_UNORM:
-               return NV34TCL_VTXFMT_TYPE_UBYTE;
+       struct pipe_screen *pscreen = &nv30->screen->pipe;
+       unsigned type;
+
+       if (!ib) {
+               nv30->idxbuf = NULL;
+               nv30->idxbuf_format = 0xdeadbeef;
+               return FALSE;
+       }
+
+       if (!pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF) || ib_size == 1)
+               return FALSE;
+
+       switch (ib_size) {
+       case 2:
+               type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
+               break;
+       case 4:
+               type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
+               break;
        default:
-               NOUVEAU_ERR("Unknown format 0x%08x\n", format);
-               return NV34TCL_VTXFMT_TYPE_FLOAT;
+               return FALSE;
        }
+
+       if (ib != nv30->idxbuf ||
+           type != nv30->idxbuf_format) {
+               nv30->dirty |= NV30_NEW_ARRAYS;
+               nv30->idxbuf = ib;
+               nv30->idxbuf_format = type;
+       }
+
+       return TRUE;
 }
 
 static boolean
-nv30_vbo_static_attrib(struct nv30_context *nv30, int attrib,
-                      struct pipe_vertex_element *ve,
+nv30_vbo_static_attrib(struct nv30_context *nv30, struct nouveau_stateobj *so,
+                      int attrib, struct pipe_vertex_element *ve,
                       struct pipe_vertex_buffer *vb)
 {
        struct pipe_winsys *ws = nv30->pipe.winsys;
-       int type, ncomp;
+       struct nouveau_grobj *rankine = nv30->screen->rankine;
+       unsigned type, ncomp;
        void *map;
 
-       type = nv30_vbo_type(ve->src_format);
-       ncomp = nv30_vbo_ncomp(ve->src_format);
+       if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp))
+               return FALSE;
 
        map  = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
        map += vb->buffer_offset + ve->src_offset;
@@ -55,31 +129,28 @@ nv30_vbo_static_attrib(struct nv30_context *nv30, int attrib,
        {
                float *v = map;
 
-               BEGIN_RING(rankine, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
                switch (ncomp) {
                case 4:
-                       OUT_RINGf(v[0]);
-                       OUT_RINGf(v[1]);
-                       OUT_RINGf(v[2]);
-                       OUT_RINGf(v[3]);
+                       so_method(so, rankine, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
+                       so_data  (so, fui(v[0]));
+                       so_data  (so, fui(v[1]));
+                       so_data  (so, fui(v[2]));
+                       so_data  (so, fui(v[3]));
                        break;
                case 3:
-                       OUT_RINGf(v[0]);
-                       OUT_RINGf(v[1]);
-                       OUT_RINGf(v[2]);
-                       OUT_RINGf(1.0);
+                       so_method(so, rankine, NV34TCL_VTX_ATTR_3F_X(attrib), 3);
+                       so_data  (so, fui(v[0]));
+                       so_data  (so, fui(v[1]));
+                       so_data  (so, fui(v[2]));
                        break;
                case 2:
-                       OUT_RINGf(v[0]);
-                       OUT_RINGf(v[1]);
-                       OUT_RINGf(0.0);
-                       OUT_RINGf(1.0);
+                       so_method(so, rankine, NV34TCL_VTX_ATTR_2F_X(attrib), 2);
+                       so_data  (so, fui(v[0]));
+                       so_data  (so, fui(v[1]));
                        break;
                case 1:
-                       OUT_RINGf(v[0]);
-                       OUT_RINGf(0.0);
-                       OUT_RINGf(0.0);
-                       OUT_RINGf(1.0);
+                       so_method(so, rankine, NV34TCL_VTX_ATTR_1F(attrib), 1);
+                       so_data  (so, fui(v[0]));
                        break;
                default:
                        ws->buffer_unmap(ws, vb->buffer);
@@ -97,209 +168,202 @@ nv30_vbo_static_attrib(struct nv30_context *nv30, int attrib,
        return TRUE;
 }
 
-static void
-nv30_vbo_arrays_update(struct nv30_context *nv30)
+boolean
+nv30_draw_arrays(struct pipe_context *pipe,
+                unsigned mode, unsigned start, unsigned count)
 {
-       struct nv30_vertex_program *vp = nv30->vertprog;
-       uint32_t inputs, vtxfmt[16];
-       int hw, num_hw = 0;
-
-       nv30->vb_enable = 0;
+       struct nv30_context *nv30 = nv30_context(pipe);
+       struct nouveau_channel *chan = nv30->nvws->channel;
+       unsigned restart = 0;
 
-       inputs = vp->ir;
-       for (hw = 0; hw < 16 && inputs; hw++) {
-               if (inputs & (1 << hw)) {
-                       num_hw = hw;
-                       inputs &= ~(1 << hw);
-               }
+       nv30_vbo_set_idxbuf(nv30, NULL, 0);
+       if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
+               /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
+                                               mode, start, count);*/
+               return FALSE;
        }
-       num_hw++;
 
-       inputs = vp->ir;
-       for (hw = 0; hw < num_hw; hw++) {
-               struct pipe_vertex_element *ve;
-               struct pipe_vertex_buffer *vb;
+       while (count) {
+               unsigned vc, nr;
 
-               if (!(inputs & (1 << hw))) {
-                       vtxfmt[hw] = NV34TCL_VTXFMT_TYPE_FLOAT;
+               nv30_state_emit(nv30);
+
+               vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
+                                       mode, start, count, &restart);
+               if (!vc) {
+                       FIRE_RING(NULL);
                        continue;
                }
 
-               ve = &nv30->vtxelt[hw];
-               vb = &nv30->vtxbuf[ve->vertex_buffer_index];
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (nvgl_primitive(mode));
 
-               if (vb->pitch == 0) {
-                       vtxfmt[hw] = NV34TCL_VTXFMT_TYPE_FLOAT;
-                       if (nv30_vbo_static_attrib(nv30, hw, ve, vb) == TRUE)
-                               continue;
+               nr = (vc & 0xff);
+               if (nr) {
+                       BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
+                       OUT_RING  (((nr - 1) << 24) | start);
+                       start += nr;
                }
 
-               nv30->vb_enable |= (1 << hw);
-               nv30->vb[hw].delta = vb->buffer_offset + ve->src_offset;
-               nv30->vb[hw].buffer = vb->buffer;
+               nr = vc >> 8;
+               while (nr) {
+                       unsigned push = nr > 2047 ? 2047 : nr;
+
+                       nr -= push;
 
-               vtxfmt[hw] = ((vb->pitch << NV34TCL_VTXFMT_STRIDE_SHIFT) |
-                             (nv30_vbo_ncomp(ve->src_format) <<
-                              NV34TCL_VTXFMT_SIZE_SHIFT) |
-                             nv30_vbo_type(ve->src_format));
+                       BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
+                       while (push--) {
+                               OUT_RING(((0x100 - 1) << 24) | start);
+                               start += 0x100;
+                       }
+               }
+
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (0);
+
+               count -= vc;
+               start = restart;
        }
 
-       BEGIN_RING(rankine, NV34TCL_VTXFMT(0), num_hw);
-       OUT_RINGp (vtxfmt, num_hw);
+       pipe->flush(pipe, 0, NULL);
+       return TRUE;
 }
 
-static boolean
-nv30_vbo_validate_state(struct nv30_context *nv30,
-                       struct pipe_buffer *ib, unsigned ib_format)
+static INLINE void
+nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
+                      unsigned mode, unsigned start, unsigned count)
 {
-       unsigned inputs;
+       struct nouveau_channel *chan = nv30->nvws->channel;
 
-       nv30_state_validate(nv30);
+       while (count) {
+               uint8_t *elts = (uint8_t *)ib + start;
+               unsigned vc, push, restart = 0;
 
-       nv30_state_emit(nv30);
+               nv30_state_emit(nv30);
 
-       if (nv30->dirty & NV30_NEW_ARRAYS) {
-               nv30_vbo_arrays_update(nv30);
-               nv30->dirty &= ~NV30_NEW_ARRAYS;
-       }
+               vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
+                                       mode, start, count, &restart);
+               if (vc == 0) {
+                       FIRE_RING(NULL);
+                       continue;
+               }
+               count -= vc;
 
-       inputs = nv30->vb_enable;
-       while (inputs) {
-               unsigned a = ffs(inputs) - 1;
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (nvgl_primitive(mode));
 
-               inputs &= ~(1 << a);
+               if (vc & 1) {
+                       BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
+                       OUT_RING  (elts[0]);
+                       elts++; vc--;
+               }
 
-               BEGIN_RING(rankine, NV34TCL_VTXBUF_ADDRESS(a), 1);
-               OUT_RELOC (nv30->vb[a].buffer, nv30->vb[a].delta,
-                          NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_LOW |
-                          NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
-                          NV34TCL_VTXBUF_ADDRESS_DMA1);
-       }
+               while (vc) {
+                       unsigned i;
 
-       if (ib) {
-               BEGIN_RING(rankine, NV34TCL_IDXBUF_ADDRESS, 2);
-               OUT_RELOCl(ib, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
-                          NOUVEAU_BO_RD);
-               OUT_RELOCd(ib, ib_format, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
-                          NOUVEAU_BO_RD | NOUVEAU_BO_OR,
-                          0, NV34TCL_IDXBUF_FORMAT_DMA1);
-       }
+                       push = MIN2(vc, 2047 * 2);
 
-       BEGIN_RING(rankine, 0x1710, 1);
-       OUT_RING  (0); /* vtx cache flush */
+                       BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
+                       for (i = 0; i < push; i+=2)
+                               OUT_RING((elts[i+1] << 16) | elts[i]);
 
-       return TRUE;
-}
+                       vc -= push;
+                       elts += push;
+               }
 
-boolean
-nv30_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
-                unsigned count)
-{
-       struct nv30_context *nv30 = nv30_context(pipe);
-       unsigned nr;
-       boolean ret;
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (0);
 
-       ret = nv30_vbo_validate_state(nv30, NULL, 0);
-       if (!ret) {
-               NOUVEAU_ERR("state validate failed\n");
-               return FALSE;
+               start = restart;
        }
+}
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (nvgl_primitive(mode));
-
-       nr = (count & 0xff);
-       if (nr) {
-               BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
-               OUT_RING  (((nr - 1) << 24) | start);
-               start += nr;
-       }
+static INLINE void
+nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
+                      unsigned mode, unsigned start, unsigned count)
+{
+       struct nouveau_channel *chan = nv30->nvws->channel;
 
-       nr = count >> 8;
-       while (nr) {
-               unsigned push = nr > 2047 ? 2047 : nr;
+       while (count) {
+               uint16_t *elts = (uint16_t *)ib + start;
+               unsigned vc, push, restart = 0;
 
-               nr -= push;
+               nv30_state_emit(nv30);
 
-               BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
-               while (push--) {
-                       OUT_RING(((0x100 - 1) << 24) | start);
-                       start += 0x100;
+               vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
+                                       mode, start, count, &restart);
+               if (vc == 0) {
+                       FIRE_RING(NULL);
+                       continue;
                }
-       }
+               count -= vc;
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (0);
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (nvgl_primitive(mode));
 
-       pipe->flush(pipe, 0, NULL);
-       return TRUE;
-}
+               if (vc & 1) {
+                       BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
+                       OUT_RING  (elts[0]);
+                       elts++; vc--;
+               }
 
-static INLINE void
-nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
-                      unsigned start, unsigned count)
-{
-       uint8_t *elts = (uint8_t *)ib + start;
-       int push, i;
+               while (vc) {
+                       unsigned i;
 
-       if (count & 1) {
-               BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
-               OUT_RING  (elts[0]);
-               elts++; count--;
-       }
+                       push = MIN2(vc, 2047 * 2);
 
-       while (count) {
-               push = MIN2(count, 2047 * 2);
+                       BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
+                       for (i = 0; i < push; i+=2)
+                               OUT_RING((elts[i+1] << 16) | elts[i]);
 
-               BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
-               for (i = 0; i < push; i+=2)
-                       OUT_RING((elts[i+1] << 16) | elts[i]);
+                       vc -= push;
+                       elts += push;
+               }
+
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (0);
 
-               count -= push;
-               elts  += push;
+               start = restart;
        }
 }
 
 static INLINE void
-nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
-                      unsigned start, unsigned count)
+nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
+                      unsigned mode, unsigned start, unsigned count)
 {
-       uint16_t *elts = (uint16_t *)ib + start;
-       int push, i;
-
-       if (count & 1) {
-               BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
-               OUT_RING  (elts[0]);
-               elts++; count--;
-       }
+       struct nouveau_channel *chan = nv30->nvws->channel;
 
        while (count) {
-               push = MIN2(count, 2047 * 2);
+               uint32_t *elts = (uint32_t *)ib + start;
+               unsigned vc, push, restart = 0;
 
-               BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
-               for (i = 0; i < push; i+=2)
-                       OUT_RING((elts[i+1] << 16) | elts[i]);
+               nv30_state_emit(nv30);
 
-               count -= push;
-               elts  += push;
-       }
-}
+               vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
+                                       mode, start, count, &restart);
+               if (vc == 0) {
+                       FIRE_RING(NULL);
+                       continue;
+               }
+               count -= vc;
 
-static INLINE void
-nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
-                      unsigned start, unsigned count)
-{
-       uint32_t *elts = (uint32_t *)ib + start;
-       int push;
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (nvgl_primitive(mode));
 
-       while (count) {
-               push = MIN2(count, 2047);
+               while (vc) {
+                       push = MIN2(vc, 2047);
 
-               BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
-               OUT_RINGp    (elts, push);
+                       BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
+                       OUT_RINGp    (elts, push);
 
-               count -= push;
-               elts  += push;
+                       vc -= push;
+                       elts += push;
+               }
+
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (0);
+
+               start = restart;
        }
 }
 
@@ -310,99 +374,82 @@ nv30_draw_elements_inline(struct pipe_context *pipe,
 {
        struct nv30_context *nv30 = nv30_context(pipe);
        struct pipe_winsys *ws = pipe->winsys;
-       boolean ret;
        void *map;
 
-       ret =  nv30_vbo_validate_state(nv30, NULL, 0);
-       if (!ret) {
-               NOUVEAU_ERR("state validate failed\n");
-               return FALSE;
-       }
-
        map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
        if (!ib) {
                NOUVEAU_ERR("failed mapping ib\n");
                return FALSE;
        }
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (nvgl_primitive(mode));
-
        switch (ib_size) {
        case 1:
-               nv30_draw_elements_u08(nv30, map, start, count);
+               nv30_draw_elements_u08(nv30, map, mode, start, count);
                break;
        case 2:
-               nv30_draw_elements_u16(nv30, map, start, count);
+               nv30_draw_elements_u16(nv30, map, mode, start, count);
                break;
        case 4:
-               nv30_draw_elements_u32(nv30, map, start, count);
+               nv30_draw_elements_u32(nv30, map, mode, start, count);
                break;
        default:
                NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
                break;
        }
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (0);
-
        ws->buffer_unmap(ws, ib);
-
        return TRUE;
 }
 
 static boolean
 nv30_draw_elements_vbo(struct pipe_context *pipe,
-                      struct pipe_buffer *ib, unsigned ib_size,
                       unsigned mode, unsigned start, unsigned count)
 {
        struct nv30_context *nv30 = nv30_context(pipe);
-       unsigned nr, type;
-       boolean ret;
-
-       switch (ib_size) {
-       case 2:
-               type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
-               break;
-       case 4:
-               type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
-               break;
-       default:
-               NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
-               return FALSE;
-       }
+       struct nouveau_channel *chan = nv30->nvws->channel;
+       unsigned restart = 0;
 
-       ret = nv30_vbo_validate_state(nv30, ib, type);
-       if (!ret) {
-               NOUVEAU_ERR("failed state validation\n");
-               return FALSE;
-       }
+       while (count) {
+               unsigned nr, vc;
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (nvgl_primitive(mode));
+               nv30_state_emit(nv30);
 
-       nr = (count & 0xff);
-       if (nr) {
-               BEGIN_RING(rankine, NV34TCL_VB_INDEX_BATCH, 1);
-               OUT_RING  (((nr - 1) << 24) | start);
-               start += nr;
-       }
+               vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
+                                       mode, start, count, &restart);
+               if (!vc) {
+                       FIRE_RING(NULL);
+                       continue;
+               }
+               
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (nvgl_primitive(mode));
+
+               nr = (vc & 0xff);
+               if (nr) {
+                       BEGIN_RING(rankine, NV34TCL_VB_INDEX_BATCH, 1);
+                       OUT_RING  (((nr - 1) << 24) | start);
+                       start += nr;
+               }
 
-       nr = count >> 8;
-       while (nr) {
-               unsigned push = nr > 2047 ? 2047 : nr;
+               nr = vc >> 8;
+               while (nr) {
+                       unsigned push = nr > 2047 ? 2047 : nr;
 
-               nr -= push;
+                       nr -= push;
 
-               BEGIN_RING_NI(rankine, NV34TCL_VB_INDEX_BATCH, push);
-               while (push--) {
-                       OUT_RING(((0x100 - 1) << 24) | start);
-                       start += 0x100;
+                       BEGIN_RING_NI(rankine, NV34TCL_VB_INDEX_BATCH, push);
+                       while (push--) {
+                               OUT_RING(((0x100 - 1) << 24) | start);
+                               start += 0x100;
+                       }
                }
-       }
 
-       BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
-       OUT_RING  (0);
+               BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
+               OUT_RING  (0);
+
+               count -= vc;
+               start = restart;
+       }
 
        return TRUE;
 }
@@ -412,10 +459,19 @@ nv30_draw_elements(struct pipe_context *pipe,
                   struct pipe_buffer *indexBuffer, unsigned indexSize,
                   unsigned mode, unsigned start, unsigned count)
 {
-/*     if (indexSize != 1) {
-               nv30_draw_elements_vbo(pipe, indexBuffer, indexSize,
-                                      mode, start, count);
-       } else */{
+       struct nv30_context *nv30 = nv30_context(pipe);
+       boolean idxbuf;
+
+       idxbuf = nv30_vbo_set_idxbuf(nv30, indexBuffer, indexSize);
+       if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
+               /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
+                                               mode, start, count);*/
+               return FALSE;   
+       }
+
+       if (idxbuf) {
+               nv30_draw_elements_vbo(pipe, mode, start, count);
+       } else {
                nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
                                          mode, start, count);
        }
@@ -424,4 +480,82 @@ nv30_draw_elements(struct pipe_context *pipe,
        return TRUE;
 }
 
+static boolean
+nv30_vbo_validate(struct nv30_context *nv30)
+{
+       struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
+       struct nouveau_grobj *rankine = nv30->screen->rankine;
+       struct pipe_buffer *ib = nv30->idxbuf;
+       unsigned ib_format = nv30->idxbuf_format;
+       unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
+       int hw;
+
+       if (nv30->edgeflags) {
+               /*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
+               return FALSE;
+       }
+
+       vtxbuf = so_new(20, 18);
+       so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
+       vtxfmt = so_new(17, 0);
+       so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
 
+       for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
+               struct pipe_vertex_element *ve;
+               struct pipe_vertex_buffer *vb;
+               unsigned type, ncomp;
+
+               ve = &nv30->vtxelt[hw];
+               vb = &nv30->vtxbuf[ve->vertex_buffer_index];
+
+               if (!vb->pitch) {
+                       if (!sattr)
+                               sattr = so_new(16 * 5, 0);
+
+                       if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
+                               so_data(vtxbuf, 0);
+                               so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
+                               continue;
+                       }
+               }
+
+               if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
+                       /*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
+                       so_ref(NULL, &vtxbuf);
+                       so_ref(NULL, &vtxfmt);
+                       return FALSE;
+               }
+
+               so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
+                        vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
+                        0, NV34TCL_VTXBUF_ADDRESS_DMA1);
+               so_data (vtxfmt, ((vb->pitch << NV34TCL_VTXFMT_STRIDE_SHIFT) |
+                                 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
+       }
+
+       if (ib) {
+               so_method(vtxbuf, rankine, NV34TCL_IDXBUF_ADDRESS, 2);
+               so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
+               so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
+                         0, NV34TCL_IDXBUF_FORMAT_DMA1);
+       }
+
+       so_method(vtxbuf, rankine, 0x1710, 1);
+       so_data  (vtxbuf, 0);
+
+       so_ref(vtxbuf, &nv30->state.hw[NV30_STATE_VTXBUF]);
+       nv30->state.dirty |= (1ULL << NV30_STATE_VTXBUF);
+       so_ref(vtxfmt, &nv30->state.hw[NV30_STATE_VTXFMT]);
+       nv30->state.dirty |= (1ULL << NV30_STATE_VTXFMT);
+       so_ref(sattr, &nv30->state.hw[NV30_STATE_VTXATTR]);
+       nv30->state.dirty |= (1ULL << NV30_STATE_VTXATTR);
+       return FALSE;
+}
+
+struct nv30_state_entry nv30_state_vbo = {
+       .validate = nv30_vbo_validate,
+       .dirty = {
+               .pipe = NV30_NEW_ARRAYS,
+               .hw = 0,
+       }
+};