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/eval.h"
76 #include "main/macros.h"
77 #include "main/api_noop.h"
78 #include "main/api_validate.h"
79 #include "main/api_arrayelt.h"
80 #include "main/vtxfmt.h"
81 #include "main/dispatch.h"
83 #include "vbo_context.h"
94 /* An interesting VBO number/name to help with debugging */
95 #define VBO_BUF_ID 12345
99 * NOTE: Old 'parity' issue is gone, but copying can still be
100 * wrong-footed on replay.
102 static GLuint
_save_copy_vertices( struct gl_context
*ctx
,
103 const struct vbo_save_vertex_list
*node
,
104 const GLfloat
*src_buffer
)
106 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
107 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
108 GLuint nr
= prim
->count
;
109 GLuint sz
= save
->vertex_size
;
110 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
111 GLfloat
*dst
= save
->copied
.buffer
;
123 for (i
= 0 ; i
< ovf
; i
++)
124 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
128 for (i
= 0 ; i
< ovf
; i
++)
129 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
133 for (i
= 0 ; i
< ovf
; i
++)
134 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
140 memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
144 case GL_TRIANGLE_FAN
:
149 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
152 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
153 memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
156 case GL_TRIANGLE_STRIP
:
159 case 0: ovf
= 0; break;
160 case 1: ovf
= 1; break;
161 default: ovf
= 2 + (nr
&1); break;
163 for (i
= 0 ; i
< ovf
; i
++)
164 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
173 static struct vbo_save_vertex_store
*alloc_vertex_store( struct gl_context
*ctx
)
175 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
177 /* obj->Name needs to be non-zero, but won't ever be examined more
178 * closely than that. In particular these buffers won't be entered
179 * into the hash and can never be confused with ones visible to the
180 * user. Perhaps there could be a special number for internal
183 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
185 GL_ARRAY_BUFFER_ARB
);
187 ctx
->Driver
.BufferData( ctx
,
189 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
192 vertex_store
->bufferobj
);
194 vertex_store
->buffer
= NULL
;
195 vertex_store
->used
= 0;
196 vertex_store
->refcount
= 1;
201 static void free_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
203 assert(!vertex_store
->buffer
);
205 if (vertex_store
->bufferobj
) {
206 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
209 FREE( vertex_store
);
212 static GLfloat
*map_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
214 assert(vertex_store
->bufferobj
);
215 assert(!vertex_store
->buffer
);
216 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
217 GL_ARRAY_BUFFER_ARB
, /* not used */
218 GL_WRITE_ONLY
, /* not used */
219 vertex_store
->bufferobj
);
221 assert(vertex_store
->buffer
);
222 return vertex_store
->buffer
+ vertex_store
->used
;
225 static void unmap_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
227 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
228 vertex_store
->buffer
= NULL
;
232 static struct vbo_save_primitive_store
*alloc_prim_store( struct gl_context
*ctx
)
234 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
241 static void _save_reset_counters( struct gl_context
*ctx
)
243 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
245 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
246 save
->buffer
= (save
->vertex_store
->buffer
+
247 save
->vertex_store
->used
);
249 assert(save
->buffer
== save
->buffer_ptr
);
251 if (save
->vertex_size
)
252 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
257 save
->vert_count
= 0;
258 save
->prim_count
= 0;
259 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
260 save
->dangling_attr_ref
= 0;
264 /* Insert the active immediate struct onto the display list currently
267 static void _save_compile_vertex_list( struct gl_context
*ctx
)
269 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
270 struct vbo_save_vertex_list
*node
;
272 /* Allocate space for this structure in the display list currently
275 node
= (struct vbo_save_vertex_list
*)
276 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
281 /* Duplicate our template, increment refcounts to the storage structs:
283 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
284 node
->vertex_size
= save
->vertex_size
;
285 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
286 node
->count
= save
->vert_count
;
287 node
->wrap_count
= save
->copied
.nr
;
288 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
289 node
->prim
= save
->prim
;
290 node
->prim_count
= save
->prim_count
;
291 node
->vertex_store
= save
->vertex_store
;
292 node
->prim_store
= save
->prim_store
;
294 node
->vertex_store
->refcount
++;
295 node
->prim_store
->refcount
++;
298 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
299 node
->current_data
= NULL
;
301 if (node
->current_size
) {
302 /* If the malloc fails, we just pull the data out of the VBO
305 node
->current_data
= MALLOC( node
->current_size
* sizeof(GLfloat
) );
306 if (node
->current_data
) {
307 const char *buffer
= (const char *)save
->vertex_store
->buffer
;
308 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
309 unsigned vertex_offset
= 0;
312 vertex_offset
= (node
->count
-1) * node
->vertex_size
* sizeof(GLfloat
);
314 memcpy( node
->current_data
,
315 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
316 node
->current_size
* sizeof(GLfloat
) );
322 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
325 if (save
->dangling_attr_ref
)
326 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
328 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
329 save
->prim_store
->used
+= node
->prim_count
;
332 /* Copy duplicated vertices
334 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
337 /* Deal with GL_COMPILE_AND_EXECUTE:
339 if (ctx
->ExecuteFlag
) {
340 struct _glapi_table
*dispatch
= GET_DISPATCH();
342 _glapi_set_dispatch(ctx
->Exec
);
344 vbo_loopback_vertex_list( ctx
,
345 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
346 node
->buffer_offset
),
353 _glapi_set_dispatch(dispatch
);
357 /* Decide whether the storage structs are full, or can be used for
358 * the next vertex lists as well.
360 if (save
->vertex_store
->used
>
361 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
365 unmap_vertex_store( ctx
, save
->vertex_store
);
367 /* Release old reference:
369 save
->vertex_store
->refcount
--;
370 assert(save
->vertex_store
->refcount
!= 0);
371 save
->vertex_store
= NULL
;
373 /* Allocate and map new store:
375 save
->vertex_store
= alloc_vertex_store( ctx
);
376 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
379 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
380 save
->prim_store
->refcount
--;
381 assert(save
->prim_store
->refcount
!= 0);
382 save
->prim_store
= alloc_prim_store( ctx
);
385 /* Reset our structures for the next run of vertices:
387 _save_reset_counters( ctx
);
391 /* TODO -- If no new vertices have been stored, don't bother saving
394 static void _save_wrap_buffers( struct gl_context
*ctx
)
396 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
397 GLint i
= save
->prim_count
- 1;
401 assert(i
< (GLint
) save
->prim_max
);
404 /* Close off in-progress primitive.
406 save
->prim
[i
].count
= (save
->vert_count
-
407 save
->prim
[i
].start
);
408 mode
= save
->prim
[i
].mode
;
409 weak
= save
->prim
[i
].weak
;
411 /* store the copied vertices, and allocate a new list.
413 _save_compile_vertex_list( ctx
);
415 /* Restart interrupted primitive
417 save
->prim
[0].mode
= mode
;
418 save
->prim
[0].weak
= weak
;
419 save
->prim
[0].begin
= 0;
420 save
->prim
[0].end
= 0;
421 save
->prim
[0].pad
= 0;
422 save
->prim
[0].start
= 0;
423 save
->prim
[0].count
= 0;
424 save
->prim
[0].num_instances
= 1;
425 save
->prim_count
= 1;
430 /* Called only when buffers are wrapped as the result of filling the
431 * vertex_store struct.
433 static void _save_wrap_filled_vertex( struct gl_context
*ctx
)
435 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
436 GLfloat
*data
= save
->copied
.buffer
;
439 /* Emit a glEnd to close off the last vertex list.
441 _save_wrap_buffers( ctx
);
443 /* Copy stored stored vertices to start of new list.
445 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
447 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
448 memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
449 data
+= save
->vertex_size
;
450 save
->buffer_ptr
+= save
->vertex_size
;
456 static void _save_copy_to_current( struct gl_context
*ctx
)
458 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
461 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
462 if (save
->attrsz
[i
]) {
463 save
->currentsz
[i
][0] = save
->attrsz
[i
];
464 COPY_CLEAN_4V(save
->current
[i
],
472 static void _save_copy_from_current( struct gl_context
*ctx
)
474 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
477 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
478 switch (save
->attrsz
[i
]) {
479 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
480 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
481 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
482 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
491 /* Flush existing data, set new attrib size, replay copied vertices.
493 static void _save_upgrade_vertex( struct gl_context
*ctx
,
497 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
502 /* Store the current run of vertices, and emit a GL_END. Emit a
503 * BEGIN in the new buffer.
505 if (save
->vert_count
)
506 _save_wrap_buffers( ctx
);
508 assert( save
->copied
.nr
== 0 );
510 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
511 * when the attribute already exists in the vertex and is having
512 * its size increased.
514 _save_copy_to_current( ctx
);
518 oldsz
= save
->attrsz
[attr
];
519 save
->attrsz
[attr
] = newsz
;
521 save
->vertex_size
+= newsz
- oldsz
;
522 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
524 save
->vert_count
= 0;
526 /* Recalculate all the attrptr[] values:
528 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
529 if (save
->attrsz
[i
]) {
530 save
->attrptr
[i
] = tmp
;
531 tmp
+= save
->attrsz
[i
];
534 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
537 /* Copy from current to repopulate the vertex with correct values.
539 _save_copy_from_current( ctx
);
541 /* Replay stored vertices to translate them to new format here.
543 * If there are copied vertices and the new (upgraded) attribute
544 * has not been defined before, this list is somewhat degenerate,
545 * and will need fixup at runtime.
549 GLfloat
*data
= save
->copied
.buffer
;
550 GLfloat
*dest
= save
->buffer
;
553 /* Need to note this and fix up at runtime (or loopback):
555 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
557 save
->dangling_attr_ref
= GL_TRUE
;
560 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
561 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
562 if (save
->attrsz
[j
]) {
565 COPY_CLEAN_4V( dest
, oldsz
, data
);
570 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
575 GLint sz
= save
->attrsz
[j
];
576 COPY_SZ_4V( dest
, sz
, data
);
584 save
->buffer_ptr
= dest
;
585 save
->vert_count
+= save
->copied
.nr
;
589 static void save_fixup_vertex( struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
591 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
593 if (sz
> save
->attrsz
[attr
]) {
594 /* New size is larger. Need to flush existing vertices and get
595 * an enlarged vertex format.
597 _save_upgrade_vertex( ctx
, attr
, sz
);
599 else if (sz
< save
->active_sz
[attr
]) {
600 static GLfloat id
[4] = { 0, 0, 0, 1 };
603 /* New size is equal or smaller - just need to fill in some
606 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
607 save
->attrptr
[attr
][i
-1] = id
[i
-1];
610 save
->active_sz
[attr
] = sz
;
613 static void _save_reset_vertex( struct gl_context
*ctx
)
615 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
618 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
620 save
->active_sz
[i
] = 0;
623 save
->vertex_size
= 0;
628 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
631 /* Only one size for each attribute may be active at once. Eg. if
632 * Color3f is installed/active, then Color4f may not be, even if the
633 * vertex actually contains 4 color coordinates. This is because the
634 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
635 * of the chooser function when switching between Color4f and Color3f.
637 #define ATTR( A, N, V0, V1, V2, V3 ) \
639 struct vbo_save_context *save = &vbo_context(ctx)->save; \
641 if (save->active_sz[A] != N) \
642 save_fixup_vertex(ctx, A, N); \
645 GLfloat *dest = save->attrptr[A]; \
646 if (N>0) dest[0] = V0; \
647 if (N>1) dest[1] = V1; \
648 if (N>2) dest[2] = V2; \
649 if (N>3) dest[3] = V3; \
655 for (i = 0; i < save->vertex_size; i++) \
656 save->buffer_ptr[i] = save->vertex[i]; \
658 save->buffer_ptr += save->vertex_size; \
660 if (++save->vert_count >= save->max_vert) \
661 _save_wrap_filled_vertex( ctx ); \
665 #define TAG(x) _save_##x
667 #include "vbo_attrib_tmp.h"
672 /* Cope with EvalCoord/CallList called within a begin/end object:
673 * -- Flush current buffer
674 * -- Fallback to opcodes for the rest of the begin/end object.
676 static void DO_FALLBACK( struct gl_context
*ctx
)
678 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
680 if (save
->vert_count
|| save
->prim_count
) {
681 GLint i
= save
->prim_count
- 1;
683 /* Close off in-progress primitive.
685 save
->prim
[i
].count
= (save
->vert_count
-
686 save
->prim
[i
].start
);
688 /* Need to replay this display list with loopback,
689 * unfortunately, otherwise this primitive won't be handled
692 save
->dangling_attr_ref
= 1;
694 _save_compile_vertex_list( ctx
);
697 _save_copy_to_current( ctx
);
698 _save_reset_vertex( ctx
);
699 _save_reset_counters( ctx
);
700 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
701 ctx
->Driver
.SaveNeedFlush
= 0;
704 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
706 GET_CURRENT_CONTEXT(ctx
);
708 CALL_EvalCoord1f(ctx
->Save
, (u
));
711 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
713 GET_CURRENT_CONTEXT(ctx
);
715 CALL_EvalCoord1fv(ctx
->Save
, (v
));
718 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
720 GET_CURRENT_CONTEXT(ctx
);
722 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
725 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
727 GET_CURRENT_CONTEXT(ctx
);
729 CALL_EvalCoord2fv(ctx
->Save
, (v
));
732 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
734 GET_CURRENT_CONTEXT(ctx
);
736 CALL_EvalPoint1(ctx
->Save
, (i
));
739 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
741 GET_CURRENT_CONTEXT(ctx
);
743 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
746 static void GLAPIENTRY
_save_CallList( GLuint l
)
748 GET_CURRENT_CONTEXT(ctx
);
750 CALL_CallList(ctx
->Save
, (l
));
753 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
755 GET_CURRENT_CONTEXT(ctx
);
757 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
763 /* This begin is hooked into ... Updating of
764 * ctx->Driver.CurrentSavePrimitive is already taken care of.
766 GLboolean
vbo_save_NotifyBegin( struct gl_context
*ctx
, GLenum mode
)
768 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
770 GLuint i
= save
->prim_count
++;
772 assert(i
< save
->prim_max
);
773 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
774 save
->prim
[i
].begin
= 1;
775 save
->prim
[i
].end
= 0;
776 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
777 save
->prim
[i
].pad
= 0;
778 save
->prim
[i
].start
= save
->vert_count
;
779 save
->prim
[i
].count
= 0;
780 save
->prim
[i
].num_instances
= 1;
782 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
783 ctx
->Driver
.SaveNeedFlush
= 1;
789 static void GLAPIENTRY
_save_End( void )
791 GET_CURRENT_CONTEXT( ctx
);
792 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
793 GLint i
= save
->prim_count
- 1;
795 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
796 save
->prim
[i
].end
= 1;
797 save
->prim
[i
].count
= (save
->vert_count
-
798 save
->prim
[i
].start
);
800 if (i
== (GLint
) save
->prim_max
- 1) {
801 _save_compile_vertex_list( ctx
);
802 assert(save
->copied
.nr
== 0);
805 /* Swap out this vertex format while outside begin/end. Any color,
806 * etc. received between here and the next begin will be compiled
809 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
813 /* These are all errors as this vtxfmt is only installed inside
816 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
817 const GLvoid
*indices
)
819 GET_CURRENT_CONTEXT(ctx
);
820 (void) mode
; (void) count
; (void) type
; (void) indices
;
821 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
825 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
826 GLuint start
, GLuint end
,
827 GLsizei count
, GLenum type
,
828 const GLvoid
*indices
)
830 GET_CURRENT_CONTEXT(ctx
);
831 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
832 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
835 static void GLAPIENTRY
_save_DrawElementsBaseVertex(GLenum mode
,
838 const GLvoid
*indices
,
841 GET_CURRENT_CONTEXT(ctx
);
842 (void) mode
; (void) count
; (void) type
; (void) indices
; (void)basevertex
;
844 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
847 static void GLAPIENTRY
_save_DrawRangeElementsBaseVertex(GLenum mode
,
852 const GLvoid
*indices
,
855 GET_CURRENT_CONTEXT(ctx
);
856 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
;
857 (void) indices
; (void)basevertex
;
859 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
862 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
864 GET_CURRENT_CONTEXT(ctx
);
865 (void) mode
; (void) start
; (void) count
;
866 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
869 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
871 GET_CURRENT_CONTEXT(ctx
);
872 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
873 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
876 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
878 GET_CURRENT_CONTEXT(ctx
);
879 (void) mode
; (void) i1
; (void) i2
;
880 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
883 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
886 GET_CURRENT_CONTEXT(ctx
);
887 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
888 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
891 static void GLAPIENTRY
_save_Begin( GLenum mode
)
893 GET_CURRENT_CONTEXT( ctx
);
895 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
899 static void GLAPIENTRY
_save_PrimitiveRestartNV( void )
902 GET_CURRENT_CONTEXT( ctx
);
904 curPrim
= ctx
->Driver
.CurrentSavePrimitive
;
907 _save_Begin(curPrim
);
911 /* Unlike the functions above, these are to be hooked into the vtxfmt
912 * maintained in ctx->ListState, active when the list is known or
913 * suspected to be outside any begin/end primitive.
915 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
917 GET_CURRENT_CONTEXT(ctx
);
918 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
919 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
920 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
921 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
922 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
923 CALL_End(GET_DISPATCH(), ());
927 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
929 GET_CURRENT_CONTEXT(ctx
);
932 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
937 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
939 for (i
= 0; i
< count
; i
++)
940 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
941 CALL_End(GET_DISPATCH(), ());
943 _ae_unmap_vbos( ctx
);
946 /* Could do better by copying the arrays and element list intact and
947 * then emitting an indexed prim at runtime.
949 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
950 const GLvoid
*indices
)
952 GET_CURRENT_CONTEXT(ctx
);
955 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
, 0 ))
960 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
961 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
963 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
966 case GL_UNSIGNED_BYTE
:
967 for (i
= 0 ; i
< count
; i
++)
968 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
970 case GL_UNSIGNED_SHORT
:
971 for (i
= 0 ; i
< count
; i
++)
972 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
974 case GL_UNSIGNED_INT
:
975 for (i
= 0 ; i
< count
; i
++)
976 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
979 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
983 CALL_End(GET_DISPATCH(), ());
985 _ae_unmap_vbos( ctx
);
988 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
989 GLuint start
, GLuint end
,
990 GLsizei count
, GLenum type
,
991 const GLvoid
*indices
)
993 GET_CURRENT_CONTEXT(ctx
);
994 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
996 count
, type
, indices
, 0 ))
997 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1004 static void _save_vtxfmt_init( struct gl_context
*ctx
)
1006 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1007 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1009 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
1011 vfmt
->Begin
= _save_Begin
;
1012 vfmt
->Color3f
= _save_Color3f
;
1013 vfmt
->Color3fv
= _save_Color3fv
;
1014 vfmt
->Color4f
= _save_Color4f
;
1015 vfmt
->Color4fv
= _save_Color4fv
;
1016 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1017 vfmt
->End
= _save_End
;
1018 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1019 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1020 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1021 vfmt
->Indexf
= _save_Indexf
;
1022 vfmt
->Indexfv
= _save_Indexfv
;
1023 vfmt
->Materialfv
= _save_Materialfv
;
1024 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1025 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1026 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1027 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1028 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1029 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1030 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1031 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1032 vfmt
->Normal3f
= _save_Normal3f
;
1033 vfmt
->Normal3fv
= _save_Normal3fv
;
1034 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1035 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1036 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1037 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1038 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1039 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1040 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1041 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1042 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1043 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1044 vfmt
->Vertex2f
= _save_Vertex2f
;
1045 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1046 vfmt
->Vertex3f
= _save_Vertex3f
;
1047 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1048 vfmt
->Vertex4f
= _save_Vertex4f
;
1049 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1050 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1051 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1052 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1053 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1054 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1055 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1056 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1057 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1059 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1060 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1061 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1062 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1063 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1064 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1065 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1066 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1068 /* integer-valued */
1069 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1070 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1071 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1072 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1073 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1074 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1075 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1077 /* unsigned integer-valued */
1078 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1079 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1080 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1081 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1082 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1083 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1084 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1086 /* This will all require us to fallback to saving the list as opcodes:
1088 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1090 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1092 /* These are all errors as we at least know we are in some sort of
1095 vfmt
->Begin
= _save_Begin
;
1096 vfmt
->Rectf
= _save_Rectf
;
1097 vfmt
->DrawArrays
= _save_DrawArrays
;
1098 vfmt
->DrawElements
= _save_DrawElements
;
1099 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1100 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1101 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1102 /* Loops back into vfmt->DrawElements */
1103 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1104 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1108 void vbo_save_SaveFlushVertices( struct gl_context
*ctx
)
1110 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1112 /* Noop when we are actually active:
1114 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1115 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1118 if (save
->vert_count
||
1120 _save_compile_vertex_list( ctx
);
1122 _save_copy_to_current( ctx
);
1123 _save_reset_vertex( ctx
);
1124 _save_reset_counters( ctx
);
1125 ctx
->Driver
.SaveNeedFlush
= 0;
1128 void vbo_save_NewList( struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1130 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1132 (void) list
; (void) mode
;
1134 if (!save
->prim_store
)
1135 save
->prim_store
= alloc_prim_store( ctx
);
1137 if (!save
->vertex_store
)
1138 save
->vertex_store
= alloc_vertex_store( ctx
);
1140 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1142 _save_reset_vertex( ctx
);
1143 _save_reset_counters( ctx
);
1144 ctx
->Driver
.SaveNeedFlush
= 0;
1147 void vbo_save_EndList( struct gl_context
*ctx
)
1149 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1151 /* EndList called inside a (saved) Begin/End pair?
1153 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1155 if (save
->prim_count
> 0) {
1156 GLint i
= save
->prim_count
- 1;
1157 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1158 save
->prim
[i
].end
= 0;
1159 save
->prim
[i
].count
= (save
->vert_count
-
1160 save
->prim
[i
].start
);
1163 /* Make sure this vertex list gets replayed by the "loopback"
1166 save
->dangling_attr_ref
= 1;
1167 vbo_save_SaveFlushVertices( ctx
);
1169 /* Swap out this vertex format while outside begin/end. Any color,
1170 * etc. received between here and the next begin will be compiled
1173 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1176 unmap_vertex_store( ctx
, save
->vertex_store
);
1178 assert(save
->vertex_size
== 0);
1181 void vbo_save_BeginCallList( struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1183 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1184 save
->replay_flags
|= dlist
->Flags
;
1187 void vbo_save_EndCallList( struct gl_context
*ctx
)
1189 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1191 if (ctx
->ListState
.CallDepth
== 1) {
1192 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1193 * flag, if it is set:
1195 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1200 static void vbo_destroy_vertex_list( struct gl_context
*ctx
, void *data
)
1202 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1205 if ( --node
->vertex_store
->refcount
== 0 )
1206 free_vertex_store( ctx
, node
->vertex_store
);
1208 if ( --node
->prim_store
->refcount
== 0 )
1209 FREE( node
->prim_store
);
1211 if (node
->current_data
) {
1212 FREE(node
->current_data
);
1213 node
->current_data
= NULL
;
1218 static void vbo_print_vertex_list( struct gl_context
*ctx
, void *data
)
1220 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1224 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1229 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1230 struct _mesa_prim
*prim
= &node
->prim
[i
];
1231 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1233 _mesa_lookup_prim_by_nr(prim
->mode
),
1234 prim
->weak
? " (weak)" : "",
1236 prim
->start
+ prim
->count
,
1237 (prim
->begin
) ? "BEGIN" : "(wrap)",
1238 (prim
->end
) ? "END" : "(wrap)");
1243 static void _save_current_init( struct gl_context
*ctx
)
1245 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1248 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1249 const GLuint j
= i
- VBO_ATTRIB_POS
;
1250 ASSERT(j
< VERT_ATTRIB_MAX
);
1251 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1252 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1255 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1256 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1257 ASSERT(j
< MAT_ATTRIB_MAX
);
1258 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1259 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1264 * Initialize the display list compiler
1266 void vbo_save_api_init( struct vbo_save_context
*save
)
1268 struct gl_context
*ctx
= save
->ctx
;
1271 save
->opcode_vertex_list
=
1272 _mesa_dlist_alloc_opcode( ctx
,
1273 sizeof(struct vbo_save_vertex_list
),
1274 vbo_save_playback_vertex_list
,
1275 vbo_destroy_vertex_list
,
1276 vbo_print_vertex_list
);
1278 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1280 _save_vtxfmt_init( ctx
);
1281 _save_current_init( ctx
);
1283 /* These will actually get set again when binding/drawing */
1284 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1285 save
->inputs
[i
] = &save
->arrays
[i
];
1287 /* Hook our array functions into the outside-begin-end vtxfmt in
1290 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1291 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1292 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1293 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1294 /* loops back into _save_OBE_DrawElements */
1295 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1296 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1297 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1301 #endif /* FEATURE_dlist */