nouveau: rewrite nouveau_stateobj to use BEGIN_RING properly
authorMaarten Maathuis <madman2003@gmail.com>
Tue, 29 Dec 2009 22:59:08 +0000 (23:59 +0100)
committerMaarten Maathuis <madman2003@gmail.com>
Tue, 5 Jan 2010 18:13:34 +0000 (19:13 +0100)
- The previous solution was hacky and didn't do subchannel autobinding.
- The beheaviour should match what libdrm_nouveau does closely.
- The solution remains statically sized, but when debugging is on it will check
for abuse.

Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
31 files changed:
src/gallium/drivers/nouveau/nouveau_stateobj.h
src/gallium/drivers/nv10/nv10_screen.c
src/gallium/drivers/nv20/nv20_screen.c
src/gallium/drivers/nv30/nv30_fragprog.c
src/gallium/drivers/nv30/nv30_fragtex.c
src/gallium/drivers/nv30/nv30_screen.c
src/gallium/drivers/nv30/nv30_state.c
src/gallium/drivers/nv30/nv30_state_blend.c
src/gallium/drivers/nv30/nv30_state_fb.c
src/gallium/drivers/nv30/nv30_state_scissor.c
src/gallium/drivers/nv30/nv30_state_stipple.c
src/gallium/drivers/nv30/nv30_state_viewport.c
src/gallium/drivers/nv30/nv30_vbo.c
src/gallium/drivers/nv30/nv30_vertprog.c
src/gallium/drivers/nv40/nv40_fragprog.c
src/gallium/drivers/nv40/nv40_fragtex.c
src/gallium/drivers/nv40/nv40_screen.c
src/gallium/drivers/nv40/nv40_state.c
src/gallium/drivers/nv40/nv40_state_blend.c
src/gallium/drivers/nv40/nv40_state_fb.c
src/gallium/drivers/nv40/nv40_state_scissor.c
src/gallium/drivers/nv40/nv40_state_stipple.c
src/gallium/drivers/nv40/nv40_state_viewport.c
src/gallium/drivers/nv40/nv40_vbo.c
src/gallium/drivers/nv40/nv40_vertprog.c
src/gallium/drivers/nv50/nv50_program.c
src/gallium/drivers/nv50/nv50_screen.c
src/gallium/drivers/nv50/nv50_state.c
src/gallium/drivers/nv50/nv50_state_validate.c
src/gallium/drivers/nv50/nv50_tex.c
src/gallium/drivers/nv50/nv50_vbo.c

index 77ff7dcf20967a9b8bf20ebc228ce97aa4b7a50a..e844f6abb3dcc120747295a9a704ae49cd06390e 100644 (file)
@@ -3,41 +3,95 @@
 
 #include "util/u_debug.h"
 
+#ifdef DEBUG
+#define DEBUG_NOUVEAU_STATEOBJ
+#endif /* DEBUG */
+
 struct nouveau_stateobj_reloc {
        struct nouveau_bo *bo;
 
-       unsigned offset;
-       unsigned packet;
+       struct nouveau_grobj *gr;
+       uint32_t push_offset;
+       uint32_t mthd;
 
-       unsigned data;
+       uint32_t data;
        unsigned flags;
        unsigned vor;
        unsigned tor;
 };
 
+struct nouveau_stateobj_start {
+       struct nouveau_grobj *gr;
+       uint32_t mthd;
+       uint32_t size;
+       unsigned offset;
+};
+
 struct nouveau_stateobj {
        struct pipe_reference reference;
 
-       unsigned *push;
+       struct nouveau_stateobj_start *start;
        struct nouveau_stateobj_reloc *reloc;
 
-       unsigned *cur;
-       unsigned cur_packet;
+       /* Common memory pool for data. */
+       uint32_t *pool;
+       unsigned pool_cur;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       unsigned start_alloc;
+       unsigned reloc_alloc;
+       unsigned pool_alloc;
+#endif  /* DEBUG_NOUVEAU_STATEOBJ */
+
+       unsigned total; /* includes begin_ring */
+       unsigned cur; /* excludes begin_ring, offset from "cur_start" */
+       unsigned cur_start;
        unsigned cur_reloc;
 };
 
+static INLINE void
+so_dump(struct nouveau_stateobj *so)
+{
+       unsigned i, nr, total = 0;
+
+       for (i = 0; i < so->cur_start; i++) {
+               if (so->start[i].gr->subc > -1)
+                       debug_printf("+0x%04x: 0x%08x\n", total++,
+                               (so->start[i].size << 18) | (so->start[i].gr->subc << 13)
+                               | so->start[i].mthd);
+               else
+                       debug_printf("+0x%04x: 0x%08x\n", total++,
+                               (so->start[i].size << 18) | so->start[i].mthd);
+               for (nr = 0; nr < so->start[i].size; nr++, total++)
+                       debug_printf("+0x%04x: 0x%08x\n", total,
+                               so->pool[so->start[i].offset + nr]);
+       }
+}
+
 static INLINE struct nouveau_stateobj *
-so_new(unsigned push, unsigned reloc)
+so_new(unsigned start, unsigned push, unsigned reloc)
 {
        struct nouveau_stateobj *so;
 
        so = MALLOC(sizeof(struct nouveau_stateobj));
        pipe_reference_init(&so->reference, 1);
-       so->push = MALLOC(sizeof(unsigned) * push);
-       so->reloc = MALLOC(sizeof(struct nouveau_stateobj_reloc) * reloc);
-
-       so->cur = so->push;
-       so->cur_reloc = so->cur_packet = 0;
+       so->total = so->cur = so->cur_start = so->cur_reloc = 0;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       so->start_alloc = start;
+       so->reloc_alloc = reloc;
+       so->pool_alloc = push;
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+       so->start = MALLOC(start * sizeof(struct nouveau_stateobj_start));
+       so->reloc = MALLOC(reloc * sizeof(struct nouveau_stateobj_reloc));
+       so->pool = MALLOC(push * sizeof(uint32_t));
+       so->pool_cur = 0;
+
+       if (!so->start || !so->reloc || !so->pool) {
+               debug_printf("malloc failed\n");
+               assert(0);
+       }
 
        return so;
 }
