i965: fix bugs in projective texture coordinates
[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 * 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 */
40 struct 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
59 static void flush_vertex( struct split_context *split )
60 {
61 GLuint min_index, max_index;
62
63 if (!split->dstprim_nr)
64 return;
65
66 if (split->ib) {
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
70 * vertices.
71 */
72 assert(split->max_index - split->min_index < split->limits->max_verts);
73 min_index = split->min_index;
74 max_index = split->max_index;
75 }
76 else {
77 /* Non-indexed rendering. Cannot assume that the primitives are
78 * ordered by increasing vertex, because of entrypoints like
79 * MultiDrawArrays.
80 */
81 GLuint i;
82 min_index = split->dstprim[0].start;
83 max_index = min_index + split->dstprim[0].count - 1;
84
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;
88
89 if (tmp_min < min_index)
90 min_index = tmp_min;
91
92 if (tmp_max > max_index)
93 max_index = tmp_max;
94 }
95 }
96
97 assert(max_index >= min_index);
98
99 split->draw( split->ctx,
100 split->array,
101 split->dstprim,
102 split->dstprim_nr,
103 NULL,
104 min_index,
105 max_index);
106
107 split->dstprim_nr = 0;
108 }
109
110
111 static struct _mesa_prim *next_outprim( struct split_context *split )
112 {
113 if (split->dstprim_nr == MAX_PRIM-1) {
114 flush_vertex(split);
115 }
116
117 {
118 struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
119 memset(prim, 0, sizeof(*prim));
120 return prim;
121 }
122 }
123
124 static int align(int value, int alignment)
125 {
126 return (value + alignment - 1) & ~(alignment - 1);
127 }
128
129
130
131 /* Break large primitives into smaller ones. If not possible, convert
132 * the primitive to indexed and pass to split_elts().
133 */
134 static void split_prims( struct split_context *split)
135 {
136 GLuint csr = 0;
137 GLuint i;
138
139 for (i = 0; i < split->nr_prims; i++) {
140 const struct _mesa_prim *prim = &split->prim[i];
141 GLuint first, incr;
142 GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
143 GLuint count;
144
145 /* Always wrap on an even numbered vertex to avoid problems with
146 * triangle strips.
147 */
148 GLuint available = align(split->limits->max_verts - csr - 1, 2);
149 assert(split->limits->max_verts >= csr);
150
151 if (prim->count < first)
152 continue;
153
154 count = prim->count - (prim->count - first) % incr;
155
156
157 if ((available < count && !split_inplace) ||
158 (available < first && split_inplace)) {
159 flush_vertex(split);
160 csr = 0;
161 available = align(split->limits->max_verts - csr - 1, 2);
162 }
163
164 if (available >= count) {
165 struct _mesa_prim *outprim = next_outprim(split);
166 *outprim = *prim;
167 csr += prim->count;
168 available = align(split->limits->max_verts - csr - 1, 2);
169 }
170 else if (split_inplace) {
171 GLuint j, nr;
172
173
174 for (j = 0 ; j < count ; ) {
175 GLuint remaining = count - j;
176 struct _mesa_prim *outprim = next_outprim(split);
177
178 nr = MIN2( available, remaining );
179
180 nr -= (nr - first) % incr;
181
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;
186 outprim->count = nr;
187
188 if (nr == remaining) {
189 /* Finished.
190 */
191 j += nr;
192 csr += nr;
193 available = align(split->limits->max_verts - csr - 1, 2);
194 }
195 else {
196 /* Wrapped the primitive:
197 */
198 j += nr - (first - incr);
199 flush_vertex(split);
200 csr = 0;
201 available = align(split->limits->max_verts - csr - 1, 2);
202 }
203 }
204 }
205 else if (split->ib == NULL) {
206 /* XXX: could at least send the first max_verts off from the
207 * inplace buffers.
208 */
209
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...
213 */
214 struct _mesa_index_buffer ib;
215 struct _mesa_prim tmpprim;
216 GLuint *elts = malloc(count * sizeof(GLuint));
217 GLuint j;
218
219 for (j = 0; j < count; j++)
220 elts[j] = prim->start + j;
221
222 ib.count = count;
223 ib.type = GL_UNSIGNED_INT;
224 ib.obj = split->ctx->Array.NullBufferObj;
225 ib.ptr = elts;
226
227 tmpprim = *prim;
228 tmpprim.indexed = 1;
229 tmpprim.start = 0;
230 tmpprim.count = count;
231
232 flush_vertex(split);
233
234 vbo_split_copy(split->ctx,
235 split->array,
236 &tmpprim, 1,
237 &ib,
238 split->draw,
239 split->limits);
240
241 free(elts);
242 }
243 else {
244 flush_vertex(split);
245
246 vbo_split_copy(split->ctx,
247 split->array,
248 prim, 1,
249 split->ib,
250 split->draw,
251 split->limits);
252 }
253 }
254
255 flush_vertex(split);
256 }
257
258
259 void vbo_split_inplace( GLcontext *ctx,
260 const struct gl_client_array *arrays[],
261 const struct _mesa_prim *prim,
262 GLuint nr_prims,
263 const struct _mesa_index_buffer *ib,
264 GLuint min_index,
265 GLuint max_index,
266 vbo_draw_func draw,
267 const struct split_limits *limits )
268 {
269 struct split_context split;
270
271 memset(&split, 0, sizeof(split));
272
273 split.ctx = ctx;
274 split.array = arrays;
275 split.prim = prim;
276 split.nr_prims = nr_prims;
277 split.ib = ib;
278 split.min_index = min_index;
279 split.max_index = max_index;
280 split.draw = draw;
281 split.limits = limits;
282
283 split_prims( &split );
284 }
285
286