Home | History | Annotate | Download | only in nvc0
      1 /*
      2  * Copyright 2010 Christoph Bumiller
      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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  */
     22 
     23 #define NVC0_PUSH_EXPLICIT_SPACE_CHECKING
     24 
     25 #include "pipe/p_context.h"
     26 #include "pipe/p_state.h"
     27 #include "util/u_inlines.h"
     28 #include "util/u_format.h"
     29 #include "translate/translate.h"
     30 
     31 #include "nvc0_context.h"
     32 #include "nvc0_resource.h"
     33 
     34 #include "nvc0_3d.xml.h"
     35 
     36 void
     37 nvc0_vertex_state_delete(struct pipe_context *pipe,
     38                          void *hwcso)
     39 {
     40    struct nvc0_vertex_stateobj *so = hwcso;
     41 
     42    if (so->translate)
     43       so->translate->release(so->translate);
     44    FREE(hwcso);
     45 }
     46 
     47 void *
     48 nvc0_vertex_state_create(struct pipe_context *pipe,
     49                          unsigned num_elements,
     50                          const struct pipe_vertex_element *elements)
     51 {
     52     struct nvc0_vertex_stateobj *so;
     53     struct translate_key transkey;
     54     unsigned i;
     55     unsigned src_offset_max = 0;
     56 
     57     so = MALLOC(sizeof(*so) +
     58                 num_elements * sizeof(struct nvc0_vertex_element));
     59     if (!so)
     60         return NULL;
     61     so->num_elements = num_elements;
     62     so->instance_elts = 0;
     63     so->instance_bufs = 0;
     64     so->shared_slots = FALSE;
     65     so->need_conversion = FALSE;
     66 
     67     memset(so->vb_access_size, 0, sizeof(so->vb_access_size));
     68 
     69     for (i = 0; i < PIPE_MAX_ATTRIBS; ++i)
     70        so->min_instance_div[i] = 0xffffffff;
     71 
     72     transkey.nr_elements = 0;
     73     transkey.output_stride = 0;
     74 
     75     for (i = 0; i < num_elements; ++i) {
     76         const struct pipe_vertex_element *ve = &elements[i];
     77         const unsigned vbi = ve->vertex_buffer_index;
     78         unsigned size;
     79         enum pipe_format fmt = ve->src_format;
     80 
     81         so->element[i].pipe = elements[i];
     82         so->element[i].state = nvc0_format_table[fmt].vtx;
     83 
     84         if (!so->element[i].state) {
     85             switch (util_format_get_nr_components(fmt)) {
     86             case 1: fmt = PIPE_FORMAT_R32_FLOAT; break;
     87             case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break;
     88             case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break;
     89             case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break;
     90             default:
     91                 assert(0);
     92                 return NULL;
     93             }
     94             so->element[i].state = nvc0_format_table[fmt].vtx;
     95             so->need_conversion = TRUE;
     96         }
     97         size = util_format_get_blocksize(fmt);
     98 
     99         src_offset_max = MAX2(src_offset_max, ve->src_offset);
    100 
    101         if (so->vb_access_size[vbi] < (ve->src_offset + size))
    102            so->vb_access_size[vbi] = ve->src_offset + size;
    103 
    104         if (unlikely(ve->instance_divisor)) {
    105            so->instance_elts |= 1 << i;
    106            so->instance_bufs |= 1 << vbi;
    107            if (ve->instance_divisor < so->min_instance_div[vbi])
    108               so->min_instance_div[vbi] = ve->instance_divisor;
    109         }
    110 
    111         if (1) {
    112             unsigned ca;
    113             unsigned j = transkey.nr_elements++;
    114 
    115             ca = util_format_description(fmt)->channel[0].size / 8;
    116             if (ca != 1 && ca != 2)
    117                ca = 4;
    118 
    119             transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL;
    120             transkey.element[j].input_format = ve->src_format;
    121             transkey.element[j].input_buffer = vbi;
    122             transkey.element[j].input_offset = ve->src_offset;
    123             transkey.element[j].instance_divisor = ve->instance_divisor;
    124 
    125             transkey.output_stride = align(transkey.output_stride, ca);
    126             transkey.element[j].output_format = fmt;
    127             transkey.element[j].output_offset = transkey.output_stride;
    128             transkey.output_stride += size;
    129 
    130             so->element[i].state_alt = so->element[i].state;
    131             so->element[i].state_alt |= transkey.element[j].output_offset << 7;
    132         }
    133 
    134         so->element[i].state |= i << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT;
    135     }
    136     transkey.output_stride = align(transkey.output_stride, 4);
    137 
    138     so->size = transkey.output_stride;
    139     so->translate = translate_create(&transkey);
    140 
    141     if (so->instance_elts || src_offset_max >= (1 << 14))
    142        return so;
    143     so->shared_slots = TRUE;
    144 
    145     for (i = 0; i < num_elements; ++i) {
    146        const unsigned b = elements[i].vertex_buffer_index;
    147        const unsigned s = elements[i].src_offset;
    148        so->element[i].state &= ~NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__MASK;
    149        so->element[i].state |= b << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT;
    150        so->element[i].state |= s << NVC0_3D_VERTEX_ATTRIB_FORMAT_OFFSET__SHIFT;
    151     }
    152     return so;
    153 }
    154 
    155 #define NVC0_3D_VERTEX_ATTRIB_INACTIVE                                       \
    156    NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |                                 \
    157    NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32 | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST
    158 
    159 #define VTX_ATTR(a, c, t, s)                            \
    160    ((NVC0_3D_VTX_ATTR_DEFINE_TYPE_##t) |                \
    161     (NVC0_3D_VTX_ATTR_DEFINE_SIZE_##s) |                \
    162     ((a) << NVC0_3D_VTX_ATTR_DEFINE_ATTR__SHIFT) |      \
    163     ((c) << NVC0_3D_VTX_ATTR_DEFINE_COMP__SHIFT))
    164 
    165 static void
    166 nvc0_set_constant_vertex_attrib(struct nvc0_context *nvc0, const unsigned a)
    167 {
    168    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    169    struct pipe_vertex_element *ve = &nvc0->vertex->element[a].pipe;
    170    struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[ve->vertex_buffer_index];
    171    uint32_t mode;
    172    const struct util_format_description *desc;
    173    void *dst;
    174    const void *src = (const uint8_t *)vb->user_buffer + ve->src_offset;
    175    assert(!vb->buffer);
    176 
    177    desc = util_format_description(ve->src_format);
    178 
    179    PUSH_SPACE(push, 6);
    180    BEGIN_NVC0(push, NVC0_3D(VTX_ATTR_DEFINE), 5);
    181    dst = &push->cur[1];
    182    if (desc->channel[0].pure_integer) {
    183       if (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) {
    184          mode = VTX_ATTR(a, 4, SINT, 32);
    185          desc->unpack_rgba_sint(dst, 0, src, 0, 1, 1);
    186       } else {
    187          mode = VTX_ATTR(a, 4, UINT, 32);
    188          desc->unpack_rgba_uint(dst, 0, src, 0, 1, 1);
    189       }
    190    } else {
    191       mode = VTX_ATTR(a, 4, FLOAT, 32);
    192       desc->unpack_rgba_float(dst, 0, src, 0, 1, 1);
    193    }
    194    push->cur[0] = mode;
    195    push->cur += 5;
    196 }
    197 
    198 static INLINE void
    199 nvc0_user_vbuf_range(struct nvc0_context *nvc0, int vbi,
    200                      uint32_t *base, uint32_t *size)
    201 {
    202    if (unlikely(nvc0->vertex->instance_bufs & (1 << vbi))) {
    203       const uint32_t div = nvc0->vertex->min_instance_div[vbi];
    204       *base = nvc0->instance_off * nvc0->vtxbuf[vbi].stride;
    205       *size = (nvc0->instance_max / div) * nvc0->vtxbuf[vbi].stride +
    206          nvc0->vertex->vb_access_size[vbi];
    207    } else {
    208       /* NOTE: if there are user buffers, we *must* have index bounds */
    209       assert(nvc0->vb_elt_limit != ~0);
    210       *base = nvc0->vb_elt_first * nvc0->vtxbuf[vbi].stride;
    211       *size = nvc0->vb_elt_limit * nvc0->vtxbuf[vbi].stride +
    212          nvc0->vertex->vb_access_size[vbi];
    213    }
    214 }
    215 
    216 static INLINE void
    217 nvc0_release_user_vbufs(struct nvc0_context *nvc0)
    218 {
    219    if (nvc0->vbo_user) {
    220       nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX_TMP);
    221       nouveau_scratch_done(&nvc0->base);
    222    }
    223 }
    224 
    225 static void
    226 nvc0_update_user_vbufs(struct nvc0_context *nvc0)
    227 {
    228    uint64_t address[PIPE_MAX_ATTRIBS];
    229    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    230    int i;
    231    uint32_t written = 0;
    232 
    233    PUSH_SPACE(push, nvc0->vertex->num_elements * 8);
    234    for (i = 0; i < nvc0->vertex->num_elements; ++i) {
    235       struct pipe_vertex_element *ve = &nvc0->vertex->element[i].pipe;
    236       const unsigned b = ve->vertex_buffer_index;
    237       struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[b];
    238       uint32_t base, size;
    239 
    240       if (!(nvc0->vbo_user & (1 << b)))
    241          continue;
    242       if (!vb->stride) {
    243          nvc0_set_constant_vertex_attrib(nvc0, i);
    244          continue;
    245       }
    246       nvc0_user_vbuf_range(nvc0, b, &base, &size);
    247 
    248       if (!(written & (1 << b))) {
    249          struct nouveau_bo *bo;
    250          const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;
    251          written |= 1 << b;
    252          address[b] = nouveau_scratch_data(&nvc0->base, vb->user_buffer,
    253                                            base, size, &bo);
    254          if (bo)
    255             BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, bo_flags, bo);
    256       }
    257 
    258       BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);
    259       PUSH_DATA (push, i);
    260       PUSH_DATAh(push, address[b] + base + size - 1);
    261       PUSH_DATA (push, address[b] + base + size - 1);
    262       PUSH_DATAh(push, address[b] + ve->src_offset);
    263       PUSH_DATA (push, address[b] + ve->src_offset);
    264    }
    265    nvc0->base.vbo_dirty = TRUE;
    266 }
    267 
    268 static void
    269 nvc0_update_user_vbufs_shared(struct nvc0_context *nvc0)
    270 {
    271    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    272    uint32_t mask = nvc0->vbo_user & ~nvc0->constant_vbos;
    273 
    274    PUSH_SPACE(push, nvc0->num_vtxbufs * 8);
    275    while (mask) {
    276       struct nouveau_bo *bo;
    277       const uint32_t bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART;
    278       uint64_t address;
    279       uint32_t base, size;
    280       const int b = ffs(mask) - 1;
    281       mask &= ~(1 << b);
    282 
    283       nvc0_user_vbuf_range(nvc0, b, &base, &size);
    284 
    285       address = nouveau_scratch_data(&nvc0->base, nvc0->vtxbuf[b].user_buffer,
    286                                      base, size, &bo);
    287       if (bo)
    288          BCTX_REFN_bo(nvc0->bufctx_3d, VTX_TMP, bo_flags, bo);
    289 
    290       BEGIN_1IC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_SELECT), 5);
    291       PUSH_DATA (push, b);
    292       PUSH_DATAh(push, address + base + size - 1);
    293       PUSH_DATA (push, address + base + size - 1);
    294       PUSH_DATAh(push, address);
    295       PUSH_DATA (push, address);
    296    }
    297 
    298    mask = nvc0->state.constant_elts;
    299    while (mask) {
    300       int i = ffs(mask) - 1;
    301       mask &= ~(1 << i);
    302       nvc0_set_constant_vertex_attrib(nvc0, i);
    303    }
    304 }
    305 
    306 static void
    307 nvc0_validate_vertex_buffers(struct nvc0_context *nvc0)
    308 {
    309    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    310    const struct nvc0_vertex_stateobj *vertex = nvc0->vertex;
    311    uint32_t refd = 0;
    312    unsigned i;
    313 
    314    PUSH_SPACE(push, vertex->num_elements * 8);
    315    for (i = 0; i < vertex->num_elements; ++i) {
    316       const struct nvc0_vertex_element *ve;
    317       const struct pipe_vertex_buffer *vb;
    318       struct nv04_resource *res;
    319       unsigned b;
    320       unsigned limit, offset;
    321 
    322       if (nvc0->state.constant_elts & (1 << i))
    323          continue;
    324       ve = &vertex->element[i];
    325       b = ve->pipe.vertex_buffer_index;
    326       vb = &nvc0->vtxbuf[b];
    327 
    328       if (!vb->buffer) {
    329          if (vb->stride) {
    330             if (ve->pipe.instance_divisor) {
    331                BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_DIVISOR(i)), 1);
    332                PUSH_DATA (push, ve->pipe.instance_divisor);
    333             }
    334             BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 1);
    335             PUSH_DATA (push, (1 << 12) | vb->stride);
    336          }
    337          /* address/value set in nvc0_update_user_vbufs */
    338          continue;
    339       }
    340       res = nv04_resource(vb->buffer);
    341       offset = ve->pipe.src_offset + vb->buffer_offset;
    342       limit = vb->buffer->width0 - 1;
    343 
    344       if (unlikely(ve->pipe.instance_divisor)) {
    345          BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 4);
    346          PUSH_DATA (push, (1 << 12) | vb->stride);
    347          PUSH_DATAh(push, res->address + offset);
    348          PUSH_DATA (push, res->address + offset);
    349          PUSH_DATA (push, ve->pipe.instance_divisor);
    350       } else {
    351          BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 3);
    352          PUSH_DATA (push, (1 << 12) | vb->stride);
    353          PUSH_DATAh(push, res->address + offset);
    354          PUSH_DATA (push, res->address + offset);
    355       }
    356       BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(i)), 2);
    357       PUSH_DATAh(push, res->address + limit);
    358       PUSH_DATA (push, res->address + limit);
    359 
    360       if (!(refd & (1 << b))) {
    361          refd |= 1 << b;
    362          BCTX_REFN(nvc0->bufctx_3d, VTX, res, RD);
    363       }
    364    }
    365    if (nvc0->vbo_user)
    366       nvc0_update_user_vbufs(nvc0);
    367 }
    368 
    369 static void
    370 nvc0_validate_vertex_buffers_shared(struct nvc0_context *nvc0)
    371 {
    372    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    373    unsigned b;
    374    const uint32_t mask = nvc0->vbo_user;
    375 
    376    PUSH_SPACE(push, nvc0->num_vtxbufs * 8);
    377    for (b = 0; b < nvc0->num_vtxbufs; ++b) {
    378       struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[b];
    379       struct nv04_resource *buf;
    380       uint32_t offset, limit;
    381 
    382       if (mask & (1 << b)) {
    383          if (vb->stride) {
    384             BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 1);
    385             PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
    386          }
    387          /* address/value set in nvc0_update_user_vbufs_shared */
    388          continue;
    389       }
    390       buf = nv04_resource(vb->buffer);
    391       offset = vb->buffer_offset;
    392       limit = buf->base.width0 - 1;
    393 
    394       BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(b)), 3);
    395       PUSH_DATA (push, NVC0_3D_VERTEX_ARRAY_FETCH_ENABLE | vb->stride);
    396       PUSH_DATAh(push, buf->address + offset);
    397       PUSH_DATA (push, buf->address + offset);
    398       BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_LIMIT_HIGH(b)), 2);
    399       PUSH_DATAh(push, buf->address + limit);
    400       PUSH_DATA (push, buf->address + limit);
    401 
    402       BCTX_REFN(nvc0->bufctx_3d, VTX, buf, RD);
    403    }
    404    if (nvc0->vbo_user)
    405       nvc0_update_user_vbufs_shared(nvc0);
    406 }
    407 
    408 void
    409 nvc0_vertex_arrays_validate(struct nvc0_context *nvc0)
    410 {
    411    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    412    struct nvc0_vertex_stateobj *vertex = nvc0->vertex;
    413    struct nvc0_vertex_element *ve;
    414    uint32_t const_vbos;
    415    unsigned i;
    416    uint8_t vbo_mode;
    417    boolean update_vertex;
    418 
    419    nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX);
    420 
    421    if (unlikely(vertex->need_conversion) ||
    422        unlikely(nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS)) {
    423       vbo_mode = 3;
    424    } else {
    425       vbo_mode = (nvc0->vbo_user && nvc0->vbo_push_hint) ? 1 : 0;
    426    }
    427    const_vbos = vbo_mode ? 0 : nvc0->constant_vbos;
    428 
    429    update_vertex = (nvc0->dirty & NVC0_NEW_VERTEX) ||
    430       (const_vbos != nvc0->state.constant_vbos) ||
    431       (vbo_mode != nvc0->state.vbo_mode);
    432 
    433    if (update_vertex) {
    434       const unsigned n = MAX2(vertex->num_elements, nvc0->state.num_vtxelts);
    435 
    436       nvc0->state.constant_vbos = const_vbos;
    437       nvc0->state.constant_elts = 0;
    438       nvc0->state.num_vtxelts = vertex->num_elements;
    439       nvc0->state.vbo_mode = vbo_mode;
    440 
    441       if (unlikely(vbo_mode)) {
    442          if (unlikely(nvc0->state.instance_elts & 3)) {
    443             /* translate mode uses only 2 vertex buffers */
    444             nvc0->state.instance_elts &= ~3;
    445             PUSH_SPACE(push, 3);
    446             BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_PER_INSTANCE(0)), 2);
    447             PUSH_DATA (push, 0);
    448             PUSH_DATA (push, 0);
    449          }
    450 
    451          PUSH_SPACE(push, n * 2 + 4);
    452 
    453          BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(0)), n);
    454          for (i = 0; i < vertex->num_elements; ++i)
    455             PUSH_DATA(push, vertex->element[i].state_alt);
    456          for (; i < n; ++i)
    457             PUSH_DATA(push, NVC0_3D_VERTEX_ATTRIB_INACTIVE);
    458 
    459          BEGIN_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(0)), 1);
    460          PUSH_DATA (push, (1 << 12) | vertex->size);
    461          for (i = 1; i < n; ++i)
    462             IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);
    463       } else {
    464          uint32_t *restrict data;
    465 
    466          if (unlikely(vertex->instance_elts != nvc0->state.instance_elts)) {
    467             nvc0->state.instance_elts = vertex->instance_elts;
    468             assert(n); /* if (n == 0), both masks should be 0 */
    469             PUSH_SPACE(push, 3);
    470             BEGIN_NVC0(push, NVC0_3D(MACRO_VERTEX_ARRAY_PER_INSTANCE), 2);
    471             PUSH_DATA (push, n);
    472             PUSH_DATA (push, vertex->instance_elts);
    473          }
    474 
    475          PUSH_SPACE(push, n * 2 + 1);
    476          BEGIN_NVC0(push, NVC0_3D(VERTEX_ATTRIB_FORMAT(0)), n);
    477          data = push->cur;
    478          push->cur += n;
    479          for (i = 0; i < vertex->num_elements; ++i) {
    480             ve = &vertex->element[i];
    481             data[i] = ve->state;
    482             if (unlikely(const_vbos & (1 << ve->pipe.vertex_buffer_index))) {
    483                nvc0->state.constant_elts |= 1 << i;
    484                data[i] |= NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST;
    485                IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);
    486             }
    487          }
    488          for (; i < n; ++i) {
    489             data[i] = NVC0_3D_VERTEX_ATTRIB_INACTIVE;
    490             IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FETCH(i)), 0);
    491          }
    492       }
    493    }
    494    if (nvc0->state.vbo_mode) /* using translate, don't set up arrays here */
    495       return;
    496 
    497    if (vertex->shared_slots)
    498       nvc0_validate_vertex_buffers_shared(nvc0);
    499    else
    500       nvc0_validate_vertex_buffers(nvc0);
    501 }
    502 
    503 void
    504 nvc0_idxbuf_validate(struct nvc0_context *nvc0)
    505 {
    506    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    507    struct nv04_resource *buf = nv04_resource(nvc0->idxbuf.buffer);
    508 
    509    assert(buf);
    510    assert(nouveau_resource_mapped_by_gpu(&buf->base));
    511 
    512    PUSH_SPACE(push, 6);
    513    BEGIN_NVC0(push, NVC0_3D(INDEX_ARRAY_START_HIGH), 5);
    514    PUSH_DATAh(push, buf->address + nvc0->idxbuf.offset);
    515    PUSH_DATA (push, buf->address + nvc0->idxbuf.offset);
    516    PUSH_DATAh(push, buf->address + buf->base.width0 - 1);
    517    PUSH_DATA (push, buf->address + buf->base.width0 - 1);
    518    PUSH_DATA (push, nvc0->idxbuf.index_size >> 1);
    519 
    520    BCTX_REFN(nvc0->bufctx_3d, IDX, buf, RD);
    521 }
    522 
    523 #define NVC0_PRIM_GL_CASE(n) \
    524    case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
    525 
    526 static INLINE unsigned
    527 nvc0_prim_gl(unsigned prim)
    528 {
    529    switch (prim) {
    530    NVC0_PRIM_GL_CASE(POINTS);
    531    NVC0_PRIM_GL_CASE(LINES);
    532    NVC0_PRIM_GL_CASE(LINE_LOOP);
    533    NVC0_PRIM_GL_CASE(LINE_STRIP);
    534    NVC0_PRIM_GL_CASE(TRIANGLES);
    535    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
    536    NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
    537    NVC0_PRIM_GL_CASE(QUADS);
    538    NVC0_PRIM_GL_CASE(QUAD_STRIP);
    539    NVC0_PRIM_GL_CASE(POLYGON);
    540    NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
    541    NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
    542    NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
    543    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
    544    /*
    545    NVC0_PRIM_GL_CASE(PATCHES); */
    546    default:
    547       return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
    548    }
    549 }
    550 
    551 static void
    552 nvc0_draw_vbo_kick_notify(struct nouveau_pushbuf *push)
    553 {
    554    struct nvc0_screen *screen = push->user_priv;
    555 
    556    nouveau_fence_update(&screen->base, TRUE);
    557 }
    558 
    559 static void
    560 nvc0_draw_arrays(struct nvc0_context *nvc0,
    561                  unsigned mode, unsigned start, unsigned count,
    562                  unsigned instance_count)
    563 {
    564    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    565    unsigned prim;
    566 
    567    if (nvc0->state.index_bias) {
    568       PUSH_SPACE(push, 1);
    569       IMMED_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 0);
    570       nvc0->state.index_bias = 0;
    571    }
    572 
    573    prim = nvc0_prim_gl(mode);
    574 
    575    while (instance_count--) {
    576       PUSH_SPACE(push, 6);
    577       BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
    578       PUSH_DATA (push, prim);
    579       BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
    580       PUSH_DATA (push, start);
    581       PUSH_DATA (push, count);
    582       IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
    583 
    584       prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    585    }
    586 }
    587 
    588 static void
    589 nvc0_draw_elements_inline_u08(struct nouveau_pushbuf *push, const uint8_t *map,
    590                               unsigned start, unsigned count)
    591 {
    592    map += start;
    593 
    594    if (count & 3) {
    595       unsigned i;
    596       PUSH_SPACE(push, 4);
    597       BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), count & 3);
    598       for (i = 0; i < (count & 3); ++i)
    599          PUSH_DATA(push, *map++);
    600       count &= ~3;
    601    }
    602    while (count) {
    603       unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4;
    604 
    605       PUSH_SPACE(push, nr + 1);
    606       BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U8), nr);
    607       for (i = 0; i < nr; ++i) {
    608          PUSH_DATA(push,
    609                   (map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]);
    610          map += 4;
    611       }
    612       count -= nr * 4;
    613    }
    614 }
    615 
    616 static void
    617 nvc0_draw_elements_inline_u16(struct nouveau_pushbuf *push, const uint16_t *map,
    618                               unsigned start, unsigned count)
    619 {
    620    map += start;
    621 
    622    if (count & 1) {
    623       count &= ~1;
    624       PUSH_SPACE(push, 2);
    625       BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
    626       PUSH_DATA (push, *map++);
    627    }
    628    while (count) {
    629       unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
    630 
    631       PUSH_SPACE(push, nr + 1);
    632       BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);
    633       for (i = 0; i < nr; ++i) {
    634          PUSH_DATA(push, (map[1] << 16) | map[0]);
    635          map += 2;
    636       }
    637       count -= nr * 2;
    638    }
    639 }
    640 
    641 static void
    642 nvc0_draw_elements_inline_u32(struct nouveau_pushbuf *push, const uint32_t *map,
    643                               unsigned start, unsigned count)
    644 {
    645    map += start;
    646 
    647    while (count) {
    648       const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
    649 
    650       PUSH_SPACE(push, nr + 1);
    651       BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U32), nr);
    652       PUSH_DATAp(push, map, nr);
    653 
    654       map += nr;
    655       count -= nr;
    656    }
    657 }
    658 
    659 static void
    660 nvc0_draw_elements_inline_u32_short(struct nouveau_pushbuf *push,
    661                                     const uint32_t *map,
    662                                     unsigned start, unsigned count)
    663 {
    664    map += start;
    665 
    666    if (count & 1) {
    667       count--;
    668       PUSH_SPACE(push, 1);
    669       BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_U32), 1);
    670       PUSH_DATA (push, *map++);
    671    }
    672    while (count) {
    673       unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
    674 
    675       PUSH_SPACE(push, nr + 1);
    676       BEGIN_NIC0(push, NVC0_3D(VB_ELEMENT_U16), nr);
    677       for (i = 0; i < nr; ++i) {
    678          PUSH_DATA(push, (map[1] << 16) | map[0]);
    679          map += 2;
    680       }
    681       count -= nr * 2;
    682    }
    683 }
    684 
    685 static void
    686 nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten,
    687                    unsigned mode, unsigned start, unsigned count,
    688                    unsigned instance_count, int32_t index_bias)
    689 {
    690    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    691    unsigned prim;
    692    const unsigned index_size = nvc0->idxbuf.index_size;
    693 
    694    prim = nvc0_prim_gl(mode);
    695 
    696    if (index_bias != nvc0->state.index_bias) {
    697       PUSH_SPACE(push, 2);
    698       BEGIN_NVC0(push, NVC0_3D(VB_ELEMENT_BASE), 1);
    699       PUSH_DATA (push, index_bias);
    700       nvc0->state.index_bias = index_bias;
    701    }
    702 
    703    if (nvc0->idxbuf.buffer) {
    704       PUSH_SPACE(push, 1);
    705       IMMED_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), prim);
    706       do {
    707          PUSH_SPACE(push, 7);
    708          BEGIN_NVC0(push, NVC0_3D(INDEX_BATCH_FIRST), 2);
    709          PUSH_DATA (push, start);
    710          PUSH_DATA (push, count);
    711          if (--instance_count) {
    712             BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 2);
    713             PUSH_DATA (push, 0);
    714             PUSH_DATA (push, prim | NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT);
    715          }
    716       } while (instance_count);
    717       IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
    718    } else {
    719       const void *data = nvc0->idxbuf.user_buffer;
    720 
    721       while (instance_count--) {
    722          PUSH_SPACE(push, 2);
    723          BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
    724          PUSH_DATA (push, prim);
    725          switch (index_size) {
    726          case 1:
    727             nvc0_draw_elements_inline_u08(push, data, start, count);
    728             break;
    729          case 2:
    730             nvc0_draw_elements_inline_u16(push, data, start, count);
    731             break;
    732          case 4:
    733             if (shorten)
    734                nvc0_draw_elements_inline_u32_short(push, data, start, count);
    735             else
    736                nvc0_draw_elements_inline_u32(push, data, start, count);
    737             break;
    738          default:
    739             assert(0);
    740             return;
    741          }
    742          PUSH_SPACE(push, 1);
    743          IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
    744 
    745          prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    746       }
    747    }
    748 }
    749 
    750 static void
    751 nvc0_draw_stream_output(struct nvc0_context *nvc0,
    752                         const struct pipe_draw_info *info)
    753 {
    754    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    755    struct nvc0_so_target *so = nvc0_so_target(info->count_from_stream_output);
    756    struct nv04_resource *res = nv04_resource(so->pipe.buffer);
    757    unsigned mode = nvc0_prim_gl(info->mode);
    758    unsigned num_instances = info->instance_count;
    759 
    760    if (res->status & NOUVEAU_BUFFER_STATUS_GPU_WRITING) {
    761       res->status &= ~NOUVEAU_BUFFER_STATUS_GPU_WRITING;
    762       PUSH_SPACE(push, 2);
    763       IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);
    764       nvc0_query_fifo_wait(push, so->pq);
    765       IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
    766    }
    767 
    768    while (num_instances--) {
    769       PUSH_SPACE(push, 8);
    770       BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
    771       PUSH_DATA (push, mode);
    772       BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BASE), 1);
    773       PUSH_DATA (push, 0);
    774       BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_STRIDE), 1);
    775       PUSH_DATA (push, so->stride);
    776       BEGIN_NVC0(push, NVC0_3D(DRAW_TFB_BYTES), 1);
    777       nvc0_query_pushbuf_submit(push, so->pq, 0x4);
    778       IMMED_NVC0(push, NVC0_3D(VERTEX_END_GL), 0);
    779 
    780       mode |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
    781    }
    782 }
    783 
    784 void
    785 nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    786 {
    787    struct nvc0_context *nvc0 = nvc0_context(pipe);
    788    struct nouveau_pushbuf *push = nvc0->base.pushbuf;
    789 
    790    /* NOTE: caller must ensure that (min_index + index_bias) is >= 0 */
    791    nvc0->vb_elt_first = info->min_index + info->index_bias;
    792    nvc0->vb_elt_limit = info->max_index - info->min_index;
    793    nvc0->instance_off = info->start_instance;
    794    nvc0->instance_max = info->instance_count - 1;
    795 
    796    /* For picking only a few vertices from a large user buffer, push is better,
    797     * if index count is larger and we expect repeated vertices, suggest upload.
    798     */
    799    nvc0->vbo_push_hint =
    800       info->indexed && (nvc0->vb_elt_limit >= (info->count * 2));
    801 
    802    /* Check whether we want to switch vertex-submission mode. */
    803    if (nvc0->vbo_user && !(nvc0->dirty & (NVC0_NEW_ARRAYS | NVC0_NEW_VERTEX))) {
    804       if (nvc0->vbo_push_hint != !!nvc0->state.vbo_mode)
    805          if (nvc0->state.vbo_mode != 3)
    806             nvc0->dirty |= NVC0_NEW_ARRAYS;
    807 
    808       if (!(nvc0->dirty & NVC0_NEW_ARRAYS) && nvc0->state.vbo_mode == 0) {
    809          if (nvc0->vertex->shared_slots)
    810             nvc0_update_user_vbufs_shared(nvc0);
    811          else
    812             nvc0_update_user_vbufs(nvc0);
    813       }
    814    }
    815 
    816    /* 8 as minimum to avoid immediate double validation of new buffers */
    817    nvc0_state_validate(nvc0, ~0, 8);
    818 
    819    push->kick_notify = nvc0_draw_vbo_kick_notify;
    820 
    821    if (nvc0->state.vbo_mode) {
    822       nvc0_push_vbo(nvc0, info);
    823       push->kick_notify = nvc0_default_kick_notify;
    824       return;
    825    }
    826 
    827    /* space for base instance, flush, and prim restart */
    828    PUSH_SPACE(push, 8);
    829 
    830    if (nvc0->state.instance_base != info->start_instance) {
    831       nvc0->state.instance_base = info->start_instance;
    832       /* NOTE: this does not affect the shader input, should it ? */
    833       BEGIN_NVC0(push, NVC0_3D(VB_INSTANCE_BASE), 1);
    834       PUSH_DATA (push, info->start_instance);
    835    }
    836 
    837    if (nvc0->base.vbo_dirty) {
    838       IMMED_NVC0(push, NVC0_3D(VERTEX_ARRAY_FLUSH), 0);
    839       nvc0->base.vbo_dirty = FALSE;
    840    }
    841 
    842    if (info->indexed) {
    843       boolean shorten = info->max_index <= 65535;
    844 
    845       if (info->primitive_restart != nvc0->state.prim_restart) {
    846          if (info->primitive_restart) {
    847             BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 2);
    848             PUSH_DATA (push, 1);
    849             PUSH_DATA (push, info->restart_index);
    850 
    851             if (info->restart_index > 65535)
    852                shorten = FALSE;
    853          } else {
    854             IMMED_NVC0(push, NVC0_3D(PRIM_RESTART_ENABLE), 0);
    855          }
    856          nvc0->state.prim_restart = info->primitive_restart;
    857       } else
    858       if (info->primitive_restart) {
    859          BEGIN_NVC0(push, NVC0_3D(PRIM_RESTART_INDEX), 1);
    860          PUSH_DATA (push, info->restart_index);
    861 
    862          if (info->restart_index > 65535)
    863             shorten = FALSE;
    864       }
    865 
    866       nvc0_draw_elements(nvc0, shorten,
    867                          info->mode, info->start, info->count,
    868                          info->instance_count, info->index_bias);
    869    } else
    870    if (unlikely(info->count_from_stream_output)) {
    871       nvc0_draw_stream_output(nvc0, info);
    872    } else {
    873       nvc0_draw_arrays(nvc0,
    874                        info->mode, info->start, info->count,
    875                        info->instance_count);
    876    }
    877    push->kick_notify = nvc0_default_kick_notify;
    878 
    879    nvc0_release_user_vbufs(nvc0);
    880 }
    881