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