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