@@ -48,54 +102,115 @@ so_ref(struct nouveau_stateobj *ref, struct nouveau_stateobj **pso)
        struct nouveau_stateobj *so = *pso;
        int i;
 
-        if (pipe_reference(&(*pso)->reference, &ref->reference)) {
-               free(so->push);
+       if (pipe_reference(&(*pso)->reference, &ref->reference)) {
+               FREE(so->start);
                for (i = 0; i < so->cur_reloc; i++)
                        nouveau_bo_ref(NULL, &so->reloc[i].bo);
-               free(so->reloc);
-               free(so);
+               FREE(so->reloc);
+               FREE(so->pool);
+               FREE(so);
        }
        *pso = ref;
 }
 
 static INLINE void
-so_data(struct nouveau_stateobj *so, unsigned data)
+so_data(struct nouveau_stateobj *so, uint32_t data)
 {
-       (*so->cur++) = (data);
-       so->cur_packet += 4;
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->cur >= so->start[so->cur_start - 1].size) {
+               debug_printf("exceeding specified size\n");
+               assert(0);
+       }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+       so->pool[so->start[so->cur_start - 1].offset + so->cur++] = data;
 }
 
 static INLINE void
-so_datap(struct nouveau_stateobj *so, unsigned *data, unsigned size)
+so_datap(struct nouveau_stateobj *so, uint32_t *data, unsigned size)
 {
-       so->cur_packet += (4 * size);
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if ((so->cur + size) > so->start[so->cur_start - 1].size) {
+               debug_printf("exceeding specified size\n");
+               assert(0);
+       }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
        while (size--)
-               (*so->cur++) = (*data++);
+               so->pool[so->start[so->cur_start - 1].offset + so->cur++] =
+                       *data++;
 }
 
 static INLINE void
 so_method(struct nouveau_stateobj *so, struct nouveau_grobj *gr,
          unsigned mthd, unsigned size)
 {
-       so->cur_packet = (gr->subc << 13) | (1 << 18) | (mthd - 4);
-       so_data(so, (gr->subc << 13) | (size << 18) | mthd);
+       struct nouveau_stateobj_start *start;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->start_alloc <= so->cur_start) {
+               debug_printf("exceeding num_start size\n");
+               assert(0);
+       } else
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+               start = so->start;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->cur_start > 0 && start[so->cur_start - 1].size > so->cur) {
+               debug_printf("previous so_method was not filled\n");
+               assert(0);
+       }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+       so->start = start;
+       start[so->cur_start].gr = gr;
+       start[so->cur_start].mthd = mthd;
+       start[so->cur_start].size = size;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->pool_alloc < (size + so->pool_cur)) {
+               debug_printf("exceeding num_pool size\n");
+               assert(0);
+       }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+       start[so->cur_start].offset = so->pool_cur;
+       so->pool_cur += size;
+
+       so->cur_start++;
+       /* The 1 is for *this* begin_ring. */
+       so->total += so->cur + 1;
+       so->cur = 0;
 }
 
 static INLINE void
 so_reloc(struct nouveau_stateobj *so, struct nouveau_bo *bo,
         unsigned data, unsigned flags, unsigned vor, unsigned tor)
 {
-       struct nouveau_stateobj_reloc *r = &so->reloc[so->cur_reloc++];
-       
-       r->bo = NULL;
-       nouveau_bo_ref(bo, &r->bo);
-       r->offset = so->cur - so->push;
-       r->packet = so->cur_packet;
-       r->data = data;
-       r->flags = flags;
-       r->vor = vor;
-       r->tor = tor;
+       struct nouveau_stateobj_reloc *r;
+
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->reloc_alloc <= so->cur_reloc) {
+               debug_printf("exceeding num_reloc size\n");
+               assert(0);
+       } else
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+               r = so->reloc;
+
+       so->reloc = r;
+       r[so->cur_reloc].bo = NULL;
+       nouveau_bo_ref(bo, &(r[so->cur_reloc].bo));
+       r[so->cur_reloc].gr = so->start[so->cur_start-1].gr;
+       r[so->cur_reloc].push_offset = so->total + so->cur;
+       r[so->cur_reloc].data = data;
+       r[so->cur_reloc].flags = flags;
+       r[so->cur_reloc].mthd = so->start[so->cur_start-1].mthd +
+                                                       (so->cur << 2);
+       r[so->cur_reloc].vor = vor;
+       r[so->cur_reloc].tor = tor;
+
        so_data(so, data);
+       so->cur_reloc++;
 }
 
 /* Determine if this buffer object is referenced by this state object. */
@@ -111,15 +226,6 @@ so_bo_is_reloc(struct nouveau_stateobj *so, struct nouveau_bo *bo)
        return false;
 }
 
