vbo_split_inplace.c revision 2708ddfb06a36d8568e2aa130bf1f7d551fcd309
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 GL_TRUE, 89 min_index, 90 max_index); 91 92 split->dstprim_nr = 0; 93} 94 95 96static struct _mesa_prim *next_outprim( struct split_context *split ) 97{ 98 if (split->dstprim_nr == MAX_PRIM-1) { 99 flush_vertex(split); 100 } 101 102 { 103 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++]; 104 memset(prim, 0, sizeof(*prim)); 105 return prim; 106 } 107} 108 109static int align(int value, int alignment) 110{ 111 return (value + alignment - 1) & ~(alignment - 1); 112} 113 114 115 116/* Break large primitives into smaller ones. If not possible, convert 117 * the primitive to indexed and pass to split_elts(). 118 */ 119static void split_prims( struct split_context *split) 120{ 121 GLuint csr = 0; 122 GLuint i; 123 124 for (i = 0; i < split->nr_prims; i++) { 125 const struct _mesa_prim *prim = &split->prim[i]; 126 GLuint first, incr; 127 GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr); 128 GLuint count; 129 130 /* Always wrap on an even numbered vertex to avoid problems with 131 * triangle strips. 132 */ 133 GLuint available = align(split->limits->max_verts - csr - 1, 2); 134 assert(split->limits->max_verts >= csr); 135 136 if (prim->count < first) 137 continue; 138 139 count = prim->count - (prim->count - first) % incr; 140 141 142 if ((available < count && !split_inplace) || 143 (available < first && split_inplace)) { 144 flush_vertex(split); 145 csr = 0; 146 available = align(split->limits->max_verts - csr - 1, 2); 147 } 148 149 if (available >= count) { 150 struct _mesa_prim *outprim = next_outprim(split); 151 *outprim = *prim; 152 csr += prim->count; 153 available = align(split->limits->max_verts - csr - 1, 2); 154 } 155 else if (split_inplace) { 156 GLuint j, nr; 157 158 159 for (j = 0 ; j < count ; ) { 160 GLuint remaining = count - j; 161 struct _mesa_prim *outprim = next_outprim(split); 162 163 nr = MIN2( available, remaining ); 164 165 nr -= (nr - first) % incr; 166 167 outprim->mode = prim->mode; 168 outprim->begin = (j == 0 && prim->begin); 169 outprim->end = (nr == remaining && prim->end); 170 outprim->start = prim->start + j; 171 outprim->count = nr; 172 173 if (nr == remaining) { 174 /* Finished. 175 */ 176 j += nr; 177 csr += nr; 178 available = align(split->limits->max_verts - csr - 1, 2); 179 } 180 else { 181 /* Wrapped the primitive: 182 */ 183 j += nr - (first - incr); 184 flush_vertex(split); 185 csr = 0; 186 available = align(split->limits->max_verts - csr - 1, 2); 187 } 188 } 189 } 190 else if (split->ib == NULL) { 191 /* XXX: could at least send the first max_verts off from the 192 * inplace buffers. 193 */ 194 195 /* else convert to indexed primitive and pass to split_elts, 196 * which will do the necessary copying and turn it back into a 197 * vertex primitive for rendering... 198 */ 199 struct _mesa_index_buffer ib; 200 struct _mesa_prim tmpprim; 201 GLuint *elts = malloc(count * sizeof(GLuint)); 202 GLuint j; 203 204 for (j = 0; j < count; j++) 205 elts[j] = prim->start + j; 206 207 ib.count = count; 208 ib.type = GL_UNSIGNED_INT; 209 ib.obj = split->ctx->Shared->NullBufferObj; 210 ib.ptr = elts; 211 212 tmpprim = *prim; 213 tmpprim.indexed = 1; 214 tmpprim.start = 0; 215 tmpprim.count = count; 216 217 flush_vertex(split); 218 219 vbo_split_copy(split->ctx, 220 split->array, 221 &tmpprim, 1, 222 &ib, 223 split->draw, 224 split->limits); 225 226 free(elts); 227 } 228 else { 229 flush_vertex(split); 230 231 vbo_split_copy(split->ctx, 232 split->array, 233 prim, 1, 234 split->ib, 235 split->draw, 236 split->limits); 237 } 238 } 239 240 flush_vertex(split); 241} 242 243 244void vbo_split_inplace( GLcontext *ctx, 245 const struct gl_client_array *arrays[], 246 const struct _mesa_prim *prim, 247 GLuint nr_prims, 248 const struct _mesa_index_buffer *ib, 249 GLuint min_index, 250 GLuint max_index, 251 vbo_draw_func draw, 252 const struct split_limits *limits ) 253{ 254 struct split_context split; 255 256 memset(&split, 0, sizeof(split)); 257 258 split.ctx = ctx; 259 split.array = arrays; 260 split.prim = prim; 261 split.nr_prims = nr_prims; 262 split.ib = ib; 263 split.min_index = min_index; 264 split.max_index = max_index; 265 split.draw = draw; 266 split.limits = limits; 267 268 split_prims( &split ); 269} 270 271 272