3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
26 * Keith Whitwell <keith@tungstengraphics.com>
29 /* Split indexed primitives with per-vertex copying.
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"
40 #include "vbo_split.h"
44 #define ELT_TABLE_SIZE 16
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.
54 const struct gl_client_array
**array
;
55 const struct _mesa_prim
*prim
;
57 const struct _mesa_index_buffer
*ib
;
60 const struct split_limits
*limits
;
65 const struct gl_client_array
*array
;
66 const GLubyte
*src_ptr
;
68 struct gl_client_array dstarray
;
70 } varying
[VERT_ATTRIB_MAX
];
73 const struct gl_client_array
*dstarray_ptr
[VERT_ATTRIB_MAX
];
74 struct _mesa_index_buffer dstib
;
76 GLuint
*translated_elt_buf
;
79 /** A baby hash table to avoid re-emitting (some) duplicate
80 * vertices when splitting indexed primitives.
85 } vert_cache
[ELT_TABLE_SIZE
];
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.
100 struct _mesa_prim dstprim
[MAX_PRIM
];
106 static GLuint
attr_size( const struct gl_client_array
*array
)
108 return array
->Size
* _mesa_sizeof_type(array
->Type
);
113 * Starts returning true slightly before the buffer fills, to ensure
114 * that there is sufficient room for any remaining vertices to finish
118 check_flush( struct copy_context
*copy
)
120 GLenum mode
= copy
->dstprim
[copy
->dstprim_nr
].mode
;
122 if (GL_TRIANGLE_STRIP
== mode
&&
123 copy
->dstelt_nr
& 1) { /* see bug9962 */
127 if (copy
->dstbuf_nr
+ 4 > copy
->dstbuf_size
)
130 if (copy
->dstelt_nr
+ 4 > copy
->dstelt_size
)
138 * Dump the parameters/info for a vbo->draw() call.
141 dump_draw_info(GLcontext
*ctx
,
142 const struct gl_client_array
**arrays
,
143 const struct _mesa_prim
*prims
,
145 const struct _mesa_index_buffer
*ib
,
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
);
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]);
173 flush( struct copy_context
*copy
)
177 /* Set some counters:
179 copy
->dstib
.count
= copy
->dstelt_nr
;
182 dump_draw_info(copy
->ctx
,
190 (void) dump_draw_info
;
193 copy
->draw( copy
->ctx
,
202 /* Reset all pointers:
204 copy
->dstprim_nr
= 0;
207 copy
->dstptr
= copy
->dstbuf
;
209 /* Clear the vertex cache:
211 for (i
= 0; i
< ELT_TABLE_SIZE
; i
++)
212 copy
->vert_cache
[i
].in
= ~0;
217 * Called at begin of each primitive during replay.
220 begin( struct copy_context
*copy
, GLenum mode
, GLboolean begin_flag
)
222 struct _mesa_prim
*prim
= ©
->dstprim
[copy
->dstprim_nr
];
224 /* _mesa_printf("begin %s (%d)\n", _mesa_lookup_prim_by_nr(mode), begin_flag); */
227 prim
->begin
= begin_flag
;
232 * Use a hashtable to attempt to identify recently-emitted vertices
233 * and avoid re-emitting them.
236 elt(struct copy_context
*copy
, GLuint elt_idx
)
238 GLuint elt
= copy
->srcelt
[elt_idx
];
239 GLuint slot
= elt
& (ELT_TABLE_SIZE
-1);
241 /* _mesa_printf("elt %d\n", elt); */
243 /* Look up the incoming element in the vertex cache. Re-emit if
246 if (copy
->vert_cache
[slot
].in
!= elt
) {
247 GLubyte
*csr
= copy
->dstptr
;
250 /* _mesa_printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
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
;
256 memcpy(csr
, srcptr
, copy
->varying
[i
].size
);
257 csr
+= copy
->varying
[i
].size
;
260 if (srcarray
->Type
== GL_FLOAT
) {
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
);
272 const GLuint
*f
= (const GLuint
*)srcptr
;
274 _mesa_printf(" varying %d: ", i
);
275 for(j
= 0; j
< copy
->varying
[i
].size
/ 4; j
++)
276 _mesa_printf("%x ", f
[j
]);
281 copy
->vert_cache
[slot
].in
= elt
;
282 copy
->vert_cache
[slot
].out
= copy
->dstbuf_nr
++;
283 copy
->dstptr
+= copy
->vertex_size
;
285 assert(csr
== copy
->dstptr
);
286 assert(copy
->dstptr
== (copy
->dstbuf
+
287 copy
->dstbuf_nr
* copy
->vertex_size
));
290 /* _mesa_printf(" --> reuse vertex\n"); */
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
);
299 * Called at end of each primitive during replay.
302 end( struct copy_context
*copy
, GLboolean end_flag
)
304 struct _mesa_prim
*prim
= ©
->dstprim
[copy
->dstprim_nr
];
306 /* _mesa_printf("end (%d)\n", end_flag); */
308 prim
->end
= end_flag
;
309 prim
->count
= copy
->dstelt_nr
- prim
->start
;
311 if (++copy
->dstprim_nr
== MAX_PRIM
||
318 replay_elts( struct copy_context
*copy
)
323 for (i
= 0; i
< copy
->nr_prims
; i
++) {
324 const struct _mesa_prim
*prim
= ©
->prim
[i
];
325 const GLuint start
= prim
->start
;
328 switch (prim
->mode
) {
331 /* Convert to linestrip and emit the final vertex explicitly,
332 * but only in the resultant strip that requires it.
335 while (j
!= prim
->count
) {
336 begin(copy
, GL_LINE_STRIP
, prim
->begin
&& j
== 0);
338 for (split
= GL_FALSE
; j
!= prim
->count
&& !split
; j
++)
339 split
= elt(copy
, start
+ j
);
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!
347 (void)elt(copy
, start
+ 0);
349 end(copy
, prim
->end
);
361 case GL_TRIANGLE_FAN
:
364 while (j
!= prim
->count
) {
365 begin(copy
, prim
->mode
, prim
->begin
&& j
== 0);
367 split
= elt(copy
, start
+0);
370 split
= elt(copy
, start
+j
-1);
373 for (; j
!= prim
->count
&& !split
; j
++)
374 split
= elt(copy
, start
+j
);
376 end(copy
, prim
->end
&& j
== prim
->count
);
378 if (j
!= prim
->count
) {
379 /* Wrapped the primitive, need to repeat some vertices:
387 (void)split_prim_inplace(prim
->mode
, &first
, &incr
);
390 while (j
!= prim
->count
) {
392 begin(copy
, prim
->mode
, prim
->begin
&& j
== 0);
395 for (k
= 0; k
< first
; k
++, j
++)
396 split
|= elt(copy
, start
+j
);
400 for (; j
!= prim
->count
&& !split
; )
401 for (k
= 0; k
< incr
; k
++, j
++)
402 split
|= elt(copy
, start
+j
);
404 end(copy
, prim
->end
&& j
== prim
->count
);
406 if (j
!= prim
->count
) {
407 /* Wrapped the primitive, need to repeat some vertices:
409 assert(j
> first
- incr
);
417 if (copy
->dstprim_nr
)
423 replay_init( struct copy_context
*copy
)
425 GLcontext
*ctx
= copy
->ctx
;
428 const GLvoid
*srcptr
;
430 /* Make a list of varying attributes and their vbo's. Also
431 * calculate vertex size.
433 copy
->vertex_size
= 0;
434 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++) {
435 struct gl_buffer_object
*vbo
= copy
->array
[i
]->BufferObj
;
437 if (copy
->array
[i
]->StrideB
== 0) {
438 copy
->dstarray_ptr
[i
] = copy
->array
[i
];
441 GLuint j
= copy
->nr_varying
++;
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
]);
448 if (_mesa_is_bufferobj(vbo
) && !_mesa_bufferobj_mapped(vbo
))
449 ctx
->Driver
.MapBuffer(ctx
, GL_ARRAY_BUFFER
, GL_READ_ONLY
, vbo
);
451 copy
->varying
[j
].src_ptr
= ADD_POINTERS(vbo
->Pointer
,
452 copy
->array
[i
]->Ptr
);
454 copy
->dstarray_ptr
[i
] = ©
->varying
[j
].dstarray
;
458 /* There must always be an index buffer. Currently require the
459 * caller convert non-indexed prims to indexed. Could alternately
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
,
467 srcptr
= (const GLubyte
*) ADD_POINTERS(copy
->ib
->obj
->Pointer
,
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
;
475 for (i
= 0; i
< copy
->ib
->count
; i
++)
476 copy
->translated_elt_buf
[i
] = ((const GLubyte
*)srcptr
)[i
];
479 case GL_UNSIGNED_SHORT
:
480 copy
->translated_elt_buf
= _mesa_malloc(sizeof(GLuint
) * copy
->ib
->count
);
481 copy
->srcelt
= copy
->translated_elt_buf
;
483 for (i
= 0; i
< copy
->ib
->count
; i
++)
484 copy
->translated_elt_buf
[i
] = ((const GLushort
*)srcptr
)[i
];
487 case GL_UNSIGNED_INT
:
488 copy
->translated_elt_buf
= NULL
;
489 copy
->srcelt
= (const GLuint
*)srcptr
;
493 /* Figure out the maximum allowed vertex buffer size:
495 if (copy
->vertex_size
* copy
->limits
->max_verts
<= copy
->limits
->max_vb_size
) {
496 copy
->dstbuf_size
= copy
->limits
->max_verts
;
499 copy
->dstbuf_size
= copy
->limits
->max_vb_size
/ copy
->vertex_size
;
502 /* Allocate an output vertex buffer:
504 * XXX: This should be a VBO!
506 copy
->dstbuf
= _mesa_malloc(copy
->dstbuf_size
* copy
->vertex_size
);
507 copy
->dstptr
= copy
->dstbuf
;
509 /* Setup new vertex arrays to point into the output buffer:
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
= ©
->varying
[i
].dstarray
;
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! */
526 offset
+= copy
->varying
[i
].size
;
529 /* Allocate an output element list:
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
);
538 /* Setup the new index buffer to point to the allocated element
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
;
549 * Free up everything allocated during split/replay.
552 replay_finish( struct copy_context
*copy
)
554 GLcontext
*ctx
= copy
->ctx
;
557 /* Free our vertex and index buffers:
559 _mesa_free(copy
->translated_elt_buf
);
560 _mesa_free(copy
->dstbuf
);
561 _mesa_free(copy
->dstelt
);
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
);
571 /* Unmap index buffer:
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
);
581 * Split VBO into smaller pieces, draw the pieces.
583 void vbo_split_copy( GLcontext
*ctx
,
584 const struct gl_client_array
*arrays
[],
585 const struct _mesa_prim
*prim
,
587 const struct _mesa_index_buffer
*ib
,
589 const struct split_limits
*limits
)
591 struct copy_context copy
;
592 GLuint i
, this_nr_prims
;
594 for (i
= 0; i
< nr_prims
;) {
595 /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
596 * will rebase the elements to the basevertex, and we'll only
597 * emit strings of prims with the same basevertex in one draw call.
599 for (this_nr_prims
= 1; i
+ this_nr_prims
< nr_prims
;
601 if (prim
[i
].basevertex
!= prim
[i
+ this_nr_prims
].basevertex
)
605 memset(©
, 0, sizeof(copy
));
607 /* Require indexed primitives:
613 copy
.prim
= &prim
[i
];
614 copy
.nr_prims
= this_nr_prims
;
617 copy
.limits
= limits
;
619 /* Clear the vertex cache:
621 for (i
= 0; i
< ELT_TABLE_SIZE
; i
++)
622 copy
.vert_cache
[i
].in
= ~0;
626 replay_finish(©
);