-static INLINE void
-so_dump(struct nouveau_stateobj *so)
-{
-       unsigned i, nr = so->cur - so->push;
-
-       for (i = 0; i < nr; i++)
-               debug_printf("+0x%04x: 0x%08x\n", i, so->push[i]);
-}
-
 static INLINE void
 so_emit(struct nouveau_channel *chan, struct nouveau_stateobj *so)
 {
@@ -127,75 +233,93 @@ so_emit(struct nouveau_channel *chan, struct nouveau_stateobj *so)
        unsigned nr, i;
        int ret = 0;
 
-       nr = so->cur - so->push;
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+       if (so->start[so->cur_start - 1].size > so->cur) {
+               debug_printf("emit: previous so_method was not filled\n");
+               assert(0);
+       }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+       /* We cannot update total in case we so_emit again. */
+       nr = so->total + so->cur;
+
        /* This will flush if we need space.
         * We don't actually need the marker.
         */
        if ((ret = nouveau_pushbuf_marker_emit(chan, nr, so->cur_reloc))) {
                debug_printf("so_emit failed marker emit with error %d\n", ret);
-               return;
+               assert(0);
+       }
+
+       /* Submit data. This will ensure proper binding of objects. */
+       for (i = 0; i < so->cur_start; i++) {
+               BEGIN_RING(chan, so->start[i].gr, so->start[i].mthd, so->start[i].size);
+               OUT_RINGp(chan, &(so->pool[so->start[i].offset]), so->start[i].size);
        }
-       pb->remaining -= nr;
 
-       memcpy(pb->cur, so->push, nr * 4);
        for (i = 0; i < so->cur_reloc; i++) {
                struct nouveau_stateobj_reloc *r = &so->reloc[i];
 
-               if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur + r->offset,
-                                          r->bo, r->data, 0, r->flags,
-                                          r->vor, r->tor))) {
+               if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur - nr +
+                                               r->push_offset, r->bo, r->data,
+                                               0, r->flags, r->vor, r->tor))) {
                        debug_printf("so_emit failed reloc with error %d\n", ret);
-                       goto out;
+                       assert(0);
                }
        }
-out:
-       pb->cur += nr;
 }
 
 static INLINE void
 so_emit_reloc_markers(struct nouveau_channel *chan, struct nouveau_stateobj *so)
 {
        struct nouveau_pushbuf *pb = chan->pushbuf;
+       struct nouveau_grobj *gr = NULL;
        unsigned i;
        int ret = 0;
 
        if (!so)
                return;
 
-       i = so->cur_reloc << 1;
-       /* This will flush if we need space.
-        * We don't actually need the marker.
-        */
-       if ((ret = nouveau_pushbuf_marker_emit(chan, i, i))) {
-               debug_printf("so_emit_reloc_markers failed marker emit with" \
-                       "error %d\n", ret);
-               return;
-       }
-       pb->remaining -= i;
-
+       /* If we need to flush in flush notify, then we have a problem anyway. */
        for (i = 0; i < so->cur_reloc; i++) {
                struct nouveau_stateobj_reloc *r = &so->reloc[i];
 
-               if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo,
-                                          r->packet, 0,
-                                          (r->flags & (NOUVEAU_BO_VRAM |
-                                                       NOUVEAU_BO_GART |
-                                                       NOUVEAU_BO_RDWR)) |
-                                          NOUVEAU_BO_DUMMY, 0, 0))) {
-                       debug_printf("so_emit_reloc_markers failed reloc" \
-                                               "with error %d\n", ret);
-                       pb->remaining += ((so->cur_reloc - i) << 1);
-                       return;
+#ifdef DEBUG_NOUVEAU_STATEOBJ
+               if (r->mthd & 0x40000000) {
+                       debug_printf("error: NI mthd 0x%08X\n", r->mthd);
+                       continue;
+               }
+#endif /* DEBUG_NOUVEAU_STATEOBJ */
+
+               /* The object needs to be bound and the system must know the
+                * subchannel is being used. Otherwise it will discard it.
+                */
+               if (gr != r->gr) {
+                       BEGIN_RING(chan, r->gr, 0x100, 1);
+                       OUT_RING(chan, 0);
+                       gr = r->gr;
+               }
+
+               /* Some relocs really don't like to be hammered,
+                * NOUVEAU_BO_DUMMY makes sure it only
+                * happens when needed.
+                */
+               ret = OUT_RELOC(chan, r->bo, (r->gr->subc << 13) | (1<< 18) |
+                       r->mthd, (r->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART
+                               | NOUVEAU_BO_RDWR)) | NOUVEAU_BO_DUMMY, 0, 0);
+               if (ret) {
+                       debug_printf("OUT_RELOC failed %d\n", ret);
+                       assert(0);
                }
-               if ((ret = nouveau_pushbuf_emit_reloc(chan, pb->cur++, r->bo,
-                                          r->data, 0,
-                                          r->flags | NOUVEAU_BO_DUMMY,
-                                          r->vor, r->tor))) {
-                       debug_printf("so_emit_reloc_markers failed reloc" \
-                                               "with error %d\n", ret);
-                       pb->remaining += ((so->cur_reloc - i) << 1) - 1;
-                       return;
+
+               ret = OUT_RELOC(chan, r->bo, r->data, r->flags |
+                       NOUVEAU_BO_DUMMY, r->vor, r->tor);
+               if (ret) {
+                       debug_printf("OUT_RELOC failed %d\n", ret);
+                       assert(0);
                }
+
+               pb->remaining -= 2;
        }
 }
 
index 6a39ddeaacb282d833d37b3ee668bea34b1f8daa..69a6dab866a6f3c2c6e0f74f0672f2fa6cd92b7e 100644 (file)
@@ -180,7 +180,6 @@ nv10_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
                return FALSE;
        }
-       BIND_RING(chan, screen->celsius, 7);
 
        /* 2D engine setup */
        screen->eng2d = nv04_surface_2d_init(&screen->base);
index a0973f1ebdc3ce184796b5abf7833df97f29c5d8..d091335063b9ba668b73a012966b5f95764fcd84 100644 (file)
@@ -176,7 +176,6 @@ nv20_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
                return FALSE;
        }
-       BIND_RING(chan, screen->kelvin, 7);
 
        /* 2D engine setup */
        screen->eng2d = nv04_surface_2d_init(&screen->base);
index d1ff18e2dfb0b843013fce59bf4528f46cfcabc5..2d565cb631b66d221d8f958f65b23a17c9f42f53 100644 (file)
@@ -837,7 +837,7 @@ nv30_fragprog_validate(struct nv30_context *nv30)
        fp->buffer = pscreen->buffer_create(pscreen, 0x100, 0, fp->insn_len * 4);
        nv30_fragprog_upload(nv30, fp);
 
