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