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_context.h"
      9 #include "nvc0_resource.h"
     10 
     11 #include "nvc0_3d.xml.h"
     12 
     13 struct push_context {
     14    struct nouveau_pushbuf *push;
     15 
     16    void *idxbuf;
     17 
     18    uint32_t vertex_words;
     19    uint32_t packet_vertex_limit;
     20 
     21    struct translate *translate;
     22 
     23    boolean primitive_restart;
     24    boolean need_vertex_id;
     25    uint32_t prim;
     26    uint32_t restart_index;
     27    uint32_t instance_id;
     28 
     29    struct {
     30       int buffer;
     31       float value;
     32       uint8_t *data;
     33       unsigned offset;
     34       unsigned stride;
     35    } edgeflag;
     36 };
     37 
     38 static void
     39 init_push_context(struct nvc0_context *nvc0, struct push_context *ctx)
     40 {
     41    struct pipe_vertex_element *ve;
     42 
     43    ctx->push = nvc0->base.pushbuf;
     44    ctx->translate = nvc0->vertex->translate;
     45 
     46    if (likely(nvc0->vertex->num_elements < 32))
     47       ctx->need_vertex_id = nvc0->vertprog->vp.need_vertex_id;
     48    else
     49       ctx->need_vertex_id = FALSE;
     50 
     51    ctx->edgeflag.buffer = -1;
     52    ctx->edgeflag.value = 0.5f;
     53 
     54    if (unlikely(nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS)) {
     55       ve = &nvc0->vertex->element[nvc0->vertprog->vp.edgeflag].pipe;
     56       ctx->edgeflag.buffer = ve->vertex_buffer_index;
     57       ctx->edgeflag.offset = ve->src_offset;
     58       ctx->packet_vertex_limit = 1;
     59    } else {
     60       ctx->packet_vertex_limit = nvc0->vertex->vtx_per_packet_max;
     61       if (unlikely(ctx->need_vertex_id))
     62          ctx->packet_vertex_limit = 1;
     63    }
     64 
     65    ctx->vertex_words = nvc0->vertex->vtx_size;
     66 }
     67 
     68 static INLINE void
     69 set_edgeflag(struct push_context *ctx, unsigned vtx_id)
     70 {
     71    float f = *(float *)(ctx->edgeflag.data + vtx_id * ctx->edgeflag.stride);
     72 
     73    if (ctx->edgeflag.value != f) {
     74       ctx->edgeflag.value = f;
     75       IMMED_NVC0(ctx->push, NVC0_3D(EDGEFLAG), f ? 1 : 0);
     76    }
     77 }
     78 
     79 static INLINE void
     80 set_vertexid(struct push_context *ctx, uint32_t vtx_id)
     81 {
     82 #if 0
     83    BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_ID), 1); /* broken on nvc0 */
     84 #else
     85    BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_DATA), 1); /* as last attribute */
     86 #endif
     87    PUSH_DATA (ctx->push, vtx_id);
     88 }
     89 
     90 static INLINE unsigned
     91 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
     92 {
     93    unsigned i;
     94    for (i = 0; i < push; ++i)
     95       if (elts[i] == index)
     96          break;
     97    return i;
     98 }
     99 
    100 static INLINE unsigned
    101 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
    102 {
    103    unsigned i;
    104    for (i = 0; i < push; ++i)
    105       if (elts[i] == index)
    106          break;
    107    return i;
    108 }
    109 
    110 static INLINE unsigned
    111 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
    112 {
    113    unsigned i;
    114    for (i = 0; i < push; ++i)
    115       if (elts[i] == index)
    116          break;
    117    return i;
    118 }
    119 
    120 static void
    121 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
    122 {
    123    uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start;
    124 
    125    while (count) {
    126       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    127       unsigned size, nr;
    128 
    129       nr = push;
    130       if (ctx->primitive_restart)
    131          nr = prim_restart_search_i08(elts, push, ctx->restart_index);
    132 
    133       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
    134          set_edgeflag(ctx, elts[0]);
    135 
    136       size = ctx->vertex_words * nr;
    137 
    138       BEGIN_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
    139 
    140       ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id,
    141                                 ctx->push->cur);
    142       ctx->push->cur += size;
    143 
    144       if (unlikely(ctx->need_vertex_id) && likely(size))
    145          set_vertexid(ctx, elts[0]);
    146 
    147       count -= nr;
    148       elts += nr;
    149 
    150       if (nr != push) {
    151          count--;
    152          elts++;
    153          BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
    154          PUSH_DATA (ctx->push, 0);
    155          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
    156                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
    157       }
    158    }
    159 }
    160 
    161 static void
    162 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
    163 {
    164    uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start;
    165 
    166    while (count) {
    167       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    168       unsigned size, nr;
    169 
    170       nr = push;
    171       if (ctx->primitive_restart)
    172          nr = prim_restart_search_i16(elts, push, ctx->restart_index);
    173 
    174       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
    175          set_edgeflag(ctx, elts[0]);
    176 
    177       size = ctx->vertex_words * nr;
    178 
    179       BEGIN_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
    180 
    181       ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id,
    182                                  ctx->push->cur);
    183       ctx->push->cur += size;
    184 
    185       if (unlikely(ctx->need_vertex_id))
    186          set_vertexid(ctx, elts[0]);
    187 
    188       count -= nr;
    189       elts += nr;
    190 
    191       if (nr != push) {
    192          count--;
    193          elts++;
    194          BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
    195          PUSH_DATA (ctx->push, 0);
    196          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
    197                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
    198       }
    199    }
    200 }
    201 
    202 static void
    203 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
    204 {
    205    uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start;
    206 
    207    while (count) {
    208       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    209       unsigned size, nr;
    210 
    211       nr = push;
    212       if (ctx->primitive_restart)
    213          nr = prim_restart_search_i32(elts, push, ctx->restart_index);
    214 
    215       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
    216          set_edgeflag(ctx, elts[0]);
    217 
    218       size = ctx->vertex_words * nr;
    219 
    220       BEGIN_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
    221 
    222       ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id,
    223                                ctx->push->cur);
    224       ctx->push->cur += size;
    225 
    226       if (unlikely(ctx->need_vertex_id))
    227          set_vertexid(ctx, elts[0]);
    228 
    229       count -= nr;
    230       elts += nr;
    231 
    232       if (nr != push) {
    233          count--;
    234          elts++;
    235          BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
    236          PUSH_DATA (ctx->push, 0);
    237          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
    238                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
    239       }
    240    }
    241 }
    242 
    243 static void
    244 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
    245 {
    246    while (count) {
    247       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    248       unsigned size = ctx->vertex_words * push;
    249 
    250       if (unlikely(ctx->edgeflag.buffer >= 0))
    251          set_edgeflag(ctx, start);
    252 
    253       BEGIN_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
    254 
    255       ctx->translate->run(ctx->translate, start, push, ctx->instance_id,
    256                           ctx->push->cur);
    257       ctx->push->cur += size;
    258 
    259       if (unlikely(ctx->need_vertex_id))
    260          set_vertexid(ctx, start);
    261 
    262       count -= push;
    263       start += push;
    264    }
    265 }
    266 
    267 
    268 #define NVC0_PRIM_GL_CASE(n) \
    269    case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
    270 
    271 static INLINE unsigned
    272 nvc0_prim_gl(unsigned prim)
    273 {
    274    switch (prim) {
    275    NVC0_PRIM_GL_CASE(POINTS);
    276    NVC0_PRIM_GL_CASE(LINES);
    277    NVC0_PRIM_GL_CASE(LINE_LOOP);
    278    NVC0_PRIM_GL_CASE(LINE_STRIP);
    279    NVC0_PRIM_GL_CASE(TRIANGLES);
    280    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
    281    NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
    282    NVC0_PRIM_GL_CASE(QUADS);
    283    NVC0_PRIM_GL_CASE(QUAD_STRIP);
    284    NVC0_PRIM_GL_CASE(POLYGON);
    285    NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
    286    NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
    287    NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
    288    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
    289    /*
    290    NVC0_PRIM_GL_CASE(PATCHES); */
    291    default:
    292       return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
    293       break;
    294    }
    295 }
    296 
    297 void
    298 nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
    299 {
    300    struct push_context ctx;
    301    unsigned i, index_size;
    302    unsigned inst_count = info->instance_count;
    303    unsigned vert_count = info->count;
    304    boolean apply_bias = info->indexed && info->index_bias;
    305 
    306    init_push_context(nvc0, &ctx);
    307 
    308    for (i = 0; i < nvc0->num_vtxbufs; ++i) {
    309       uint8_t *data;
    310       struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
    311       struct nv04_resource *res = nv04_resource(vb->buffer);
    312 
    313       data = nouveau_resource_map_offset(&nvc0->base, res,
    314                                          vb->buffer_offset, NOUVEAU_BO_RD);
    315 
    316       if (apply_bias && likely(!(nvc0->vertex->instance_bufs & (1 << i))))
    317          data += info->index_bias * vb->stride;
    318 
    319       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
    320 
    321       if (unlikely(i == ctx.edgeflag.buffer)) {
    322          ctx.edgeflag.data = data + ctx.edgeflag.offset;
    323          ctx.edgeflag.stride = vb->stride;
    324       }
    325    }
    326 
    327    if (info->indexed) {
    328       ctx.idxbuf =
    329          nouveau_resource_map_offset(&nvc0->base,
    330                                      nv04_resource(nvc0->idxbuf.buffer),
    331                                      nvc0->idxbuf.offset, NOUVEAU_BO_RD);
    332       if (!ctx.idxbuf)
    333          return;
    334       index_size = nvc0->idxbuf.index_size;
    335       ctx.primitive_restart = info->primitive_restart;
    336       ctx.restart_index = info->restart_index;
    337    } else {
    338       ctx.idxbuf = NULL;
    339       index_size = 0;
    340       ctx.primitive_restart = FALSE;
    341       ctx.restart_index = 0;
    342 
    343       if (info->count_from_stream_output) {
    344          struct pipe_context *pipe = &nvc0->base.pipe;
    345          struct nvc0_so_target *targ;
    346          targ = nvc0_so_target(info->count_from_stream_output);
    347          pipe->get_query_result(pipe, targ->pq, TRUE, (void*)&vert_count);
    348          vert_count /= targ->stride;
    349       }
    350    }
    351 
    352    ctx.instance_id = info->start_instance;
    353    ctx.prim = nvc0_prim_gl(info->mode);
    354 
    355    if (unlikely(ctx.need_vertex_id)) {
    356       const unsigned a = nvc0->vertex->num_elements;
    357       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
    358       PUSH_DATA (ctx.push, (a << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT) |
    359                  NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
    360                  NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
    361       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 1);
    362       PUSH_DATA (ctx.push, (((0x80 + a * 0x10) / 4) << 4) | 1);
    363    }
    364 
    365    while (inst_count--) {
    366       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_BEGIN_GL), 1);
    367       PUSH_DATA (ctx.push, ctx.prim);
    368       switch (index_size) {
    369       case 0:
    370          emit_vertices_seq(&ctx, info->start, vert_count);
    371          break;
    372       case 1:
    373          emit_vertices_i08(&ctx, info->start, vert_count);
    374          break;
    375       case 2:
    376          emit_vertices_i16(&ctx, info->start, vert_count);
    377          break;
    378       case 4:
    379          emit_vertices_i32(&ctx, info->start, vert_count);
    380          break;
    381       default:
    382          assert(0);
    383          break;
    384       }
    385       IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_END_GL), 0);
    386 
    387       ctx.instance_id++;
    388       ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    389    }
    390 
    391    if (unlikely(ctx.edgeflag.value == 0.0f))
    392       IMMED_NVC0(ctx.push, NVC0_3D(EDGEFLAG), 1);
    393 
    394    if (unlikely(ctx.need_vertex_id)) {
    395       const unsigned a = nvc0->vertex->num_elements;
    396       IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 0);
    397       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
    398       PUSH_DATA (ctx.push,
    399                  NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST |
    400                  NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
    401                  NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
    402    }
    403 
    404    if (info->indexed)
    405       nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
    406 
    407    for (i = 0; i < nvc0->num_vtxbufs; ++i)
    408       nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
    409 }
    410