Home | History | Annotate | Download | only in draw
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /**
     29  * \file
     30  * Vertex buffer drawing stage.
     31  *
     32  * \author Jose Fonseca <jfonseca (at) vmware.com>
     33  * \author Keith Whitwell <keithw (at) vmware.com>
     34  */
     35 
     36 
     37 #include "util/u_debug.h"
     38 #include "util/u_math.h"
     39 #include "util/u_memory.h"
     40 
     41 #include "draw_vbuf.h"
     42 #include "draw_private.h"
     43 #include "draw_vertex.h"
     44 #include "draw_pipe.h"
     45 #include "translate/translate.h"
     46 #include "translate/translate_cache.h"
     47 
     48 
     49 /**
     50  * Vertex buffer emit stage.
     51  */
     52 struct vbuf_stage {
     53    struct draw_stage stage; /**< This must be first (base class) */
     54 
     55    struct vbuf_render *render;
     56 
     57    const struct vertex_info *vinfo;
     58 
     59    /** Vertex size in bytes */
     60    unsigned vertex_size;
     61 
     62    struct translate *translate;
     63 
     64    /* FIXME: we have no guarantee that 'unsigned' is 32bit */
     65 
     66    /** Vertices in hardware format */
     67    unsigned *vertices;
     68    unsigned *vertex_ptr;
     69    unsigned max_vertices;
     70    unsigned nr_vertices;
     71 
     72    /** Indices */
     73    ushort *indices;
     74    unsigned max_indices;
     75    unsigned nr_indices;
     76 
     77    /* Cache point size somewhere its address won't change:
     78     */
     79    float point_size;
     80    float zero4[4];
     81 
     82    struct translate_cache *cache;
     83 };
     84 
     85 
     86 /**
     87  * Basically a cast wrapper.
     88  */
     89 static inline struct vbuf_stage *
     90 vbuf_stage( struct draw_stage *stage )
     91 {
     92    assert(stage);
     93    return (struct vbuf_stage *)stage;
     94 }
     95 
     96 
     97 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
     98 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
     99 
    100 
    101 static inline boolean
    102 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
    103 {
    104    unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
    105    return (used + bytes) > bufsz;
    106 }
    107 
    108 
    109 static inline void
    110 check_space( struct vbuf_stage *vbuf, unsigned nr )
    111 {
    112    if (vbuf->nr_vertices + nr > vbuf->max_vertices ||
    113        vbuf->nr_indices + nr > vbuf->max_indices)
    114    {
    115       vbuf_flush_vertices( vbuf );
    116       vbuf_alloc_vertices( vbuf );
    117    }
    118 }
    119 
    120 
    121 
    122 
    123 /**
    124  * Extract the needed fields from post-transformed vertex and emit
    125  * a hardware(driver) vertex.
    126  * Recall that the vertices are constructed by the 'draw' module and
    127  * have a couple of slots at the beginning (1-dword header, 4-dword
    128  * clip pos) that we ignore here.  We only use the vertex->data[] fields.
    129  */
    130 static inline ushort
    131 emit_vertex( struct vbuf_stage *vbuf,
    132              struct vertex_header *vertex )
    133 {
    134    if (vertex->vertex_id == UNDEFINED_VERTEX_ID && vbuf->vertex_ptr) {
    135       /* Hmm - vertices are emitted one at a time - better make sure
    136        * set_buffer is efficient.  Consider a special one-shot mode for
    137        * translate.
    138        */
    139       /* Note: we really do want data[0] here, not data[pos]:
    140        */
    141       vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0, ~0);
    142       vbuf->translate->run(vbuf->translate, 0, 1, 0, 0, vbuf->vertex_ptr);
    143 
    144       if (0) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
    145 
    146       vbuf->vertex_ptr += vbuf->vertex_size/4;
    147       vertex->vertex_id = vbuf->nr_vertices++;
    148    }
    149 
    150    return (ushort)vertex->vertex_id;
    151 }
    152 
    153 
    154 static void
    155 vbuf_tri( struct draw_stage *stage,
    156           struct prim_header *prim )
    157 {
    158    struct vbuf_stage *vbuf = vbuf_stage( stage );
    159    unsigned i;
    160 
    161    check_space( vbuf, 3 );
    162 
    163    for (i = 0; i < 3; i++) {
    164       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
    165    }
    166 }
    167 
    168 
    169 static void
    170 vbuf_line( struct draw_stage *stage,
    171            struct prim_header *prim )
    172 {
    173    struct vbuf_stage *vbuf = vbuf_stage( stage );
    174    unsigned i;
    175 
    176    check_space( vbuf, 2 );
    177 
    178    for (i = 0; i < 2; i++) {
    179       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
    180    }
    181 }
    182 
    183 
    184 static void
    185 vbuf_point( struct draw_stage *stage,
    186             struct prim_header *prim )
    187 {
    188    struct vbuf_stage *vbuf = vbuf_stage( stage );
    189 
    190    check_space( vbuf, 1 );
    191 
    192    vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
    193 }
    194 
    195 
    196 
    197 
    198 /**
    199  * Set the prim type for subsequent vertices.
    200  * This may result in a new vertex size.  The existing vbuffer (if any)
    201  * will be flushed if needed and a new one allocated.
    202  */
    203 static void
    204 vbuf_start_prim( struct vbuf_stage *vbuf, uint prim )
    205 {
    206    struct translate_key hw_key;
    207    unsigned dst_offset;
    208    unsigned i;
    209    const struct vertex_info *vinfo;
    210 
    211    vbuf->render->set_primitive(vbuf->render, prim);
    212 
    213    /* Must do this after set_primitive() above:
    214     *
    215     * XXX: need some state managment to track when this needs to be
    216     * recalculated.  The driver should tell us whether there was a
    217     * state change.
    218     */
    219    vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
    220    vinfo = vbuf->vinfo;
    221    vbuf->vertex_size = vinfo->size * sizeof(float);
    222 
    223    /* Translate from pipeline vertices to hw vertices.
    224     */
    225    dst_offset = 0;
    226 
    227    for (i = 0; i < vinfo->num_attribs; i++) {
    228       unsigned emit_sz = 0;
    229       unsigned src_buffer = 0;
    230       enum pipe_format output_format;
    231       unsigned src_offset = (vinfo->attrib[i].src_index * 4 * sizeof(float) );
    232 
    233       output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
    234       emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
    235 
    236       /* doesn't handle EMIT_OMIT */
    237       assert(emit_sz != 0);
    238 
    239       if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
    240          src_buffer = 1;
    241          src_offset = 0;
    242       }
    243       else if (vinfo->attrib[i].src_index == DRAW_ATTR_NONEXIST) {
    244          /* elements which don't exist will get assigned zeros */
    245          src_buffer = 2;
    246          src_offset = 0;
    247       }
    248 
    249       hw_key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
    250       hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
    251       hw_key.element[i].input_buffer = src_buffer;
    252       hw_key.element[i].input_offset = src_offset;
    253       hw_key.element[i].instance_divisor = 0;
    254       hw_key.element[i].output_format = output_format;
    255       hw_key.element[i].output_offset = dst_offset;
    256 
    257       dst_offset += emit_sz;
    258    }
    259 
    260    hw_key.nr_elements = vinfo->num_attribs;
    261    hw_key.output_stride = vbuf->vertex_size;
    262 
    263    /* Don't bother with caching at this stage:
    264     */
    265    if (!vbuf->translate ||
    266        translate_key_compare(&vbuf->translate->key, &hw_key) != 0)
    267    {
    268       translate_key_sanitize(&hw_key);
    269       vbuf->translate = translate_cache_find(vbuf->cache, &hw_key);
    270 
    271       vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0, ~0);
    272       vbuf->translate->set_buffer(vbuf->translate, 2, &vbuf->zero4[0], 0, ~0);
    273    }
    274 
    275    vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
    276 
    277    /* Allocate new buffer?
    278     */
    279    assert(vbuf->vertices == NULL);
    280    vbuf_alloc_vertices(vbuf);
    281 }
    282 
    283 
    284 static void
    285 vbuf_first_tri( struct draw_stage *stage,
    286                 struct prim_header *prim )
    287 {
    288    struct vbuf_stage *vbuf = vbuf_stage( stage );
    289 
    290    vbuf_flush_vertices( vbuf );
    291    vbuf_start_prim(vbuf, PIPE_PRIM_TRIANGLES);
    292    stage->tri = vbuf_tri;
    293    stage->tri( stage, prim );
    294 }
    295 
    296 
    297 static void
    298 vbuf_first_line( struct draw_stage *stage,
    299                  struct prim_header *prim )
    300 {
    301    struct vbuf_stage *vbuf = vbuf_stage( stage );
    302 
    303    vbuf_flush_vertices( vbuf );
    304    vbuf_start_prim(vbuf, PIPE_PRIM_LINES);
    305    stage->line = vbuf_line;
    306    stage->line( stage, prim );
    307 }
    308 
    309 
    310 static void
    311 vbuf_first_point( struct draw_stage *stage,
    312                   struct prim_header *prim )
    313 {
    314    struct vbuf_stage *vbuf = vbuf_stage( stage );
    315 
    316    vbuf_flush_vertices(vbuf);
    317    vbuf_start_prim(vbuf, PIPE_PRIM_POINTS);
    318    stage->point = vbuf_point;
    319    stage->point( stage, prim );
    320 }
    321 
    322 
    323 
    324 /**
    325  * Flush existing vertex buffer and allocate a new one.
    326  */
    327 static void
    328 vbuf_flush_vertices( struct vbuf_stage *vbuf )
    329 {
    330    if(vbuf->vertices) {
    331 
    332       vbuf->render->unmap_vertices( vbuf->render, 0, vbuf->nr_vertices - 1 );
    333 
    334       if (vbuf->nr_indices)
    335       {
    336          vbuf->render->draw_elements(vbuf->render,
    337                                      vbuf->indices,
    338                                      vbuf->nr_indices );
    339 
    340          vbuf->nr_indices = 0;
    341       }
    342 
    343       /* Reset temporary vertices ids */
    344       if(vbuf->nr_vertices)
    345 	 draw_reset_vertex_ids( vbuf->stage.draw );
    346 
    347       /* Free the vertex buffer */
    348       vbuf->render->release_vertices( vbuf->render );
    349 
    350       vbuf->max_vertices = vbuf->nr_vertices = 0;
    351       vbuf->vertex_ptr = vbuf->vertices = NULL;
    352    }
    353 
    354    /* Reset point/line/tri function pointers.
    355     * If (for example) we transition from points to tris and back to points
    356     * again, we need to call the vbuf_first_point() function again to flush
    357     * the triangles before drawing more points.  This can happen when drawing
    358     * with front polygon mode = filled and back polygon mode = line or point.
    359     */
    360    vbuf->stage.point = vbuf_first_point;
    361    vbuf->stage.line = vbuf_first_line;
    362    vbuf->stage.tri = vbuf_first_tri;
    363 }
    364 
    365 
    366 static void
    367 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
    368 {
    369    if (vbuf->vertex_ptr) {
    370       assert(!vbuf->nr_indices);
    371       assert(!vbuf->vertices);
    372    }
    373 
    374    /* Allocate a new vertex buffer */
    375    vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
    376 
    377    if(vbuf->max_vertices >= UNDEFINED_VERTEX_ID)
    378       vbuf->max_vertices = UNDEFINED_VERTEX_ID - 1;
    379 
    380    /* Must always succeed -- driver gives us a
    381     * 'max_vertex_buffer_bytes' which it guarantees it can allocate,
    382     * and it will flush itself if necessary to do so.  If this does
    383     * fail, we are basically without usable hardware.
    384     */
    385    vbuf->render->allocate_vertices(vbuf->render,
    386                                    (ushort) vbuf->vertex_size,
    387                                    (ushort) vbuf->max_vertices);
    388 
    389    vbuf->vertices = (uint *) vbuf->render->map_vertices( vbuf->render );
    390 
    391    vbuf->vertex_ptr = vbuf->vertices;
    392 }
    393 
    394 
    395 
    396 static void
    397 vbuf_flush( struct draw_stage *stage, unsigned flags )
    398 {
    399    struct vbuf_stage *vbuf = vbuf_stage( stage );
    400 
    401    vbuf_flush_vertices( vbuf );
    402 }
    403 
    404 
    405 static void
    406 vbuf_reset_stipple_counter( struct draw_stage *stage )
    407 {
    408    /* XXX: Need to do something here for hardware with linestipple.
    409     */
    410    (void) stage;
    411 }
    412 
    413 
    414 static void vbuf_destroy( struct draw_stage *stage )
    415 {
    416    struct vbuf_stage *vbuf = vbuf_stage( stage );
    417 
    418    if(vbuf->indices)
    419       align_free( vbuf->indices );
    420 
    421    if (vbuf->render)
    422       vbuf->render->destroy( vbuf->render );
    423 
    424    if (vbuf->cache)
    425       translate_cache_destroy(vbuf->cache);
    426 
    427    FREE( stage );
    428 }
    429 
    430 
    431 /**
    432  * Create a new primitive vbuf/render stage.
    433  */
    434 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
    435                                     struct vbuf_render *render )
    436 {
    437    struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
    438    if (!vbuf)
    439       goto fail;
    440 
    441    vbuf->stage.draw = draw;
    442    vbuf->stage.name = "vbuf";
    443    vbuf->stage.point = vbuf_first_point;
    444    vbuf->stage.line = vbuf_first_line;
    445    vbuf->stage.tri = vbuf_first_tri;
    446    vbuf->stage.flush = vbuf_flush;
    447    vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
    448    vbuf->stage.destroy = vbuf_destroy;
    449 
    450    vbuf->render = render;
    451    vbuf->max_indices = MIN2(render->max_indices, UNDEFINED_VERTEX_ID-1);
    452 
    453    vbuf->indices = (ushort *) align_malloc(vbuf->max_indices *
    454                     sizeof(vbuf->indices[0]),
    455                     16);
    456    if (!vbuf->indices)
    457       goto fail;
    458 
    459    vbuf->cache = translate_cache_create();
    460    if (!vbuf->cache)
    461       goto fail;
    462 
    463    vbuf->vertices = NULL;
    464    vbuf->vertex_ptr = vbuf->vertices;
    465 
    466    vbuf->zero4[0] = vbuf->zero4[1] = vbuf->zero4[2] = vbuf->zero4[3] = 0.0f;
    467 
    468    return &vbuf->stage;
    469 
    470 fail:
    471    if (vbuf)
    472       vbuf_destroy(&vbuf->stage);
    473 
    474    return NULL;
    475 }
    476