3 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 * Keith Whitwell <keithw@vmware.com>
30 #include "main/mtypes.h"
31 #include "main/macros.h"
32 #include "main/enums.h"
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
44 struct split_context
{
45 struct gl_context
*ctx
;
46 const struct tnl_vertex_array
*array
;
47 const struct _mesa_prim
*prim
;
49 const struct _mesa_index_buffer
*ib
;
56 const struct split_limits
*limits
;
59 struct _mesa_prim dstprim
[MAX_PRIM
];
67 flush_vertex( struct split_context
*split
)
69 struct gl_context
*ctx
= split
->ctx
;
70 struct _mesa_index_buffer ib
;
73 if (!split
->dstprim_nr
)
79 ib
.count
= split
->max_index
- split
->min_index
+ 1;
80 ib
.ptr
= (const void *)((const char *)ib
.ptr
+
81 (split
->min_index
<< ib
.index_size_shift
));
83 /* Rebase the primitives to save index buffer entries. */
84 for (i
= 0; i
< split
->dstprim_nr
; i
++)
85 split
->dstprim
[i
].start
-= split
->min_index
;
88 assert(split
->max_index
>= split
->min_index
);
94 split
->ib
? &ib
: NULL
,
99 split
->base_instance
);
101 split
->dstprim_nr
= 0;
102 split
->min_index
= ~0;
103 split
->max_index
= 0;
107 static struct _mesa_prim
*
108 next_outprim(struct split_context
*split
)
110 if (split
->dstprim_nr
== MAX_PRIM
-1) {
115 struct _mesa_prim
*prim
= &split
->dstprim
[split
->dstprim_nr
++];
116 memset(prim
, 0, sizeof(*prim
));
123 update_index_bounds(struct split_context
*split
,
124 const struct _mesa_prim
*prim
)
126 split
->min_index
= MIN2(split
->min_index
, prim
->start
);
127 split
->max_index
= MAX2(split
->max_index
, prim
->start
+ prim
->count
- 1);
131 /* Return the maximum amount of vertices that can be emitted for a
132 * primitive starting at 'prim->start', depending on the previous
136 get_max_vertices(struct split_context
*split
,
137 const struct _mesa_prim
*prim
)
139 if ((prim
->start
> split
->min_index
&&
140 prim
->start
- split
->min_index
>= split
->limit
) ||
141 (prim
->start
< split
->max_index
&&
142 split
->max_index
- prim
->start
>= split
->limit
))
143 /* "prim" starts too far away from the old range. */
146 return MIN2(split
->min_index
, prim
->start
) + split
->limit
- prim
->start
;
150 /* Break large primitives into smaller ones. If not possible, convert
151 * the primitive to indexed and pass to split_elts().
154 split_prims(struct split_context
*split
)
158 for (i
= 0; i
< split
->nr_prims
; i
++) {
159 const struct _mesa_prim
*prim
= &split
->prim
[i
];
161 GLboolean split_inplace
=
162 _tnl_split_prim_inplace(prim
->mode
, &first
, &incr
);
163 GLuint available
= get_max_vertices(split
, prim
);
164 GLuint count
= prim
->count
- (prim
->count
- first
) % incr
;
166 if (prim
->count
< first
)
169 if ((available
< count
&& !split_inplace
) ||
170 (available
< first
&& split_inplace
)) {
172 available
= get_max_vertices(split
, prim
);
175 if (available
>= count
) {
176 struct _mesa_prim
*outprim
= next_outprim(split
);
179 update_index_bounds(split
, outprim
);
181 else if (split_inplace
) {
184 for (j
= 0 ; j
< count
;) {
185 GLuint remaining
= count
- j
;
186 struct _mesa_prim
*outprim
= next_outprim(split
);
188 nr
= MIN2(available
, remaining
);
189 nr
-= (nr
- first
) % incr
;
191 outprim
->mode
= prim
->mode
;
192 outprim
->begin
= (j
== 0 && prim
->begin
);
193 outprim
->end
= (nr
== remaining
&& prim
->end
);
194 outprim
->start
= prim
->start
+ j
;
197 update_index_bounds(split
, outprim
);
199 if (nr
== remaining
) {
204 /* Wrapped the primitive */
205 j
+= nr
- (first
- incr
);
207 available
= get_max_vertices(split
, prim
);
211 else if (split
->ib
== NULL
) {
212 /* XXX: could at least send the first max_verts off from the
216 /* else convert to indexed primitive and pass to split_elts,
217 * which will do the necessary copying and turn it back into a
218 * vertex primitive for rendering...
220 struct _mesa_index_buffer ib
;
221 struct _mesa_prim tmpprim
;
222 GLuint
*elts
= malloc(count
* sizeof(GLuint
));
225 for (j
= 0; j
< count
; j
++)
226 elts
[j
] = prim
->start
+ j
;
229 ib
.index_size_shift
= 2;
235 tmpprim
.count
= count
;
239 _tnl_split_copy(split
->ctx
,
251 _tnl_split_copy(split
->ctx
,
265 _tnl_split_inplace(struct gl_context
*ctx
,
266 const struct tnl_vertex_array
*arrays
,
267 const struct _mesa_prim
*prim
,
269 const struct _mesa_index_buffer
*ib
,
270 GLuint num_instances
,
271 GLuint base_instance
,
273 const struct split_limits
*limits
)
275 struct split_context split
;
277 memset(&split
, 0, sizeof(split
));
280 split
.array
= arrays
;
282 split
.nr_prims
= nr_prims
;
285 /* Empty interval, makes calculations simpler. */
286 split
.min_index
= ~0;
288 split
.num_instances
= num_instances
;
289 split
.base_instance
= base_instance
;
292 split
.limits
= limits
;
293 split
.limit
= ib
? limits
->max_indices
: limits
->max_verts
;