+nv30_render_release_vertices(struct vbuf_render *render)
+{
+ struct nv30_render *r = nv30_render(render);
+ r->offset += r->length;
+}
+
+static const struct {
+ unsigned emit;
+ unsigned interp;
+ unsigned vp30;
+ unsigned vp40;
+ unsigned ow40;
+} vroute [] = {
+ [TGSI_SEMANTIC_POSITION] = { EMIT_4F, INTERP_PERSPECTIVE, 0, 0, 0x00000000 },
+ [TGSI_SEMANTIC_COLOR ] = { EMIT_4F, INTERP_LINEAR , 3, 1, 0x00000001 },
+ [TGSI_SEMANTIC_BCOLOR ] = { EMIT_4F, INTERP_LINEAR , 1, 3, 0x00000004 },
+ [TGSI_SEMANTIC_FOG ] = { EMIT_4F, INTERP_PERSPECTIVE, 5, 5, 0x00000010 },
+ [TGSI_SEMANTIC_PSIZE ] = { EMIT_1F_PSIZE, INTERP_POS , 6, 6, 0x00000020 },
+ [TGSI_SEMANTIC_GENERIC ] = { EMIT_4F, INTERP_PERSPECTIVE, 8, 7, 0x00004000 }
+};
+
+static boolean
+vroute_add(struct nv30_render *r, uint attrib, uint sem, uint *idx)
+{
+ struct pipe_screen *pscreen = &r->nv30->screen->base.base;
+ struct nv30_fragprog *fp = r->nv30->fragprog.program;
+ struct vertex_info *vinfo = &r->vertex_info;
+ enum pipe_format format;
+ uint emit = EMIT_OMIT;
+ uint result = *idx;
+
+ if (sem == TGSI_SEMANTIC_GENERIC && result >= 8) {
+ for (result = 0; result < 8; result++) {
+ if (fp->texcoord[result] == *idx) {
+ emit = vroute[sem].emit;
+ break;
+ }
+ }
+ } else {
+ emit = vroute[sem].emit;
+ }
+
+ if (emit == EMIT_OMIT)
+ return FALSE;
+
+ draw_emit_vertex_attr(vinfo, emit, vroute[sem].interp, attrib);
+ format = draw_translate_vinfo_format(emit);
+
+ r->vtxfmt[attrib] = nv30_vtxfmt(pscreen, format)->hw;
+ r->vtxptr[attrib] = vinfo->size | NV30_3D_VTXBUF_DMA1;
+ vinfo->size += draw_translate_vinfo_size(emit);
+
+ if (nv30_screen(pscreen)->eng3d->oclass < NV40_3D_CLASS) {
+ r->vtxprog[attrib][0] = 0x001f38d8;
+ r->vtxprog[attrib][1] = 0x0080001b | (attrib << 9);
+ r->vtxprog[attrib][2] = 0x0836106c;
+ r->vtxprog[attrib][3] = 0x2000f800 | (result + vroute[sem].vp30) << 2;
+ } else {
+ r->vtxprog[attrib][0] = 0x401f9c6c;
+ r->vtxprog[attrib][1] = 0x0040000d | (attrib << 8);
+ r->vtxprog[attrib][2] = 0x8106c083;
+ r->vtxprog[attrib][3] = 0x6041ff80 | (result + vroute[sem].vp40) << 2;
+ }
+
+ *idx = vroute[sem].ow40 << result;
+ return TRUE;
+}
+
+static boolean
+nv30_render_validate(struct nv30_context *nv30)
+{
+ struct nv30_render *r = nv30_render(nv30->draw->render);
+ struct nv30_rasterizer_stateobj *rast = nv30->rast;
+ struct pipe_screen *pscreen = &nv30->screen->base.base;
+ struct nouveau_pushbuf *push = nv30->screen->base.pushbuf;
+ struct nouveau_object *eng3d = nv30->screen->eng3d;
+ struct nv30_vertprog *vp = nv30->vertprog.program;
+ struct vertex_info *vinfo = &r->vertex_info;
+ unsigned vp_attribs = 0;
+ unsigned vp_results = 0;
+ unsigned attrib = 0;
+ unsigned pntc;
+ int i;
+
+ if (!r->vertprog) {
+ struct nouveau_heap *heap = nv30_screen(pscreen)->vp_exec_heap;
+ if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog)) {
+ while (heap->next && heap->size < 16) {
+ struct nouveau_heap **evict = heap->next->priv;
+ nouveau_heap_free(evict);
+ }
+
+ if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog))
+ return FALSE;
+ }
+ }
+
+ vinfo->num_attribs = 0;
+ vinfo->size = 0;
+
+ /* setup routing for all necessary vp outputs */
+ for (i = 0; i < vp->info.num_outputs && attrib < 16; i++) {
+ uint semantic = vp->info.output_semantic_name[i];
+ uint index = vp->info.output_semantic_index[i];
+ if (vroute_add(r, attrib, semantic, &index)) {
+ vp_attribs |= (1 << attrib++);
+ vp_results |= index;
+ }
+ }
+
+ /* setup routing for replaced point coords not written by vp */
+ if (rast && rast->pipe.point_quad_rasterization)
+ pntc = rast->pipe.sprite_coord_enable & 0x000002ff;
+ else
+ pntc = 0;
+
+ while (pntc && attrib < 16) {
+ uint index = ffs(pntc) - 1; pntc &= ~(1 << index);
+ if (vroute_add(r, attrib, TGSI_SEMANTIC_GENERIC, &index)) {
+ vp_attribs |= (1 << attrib++);
+ vp_results |= index;
+ }
+ }
+
+ /* modify vertex format for correct stride, and stub out unused ones */
+ BEGIN_NV04(push, NV30_3D(VP_UPLOAD_FROM_ID), 1);
+ PUSH_DATA (push, r->vertprog->start);
+ r->vtxprog[attrib - 1][3] |= 1;
+ for (i = 0; i < attrib; i++) {
+ BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4);
+ PUSH_DATAp(push, r->vtxprog[i], 4);
+ r->vtxfmt[i] |= vinfo->size << 8;
+ }
+ for (; i < 16; i++)
+ r->vtxfmt[i] = NV30_3D_VTXFMT_TYPE_V32_FLOAT;
+
+ BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
+ PUSH_DATAf(push, 0.0);
+ PUSH_DATAf(push, 0.0);
+ PUSH_DATAf(push, 0.0);
+ PUSH_DATAf(push, 0.0);
+ PUSH_DATAf(push, 1.0);
+ PUSH_DATAf(push, 1.0);
+ PUSH_DATAf(push, 1.0);
+ PUSH_DATAf(push, 1.0);
+ BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
+ PUSH_DATAf(push, 0.0);
+ PUSH_DATAf(push, 1.0);
+
+ BEGIN_NV04(push, NV30_3D(VTXFMT(0)), 16);
+ PUSH_DATAp(push, r->vtxfmt, 16);
+
+ BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1);
+ PUSH_DATA (push, r->vertprog->start);
+ BEGIN_NV04(push, NV30_3D(ENGINE), 1);
+ PUSH_DATA (push, 0x00000103);
+ if (eng3d->oclass >= NV40_3D_CLASS) {
+ BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2);
+ PUSH_DATA (push, vp_attribs);
+ PUSH_DATA (push, vp_results);
+ }
+
+ vinfo->size /= 4;
+ return TRUE;
+}
+
+void
+nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)