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