nv50: reimplement draw_elements_instance(), use for draw_elements() too
[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 "nv50_context.h"
29
30 #define NV50_USING_LOATHED_EDGEFLAG(ctx) ((ctx)->vertprog->cfg.edgeflag_in < 16)
31
32 static INLINE unsigned
33 nv50_prim(unsigned mode)
34 {
35 switch (mode) {
36 case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
37 case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
38 case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
39 case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
40 case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
41 case PIPE_PRIM_TRIANGLE_STRIP:
42 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
43 case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
44 case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
45 case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
46 case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
47 case PIPE_PRIM_LINES_ADJACENCY:
48 return NV50TCL_VERTEX_BEGIN_LINES_ADJACENCY;
49 case PIPE_PRIM_LINE_STRIP_ADJACENCY:
50 return NV50TCL_VERTEX_BEGIN_LINE_STRIP_ADJACENCY;
51 case PIPE_PRIM_TRIANGLES_ADJACENCY:
52 return NV50TCL_VERTEX_BEGIN_TRIANGLES_ADJACENCY;
53 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
54 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP_ADJACENCY;
55 default:
56 break;
57 }
58
59 NOUVEAU_ERR("invalid primitive type %d\n", mode);
60 return NV50TCL_VERTEX_BEGIN_POINTS;
61 }
62
63 static INLINE uint32_t
64 nv50_vbo_type_to_hw(enum pipe_format format)
65 {
66 const struct util_format_description *desc;
67
68 desc = util_format_description(format);
69 assert(desc);
70
71 switch (desc->channel[0].type) {
72 case UTIL_FORMAT_TYPE_FLOAT:
73 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT;
74 case UTIL_FORMAT_TYPE_UNSIGNED:
75 if (desc->channel[0].normalized) {
76 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UNORM;
77 }
78 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_USCALED;
79 case UTIL_FORMAT_TYPE_SIGNED:
80 if (desc->channel[0].normalized) {
81 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SNORM;
82 }
83 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SSCALED;
84 /*
85 case PIPE_FORMAT_TYPE_UINT:
86 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UINT;
87 case PIPE_FORMAT_TYPE_SINT:
88 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SINT; */
89 default:
90 return 0;
91 }
92 }
93
94 static INLINE uint32_t
95 nv50_vbo_size_to_hw(unsigned size, unsigned nr_c)
96 {
97 static const uint32_t hw_values[] = {
98 0, 0, 0, 0,
99 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8,
100 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8,
101 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8,
102 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8_8,
103 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16,
104 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16,
105 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16,
106 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16_16,
107 0, 0, 0, 0,
108 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32,
109 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32,
110 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32,
111 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 };
112
113 /* we'd also have R11G11B10 and R10G10B10A2 */
114
115 assert(nr_c > 0 && nr_c <= 4);
116
117 if (size > 32)
118 return 0;
119 size >>= (3 - 2);
120
121 return hw_values[size + (nr_c - 1)];
122 }
123
124 static INLINE uint32_t
125 nv50_vbo_vtxelt_to_hw(struct pipe_vertex_element *ve)
126 {
127 uint32_t hw_type, hw_size;
128 enum pipe_format pf = ve->src_format;
129 const struct util_format_description *desc;
130 unsigned size, nr_components;
131
132 desc = util_format_description(pf);
133 assert(desc);
134
135 size = util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0);
136 nr_components = util_format_get_nr_components(pf);
137
138 hw_type = nv50_vbo_type_to_hw(pf);
139 hw_size = nv50_vbo_size_to_hw(size, nr_components);
140
141 if (!hw_type || !hw_size) {
142 NOUVEAU_ERR("unsupported vbo format: %s\n", util_format_name(pf));
143 abort();
144 return 0x24e80000;
145 }
146
147 if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z) /* BGRA */
148 hw_size |= (1 << 31); /* no real swizzle bits :-( */
149
150 return (hw_type | hw_size);
151 }
152
153 struct instance {
154 struct nouveau_bo *bo;
155 unsigned delta;
156 unsigned stride;
157 unsigned step;
158 unsigned divisor;
159 };
160
161 static void
162 instance_init(struct nv50_context *nv50, struct instance *a, unsigned first)
163 {
164 int i;
165
166 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
167 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
168 struct pipe_vertex_buffer *vb;
169
170 a[i].divisor = ve->instance_divisor;
171 if (a[i].divisor) {
172 vb = &nv50->vtxbuf[ve->vertex_buffer_index];
173
174 a[i].bo = nouveau_bo(vb->buffer);
175 a[i].stride = vb->stride;
176 a[i].step = first % a[i].divisor;
177 a[i].delta = vb->buffer_offset + ve->src_offset +
178 (first * a[i].stride);
179 }
180 }
181 }
182
183 static void
184 instance_step(struct nv50_context *nv50, struct instance *a)
185 {
186 struct nouveau_channel *chan = nv50->screen->tesla->channel;
187 struct nouveau_grobj *tesla = nv50->screen->tesla;
188 int i;
189
190 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
191 if (!a[i].divisor)
192 continue;
193
194 BEGIN_RING(chan, tesla,
195 NV50TCL_VERTEX_ARRAY_START_HIGH(i), 2);
196 OUT_RELOCh(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD |
197 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART);
198 OUT_RELOCl(chan, a[i].bo, a[i].delta, NOUVEAU_BO_RD |
199 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART);
200 if (++a[i].step == a[i].divisor) {
201 a[i].step = 0;
202 a[i].delta += a[i].stride;
203 }
204 }
205 }
206
207 void
208 nv50_draw_arrays_instanced(struct pipe_context *pipe,
209 unsigned mode, unsigned start, unsigned count,
210 unsigned startInstance, unsigned instanceCount)
211 {
212 struct nv50_context *nv50 = nv50_context(pipe);
213 struct nouveau_channel *chan = nv50->screen->tesla->channel;
214 struct nouveau_grobj *tesla = nv50->screen->tesla;
215 struct instance a[16];
216 unsigned prim = nv50_prim(mode);
217
218 instance_init(nv50, a, startInstance);
219 if (!nv50_state_validate(nv50, 10 + 16*3))
220 return;
221
222 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
223 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
224 OUT_RING (chan, startInstance);
225 while (instanceCount--) {
226 if (AVAIL_RING(chan) < (7 + 16*3)) {
227 FIRE_RING(chan);
228 if (!nv50_state_validate(nv50, 7 + 16*3)) {
229 assert(0);
230 return;
231 }
232 }
233 instance_step(nv50, a);
234
235 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
236 OUT_RING (chan, prim);
237 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
238 OUT_RING (chan, start);
239 OUT_RING (chan, count);
240 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
241 OUT_RING (chan, 0);
242
243 prim |= (1 << 28);
244 }
245 }
246
247 void
248 nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
249 unsigned count)
250 {
251 nv50_draw_arrays_instanced(pipe, mode, start, count, 0, 1);
252 }
253
254 static INLINE boolean
255 nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map,
256 unsigned start, unsigned count)
257 {
258 struct nouveau_channel *chan = nv50->screen->tesla->channel;
259 struct nouveau_grobj *tesla = nv50->screen->tesla;
260
261 map += start;
262
263 if (count & 1) {
264 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
265 OUT_RING (chan, map[0]);
266 map++;
267 count--;
268 }
269
270 while (count) {
271 unsigned nr = count > 2046 ? 2046 : count;
272 int i;
273
274 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
275 for (i = 0; i < nr; i += 2)
276 OUT_RING (chan, (map[i + 1] << 16) | map[i]);
277
278 count -= nr;
279 map += nr;
280 }
281 return TRUE;
282 }
283
284 static INLINE boolean
285 nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map,
286 unsigned start, unsigned count)
287 {
288 struct nouveau_channel *chan = nv50->screen->tesla->channel;
289 struct nouveau_grobj *tesla = nv50->screen->tesla;
290
291 map += start;
292
293 if (count & 1) {
294 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
295 OUT_RING (chan, map[0]);
296 map++;
297 count--;
298 }
299
300 while (count) {
301 unsigned nr = count > 2046 ? 2046 : count;
302 int i;
303
304 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
305 for (i = 0; i < nr; i += 2)
306 OUT_RING (chan, (map[i + 1] << 16) | map[i]);
307
308 count -= nr;
309 map += nr;
310 }
311 return TRUE;
312 }
313
314 static INLINE boolean
315 nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint32_t *map,
316 unsigned start, unsigned count)
317 {
318 struct nouveau_channel *chan = nv50->screen->tesla->channel;
319 struct nouveau_grobj *tesla = nv50->screen->tesla;
320
321 map += start;
322
323 while (count) {
324 unsigned nr = count > 2047 ? 2047 : count;
325
326 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, nr);
327 OUT_RINGp (chan, map, nr);
328
329 count -= nr;
330 map += nr;
331 }
332 return TRUE;
333 }
334
335 static void
336 nv50_draw_elements_inline(struct pipe_context *pipe,
337 struct pipe_buffer *indexBuffer, unsigned indexSize,
338 unsigned mode, unsigned start, unsigned count,
339 unsigned startInstance, unsigned instanceCount)
340 {
341 struct pipe_screen *pscreen = pipe->screen;
342 struct nv50_context *nv50 = nv50_context(pipe);
343 struct nouveau_channel *chan = nv50->screen->tesla->channel;
344 struct nouveau_grobj *tesla = nv50->screen->tesla;
345 struct instance a[16];
346 unsigned prim = nv50_prim(mode);
347 void *map;
348
349 map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
350 assert(map);
351 if (!map)
352 return;
353
354 instance_init(nv50, a, startInstance);
355 if (!nv50_state_validate(nv50, 0))
356 return;
357
358 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
359 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
360 OUT_RING (chan, startInstance);
361 while (instanceCount--) {
362 if (AVAIL_RING(chan) < (7 + 16*3)) {
363 FIRE_RING(chan);
364 if (!nv50_state_validate(nv50, 0)) {
365 assert(0);
366 return;
367 }
368 }
369 instance_step(nv50, a);
370
371 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
372 OUT_RING (chan, prim);
373 switch (indexSize) {
374 case 1:
375 nv50_draw_elements_inline_u08(nv50, map, start, count);
376 break;
377 case 2:
378 nv50_draw_elements_inline_u16(nv50, map, start, count);
379 break;
380 case 4:
381 nv50_draw_elements_inline_u32(nv50, map, start, count);
382 break;
383 default:
384 assert(0);
385 break;
386 }
387 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
388 OUT_RING (chan, 0);
389
390 prim |= (1 << 28);
391 }
392
393 pipe_buffer_unmap(pscreen, indexBuffer);
394 }
395
396 void
397 nv50_draw_elements_instanced(struct pipe_context *pipe,
398 struct pipe_buffer *indexBuffer,
399 unsigned indexSize,
400 unsigned mode, unsigned start, unsigned count,
401 unsigned startInstance, unsigned instanceCount)
402 {
403 struct nv50_context *nv50 = nv50_context(pipe);
404 struct nouveau_channel *chan = nv50->screen->tesla->channel;
405 struct nouveau_grobj *tesla = nv50->screen->tesla;
406 struct instance a[16];
407 unsigned prim = nv50_prim(mode);
408
409 if (indexSize == 1) {
410 nv50_draw_elements_inline(pipe, indexBuffer, indexSize,
411 mode, start, count, startInstance,
412 instanceCount);
413 return;
414 }
415
416 instance_init(nv50, a, startInstance);
417 if (!nv50_state_validate(nv50, 13 + 16*3))
418 return;
419
420 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
421 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
422 OUT_RING (chan, startInstance);
423 while (instanceCount--) {
424 if (AVAIL_RING(chan) < (7 + 16*3)) {
425 FIRE_RING(chan);
426 if (!nv50_state_validate(nv50, 10 + 16*3)) {
427 assert(0);
428 return;
429 }
430 }
431 instance_step(nv50, a);
432
433 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
434 OUT_RING (chan, prim);
435 if (indexSize == 4) {
436 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32 | 0x30000, 0);
437 OUT_RING (chan, count);
438 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
439 start << 2, count << 2);
440 } else
441 if (indexSize == 2) {
442 unsigned vb_start = (start & ~1);
443 unsigned vb_end = (start + count + 1) & ~1;
444 unsigned dwords = (vb_end - vb_start) >> 1;
445
446 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
447 OUT_RING (chan, ((start & 1) << 31) | count);
448 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16 | 0x30000, 0);
449 OUT_RING (chan, dwords);
450 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
451 vb_start << 1, dwords << 2);
452 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
453 OUT_RING (chan, 0);
454 }
455 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
456 OUT_RING (chan, 0);
457
458 prim |= (1 << 28);
459 }
460 }
461
462 void
463 nv50_draw_elements(struct pipe_context *pipe,
464 struct pipe_buffer *indexBuffer, unsigned indexSize,
465 unsigned mode, unsigned start, unsigned count)
466 {
467 nv50_draw_elements_instanced(pipe, indexBuffer, indexSize,
468 mode, start, count, 0, 1);
469 }
470
471 static INLINE boolean
472 nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
473 struct nouveau_stateobj **pso,
474 struct pipe_vertex_element *ve,
475 struct pipe_vertex_buffer *vb)
476
477 {
478 struct nouveau_stateobj *so;
479 struct nouveau_grobj *tesla = nv50->screen->tesla;
480 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
481 float v[4];
482 int ret;
483 unsigned nr_components = util_format_get_nr_components(ve->src_format);
484
485 ret = nouveau_bo_map(bo, NOUVEAU_BO_RD);
486 if (ret)
487 return FALSE;
488
489 util_format_read_4f(ve->src_format, v, 0, (uint8_t *)bo->map +
490 (vb->buffer_offset + ve->src_offset), 0,
491 0, 0, 1, 1);
492 so = *pso;
493 if (!so)
494 *pso = so = so_new(nv50->vtxelt->num_elements,
495 nv50->vtxelt->num_elements * 4, 0);
496
497 switch (nr_components) {
498 case 4:
499 so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4);
500 so_data (so, fui(v[0]));
501 so_data (so, fui(v[1]));
502 so_data (so, fui(v[2]));
503 so_data (so, fui(v[3]));
504 break;
505 case 3:
506 so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3);
507 so_data (so, fui(v[0]));
508 so_data (so, fui(v[1]));
509 so_data (so, fui(v[2]));
510 break;
511 case 2:
512 so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2);
513 so_data (so, fui(v[0]));
514 so_data (so, fui(v[1]));
515 break;
516 case 1:
517 if (attrib == nv50->vertprog->cfg.edgeflag_in) {
518 so_method(so, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
519 so_data (so, v[0] ? 1 : 0);
520 }
521 so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
522 so_data (so, fui(v[0]));
523 break;
524 default:
525 nouveau_bo_unmap(bo);
526 return FALSE;
527 }
528
529 nouveau_bo_unmap(bo);
530 return TRUE;
531 }
532
533 void
534 nv50_vtxelt_construct(struct nv50_vtxelt_stateobj *cso)
535 {
536 unsigned i;
537
538 for (i = 0; i < cso->num_elements; ++i) {
539 struct pipe_vertex_element *ve = &cso->pipe[i];
540
541 cso->hw[i] = nv50_vbo_vtxelt_to_hw(ve);
542 }
543 }
544
545 struct nouveau_stateobj *
546 nv50_vbo_validate(struct nv50_context *nv50)
547 {
548 struct nouveau_grobj *tesla = nv50->screen->tesla;
549 struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
550 unsigned i, n_ve;
551
552 /* don't validate if Gallium took away our buffers */
553 if (nv50->vtxbuf_nr == 0)
554 return NULL;
555
556 assert(!NV50_USING_LOATHED_EDGEFLAG(nv50));
557
558 n_ve = MAX2(nv50->vtxelt->num_elements, nv50->state.vtxelt_nr);
559
560 vtxattr = NULL;
561 vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt->num_elements * 4);
562 vtxfmt = so_new(1, n_ve, 0);
563 so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
564
565 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
566 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
567 struct pipe_vertex_buffer *vb =
568 &nv50->vtxbuf[ve->vertex_buffer_index];
569 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
570 uint32_t hw = nv50->vtxelt->hw[i];
571
572 if (!vb->stride &&
573 nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
574 so_data(vtxfmt, hw | (1 << 4));
575
576 so_method(vtxbuf, tesla,
577 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
578 so_data (vtxbuf, 0);
579 continue;
580 }
581
582 so_data(vtxfmt, hw | i);
583
584 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
585 so_data (vtxbuf, 0x20000000 |
586 (ve->instance_divisor ? 0 : vb->stride));
587 so_reloc (vtxbuf, bo, vb->buffer_offset +
588 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
589 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
590 so_reloc (vtxbuf, bo, vb->buffer_offset +
591 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
592 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
593
594 /* vertex array limits */
595 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
596 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
597 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
598 NOUVEAU_BO_HIGH, 0, 0);
599 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
600 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
601 NOUVEAU_BO_LOW, 0, 0);
602 }
603 for (; i < n_ve; ++i) {
604 so_data (vtxfmt, 0x7e080010);
605
606 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
607 so_data (vtxbuf, 0);
608 }
609 nv50->state.vtxelt_nr = nv50->vtxelt->num_elements;
610
611 so_ref (vtxbuf, &nv50->state.vtxbuf);
612 so_ref (vtxattr, &nv50->state.vtxattr);
613 so_ref (NULL, &vtxbuf);
614 so_ref (NULL, &vtxattr);
615 return vtxfmt;
616 }
617
618