b63c05c75f06cbd47a777e0e1cd4c3f7b86acfa6
[mesa.git] / src / mesa / vbo / vbo_split_inplace.c
1
2 /*
3 * Mesa 3-D graphics library
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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
18 * OR 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
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Keith Whitwell <keithw@vmware.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. No attempt is made to handle
39 * too large indexed vertex buffers: In general you need to copy to do
40 * that.
41 */
42 struct split_context {
43 struct gl_context *ctx;
44 const struct gl_vertex_array *array;
45 const struct _mesa_prim *prim;
46 GLuint nr_prims;
47 const struct _mesa_index_buffer *ib;
48 GLuint min_index;
49 GLuint max_index;
50 vbo_draw_func draw;
51
52 const struct split_limits *limits;
53 GLuint limit;
54
55 struct _mesa_prim dstprim[MAX_PRIM];
56 GLuint dstprim_nr;
57 };
58
59
60
61
62 static void
63 flush_vertex( struct split_context *split)
64 {
65 struct gl_context *ctx = split->ctx;
66 struct _mesa_index_buffer ib;
67 GLuint i;
68
69 if (!split->dstprim_nr)
70 return;
71
72 if (split->ib) {
73 ib = *split->ib;
74
75 ib.count = split->max_index - split->min_index + 1;
76 ib.ptr = (const void *)((const char *)ib.ptr +
77 split->min_index * ib.index_size);
78
79 /* Rebase the primitives to save index buffer entries. */
80 for (i = 0; i < split->dstprim_nr; i++)
81 split->dstprim[i].start -= split->min_index;
82 }
83
84 assert(split->max_index >= split->min_index);
85
86 split->draw(ctx,
87 split->array,
88 split->dstprim,
89 split->dstprim_nr,
90 split->ib ? &ib : NULL,
91 !split->ib,
92 split->min_index,
93 split->max_index,
94 NULL, 0, NULL);
95
96 split->dstprim_nr = 0;
97 split->min_index = ~0;
98 split->max_index = 0;
99 }
100
101
102 static struct _mesa_prim *
103 next_outprim(struct split_context *split)
104 {
105 if (split->dstprim_nr == MAX_PRIM-1) {
106 flush_vertex(split);
107 }
108
109 {
110 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
111 memset(prim, 0, sizeof(*prim));
112 return prim;
113 }
114 }
115
116
117 static void
118 update_index_bounds(struct split_context *split,
119 const struct _mesa_prim *prim)
120 {
121 split->min_index = MIN2(split->min_index, prim->start);
122 split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
123 }
124
125
126 /* Return the maximum amount of vertices that can be emitted for a
127 * primitive starting at 'prim->start', depending on the previous
128 * index bounds.
129 */
130 static GLuint
131 get_max_vertices(struct split_context *split,
132 const struct _mesa_prim *prim)
133 {
134 if ((prim->start > split->min_index &&
135 prim->start - split->min_index >= split->limit) ||
136 (prim->start < split->max_index &&
137 split->max_index - prim->start >= split->limit))
138 /* "prim" starts too far away from the old range. */
139 return 0;
140
141 return MIN2(split->min_index, prim->start) + split->limit - prim->start;
142 }
143
144
145 /* Break large primitives into smaller ones. If not possible, convert
146 * the primitive to indexed and pass to split_elts().
147 */
148 static void
149 split_prims(struct split_context *split)
150 {
151 GLuint i;
152
153 for (i = 0; i < split->nr_prims; i++) {
154 const struct _mesa_prim *prim = &split->prim[i];
155 GLuint first, incr;
156 GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
157 GLuint available = get_max_vertices(split, prim);
158 GLuint count = prim->count - (prim->count - first) % incr;
159
160 if (prim->count < first)
161 continue;
162
163 if ((available < count && !split_inplace) ||
164 (available < first && split_inplace)) {
165 flush_vertex(split);
166 available = get_max_vertices(split, prim);
167 }
168
169 if (available >= count) {
170 struct _mesa_prim *outprim = next_outprim(split);
171
172 *outprim = *prim;
173 update_index_bounds(split, outprim);
174 }
175 else if (split_inplace) {
176 GLuint j, nr;
177
178 for (j = 0 ; j < count ;) {
179 GLuint remaining = count - j;
180 struct _mesa_prim *outprim = next_outprim(split);
181
182 nr = MIN2(available, remaining);
183 nr -= (nr - first) % incr;
184
185 outprim->mode = prim->mode;
186 outprim->begin = (j == 0 && prim->begin);
187 outprim->end = (nr == remaining && prim->end);
188 outprim->start = prim->start + j;
189 outprim->count = nr;
190 outprim->num_instances = prim->num_instances;
191 outprim->base_instance = prim->base_instance;
192
193 update_index_bounds(split, outprim);
194
195 if (nr == remaining) {
196 /* Finished */
197 j += nr;
198 }
199 else {
200 /* Wrapped the primitive */
201 j += nr - (first - incr);
202 flush_vertex(split);
203 available = get_max_vertices(split, prim);
204 }
205 }
206 }
207 else if (split->ib == NULL) {
208 /* XXX: could at least send the first max_verts off from the
209 * inplace buffers.
210 */
211
212 /* else convert to indexed primitive and pass to split_elts,
213 * which will do the necessary copying and turn it back into a
214 * vertex primitive for rendering...
215 */
216 struct _mesa_index_buffer ib;
217 struct _mesa_prim tmpprim;
218 GLuint *elts = malloc(count * sizeof(GLuint));
219 GLuint j;
220
221 for (j = 0; j < count; j++)
222 elts[j] = prim->start + j;
223
224 ib.count = count;
225 ib.index_size = 4;
226 ib.obj = split->ctx->Shared->NullBufferObj;
227 ib.ptr = elts;
228
229 tmpprim = *prim;
230 tmpprim.indexed = 1;
231 tmpprim.start = 0;
232 tmpprim.count = count;
233 tmpprim.num_instances = 1;
234 tmpprim.base_instance = 0;
235
236 flush_vertex(split);
237
238 vbo_split_copy(split->ctx,
239 split->array,
240 &tmpprim, 1,
241 &ib,
242 split->draw,
243 split->limits);
244
245 free(elts);
246 }
247 else {
248 flush_vertex(split);
249
250 vbo_split_copy(split->ctx,
251 split->array,
252 prim, 1,
253 split->ib,
254 split->draw,
255 split->limits);
256 }
257 }
258
259 flush_vertex(split);
260 }
261
262
263 void
264 vbo_split_inplace(struct gl_context *ctx,
265 const struct gl_vertex_array *arrays,
266 const struct _mesa_prim *prim,
267 GLuint nr_prims,
268 const struct _mesa_index_buffer *ib,
269 GLuint min_index,
270 GLuint max_index,
271 vbo_draw_func draw,
272 const struct split_limits *limits)
273 {
274 struct split_context split;
275
276 memset(&split, 0, sizeof(split));
277
278 split.ctx = ctx;
279 split.array = arrays;
280 split.prim = prim;
281 split.nr_prims = nr_prims;
282 split.ib = ib;
283
284 /* Empty interval, makes calculations simpler. */
285 split.min_index = ~0;
286 split.max_index = 0;
287
288 split.draw = draw;
289 split.limits = limits;
290 split.limit = ib ? limits->max_indices : limits->max_verts;
291
292 split_prims(&split);
293 }
294
295