mesa: remove _MESA_INIT_ARRAYELT_VTXFMT() macro
[mesa.git] / src / mesa / vbo / vbo_split_inplace.c
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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Keith Whitwell <keith@tungstengraphics.com>
28 */
29
30
31 #include "main/mtypes.h"
32 #include "main/macros.h"
33 #include "main/enums.h"
34 #include "main/glformats.h"
35 #include "vbo_split.h"
36
37
38 #define MAX_PRIM 32
39
40 /* Used for splitting without copying. No attempt is made to handle
41 * too large indexed vertex buffers: In general you need to copy to do
42 * that.
43 */
44 struct split_context {
45 struct gl_context *ctx;
46 const struct gl_client_array **array;
47 const struct _mesa_prim *prim;
48 GLuint nr_prims;
49 const struct _mesa_index_buffer *ib;
50 GLuint min_index;
51 GLuint max_index;
52 vbo_draw_func draw;
53
54 const struct split_limits *limits;
55 GLuint limit;
56
57 struct _mesa_prim dstprim[MAX_PRIM];
58 GLuint dstprim_nr;
59 };
60
61
62
63
64 static void flush_vertex( struct split_context *split )
65 {
66 struct gl_context *ctx = split->ctx;
67 const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
68 struct _mesa_index_buffer ib;
69 GLuint i;
70
71 if (!split->dstprim_nr)
72 return;
73
74 if (split->ib) {
75 ib = *split->ib;
76
77 ib.count = split->max_index - split->min_index + 1;
78 ib.ptr = (const void *)((const char *)ib.ptr +
79 split->min_index * _mesa_sizeof_type(ib.type));
80
81 /* Rebase the primitives to save index buffer entries. */
82 for (i = 0; i < split->dstprim_nr; i++)
83 split->dstprim[i].start -= split->min_index;
84 }
85
86 assert(split->max_index >= split->min_index);
87
88 ctx->Array._DrawArrays = split->array;
89 ctx->NewDriverState |= ctx->DriverFlags.NewArray;
90
91 split->draw(ctx,
92 split->dstprim,
93 split->dstprim_nr,
94 split->ib ? &ib : NULL,
95 !split->ib,
96 split->min_index,
97 split->max_index,
98 NULL);
99
100 ctx->Array._DrawArrays = saved_arrays;
101 ctx->NewDriverState |= ctx->DriverFlags.NewArray;
102
103 split->dstprim_nr = 0;
104 split->min_index = ~0;
105 split->max_index = 0;
106 }
107
108
109 static struct _mesa_prim *next_outprim( struct split_context *split )
110 {
111 if (split->dstprim_nr == MAX_PRIM-1) {
112 flush_vertex(split);
113 }
114
115 {
116 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
117 memset(prim, 0, sizeof(*prim));
118 return prim;
119 }
120 }
121
122 static void update_index_bounds(struct split_context *split,
123 const struct _mesa_prim *prim)
124 {
125 split->min_index = MIN2(split->min_index, prim->start);
126 split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
127 }
128
129 /* Return the maximum amount of vertices that can be emitted for a
130 * primitive starting at 'prim->start', depending on the previous
131 * index bounds.
132 */
133 static GLuint get_max_vertices(struct split_context *split,
134 const struct _mesa_prim *prim)
135 {
136 if ((prim->start > split->min_index &&
137 prim->start - split->min_index >= split->limit) ||
138 (prim->start < split->max_index &&
139 split->max_index - prim->start >= split->limit))
140 /* "prim" starts too far away from the old range. */
141 return 0;
142
143 return MIN2(split->min_index, prim->start) + split->limit - prim->start;
144 }
145
146 /* Break large primitives into smaller ones. If not possible, convert
147 * the primitive to indexed and pass to split_elts().
148 */
149 static void 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 */
198 j += nr;
199 }
200 else {
201 /* Wrapped the primitive:
202 */
203 j += nr - (first - incr);
204 flush_vertex(split);
205 available = get_max_vertices(split, prim);
206 }
207 }
208 }
209 else if (split->ib == NULL) {
210 /* XXX: could at least send the first max_verts off from the
211 * inplace buffers.
212 */
213
214 /* else convert to indexed primitive and pass to split_elts,
215 * which will do the necessary copying and turn it back into a
216 * vertex primitive for rendering...
217 */
218 struct _mesa_index_buffer ib;
219 struct _mesa_prim tmpprim;
220 GLuint *elts = malloc(count * sizeof(GLuint));
221 GLuint j;
222
223 for (j = 0; j < count; j++)
224 elts[j] = prim->start + j;
225
226 ib.count = count;
227 ib.type = GL_UNSIGNED_INT;
228 ib.obj = split->ctx->Shared->NullBufferObj;
229 ib.ptr = elts;
230
231 tmpprim = *prim;
232 tmpprim.indexed = 1;
233 tmpprim.start = 0;
234 tmpprim.count = count;
235 tmpprim.num_instances = 1;
236 tmpprim.base_instance = 0;
237
238 flush_vertex(split);
239
240 vbo_split_copy(split->ctx,
241 split->array,
242 &tmpprim, 1,
243 &ib,
244 split->draw,
245 split->limits);
246
247 free(elts);
248 }
249 else {
250 flush_vertex(split);
251
252 vbo_split_copy(split->ctx,
253 split->array,
254 prim, 1,
255 split->ib,
256 split->draw,
257 split->limits);
258 }
259 }
260
261 flush_vertex(split);
262 }
263
264
265 void vbo_split_inplace( struct gl_context *ctx,
266 const struct gl_client_array *arrays[],
267 const struct _mesa_prim *prim,
268 GLuint nr_prims,
269 const struct _mesa_index_buffer *ib,
270 GLuint min_index,
271 GLuint max_index,
272 vbo_draw_func draw,
273 const struct split_limits *limits )
274 {
275 struct split_context split;
276
277 memset(&split, 0, sizeof(split));
278
279 split.ctx = ctx;
280 split.array = arrays;
281 split.prim = prim;
282 split.nr_prims = nr_prims;
283 split.ib = ib;
284
285 /* Empty interval, makes calculations simpler. */
286 split.min_index = ~0;
287 split.max_index = 0;
288
289 split.draw = draw;
290 split.limits = limits;
291 split.limit = ib ? limits->max_indices : limits->max_verts;
292
293 split_prims( &split );
294 }
295
296