Home | History | Annotate | Download | only in draw
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.9
      4  *
      5  * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      6  * Copyright (C) 2010 LunarG Inc.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included
     16  * in all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     24  * DEALINGS IN THE SOFTWARE.
     25  */
     26 
     27 #define CONCAT2(name, elt_type) name ## elt_type
     28 #define CONCAT(name, elt_type) CONCAT2(name, elt_type)
     29 
     30 #ifdef ELT_TYPE
     31 
     32 /**
     33  * Fetch all elements in [min_index, max_index] with bias, and use the
     34  * (rebased) index buffer as the draw elements.
     35  */
     36 static boolean
     37 CONCAT(vsplit_primitive_, ELT_TYPE)(struct vsplit_frontend *vsplit,
     38                                     unsigned istart, unsigned icount)
     39 {
     40    struct draw_context *draw = vsplit->draw;
     41    const ELT_TYPE *ib = (const ELT_TYPE *) draw->pt.user.elts;
     42    const unsigned min_index = draw->pt.user.min_index;
     43    const unsigned max_index = draw->pt.user.max_index;
     44    const int elt_bias = draw->pt.user.eltBias;
     45    unsigned fetch_start, fetch_count;
     46    const ushort *draw_elts = NULL;
     47    unsigned i;
     48 
     49    ib += istart;
     50 
     51    /* use the ib directly */
     52    if (min_index == 0 && sizeof(ib[0]) == sizeof(draw_elts[0])) {
     53       if (icount > vsplit->max_vertices)
     54          return FALSE;
     55 
     56       for (i = 0; i < icount; i++) {
     57          ELT_TYPE idx = ib[i];
     58             if (idx < min_index || idx > max_index) {
     59             debug_printf("warning: index out of range\n");
     60          }
     61       }
     62       draw_elts = (const ushort *) ib;
     63    }
     64    else {
     65       /* have to go through vsplit->draw_elts */
     66       if (icount > vsplit->segment_size)
     67          return FALSE;
     68    }
     69 
     70    /* this is faster only when we fetch less elements than the normal path */
     71    if (max_index - min_index > icount - 1)
     72       return FALSE;
     73 
     74    if (elt_bias < 0 && min_index < -elt_bias)
     75       return FALSE;
     76 
     77    /* why this check? */
     78    for (i = 0; i < draw->pt.nr_vertex_elements; i++) {
     79       if (draw->pt.vertex_element[i].instance_divisor)
     80          return FALSE;
     81    }
     82 
     83    fetch_start = min_index + elt_bias;
     84    fetch_count = max_index - min_index + 1;
     85 
     86    if (!draw_elts) {
     87       if (min_index == 0) {
     88          for (i = 0; i < icount; i++) {
     89             ELT_TYPE idx = ib[i];
     90 
     91             if (idx < min_index || idx > max_index) {
     92                debug_printf("warning: index out of range\n");
     93 	    }
     94             vsplit->draw_elts[i] = (ushort) idx;
     95          }
     96       }
     97       else {
     98          for (i = 0; i < icount; i++) {
     99             ELT_TYPE idx = ib[i];
    100 
    101             if (idx < min_index || idx > max_index) {
    102                debug_printf("warning: index out of range\n");
    103 	    }
    104             vsplit->draw_elts[i] = (ushort) (idx - min_index);
    105          }
    106       }
    107 
    108       draw_elts = vsplit->draw_elts;
    109    }
    110 
    111    return vsplit->middle->run_linear_elts(vsplit->middle,
    112                                           fetch_start, fetch_count,
    113                                           draw_elts, icount, 0x0);
    114 }
    115 
    116 /**
    117  * Use the cache to prepare the fetch and draw elements, and flush.
    118  *
    119  * When spoken is TRUE, ispoken replaces istart;  When close is TRUE, iclose is
    120  * appended.
    121  */
    122 static INLINE void
    123 CONCAT(vsplit_segment_cache_, ELT_TYPE)(struct vsplit_frontend *vsplit,
    124                                         unsigned flags,
    125                                         unsigned istart, unsigned icount,
    126                                         boolean spoken, unsigned ispoken,
    127                                         boolean close, unsigned iclose)
    128 {
    129    struct draw_context *draw = vsplit->draw;
    130    const ELT_TYPE *ib = (const ELT_TYPE *) draw->pt.user.elts;
    131    const int ibias = draw->pt.user.eltBias;
    132    unsigned i;
    133 
    134    assert(icount + !!close <= vsplit->segment_size);
    135 
    136    vsplit_clear_cache(vsplit);
    137 
    138    spoken = !!spoken;
    139    if (ibias == 0) {
    140       if (spoken)
    141          ADD_CACHE(vsplit, ib[ispoken]);
    142 
    143       for (i = spoken; i < icount; i++)
    144          ADD_CACHE(vsplit, ib[istart + i]);
    145 
    146       if (close)
    147          ADD_CACHE(vsplit, ib[iclose]);
    148    }
    149    else if (ibias > 0) {
    150       if (spoken)
    151          ADD_CACHE(vsplit, (uint) ib[ispoken] + ibias);
    152 
    153       for (i = spoken; i < icount; i++)
    154          ADD_CACHE(vsplit, (uint) ib[istart + i] + ibias);
    155 
    156       if (close)
    157          ADD_CACHE(vsplit, (uint) ib[iclose] + ibias);
    158    }
    159    else {
    160       if (spoken) {
    161          if (ib[ispoken] < -ibias)
    162             return;
    163          ADD_CACHE(vsplit, ib[ispoken] + ibias);
    164       }
    165 
    166       for (i = spoken; i < icount; i++) {
    167          if (ib[istart + i] < -ibias)
    168             return;
    169          ADD_CACHE(vsplit, ib[istart + i] + ibias);
    170       }
    171 
    172       if (close) {
    173          if (ib[iclose] < -ibias)
    174             return;
    175          ADD_CACHE(vsplit, ib[iclose] + ibias);
    176       }
    177    }
    178 
    179    vsplit_flush_cache(vsplit, flags);
    180 }
    181 
    182 static void
    183 CONCAT(vsplit_segment_simple_, ELT_TYPE)(struct vsplit_frontend *vsplit,
    184                                          unsigned flags,
    185                                          unsigned istart,
    186                                          unsigned icount)
    187 {
    188    CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit,
    189          flags, istart, icount, FALSE, 0, FALSE, 0);
    190 }
    191 
    192 static void
    193 CONCAT(vsplit_segment_loop_, ELT_TYPE)(struct vsplit_frontend *vsplit,
    194                                        unsigned flags,
    195                                        unsigned istart,
    196                                        unsigned icount,
    197                                        unsigned i0)
    198 {
    199    const boolean close_loop = ((flags) == DRAW_SPLIT_BEFORE);
    200 
    201    CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit,
    202          flags, istart, icount, FALSE, 0, close_loop, i0);
    203 }
    204 
    205 static void
    206 CONCAT(vsplit_segment_fan_, ELT_TYPE)(struct vsplit_frontend *vsplit,
    207                                       unsigned flags,
    208                                       unsigned istart,
    209                                       unsigned icount,
    210                                       unsigned i0)
    211 {
    212    const boolean use_spoken = (((flags) & DRAW_SPLIT_BEFORE) != 0);
    213 
    214    CONCAT(vsplit_segment_cache_, ELT_TYPE)(vsplit,
    215          flags, istart, icount, use_spoken, i0, FALSE, 0);
    216 }
    217 
    218 #define LOCAL_VARS                                                         \
    219    struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;   \
    220    const unsigned prim = vsplit->prim;                                     \
    221    const unsigned max_count_simple = vsplit->segment_size;                 \
    222    const unsigned max_count_loop = vsplit->segment_size - 1;               \
    223    const unsigned max_count_fan = vsplit->segment_size;
    224 
    225 #define PRIMITIVE(istart, icount)   \
    226    CONCAT(vsplit_primitive_, ELT_TYPE)(vsplit, istart, icount)
    227 
    228 #else /* ELT_TYPE */
    229 
    230 static void
    231 vsplit_segment_simple_linear(struct vsplit_frontend *vsplit, unsigned flags,
    232                              unsigned istart, unsigned icount)
    233 {
    234    assert(icount <= vsplit->max_vertices);
    235    vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
    236 }
    237 
    238 static void
    239 vsplit_segment_loop_linear(struct vsplit_frontend *vsplit, unsigned flags,
    240                            unsigned istart, unsigned icount, unsigned i0)
    241 {
    242    boolean close_loop = (flags == DRAW_SPLIT_BEFORE);
    243    unsigned nr;
    244 
    245    assert(icount + !!close_loop <= vsplit->segment_size);
    246 
    247    if (close_loop) {
    248       for (nr = 0; nr < icount; nr++)
    249          vsplit->fetch_elts[nr] = istart + nr;
    250       vsplit->fetch_elts[nr++] = i0;
    251 
    252       vsplit->middle->run(vsplit->middle, vsplit->fetch_elts, nr,
    253             vsplit->identity_draw_elts, nr, flags);
    254    }
    255    else {
    256       vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
    257    }
    258 }
    259 
    260 static void
    261 vsplit_segment_fan_linear(struct vsplit_frontend *vsplit, unsigned flags,
    262                           unsigned istart, unsigned icount, unsigned i0)
    263 {
    264    boolean use_spoken = ((flags & DRAW_SPLIT_BEFORE) != 0);
    265    unsigned nr = 0, i;
    266 
    267    assert(icount <= vsplit->segment_size);
    268 
    269    if (use_spoken) {
    270       /* replace istart by i0 */
    271       vsplit->fetch_elts[nr++] = i0;
    272       for (i = 1 ; i < icount; i++)
    273          vsplit->fetch_elts[nr++] = istart + i;
    274 
    275       vsplit->middle->run(vsplit->middle, vsplit->fetch_elts, nr,
    276             vsplit->identity_draw_elts, nr, flags);
    277    }
    278    else {
    279       vsplit->middle->run_linear(vsplit->middle, istart, icount, flags);
    280    }
    281 }
    282 
    283 #define LOCAL_VARS                                                         \
    284    struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;   \
    285    const unsigned prim = vsplit->prim;                                     \
    286    const unsigned max_count_simple = vsplit->max_vertices;                 \
    287    const unsigned max_count_loop = vsplit->segment_size - 1;               \
    288    const unsigned max_count_fan = vsplit->segment_size;
    289 
    290 #define PRIMITIVE(istart, icount) FALSE
    291 
    292 #define ELT_TYPE linear
    293 
    294 #endif /* ELT_TYPE */
    295 
    296 #define FUNC_VARS                      \
    297    struct draw_pt_front_end *frontend, \
    298    unsigned start,                     \
    299    unsigned count
    300 
    301 #define SEGMENT_SIMPLE(flags, istart, icount)   \
    302    CONCAT(vsplit_segment_simple_, ELT_TYPE)(vsplit, flags, istart, icount)
    303 
    304 #define SEGMENT_LOOP(flags, istart, icount, i0) \
    305    CONCAT(vsplit_segment_loop_, ELT_TYPE)(vsplit, flags, istart, icount, i0)
    306 
    307 #define SEGMENT_FAN(flags, istart, icount, i0)  \
    308    CONCAT(vsplit_segment_fan_, ELT_TYPE)(vsplit, flags, istart, icount, i0)
    309 
    310 #include "draw_split_tmp.h"
    311 
    312 #undef CONCAT2
    313 #undef CONCAT
    314 
    315 #undef ELT_TYPE
    316 #undef ADD_CACHE
    317