Home | History | Annotate | Download | only in nv30
      1 /*
      2  * Copyright 2012 Red Hat Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * Authors: Ben Skeggs
     23  *
     24  */
     25 
     26 #include "pipe/p_context.h"
     27 #include "pipe/p_state.h"
     28 #include "util/u_inlines.h"
     29 #include "util/u_format.h"
     30 #include "translate/translate.h"
     31 
     32 #include "nv_object.xml.h"
     33 #include "nv30/nv30-40_3d.xml.h"
     34 #include "nv30/nv30_context.h"
     35 #include "nv30/nv30_resource.h"
     36 
     37 struct push_context {
     38    struct nouveau_pushbuf *push;
     39 
     40    const void *idxbuf;
     41 
     42    float edgeflag;
     43    int edgeflag_attr;
     44 
     45    uint32_t vertex_words;
     46    uint32_t packet_vertex_limit;
     47 
     48    struct translate *translate;
     49 
     50    bool primitive_restart;
     51    uint32_t prim;
     52    uint32_t restart_index;
     53 };
     54 
     55 static inline unsigned
     56 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
     57 {
     58    unsigned i;
     59    for (i = 0; i < push; ++i)
     60       if (elts[i] == index)
     61          break;
     62    return i;
     63 }
     64 
     65 static inline unsigned
     66 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
     67 {
     68    unsigned i;
     69    for (i = 0; i < push; ++i)
     70       if (elts[i] == index)
     71          break;
     72    return i;
     73 }
     74 
     75 static inline unsigned
     76 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
     77 {
     78    unsigned i;
     79    for (i = 0; i < push; ++i)
     80       if (elts[i] == index)
     81          break;
     82    return i;
     83 }
     84 
     85 static void
     86 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
     87 {
     88    uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
     89 
     90    while (count) {
     91       unsigned push = MIN2(count, ctx->packet_vertex_limit);
     92       unsigned size, nr;
     93 
     94       nr = push;
     95       if (ctx->primitive_restart)
     96          nr = prim_restart_search_i08(elts, push, ctx->restart_index);
     97 
     98       size = ctx->vertex_words * nr;
     99 
    100       BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
    101 
    102       ctx->translate->run_elts8(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
    103 
    104       ctx->push->cur += size;
    105       count -= nr;
    106       elts += nr;
    107 
    108       if (nr != push) {
    109          BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
    110          PUSH_DATA (ctx->push, ctx->restart_index);
    111          count--;
    112          elts++;
    113       }
    114    }
    115 }
    116 
    117 static void
    118 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
    119 {
    120    uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
    121 
    122    while (count) {
    123       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    124       unsigned size, nr;
    125 
    126       nr = push;
    127       if (ctx->primitive_restart)
    128          nr = prim_restart_search_i16(elts, push, ctx->restart_index);
    129 
    130       size = ctx->vertex_words * nr;
    131 
    132       BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
    133 
    134       ctx->translate->run_elts16(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
    135 
    136       ctx->push->cur += size;
    137       count -= nr;
    138       elts += nr;
    139 
    140       if (nr != push) {
    141          BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
    142          PUSH_DATA (ctx->push, ctx->restart_index);
    143          count--;
    144          elts++;
    145       }
    146    }
    147 }
    148 
    149 static void
    150 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
    151 {
    152    uint32_t *elts = (uint32_t *)ctx->idxbuf + start;
    153 
    154    while (count) {
    155       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    156       unsigned size, nr;
    157 
    158       nr = push;
    159       if (ctx->primitive_restart)
    160          nr = prim_restart_search_i32(elts, push, ctx->restart_index);
    161 
    162       size = ctx->vertex_words * nr;
    163 
    164       BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
    165 
    166       ctx->translate->run_elts(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
    167 
    168       ctx->push->cur += size;
    169       count -= nr;
    170       elts += nr;
    171 
    172       if (nr != push) {
    173          BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
    174          PUSH_DATA (ctx->push, ctx->restart_index);
    175          count--;
    176          elts++;
    177       }
    178    }
    179 }
    180 
    181 static void
    182 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
    183 {
    184    while (count) {
    185       unsigned push = MIN2(count, ctx->packet_vertex_limit);
    186       unsigned size = ctx->vertex_words * push;
    187 
    188       BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
    189 
    190       ctx->translate->run(ctx->translate, start, push, 0, 0, ctx->push->cur);
    191       ctx->push->cur += size;
    192       count -= push;
    193       start += push;
    194    }
    195 }
    196 
    197 void
    198 nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info)
    199 {
    200    struct push_context ctx;
    201    unsigned i, index_size;
    202    bool apply_bias = info->index_size && info->index_bias;
    203 
    204    ctx.push = nv30->base.pushbuf;
    205    ctx.translate = nv30->vertex->translate;
    206    ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max;
    207    ctx.vertex_words = nv30->vertex->vtx_size;
    208 
    209    for (i = 0; i < nv30->num_vtxbufs; ++i) {
    210       uint8_t *data;
    211       struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i];
    212       struct nv04_resource *res = nv04_resource(vb->buffer.resource);
    213 
    214       if (!vb->buffer.resource) {
    215          continue;
    216       }
    217 
    218       data = nouveau_resource_map_offset(&nv30->base, res,
    219                                          vb->buffer_offset, NOUVEAU_BO_RD);
    220 
    221       if (apply_bias)
    222          data += info->index_bias * vb->stride;
    223 
    224       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
    225    }
    226 
    227    if (info->index_size) {
    228       if (!info->has_user_indices)
    229          ctx.idxbuf = nouveau_resource_map_offset(&nv30->base,
    230             nv04_resource(info->index.resource), info->start * info->index_size,
    231             NOUVEAU_BO_RD);
    232       else
    233          ctx.idxbuf = info->index.user;
    234       if (!ctx.idxbuf) {
    235          nv30_state_release(nv30);
    236          return;
    237       }
    238       index_size = info->index_size;
    239       ctx.primitive_restart = info->primitive_restart;
    240       ctx.restart_index = info->restart_index;
    241    } else {
    242       ctx.idxbuf = NULL;
    243       index_size = 0;
    244       ctx.primitive_restart = false;
    245       ctx.restart_index = 0;
    246    }
    247 
    248    if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) {
    249       BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2);
    250       PUSH_DATA (ctx.push, info->primitive_restart);
    251       PUSH_DATA (ctx.push, info->restart_index);
    252       nv30->state.prim_restart = info->primitive_restart;
    253    }
    254 
    255    ctx.prim = nv30_prim_gl(info->mode);
    256 
    257    PUSH_RESET(ctx.push, BUFCTX_IDXBUF);
    258    BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
    259    PUSH_DATA (ctx.push, ctx.prim);
    260    switch (index_size) {
    261    case 0:
    262       emit_vertices_seq(&ctx, info->start, info->count);
    263       break;
    264    case 1:
    265       emit_vertices_i08(&ctx, info->start, info->count);
    266       break;
    267    case 2:
    268       emit_vertices_i16(&ctx, info->start, info->count);
    269       break;
    270    case 4:
    271       emit_vertices_i32(&ctx, info->start, info->count);
    272       break;
    273    default:
    274       assert(0);
    275       break;
    276    }
    277    BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
    278    PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP);
    279 
    280    if (info->index_size && !info->has_user_indices)
    281       nouveau_resource_unmap(nv04_resource(info->index.resource));
    282 
    283    for (i = 0; i < nv30->num_vtxbufs; ++i) {
    284       if (nv30->vtxbuf[i].buffer.resource) {
    285          nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer.resource));
    286       }
    287    }
    288 
    289    nv30_state_release(nv30);
    290 }
    291