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