vbo_split_inplace.c revision 2708ddfb06a36d8568e2aa130bf1f7d551fcd309
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 * 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.
24 *
25 * Authors:
26 *    Keith Whitwell <keith@tungstengraphics.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.
39 */
40struct split_context {
41   GLcontext *ctx;
42   const struct gl_client_array **array;
43   const struct _mesa_prim *prim;
44   GLuint nr_prims;
45   const struct _mesa_index_buffer *ib;
46   GLuint min_index;
47   GLuint max_index;
48   vbo_draw_func draw;
49
50   const struct split_limits *limits;
51
52   struct _mesa_prim dstprim[MAX_PRIM];
53   GLuint dstprim_nr;
54};
55
56
57
58
59static void flush_vertex( struct split_context *split )
60{
61   GLuint min_index, max_index;
62   GLuint i;
63
64   if (!split->dstprim_nr)
65      return;
66
67   min_index = split->dstprim[0].start;
68   max_index = min_index + split->dstprim[0].count - 1;
69
70   for (i = 1; i < split->dstprim_nr; i++) {
71      GLuint tmp_min = split->dstprim[i].start;
72      GLuint tmp_max = tmp_min + split->dstprim[i].count - 1;
73
74      if (tmp_min < min_index)
75	 min_index = tmp_min;
76
77      if (tmp_max > max_index)
78	 max_index = tmp_max;
79   }
80
81   assert(max_index >= min_index);
82
83   split->draw( split->ctx,
84		split->array,
85		split->dstprim,
86		split->dstprim_nr,
87		NULL,
88		GL_TRUE,
89		min_index,
90		max_index);
91
92   split->dstprim_nr = 0;
93}
94
95
96static struct _mesa_prim *next_outprim( struct split_context *split )
97{
98   if (split->dstprim_nr == MAX_PRIM-1) {
99      flush_vertex(split);
100   }
101
102   {
103      struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
104      memset(prim, 0, sizeof(*prim));
105      return prim;
106   }
107}
108
109static int align(int value, int alignment)
110{
111   return (value + alignment - 1) & ~(alignment - 1);
112}
113
114
115
116/* Break large primitives into smaller ones.  If not possible, convert
117 * the primitive to indexed and pass to split_elts().
118 */
119static void split_prims( struct split_context *split)
120{
121   GLuint csr = 0;
122   GLuint i;
123
124   for (i = 0; i < split->nr_prims; i++) {
125      const struct _mesa_prim *prim = &split->prim[i];
126      GLuint first, incr;
127      GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
128      GLuint count;
129
130      /* Always wrap on an even numbered vertex to avoid problems with
131       * triangle strips.
132       */
133      GLuint available = align(split->limits->max_verts - csr - 1, 2);
134      assert(split->limits->max_verts >= csr);
135
136      if (prim->count < first)
137	 continue;
138
139      count = prim->count - (prim->count - first) % incr;
140
141
142      if ((available < count && !split_inplace) ||
143	  (available < first && split_inplace)) {
144	 flush_vertex(split);
145	 csr = 0;
146	 available = align(split->limits->max_verts - csr - 1, 2);
147      }
148
149      if (available >= count) {
150	 struct _mesa_prim *outprim = next_outprim(split);
151	 *outprim = *prim;
152	 csr += prim->count;
153	 available = align(split->limits->max_verts - csr - 1, 2);
154      }
155      else if (split_inplace) {
156	 GLuint j, nr;
157
158
159	 for (j = 0 ; j < count ; ) {
160	    GLuint remaining = count - j;
161	    struct _mesa_prim *outprim = next_outprim(split);
162
163	    nr = MIN2( available, remaining );
164
165	    nr -= (nr - first) % incr;
166
167	    outprim->mode = prim->mode;
168	    outprim->begin = (j == 0 && prim->begin);
169	    outprim->end = (nr == remaining && prim->end);
170	    outprim->start = prim->start + j;
171	    outprim->count = nr;
172
173	    if (nr == remaining) {
174	       /* Finished.
175		*/
176	       j += nr;
177	       csr += nr;
178	       available = align(split->limits->max_verts - csr - 1, 2);
179	    }
180	    else {
181	       /* Wrapped the primitive:
182		*/
183	       j += nr - (first - incr);
184	       flush_vertex(split);
185	       csr = 0;
186	       available = align(split->limits->max_verts - csr - 1, 2);
187	    }
188	 }
189      }
190      else if (split->ib == NULL) {
191	 /* XXX: could at least send the first max_verts off from the
192	  * inplace buffers.
193	  */
194
195	 /* else convert to indexed primitive and pass to split_elts,
196	  * which will do the necessary copying and turn it back into a
197	  * vertex primitive for rendering...
198	  */
199	 struct _mesa_index_buffer ib;
200	 struct _mesa_prim tmpprim;
201	 GLuint *elts = malloc(count * sizeof(GLuint));
202	 GLuint j;
203
204	 for (j = 0; j < count; j++)
205	    elts[j] = prim->start + j;
206
207	 ib.count = count;
208	 ib.type = GL_UNSIGNED_INT;
209	 ib.obj = split->ctx->Shared->NullBufferObj;
210	 ib.ptr = elts;
211
212	 tmpprim = *prim;
213	 tmpprim.indexed = 1;
214	 tmpprim.start = 0;
215	 tmpprim.count = count;
216
217	 flush_vertex(split);
218
219	 vbo_split_copy(split->ctx,
220			split->array,
221			&tmpprim, 1,
222			&ib,
223			split->draw,
224			split->limits);
225
226	 free(elts);
227      }
228      else {
229	 flush_vertex(split);
230
231	 vbo_split_copy(split->ctx,
232			split->array,
233			prim, 1,
234			split->ib,
235			split->draw,
236			split->limits);
237      }
238   }
239
240   flush_vertex(split);
241}
242
243
244void vbo_split_inplace( GLcontext *ctx,
245			const struct gl_client_array *arrays[],
246			const struct _mesa_prim *prim,
247			GLuint nr_prims,
248			const struct _mesa_index_buffer *ib,
249			GLuint min_index,
250			GLuint max_index,
251			vbo_draw_func draw,
252			const struct split_limits *limits )
253{
254   struct split_context split;
255
256   memset(&split, 0, sizeof(split));
257
258   split.ctx = ctx;
259   split.array = arrays;
260   split.prim = prim;
261   split.nr_prims = nr_prims;
262   split.ib = ib;
263   split.min_index = min_index;
264   split.max_index = max_index;
265   split.draw = draw;
266   split.limits = limits;
267
268   split_prims( &split );
269}
270
271
272