vbo_split_inplace.c revision 1e9d3ad4e1d987e1130e4bcd2ffc35f0e18064c3
1 2/* 3 * Mesa 3-D graphics library 4 * Version: 6.5 5 * 6 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 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 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Keith Whitwell <keith@tungstengraphics.com> 27 */ 28 29 30#include "main/mtypes.h" 31#include "main/macros.h" 32#include "main/enums.h" 33#include "vbo_split.h" 34 35 36#define MAX_PRIM 32 37 38/* Used for splitting without copying. 39 */ 40struct split_context { 41 GLcontext *ctx; 42 const struct gl_client_array **array; 43 const struct _mesa_prim *prim; 44 GLuint nr_prims; 45 const struct _mesa_index_buffer *ib; 46 GLuint min_index; 47 GLuint max_index; 48 vbo_draw_func draw; 49 50 const struct split_limits *limits; 51 52 struct _mesa_prim dstprim[MAX_PRIM]; 53 GLuint dstprim_nr; 54}; 55 56 57 58 59static void flush_vertex( struct split_context *split ) 60{ 61 GLuint min_index, max_index; 62 GLuint i; 63 64 if (!split->dstprim_nr) 65 return; 66 67 min_index = split->dstprim[0].start; 68 max_index = min_index + split->dstprim[0].count - 1; 69 70 for (i = 1; i < split->dstprim_nr; i++) { 71 GLuint tmp_min = split->dstprim[i].start; 72 GLuint tmp_max = tmp_min + split->dstprim[i].count - 1; 73 74 if (tmp_min < min_index) 75 min_index = tmp_min; 76 77 if (tmp_max > max_index) 78 max_index = tmp_max; 79 } 80 81 assert(max_index >= min_index); 82 83 split->draw( split->ctx, 84 split->array, 85 split->dstprim, 86 split->dstprim_nr, 87 NULL, 88 min_index, 89 max_index); 90 91 split->dstprim_nr = 0; 92} 93 94 95static struct _mesa_prim *next_outprim( struct split_context *split ) 96{ 97 if (split->dstprim_nr == MAX_PRIM-1) { 98 flush_vertex(split); 99 } 100 101 { 102 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++]; 103 memset(prim, 0, sizeof(*prim)); 104 return prim; 105 } 106} 107 108static int align(int value, int alignment) 109{ 110 return (value + alignment - 1) & ~(alignment - 1); 111} 112 113 114 115/* Break large primitives into smaller ones. If not possible, convert 116 * the primitive to indexed and pass to split_elts(). 117 */ 118static void split_prims( struct split_context *split) 119{ 120 GLuint csr = 0; 121 GLuint i; 122 123 for (i = 0; i < split->nr_prims; i++) { 124 const struct _mesa_prim *prim = &split->prim[i]; 125 GLuint first, incr; 126 GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr); 127 GLuint count; 128 129 /* Always wrap on an even numbered vertex to avoid problems with 130 * triangle strips. 131 */ 132 GLuint available = align(split->limits->max_verts - csr - 1, 2); 133 assert(split->limits->max_verts >= csr); 134 135 if (prim->count < first) 136 continue; 137 138 count = prim->count - (prim->count - first) % incr; 139 140 141 if ((available < count && !split_inplace) || 142 (available < first && split_inplace)) { 143 flush_vertex(split); 144 csr = 0; 145 available = align(split->limits->max_verts - csr - 1, 2); 146 } 147 148 if (available >= count) { 149 struct _mesa_prim *outprim = next_outprim(split); 150 *outprim = *prim; 151 csr += prim->count; 152 available = align(split->limits->max_verts - csr - 1, 2); 153 } 154 else if (split_inplace) { 155 GLuint j, nr; 156 157 158 for (j = 0 ; j < count ; ) { 159 GLuint remaining = count - j; 160 struct _mesa_prim *outprim = next_outprim(split); 161 162 nr = MIN2( available, remaining ); 163 164 nr -= (nr - first) % incr; 165 166 outprim->mode = prim->mode; 167 outprim->begin = (j == 0 && prim->begin); 168 outprim->end = (nr == remaining && prim->end); 169 outprim->start = prim->start + j; 170 outprim->count = nr; 171 172 if (nr == remaining) { 173 /* Finished. 174 */ 175 j += nr; 176 csr += nr; 177 available = align(split->limits->max_verts - csr - 1, 2); 178 } 179 else { 180 /* Wrapped the primitive: 181 */ 182 j += nr - (first - incr); 183 flush_vertex(split); 184 csr = 0; 185 available = align(split->limits->max_verts - csr - 1, 2); 186 } 187 } 188 } 189 else if (split->ib == NULL) { 190 /* XXX: could at least send the first max_verts off from the 191 * inplace buffers. 192 */ 193 194 /* else convert to indexed primitive and pass to split_elts, 195 * which will do the necessary copying and turn it back into a 196 * vertex primitive for rendering... 197 */ 198 struct _mesa_index_buffer ib; 199 struct _mesa_prim tmpprim; 200 GLuint *elts = malloc(count * sizeof(GLuint)); 201 GLuint j; 202 203 for (j = 0; j < count; j++) 204 elts[j] = prim->start + j; 205 206 ib.count = count; 207 ib.type = GL_UNSIGNED_INT; 208 ib.obj = split->ctx->Shared->NullBufferObj; 209 ib.ptr = elts; 210 211 tmpprim = *prim; 212 tmpprim.indexed = 1; 213 tmpprim.start = 0; 214 tmpprim.count = count; 215 216 flush_vertex(split); 217 218 vbo_split_copy(split->ctx, 219 split->array, 220 &tmpprim, 1, 221 &ib, 222 split->draw, 223 split->limits); 224 225 free(elts); 226 } 227 else { 228 flush_vertex(split); 229 230 vbo_split_copy(split->ctx, 231 split->array, 232 prim, 1, 233 split->ib, 234 split->draw, 235 split->limits); 236 } 237 } 238 239 flush_vertex(split); 240} 241 242 243void vbo_split_inplace( GLcontext *ctx, 244 const struct gl_client_array *arrays[], 245 const struct _mesa_prim *prim, 246 GLuint nr_prims, 247 const struct _mesa_index_buffer *ib, 248 GLuint min_index, 249 GLuint max_index, 250 vbo_draw_func draw, 251 const struct split_limits *limits ) 252{ 253 struct split_context split; 254 255 memset(&split, 0, sizeof(split)); 256 257 split.ctx = ctx; 258 split.array = arrays; 259 split.prim = prim; 260 split.nr_prims = nr_prims; 261 split.ib = ib; 262 split.min_index = min_index; 263 split.max_index = max_index; 264 split.draw = draw; 265 split.limits = limits; 266 267 split_prims( &split ); 268} 269 270 271