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 "vbo_split.h"
38 /* Used for splitting without copying.
40 struct split_context
{
42 const struct gl_client_array
**array
;
43 const struct _mesa_prim
*prim
;
45 const struct _mesa_index_buffer
*ib
;
50 const struct split_limits
*limits
;
52 struct _mesa_prim dstprim
[MAX_PRIM
];
59 static void flush_vertex( struct split_context
*split
)
61 GLuint min_index
, max_index
;
63 if (!split
->dstprim_nr
)
67 /* This should basically be multipass rendering over the same
68 * unchanging set of VBO's. Would like the driver not to
69 * re-upload the data, or swtnl not to re-transform the
72 assert(split
->max_index
- split
->min_index
< split
->limits
->max_verts
);
73 min_index
= split
->min_index
;
74 max_index
= split
->max_index
;
77 /* Non-indexed rendering. Cannot assume that the primitives are
78 * ordered by increasing vertex, because of entrypoints like
82 min_index
= split
->dstprim
[0].start
;
83 max_index
= min_index
+ split
->dstprim
[0].count
- 1;
85 for (i
= 1; i
< split
->dstprim_nr
; i
++) {
86 GLuint tmp_min
= split
->dstprim
[i
].start
;
87 GLuint tmp_max
= tmp_min
+ split
->dstprim
[i
].count
- 1;
89 if (tmp_min
< min_index
)
92 if (tmp_max
> max_index
)
97 assert(max_index
>= min_index
);
99 split
->draw( split
->ctx
,
107 split
->dstprim_nr
= 0;
111 static struct _mesa_prim
*next_outprim( struct split_context
*split
)
113 if (split
->dstprim_nr
== MAX_PRIM
-1) {
118 struct _mesa_prim
*prim
= &split
->dstprim
[split
->dstprim_nr
++];
119 memset(prim
, 0, sizeof(*prim
));
124 static int align(int value
, int alignment
)
126 return (value
+ alignment
- 1) & ~(alignment
- 1);
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
)
139 for (i
= 0; i
< split
->nr_prims
; i
++) {
140 const struct _mesa_prim
*prim
= &split
->prim
[i
];
142 GLboolean split_inplace
= split_prim_inplace(prim
->mode
, &first
, &incr
);
145 /* Always wrap on an even numbered vertex to avoid problems with
148 GLuint available
= align(split
->limits
->max_verts
- csr
- 1, 2);
149 assert(split
->limits
->max_verts
>= csr
);
151 if (prim
->count
< first
)
154 count
= prim
->count
- (prim
->count
- first
) % incr
;
157 if ((available
< count
&& !split_inplace
) ||
158 (available
< first
&& split_inplace
)) {
161 available
= align(split
->limits
->max_verts
- csr
- 1, 2);
164 if (available
>= count
) {
165 struct _mesa_prim
*outprim
= next_outprim(split
);
168 available
= align(split
->limits
->max_verts
- csr
- 1, 2);
170 else if (split_inplace
) {
174 for (j
= 0 ; j
< count
; ) {
175 GLuint remaining
= count
- j
;
176 struct _mesa_prim
*outprim
= next_outprim(split
);
178 nr
= MIN2( available
, remaining
);
180 nr
-= (nr
- first
) % incr
;
182 outprim
->mode
= prim
->mode
;
183 outprim
->begin
= (j
== 0 && prim
->begin
);
184 outprim
->end
= (nr
== remaining
&& prim
->end
);
185 outprim
->start
= prim
->start
+ j
;
188 if (nr
== remaining
) {
193 available
= align(split
->limits
->max_verts
- csr
- 1, 2);
196 /* Wrapped the primitive:
198 j
+= nr
- (first
- incr
);
201 available
= align(split
->limits
->max_verts
- csr
- 1, 2);
205 else if (split
->ib
== NULL
) {
206 /* XXX: could at least send the first max_verts off from the
210 /* else convert to indexed primitive and pass to split_elts,
211 * which will do the necessary copying and turn it back into a
212 * vertex primitive for rendering...
214 struct _mesa_index_buffer ib
;
215 struct _mesa_prim tmpprim
;
216 GLuint
*elts
= malloc(count
* sizeof(GLuint
));
219 for (j
= 0; j
< count
; j
++)
220 elts
[j
] = prim
->start
+ j
;
223 ib
.type
= GL_UNSIGNED_INT
;
224 ib
.obj
= split
->ctx
->Shared
->NullBufferObj
;
230 tmpprim
.count
= count
;
234 vbo_split_copy(split
->ctx
,
246 vbo_split_copy(split
->ctx
,
259 void vbo_split_inplace( GLcontext
*ctx
,
260 const struct gl_client_array
*arrays
[],
261 const struct _mesa_prim
*prim
,
263 const struct _mesa_index_buffer
*ib
,
267 const struct split_limits
*limits
)
269 struct split_context split
;
271 memset(&split
, 0, sizeof(split
));
274 split
.array
= arrays
;
276 split
.nr_prims
= nr_prims
;
278 split
.min_index
= min_index
;
279 split
.max_index
= max_index
;
281 split
.limits
= limits
;
283 split_prims( &split
);