nv50: when doing inline indices, split elt lists so they fit into pushbuf
[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 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
224 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
225 OUT_RING (chan, startInstance);
226 while (instanceCount--) {
227 if (AVAIL_RING(chan) < (7 + 16*3)) {
228 FIRE_RING(chan);
229 if (!nv50_state_validate(nv50, 7 + 16*3)) {
230 assert(0);
231 return;
232 }
233 }
234 instance_step(nv50, a);
235
236 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
237 OUT_RING (chan, prim);
238 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
239 OUT_RING (chan, start);
240 OUT_RING (chan, count);
241 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
242 OUT_RING (chan, 0);
243
244 prim |= (1 << 28);
245 }
246 }
247
248 void
249 nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
250 unsigned count)
251 {
252 nv50_draw_arrays_instanced(pipe, mode, start, count, 0, 1);
253 }
254
255 struct inline_ctx {
256 struct nv50_context *nv50;
257 void *map;
258 };
259
260 static void
261 inline_elt08(void *priv, unsigned start, unsigned count)
262 {
263 struct inline_ctx *ctx = priv;
264 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
265 struct nouveau_channel *chan = tesla->channel;
266 uint8_t *map = (uint8_t *)ctx->map + start;
267
268 if (count & 1) {
269 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
270 OUT_RING (chan, map[0]);
271 map++;
272 count &= ~1;
273 }
274
275 count >>= 1;
276 if (!count)
277 return;
278
279 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
280 while (count--) {
281 OUT_RING(chan, (map[1] << 16) | map[0]);
282 map += 2;
283 }
284 }
285
286 static void
287 inline_elt16(void *priv, unsigned start, unsigned count)
288 {
289 struct inline_ctx *ctx = priv;
290 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
291 struct nouveau_channel *chan = tesla->channel;
292 uint16_t *map = (uint16_t *)ctx->map + start;
293
294 if (count & 1) {
295 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
296 OUT_RING (chan, map[0]);
297 count &= ~1;
298 map++;
299 }
300
301 count >>= 1;
302 if (!count)
303 return;
304
305 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, count);
306 while (count--) {
307 OUT_RING(chan, (map[1] << 16) | map[0]);
308 map += 2;
309 }
310 }
311
312 static void
313 inline_elt32(void *priv, unsigned start, unsigned count)
314 {
315 struct inline_ctx *ctx = priv;
316 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
317 struct nouveau_channel *chan = tesla->channel;
318
319 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, count);
320 OUT_RINGp (chan, (uint32_t *)ctx->map + start, count);
321 }
322
323 static void
324 inline_edgeflag(void *priv, boolean enabled)
325 {
326 struct inline_ctx *ctx = priv;
327 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
328 struct nouveau_channel *chan = tesla->channel;
329
330 BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
331 OUT_RING (chan, enabled ? 1 : 0);
332 }
333
334 static void
335 nv50_draw_elements_inline(struct pipe_context *pipe,
336 struct pipe_buffer *indexBuffer, unsigned indexSize,
337 unsigned mode, unsigned start, unsigned count,
338 unsigned startInstance, unsigned instanceCount)
339 {
340 struct pipe_screen *pscreen = pipe->screen;
341 struct nv50_context *nv50 = nv50_context(pipe);
342 struct nouveau_channel *chan = nv50->screen->tesla->channel;
343 struct nouveau_grobj *tesla = nv50->screen->tesla;
344 struct instance a[16];
345 struct inline_ctx ctx;
346 struct u_split_prim s;
347 boolean nzi = FALSE;
348 unsigned overhead;
349
350 overhead = 16*3; /* potential instance adjustments */
351 overhead += 4; /* Begin()/End() */
352 overhead += 4; /* potential edgeflag disable/reenable */
353 overhead += 3; /* potentially 3 VTX_ELT_U16/U32 packet headers */
354
355 s.priv = &ctx;
356 if (indexSize == 1)
357 s.emit = inline_elt08;
358 else
359 if (indexSize == 2)
360 s.emit = inline_elt16;
361 else
362 s.emit = inline_elt32;
363 s.edge = inline_edgeflag;
364
365 ctx.nv50 = nv50;
366 ctx.map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
367 assert(ctx.map);
368 if (!ctx.map)
369 return;
370
371 instance_init(nv50, a, startInstance);
372 if (!nv50_state_validate(nv50, overhead + 6 + 3))
373 return;
374
375 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
376 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
377 OUT_RING (chan, startInstance);
378 while (instanceCount--) {
379 unsigned max_verts;
380 boolean done;
381
382 u_split_prim_init(&s, mode, start, count);
383 do {
384 if (AVAIL_RING(chan) < (overhead + 6)) {
385 FIRE_RING(chan);
386 if (!nv50_state_validate(nv50, (overhead + 6))) {
387 assert(0);
388 return;
389 }
390 }
391
392 max_verts = AVAIL_RING(chan) - overhead;
393 if (max_verts > 2047)
394 max_verts = 2047;
395 if (indexSize != 4)
396 max_verts <<= 1;
397 instance_step(nv50, a);
398
399 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
400 OUT_RING (chan, nv50_prim(s.mode) | (nzi ? (1<<28) : 0));
401 done = u_split_prim_next(&s, max_verts);
402 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
403 OUT_RING (chan, 0);
404 } while (!done);
405
406 nzi = TRUE;
407 }
408
409 pipe_buffer_unmap(pscreen, indexBuffer);
410 }
411
412 void
413 nv50_draw_elements_instanced(struct pipe_context *pipe,
414 struct pipe_buffer *indexBuffer,
415 unsigned indexSize,
416 unsigned mode, unsigned start, unsigned count,
417 unsigned startInstance, unsigned instanceCount)
418 {
419 struct nv50_context *nv50 = nv50_context(pipe);
420 struct nouveau_channel *chan = nv50->screen->tesla->channel;
421 struct nouveau_grobj *tesla = nv50->screen->tesla;
422 struct instance a[16];
423 unsigned prim = nv50_prim(mode);
424
425 if (!(indexBuffer->usage & PIPE_BUFFER_USAGE_INDEX) ||
426 indexSize == 1) {
427 nv50_draw_elements_inline(pipe, indexBuffer, indexSize,
428 mode, start, count, startInstance,
429 instanceCount);
430 return;
431 }
432
433 instance_init(nv50, a, startInstance);
434 if (!nv50_state_validate(nv50, 13 + 16*3))
435 return;
436
437 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
438 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
439 OUT_RING (chan, startInstance);
440 while (instanceCount--) {
441 if (AVAIL_RING(chan) < (7 + 16*3)) {
442 FIRE_RING(chan);
443 if (!nv50_state_validate(nv50, 10 + 16*3)) {
444 assert(0);
445 return;
446 }
447 }
448 instance_step(nv50, a);
449
450 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
451 OUT_RING (chan, prim);
452 if (indexSize == 4) {
453 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32 | 0x30000, 0);
454 OUT_RING (chan, count);
455 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
456 start << 2, count << 2);
457 } else
458 if (indexSize == 2) {
459 unsigned vb_start = (start & ~1);
460 unsigned vb_end = (start + count + 1) & ~1;
461 unsigned dwords = (vb_end - vb_start) >> 1;
462
463 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
464 OUT_RING (chan, ((start & 1) << 31) | count);
465 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16 | 0x30000, 0);
466 OUT_RING (chan, dwords);
467 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
468 vb_start << 1, dwords << 2);
469 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
470 OUT_RING (chan, 0);
471 }
472 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
473 OUT_RING (chan, 0);
474
475 prim |= (1 << 28);
476 }
477 }
478
479 void
480 nv50_draw_elements(struct pipe_context *pipe,
481 struct pipe_buffer *indexBuffer, unsigned indexSize,
482 unsigned mode, unsigned start, unsigned count)
483 {
484 nv50_draw_elements_instanced(pipe, indexBuffer, indexSize,
485 mode, start, count, 0, 1);
486 }
487
488 static INLINE boolean
489 nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
490 struct nouveau_stateobj **pso,
491 struct pipe_vertex_element *ve,
492 struct pipe_vertex_buffer *vb)
493
494 {
495 struct nouveau_stateobj *so;
496 struct nouveau_grobj *tesla = nv50->screen->tesla;
497 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
498 float v[4];
499 int ret;
500 unsigned nr_components = util_format_get_nr_components(ve->src_format);
501
502 ret = nouveau_bo_map(bo, NOUVEAU_BO_RD);
503 if (ret)
504 return FALSE;
505
506 util_format_read_4f(ve->src_format, v, 0, (uint8_t *)bo->map +
507 (vb->buffer_offset + ve->src_offset), 0,
508 0, 0, 1, 1);
509 so = *pso;
510 if (!so)
511 *pso = so = so_new(nv50->vtxelt->num_elements,
512 nv50->vtxelt->num_elements * 4, 0);
513
514 switch (nr_components) {
515 case 4:
516 so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4);
517 so_data (so, fui(v[0]));
518 so_data (so, fui(v[1]));
519 so_data (so, fui(v[2]));
520 so_data (so, fui(v[3]));
521 break;
522 case 3:
523 so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3);
524 so_data (so, fui(v[0]));
525 so_data (so, fui(v[1]));
526 so_data (so, fui(v[2]));
527 break;
528 case 2:
529 so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2);
530 so_data (so, fui(v[0]));
531 so_data (so, fui(v[1]));
532 break;
533 case 1:
534 if (attrib == nv50->vertprog->cfg.edgeflag_in) {
535 so_method(so, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
536 so_data (so, v[0] ? 1 : 0);
537 }
538 so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
539 so_data (so, fui(v[0]));
540 break;
541 default:
542 nouveau_bo_unmap(bo);
543 return FALSE;
544 }
545
546 nouveau_bo_unmap(bo);
547 return TRUE;
548 }
549
550 void
551 nv50_vtxelt_construct(struct nv50_vtxelt_stateobj *cso)
552 {
553 unsigned i;
554
555 for (i = 0; i < cso->num_elements; ++i) {
556 struct pipe_vertex_element *ve = &cso->pipe[i];
557
558 cso->hw[i] = nv50_vbo_vtxelt_to_hw(ve);
559 }
560 }
561
562 struct nouveau_stateobj *
563 nv50_vbo_validate(struct nv50_context *nv50)
564 {
565 struct nouveau_grobj *tesla = nv50->screen->tesla;
566 struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
567 unsigned i, n_ve;
568
569 /* don't validate if Gallium took away our buffers */
570 if (nv50->vtxbuf_nr == 0)
571 return NULL;
572
573 assert(!NV50_USING_LOATHED_EDGEFLAG(nv50));
574
575 n_ve = MAX2(nv50->vtxelt->num_elements, nv50->state.vtxelt_nr);
576
577 vtxattr = NULL;
578 vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt->num_elements * 4);
579 vtxfmt = so_new(1, n_ve, 0);
580 so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
581
582 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
583 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
584 struct pipe_vertex_buffer *vb =
585 &nv50->vtxbuf[ve->vertex_buffer_index];
586 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
587 uint32_t hw = nv50->vtxelt->hw[i];
588
589 if (!vb->stride &&
590 nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
591 so_data(vtxfmt, hw | (1 << 4));
592
593 so_method(vtxbuf, tesla,
594 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
595 so_data (vtxbuf, 0);
596 continue;
597 }
598
599 so_data(vtxfmt, hw | i);
600
601 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
602 so_data (vtxbuf, 0x20000000 |
603 (ve->instance_divisor ? 0 : vb->stride));
604 so_reloc (vtxbuf, bo, vb->buffer_offset +
605 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
606 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
607 so_reloc (vtxbuf, bo, vb->buffer_offset +
608 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
609 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
610
611 /* vertex array limits */
612 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
613 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
614 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
615 NOUVEAU_BO_HIGH, 0, 0);
616 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
617 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
618 NOUVEAU_BO_LOW, 0, 0);
619 }
620 for (; i < n_ve; ++i) {
621 so_data (vtxfmt, 0x7e080010);
622
623 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
624 so_data (vtxbuf, 0);
625 }
626 nv50->state.vtxelt_nr = nv50->vtxelt->num_elements;
627
628 so_ref (vtxbuf, &nv50->state.vtxbuf);
629 so_ref (vtxattr, &nv50->state.vtxattr);
630 so_ref (NULL, &vtxbuf);
631 so_ref (NULL, &vtxattr);
632 return vtxfmt;
633 }
634
635