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 #include "util/u_math.h"
     28 #include "util/u_memory.h"
     29 
     30 #include "draw/draw_context.h"
     31 #include "draw/draw_private.h"
     32 #include "draw/draw_pt.h"
     33 
     34 #define SEGMENT_SIZE 1024
     35 #define MAP_SIZE     256
     36 
     37 struct vsplit_frontend {
     38    struct draw_pt_front_end base;
     39    struct draw_context *draw;
     40 
     41    unsigned prim;
     42 
     43    struct draw_pt_middle_end *middle;
     44 
     45    unsigned max_vertices;
     46    ushort segment_size;
     47 
     48    /* buffers for splitting */
     49    unsigned fetch_elts[SEGMENT_SIZE];
     50    ushort draw_elts[SEGMENT_SIZE];
     51    ushort identity_draw_elts[SEGMENT_SIZE];
     52 
     53    struct {
     54       /* map a fetch element to a draw element */
     55       unsigned fetches[MAP_SIZE];
     56       ushort draws[MAP_SIZE];
     57       boolean has_max_fetch;
     58 
     59       ushort num_fetch_elts;
     60       ushort num_draw_elts;
     61    } cache;
     62 };
     63 
     64 
     65 static void
     66 vsplit_clear_cache(struct vsplit_frontend *vsplit)
     67 {
     68    memset(vsplit->cache.fetches, 0xff, sizeof(vsplit->cache.fetches));
     69    vsplit->cache.has_max_fetch = FALSE;
     70    vsplit->cache.num_fetch_elts = 0;
     71    vsplit->cache.num_draw_elts = 0;
     72 }
     73 
     74 static void
     75 vsplit_flush_cache(struct vsplit_frontend *vsplit, unsigned flags)
     76 {
     77    vsplit->middle->run(vsplit->middle,
     78          vsplit->fetch_elts, vsplit->cache.num_fetch_elts,
     79          vsplit->draw_elts, vsplit->cache.num_draw_elts, flags);
     80 }
     81 
     82 /**
     83  * Add a fetch element and add it to the draw elements.
     84  */
     85 static INLINE void
     86 vsplit_add_cache(struct vsplit_frontend *vsplit, unsigned fetch)
     87 {
     88    struct draw_context *draw = vsplit->draw;
     89    unsigned hash;
     90 
     91    fetch = MIN2(fetch, draw->pt.max_index);
     92 
     93    hash = fetch % MAP_SIZE;
     94 
     95    if (vsplit->cache.fetches[hash] != fetch) {
     96       /* update cache */
     97       vsplit->cache.fetches[hash] = fetch;
     98       vsplit->cache.draws[hash] = vsplit->cache.num_fetch_elts;
     99 
    100       /* add fetch */
    101       assert(vsplit->cache.num_fetch_elts < vsplit->segment_size);
    102       vsplit->fetch_elts[vsplit->cache.num_fetch_elts++] = fetch;
    103    }
    104 
    105    vsplit->draw_elts[vsplit->cache.num_draw_elts++] = vsplit->cache.draws[hash];
    106 }
    107 
    108 
    109 /**
    110  * Add a fetch element and add it to the draw elements.  The fetch element is
    111  * in full range (uint).
    112  */
    113 static INLINE void
    114 vsplit_add_cache_uint(struct vsplit_frontend *vsplit, unsigned fetch)
    115 {
    116    /* special care for 0xffffffff */
    117    if (fetch == 0xffffffff && !vsplit->cache.has_max_fetch) {
    118       unsigned hash = fetch % MAP_SIZE;
    119       vsplit->cache.fetches[hash] = fetch - 1; /* force update */
    120       vsplit->cache.has_max_fetch = TRUE;
    121    }
    122 
    123    vsplit_add_cache(vsplit, fetch);
    124 }
    125 
    126 
    127 #define FUNC vsplit_run_linear
    128 #include "draw_pt_vsplit_tmp.h"
    129 
    130 #define FUNC vsplit_run_ubyte
    131 #define ELT_TYPE ubyte
    132 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch)
    133 #include "draw_pt_vsplit_tmp.h"
    134 
    135 #define FUNC vsplit_run_ushort
    136 #define ELT_TYPE ushort
    137 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache(vsplit, fetch)
    138 #include "draw_pt_vsplit_tmp.h"
    139 
    140 #define FUNC vsplit_run_uint
    141 #define ELT_TYPE uint
    142 #define ADD_CACHE(vsplit, fetch) vsplit_add_cache_uint(vsplit, fetch)
    143 #include "draw_pt_vsplit_tmp.h"
    144 
    145 
    146 static void vsplit_prepare(struct draw_pt_front_end *frontend,
    147                            unsigned in_prim,
    148                            struct draw_pt_middle_end *middle,
    149                            unsigned opt)
    150 {
    151    struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
    152 
    153    switch (vsplit->draw->pt.user.eltSize) {
    154    case 0:
    155       vsplit->base.run = vsplit_run_linear;
    156       break;
    157    case 1:
    158       vsplit->base.run = vsplit_run_ubyte;
    159       break;
    160    case 2:
    161       vsplit->base.run = vsplit_run_ushort;
    162       break;
    163    case 4:
    164       vsplit->base.run = vsplit_run_uint;
    165       break;
    166    default:
    167       assert(0);
    168       break;
    169    }
    170 
    171    /* split only */
    172    vsplit->prim = in_prim;
    173 
    174    vsplit->middle = middle;
    175    middle->prepare(middle, vsplit->prim, opt, &vsplit->max_vertices);
    176 
    177    vsplit->segment_size = MIN2(SEGMENT_SIZE, vsplit->max_vertices);
    178 }
    179 
    180 
    181 static void vsplit_flush(struct draw_pt_front_end *frontend, unsigned flags)
    182 {
    183    struct vsplit_frontend *vsplit = (struct vsplit_frontend *) frontend;
    184 
    185    if (!(flags & DRAW_FLUSH_BACKEND)) {
    186       vsplit->middle->finish(vsplit->middle);
    187       vsplit->middle = NULL;
    188    }
    189 }
    190 
    191 
    192 static void vsplit_destroy(struct draw_pt_front_end *frontend)
    193 {
    194    FREE(frontend);
    195 }
    196 
    197 
    198 struct draw_pt_front_end *draw_pt_vsplit(struct draw_context *draw)
    199 {
    200    struct vsplit_frontend *vsplit = CALLOC_STRUCT(vsplit_frontend);
    201    ushort i;
    202 
    203    if (!vsplit)
    204       return NULL;
    205 
    206    vsplit->base.prepare = vsplit_prepare;
    207    vsplit->base.run     = NULL;
    208    vsplit->base.flush   = vsplit_flush;
    209    vsplit->base.destroy = vsplit_destroy;
    210    vsplit->draw = draw;
    211 
    212    for (i = 0; i < SEGMENT_SIZE; i++)
    213       vsplit->identity_draw_elts[i] = i;
    214 
    215    return &vsplit->base;
    216 }
    217