vbo: Readd the arrays argument to the legacy draw methods.
[mesa.git] / src / mesa / vbo / vbo_split_copy.c
1
2 /*
3 * Mesa 3-D graphics library
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Keith Whitwell <keithw@vmware.com>
27 */
28
29 /* Split indexed primitives with per-vertex copying.
30 */
31
32 #include <stdio.h>
33
34 #include "main/glheader.h"
35 #include "main/bufferobj.h"
36 #include "main/imports.h"
37 #include "main/glformats.h"
38 #include "main/macros.h"
39 #include "main/mtypes.h"
40 #include "main/varray.h"
41
42 #include "vbo_split.h"
43 #include "vbo.h"
44
45
46 #define ELT_TABLE_SIZE 16
47
48 /**
49 * Used for vertex-level splitting of indexed buffers. Note that
50 * non-indexed primitives may be converted to indexed in some cases
51 * (eg loops, fans) in order to use this splitting path.
52 */
53 struct copy_context {
54 struct gl_context *ctx;
55 const struct gl_vertex_array *array;
56 const struct _mesa_prim *prim;
57 GLuint nr_prims;
58 const struct _mesa_index_buffer *ib;
59 vbo_draw_func draw;
60
61 const struct split_limits *limits;
62
63 struct {
64 GLuint attr;
65 GLuint size;
66 const struct gl_vertex_array *array;
67 const GLubyte *src_ptr;
68
69 struct gl_vertex_buffer_binding dstbinding;
70 struct gl_array_attributes dstattribs;
71
72 } varying[VERT_ATTRIB_MAX];
73 GLuint nr_varying;
74
75 struct gl_vertex_array dstarray[VERT_ATTRIB_MAX];
76 struct _mesa_index_buffer dstib;
77
78 GLuint *translated_elt_buf;
79 const GLuint *srcelt;
80
81 /** A baby hash table to avoid re-emitting (some) duplicate
82 * vertices when splitting indexed primitives.
83 */
84 struct {
85 GLuint in;
86 GLuint out;
87 } vert_cache[ELT_TABLE_SIZE];
88
89 GLuint vertex_size;
90 GLubyte *dstbuf;
91 GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
92 GLuint dstbuf_size; /**< in vertices */
93 GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
94 * in dstelt. Our MaxIndex.
95 */
96
97 GLuint *dstelt;
98 GLuint dstelt_nr;
99 GLuint dstelt_size;
100
101 #define MAX_PRIM 32
102 struct _mesa_prim dstprim[MAX_PRIM];
103 GLuint dstprim_nr;
104 };
105
106
107 static GLuint
108 attr_size(const struct gl_array_attributes *attrib)
109 {
110 return attrib->Size * _mesa_sizeof_type(attrib->Type);
111 }
112
113
114 /**
115 * Starts returning true slightly before the buffer fills, to ensure
116 * that there is sufficient room for any remaining vertices to finish
117 * off the prim:
118 */
119 static GLboolean
120 check_flush(struct copy_context *copy)
121 {
122 GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
123
124 if (GL_TRIANGLE_STRIP == mode &&
125 copy->dstelt_nr & 1) { /* see bug9962 */
126 return GL_FALSE;
127 }
128
129 if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
130 return GL_TRUE;
131
132 if (copy->dstelt_nr + 4 > copy->dstelt_size)
133 return GL_TRUE;
134
135 return GL_FALSE;
136 }
137
138
139 /**
140 * Dump the parameters/info for a vbo->draw() call.
141 */
142 static void
143 dump_draw_info(struct gl_context *ctx,
144 const struct gl_vertex_array *arrays,
145 const struct _mesa_prim *prims,
146 GLuint nr_prims,
147 const struct _mesa_index_buffer *ib,
148 GLuint min_index,
149 GLuint max_index)
150 {
151 GLuint i, j;
152
153 printf("VBO Draw:\n");
154 for (i = 0; i < nr_prims; i++) {
155 printf("Prim %u of %u\n", i, nr_prims);
156 printf(" Prim mode 0x%x\n", prims[i].mode);
157 printf(" IB: %p\n", (void*) ib);
158 for (j = 0; j < VERT_ATTRIB_MAX; j++) {
159 const struct gl_vertex_array *array = &arrays[j];
160 const struct gl_vertex_buffer_binding *binding
161 = array->BufferBinding;
162 const struct gl_array_attributes *attrib = array->VertexAttrib;
163 const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
164 printf(" array %d at %p:\n", j, (void*) &arrays[j]);
165 printf(" ptr %p, size %d, type 0x%x, stride %d\n",
166 ptr, attrib->Size, attrib->Type, binding->Stride);
167 if (0) {
168 GLint k = prims[i].start + prims[i].count - 1;
169 GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
170 printf(" last: %f %f %f\n",
171 last[0], last[1], last[2]);
172 }
173 }
174 }
175 }
176
177
178 static void
179 flush(struct copy_context *copy)
180 {
181 struct gl_context *ctx = copy->ctx;
182 GLuint i;
183
184 /* Set some counters:
185 */
186 copy->dstib.count = copy->dstelt_nr;
187
188 #if 0
189 dump_draw_info(copy->ctx,
190 copy->dstarray,
191 copy->dstprim,
192 copy->dstprim_nr,
193 &copy->dstib,
194 0,
195 copy->dstbuf_nr);
196 #else
197 (void) dump_draw_info;
198 #endif
199
200 copy->draw(ctx,
201 copy->dstarray,
202 copy->dstprim,
203 copy->dstprim_nr,
204 &copy->dstib,
205 GL_TRUE,
206 0,
207 copy->dstbuf_nr - 1,
208 NULL, 0, NULL);
209
210 /* Reset all pointers:
211 */
212 copy->dstprim_nr = 0;
213 copy->dstelt_nr = 0;
214 copy->dstbuf_nr = 0;
215 copy->dstptr = copy->dstbuf;
216
217 /* Clear the vertex cache:
218 */
219 for (i = 0; i < ELT_TABLE_SIZE; i++)
220 copy->vert_cache[i].in = ~0;
221 }
222
223
224 /**
225 * Called at begin of each primitive during replay.
226 */
227 static void
228 begin(struct copy_context *copy, GLenum mode, GLboolean begin_flag)
229 {
230 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
231
232 prim->mode = mode;
233 prim->begin = begin_flag;
234 prim->num_instances = 1;
235 }
236
237
238 /**
239 * Use a hashtable to attempt to identify recently-emitted vertices
240 * and avoid re-emitting them.
241 */
242 static GLuint
243 elt(struct copy_context *copy, GLuint elt_idx)
244 {
245 GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex;
246 GLuint slot = elt & (ELT_TABLE_SIZE-1);
247
248 /* Look up the incoming element in the vertex cache. Re-emit if
249 * necessary.
250 */
251 if (copy->vert_cache[slot].in != elt) {
252 GLubyte *csr = copy->dstptr;
253 GLuint i;
254
255 for (i = 0; i < copy->nr_varying; i++) {
256 const struct gl_vertex_array *srcarray = copy->varying[i].array;
257 const struct gl_vertex_buffer_binding* srcbinding
258 = srcarray->BufferBinding;
259 const GLubyte *srcptr
260 = copy->varying[i].src_ptr + elt * srcbinding->Stride;
261
262 memcpy(csr, srcptr, copy->varying[i].size);
263 csr += copy->varying[i].size;
264
265 #ifdef NAN_CHECK
266 if (srcarray->Type == GL_FLOAT) {
267 GLuint k;
268 GLfloat *f = (GLfloat *) srcptr;
269 for (k = 0; k < srcarray->Size; k++) {
270 assert(!IS_INF_OR_NAN(f[k]));
271 assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
272 }
273 }
274 #endif
275
276 if (0) {
277 const GLuint *f = (const GLuint *)srcptr;
278 GLuint j;
279 printf(" varying %d: ", i);
280 for (j = 0; j < copy->varying[i].size / 4; j++)
281 printf("%x ", f[j]);
282 printf("\n");
283 }
284 }
285
286 copy->vert_cache[slot].in = elt;
287 copy->vert_cache[slot].out = copy->dstbuf_nr++;
288 copy->dstptr += copy->vertex_size;
289
290 assert(csr == copy->dstptr);
291 assert(copy->dstptr == (copy->dstbuf +
292 copy->dstbuf_nr * copy->vertex_size));
293 }
294
295 copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
296 return check_flush(copy);
297 }
298
299
300 /**
301 * Called at end of each primitive during replay.
302 */
303 static void
304 end(struct copy_context *copy, GLboolean end_flag)
305 {
306 struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
307
308 prim->end = end_flag;
309 prim->count = copy->dstelt_nr - prim->start;
310
311 if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) {
312 flush(copy);
313 }
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 case GL_LINE_LOOP:
330 /* Convert to linestrip and emit the final vertex explicitly,
331 * but only in the resultant strip that requires it.
332 */
333 j = 0;
334 while (j != prim->count) {
335 begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
336
337 for (split = GL_FALSE; j != prim->count && !split; j++)
338 split = elt(copy, start + j);
339
340 if (j == prim->count) {
341 /* Done, emit final line. Split doesn't matter as
342 * it is always raised a bit early so we can emit
343 * the last verts if necessary!
344 */
345 if (prim->end)
346 (void)elt(copy, start + 0);
347
348 end(copy, prim->end);
349 }
350 else {
351 /* Wrap
352 */
353 assert(split);
354 end(copy, 0);
355 j--;
356 }
357 }
358 break;
359
360 case GL_TRIANGLE_FAN:
361 case GL_POLYGON:
362 j = 2;
363 while (j != prim->count) {
364 begin(copy, prim->mode, prim->begin && j == 0);
365
366 split = elt(copy, start+0);
367 assert(!split);
368
369 split = elt(copy, start+j-1);
370 assert(!split);
371
372 for (; j != prim->count && !split; j++)
373 split = elt(copy, start+j);
374
375 end(copy, prim->end && j == prim->count);
376
377 if (j != prim->count) {
378 /* Wrapped the primitive, need to repeat some vertices:
379 */
380 j -= 1;
381 }
382 }
383 break;
384
385 default:
386 (void)split_prim_inplace(prim->mode, &first, &incr);
387
388 j = 0;
389 while (j != prim->count) {
390
391 begin(copy, prim->mode, prim->begin && j == 0);
392
393 split = 0;
394 for (k = 0; k < first; k++, j++)
395 split |= elt(copy, start+j);
396
397 assert(!split);
398
399 for (; j != prim->count && !split;)
400 for (k = 0; k < incr; k++, j++)
401 split |= elt(copy, start+j);
402
403 end(copy, prim->end && j == prim->count);
404
405 if (j != prim->count) {
406 /* Wrapped the primitive, need to repeat some vertices:
407 */
408 assert(j > first - incr);
409 j -= (first - incr);
410 }
411 }
412 break;
413 }
414 }
415
416 if (copy->dstprim_nr)
417 flush(copy);
418 }
419
420
421 static void
422 replay_init(struct copy_context *copy)
423 {
424 struct gl_context *ctx = copy->ctx;
425 GLuint i;
426 GLuint offset;
427 const GLvoid *srcptr;
428
429 /* Make a list of varying attributes and their vbo's. Also
430 * calculate vertex size.
431 */
432 copy->vertex_size = 0;
433 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
434 const struct gl_vertex_array *array = &copy->array[i];
435 const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
436
437 if (binding->Stride == 0) {
438 _mesa_copy_vertex_array(&copy->dstarray[i], array);
439 }
440 else {
441 const struct gl_array_attributes *attrib = array->VertexAttrib;
442 struct gl_buffer_object *vbo = binding->BufferObj;
443 const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
444 GLuint j = copy->nr_varying++;
445
446 copy->varying[j].attr = i;
447 copy->varying[j].array = &copy->array[i];
448 copy->varying[j].size = attr_size(attrib);
449 copy->vertex_size += attr_size(attrib);
450
451 if (_mesa_is_bufferobj(vbo) &&
452 !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
453 ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo,
454 MAP_INTERNAL);
455
456 copy->varying[j].src_ptr =
457 ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
458
459 copy->dstarray[i].VertexAttrib = &copy->varying[j].dstattribs;
460 copy->dstarray[i].BufferBinding = &copy->varying[j].dstbinding;
461 }
462 }
463
464 /* There must always be an index buffer. Currently require the
465 * caller convert non-indexed prims to indexed. Could alternately
466 * do it internally.
467 */
468 if (_mesa_is_bufferobj(copy->ib->obj) &&
469 !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL))
470 ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
471 copy->ib->obj, MAP_INTERNAL);
472
473 srcptr = (const GLubyte *)
474 ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer,
475 copy->ib->ptr);
476
477 switch (copy->ib->index_size) {
478 case 1:
479 copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
480 copy->srcelt = copy->translated_elt_buf;
481
482 for (i = 0; i < copy->ib->count; i++)
483 copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
484 break;
485
486 case 2:
487 copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
488 copy->srcelt = copy->translated_elt_buf;
489
490 for (i = 0; i < copy->ib->count; i++)
491 copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
492 break;
493
494 case 4:
495 copy->translated_elt_buf = NULL;
496 copy->srcelt = (const GLuint *)srcptr;
497 break;
498 }
499
500 /* Figure out the maximum allowed vertex buffer size:
501 */
502 if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
503 copy->dstbuf_size = copy->limits->max_verts;
504 }
505 else {
506 copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
507 }
508
509 /* Allocate an output vertex buffer:
510 *
511 * XXX: This should be a VBO!
512 */
513 copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
514 copy->dstptr = copy->dstbuf;
515
516 /* Setup new vertex arrays to point into the output buffer:
517 */
518 for (offset = 0, i = 0; i < copy->nr_varying; i++) {
519 const struct gl_vertex_array *src = copy->varying[i].array;
520 const struct gl_array_attributes *srcattr = src->VertexAttrib;
521 struct gl_vertex_array *dst = &copy->dstarray[i];
522 struct gl_vertex_buffer_binding *dstbind = &copy->varying[i].dstbinding;
523 struct gl_array_attributes *dstattr = &copy->varying[i].dstattribs;
524
525 dstattr->Size = srcattr->Size;
526 dstattr->Type = srcattr->Type;
527 dstattr->Format = GL_RGBA;
528 dstbind->Stride = copy->vertex_size;
529 dstattr->Ptr = copy->dstbuf + offset;
530 dstattr->Normalized = srcattr->Normalized;
531 dstattr->Integer = srcattr->Integer;
532 dstattr->Doubles = srcattr->Doubles;
533 dstbind->BufferObj = ctx->Shared->NullBufferObj;
534 dstattr->_ElementSize = srcattr->_ElementSize;
535 dst->BufferBinding = dstbind;
536 dst->VertexAttrib = dstattr;
537
538 offset += copy->varying[i].size;
539 }
540
541 /* Allocate an output element list:
542 */
543 copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3);
544 copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices);
545 copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
546 copy->dstelt_nr = 0;
547
548 /* Setup the new index buffer to point to the allocated element
549 * list:
550 */
551 copy->dstib.count = 0; /* duplicates dstelt_nr */
552 copy->dstib.index_size = 4;
553 copy->dstib.obj = ctx->Shared->NullBufferObj;
554 copy->dstib.ptr = copy->dstelt;
555 }
556
557
558 /**
559 * Free up everything allocated during split/replay.
560 */
561 static void
562 replay_finish(struct copy_context *copy)
563 {
564 struct gl_context *ctx = copy->ctx;
565 GLuint i;
566
567 /* Free our vertex and index buffers */
568 free(copy->translated_elt_buf);
569 free(copy->dstbuf);
570 free(copy->dstelt);
571
572 /* Unmap VBO's */
573 for (i = 0; i < copy->nr_varying; i++) {
574 struct gl_buffer_object *vbo =
575 copy->varying[i].array->BufferBinding->BufferObj;
576 if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
577 ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
578 }
579
580 /* Unmap index buffer */
581 if (_mesa_is_bufferobj(copy->ib->obj) &&
582 _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) {
583 ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL);
584 }
585 }
586
587
588 /**
589 * Split VBO into smaller pieces, draw the pieces.
590 */
591 void
592 vbo_split_copy(struct gl_context *ctx,
593 const struct gl_vertex_array *arrays,
594 const struct _mesa_prim *prim,
595 GLuint nr_prims,
596 const struct _mesa_index_buffer *ib,
597 vbo_draw_func draw,
598 const struct split_limits *limits)
599 {
600 struct copy_context copy;
601 GLuint i, this_nr_prims;
602
603 for (i = 0; i < nr_prims;) {
604 /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
605 * will rebase the elements to the basevertex, and we'll only
606 * emit strings of prims with the same basevertex in one draw call.
607 */
608 for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
609 this_nr_prims++) {
610 if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
611 break;
612 }
613
614 memset(&copy, 0, sizeof(copy));
615
616 /* Require indexed primitives:
617 */
618 assert(ib);
619
620 copy.ctx = ctx;
621 copy.array = arrays;
622 copy.prim = &prim[i];
623 copy.nr_prims = this_nr_prims;
624 copy.ib = ib;
625 copy.draw = draw;
626 copy.limits = limits;
627
628 /* Clear the vertex cache:
629 */
630 for (i = 0; i < ELT_TABLE_SIZE; i++)
631 copy.vert_cache[i].in = ~0;
632
633 replay_init(&copy);
634 replay_elts(&copy);
635 replay_finish(&copy);
636 }
637 }