gallium: add PIPE_CAP_TGSI_CAN_READ_OUTPUTS
[mesa.git] / src / gallium / drivers / nouveau / nvc0 / nvc0_vbo_translate.c
1
2 #include "pipe/p_context.h"
3 #include "pipe/p_state.h"
4 #include "util/u_inlines.h"
5 #include "util/u_format.h"
6 #include "translate/translate.h"
7
8 #include "nvc0/nvc0_context.h"
9 #include "nvc0/nvc0_resource.h"
10
11 #include "nvc0/nvc0_3d.xml.h"
12
13 struct push_context {
14 struct nouveau_pushbuf *push;
15
16 struct translate *translate;
17 void *dest;
18 const void *idxbuf;
19
20 uint32_t vertex_size;
21 uint32_t restart_index;
22 uint32_t start_instance;
23 uint32_t instance_id;
24
25 bool prim_restart;
26 bool need_vertex_id;
27
28 struct {
29 bool enabled;
30 bool value;
31 uint8_t width;
32 unsigned stride;
33 const uint8_t *data;
34 } edgeflag;
35 };
36
37 static void nvc0_push_upload_vertex_ids(struct push_context *,
38 struct nvc0_context *,
39 const struct pipe_draw_info *);
40
41 static void
42 nvc0_push_context_init(struct nvc0_context *nvc0, struct push_context *ctx)
43 {
44 ctx->push = nvc0->base.pushbuf;
45
46 ctx->translate = nvc0->vertex->translate;
47 ctx->vertex_size = nvc0->vertex->size;
48 ctx->instance_id = 0;
49
50 ctx->need_vertex_id =
51 nvc0->vertprog->vp.need_vertex_id && (nvc0->vertex->num_elements < 32);
52
53 ctx->edgeflag.value = true;
54 ctx->edgeflag.enabled = nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS;
55
56 /* silence warnings */
57 ctx->edgeflag.data = NULL;
58 ctx->edgeflag.stride = 0;
59 ctx->edgeflag.width = 0;
60 }
61
62 static inline void
63 nvc0_vertex_configure_translate(struct nvc0_context *nvc0, int32_t index_bias)
64 {
65 struct translate *translate = nvc0->vertex->translate;
66 unsigned i;
67
68 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
69 const uint8_t *map;
70 const struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
71
72 if (likely(!vb->buffer))
73 map = (const uint8_t *)vb->user_buffer;
74 else
75 map = nouveau_resource_map_offset(&nvc0->base,
76 nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD);
77
78 if (index_bias && !unlikely(nvc0->vertex->instance_bufs & (1 << i)))
79 map += (intptr_t)index_bias * vb->stride;
80
81 translate->set_buffer(translate, i, map, vb->stride, ~0);
82 }
83 }
84
85 static inline void
86 nvc0_push_map_idxbuf(struct push_context *ctx, struct nvc0_context *nvc0)
87 {
88 if (nvc0->idxbuf.buffer) {
89 struct nv04_resource *buf = nv04_resource(nvc0->idxbuf.buffer);
90 ctx->idxbuf = nouveau_resource_map_offset(&nvc0->base,
91 buf, nvc0->idxbuf.offset, NOUVEAU_BO_RD);
92 } else {
93 ctx->idxbuf = nvc0->idxbuf.user_buffer;
94 }
95 }
96
97 static inline void
98 nvc0_push_map_edgeflag(struct push_context *ctx, struct nvc0_context *nvc0,
99 int32_t index_bias)
100 {
101 unsigned attr = nvc0->vertprog->vp.edgeflag;
102 struct pipe_vertex_element *ve = &nvc0->vertex->element[attr].pipe;
103 struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];
104 struct nv04_resource *buf = nv04_resource(vb->buffer);
105
106 ctx->edgeflag.stride = vb->stride;
107 ctx->edgeflag.width = util_format_get_blocksize(ve->src_format);
108 if (buf) {
109 unsigned offset = vb->buffer_offset + ve->src_offset;
110 ctx->edgeflag.data = nouveau_resource_map_offset(&nvc0->base,
111 buf, offset, NOUVEAU_BO_RD);
112 } else {
113 ctx->edgeflag.data = (const uint8_t *)vb->user_buffer + ve->src_offset;
114 }
115
116 if (index_bias)
117 ctx->edgeflag.data += (intptr_t)index_bias * vb->stride;
118 }
119
120 static inline unsigned
121 prim_restart_search_i08(const uint8_t *elts, unsigned push, uint8_t index)
122 {
123 unsigned i;
124 for (i = 0; i < push && elts[i] != index; ++i);
125 return i;
126 }
127
128 static inline unsigned
129 prim_restart_search_i16(const uint16_t *elts, unsigned push, uint16_t index)
130 {
131 unsigned i;
132 for (i = 0; i < push && elts[i] != index; ++i);
133 return i;
134 }
135
136 static inline unsigned
137 prim_restart_search_i32(const uint32_t *elts, unsigned push, uint32_t index)
138 {
139 unsigned i;
140 for (i = 0; i < push && elts[i] != index; ++i);
141 return i;
142 }
143
144 static inline bool
145 ef_value_8(const struct push_context *ctx, uint32_t index)
146 {
147 uint8_t *pf = (uint8_t *)&ctx->edgeflag.data[index * ctx->edgeflag.stride];
148 return !!*pf;
149 }
150
151 static inline bool
152 ef_value_32(const struct push_context *ctx, uint32_t index)
153 {
154 uint32_t *pf = (uint32_t *)&ctx->edgeflag.data[index * ctx->edgeflag.stride];
155 return !!*pf;
156 }
157
158 static inline bool
159 ef_toggle(struct push_context *ctx)
160 {
161 ctx->edgeflag.value = !ctx->edgeflag.value;
162 return ctx->edgeflag.value;
163 }
164
165 static inline unsigned
166 ef_toggle_search_i08(struct push_context *ctx, const uint8_t *elts, unsigned n)
167 {
168 unsigned i;
169 bool ef = ctx->edgeflag.value;
170 if (ctx->edgeflag.width == 1)
171 for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
172 else
173 for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
174 return i;
175 }
176
177 static inline unsigned
178 ef_toggle_search_i16(struct push_context *ctx, const uint16_t *elts, unsigned n)
179 {
180 unsigned i;
181 bool ef = ctx->edgeflag.value;
182 if (ctx->edgeflag.width == 1)
183 for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
184 else
185 for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
186 return i;
187 }
188
189 static inline unsigned
190 ef_toggle_search_i32(struct push_context *ctx, const uint32_t *elts, unsigned n)
191 {
192 unsigned i;
193 bool ef = ctx->edgeflag.value;
194 if (ctx->edgeflag.width == 1)
195 for (i = 0; i < n && ef_value_8(ctx, elts[i]) == ef; ++i);
196 else
197 for (i = 0; i < n && ef_value_32(ctx, elts[i]) == ef; ++i);
198 return i;
199 }
200
201 static inline unsigned
202 ef_toggle_search_seq(struct push_context *ctx, unsigned start, unsigned n)
203 {
204 unsigned i;
205 bool ef = ctx->edgeflag.value;
206 if (ctx->edgeflag.width == 1)
207 for (i = 0; i < n && ef_value_8(ctx, start++) == ef; ++i);
208 else
209 for (i = 0; i < n && ef_value_32(ctx, start++) == ef; ++i);
210 return i;
211 }
212
213 static inline void *
214 nvc0_push_setup_vertex_array(struct nvc0_context *nvc0, const unsigned count)
215 {
216 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
217 struct nouveau_bo *bo;
218 uint64_t va;
219 const unsigned size = count * nvc0->vertex->size;
220
221 void *const dest = nouveau_scratch_get(&nvc0->base, size, &va, &bo);
222
223 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_START_HIGH(0)), 2);
224 PUSH_DATAh(push, va);
225 PUSH_DATA (push, va);
226 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(0)), 2);
227 PUSH_DATAh(push, va + size - 1);
228 PUSH_DATA (push, va + size - 1);
229
230 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
231 bo);
232 nouveau_pushbuf_validate(push);
233
234 return dest;
235 }
236
237 static void
238 disp_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
239 {
240 struct nouveau_pushbuf *push = ctx->push;
241 struct translate *translate = ctx->translate;
242 const uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start;
243 unsigned pos = 0;
244
245 do {
246 unsigned nR = count;
247
248 if (unlikely(ctx->prim_restart))
249 nR = prim_restart_search_i08(elts, nR, ctx->restart_index);
250
251 translate->run_elts8(translate, elts, nR,
252 ctx->start_instance, ctx->instance_id, ctx->dest);
253 count -= nR;
254 ctx->dest += nR * ctx->vertex_size;
255
256 while (nR) {
257 unsigned nE = nR;
258
259 if (unlikely(ctx->edgeflag.enabled))
260 nE = ef_toggle_search_i08(ctx, elts, nR);
261
262 PUSH_SPACE(push, 4);
263 if (likely(nE >= 2)) {
264 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
265 PUSH_DATA (push, pos);
266 PUSH_DATA (push, nE);
267 } else
268 if (nE) {
269 if (pos <= 0xff) {
270 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos);
271 } else {
272 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
273 PUSH_DATA (push, pos);
274 }
275 }
276 if (unlikely(nE != nR))
277 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx));
278
279 pos += nE;
280 elts += nE;
281 nR -= nE;
282 }
283 if (count) {
284 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
285 PUSH_DATA (push, 0xffffffff);
286 ++elts;
287 ctx->dest += ctx->vertex_size;
288 ++pos;
289 --count;
290 }
291 } while (count);
292 }
293
294 static void
295 disp_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
296 {
297 struct nouveau_pushbuf *push = ctx->push;
298 struct translate *translate = ctx->translate;
299 const uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start;
300 unsigned pos = 0;
301
302 do {
303 unsigned nR = count;
304
305 if (unlikely(ctx->prim_restart))
306 nR = prim_restart_search_i16(elts, nR, ctx->restart_index);
307
308 translate->run_elts16(translate, elts, nR,
309 ctx->start_instance, ctx->instance_id, ctx->dest);
310 count -= nR;
311 ctx->dest += nR * ctx->vertex_size;
312
313 while (nR) {
314 unsigned nE = nR;
315
316 if (unlikely(ctx->edgeflag.enabled))
317 nE = ef_toggle_search_i16(ctx, elts, nR);
318
319 PUSH_SPACE(push, 4);
320 if (likely(nE >= 2)) {
321 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
322 PUSH_DATA (push, pos);
323 PUSH_DATA (push, nE);
324 } else
325 if (nE) {
326 if (pos <= 0xff) {
327 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos);
328 } else {
329 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
330 PUSH_DATA (push, pos);
331 }
332 }
333 if (unlikely(nE != nR))
334 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx));
335
336 pos += nE;
337 elts += nE;
338 nR -= nE;
339 }
340 if (count) {
341 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
342 PUSH_DATA (push, 0xffffffff);
343 ++elts;
344 ctx->dest += ctx->vertex_size;
345 ++pos;
346 --count;
347 }
348 } while (count);
349 }
350
351 static void
352 disp_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
353 {
354 struct nouveau_pushbuf *push = ctx->push;
355 struct translate *translate = ctx->translate;
356 const uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start;
357 unsigned pos = 0;
358
359 do {
360 unsigned nR = count;
361
362 if (unlikely(ctx->prim_restart))
363 nR = prim_restart_search_i32(elts, nR, ctx->restart_index);
364
365 translate->run_elts(translate, elts, nR,
366 ctx->start_instance, ctx->instance_id, ctx->dest);
367 count -= nR;
368 ctx->dest += nR * ctx->vertex_size;
369
370 while (nR) {
371 unsigned nE = nR;
372
373 if (unlikely(ctx->edgeflag.enabled))
374 nE = ef_toggle_search_i32(ctx, elts, nR);
375
376 PUSH_SPACE(push, 4);
377 if (likely(nE >= 2)) {
378 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
379 PUSH_DATA (push, pos);
380 PUSH_DATA (push, nE);
381 } else
382 if (nE) {
383 if (pos <= 0xff) {
384 IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_U32), pos);
385 } else {
386 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
387 PUSH_DATA (push, pos);
388 }
389 }
390 if (unlikely(nE != nR))
391 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx));
392
393 pos += nE;
394 elts += nE;
395 nR -= nE;
396 }
397 if (count) {
398 BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
399 PUSH_DATA (push, 0xffffffff);
400 ++elts;
401 ctx->dest += ctx->vertex_size;
402 ++pos;
403 --count;
404 }
405 } while (count);
406 }
407
408 static void
409 disp_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
410 {
411 struct nouveau_pushbuf *push = ctx->push;
412 struct translate *translate = ctx->translate;
413 unsigned pos = 0;
414
415 /* XXX: This will read the data corresponding to the primitive restart index,
416 * maybe we should avoid that ?
417 */
418 translate->run(translate, start, count,
419 ctx->start_instance, ctx->instance_id, ctx->dest);
420 do {
421 unsigned nr = count;
422
423 if (unlikely(ctx->edgeflag.enabled))
424 nr = ef_toggle_search_seq(ctx, start + pos, nr);
425
426 PUSH_SPACE(push, 4);
427 if (likely(nr)) {
428 BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
429 PUSH_DATA (push, pos);
430 PUSH_DATA (push, nr);
431 }
432 if (unlikely(nr != count))
433 IMMED_NVC0(push, NVC0_3D(EDGEFLAG), ef_toggle(ctx));
434
435 pos += nr;
436 count -= nr;
437 } while (count);
438 }
439
440
441 #define NVC0_PRIM_GL_CASE(n) \
442 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
443
444 static inline unsigned
445 nvc0_prim_gl(unsigned prim)
446 {
447 switch (prim) {
448 NVC0_PRIM_GL_CASE(POINTS);
449 NVC0_PRIM_GL_CASE(LINES);
450 NVC0_PRIM_GL_CASE(LINE_LOOP);
451 NVC0_PRIM_GL_CASE(LINE_STRIP);
452 NVC0_PRIM_GL_CASE(TRIANGLES);
453 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
454 NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
455 NVC0_PRIM_GL_CASE(QUADS);
456 NVC0_PRIM_GL_CASE(QUAD_STRIP);
457 NVC0_PRIM_GL_CASE(POLYGON);
458 NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
459 NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
460 NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
461 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
462 NVC0_PRIM_GL_CASE(PATCHES);
463 default:
464 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
465 }
466 }
467
468 void
469 nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
470 {
471 struct push_context ctx;
472 unsigned i, index_size;
473 unsigned inst_count = info->instance_count;
474 unsigned vert_count = info->count;
475 unsigned prim;
476
477 nvc0_push_context_init(nvc0, &ctx);
478
479 nvc0_vertex_configure_translate(nvc0, info->index_bias);
480
481 if (nvc0->state.index_bias) {
482 /* this is already taken care of by translate */
483 IMMED_NVC0(ctx.push, NVC0_3D(VB_ELEMENT_BASE), 0);
484 nvc0->state.index_bias = 0;
485 }
486
487 if (unlikely(ctx.edgeflag.enabled))
488 nvc0_push_map_edgeflag(&ctx, nvc0, info->index_bias);
489
490 ctx.prim_restart = info->primitive_restart;
491 ctx.restart_index = info->restart_index;
492
493 if (info->primitive_restart) {
494 /* NOTE: I hope we won't ever need that last index (~0).
495 * If we do, we have to disable primitive restart here always and
496 * use END,BEGIN to restart. (XXX: would that affect PrimitiveID ?)
497 * We could also deactive PRIM_RESTART_WITH_DRAW_ARRAYS temporarily,
498 * and add manual restart to disp_vertices_seq.
499 */
500 BEGIN_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 2);
501 PUSH_DATA (ctx.push, 1);
502 PUSH_DATA (ctx.push, info->indexed ? 0xffffffff : info->restart_index);
503 } else
504 if (nvc0->state.prim_restart) {
505 IMMED_NVC0(ctx.push, NVC0_3D(PRIM_RESTART_ENABLE), 0);
506 }
507 nvc0->state.prim_restart = info->primitive_restart;
508
509 if (info->indexed) {
510 nvc0_push_map_idxbuf(&ctx, nvc0);
511 index_size = nvc0->idxbuf.index_size;
512 } else {
513 if (unlikely(info->count_from_stream_output)) {
514 struct pipe_context *pipe = &nvc0->base.pipe;
515 struct nvc0_so_target *targ;
516 targ = nvc0_so_target(info->count_from_stream_output);
517 pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
518 vert_count /= targ->stride;
519 }
520 ctx.idxbuf = NULL; /* shut up warnings */
521 index_size = 0;
522 }
523
524 ctx.start_instance = info->start_instance;
525
526 prim = nvc0_prim_gl(info->mode);
527 do {
528 PUSH_SPACE(ctx.push, 9);
529
530 ctx.dest = nvc0_push_setup_vertex_array(nvc0, vert_count);
531 if (unlikely(!ctx.dest))
532 break;
533
534 if (unlikely(ctx.need_vertex_id))
535 nvc0_push_upload_vertex_ids(&ctx, nvc0, info);
536
537 if (nvc0->screen->eng3d->oclass < GM107_3D_CLASS)
538 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
539 BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_BEGIN_GL), 1);
540 PUSH_DATA (ctx.push, prim);
541 switch (index_size) {
542 case 1:
543 disp_vertices_i08(&ctx, info->start, vert_count);
544 break;
545 case 2:
546 disp_vertices_i16(&ctx, info->start, vert_count);
547 break;
548 case 4:
549 disp_vertices_i32(&ctx, info->start, vert_count);
550 break;
551 default:
552 assert(index_size == 0);
553 disp_vertices_seq(&ctx, info->start, vert_count);
554 break;
555 }
556 PUSH_SPACE(ctx.push, 1);
557 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_END_GL), 0);
558
559 if (--inst_count) {
560 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
561 ++ctx.instance_id;
562 }
563 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX_TMP);
564 nouveau_scratch_done(&nvc0->base);
565 } while (inst_count);
566
567
568 /* reset state and unmap buffers (no-op) */
569
570 if (unlikely(!ctx.edgeflag.value)) {
571 PUSH_SPACE(ctx.push, 1);
572 IMMED_NVC0(ctx.push, NVC0_3D(EDGEFLAG), 1);
573 }
574
575 if (unlikely(ctx.need_vertex_id)) {
576 PUSH_SPACE(ctx.push, 4);
577 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 0);
578 BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(1)), 1);
579 PUSH_DATA (ctx.push,
580 NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST |
581 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
582 NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
583 IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 0);
584 }
585
586 if (info->indexed)
587 nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
588 for (i = 0; i < nvc0->num_vtxbufs; ++i)
589 nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
590
591 NOUVEAU_DRV_STAT(&nvc0->screen->base, draw_calls_fallback_count, 1);
592 }
593
594 static inline void
595 copy_indices_u8(uint32_t *dst, const uint8_t *elts, uint32_t bias, unsigned n)
596 {
597 unsigned i;
598 for (i = 0; i < n; ++i)
599 dst[i] = elts[i] + bias;
600 }
601
602 static inline void
603 copy_indices_u16(uint32_t *dst, const uint16_t *elts, uint32_t bias, unsigned n)
604 {
605 unsigned i;
606 for (i = 0; i < n; ++i)
607 dst[i] = elts[i] + bias;
608 }
609
610 static inline void
611 copy_indices_u32(uint32_t *dst, const uint32_t *elts, uint32_t bias, unsigned n)
612 {
613 unsigned i;
614 for (i = 0; i < n; ++i)
615 dst[i] = elts[i] + bias;
616 }
617
618 static void
619 nvc0_push_upload_vertex_ids(struct push_context *ctx,
620 struct nvc0_context *nvc0,
621 const struct pipe_draw_info *info)
622
623 {
624 struct nouveau_pushbuf *push = ctx->push;
625 struct nouveau_bo *bo;
626 uint64_t va;
627 uint32_t *data;
628 uint32_t format;
629 unsigned index_size = nvc0->idxbuf.index_size;
630 unsigned i;
631 unsigned a = nvc0->vertex->num_elements;
632
633 if (!index_size || info->index_bias)
634 index_size = 4;
635 data = (uint32_t *)nouveau_scratch_get(&nvc0->base,
636 info->count * index_size, &va, &bo);
637
638 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_VTX_TMP, NOUVEAU_BO_GART | NOUVEAU_BO_RD,
639 bo);
640 nouveau_pushbuf_validate(push);
641
642 if (info->indexed) {
643 if (!info->index_bias) {
644 memcpy(data, ctx->idxbuf, info->count * index_size);
645 } else {
646 switch (nvc0->idxbuf.index_size) {
647 case 1:
648 copy_indices_u8(data, ctx->idxbuf, info->index_bias, info->count);
649 break;
650 case 2:
651 copy_indices_u16(data, ctx->idxbuf, info->index_bias, info->count);
652 break;
653 default:
654 copy_indices_u32(data, ctx->idxbuf, info->index_bias, info->count);
655 break;
656 }
657 }
658 } else {
659 for (i = 0; i < info->count; ++i)
660 data[i] = i + (info->start + info->index_bias);
661 }
662
663 format = (1 << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT) |
664 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_UINT;
665
666 switch (index_size) {
667 case 1:
668 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_8;
669 break;
670 case 2:
671 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_16;
672 break;
673 default:
674 format |= NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32;
675 break;
676 }
677
678 PUSH_SPACE(push, 12);
679
680 if (unlikely(nvc0->state.instance_elts & 2)) {
681 nvc0->state.instance_elts &= ~2;
682 IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(1)), 0);
683 }
684
685 BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
686 PUSH_DATA (push, format);
687
688 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(1)), 3);
689 PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | index_size);
690 PUSH_DATAh(push, va);
691 PUSH_DATA (push, va);
692 BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(1)), 2);
693 PUSH_DATAh(push, va + info->count * index_size - 1);
694 PUSH_DATA (push, va + info->count * index_size - 1);
695
696 #define NVC0_3D_VERTEX_ID_REPLACE_SOURCE_ATTR_X(a) \
697 (((0x80 + (a) * 0x10) / 4) << NVC0_3D_VERTEX_ID_REPLACE_SOURCE__SHIFT)
698
699 BEGIN_NVC0(push, NVC0_3D(VERTEX_ID_REPLACE), 1);
700 PUSH_DATA (push, NVC0_3D_VERTEX_ID_REPLACE_SOURCE_ATTR_X(a) | 1);
701 }