Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / vbo / vbo_split_copy.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 /* Split indexed primitives with per-vertex copying.
30 */
31
32 #include "main/glheader.h"
33 #include "main/imports.h"
34 #include "main/image.h"
35 #include "main/macros.h"
36 #include "main/enums.h"
37 #include "main/mtypes.h"
38
39 #include "vbo_split.h"
40 #include "vbo.h"
41
42
43 #define ELT_TABLE_SIZE 16
44
45 /**
46 * Used for vertex-level splitting of indexed buffers. Note that
47 * non-indexed primitives may be converted to indexed in some cases
48 * (eg loops, fans) in order to use this splitting path.
49 */
50 struct copy_context {
51
52 GLcontext *ctx;
53 const struct gl_client_array **array;
54 const struct _mesa_prim *prim;
55 GLuint nr_prims;
56 const struct _mesa_index_buffer *ib;
57 vbo_draw_func draw;
58
59 const struct split_limits *limits;
60
61 struct {
62 GLuint attr;
63 GLuint size;
64 const struct gl_client_array *array;
65 const GLubyte *src_ptr;
66
67 struct gl_client_array dstarray;
68
69 } varying[VERT_ATTRIB_MAX];
70 GLuint nr_varying;
71
72 const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
73 struct _mesa_index_buffer dstib;
74
75 GLuint *translated_elt_buf;
76 const GLuint *srcelt;
77
78 /** A baby hash table to avoid re-emitting (some) duplicate
79 * vertices when splitting indexed primitives.
80 */
81 struct {
82 GLuint in;
83 GLuint out;
84 } vert_cache[ELT_TABLE_SIZE];
85
86 GLuint vertex_size;
87 GLubyte *dstbuf;
88 GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
89 GLuint dstbuf_size; /**< in vertices */
90 GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
91 * in dstelt. Our MaxIndex.
92 */
93
94 GLuint *dstelt;
95 GLuint dstelt_nr;
96 GLuint dstelt_size;
97
98 #define MAX_PRIM 32
99 struct _mesa_prim dstprim[MAX_PRIM];
100 GLuint dstprim_nr;
101
102 };
103
104
105 static GLuint attr_size( const struct gl_client_array *array )
106 {
107 return array->Size * _mesa_sizeof_type(array->Type);
108 }
109
110
111 /**
112 * Starts returning true slightly before the buffer fills, to ensure
113 * that there is sufficient room for any remaining vertices to finish
114 * off the prim:
115 */
116 static GLboolean
117 check_flush( struct copy_context *copy )
118 {
119 GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
120
121 if (GL_TRIANGLE_STRIP == mode &&
122 copy->dstelt_nr & 1) { /* see bug9962 */
123 return GL_FALSE;
124 }
125
126 if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
127 return GL_TRUE;
128
129 if (copy->dstelt_nr + 4 > copy->dstelt_size)
130 return GL_TRUE;
131
132 return GL_FALSE;
133 }
134
135
136 static void
137 flush( struct copy_context *copy )
138 {
139 GLuint i;
140
141 /* Set some counters:
142 */
143 copy->dstib.count = copy->dstelt_nr;
144
145 copy->draw( copy->ctx,
146 copy->dstarray_ptr,
147 copy->dstprim,
148 copy->dstprim_nr,
149 &copy->dstib,
150 0,
151 copy->dstbuf_nr );
152
153 /* Reset all pointers:
154 */
155 copy->dstprim_nr = 0;
156 copy->dstelt_nr = 0;
157 copy->dstbuf_nr = 0;
158 copy->dstptr = copy->dstbuf;
159
160 /* Clear the vertex cache:
161 */
162 for (i = 0; i < ELT_TABLE_SIZE; i++)
163 copy->vert_cache[i].in = ~0;
164 }
165
166
167 /**
168 * Called at begin of each primitive during replay.
169 */
170 static void
171 begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
172 {
173 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
174
175 /* _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag); */
176
177 prim->mode = mode;
178 prim->begin = begin_flag;
179 }
180
181
182 /**
183 * Use a hashtable to attempt to identify recently-emitted vertices
184 * and avoid re-emitting them.
185 */
186 static GLuint
187 elt(struct copy_context *copy, GLuint elt_idx)
188 {
189 GLuint elt = copy->srcelt[elt_idx];
190 GLuint slot = elt & (ELT_TABLE_SIZE-1);
191
192 /* _mesa_printf("elt %d\n", elt); */
193
194 /* Look up the incoming element in the vertex cache. Re-emit if
195 * necessary.
196 */
197 if (copy->vert_cache[slot].in != elt) {
198 GLubyte *csr = copy->dstptr;
199 GLuint i;
200
201 /* _mesa_printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
202
203 for (i = 0; i < copy->nr_varying; i++) {
204 const struct gl_client_array *srcarray = copy->varying[i].array;
205 const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
206
207 memcpy(csr, srcptr, copy->varying[i].size);
208 csr += copy->varying[i].size;
209
210 if (0)
211 {
212 const GLuint *f = (const GLuint *)srcptr;
213 GLuint j;
214 _mesa_printf(" varying %d: ", i);
215 for(j = 0; j < copy->varying[i].size / 4; j++)
216 _mesa_printf("%x ", f[j]);
217 _mesa_printf("\n");
218 }
219 }
220
221 copy->vert_cache[slot].in = elt;
222 copy->vert_cache[slot].out = copy->dstbuf_nr++;
223 copy->dstptr += copy->vertex_size;
224
225 assert(csr == copy->dstptr);
226 assert(copy->dstptr == (copy->dstbuf +
227 copy->dstbuf_nr * copy->vertex_size));
228 }
229 /* else */
230 /* _mesa_printf(" --> reuse vertex\n"); */
231
232 /* _mesa_printf(" --> emit %d\n", copy->vert_cache[slot].out); */
233 copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
234 return check_flush(copy);
235 }
236
237
238 /**
239 * Called at end of each primitive during replay.
240 */
241 static void
242 end( struct copy_context *copy, GLboolean end_flag )
243 {
244 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
245
246 /* _mesa_printf("end (%d)\n", end_flag); */
247
248 prim->end = end_flag;
249 prim->count = copy->dstelt_nr - prim->start;
250
251 if (++copy->dstprim_nr == MAX_PRIM ||
252 check_flush(copy))
253 flush(copy);
254 }
255
256
257 static void
258 replay_elts( struct copy_context *copy )
259 {
260 GLuint i, j, k;
261 GLboolean split;
262
263 for (i = 0; i < copy->nr_prims; i++) {
264 const struct _mesa_prim *prim = &copy->prim[i];
265 const GLuint start = prim->start;
266 GLuint first, incr;
267
268 switch (prim->mode) {
269
270 case GL_LINE_LOOP:
271 /* Convert to linestrip and emit the final vertex explicitly,
272 * but only in the resultant strip that requires it.
273 */
274 j = 0;
275 while (j != prim->count) {
276 begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
277
278 for (split = GL_FALSE; j != prim->count && !split; j++)
279 split = elt(copy, start + j);
280
281 if (j == prim->count) {
282 /* Done, emit final line. Split doesn't matter as
283 * it is always raised a bit early so we can emit
284 * the last verts if necessary!
285 */
286 if (prim->end)
287 (void)elt(copy, start + 0);
288
289 end(copy, prim->end);
290 }
291 else {
292 /* Wrap
293 */
294 assert(split);
295 end(copy, 0);
296 j--;
297 }
298 }
299 break;
300
301 case GL_TRIANGLE_FAN:
302 case GL_POLYGON:
303 j = 2;
304 while (j != prim->count) {
305 begin(copy, prim->mode, prim->begin && j == 0);
306
307 split = elt(copy, start+0);
308 assert(!split);
309
310 split = elt(copy, start+j-1);
311 assert(!split);
312
313 for (; j != prim->count && !split; j++)
314 split = elt(copy, start+j);
315
316 end(copy, prim->end && j == prim->count);
317
318 if (j != prim->count) {
319 /* Wrapped the primitive, need to repeat some vertices:
320 */
321 j -= 1;
322 }
323 }
324 break;
325
326 default:
327 (void)split_prim_inplace(prim->mode, &first, &incr);
328
329 j = 0;
330 while (j != prim->count) {
331
332 begin(copy, prim->mode, prim->begin && j == 0);
333
334 split = 0;
335 for (k = 0; k < first; k++, j++)
336 split |= elt(copy, start+j);
337
338 assert(!split);
339
340 for (; j != prim->count && !split; )
341 for (k = 0; k < incr; k++, j++)
342 split |= elt(copy, start+j);
343
344 end(copy, prim->end && j == prim->count);
345
346 if (j != prim->count) {
347 /* Wrapped the primitive, need to repeat some vertices:
348 */
349 assert(j > first - incr);
350 j -= (first - incr);
351 }
352 }
353 break;
354 }
355 }
356
357 if (copy->dstprim_nr)
358 flush(copy);
359 }
360
361
362 static void
363 replay_init( struct copy_context *copy )
364 {
365 GLcontext *ctx = copy->ctx;
366 GLuint i;
367 GLuint offset;
368 const GLvoid *srcptr;
369
370 /* Make a list of varying attributes and their vbo's. Also
371 * calculate vertex size.
372 */
373 copy->vertex_size = 0;
374 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
375 struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
376
377 if (copy->array[i]->StrideB == 0) {
378 copy->dstarray_ptr[i] = copy->array[i];
379 }
380 else {
381 GLuint j = copy->nr_varying++;
382
383 copy->varying[j].attr = i;
384 copy->varying[j].array = copy->array[i];
385 copy->varying[j].size = attr_size(copy->array[i]);
386 copy->vertex_size += attr_size(copy->array[i]);
387
388 if (vbo->Name && !vbo->Pointer)
389 ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
390
391 copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
392 copy->array[i]->Ptr);
393
394 copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
395 }
396 }
397
398 /* There must always be an index buffer. Currently require the
399 * caller convert non-indexed prims to indexed. Could alternately
400 * do it internally.
401 */
402 if (copy->ib->obj->Name && !copy->ib->obj->Pointer)
403 ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
404 copy->ib->obj);
405
406 srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
407 copy->ib->ptr);
408
409 switch (copy->ib->type) {
410 case GL_UNSIGNED_BYTE:
411 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
412 copy->srcelt = copy->translated_elt_buf;
413
414 for (i = 0; i < copy->ib->count; i++)
415 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
416 break;
417
418 case GL_UNSIGNED_SHORT:
419 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
420 copy->srcelt = copy->translated_elt_buf;
421
422 for (i = 0; i < copy->ib->count; i++)
423 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
424 break;
425
426 case GL_UNSIGNED_INT:
427 copy->translated_elt_buf = NULL;
428 copy->srcelt = (const GLuint *)srcptr;
429 break;
430 }
431
432 /* Figure out the maximum allowed vertex buffer size:
433 */
434 if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
435 copy->dstbuf_size = copy->limits->max_verts;
436 }
437 else {
438 copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
439 }
440
441 /* Allocate an output vertex buffer:
442 *
443 * XXX: This should be a VBO!
444 */
445 copy->dstbuf = _mesa_malloc(copy->dstbuf_size * copy->vertex_size);
446 copy->dstptr = copy->dstbuf;
447
448 /* Setup new vertex arrays to point into the output buffer:
449 */
450 for (offset = 0, i = 0; i < copy->nr_varying; i++) {
451 const struct gl_client_array *src = copy->varying[i].array;
452 struct gl_client_array *dst = &copy->varying[i].dstarray;
453
454 dst->Size = src->Size;
455 dst->Type = src->Type;
456 dst->Format = GL_RGBA;
457 dst->Stride = copy->vertex_size;
458 dst->StrideB = copy->vertex_size;
459 dst->Ptr = copy->dstbuf + offset;
460 dst->Enabled = GL_TRUE;
461 dst->Normalized = src->Normalized;
462 dst->BufferObj = ctx->Shared->NullBufferObj;
463 dst->_MaxElement = copy->dstbuf_size; /* may be less! */
464
465 offset += copy->varying[i].size;
466 }
467
468 /* Allocate an output element list:
469 */
470 copy->dstelt_size = MIN2(65536,
471 copy->ib->count * 2 + 3);
472 copy->dstelt_size = MIN2(copy->dstelt_size,
473 copy->limits->max_indices);
474 copy->dstelt = _mesa_malloc(sizeof(GLuint) * copy->dstelt_size);
475 copy->dstelt_nr = 0;
476
477 /* Setup the new index buffer to point to the allocated element
478 * list:
479 */
480 copy->dstib.count = 0; /* duplicates dstelt_nr */
481 copy->dstib.type = GL_UNSIGNED_INT;
482 copy->dstib.obj = ctx->Shared->NullBufferObj;
483 copy->dstib.ptr = copy->dstelt;
484 }
485
486
487 /**
488 * Free up everything allocated during split/replay.
489 */
490 static void
491 replay_finish( struct copy_context *copy )
492 {
493 GLcontext *ctx = copy->ctx;
494 GLuint i;
495
496 /* Free our vertex and index buffers:
497 */
498 _mesa_free(copy->translated_elt_buf);
499 _mesa_free(copy->dstbuf);
500 _mesa_free(copy->dstelt);
501
502 /* Unmap VBO's
503 */
504 for (i = 0; i < copy->nr_varying; i++) {
505 struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
506 if (vbo->Name && vbo->Pointer)
507 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
508 }
509
510 /* Unmap index buffer:
511 */
512 if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
513 ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
514 }
515 }
516
517
518 /**
519 * Split VBO into smaller pieces, draw the pieces.
520 */
521 void vbo_split_copy( GLcontext *ctx,
522 const struct gl_client_array *arrays[],
523 const struct _mesa_prim *prim,
524 GLuint nr_prims,
525 const struct _mesa_index_buffer *ib,
526 vbo_draw_func draw,
527 const struct split_limits *limits )
528 {
529 struct copy_context copy;
530 GLuint i;
531
532 memset(&copy, 0, sizeof(copy));
533
534 /* Require indexed primitives:
535 */
536 assert(ib);
537
538 copy.ctx = ctx;
539 copy.array = arrays;
540 copy.prim = prim;
541 copy.nr_prims = nr_prims;
542 copy.ib = ib;
543 copy.draw = draw;
544 copy.limits = limits;
545
546 /* Clear the vertex cache:
547 */
548 for (i = 0; i < ELT_TABLE_SIZE; i++)
549 copy.vert_cache[i].in = ~0;
550
551 replay_init(&copy);
552 replay_elts(&copy);
553 replay_finish(&copy);
554 }