-       so = so_new(8, 1);
+       so = so_new(4, 4, 1);
        so_method(so, nv30->screen->rankine, NV34TCL_FP_ACTIVE_PROGRAM, 1);
        so_reloc (so, nouveau_bo(fp->buffer), 0, NOUVEAU_BO_VRAM |
                      NOUVEAU_BO_GART | NOUVEAU_BO_RD | NOUVEAU_BO_LOW |
index b3293ee700dc7ab023bb1939d699115b0557cbc1..989356789114baa0dc5ca2da98ca402254854f02 100644 (file)
@@ -106,7 +106,7 @@ nv30_fragtex_build(struct nv30_context *nv30, int unit)
 
        txs = tf->swizzle;
 
-       so = so_new(16, 2);
+       so = so_new(1, 8, 2);
        so_method(so, nv30->screen->rankine, NV34TCL_TX_OFFSET(unit), 8);
        so_reloc (so, bo, 0, tex_flags | NOUVEAU_BO_LOW, 0, 0);
        so_reloc (so, bo, txf, tex_flags | NOUVEAU_BO_OR,
@@ -135,7 +135,7 @@ nv30_fragtex_validate(struct nv30_context *nv30)
                unit = ffs(samplers) - 1;
                samplers &= ~(1 << unit);
 
-               so = so_new(2, 0);
+               so = so_new(1, 1, 0);
                so_method(so, nv30->screen->rankine, NV34TCL_TX_ENABLE(unit), 1);
                so_data  (so, 0);
                so_ref(so, &nv30->state.hw[NV30_STATE_FRAGTEX0 + unit]);
index 760467f73673db14a3e8f547935d422a0b536b79..9ed48178dc2b6d12bf26c8f41abcb6b64e1a4325 100644 (file)
@@ -233,7 +233,6 @@ nv30_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
                return FALSE;
        }
-       BIND_RING(chan, screen->rankine, 7);
 
        /* 2D engine setup */
        screen->eng2d = nv04_surface_2d_init(&screen->base);
@@ -270,7 +269,7 @@ nv30_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        }
 
        /* Static rankine initialisation */
-       so = so_new(128, 0);
+       so = so_new(36, 60, 0);
        so_method(so, screen->rankine, NV34TCL_DMA_NOTIFY, 1);
        so_data  (so, screen->sync->handle);
        so_method(so, screen->rankine, NV34TCL_DMA_TEXTURE0, 2);
