Home | History | Annotate | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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  * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
     30  * code.  When the 'draw' module has finished filling a vertex buffer, the
     31  * draw_arrays() functions below will be called.  Loop over the vertices and
     32  * call the point/line/tri setup functions.
     33  *
     34  * Authors
     35  *  Brian Paul
     36  */
     37 
     38 
     39 #include "lp_setup_context.h"
     40 #include "draw/draw_vbuf.h"
     41 #include "draw/draw_vertex.h"
     42 #include "util/u_memory.h"
     43 
     44 
     45 #define LP_MAX_VBUF_INDEXES 1024
     46 #define LP_MAX_VBUF_SIZE    4096
     47 
     48 
     49 
     50 /** cast wrapper */
     51 static struct lp_setup_context *
     52 lp_setup_context(struct vbuf_render *vbr)
     53 {
     54    return (struct lp_setup_context *) vbr;
     55 }
     56 
     57 
     58 
     59 static const struct vertex_info *
     60 lp_setup_get_vertex_info(struct vbuf_render *vbr)
     61 {
     62    struct lp_setup_context *setup = lp_setup_context(vbr);
     63 
     64    /* Vertex size/info depends on the latest state.
     65     * The draw module may have issued additional state-change commands.
     66     */
     67    lp_setup_update_state(setup, FALSE);
     68 
     69    return setup->vertex_info;
     70 }
     71 
     72 
     73 static boolean
     74 lp_setup_allocate_vertices(struct vbuf_render *vbr,
     75                           ushort vertex_size, ushort nr_vertices)
     76 {
     77    struct lp_setup_context *setup = lp_setup_context(vbr);
     78    unsigned size = vertex_size * nr_vertices;
     79 
     80    if (setup->vertex_buffer_size < size) {
     81       align_free(setup->vertex_buffer);
     82       setup->vertex_buffer = align_malloc(size, 16);
     83       setup->vertex_buffer_size = size;
     84    }
     85 
     86    setup->vertex_size = vertex_size;
     87    setup->nr_vertices = nr_vertices;
     88 
     89    return setup->vertex_buffer != NULL;
     90 }
     91 
     92 static void
     93 lp_setup_release_vertices(struct vbuf_render *vbr)
     94 {
     95    /* keep the old allocation for next time */
     96 }
     97 
     98 static void *
     99 lp_setup_map_vertices(struct vbuf_render *vbr)
    100 {
    101    struct lp_setup_context *setup = lp_setup_context(vbr);
    102    return setup->vertex_buffer;
    103 }
    104 
    105 static void
    106 lp_setup_unmap_vertices(struct vbuf_render *vbr,
    107                        ushort min_index,
    108                        ushort max_index )
    109 {
    110    struct lp_setup_context *setup = lp_setup_context(vbr);
    111    assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
    112    /* do nothing */
    113 }
    114 
    115 
    116 static void
    117 lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
    118 {
    119    lp_setup_context(vbr)->prim = prim;
    120 }
    121 
    122 typedef const float (*const_float4_ptr)[4];
    123 
    124 static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
    125                                          int index,
    126                                          int stride )
    127 {
    128    return (const_float4_ptr)((char *)vertex_buffer + index * stride);
    129 }
    130 
    131 /**
    132  * draw elements / indexed primitives
    133  */
    134 static void
    135 lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
    136 {
    137    struct lp_setup_context *setup = lp_setup_context(vbr);
    138    const unsigned stride = setup->vertex_info->size * sizeof(float);
    139    const void *vertex_buffer = setup->vertex_buffer;
    140    const boolean flatshade_first = setup->flatshade_first;
    141    unsigned i;
    142 
    143    assert(setup->setup.variant);
    144 
    145    if (!lp_setup_update_state(setup, TRUE))
    146       return;
    147 
    148    switch (setup->prim) {
    149    case PIPE_PRIM_POINTS:
    150       for (i = 0; i < nr; i++) {
    151          setup->point( setup,
    152                        get_vert(vertex_buffer, indices[i-0], stride) );
    153       }
    154       break;
    155 
    156    case PIPE_PRIM_LINES:
    157       for (i = 1; i < nr; i += 2) {
    158          setup->line( setup,
    159                       get_vert(vertex_buffer, indices[i-1], stride),
    160                       get_vert(vertex_buffer, indices[i-0], stride) );
    161       }
    162       break;
    163 
    164    case PIPE_PRIM_LINE_STRIP:
    165       for (i = 1; i < nr; i ++) {
    166          setup->line( setup,
    167                       get_vert(vertex_buffer, indices[i-1], stride),
    168                       get_vert(vertex_buffer, indices[i-0], stride) );
    169       }
    170       break;
    171 
    172    case PIPE_PRIM_LINE_LOOP:
    173       for (i = 1; i < nr; i ++) {
    174          setup->line( setup,
    175                       get_vert(vertex_buffer, indices[i-1], stride),
    176                       get_vert(vertex_buffer, indices[i-0], stride) );
    177       }
    178       if (nr) {
    179          setup->line( setup,
    180                       get_vert(vertex_buffer, indices[nr-1], stride),
    181                       get_vert(vertex_buffer, indices[0], stride) );
    182       }
    183       break;
    184 
    185    case PIPE_PRIM_TRIANGLES:
    186       for (i = 2; i < nr; i += 3) {
    187          setup->triangle( setup,
    188                           get_vert(vertex_buffer, indices[i-2], stride),
    189                           get_vert(vertex_buffer, indices[i-1], stride),
    190                           get_vert(vertex_buffer, indices[i-0], stride) );
    191       }
    192       break;
    193 
    194    case PIPE_PRIM_TRIANGLE_STRIP:
    195       if (flatshade_first) {
    196          for (i = 2; i < nr; i += 1) {
    197             /* emit first triangle vertex as first triangle vertex */
    198             setup->triangle( setup,
    199                              get_vert(vertex_buffer, indices[i-2], stride),
    200                              get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
    201                              get_vert(vertex_buffer, indices[i-(i&1)], stride) );
    202 
    203          }
    204       }
    205       else {
    206          for (i = 2; i < nr; i += 1) {
    207             /* emit last triangle vertex as last triangle vertex */
    208             setup->triangle( setup,
    209                              get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
    210                              get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
    211                              get_vert(vertex_buffer, indices[i-0], stride) );
    212          }
    213       }
    214       break;
    215 
    216    case PIPE_PRIM_TRIANGLE_FAN:
    217       if (flatshade_first) {
    218          for (i = 2; i < nr; i += 1) {
    219             /* emit first non-spoke vertex as first vertex */
    220             setup->triangle( setup,
    221                              get_vert(vertex_buffer, indices[i-1], stride),
    222                              get_vert(vertex_buffer, indices[i-0], stride),
    223                              get_vert(vertex_buffer, indices[0], stride) );
    224          }
    225       }
    226       else {
    227          for (i = 2; i < nr; i += 1) {
    228             /* emit last non-spoke vertex as last vertex */
    229             setup->triangle( setup,
    230                              get_vert(vertex_buffer, indices[0], stride),
    231                              get_vert(vertex_buffer, indices[i-1], stride),
    232                              get_vert(vertex_buffer, indices[i-0], stride) );
    233          }
    234       }
    235       break;
    236 
    237    case PIPE_PRIM_QUADS:
    238       /* GL quads don't follow provoking vertex convention */
    239       if (flatshade_first) {
    240          /* emit last quad vertex as first triangle vertex */
    241          for (i = 3; i < nr; i += 4) {
    242             setup->triangle( setup,
    243                              get_vert(vertex_buffer, indices[i-0], stride),
    244                              get_vert(vertex_buffer, indices[i-3], stride),
    245                              get_vert(vertex_buffer, indices[i-2], stride) );
    246 
    247             setup->triangle( setup,
    248                              get_vert(vertex_buffer, indices[i-0], stride),
    249                              get_vert(vertex_buffer, indices[i-2], stride),
    250                              get_vert(vertex_buffer, indices[i-1], stride) );
    251          }
    252       }
    253       else {
    254          /* emit last quad vertex as last triangle vertex */
    255          for (i = 3; i < nr; i += 4) {
    256             setup->triangle( setup,
    257                           get_vert(vertex_buffer, indices[i-3], stride),
    258                           get_vert(vertex_buffer, indices[i-2], stride),
    259                           get_vert(vertex_buffer, indices[i-0], stride) );
    260 
    261             setup->triangle( setup,
    262                              get_vert(vertex_buffer, indices[i-2], stride),
    263                              get_vert(vertex_buffer, indices[i-1], stride),
    264                              get_vert(vertex_buffer, indices[i-0], stride) );
    265          }
    266       }
    267       break;
    268 
    269    case PIPE_PRIM_QUAD_STRIP:
    270       /* GL quad strips don't follow provoking vertex convention */
    271       if (flatshade_first) {
    272          /* emit last quad vertex as first triangle vertex */
    273          for (i = 3; i < nr; i += 2) {
    274             setup->triangle( setup,
    275                              get_vert(vertex_buffer, indices[i-0], stride),
    276                              get_vert(vertex_buffer, indices[i-3], stride),
    277                              get_vert(vertex_buffer, indices[i-2], stride) );
    278             setup->triangle( setup,
    279                              get_vert(vertex_buffer, indices[i-0], stride),
    280                              get_vert(vertex_buffer, indices[i-1], stride),
    281                              get_vert(vertex_buffer, indices[i-3], stride) );
    282          }
    283       }
    284       else {
    285          /* emit last quad vertex as last triangle vertex */
    286          for (i = 3; i < nr; i += 2) {
    287             setup->triangle( setup,
    288                              get_vert(vertex_buffer, indices[i-3], stride),
    289                              get_vert(vertex_buffer, indices[i-2], stride),
    290                              get_vert(vertex_buffer, indices[i-0], stride) );
    291             setup->triangle( setup,
    292                              get_vert(vertex_buffer, indices[i-1], stride),
    293                              get_vert(vertex_buffer, indices[i-3], stride),
    294                              get_vert(vertex_buffer, indices[i-0], stride) );
    295          }
    296       }
    297       break;
    298 
    299    case PIPE_PRIM_POLYGON:
    300       /* Almost same as tri fan but the _first_ vertex specifies the flat
    301        * shading color.
    302        */
    303       if (flatshade_first) {
    304          /* emit first polygon  vertex as first triangle vertex */
    305          for (i = 2; i < nr; i += 1) {
    306             setup->triangle( setup,
    307                              get_vert(vertex_buffer, indices[0], stride),
    308                              get_vert(vertex_buffer, indices[i-1], stride),
    309                              get_vert(vertex_buffer, indices[i-0], stride) );
    310          }
    311       }
    312       else {
    313          /* emit first polygon  vertex as last triangle vertex */
    314          for (i = 2; i < nr; i += 1) {
    315             setup->triangle( setup,
    316                              get_vert(vertex_buffer, indices[i-1], stride),
    317                              get_vert(vertex_buffer, indices[i-0], stride),
    318                              get_vert(vertex_buffer, indices[0], stride) );
    319          }
    320       }
    321       break;
    322 
    323    default:
    324       assert(0);
    325    }
    326 }
    327 
    328 
    329 /**
    330  * This function is hit when the draw module is working in pass-through mode.
    331  * It's up to us to convert the vertex array into point/line/tri prims.
    332  */
    333 static void
    334 lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
    335 {
    336    struct lp_setup_context *setup = lp_setup_context(vbr);
    337    const unsigned stride = setup->vertex_info->size * sizeof(float);
    338    const void *vertex_buffer =
    339       (void *) get_vert(setup->vertex_buffer, start, stride);
    340    const boolean flatshade_first = setup->flatshade_first;
    341    unsigned i;
    342 
    343    if (!lp_setup_update_state(setup, TRUE))
    344       return;
    345 
    346    switch (setup->prim) {
    347    case PIPE_PRIM_POINTS:
    348       for (i = 0; i < nr; i++) {
    349          setup->point( setup,
    350                        get_vert(vertex_buffer, i-0, stride) );
    351       }
    352       break;
    353 
    354    case PIPE_PRIM_LINES:
    355       for (i = 1; i < nr; i += 2) {
    356          setup->line( setup,
    357                       get_vert(vertex_buffer, i-1, stride),
    358                       get_vert(vertex_buffer, i-0, stride) );
    359       }
    360       break;
    361 
    362    case PIPE_PRIM_LINE_STRIP:
    363       for (i = 1; i < nr; i ++) {
    364          setup->line( setup,
    365                       get_vert(vertex_buffer, i-1, stride),
    366                       get_vert(vertex_buffer, i-0, stride) );
    367       }
    368       break;
    369 
    370    case PIPE_PRIM_LINE_LOOP:
    371       for (i = 1; i < nr; i ++) {
    372          setup->line( setup,
    373                       get_vert(vertex_buffer, i-1, stride),
    374                       get_vert(vertex_buffer, i-0, stride) );
    375       }
    376       if (nr) {
    377          setup->line( setup,
    378                       get_vert(vertex_buffer, nr-1, stride),
    379                       get_vert(vertex_buffer, 0, stride) );
    380       }
    381       break;
    382 
    383    case PIPE_PRIM_TRIANGLES:
    384       for (i = 2; i < nr; i += 3) {
    385          setup->triangle( setup,
    386                           get_vert(vertex_buffer, i-2, stride),
    387                           get_vert(vertex_buffer, i-1, stride),
    388                           get_vert(vertex_buffer, i-0, stride) );
    389       }
    390       break;
    391 
    392    case PIPE_PRIM_TRIANGLE_STRIP:
    393       if (flatshade_first) {
    394          for (i = 2; i < nr; i++) {
    395             /* emit first triangle vertex as first triangle vertex */
    396             setup->triangle( setup,
    397                              get_vert(vertex_buffer, i-2, stride),
    398                              get_vert(vertex_buffer, i+(i&1)-1, stride),
    399                              get_vert(vertex_buffer, i-(i&1), stride) );
    400          }
    401       }
    402       else {
    403          for (i = 2; i < nr; i++) {
    404             /* emit last triangle vertex as last triangle vertex */
    405             setup->triangle( setup,
    406                              get_vert(vertex_buffer, i+(i&1)-2, stride),
    407                              get_vert(vertex_buffer, i-(i&1)-1, stride),
    408                              get_vert(vertex_buffer, i-0, stride) );
    409          }
    410       }
    411       break;
    412 
    413    case PIPE_PRIM_TRIANGLE_FAN:
    414       if (flatshade_first) {
    415          for (i = 2; i < nr; i += 1) {
    416             /* emit first non-spoke vertex as first vertex */
    417             setup->triangle( setup,
    418                              get_vert(vertex_buffer, i-1, stride),
    419                              get_vert(vertex_buffer, i-0, stride),
    420                              get_vert(vertex_buffer, 0, stride)  );
    421          }
    422       }
    423       else {
    424          for (i = 2; i < nr; i += 1) {
    425             /* emit last non-spoke vertex as last vertex */
    426             setup->triangle( setup,
    427                              get_vert(vertex_buffer, 0, stride),
    428                              get_vert(vertex_buffer, i-1, stride),
    429                              get_vert(vertex_buffer, i-0, stride) );
    430          }
    431       }
    432       break;
    433 
    434    case PIPE_PRIM_QUADS:
    435       /* GL quads don't follow provoking vertex convention */
    436       if (flatshade_first) {
    437          /* emit last quad vertex as first triangle vertex */
    438          for (i = 3; i < nr; i += 4) {
    439             setup->triangle( setup,
    440                              get_vert(vertex_buffer, i-0, stride),
    441                              get_vert(vertex_buffer, i-3, stride),
    442                              get_vert(vertex_buffer, i-2, stride) );
    443             setup->triangle( setup,
    444                              get_vert(vertex_buffer, i-0, stride),
    445                              get_vert(vertex_buffer, i-2, stride),
    446                              get_vert(vertex_buffer, i-1, stride) );
    447          }
    448       }
    449       else {
    450          /* emit last quad vertex as last triangle vertex */
    451          for (i = 3; i < nr; i += 4) {
    452             setup->triangle( setup,
    453                              get_vert(vertex_buffer, i-3, stride),
    454                              get_vert(vertex_buffer, i-2, stride),
    455                              get_vert(vertex_buffer, i-0, stride) );
    456             setup->triangle( setup,
    457                              get_vert(vertex_buffer, i-2, stride),
    458                              get_vert(vertex_buffer, i-1, stride),
    459                              get_vert(vertex_buffer, i-0, stride) );
    460          }
    461       }
    462       break;
    463 
    464    case PIPE_PRIM_QUAD_STRIP:
    465       /* GL quad strips don't follow provoking vertex convention */
    466       if (flatshade_first) {
    467          /* emit last quad vertex as first triangle vertex */
    468          for (i = 3; i < nr; i += 2) {
    469             setup->triangle( setup,
    470                              get_vert(vertex_buffer, i-0, stride),
    471                              get_vert(vertex_buffer, i-3, stride),
    472                              get_vert(vertex_buffer, i-2, stride) );
    473             setup->triangle( setup,
    474                              get_vert(vertex_buffer, i-0, stride),
    475                              get_vert(vertex_buffer, i-1, stride),
    476                              get_vert(vertex_buffer, i-3, stride) );
    477          }
    478       }
    479       else {
    480          /* emit last quad vertex as last triangle vertex */
    481          for (i = 3; i < nr; i += 2) {
    482             setup->triangle( setup,
    483                              get_vert(vertex_buffer, i-3, stride),
    484                              get_vert(vertex_buffer, i-2, stride),
    485                              get_vert(vertex_buffer, i-0, stride) );
    486             setup->triangle( setup,
    487                              get_vert(vertex_buffer, i-1, stride),
    488                              get_vert(vertex_buffer, i-3, stride),
    489                              get_vert(vertex_buffer, i-0, stride) );
    490          }
    491       }
    492       break;
    493 
    494    case PIPE_PRIM_POLYGON:
    495       /* Almost same as tri fan but the _first_ vertex specifies the flat
    496        * shading color.
    497        */
    498       if (flatshade_first) {
    499          /* emit first polygon  vertex as first triangle vertex */
    500          for (i = 2; i < nr; i += 1) {
    501             setup->triangle( setup,
    502                              get_vert(vertex_buffer, 0, stride),
    503                              get_vert(vertex_buffer, i-1, stride),
    504                              get_vert(vertex_buffer, i-0, stride) );
    505          }
    506       }
    507       else {
    508          /* emit first polygon  vertex as last triangle vertex */
    509          for (i = 2; i < nr; i += 1) {
    510             setup->triangle( setup,
    511                              get_vert(vertex_buffer, i-1, stride),
    512                              get_vert(vertex_buffer, i-0, stride),
    513                              get_vert(vertex_buffer, 0, stride) );
    514          }
    515       }
    516       break;
    517 
    518    default:
    519       assert(0);
    520    }
    521 }
    522 
    523 
    524 
    525 static void
    526 lp_setup_vbuf_destroy(struct vbuf_render *vbr)
    527 {
    528    struct lp_setup_context *setup = lp_setup_context(vbr);
    529    if (setup->vertex_buffer) {
    530       align_free(setup->vertex_buffer);
    531       setup->vertex_buffer = NULL;
    532    }
    533    lp_setup_destroy(setup);
    534 }
    535 
    536 
    537 /**
    538  * Create the post-transform vertex handler for the given context.
    539  */
    540 void
    541 lp_setup_init_vbuf(struct lp_setup_context *setup)
    542 {
    543    setup->base.max_indices = LP_MAX_VBUF_INDEXES;
    544    setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
    545 
    546    setup->base.get_vertex_info = lp_setup_get_vertex_info;
    547    setup->base.allocate_vertices = lp_setup_allocate_vertices;
    548    setup->base.map_vertices = lp_setup_map_vertices;
    549    setup->base.unmap_vertices = lp_setup_unmap_vertices;
    550    setup->base.set_primitive = lp_setup_set_primitive;
    551    setup->base.draw_elements = lp_setup_draw_elements;
    552    setup->base.draw_arrays = lp_setup_draw_arrays;
    553    setup->base.release_vertices = lp_setup_release_vertices;
    554    setup->base.destroy = lp_setup_vbuf_destroy;
    555 }
    556