Home | History | Annotate | Download | only in nvc0
      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->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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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