index e6321b480f6f55cc96d3082da5d40493404cf3a3..a80dfb04880db04a30967706ca72d083e3546eb7 100644 (file)
@@ -14,7 +14,7 @@ nv30_blend_state_create(struct pipe_context *pipe,
        struct nv30_context *nv30 = nv30_context(pipe);
        struct nouveau_grobj *rankine = nv30->screen->rankine;
        struct nv30_blend_state *bso = CALLOC(1, sizeof(*bso));
-       struct nouveau_stateobj *so = so_new(16, 0);
+       struct nouveau_stateobj *so = so_new(5, 8, 0);
 
        if (cso->blend_enable) {
                so_method(so, rankine, NV34TCL_BLEND_FUNC_ENABLE, 3);
@@ -300,7 +300,7 @@ nv30_rasterizer_state_create(struct pipe_context *pipe,
 {
        struct nv30_context *nv30 = nv30_context(pipe);
        struct nv30_rasterizer_state *rsso = CALLOC(1, sizeof(*rsso));
-       struct nouveau_stateobj *so = so_new(32, 0);
+       struct nouveau_stateobj *so = so_new(9, 19, 0);
        struct nouveau_grobj *rankine = nv30->screen->rankine;
 
        /*XXX: ignored:
@@ -435,7 +435,7 @@ nv30_depth_stencil_alpha_state_create(struct pipe_context *pipe,
 {
        struct nv30_context *nv30 = nv30_context(pipe);
        struct nv30_zsa_state *zsaso = CALLOC(1, sizeof(*zsaso));
-       struct nouveau_stateobj *so = so_new(32, 0);
+       struct nouveau_stateobj *so = so_new(5, 21, 0);
        struct nouveau_grobj *rankine = nv30->screen->rankine;
 
        so_method(so, rankine, NV34TCL_DEPTH_FUNC, 3);
index 64cf9ae93a0a6018262be11a7b715900acc145b6..c36d58c040cd8a1e4a194483fdb5346150168051 100644 (file)
@@ -18,7 +18,7 @@ struct nv30_state_entry nv30_state_blend = {
 static boolean
 nv30_state_blend_colour_validate(struct nv30_context *nv30)
 {
-       struct nouveau_stateobj *so = so_new(2, 0);
+       struct nouveau_stateobj *so = so_new(1, 1, 0);
        struct pipe_blend_color *bcol = &nv30->blend_colour;
 
        so_method(so, nv30->screen->rankine, NV34TCL_BLEND_COLOR, 1);
index 6f6d1740d6ef821013c2343f8cf5584b0a912fdb..2ed2ea55e8473875e695d53b68e44140650cbf4a 100644 (file)
@@ -10,7 +10,7 @@ nv30_state_framebuffer_validate(struct nv30_context *nv30)
        struct nv04_surface *rt[2], *zeta = NULL;
        uint32_t rt_enable = 0, rt_format = 0;
        int i, colour_format = 0, zeta_format = 0, depth_only = 0;
-       struct nouveau_stateobj *so = so_new(64, 10);
+       struct nouveau_stateobj *so = so_new(12, 18, 10);
        unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
        unsigned w = fb->width;
        unsigned h = fb->height;
index 3ac7a8471eae26df8cc040e144c098bbca69121f..ba61a9e24a478cf2298d5afc7282a18ec03094c3 100644 (file)
@@ -12,7 +12,7 @@ nv30_state_scissor_validate(struct nv30_context *nv30)
                return FALSE;
        nv30->state.scissor_enabled = rast->scissor;
 
-       so = so_new(3, 0);
+       so = so_new(1, 2, 0);
        so_method(so, nv30->screen->rankine, NV34TCL_SCISSOR_HORIZ, 2);
        if (nv30->state.scissor_enabled) {
                so_data  (so, ((s->maxx - s->minx) << 16) | s->minx);
index d0c791ac0821648337f0b367bf45b189410211f5..ed520a4f439cc5dc33174378bd53653b0991210b 100644 (file)
@@ -14,14 +14,14 @@ nv30_state_stipple_validate(struct nv30_context *nv30)
        if (rast->poly_stipple_enable) {
                unsigned i;
 
-               so = so_new(35, 0);
+               so = so_new(2, 33, 0);
                so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_ENABLE, 1);
                so_data  (so, 1);
                so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_PATTERN(0), 32);
                for (i = 0; i < 32; i++)
                        so_data(so, nv30->stipple[i]);
        } else {
-               so = so_new(2, 0);
+               so = so_new(1, 1, 0);
                so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_ENABLE, 1);
                so_data  (so, 0);
        }
index c3eb413dac69178a41d20a507df3ae94e3b2b29d..2d7781292bdded0700ac0099689f18feab759d55 100644 (file)
@@ -19,7 +19,7 @@ nv30_state_viewport_validate(struct nv30_context *nv30)
                return FALSE;
        nv30->state.viewport_bypass = bypass;
 
-       so = so_new(11, 0);
+       so = so_new(3, 10, 0);
        if (!bypass) {
                so_method(so, nv30->screen->rankine,
                          NV34TCL_VIEWPORT_TRANSLATE_X, 8);
index bccc805324c478a9b159560e57cef76ed8dcb275..1c5db03ea240293c420d95740cfa3a34a8d56941 100644 (file)
@@ -491,9 +491,9 @@ nv30_vbo_validate(struct nv30_context *nv30)
        unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
        int hw;
 
-       vtxbuf = so_new(20, 18);
+       vtxbuf = so_new(3, 17, 18);
        so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
-       vtxfmt = so_new(17, 0);
+       vtxfmt = so_new(1, 16, 0);
        so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
 
        for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
@@ -506,7 +506,7 @@ nv30_vbo_validate(struct nv30_context *nv30)
 
                if (!vb->stride) {
                        if (!sattr)
-                               sattr = so_new(16 * 5, 0);
+                               sattr = so_new(16, 16 * 4, 0);
 
                        if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
                                so_data(vtxbuf, 0);
index 4e6d3d01c74b14382c7ad7e9d06c872c0596aac8..e77a5be3f23152a6cc1ee4bbf8c17c9e8b7f9350 100644 (file)
@@ -686,7 +686,7 @@ nv30_vertprog_validate(struct nv30_context *nv30)
                                assert(0);
                }
 
-               so = so_new(2, 0);
+               so = so_new(1, 1, 0);
                so_method(so, rankine, NV34TCL_VP_START_FROM_ID, 1);
                so_data  (so, vp->exec->start);
                so_ref(so, &vp->so);
index bb9c85cc434a6ce0383a5fdc68956355c7c35762..1237066c3981df27e338487ffff7ddb63102d0c6 100644 (file)
@@ -919,7 +919,7 @@ nv40_fragprog_validate(struct nv40_context *nv40)
        fp->buffer = pscreen->buffer_create(pscreen, 0x100, 0, fp->insn_len * 4);
        nv40_fragprog_upload(nv40, fp);
 
-       so = so_new(4, 1);
+       so = so_new(2, 2, 1);
        so_method(so, nv40->screen->curie, NV40TCL_FP_ADDRESS, 1);
        so_reloc (so, nouveau_bo(fp->buffer), 0, NOUVEAU_BO_VRAM |
                      NOUVEAU_BO_GART | NOUVEAU_BO_RD | NOUVEAU_BO_LOW |
index 44abc845969f4b1fe208a27abd0420408b04896a..aad9198210fd22626cbbabc6ea7a8e32e0056285 100644 (file)
@@ -108,7 +108,7 @@ nv40_fragtex_build(struct nv40_context *nv40, int unit)
 
        txs = tf->swizzle;
 
-       so = so_new(16, 2);
+       so = so_new(2, 9, 2);
        so_method(so, nv40->screen->curie, NV40TCL_TEX_OFFSET(unit), 8);
        so_reloc (so, bo, 0, tex_flags | NOUVEAU_BO_LOW, 0, 0);
        so_reloc (so, bo, txf, tex_flags | NOUVEAU_BO_OR,
@@ -139,7 +139,7 @@ nv40_fragtex_validate(struct nv40_context *nv40)
                unit = ffs(samplers) - 1;
                samplers &= ~(1 << unit);
 
-               so = so_new(2, 0);
+               so = so_new(1, 1, 0);
                so_method(so, nv40->screen->curie, NV40TCL_TEX_ENABLE(unit), 1);
                so_data  (so, 0);
                so_ref(so, &nv40->state.hw[NV40_STATE_FRAGTEX0 + unit]);
index d01e71280510741c362f9b5c5a693aeb55113939..9e55e5a089c6eb46790c44b9e7902bc593fa1188 100644 (file)
@@ -215,7 +215,6 @@ nv40_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
                return FALSE;
        }
-       BIND_RING(chan, screen->curie, 7);
 
        /* 2D engine setup */
        screen->eng2d = nv04_surface_2d_init(&screen->base);
@@ -252,7 +251,7 @@ nv40_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        }
 
        /* Static curie initialisation */
-       so = so_new(128, 0);
+       so = so_new(16, 25, 0);
        so_method(so, screen->curie, NV40TCL_DMA_NOTIFY, 1);
        so_data  (so, screen->sync->handle);
        so_method(so, screen->curie, NV40TCL_DMA_TEXTURE0, 2);
index ed55d29affde8565541fcb077400424a98a2418f..ed0ca9e02c31d8c0b183ebd59e9e126993d164a3 100644 (file)
@@ -16,7 +16,7 @@ nv40_blend_state_create(struct pipe_context *pipe,
        struct nv40_context *nv40 = nv40_context(pipe);
        struct nouveau_grobj *curie = nv40->screen->curie;
        struct nv40_blend_state *bso = CALLOC(1, sizeof(*bso));
-       struct nouveau_stateobj *so = so_new(16, 0);
+       struct nouveau_stateobj *so = so_new(5, 8, 0);
 
        if (cso->blend_enable) {
                so_method(so, curie, NV40TCL_BLEND_ENABLE, 3);
@@ -310,7 +310,7 @@ nv40_rasterizer_state_create(struct pipe_context *pipe,
 {
        struct nv40_context *nv40 = nv40_context(pipe);
        struct nv40_rasterizer_state *rsso = CALLOC(1, sizeof(*rsso));
-       struct nouveau_stateobj *so = so_new(32, 0);
+       struct nouveau_stateobj *so = so_new(8, 18, 0);
        struct nouveau_grobj *curie = nv40->screen->curie;
 
        /*XXX: ignored:
@@ -445,7 +445,7 @@ nv40_depth_stencil_alpha_state_create(struct pipe_context *pipe,
 {
        struct nv40_context *nv40 = nv40_context(pipe);
        struct nv40_zsa_state *zsaso = CALLOC(1, sizeof(*zsaso));
-       struct nouveau_stateobj *so = so_new(32, 0);
+       struct nouveau_stateobj *so = so_new(4, 21, 0);
        struct nouveau_grobj *curie = nv40->screen->curie;
 
        so_method(so, curie, NV40TCL_DEPTH_FUNC, 3);
index 8cd05ce66ef858f138d0c9d064b9cbf2ed8e7af3..3ff00a37f66b7067093a6b5202e08b34a6f26eee 100644 (file)
@@ -18,7 +18,7 @@ struct nv40_state_entry nv40_state_blend = {
 static boolean
 nv40_state_blend_colour_validate(struct nv40_context *nv40)
 {
-       struct nouveau_stateobj *so = so_new(2, 0);
+       struct nouveau_stateobj *so = so_new(1, 1, 0);
        struct pipe_blend_color *bcol = &nv40->blend_colour;
 
        so_method(so, nv40->screen->curie, NV40TCL_BLEND_COLOR, 1);
index 1c7a7cd64f051ce0aa0db7597c235a318e585fc2..a58fe9ddb1954718a185e6eb8eb6436953902bed 100644 (file)
@@ -19,7 +19,7 @@ nv40_state_framebuffer_validate(struct nv40_context *nv40)
        struct nv04_surface *rt[4], *zeta;
        uint32_t rt_enable, rt_format;
        int i, colour_format = 0, zeta_format = 0;
-       struct nouveau_stateobj *so = so_new(64, 10);
+       struct nouveau_stateobj *so = so_new(18, 24, 10);
        unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
        unsigned w = fb->width;
        unsigned h = fb->height;
index cf58d33906a9629c134f673ac8aaf6f937ac821f..753a505e934b13881a903960d4a10abeac4a9790 100644 (file)
@@ -12,7 +12,7 @@ nv40_state_scissor_validate(struct nv40_context *nv40)
                return FALSE;
        nv40->state.scissor_enabled = rast->scissor;
 
-       so = so_new(3, 0);
+       so = so_new(1, 2, 0);
        so_method(so, nv40->screen->curie, NV40TCL_SCISSOR_HORIZ, 2);
        if (nv40->state.scissor_enabled) {
                so_data  (so, ((s->maxx - s->minx) << 16) | s->minx);
index b51024ad9b20c293d365a64145177deaa95d6d86..2b371ebfec065dcbb932e35a28cd1b6a4d085c65 100644 (file)
@@ -14,14 +14,14 @@ nv40_state_stipple_validate(struct nv40_context *nv40)
        if (rast->poly_stipple_enable) {
                unsigned i;
 
-               so = so_new(35, 0);
+               so = so_new(2, 33, 0);
                so_method(so, curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1);
                so_data  (so, 1);
                so_method(so, curie, NV40TCL_POLYGON_STIPPLE_PATTERN(0), 32);
                for (i = 0; i < 32; i++)
                        so_data(so, nv40->stipple[i]);
        } else {
-               so = so_new(2, 0);
+               so = so_new(1, 1, 0);
                so_method(so, curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1);
                so_data  (so, 0);
        }
index 665d2d5fcaca698125438fdad42eb0d68aae9763..9919ba1d0b0dcd5e766181ebf5e67c5ad269c57e 100644 (file)
@@ -19,7 +19,7 @@ nv40_state_viewport_validate(struct nv40_context *nv40)
                return FALSE;
        nv40->state.viewport_bypass = bypass;
 
-       so = so_new(11, 0);
+       so = so_new(2, 9, 0);
        if (!bypass) {
                so_method(so, nv40->screen->curie,
                          NV40TCL_VIEWPORT_TRANSLATE_X, 8);
index 90087f0bee3fc78a09d8b7069852884fac9e026b..a777898f6880dafa9586febcccb3eec360f70a53 100644 (file)
@@ -491,9 +491,9 @@ nv40_vbo_validate(struct nv40_context *nv40)
        unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
        int hw;
 
-       vtxbuf = so_new(20, 18);
+       vtxbuf = so_new(3, 17, 18);
        so_method(vtxbuf, curie, NV40TCL_VTXBUF_ADDRESS(0), nv40->vtxelt_nr);
-       vtxfmt = so_new(17, 0);
+       vtxfmt = so_new(1, 16, 0);
        so_method(vtxfmt, curie, NV40TCL_VTXFMT(0), nv40->vtxelt_nr);
 
        for (hw = 0; hw < nv40->vtxelt_nr; hw++) {
@@ -506,7 +506,7 @@ nv40_vbo_validate(struct nv40_context *nv40)
 
                if (!vb->stride) {
                        if (!sattr)
-                               sattr = so_new(16 * 5, 0);
+                               sattr = so_new(16, 16 * 4, 0);
 
                        if (nv40_vbo_static_attrib(nv40, sattr, hw, ve, vb)) {
                                so_data(vtxbuf, 0);
index afbb2cb47bd0a8f4e99684c3b1f497e57b0dd1c2..8d80fcad38e51104bd7d85096c3ec32c47f203e8 100644 (file)
@@ -886,7 +886,7 @@ check_gpu_resources:
                                assert(0);
                }
 
-               so = so_new(7, 0);
+               so = so_new(3, 4, 0);
                so_method(so, curie, NV40TCL_VP_START_FROM_ID, 1);
                so_data  (so, vp->exec->start);
                so_method(so, curie, NV40TCL_VP_ATTRIB_EN, 2);
index 2d0b1818ef60a4ee156f9921a60729f00b2058c0..af0759e50385d6aff90bcd8954ca2542934145c5 100644 (file)
@@ -3579,7 +3579,7 @@ nv50_vertprog_validate(struct nv50_context *nv50)
        nv50_program_validate_data(nv50, p);
        nv50_program_validate_code(nv50, p);
 
-       so = so_new(13, 2);
+       so = so_new(5, 8, 2);
        so_method(so, tesla, NV50TCL_VP_ADDRESS_HIGH, 2);
        so_reloc (so, p->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
                      NOUVEAU_BO_HIGH, 0, 0);
@@ -3615,7 +3615,7 @@ nv50_fragprog_validate(struct nv50_context *nv50)
        nv50_program_validate_data(nv50, p);
        nv50_program_validate_code(nv50, p);
 
-       so = so_new(64, 2);
+       so = so_new(6, 7, 2);
        so_method(so, tesla, NV50TCL_FP_ADDRESS_HIGH, 2);
        so_reloc (so, p->bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
                      NOUVEAU_BO_HIGH, 0, 0);
@@ -3783,7 +3783,7 @@ nv50_linkage_validate(struct nv50_context *nv50)
        }
 
        /* now fill the stateobj */
-       so = so_new(64, 0);
+       so = so_new(6, 58, 0);
 
        n = (m + 3) / 4;
        so_method(so, tesla, NV50TCL_VP_RESULT_MAP_SIZE, 1);
index 1778a74517940613ee4fab613eedd04c65fa8e4e..28e2b35deaaa664cece88ce5b162974152c408de 100644 (file)
@@ -251,7 +251,6 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                nv50_screen_destroy(pscreen);
                return NULL;
        }
-       BIND_RING(chan, screen->m2mf, 1);
 
        /* 2D object */
        ret = nouveau_grobj_alloc(chan, 0xbeef502d, NV50_2D, &screen->eng2d);
@@ -260,7 +259,6 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                nv50_screen_destroy(pscreen);
                return NULL;
        }
-       BIND_RING(chan, screen->eng2d, 2);
 
        /* 3D object */
        switch (chipset & 0xf0) {
@@ -296,7 +294,6 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                nv50_screen_destroy(pscreen);
                return NULL;
        }
-       BIND_RING(chan, screen->tesla, 3);
 
        /* Sync notifier */
        ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync);
@@ -307,7 +304,7 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        }
 
        /* Static M2MF init */
-       so = so_new(32, 0);
+       so = so_new(1, 3, 0);
        so_method(so, screen->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
        so_data  (so, screen->sync->handle);
        so_data  (so, chan->vram->handle);
@@ -316,7 +313,7 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        so_ref (NULL, &so);
 
        /* Static 2D init */
-       so = so_new(64, 0);
+       so = so_new(4, 7, 0);
        so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4);
        so_data  (so, screen->sync->handle);
        so_data  (so, chan->vram->handle);
@@ -332,7 +329,7 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        so_ref(NULL, &so);
 
        /* Static tesla init */
-       so = so_new(256, 20);
+       so = so_new(40, 84, 20);
 
        so_method(so, screen->tesla, NV50TCL_COND_MODE, 1);
        so_data  (so, NV50TCL_COND_MODE_ALWAYS);
index 30b2b0f91bfb93799182edd349a12941ca6ce049..fd0a33d7f7e5f60b54fa7d80ce7ad43cdc2abc98 100644 (file)
@@ -35,7 +35,7 @@ static void *
 nv50_blend_state_create(struct pipe_context *pipe,
                        const struct pipe_blend_state *cso)
 {
-       struct nouveau_stateobj *so = so_new(64, 0);
+       struct nouveau_stateobj *so = so_new(5, 24, 0);
        struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
        struct nv50_blend_stateobj *bso = CALLOC_STRUCT(nv50_blend_stateobj);
        unsigned cmask = 0, i;
@@ -280,7 +280,7 @@ static void *
 nv50_rasterizer_state_create(struct pipe_context *pipe,
                             const struct pipe_rasterizer_state *cso)
 {
-       struct nouveau_stateobj *so = so_new(64, 0);
+       struct nouveau_stateobj *so = so_new(15, 21, 0);
        struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
        struct nv50_rasterizer_stateobj *rso =
                CALLOC_STRUCT(nv50_rasterizer_stateobj);
@@ -425,7 +425,7 @@ nv50_depth_stencil_alpha_state_create(struct pipe_context *pipe,
 {
        struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
        struct nv50_zsa_stateobj *zsa = CALLOC_STRUCT(nv50_zsa_stateobj);
-       struct nouveau_stateobj *so = so_new(64, 0);
+       struct nouveau_stateobj *so = so_new(8, 22, 0);
 
        so_method(so, tesla, NV50TCL_DEPTH_WRITE_ENABLE, 1);
        so_data  (so, cso->depth.writemask ? 1 : 0);
index 682786345ef8ddc20ed0b9565803e17dad8d1d23..f83232f43cf5cc0eca3114ecd336ae8f1458821c 100644 (file)
@@ -33,7 +33,7 @@ static void
 nv50_state_validate_fb(struct nv50_context *nv50)
 {
        struct nouveau_grobj *tesla = nv50->screen->tesla;
-       struct nouveau_stateobj *so = so_new(128, 18);
+       struct nouveau_stateobj *so = so_new(32, 79, 18);
        struct pipe_framebuffer_state *fb = &nv50->framebuffer;
        unsigned i, w, h, gw = 0;
 
@@ -299,7 +299,7 @@ nv50_state_validate(struct nv50_context *nv50)
                so_ref(nv50->rasterizer->so, &nv50->state.rast);
 
        if (nv50->dirty & NV50_NEW_BLEND_COLOUR) {
-               so = so_new(5, 0);
+               so = so_new(1, 4, 0);
                so_method(so, tesla, NV50TCL_BLEND_COLOR(0), 4);
                so_data  (so, fui(nv50->blend_colour.color[0]));
                so_data  (so, fui(nv50->blend_colour.color[1]));
@@ -310,7 +310,7 @@ nv50_state_validate(struct nv50_context *nv50)
        }
 
        if (nv50->dirty & NV50_NEW_STIPPLE) {
-               so = so_new(33, 0);
+               so = so_new(1, 32, 0);
                so_method(so, tesla, NV50TCL_POLYGON_STIPPLE_PATTERN(0), 32);
                for (i = 0; i < 32; i++)
                        so_data(so, util_bswap32(nv50->stipple.stipple[i]));
@@ -327,7 +327,7 @@ nv50_state_validate(struct nv50_context *nv50)
                        goto scissor_uptodate;
                nv50->state.scissor_enabled = rast->scissor;
 
-               so = so_new(3, 0);
+               so = so_new(1, 2, 0);
                so_method(so, tesla, NV50TCL_SCISSOR_HORIZ(0), 2);
                if (nv50->state.scissor_enabled) {
                        so_data(so, (s->maxx << 16) | s->minx);
@@ -356,7 +356,7 @@ scissor_uptodate:
                        goto viewport_uptodate;
                nv50->state.viewport_bypass = bypass;
 
-               so = so_new(14, 0);
+               so = so_new(5, 9, 0);
                if (!bypass) {
                        so_method(so, tesla, NV50TCL_VIEWPORT_TRANSLATE_X(0), 3);
                        so_data  (so, fui(nv50->viewport.translate[0]));
@@ -400,7 +400,8 @@ viewport_uptodate:
                for (i = 0; i < PIPE_SHADER_TYPES; ++i)
                        nr += nv50->sampler_nr[i];
 
-               so = so_new(nr * 8 + 24 * PIPE_SHADER_TYPES + 2, 4);
+               so = so_new(1+ 5 * PIPE_SHADER_TYPES, 1+ 19 * PIPE_SHADER_TYPES
+                                       + nr * 8, PIPE_SHADER_TYPES * 2);
 
                nv50_validate_samplers(nv50, so, PIPE_SHADER_VERTEX);
                nv50_validate_samplers(nv50, so, PIPE_SHADER_FRAGMENT);
index c4ca096d6ac5ef726c6f196d57f5a926250e64e7..bef548b728673684caca98afe605bbd9b60763ed 100644 (file)
@@ -199,16 +199,18 @@ nv50_tex_validate(struct nv50_context *nv50)
 {
        struct nouveau_stateobj *so;
        struct nouveau_grobj *tesla = nv50->screen->tesla;
-       unsigned p, push, nrlc;
+       unsigned p, start, push, nrlc;
 
-       for (nrlc = 0, push = 0, p = 0; p < PIPE_SHADER_TYPES; ++p) {
+       for (nrlc = 0, start = 0, push = 0, p = 0; p < PIPE_SHADER_TYPES; ++p) {
+               start += MAX2(nv50->miptree_nr[p], nv50->state.miptree_nr[p]);
                push += MAX2(nv50->miptree_nr[p], nv50->state.miptree_nr[p]);
                nrlc += nv50->miptree_nr[p];
        }
-       push = push * 11 + 23 * PIPE_SHADER_TYPES + 4;
+       start = start * 2 + 4 * PIPE_SHADER_TYPES + 2;
+       push = push * 9 + 19 * PIPE_SHADER_TYPES + 2;
        nrlc = nrlc * 2 + 2 * PIPE_SHADER_TYPES;
 
-       so = so_new(push, nrlc);
+       so = so_new(start, push, nrlc);
 
        if (nv50_validate_textures(nv50, so, PIPE_SHADER_VERTEX) == FALSE ||
            nv50_validate_textures(nv50, so, PIPE_SHADER_FRAGMENT) == FALSE) {
index df18c2dd20aa0b66982fdcef287e729cfff55e5c..f2e510fba6181df3cb646866b64f3e275cbc060e 100644 (file)
@@ -354,7 +354,7 @@ nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
 
        so = *pso;
        if (!so)
-               *pso = so = so_new(nv50->vtxelt_nr * 5, 0);
+               *pso = so = so_new(nv50->vtxelt_nr, nv50->vtxelt_nr * 4, 0);
 
        switch (ve->nr_components) {
        case 4:
@@ -415,8 +415,8 @@ nv50_vbo_validate(struct nv50_context *nv50)
        n_ve = MAX2(nv50->vtxelt_nr, nv50->state.vtxelt_nr);
 
        vtxattr = NULL;
-       vtxbuf = so_new(n_ve * 7, nv50->vtxelt_nr * 4);
-       vtxfmt = so_new(n_ve + 1, 0);
+       vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt_nr * 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_nr; i++) {