1 /**************************************************************************
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
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 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/macros.h"
76 #include "main/api_noop.h"
77 #include "main/api_validate.h"
78 #include "main/api_arrayelt.h"
79 #include "main/vtxfmt.h"
80 #include "glapi/dispatch.h"
82 #include "vbo_context.h"
90 /* An interesting VBO number/name to help with debugging */
91 #define VBO_BUF_ID 12345
95 * NOTE: Old 'parity' issue is gone, but copying can still be
96 * wrong-footed on replay.
98 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
99 const struct vbo_save_vertex_list
*node
,
100 const GLfloat
*src_buffer
)
102 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
103 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
104 GLuint nr
= prim
->count
;
105 GLuint sz
= save
->vertex_size
;
106 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
107 GLfloat
*dst
= save
->copied
.buffer
;
119 for (i
= 0 ; i
< ovf
; i
++)
120 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
124 for (i
= 0 ; i
< ovf
; i
++)
125 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
129 for (i
= 0 ; i
< ovf
; i
++)
130 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
136 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
140 case GL_TRIANGLE_FAN
:
145 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
148 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
149 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
152 case GL_TRIANGLE_STRIP
:
155 case 0: ovf
= 0; break;
156 case 1: ovf
= 1; break;
157 default: ovf
= 2 + (nr
&1); break;
159 for (i
= 0 ; i
< ovf
; i
++)
160 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
169 static struct vbo_save_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
171 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
173 /* obj->Name needs to be non-zero, but won't ever be examined more
174 * closely than that. In particular these buffers won't be entered
175 * into the hash and can never be confused with ones visible to the
176 * user. Perhaps there could be a special number for internal
179 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
181 GL_ARRAY_BUFFER_ARB
);
183 ctx
->Driver
.BufferData( ctx
,
185 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
188 vertex_store
->bufferobj
);
190 vertex_store
->buffer
= NULL
;
191 vertex_store
->used
= 0;
192 vertex_store
->refcount
= 1;
197 static void free_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
199 assert(!vertex_store
->buffer
);
201 if (vertex_store
->bufferobj
) {
202 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
205 FREE( vertex_store
);
208 static GLfloat
*map_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
210 assert(vertex_store
->bufferobj
);
211 assert(!vertex_store
->buffer
);
212 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
213 GL_ARRAY_BUFFER_ARB
, /* not used */
214 GL_WRITE_ONLY
, /* not used */
215 vertex_store
->bufferobj
);
217 assert(vertex_store
->buffer
);
218 return vertex_store
->buffer
+ vertex_store
->used
;
221 static void unmap_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
223 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
224 vertex_store
->buffer
= NULL
;
228 static struct vbo_save_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
230 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
237 static void _save_reset_counters( GLcontext
*ctx
)
239 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
241 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
242 save
->buffer
= (save
->vertex_store
->buffer
+
243 save
->vertex_store
->used
);
245 assert(save
->buffer
== save
->buffer_ptr
);
247 if (save
->vertex_size
)
248 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
253 save
->vert_count
= 0;
254 save
->prim_count
= 0;
255 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
256 save
->dangling_attr_ref
= 0;
260 /* Insert the active immediate struct onto the display list currently
263 static void _save_compile_vertex_list( GLcontext
*ctx
)
265 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
266 struct vbo_save_vertex_list
*node
;
268 /* Allocate space for this structure in the display list currently
271 node
= (struct vbo_save_vertex_list
*)
272 _mesa_alloc_instruction(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
277 /* Duplicate our template, increment refcounts to the storage structs:
279 _mesa_memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
280 node
->vertex_size
= save
->vertex_size
;
281 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
282 node
->count
= save
->vert_count
;
283 node
->wrap_count
= save
->copied
.nr
;
284 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
285 node
->prim
= save
->prim
;
286 node
->prim_count
= save
->prim_count
;
287 node
->vertex_store
= save
->vertex_store
;
288 node
->prim_store
= save
->prim_store
;
290 node
->vertex_store
->refcount
++;
291 node
->prim_store
->refcount
++;
294 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
295 node
->current_data
= NULL
;
297 if (node
->current_size
) {
298 /* If the malloc fails, we just pull the data out of the VBO
301 node
->current_data
= MALLOC( node
->current_size
* sizeof(GLfloat
) );
302 if (node
->current_data
) {
303 const char *buffer
= (const char *)save
->vertex_store
->buffer
;
304 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
305 unsigned vertex_offset
= 0;
308 vertex_offset
= (node
->count
-1) * node
->vertex_size
* sizeof(GLfloat
);
310 memcpy( node
->current_data
,
311 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
312 node
->current_size
* sizeof(GLfloat
) );
318 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
321 if (save
->dangling_attr_ref
)
322 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
324 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
325 save
->prim_store
->used
+= node
->prim_count
;
328 /* Copy duplicated vertices
330 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
333 /* Deal with GL_COMPILE_AND_EXECUTE:
335 if (ctx
->ExecuteFlag
) {
336 struct _glapi_table
*dispatch
= GET_DISPATCH();
338 _glapi_set_dispatch(ctx
->Exec
);
340 vbo_loopback_vertex_list( ctx
,
341 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
342 node
->buffer_offset
),
349 _glapi_set_dispatch(dispatch
);
353 /* Decide whether the storage structs are full, or can be used for
354 * the next vertex lists as well.
356 if (save
->vertex_store
->used
>
357 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
361 unmap_vertex_store( ctx
, save
->vertex_store
);
363 /* Release old reference:
365 save
->vertex_store
->refcount
--;
366 assert(save
->vertex_store
->refcount
!= 0);
367 save
->vertex_store
= NULL
;
369 /* Allocate and map new store:
371 save
->vertex_store
= alloc_vertex_store( ctx
);
372 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
375 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
376 save
->prim_store
->refcount
--;
377 assert(save
->prim_store
->refcount
!= 0);
378 save
->prim_store
= alloc_prim_store( ctx
);
381 /* Reset our structures for the next run of vertices:
383 _save_reset_counters( ctx
);
387 /* TODO -- If no new vertices have been stored, don't bother saving
390 static void _save_wrap_buffers( GLcontext
*ctx
)
392 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
393 GLint i
= save
->prim_count
- 1;
397 assert(i
< (GLint
) save
->prim_max
);
400 /* Close off in-progress primitive.
402 save
->prim
[i
].count
= (save
->vert_count
-
403 save
->prim
[i
].start
);
404 mode
= save
->prim
[i
].mode
;
405 weak
= save
->prim
[i
].weak
;
407 /* store the copied vertices, and allocate a new list.
409 _save_compile_vertex_list( ctx
);
411 /* Restart interrupted primitive
413 save
->prim
[0].mode
= mode
;
414 save
->prim
[0].weak
= weak
;
415 save
->prim
[0].begin
= 0;
416 save
->prim
[0].end
= 0;
417 save
->prim
[0].pad
= 0;
418 save
->prim
[0].start
= 0;
419 save
->prim
[0].count
= 0;
420 save
->prim_count
= 1;
425 /* Called only when buffers are wrapped as the result of filling the
426 * vertex_store struct.
428 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
430 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
431 GLfloat
*data
= save
->copied
.buffer
;
434 /* Emit a glEnd to close off the last vertex list.
436 _save_wrap_buffers( ctx
);
438 /* Copy stored stored vertices to start of new list.
440 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
442 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
443 _mesa_memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
444 data
+= save
->vertex_size
;
445 save
->buffer_ptr
+= save
->vertex_size
;
451 static void _save_copy_to_current( GLcontext
*ctx
)
453 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
456 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
457 if (save
->attrsz
[i
]) {
458 save
->currentsz
[i
][0] = save
->attrsz
[i
];
459 COPY_CLEAN_4V(save
->current
[i
],
467 static void _save_copy_from_current( GLcontext
*ctx
)
469 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
472 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
473 switch (save
->attrsz
[i
]) {
474 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
475 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
476 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
477 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
486 /* Flush existing data, set new attrib size, replay copied vertices.
488 static void _save_upgrade_vertex( GLcontext
*ctx
,
492 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
497 /* Store the current run of vertices, and emit a GL_END. Emit a
498 * BEGIN in the new buffer.
500 if (save
->vert_count
)
501 _save_wrap_buffers( ctx
);
503 assert( save
->copied
.nr
== 0 );
505 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
506 * when the attribute already exists in the vertex and is having
507 * its size increased.
509 _save_copy_to_current( ctx
);
513 oldsz
= save
->attrsz
[attr
];
514 save
->attrsz
[attr
] = newsz
;
516 save
->vertex_size
+= newsz
- oldsz
;
517 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
519 save
->vert_count
= 0;
521 /* Recalculate all the attrptr[] values:
523 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
524 if (save
->attrsz
[i
]) {
525 save
->attrptr
[i
] = tmp
;
526 tmp
+= save
->attrsz
[i
];
529 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
532 /* Copy from current to repopulate the vertex with correct values.
534 _save_copy_from_current( ctx
);
536 /* Replay stored vertices to translate them to new format here.
538 * If there are copied vertices and the new (upgraded) attribute
539 * has not been defined before, this list is somewhat degenerate,
540 * and will need fixup at runtime.
544 GLfloat
*data
= save
->copied
.buffer
;
545 GLfloat
*dest
= save
->buffer
;
548 /* Need to note this and fix up at runtime (or loopback):
550 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
552 save
->dangling_attr_ref
= GL_TRUE
;
555 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
556 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
557 if (save
->attrsz
[j
]) {
560 COPY_CLEAN_4V( dest
, oldsz
, data
);
565 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
570 GLint sz
= save
->attrsz
[j
];
571 COPY_SZ_4V( dest
, sz
, data
);
579 save
->buffer_ptr
= dest
;
580 save
->vert_count
+= save
->copied
.nr
;
584 static void save_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
586 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
588 if (sz
> save
->attrsz
[attr
]) {
589 /* New size is larger. Need to flush existing vertices and get
590 * an enlarged vertex format.
592 _save_upgrade_vertex( ctx
, attr
, sz
);
594 else if (sz
< save
->active_sz
[attr
]) {
595 static GLfloat id
[4] = { 0, 0, 0, 1 };
598 /* New size is equal or smaller - just need to fill in some
601 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
602 save
->attrptr
[attr
][i
-1] = id
[i
-1];
605 save
->active_sz
[attr
] = sz
;
608 static void _save_reset_vertex( GLcontext
*ctx
)
610 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
613 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
615 save
->active_sz
[i
] = 0;
618 save
->vertex_size
= 0;
623 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
626 /* Only one size for each attribute may be active at once. Eg. if
627 * Color3f is installed/active, then Color4f may not be, even if the
628 * vertex actually contains 4 color coordinates. This is because the
629 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
630 * of the chooser function when switching between Color4f and Color3f.
632 #define ATTR( A, N, V0, V1, V2, V3 ) \
634 struct vbo_save_context *save = &vbo_context(ctx)->save; \
636 if (save->active_sz[A] != N) \
637 save_fixup_vertex(ctx, A, N); \
640 GLfloat *dest = save->attrptr[A]; \
641 if (N>0) dest[0] = V0; \
642 if (N>1) dest[1] = V1; \
643 if (N>2) dest[2] = V2; \
644 if (N>3) dest[3] = V3; \
650 for (i = 0; i < save->vertex_size; i++) \
651 save->buffer_ptr[i] = save->vertex[i]; \
653 save->buffer_ptr += save->vertex_size; \
655 if (++save->vert_count >= save->max_vert) \
656 _save_wrap_filled_vertex( ctx ); \
660 #define TAG(x) _save_##x
662 #include "vbo_attrib_tmp.h"
667 /* Cope with EvalCoord/CallList called within a begin/end object:
668 * -- Flush current buffer
669 * -- Fallback to opcodes for the rest of the begin/end object.
671 static void DO_FALLBACK( GLcontext
*ctx
)
673 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
675 if (save
->vert_count
|| save
->prim_count
) {
676 GLint i
= save
->prim_count
- 1;
678 /* Close off in-progress primitive.
680 save
->prim
[i
].count
= (save
->vert_count
-
681 save
->prim
[i
].start
);
683 /* Need to replay this display list with loopback,
684 * unfortunately, otherwise this primitive won't be handled
687 save
->dangling_attr_ref
= 1;
689 _save_compile_vertex_list( ctx
);
692 _save_copy_to_current( ctx
);
693 _save_reset_vertex( ctx
);
694 _save_reset_counters( ctx
);
695 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
696 ctx
->Driver
.SaveNeedFlush
= 0;
699 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
701 GET_CURRENT_CONTEXT(ctx
);
703 ctx
->Save
->EvalCoord1f( u
);
706 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
708 GET_CURRENT_CONTEXT(ctx
);
710 ctx
->Save
->EvalCoord1fv( v
);
713 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
715 GET_CURRENT_CONTEXT(ctx
);
717 ctx
->Save
->EvalCoord2f( u
, v
);
720 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
722 GET_CURRENT_CONTEXT(ctx
);
724 ctx
->Save
->EvalCoord2fv( v
);
727 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
729 GET_CURRENT_CONTEXT(ctx
);
731 ctx
->Save
->EvalPoint1( i
);
734 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
736 GET_CURRENT_CONTEXT(ctx
);
738 ctx
->Save
->EvalPoint2( i
, j
);
741 static void GLAPIENTRY
_save_CallList( GLuint l
)
743 GET_CURRENT_CONTEXT(ctx
);
745 ctx
->Save
->CallList( l
);
748 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
750 GET_CURRENT_CONTEXT(ctx
);
752 ctx
->Save
->CallLists( n
, type
, v
);
758 /* This begin is hooked into ... Updating of
759 * ctx->Driver.CurrentSavePrimitive is already taken care of.
761 GLboolean
vbo_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
763 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
765 GLuint i
= save
->prim_count
++;
767 assert(i
< save
->prim_max
);
768 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
769 save
->prim
[i
].begin
= 1;
770 save
->prim
[i
].end
= 0;
771 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
772 save
->prim
[i
].pad
= 0;
773 save
->prim
[i
].start
= save
->vert_count
;
774 save
->prim
[i
].count
= 0;
776 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
777 ctx
->Driver
.SaveNeedFlush
= 1;
783 static void GLAPIENTRY
_save_End( void )
785 GET_CURRENT_CONTEXT( ctx
);
786 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
787 GLint i
= save
->prim_count
- 1;
789 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
790 save
->prim
[i
].end
= 1;
791 save
->prim
[i
].count
= (save
->vert_count
-
792 save
->prim
[i
].start
);
794 if (i
== (GLint
) save
->prim_max
- 1) {
795 _save_compile_vertex_list( ctx
);
796 assert(save
->copied
.nr
== 0);
799 /* Swap out this vertex format while outside begin/end. Any color,
800 * etc. received between here and the next begin will be compiled
803 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
807 /* These are all errors as this vtxfmt is only installed inside
810 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
811 const GLvoid
*indices
)
813 GET_CURRENT_CONTEXT(ctx
);
814 (void) mode
; (void) count
; (void) type
; (void) indices
;
815 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
819 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
820 GLuint start
, GLuint end
,
821 GLsizei count
, GLenum type
,
822 const GLvoid
*indices
)
824 GET_CURRENT_CONTEXT(ctx
);
825 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
826 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
829 static void GLAPIENTRY
_save_DrawElementsBaseVertex(GLenum mode
,
832 const GLvoid
*indices
,
835 GET_CURRENT_CONTEXT(ctx
);
836 (void) mode
; (void) count
; (void) type
; (void) indices
; (void)basevertex
;
838 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
841 static void GLAPIENTRY
_save_DrawRangeElementsBaseVertex(GLenum mode
,
846 const GLvoid
*indices
,
849 GET_CURRENT_CONTEXT(ctx
);
850 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
;
851 (void) indices
; (void)basevertex
;
853 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
856 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
858 GET_CURRENT_CONTEXT(ctx
);
859 (void) mode
; (void) start
; (void) count
;
860 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
863 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
865 GET_CURRENT_CONTEXT(ctx
);
866 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
867 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
870 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
872 GET_CURRENT_CONTEXT(ctx
);
873 (void) mode
; (void) i1
; (void) i2
;
874 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
877 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
880 GET_CURRENT_CONTEXT(ctx
);
881 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
882 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
885 static void GLAPIENTRY
_save_Begin( GLenum mode
)
887 GET_CURRENT_CONTEXT( ctx
);
889 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
893 /* Unlike the functions above, these are to be hooked into the vtxfmt
894 * maintained in ctx->ListState, active when the list is known or
895 * suspected to be outside any begin/end primitive.
897 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
899 GET_CURRENT_CONTEXT(ctx
);
900 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
901 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
902 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
903 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
904 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
905 CALL_End(GET_DISPATCH(), ());
909 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
911 GET_CURRENT_CONTEXT(ctx
);
914 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
919 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
921 for (i
= 0; i
< count
; i
++)
922 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
923 CALL_End(GET_DISPATCH(), ());
925 _ae_unmap_vbos( ctx
);
928 /* Could do better by copying the arrays and element list intact and
929 * then emitting an indexed prim at runtime.
931 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
932 const GLvoid
*indices
)
934 GET_CURRENT_CONTEXT(ctx
);
937 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
, 0 ))
942 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
943 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
945 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
948 case GL_UNSIGNED_BYTE
:
949 for (i
= 0 ; i
< count
; i
++)
950 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
952 case GL_UNSIGNED_SHORT
:
953 for (i
= 0 ; i
< count
; i
++)
954 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
956 case GL_UNSIGNED_INT
:
957 for (i
= 0 ; i
< count
; i
++)
958 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
961 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
965 CALL_End(GET_DISPATCH(), ());
967 _ae_unmap_vbos( ctx
);
970 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
971 GLuint start
, GLuint end
,
972 GLsizei count
, GLenum type
,
973 const GLvoid
*indices
)
975 GET_CURRENT_CONTEXT(ctx
);
976 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
978 count
, type
, indices
, 0 ))
979 _save_OBE_DrawElements( mode
, count
, type
, indices
);
986 static void _save_vtxfmt_init( GLcontext
*ctx
)
988 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
989 GLvertexformat
*vfmt
= &save
->vtxfmt
;
991 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
992 vfmt
->Begin
= _save_Begin
;
993 vfmt
->Color3f
= _save_Color3f
;
994 vfmt
->Color3fv
= _save_Color3fv
;
995 vfmt
->Color4f
= _save_Color4f
;
996 vfmt
->Color4fv
= _save_Color4fv
;
997 vfmt
->EdgeFlag
= _save_EdgeFlag
;
998 vfmt
->End
= _save_End
;
999 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1000 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1001 vfmt
->Indexf
= _save_Indexf
;
1002 vfmt
->Indexfv
= _save_Indexfv
;
1003 vfmt
->Materialfv
= _save_Materialfv
;
1004 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1005 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1006 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1007 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1008 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1009 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1010 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1011 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1012 vfmt
->Normal3f
= _save_Normal3f
;
1013 vfmt
->Normal3fv
= _save_Normal3fv
;
1014 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1015 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1016 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1017 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1018 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1019 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1020 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1021 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1022 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1023 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1024 vfmt
->Vertex2f
= _save_Vertex2f
;
1025 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1026 vfmt
->Vertex3f
= _save_Vertex3f
;
1027 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1028 vfmt
->Vertex4f
= _save_Vertex4f
;
1029 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1030 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1031 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1032 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1033 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1034 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1035 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1036 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1037 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1039 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1040 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1041 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1042 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1043 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1044 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1045 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1046 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1048 /* This will all require us to fallback to saving the list as opcodes:
1050 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1051 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1052 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1053 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1054 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1055 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1056 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1057 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1059 /* These are all errors as we at least know we are in some sort of
1062 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1063 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1064 vfmt
->Begin
= _save_Begin
;
1065 vfmt
->Rectf
= _save_Rectf
;
1066 vfmt
->DrawArrays
= _save_DrawArrays
;
1067 vfmt
->DrawElements
= _save_DrawElements
;
1068 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1069 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1070 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1071 /* Loops back into vfmt->DrawElements */
1072 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1073 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1077 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
1079 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1081 /* Noop when we are actually active:
1083 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1084 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1087 if (save
->vert_count
||
1089 _save_compile_vertex_list( ctx
);
1091 _save_copy_to_current( ctx
);
1092 _save_reset_vertex( ctx
);
1093 _save_reset_counters( ctx
);
1094 ctx
->Driver
.SaveNeedFlush
= 0;
1097 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1099 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1101 (void) list
; (void) mode
;
1103 if (!save
->prim_store
)
1104 save
->prim_store
= alloc_prim_store( ctx
);
1106 if (!save
->vertex_store
)
1107 save
->vertex_store
= alloc_vertex_store( ctx
);
1109 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1111 _save_reset_vertex( ctx
);
1112 _save_reset_counters( ctx
);
1113 ctx
->Driver
.SaveNeedFlush
= 0;
1116 void vbo_save_EndList( GLcontext
*ctx
)
1118 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1120 /* EndList called inside a (saved) Begin/End pair?
1122 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1124 if (save
->prim_count
> 0) {
1125 GLint i
= save
->prim_count
- 1;
1126 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1127 save
->prim
[i
].end
= 0;
1128 save
->prim
[i
].count
= (save
->vert_count
-
1129 save
->prim
[i
].start
);
1132 /* Make sure this vertex list gets replayed by the "loopback"
1135 save
->dangling_attr_ref
= 1;
1136 vbo_save_SaveFlushVertices( ctx
);
1138 /* Swap out this vertex format while outside begin/end. Any color,
1139 * etc. received between here and the next begin will be compiled
1142 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1145 unmap_vertex_store( ctx
, save
->vertex_store
);
1147 assert(save
->vertex_size
== 0);
1150 void vbo_save_BeginCallList( GLcontext
*ctx
, struct gl_display_list
*dlist
)
1152 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1153 save
->replay_flags
|= dlist
->Flags
;
1156 void vbo_save_EndCallList( GLcontext
*ctx
)
1158 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1160 if (ctx
->ListState
.CallDepth
== 1) {
1161 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1162 * flag, if it is set:
1164 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1169 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1171 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1174 if ( --node
->vertex_store
->refcount
== 0 )
1175 free_vertex_store( ctx
, node
->vertex_store
);
1177 if ( --node
->prim_store
->refcount
== 0 )
1178 FREE( node
->prim_store
);
1180 if (node
->current_data
) {
1181 FREE(node
->current_data
);
1182 node
->current_data
= NULL
;
1187 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1189 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1193 _mesa_printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1198 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1199 struct _mesa_prim
*prim
= &node
->prim
[i
];
1200 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1202 _mesa_lookup_prim_by_nr(prim
->mode
),
1203 prim
->weak
? " (weak)" : "",
1205 prim
->start
+ prim
->count
,
1206 (prim
->begin
) ? "BEGIN" : "(wrap)",
1207 (prim
->end
) ? "END" : "(wrap)");
1212 static void _save_current_init( GLcontext
*ctx
)
1214 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1217 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1218 const GLuint j
= i
- VBO_ATTRIB_POS
;
1219 ASSERT(j
< VERT_ATTRIB_MAX
);
1220 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1221 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1224 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1225 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1226 ASSERT(j
< MAT_ATTRIB_MAX
);
1227 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1228 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1233 * Initialize the display list compiler
1235 void vbo_save_api_init( struct vbo_save_context
*save
)
1237 GLcontext
*ctx
= save
->ctx
;
1240 save
->opcode_vertex_list
=
1241 _mesa_alloc_opcode( ctx
,
1242 sizeof(struct vbo_save_vertex_list
),
1243 vbo_save_playback_vertex_list
,
1244 vbo_destroy_vertex_list
,
1245 vbo_print_vertex_list
);
1247 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1249 _save_vtxfmt_init( ctx
);
1250 _save_current_init( ctx
);
1252 /* These will actually get set again when binding/drawing */
1253 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1254 save
->inputs
[i
] = &save
->arrays
[i
];
1256 /* Hook our array functions into the outside-begin-end vtxfmt in
1259 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1260 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1261 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1262 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1263 /* loops back into _save_OBE_DrawElements */
1264 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1265 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1266 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);