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 /**
137 * Dump the parameters/info for a vbo->draw() call.
138 */
139 static void
140 dump_draw_info(GLcontext *ctx,
141 const struct gl_client_array **arrays,
142 const struct _mesa_prim *prims,
143 GLuint nr_prims,
144 const struct _mesa_index_buffer *ib,
145 GLuint min_index,
146 GLuint max_index)
147 {
148 GLuint i, j;
149
150 _mesa_printf("VBO Draw:\n");
151 for (i = 0; i < nr_prims; i++) {
152 _mesa_printf("Prim %u of %u\n", i, nr_prims);
153 _mesa_printf(" Prim mode 0x%x\n", prims[i].mode);
154 _mesa_printf(" IB: %p\n", (void*) ib);
155 for (j = 0; j < VERT_ATTRIB_MAX; j++) {
156 _mesa_printf(" array %d at %p:\n", j, (void*) arrays[j]);
157 _mesa_printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
158 arrays[j]->Enabled, arrays[j]->Ptr,
159 arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
160 if (0) {
161 GLint k = prims[i].start + prims[i].count - 1;
162 GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
163 _mesa_printf(" last: %f %f %f\n",
164 last[0], last[1], last[2]);
165 }
166 }
167 }
168 }
169
170
171 static void
172 flush( struct copy_context *copy )
173 {
174 GLuint i;
175
176 /* Set some counters:
177 */
178 copy->dstib.count = copy->dstelt_nr;
179
180 #if 0
181 dump_draw_info(copy->ctx,
182 copy->dstarray_ptr,
183 copy->dstprim,
184 copy->dstprim_nr,
185 &copy->dstib,
186 0,
187 copy->dstbuf_nr);
188 #else
189 (void) dump_draw_info;
190 #endif
191
192 copy->draw( copy->ctx,
193 copy->dstarray_ptr,
194 copy->dstprim,
195 copy->dstprim_nr,
196 &copy->dstib,
197 0,
198 copy->dstbuf_nr );
199
200 /* Reset all pointers:
201 */
202 copy->dstprim_nr = 0;
203 copy->dstelt_nr = 0;
204 copy->dstbuf_nr = 0;
205 copy->dstptr = copy->dstbuf;
206
207 /* Clear the vertex cache:
208 */
209 for (i = 0; i < ELT_TABLE_SIZE; i++)
210 copy->vert_cache[i].in = ~0;
211 }
212
213
214 /**
215 * Called at begin of each primitive during replay.
216 */
217 static void
218 begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
219 {
220 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
221
222 /* _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag); */
223
224 prim->mode = mode;
225 prim->begin = begin_flag;
226 }
227
228
229 /**
230 * Use a hashtable to attempt to identify recently-emitted vertices
231 * and avoid re-emitting them.
232 */
233 static GLuint
234 elt(struct copy_context *copy, GLuint elt_idx)
235 {
236 GLuint elt = copy->srcelt[elt_idx];
237 GLuint slot = elt & (ELT_TABLE_SIZE-1);
238
239 /* _mesa_printf("elt %d\n", elt); */
240
241 /* Look up the incoming element in the vertex cache. Re-emit if
242 * necessary.
243 */
244 if (copy->vert_cache[slot].in != elt) {
245 GLubyte *csr = copy->dstptr;
246 GLuint i;
247
248 /* _mesa_printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
249
250 for (i = 0; i < copy->nr_varying; i++) {
251 const struct gl_client_array *srcarray = copy->varying[i].array;
252 const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
253
254 memcpy(csr, srcptr, copy->varying[i].size);
255 csr += copy->varying[i].size;
256
257 #ifdef NAN_CHECK
258 if (srcarray->Type == GL_FLOAT) {
259 GLuint k;
260 GLfloat *f = (GLfloat *) srcptr;
261 for (k = 0; k < srcarray->Size; k++) {
262 assert(!IS_INF_OR_NAN(f[k]));
263 assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
264 }
265 }
266 #endif
267
268 if (0)
269 {
270 const GLuint *f = (const GLuint *)srcptr;
271 GLuint j;
272 _mesa_printf(" varying %d: ", i);
273 for(j = 0; j < copy->varying[i].size / 4; j++)
274 _mesa_printf("%x ", f[j]);
275 _mesa_printf("\n");
276 }
277 }
278
279 copy->vert_cache[slot].in = elt;
280 copy->vert_cache[slot].out = copy->dstbuf_nr++;
281 copy->dstptr += copy->vertex_size;
282
283 assert(csr == copy->dstptr);
284 assert(copy->dstptr == (copy->dstbuf +
285 copy->dstbuf_nr * copy->vertex_size));
286 }
287 /* else */
288 /* _mesa_printf(" --> reuse vertex\n"); */
289
290 /* _mesa_printf(" --> emit %d\n", copy->vert_cache[slot].out); */
291 copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
292 return check_flush(copy);
293 }
294
295
296 /**
297 * Called at end of each primitive during replay.
298 */
299 static void
300 end( struct copy_context *copy, GLboolean end_flag )
301 {
302 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
303
304 /* _mesa_printf("end (%d)\n", end_flag); */
305
306 prim->end = end_flag;
307 prim->count = copy->dstelt_nr - prim->start;
308
309 if (++copy->dstprim_nr == MAX_PRIM ||
310 check_flush(copy))
311 flush(copy);
312 }
313
314
315 static void
316 replay_elts( struct copy_context *copy )
317 {
318 GLuint i, j, k;
319 GLboolean split;
320
321 for (i = 0; i < copy->nr_prims; i++) {
322 const struct _mesa_prim *prim = &copy->prim[i];
323 const GLuint start = prim->start;
324 GLuint first, incr;
325
326 switch (prim->mode) {
327
328 case GL_LINE_LOOP:
329 /* Convert to linestrip and emit the final vertex explicitly,
330 * but only in the resultant strip that requires it.
331 */
332 j = 0;
333 while (j != prim->count) {
334 begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
335
336 for (split = GL_FALSE; j != prim->count && !split; j++)
337 split = elt(copy, start + j);
338
339 if (j == prim->count) {
340 /* Done, emit final line. Split doesn't matter as
341 * it is always raised a bit early so we can emit
342 * the last verts if necessary!
343 */
344 if (prim->end)
345 (void)elt(copy, start + 0);
346
347 end(copy, prim->end);
348 }
349 else {
350 /* Wrap
351 */
352 assert(split);
353 end(copy, 0);
354 j--;
355 }
356 }
357 break;
358
359 case GL_TRIANGLE_FAN:
360 case GL_POLYGON:
361 j = 2;
362 while (j != prim->count) {
363 begin(copy, prim->mode, prim->begin && j == 0);
364
365 split = elt(copy, start+0);
366 assert(!split);
367
368 split = elt(copy, start+j-1);
369 assert(!split);
370
371 for (; j != prim->count && !split; j++)
372 split = elt(copy, start+j);
373
374 end(copy, prim->end && j == prim->count);
375
376 if (j != prim->count) {
377 /* Wrapped the primitive, need to repeat some vertices:
378 */
379 j -= 1;
380 }
381 }
382 break;
383
384 default:
385 (void)split_prim_inplace(prim->mode, &first, &incr);
386
387 j = 0;
388 while (j != prim->count) {
389
390 begin(copy, prim->mode, prim->begin && j == 0);
391
392 split = 0;
393 for (k = 0; k < first; k++, j++)
394 split |= elt(copy, start+j);
395
396 assert(!split);
397
398 for (; j != prim->count && !split; )
399 for (k = 0; k < incr; k++, j++)
400 split |= elt(copy, start+j);
401
402 end(copy, prim->end && j == prim->count);
403
404 if (j != prim->count) {
405 /* Wrapped the primitive, need to repeat some vertices:
406 */
407 assert(j > first - incr);
408 j -= (first - incr);
409 }
410 }
411 break;
412 }
413 }
414
415 if (copy->dstprim_nr)
416 flush(copy);
417 }
418
419
420 static void
421 replay_init( struct copy_context *copy )
422 {
423 GLcontext *ctx = copy->ctx;
424 GLuint i;
425 GLuint offset;
426 const GLvoid *srcptr;
427
428 /* Make a list of varying attributes and their vbo's. Also
429 * calculate vertex size.
430 */
431 copy->vertex_size = 0;
432 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
433 struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
434
435 if (copy->array[i]->StrideB == 0) {
436 copy->dstarray_ptr[i] = copy->array[i];
437 }
438 else {
439 GLuint j = copy->nr_varying++;
440
441 copy->varying[j].attr = i;
442 copy->varying[j].array = copy->array[i];
443 copy->varying[j].size = attr_size(copy->array[i]);
444 copy->vertex_size += attr_size(copy->array[i]);
445
446 if (vbo->Name && !vbo->Pointer)
447 ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
448
449 copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
450 copy->array[i]->Ptr);
451
452 copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
453 }
454 }
455
456 /* There must always be an index buffer. Currently require the
457 * caller convert non-indexed prims to indexed. Could alternately
458 * do it internally.
459 */
460 if (copy->ib->obj->Name && !copy->ib->obj->Pointer)
461 ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
462 copy->ib->obj);
463
464 srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
465 copy->ib->ptr);
466
467 switch (copy->ib->type) {
468 case GL_UNSIGNED_BYTE:
469 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
470 copy->srcelt = copy->translated_elt_buf;
471
472 for (i = 0; i < copy->ib->count; i++)
473 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
474 break;
475
476 case GL_UNSIGNED_SHORT:
477 copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
478 copy->srcelt = copy->translated_elt_buf;
479
480 for (i = 0; i < copy->ib->count; i++)
481 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
482 break;
483
484 case GL_UNSIGNED_INT:
485 copy->translated_elt_buf = NULL;
486 copy->srcelt = (const GLuint *)srcptr;
487 break;
488 }
489
490 /* Figure out the maximum allowed vertex buffer size:
491 */
492 if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
493 copy->dstbuf_size = copy->limits->max_verts;
494 }
495 else {
496 copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
497 }
498
499 /* Allocate an output vertex buffer:
500 *
501 * XXX: This should be a VBO!
502 */
503 copy->dstbuf = _mesa_malloc(copy->dstbuf_size * copy->vertex_size);
504 copy->dstptr = copy->dstbuf;
505
506 /* Setup new vertex arrays to point into the output buffer:
507 */
508 for (offset = 0, i = 0; i < copy->nr_varying; i++) {
509 const struct gl_client_array *src = copy->varying[i].array;
510 struct gl_client_array *dst = &copy->varying[i].dstarray;
511
512 dst->Size = src->Size;
513 dst->Type = src->Type;
514 dst->Format = GL_RGBA;
515 dst->Stride = copy->vertex_size;
516 dst->StrideB = copy->vertex_size;
517 dst->Ptr = copy->dstbuf + offset;
518 dst->Enabled = GL_TRUE;
519 dst->Normalized = src->Normalized;
520 dst->BufferObj = ctx->Shared->NullBufferObj;
521 dst->_MaxElement = copy->dstbuf_size; /* may be less! */
522
523 offset += copy->varying[i].size;
524 }
525
526 /* Allocate an output element list:
527 */
528 copy->dstelt_size = MIN2(65536,
529 copy->ib->count * 2 + 3);
530 copy->dstelt_size = MIN2(copy->dstelt_size,
531 copy->limits->max_indices);
532 copy->dstelt = _mesa_malloc(sizeof(GLuint) * copy->dstelt_size);
533 copy->dstelt_nr = 0;
534
535 /* Setup the new index buffer to point to the allocated element
536 * list:
537 */
538 copy->dstib.count = 0; /* duplicates dstelt_nr */
539 copy->dstib.type = GL_UNSIGNED_INT;
540 copy->dstib.obj = ctx->Shared->NullBufferObj;
541 copy->dstib.ptr = copy->dstelt;
542 }
543
544
545 /**
546 * Free up everything allocated during split/replay.
547 */
548 static void
549 replay_finish( struct copy_context *copy )
550 {
551 GLcontext *ctx = copy->ctx;
552 GLuint i;
553
554 /* Free our vertex and index buffers:
555 */
556 _mesa_free(copy->translated_elt_buf);
557 _mesa_free(copy->dstbuf);
558 _mesa_free(copy->dstelt);
559
560 /* Unmap VBO's
561 */
562 for (i = 0; i < copy->nr_varying; i++) {
563 struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
564 if (vbo->Name && vbo->Pointer)
565 ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
566 }
567
568 /* Unmap index buffer:
569 */
570 if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
571 ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
572 }
573 }
574
575
576 /**
577 * Split VBO into smaller pieces, draw the pieces.
578 */
579 void vbo_split_copy( GLcontext *ctx,
580 const struct gl_client_array *arrays[],
581 const struct _mesa_prim *prim,
582 GLuint nr_prims,
583 const struct _mesa_index_buffer *ib,
584 vbo_draw_func draw,
585 const struct split_limits *limits )
586 {
587 struct copy_context copy;
588 GLuint i;
589
590 memset(&copy, 0, sizeof(copy));
591
592 /* Require indexed primitives:
593 */
594 assert(ib);
595
596 copy.ctx = ctx;
597 copy.array = arrays;
598 copy.prim = prim;
599 copy.nr_prims = nr_prims;
600 copy.ib = ib;
601 copy.draw = draw;
602 copy.limits = limits;
603
604 /* Clear the vertex cache:
605 */
606 for (i = 0; i < ELT_TABLE_SIZE; i++)
607 copy.vert_cache[i].in = ~0;
608
609 replay_init(&copy);
610 replay_elts(&copy);
611 replay_finish(&copy);
612 }