nv50: re-add immediate mode vertex submission paths
[mesa.git] / src / gallium / drivers / nv50 / nv50_vbo.c
1 /*
2 * Copyright 2008 Ben Skeggs
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "pipe/p_context.h"
24 #include "pipe/p_state.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
27
28 #include "nouveau/nouveau_util.h"
29 #include "nv50_context.h"
30
31 #define NV50_USING_LOATHED_EDGEFLAG(ctx) ((ctx)->vertprog->cfg.edgeflag_in < 16)
32
33 static INLINE unsigned
34 nv50_prim(unsigned mode)
35 {
36 switch (mode) {
37 case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
38 case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
39 case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
40 case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
41 case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
42 case PIPE_PRIM_TRIANGLE_STRIP:
43 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
44 case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
45 case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
46 case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
47 case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
48 case PIPE_PRIM_LINES_ADJACENCY:
49 return NV50TCL_VERTEX_BEGIN_LINES_ADJACENCY;
50 case PIPE_PRIM_LINE_STRIP_ADJACENCY:
51 return NV50TCL_VERTEX_BEGIN_LINE_STRIP_ADJACENCY;
52 case PIPE_PRIM_TRIANGLES_ADJACENCY:
53 return NV50TCL_VERTEX_BEGIN_TRIANGLES_ADJACENCY;
54 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
55 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP_ADJACENCY;
56 default:
57 break;
58 }
59
60 NOUVEAU_ERR("invalid primitive type %d\n", mode);
61 return NV50TCL_VERTEX_BEGIN_POINTS;
62 }
63
64 static INLINE uint32_t
65 nv50_vbo_type_to_hw(enum pipe_format format)
66 {
67 const struct util_format_description *desc;
68
69 desc = util_format_description(format);
70 assert(desc);
71
72 switch (desc->channel[0].type) {
73 case UTIL_FORMAT_TYPE_FLOAT:
74 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT;
75 case UTIL_FORMAT_TYPE_UNSIGNED:
76 if (desc->channel[0].normalized) {
77 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UNORM;
78 }
79 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_USCALED;
80 case UTIL_FORMAT_TYPE_SIGNED:
81 if (desc->channel[0].normalized) {
82 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SNORM;
83 }
84 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SSCALED;
85 /*
86 case PIPE_FORMAT_TYPE_UINT:
87 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UINT;
88 case PIPE_FORMAT_TYPE_SINT:
89 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SINT; */
90 default:
91 return 0;
92 }
93 }
94
95 static INLINE uint32_t
96 nv50_vbo_size_to_hw(unsigned size, unsigned nr_c)
97 {
98 static const uint32_t hw_values[] = {
99 0, 0, 0, 0,
100 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8,
101 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8,
102 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8,
103 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8_8,
104 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16,
105 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16,
106 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16,
107 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16_16,
108 0, 0, 0, 0,
109 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32,
110 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32,
111 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32,
112 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 };
113
114 /* we'd also have R11G11B10 and R10G10B10A2 */
115
116 assert(nr_c > 0 && nr_c <= 4);
117
118 if (size > 32)
119 return 0;
120 size >>= (3 - 2);
121
122 return hw_values[size + (nr_c - 1)];
123 }
124
125 static INLINE uint32_t
126 nv50_vbo_vtxelt_to_hw(struct pipe_vertex_element *ve)
127 {
128 uint32_t hw_type, hw_size;
129 enum pipe_format pf = ve->src_format;
130 const struct util_format_description *desc;
131 unsigned size, nr_components;
132
133 desc = util_format_description(pf);
134 assert(desc);
135
136 size = util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0);
137 nr_components = util_format_get_nr_components(pf);
138
139 hw_type = nv50_vbo_type_to_hw(pf);
140 hw_size = nv50_vbo_size_to_hw(size, nr_components);
141
142 if (!hw_type || !hw_size) {
143 NOUVEAU_ERR("unsupported vbo format: %s\n", util_format_name(pf));
144 abort();
145 return 0x24e80000;
146 }
147
148 if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z) /* BGRA */
149 hw_size |= (1 << 31); /* no real swizzle bits :-( */
150
151 return (hw_type | hw_size);
152 }
153
154 struct instance {
155 struct nouveau_bo *bo;
156 unsigned delta;
157 unsigned stride;
158 unsigned step;
159 unsigned divisor;
160 };
161
162 static void
163 instance_init(struct nv50_context *nv50, struct instance *a, unsigned first)
164 {
165 int i;
166
167 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
168 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
169 struct pipe_vertex_buffer *vb;
170
171 a[i].divisor = ve->instance_divisor;
172 if (a[i].divisor) {
173 vb = &nv50->vtxbuf[ve->vertex_buffer_index];
174
175 a[i].bo = nouveau_bo(vb->buffer);
176 a[i].stride = vb->stride;
177 a[i].step = first % a[i].divisor;
178 a[i].delta = vb->buffer_offset + ve->src_offset +
179 (first * a[i].stride);
180 }
181 }
182 }
183
184 static void
185 instance_step(struct nv50_context *nv50, struct instance *a)
186 {
187 struct nouveau_channel *chan = nv50->screen->tesla->channel;
188 struct nouveau_grobj *tesla = nv50->screen->tesla;
189 int i;
190
191 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
192 if (!a[i].divisor)
193 continue;
194
195 BEGIN_RING(chan, tesla,
196 NV50TCL_VERTEX_ARRAY_START_HIGH(i), 2);
197 OUT_RELOCh(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD |
198 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART);
199 OUT_RELOCl(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD |
200 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART);
201 if (++a[i].step == a[i].divisor) {
202 a[i].step = 0;
203 a[i].delta += a[i].stride;
204 }
205 }
206 }
207
208 void
209 nv50_draw_arrays_instanced(struct pipe_context *pipe,
210 unsigned mode, unsigned start, unsigned count,
211 unsigned startInstance, unsigned instanceCount)
212 {
213 struct nv50_context *nv50 = nv50_context(pipe);
214 struct nouveau_channel *chan = nv50->screen->tesla->channel;
215 struct nouveau_grobj *tesla = nv50->screen->tesla;
216 struct instance a[16];
217 unsigned prim = nv50_prim(mode);
218
219 instance_init(nv50, a, startInstance);
220 if (!nv50_state_validate(nv50, 10 + 16*3))
221 return;
222
223 if (nv50->vbo_fifo) {
224 nv50_push_elements_instanced(pipe, NULL, 0, mode, start,
225 count, startInstance,
226 instanceCount);
227 return;
228 }
229
230 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
231 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
232 OUT_RING (chan, startInstance);
233 while (instanceCount--) {
234 if (AVAIL_RING(chan) < (7 + 16*3)) {
235 FIRE_RING(chan);
236 if (!nv50_state_validate(nv50, 7 + 16*3)) {
237 assert(0);
238 return;
239 }
240 }
241 instance_step(nv50, a);
242
243 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
244 OUT_RING (chan, prim);
245 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
246 OUT_RING (chan, start);
247 OUT_RING (chan, count);
248 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
249 OUT_RING (chan, 0);
250
251 prim |= (1 << 28);
252 }
253 }
254
255 void
256 nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
257 unsigned count)
258 {
259 nv50_draw_arrays_instanced(pipe, mode, start, count, 0, 1);
260 }
261
262 struct inline_ctx {
263 struct nv50_context *nv50;
264 void *map;
265 };
266
267 static void
268 inline_elt08(void *priv, unsigned start, unsigned count)
269 {
270 struct inline_ctx *ctx = priv;
271 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
272 struct nouveau_channel *chan = tesla->channel;
273 uint8_t *map = (uint8_t *)ctx->map + start;
274
275 if (count & 1) {
276 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
277 OUT_RING (chan, map[0]);
278 map++;
279 count &= ~1;
280 }
281
282 count >>= 1;
283 if (!count)
284 return;
285
286 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
287 while (count--) {
288 OUT_RING(chan, (map[1] << 16) | map[0]);
289 map += 2;
290 }
291 }
292
293 static void
294 inline_elt16(void *priv, unsigned start, unsigned count)
295 {
296 struct inline_ctx *ctx = priv;
297 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
298 struct nouveau_channel *chan = tesla->channel;
299 uint16_t *map = (uint16_t *)ctx->map + start;
300
301 if (count & 1) {
302 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
303 OUT_RING (chan, map[0]);
304 count &= ~1;
305 map++;
306 }
307
308 count >>= 1;
309 if (!count)
310 return;
311
312 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
313 while (count--) {
314 OUT_RING(chan, (map[1] << 16) | map[0]);
315 map += 2;
316 }
317 }
318
319 static void
320 inline_elt32(void *priv, unsigned start, unsigned count)
321 {
322 struct inline_ctx *ctx = priv;
323 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
324 struct nouveau_channel *chan = tesla->channel;
325
326 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, count);
327 OUT_RINGp (chan, (uint32_t *)ctx->map + start, count);
328 }
329
330 static void
331 inline_edgeflag(void *priv, boolean enabled)
332 {
333 struct inline_ctx *ctx = priv;
334 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
335 struct nouveau_channel *chan = tesla->channel;
336
337 BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
338 OUT_RING (chan, enabled ? 1 : 0);
339 }
340
341 static void
342 nv50_draw_elements_inline(struct pipe_context *pipe,
343 struct pipe_buffer *indexBuffer, unsigned indexSize,
344 unsigned mode, unsigned start, unsigned count,
345 unsigned startInstance, unsigned instanceCount)
346 {
347 struct pipe_screen *pscreen = pipe->screen;
348 struct nv50_context *nv50 = nv50_context(pipe);
349 struct nouveau_channel *chan = nv50->screen->tesla->channel;
350 struct nouveau_grobj *tesla = nv50->screen->tesla;
351 struct instance a[16];
352 struct inline_ctx ctx;
353 struct u_split_prim s;
354 boolean nzi = FALSE;
355 unsigned overhead;
356
357 overhead = 16*3; /* potential instance adjustments */
358 overhead += 4; /* Begin()/End() */
359 overhead += 4; /* potential edgeflag disable/reenable */
360 overhead += 3; /* potentially 3 VTX_ELT_U16/U32 packet headers */
361
362 s.priv = &ctx;
363 if (indexSize == 1)
364 s.emit = inline_elt08;
365 else
366 if (indexSize == 2)
367 s.emit = inline_elt16;
368 else
369 s.emit = inline_elt32;
370 s.edge = inline_edgeflag;
371
372 ctx.nv50 = nv50;
373 ctx.map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
374 assert(ctx.map);
375 if (!ctx.map)
376 return;
377
378 instance_init(nv50, a, startInstance);
379 if (!nv50_state_validate(nv50, overhead + 6 + 3))
380 return;
381
382 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
383 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
384 OUT_RING (chan, startInstance);
385 while (instanceCount--) {
386 unsigned max_verts;
387 boolean done;
388
389 u_split_prim_init(&s, mode, start, count);
390 do {
391 if (AVAIL_RING(chan) < (overhead + 6)) {
392 FIRE_RING(chan);
393 if (!nv50_state_validate(nv50, (overhead + 6))) {
394 assert(0);
395 return;
396 }
397 }
398
399 max_verts = AVAIL_RING(chan) - overhead;
400 if (max_verts > 2047)
401 max_verts = 2047;
402 if (indexSize != 4)
403 max_verts <<= 1;
404 instance_step(nv50, a);
405
406 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
407 OUT_RING (chan, nv50_prim(s.mode) | (nzi ? (1<<28) : 0));
408 done = u_split_prim_next(&s, max_verts);
409 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
410 OUT_RING (chan, 0);
411 } while (!done);
412
413 nzi = TRUE;
414 }
415
416 pipe_buffer_unmap(pscreen, indexBuffer);
417 }
418
419 void
420 nv50_draw_elements_instanced(struct pipe_context *pipe,
421 struct pipe_buffer *indexBuffer,
422 unsigned indexSize,
423 unsigned mode, unsigned start, unsigned count,
424 unsigned startInstance, unsigned instanceCount)
425 {
426 struct nv50_context *nv50 = nv50_context(pipe);
427 struct nouveau_channel *chan = nv50->screen->tesla->channel;
428 struct nouveau_grobj *tesla = nv50->screen->tesla;
429 struct instance a[16];
430 unsigned prim = nv50_prim(mode);
431
432 instance_init(nv50, a, startInstance);
433 if (!nv50_state_validate(nv50, 13 + 16*3))
434 return;
435
436 if (nv50->vbo_fifo) {
437 nv50_push_elements_instanced(pipe, indexBuffer, indexSize,
438 mode, start, count, startInstance,
439 instanceCount);
440 return;
441 } else
442 if (!(indexBuffer->usage & PIPE_BUFFER_USAGE_INDEX) || indexSize == 1) {
443 nv50_draw_elements_inline(pipe, indexBuffer, indexSize,
444 mode, start, count, startInstance,
445 instanceCount);
446 return;
447 }
448
449 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
450 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
451 OUT_RING (chan, startInstance);
452 while (instanceCount--) {
453 if (AVAIL_RING(chan) < (7 + 16*3)) {
454 FIRE_RING(chan);
455 if (!nv50_state_validate(nv50, 10 + 16*3)) {
456 assert(0);
457 return;
458 }
459 }
460 instance_step(nv50, a);
461
462 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
463 OUT_RING (chan, prim);
464 if (indexSize == 4) {
465 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32 | 0x30000, 0);
466 OUT_RING (chan, count);
467 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
468 start << 2, count << 2);
469 } else
470 if (indexSize == 2) {
471 unsigned vb_start = (start & ~1);
472 unsigned vb_end = (start + count + 1) & ~1;
473 unsigned dwords = (vb_end - vb_start) >> 1;
474
475 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
476 OUT_RING (chan, ((start & 1) << 31) | count);
477 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16 | 0x30000, 0);
478 OUT_RING (chan, dwords);
479 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
480 vb_start << 1, dwords << 2);
481 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
482 OUT_RING (chan, 0);
483 }
484 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
485 OUT_RING (chan, 0);
486
487 prim |= (1 << 28);
488 }
489 }
490
491 void
492 nv50_draw_elements(struct pipe_context *pipe,
493 struct pipe_buffer *indexBuffer, unsigned indexSize,
494 unsigned mode, unsigned start, unsigned count)
495 {
496 nv50_draw_elements_instanced(pipe, indexBuffer, indexSize,
497 mode, start, count, 0, 1);
498 }
499
500 static INLINE boolean
501 nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
502 struct nouveau_stateobj **pso,
503 struct pipe_vertex_element *ve,
504 struct pipe_vertex_buffer *vb)
505
506 {
507 struct nouveau_stateobj *so;
508 struct nouveau_grobj *tesla = nv50->screen->tesla;
509 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
510 float v[4];
511 int ret;
512 unsigned nr_components = util_format_get_nr_components(ve->src_format);
513
514 ret = nouveau_bo_map(bo, NOUVEAU_BO_RD);
515 if (ret)
516 return FALSE;
517
518 util_format_read_4f(ve->src_format, v, 0, (uint8_t *)bo->map +
519 (vb->buffer_offset + ve->src_offset), 0,
520 0, 0, 1, 1);
521 so = *pso;
522 if (!so)
523 *pso = so = so_new(nv50->vtxelt->num_elements,
524 nv50->vtxelt->num_elements * 4, 0);
525
526 switch (nr_components) {
527 case 4:
528 so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4);
529 so_data (so, fui(v[0]));
530 so_data (so, fui(v[1]));
531 so_data (so, fui(v[2]));
532 so_data (so, fui(v[3]));
533 break;
534 case 3:
535 so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3);
536 so_data (so, fui(v[0]));
537 so_data (so, fui(v[1]));
538 so_data (so, fui(v[2]));
539 break;
540 case 2:
541 so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2);
542 so_data (so, fui(v[0]));
543 so_data (so, fui(v[1]));
544 break;
545 case 1:
546 if (attrib == nv50->vertprog->cfg.edgeflag_in) {
547 so_method(so, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
548 so_data (so, v[0] ? 1 : 0);
549 }
550 so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
551 so_data (so, fui(v[0]));
552 break;
553 default:
554 nouveau_bo_unmap(bo);
555 return FALSE;
556 }
557
558 nouveau_bo_unmap(bo);
559 return TRUE;
560 }
561
562 void
563 nv50_vtxelt_construct(struct nv50_vtxelt_stateobj *cso)
564 {
565 unsigned i;
566
567 for (i = 0; i < cso->num_elements; ++i) {
568 struct pipe_vertex_element *ve = &cso->pipe[i];
569
570 cso->hw[i] = nv50_vbo_vtxelt_to_hw(ve);
571 }
572 }
573
574 struct nouveau_stateobj *
575 nv50_vbo_validate(struct nv50_context *nv50)
576 {
577 struct nouveau_grobj *tesla = nv50->screen->tesla;
578 struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
579 unsigned i, n_ve;
580
581 /* don't validate if Gallium took away our buffers */
582 if (nv50->vtxbuf_nr == 0)
583 return NULL;
584
585 if (NV50_USING_LOATHED_EDGEFLAG(nv50))
586 nv50->vbo_fifo = 0xffff;
587 nv50->vbo_fifo = 0xffff;
588
589 n_ve = MAX2(nv50->vtxelt->num_elements, nv50->state.vtxelt_nr);
590
591 vtxattr = NULL;
592 vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt->num_elements * 4);
593 vtxfmt = so_new(1, n_ve, 0);
594 so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
595
596 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
597 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
598 struct pipe_vertex_buffer *vb =
599 &nv50->vtxbuf[ve->vertex_buffer_index];
600 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
601 uint32_t hw = nv50->vtxelt->hw[i];
602
603 if (!vb->stride &&
604 nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
605 so_data(vtxfmt, hw | (1 << 4));
606
607 so_method(vtxbuf, tesla,
608 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
609 so_data (vtxbuf, 0);
610
611 nv50->vbo_fifo &= ~(1 << i);
612 continue;
613 }
614
615 if (nv50->vbo_fifo) {
616 so_data (vtxfmt, hw | (ve->instance_divisor ? (1 << 4) : i));
617 so_method(vtxbuf, tesla,
618 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
619 so_data (vtxbuf, 0);
620 continue;
621 }
622
623 so_data(vtxfmt, hw | i);
624
625 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
626 so_data (vtxbuf, 0x20000000 |
627 (ve->instance_divisor ? 0 : vb->stride));
628 so_reloc (vtxbuf, bo, vb->buffer_offset +
629 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
630 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
631 so_reloc (vtxbuf, bo, vb->buffer_offset +
632 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
633 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
634
635 /* vertex array limits */
636 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
637 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
638 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
639 NOUVEAU_BO_HIGH, 0, 0);
640 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
641 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
642 NOUVEAU_BO_LOW, 0, 0);
643 }
644 for (; i < n_ve; ++i) {
645 so_data (vtxfmt, 0x7e080010);
646
647 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
648 so_data (vtxbuf, 0);
649 }
650 nv50->state.vtxelt_nr = nv50->vtxelt->num_elements;
651
652 so_ref (vtxbuf, &nv50->state.vtxbuf);
653 so_ref (vtxattr, &nv50->state.vtxattr);
654 so_ref (NULL, &vtxbuf);
655 so_ref (NULL, &vtxattr);
656 return vtxfmt;
657 }
658
659