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>
33 /* Used for splitting without copying. No attempt is made to handle
34 * too large indexed vertex buffers: In general you need to copy to do
37 struct split_context
{
38 struct gl_context
*ctx
;
39 const struct gl_client_array
**array
;
40 const struct _mesa_prim
*prim
;
42 const struct _mesa_index_buffer
*ib
;
47 const struct split_limits
*limits
;
50 struct _mesa_prim dstprim
[MAX_PRIM
];
57 static void flush_vertex( struct split_context
*split
)
59 struct _mesa_index_buffer ib
;
62 if (!split
->dstprim_nr
)
68 ib
.count
= split
->max_index
- split
->min_index
+ 1;
69 ib
.ptr
= (const void *)((const char *)ib
.ptr
+
70 split
->min_index
* _mesa_sizeof_type(ib
.type
));
72 /* Rebase the primitives to save index buffer entries. */
73 for (i
= 0; i
< split
->dstprim_nr
; i
++)
74 split
->dstprim
[i
].start
-= split
->min_index
;
77 assert(split
->max_index
>= split
->min_index
);
79 split
->draw(split
->ctx
,
83 split
->ib
? &ib
: NULL
,
88 split
->dstprim_nr
= 0;
89 split
->min_index
= ~0;
94 static struct _mesa_prim
*next_outprim( struct split_context
*split
)
96 if (split
->dstprim_nr
== MAX_PRIM
-1) {
101 struct _mesa_prim
*prim
= &split
->dstprim
[split
->dstprim_nr
++];
102 memset(prim
, 0, sizeof(*prim
));
107 static void update_index_bounds(struct split_context
*split
,
108 const struct _mesa_prim
*prim
)
110 split
->min_index
= MIN2(split
->min_index
, prim
->start
);
111 split
->max_index
= MAX2(split
->max_index
, prim
->start
+ prim
->count
- 1);
114 /* Return the maximum amount of vertices that can be emitted for a
115 * primitive starting at 'prim->start', depending on the previous
118 static GLuint
get_max_vertices(struct split_context
*split
,
119 const struct _mesa_prim
*prim
)
121 if ((prim
->start
> split
->min_index
&&
122 prim
->start
- split
->min_index
>= split
->limit
) ||
123 (prim
->start
< split
->max_index
&&
124 split
->max_index
- prim
->start
>= split
->limit
))
125 /* "prim" starts too far away from the old range. */
128 return MIN2(split
->min_index
, prim
->start
) + split
->limit
- prim
->start
;
131 /* Break large primitives into smaller ones. If not possible, convert
132 * the primitive to indexed and pass to split_elts().
134 static void split_prims( struct split_context
*split
)
138 for (i
= 0; i
< split
->nr_prims
; i
++) {
139 const struct _mesa_prim
*prim
= &split
->prim
[i
];
141 GLboolean split_inplace
= split_prim_inplace(prim
->mode
, &first
, &incr
);
142 GLuint available
= get_max_vertices(split
, prim
);
143 GLuint count
= prim
->count
- (prim
->count
- first
) % incr
;
145 if (prim
->count
< first
)
148 if ((available
< count
&& !split_inplace
) ||
149 (available
< first
&& split_inplace
)) {
151 available
= get_max_vertices(split
, prim
);
154 if (available
>= count
) {
155 struct _mesa_prim
*outprim
= next_outprim(split
);
158 update_index_bounds(split
, outprim
);
160 else if (split_inplace
) {
163 for (j
= 0 ; j
< count
; ) {
164 GLuint remaining
= count
- j
;
165 struct _mesa_prim
*outprim
= next_outprim(split
);
167 nr
= MIN2( available
, remaining
);
168 nr
-= (nr
- first
) % incr
;
170 outprim
->mode
= prim
->mode
;
171 outprim
->begin
= (j
== 0 && prim
->begin
);
172 outprim
->end
= (nr
== remaining
&& prim
->end
);
173 outprim
->start
= prim
->start
+ j
;
175 outprim
->num_instances
= prim
->num_instances
;
177 update_index_bounds(split
, outprim
);
179 if (nr
== remaining
) {
185 /* Wrapped the primitive:
187 j
+= nr
- (first
- incr
);
189 available
= get_max_vertices(split
, prim
);
193 else if (split
->ib
== NULL
) {
194 /* XXX: could at least send the first max_verts off from the
198 /* else convert to indexed primitive and pass to split_elts,
199 * which will do the necessary copying and turn it back into a
200 * vertex primitive for rendering...
202 struct _mesa_index_buffer ib
;
203 struct _mesa_prim tmpprim
;
204 GLuint
*elts
= malloc(count
* sizeof(GLuint
));
207 for (j
= 0; j
< count
; j
++)
208 elts
[j
] = prim
->start
+ j
;
211 ib
.type
= GL_UNSIGNED_INT
;
212 ib
.obj
= split
->ctx
->Shared
->NullBufferObj
;
218 tmpprim
.count
= count
;
219 tmpprim
.num_instances
= 1;
223 vbo_split_copy(split
->ctx
,
235 vbo_split_copy(split
->ctx
,
248 void vbo_split_inplace( struct gl_context
*ctx
,
249 const struct gl_client_array
*arrays
[],
250 const struct _mesa_prim
*prim
,
252 const struct _mesa_index_buffer
*ib
,
256 const struct split_limits
*limits
)
258 struct split_context split
;
260 memset(&split
, 0, sizeof(split
));
263 split
.array
= arrays
;
265 split
.nr_prims
= nr_prims
;
268 /* Empty interval, makes calculations simpler. */
269 split
.min_index
= ~0;
273 split
.limits
= limits
;
274 split
.limit
= ib
? limits
->max_indices
: limits
->max_verts
;
276 split_prims( &split
);