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