• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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