3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
26 * Keith Whitwell <keith@tungstengraphics.com>
30 #include "main/mtypes.h"
31 #include "main/macros.h"
32 #include "main/enums.h"
33 #include "main/image.h"
34 #include "vbo_split.h"
39 /* Used for splitting without copying. No attempt is made to handle
40 * too large indexed vertex buffers: In general you need to copy to do
43 struct split_context {
44 struct gl_context *ctx;
45 const struct gl_client_array **array;
46 const struct _mesa_prim *prim;
48 const struct _mesa_index_buffer *ib;
53 const struct split_limits *limits;
56 struct _mesa_prim dstprim[MAX_PRIM];
63 static void flush_vertex( struct split_context *split )
65 struct _mesa_index_buffer ib;
68 if (!split->dstprim_nr)
74 ib.count = split->max_index - split->min_index + 1;
75 ib.ptr = (const void *)((const char *)ib.ptr +
76 split->min_index * _mesa_sizeof_type(ib.type));
78 /* Rebase the primitives to save index buffer entries. */
79 for (i = 0; i < split->dstprim_nr; i++)
80 split->dstprim[i].start -= split->min_index;
83 assert(split->max_index >= split->min_index);
85 split->draw(split->ctx,
89 split->ib ? &ib : NULL,
94 split->dstprim_nr = 0;
95 split->min_index = ~0;
100 static struct _mesa_prim *next_outprim( struct split_context *split )
102 if (split->dstprim_nr == MAX_PRIM-1) {
107 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
108 memset(prim, 0, sizeof(*prim));
113 static void update_index_bounds(struct split_context *split,
114 const struct _mesa_prim *prim)
116 split->min_index = MIN2(split->min_index, prim->start);
117 split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
120 /* Return the maximum amount of vertices that can be emitted for a
121 * primitive starting at 'prim->start', depending on the previous
124 static GLuint get_max_vertices(struct split_context *split,
125 const struct _mesa_prim *prim)
127 if ((prim->start > split->min_index &&
128 prim->start - split->min_index >= split->limit) ||
129 (prim->start < split->max_index &&
130 split->max_index - prim->start >= split->limit))
131 /* "prim" starts too far away from the old range. */
134 return MIN2(split->min_index, prim->start) + split->limit - prim->start;
137 /* Break large primitives into smaller ones. If not possible, convert
138 * the primitive to indexed and pass to split_elts().
140 static void split_prims( struct split_context *split)
144 for (i = 0; i < split->nr_prims; i++) {
145 const struct _mesa_prim *prim = &split->prim[i];
147 GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
148 GLuint available = get_max_vertices(split, prim);
149 GLuint count = prim->count - (prim->count - first) % incr;
151 if (prim->count < first)
154 if ((available < count && !split_inplace) ||
155 (available < first && split_inplace)) {
157 available = get_max_vertices(split, prim);
160 if (available >= count) {
161 struct _mesa_prim *outprim = next_outprim(split);
164 update_index_bounds(split, outprim);
166 else if (split_inplace) {
169 for (j = 0 ; j < count ; ) {
170 GLuint remaining = count - j;
171 struct _mesa_prim *outprim = next_outprim(split);
173 nr = MIN2( available, remaining );
174 nr -= (nr - first) % incr;
176 outprim->mode = prim->mode;
177 outprim->begin = (j == 0 && prim->begin);
178 outprim->end = (nr == remaining && prim->end);
179 outprim->start = prim->start + j;
181 outprim->num_instances = prim->num_instances;
183 update_index_bounds(split, outprim);
185 if (nr == remaining) {
191 /* Wrapped the primitive:
193 j += nr - (first - incr);
195 available = get_max_vertices(split, prim);
199 else if (split->ib == NULL) {
200 /* XXX: could at least send the first max_verts off from the
204 /* else convert to indexed primitive and pass to split_elts,
205 * which will do the necessary copying and turn it back into a
206 * vertex primitive for rendering...
208 struct _mesa_index_buffer ib;
209 struct _mesa_prim tmpprim;
210 GLuint *elts = malloc(count * sizeof(GLuint));
213 for (j = 0; j < count; j++)
214 elts[j] = prim->start + j;
217 ib.type = GL_UNSIGNED_INT;
218 ib.obj = split->ctx->Shared->NullBufferObj;
224 tmpprim.count = count;
225 tmpprim.num_instances = 1;
229 vbo_split_copy(split->ctx,
241 vbo_split_copy(split->ctx,
254 void vbo_split_inplace( struct gl_context *ctx,
255 const struct gl_client_array *arrays[],
256 const struct _mesa_prim *prim,
258 const struct _mesa_index_buffer *ib,
262 const struct split_limits *limits )
264 struct split_context split;
266 memset(&split, 0, sizeof(split));
269 split.array = arrays;
271 split.nr_prims = nr_prims;
274 /* Empty interval, makes calculations simpler. */
275 split.min_index = ~0;
279 split.limits = limits;
280 split.limit = ib ? limits->max_indices : limits->max_verts;
282 split_prims( &split );