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 */ 35static boolean 36CONCAT(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 */ 131static inline void 132CONCAT(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 173static void 174CONCAT(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 183static void 184CONCAT(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 196static void 197CONCAT(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 221static void 222vsplit_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 229static void 230vsplit_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 254static void 255vsplit_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