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"
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID 12345
96 * NOTE: Old 'parity' issue is gone, but copying can still be
97 * wrong-footed on replay.
99 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
100 const struct vbo_save_vertex_list
*node
,
101 const GLfloat
*src_buffer
)
103 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
104 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
105 GLuint nr
= prim
->count
;
106 GLuint sz
= save
->vertex_size
;
107 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
108 GLfloat
*dst
= save
->copied
.buffer
;
120 for (i
= 0 ; i
< ovf
; i
++)
121 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
125 for (i
= 0 ; i
< ovf
; i
++)
126 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
130 for (i
= 0 ; i
< ovf
; i
++)
131 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
137 memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
141 case GL_TRIANGLE_FAN
:
146 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
149 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
150 memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
153 case GL_TRIANGLE_STRIP
:
156 case 0: ovf
= 0; break;
157 case 1: ovf
= 1; break;
158 default: ovf
= 2 + (nr
&1); break;
160 for (i
= 0 ; i
< ovf
; i
++)
161 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
170 static struct vbo_save_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
172 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
174 /* obj->Name needs to be non-zero, but won't ever be examined more
175 * closely than that. In particular these buffers won't be entered
176 * into the hash and can never be confused with ones visible to the
177 * user. Perhaps there could be a special number for internal
180 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
182 GL_ARRAY_BUFFER_ARB
);
184 ctx
->Driver
.BufferData( ctx
,
186 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
189 vertex_store
->bufferobj
);
191 vertex_store
->buffer
= NULL
;
192 vertex_store
->used
= 0;
193 vertex_store
->refcount
= 1;
198 static void free_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
200 assert(!vertex_store
->buffer
);
202 if (vertex_store
->bufferobj
) {
203 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
206 FREE( vertex_store
);
209 static GLfloat
*map_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
211 assert(vertex_store
->bufferobj
);
212 assert(!vertex_store
->buffer
);
213 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
214 GL_ARRAY_BUFFER_ARB
, /* not used */
215 GL_WRITE_ONLY
, /* not used */
216 vertex_store
->bufferobj
);
218 assert(vertex_store
->buffer
);
219 return vertex_store
->buffer
+ vertex_store
->used
;
222 static void unmap_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
224 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
225 vertex_store
->buffer
= NULL
;
229 static struct vbo_save_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
231 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
238 static void _save_reset_counters( GLcontext
*ctx
)
240 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
242 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
243 save
->buffer
= (save
->vertex_store
->buffer
+
244 save
->vertex_store
->used
);
246 assert(save
->buffer
== save
->buffer_ptr
);
248 if (save
->vertex_size
)
249 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
254 save
->vert_count
= 0;
255 save
->prim_count
= 0;
256 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
257 save
->dangling_attr_ref
= 0;
261 /* Insert the active immediate struct onto the display list currently
264 static void _save_compile_vertex_list( GLcontext
*ctx
)
266 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
267 struct vbo_save_vertex_list
*node
;
269 /* Allocate space for this structure in the display list currently
272 node
= (struct vbo_save_vertex_list
*)
273 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
278 /* Duplicate our template, increment refcounts to the storage structs:
280 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
281 node
->vertex_size
= save
->vertex_size
;
282 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
283 node
->count
= save
->vert_count
;
284 node
->wrap_count
= save
->copied
.nr
;
285 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
286 node
->prim
= save
->prim
;
287 node
->prim_count
= save
->prim_count
;
288 node
->vertex_store
= save
->vertex_store
;
289 node
->prim_store
= save
->prim_store
;
291 node
->vertex_store
->refcount
++;
292 node
->prim_store
->refcount
++;
295 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
296 node
->current_data
= NULL
;
298 if (node
->current_size
) {
299 /* If the malloc fails, we just pull the data out of the VBO
302 node
->current_data
= MALLOC( node
->current_size
* sizeof(GLfloat
) );
303 if (node
->current_data
) {
304 const char *buffer
= (const char *)save
->vertex_store
->buffer
;
305 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
306 unsigned vertex_offset
= 0;
309 vertex_offset
= (node
->count
-1) * node
->vertex_size
* sizeof(GLfloat
);
311 memcpy( node
->current_data
,
312 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
313 node
->current_size
* sizeof(GLfloat
) );
319 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
322 if (save
->dangling_attr_ref
)
323 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
325 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
326 save
->prim_store
->used
+= node
->prim_count
;
329 /* Copy duplicated vertices
331 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
334 /* Deal with GL_COMPILE_AND_EXECUTE:
336 if (ctx
->ExecuteFlag
) {
337 struct _glapi_table
*dispatch
= GET_DISPATCH();
339 _glapi_set_dispatch(ctx
->Exec
);
341 vbo_loopback_vertex_list( ctx
,
342 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
343 node
->buffer_offset
),
350 _glapi_set_dispatch(dispatch
);
354 /* Decide whether the storage structs are full, or can be used for
355 * the next vertex lists as well.
357 if (save
->vertex_store
->used
>
358 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
362 unmap_vertex_store( ctx
, save
->vertex_store
);
364 /* Release old reference:
366 save
->vertex_store
->refcount
--;
367 assert(save
->vertex_store
->refcount
!= 0);
368 save
->vertex_store
= NULL
;
370 /* Allocate and map new store:
372 save
->vertex_store
= alloc_vertex_store( ctx
);
373 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
376 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
377 save
->prim_store
->refcount
--;
378 assert(save
->prim_store
->refcount
!= 0);
379 save
->prim_store
= alloc_prim_store( ctx
);
382 /* Reset our structures for the next run of vertices:
384 _save_reset_counters( ctx
);
388 /* TODO -- If no new vertices have been stored, don't bother saving
391 static void _save_wrap_buffers( GLcontext
*ctx
)
393 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
394 GLint i
= save
->prim_count
- 1;
398 assert(i
< (GLint
) save
->prim_max
);
401 /* Close off in-progress primitive.
403 save
->prim
[i
].count
= (save
->vert_count
-
404 save
->prim
[i
].start
);
405 mode
= save
->prim
[i
].mode
;
406 weak
= save
->prim
[i
].weak
;
408 /* store the copied vertices, and allocate a new list.
410 _save_compile_vertex_list( ctx
);
412 /* Restart interrupted primitive
414 save
->prim
[0].mode
= mode
;
415 save
->prim
[0].weak
= weak
;
416 save
->prim
[0].begin
= 0;
417 save
->prim
[0].end
= 0;
418 save
->prim
[0].pad
= 0;
419 save
->prim
[0].start
= 0;
420 save
->prim
[0].count
= 0;
421 save
->prim
[0].num_instances
= 1;
422 save
->prim_count
= 1;
427 /* Called only when buffers are wrapped as the result of filling the
428 * vertex_store struct.
430 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
432 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
433 GLfloat
*data
= save
->copied
.buffer
;
436 /* Emit a glEnd to close off the last vertex list.
438 _save_wrap_buffers( ctx
);
440 /* Copy stored stored vertices to start of new list.
442 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
444 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
445 memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
446 data
+= save
->vertex_size
;
447 save
->buffer_ptr
+= save
->vertex_size
;
453 static void _save_copy_to_current( GLcontext
*ctx
)
455 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
458 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
459 if (save
->attrsz
[i
]) {
460 save
->currentsz
[i
][0] = save
->attrsz
[i
];
461 COPY_CLEAN_4V(save
->current
[i
],
469 static void _save_copy_from_current( GLcontext
*ctx
)
471 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
474 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
475 switch (save
->attrsz
[i
]) {
476 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
477 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
478 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
479 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
488 /* Flush existing data, set new attrib size, replay copied vertices.
490 static void _save_upgrade_vertex( GLcontext
*ctx
,
494 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
499 /* Store the current run of vertices, and emit a GL_END. Emit a
500 * BEGIN in the new buffer.
502 if (save
->vert_count
)
503 _save_wrap_buffers( ctx
);
505 assert( save
->copied
.nr
== 0 );
507 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
508 * when the attribute already exists in the vertex and is having
509 * its size increased.
511 _save_copy_to_current( ctx
);
515 oldsz
= save
->attrsz
[attr
];
516 save
->attrsz
[attr
] = newsz
;
518 save
->vertex_size
+= newsz
- oldsz
;
519 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
521 save
->vert_count
= 0;
523 /* Recalculate all the attrptr[] values:
525 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
526 if (save
->attrsz
[i
]) {
527 save
->attrptr
[i
] = tmp
;
528 tmp
+= save
->attrsz
[i
];
531 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
534 /* Copy from current to repopulate the vertex with correct values.
536 _save_copy_from_current( ctx
);
538 /* Replay stored vertices to translate them to new format here.
540 * If there are copied vertices and the new (upgraded) attribute
541 * has not been defined before, this list is somewhat degenerate,
542 * and will need fixup at runtime.
546 GLfloat
*data
= save
->copied
.buffer
;
547 GLfloat
*dest
= save
->buffer
;
550 /* Need to note this and fix up at runtime (or loopback):
552 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
554 save
->dangling_attr_ref
= GL_TRUE
;
557 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
558 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
559 if (save
->attrsz
[j
]) {
562 COPY_CLEAN_4V( dest
, oldsz
, data
);
567 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
572 GLint sz
= save
->attrsz
[j
];
573 COPY_SZ_4V( dest
, sz
, data
);
581 save
->buffer_ptr
= dest
;
582 save
->vert_count
+= save
->copied
.nr
;
586 static void save_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
588 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
590 if (sz
> save
->attrsz
[attr
]) {
591 /* New size is larger. Need to flush existing vertices and get
592 * an enlarged vertex format.
594 _save_upgrade_vertex( ctx
, attr
, sz
);
596 else if (sz
< save
->active_sz
[attr
]) {
597 static GLfloat id
[4] = { 0, 0, 0, 1 };
600 /* New size is equal or smaller - just need to fill in some
603 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
604 save
->attrptr
[attr
][i
-1] = id
[i
-1];
607 save
->active_sz
[attr
] = sz
;
610 static void _save_reset_vertex( GLcontext
*ctx
)
612 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
615 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
617 save
->active_sz
[i
] = 0;
620 save
->vertex_size
= 0;
625 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
628 /* Only one size for each attribute may be active at once. Eg. if
629 * Color3f is installed/active, then Color4f may not be, even if the
630 * vertex actually contains 4 color coordinates. This is because the
631 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
632 * of the chooser function when switching between Color4f and Color3f.
634 #define ATTR( A, N, V0, V1, V2, V3 ) \
636 struct vbo_save_context *save = &vbo_context(ctx)->save; \
638 if (save->active_sz[A] != N) \
639 save_fixup_vertex(ctx, A, N); \
642 GLfloat *dest = save->attrptr[A]; \
643 if (N>0) dest[0] = V0; \
644 if (N>1) dest[1] = V1; \
645 if (N>2) dest[2] = V2; \
646 if (N>3) dest[3] = V3; \
652 for (i = 0; i < save->vertex_size; i++) \
653 save->buffer_ptr[i] = save->vertex[i]; \
655 save->buffer_ptr += save->vertex_size; \
657 if (++save->vert_count >= save->max_vert) \
658 _save_wrap_filled_vertex( ctx ); \
662 #define TAG(x) _save_##x
664 #include "vbo_attrib_tmp.h"
669 /* Cope with EvalCoord/CallList called within a begin/end object:
670 * -- Flush current buffer
671 * -- Fallback to opcodes for the rest of the begin/end object.
673 static void DO_FALLBACK( GLcontext
*ctx
)
675 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
677 if (save
->vert_count
|| save
->prim_count
) {
678 GLint i
= save
->prim_count
- 1;
680 /* Close off in-progress primitive.
682 save
->prim
[i
].count
= (save
->vert_count
-
683 save
->prim
[i
].start
);
685 /* Need to replay this display list with loopback,
686 * unfortunately, otherwise this primitive won't be handled
689 save
->dangling_attr_ref
= 1;
691 _save_compile_vertex_list( ctx
);
694 _save_copy_to_current( ctx
);
695 _save_reset_vertex( ctx
);
696 _save_reset_counters( ctx
);
697 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
698 ctx
->Driver
.SaveNeedFlush
= 0;
701 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
703 GET_CURRENT_CONTEXT(ctx
);
705 ctx
->Save
->EvalCoord1f( u
);
708 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
710 GET_CURRENT_CONTEXT(ctx
);
712 ctx
->Save
->EvalCoord1fv( v
);
715 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
717 GET_CURRENT_CONTEXT(ctx
);
719 ctx
->Save
->EvalCoord2f( u
, v
);
722 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
724 GET_CURRENT_CONTEXT(ctx
);
726 ctx
->Save
->EvalCoord2fv( v
);
729 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
731 GET_CURRENT_CONTEXT(ctx
);
733 ctx
->Save
->EvalPoint1( i
);
736 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
738 GET_CURRENT_CONTEXT(ctx
);
740 ctx
->Save
->EvalPoint2( i
, j
);
743 static void GLAPIENTRY
_save_CallList( GLuint l
)
745 GET_CURRENT_CONTEXT(ctx
);
747 ctx
->Save
->CallList( l
);
750 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
752 GET_CURRENT_CONTEXT(ctx
);
754 ctx
->Save
->CallLists( n
, type
, v
);
760 /* This begin is hooked into ... Updating of
761 * ctx->Driver.CurrentSavePrimitive is already taken care of.
763 GLboolean
vbo_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
765 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
767 GLuint i
= save
->prim_count
++;
769 assert(i
< save
->prim_max
);
770 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
771 save
->prim
[i
].begin
= 1;
772 save
->prim
[i
].end
= 0;
773 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
774 save
->prim
[i
].pad
= 0;
775 save
->prim
[i
].start
= save
->vert_count
;
776 save
->prim
[i
].count
= 0;
777 save
->prim
[i
].num_instances
= 1;
779 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
780 ctx
->Driver
.SaveNeedFlush
= 1;
786 static void GLAPIENTRY
_save_End( void )
788 GET_CURRENT_CONTEXT( ctx
);
789 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
790 GLint i
= save
->prim_count
- 1;
792 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
793 save
->prim
[i
].end
= 1;
794 save
->prim
[i
].count
= (save
->vert_count
-
795 save
->prim
[i
].start
);
797 if (i
== (GLint
) save
->prim_max
- 1) {
798 _save_compile_vertex_list( ctx
);
799 assert(save
->copied
.nr
== 0);
802 /* Swap out this vertex format while outside begin/end. Any color,
803 * etc. received between here and the next begin will be compiled
806 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
810 /* These are all errors as this vtxfmt is only installed inside
813 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
814 const GLvoid
*indices
)
816 GET_CURRENT_CONTEXT(ctx
);
817 (void) mode
; (void) count
; (void) type
; (void) indices
;
818 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
822 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
823 GLuint start
, GLuint end
,
824 GLsizei count
, GLenum type
,
825 const GLvoid
*indices
)
827 GET_CURRENT_CONTEXT(ctx
);
828 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
829 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
832 static void GLAPIENTRY
_save_DrawElementsBaseVertex(GLenum mode
,
835 const GLvoid
*indices
,
838 GET_CURRENT_CONTEXT(ctx
);
839 (void) mode
; (void) count
; (void) type
; (void) indices
; (void)basevertex
;
841 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
844 static void GLAPIENTRY
_save_DrawRangeElementsBaseVertex(GLenum mode
,
849 const GLvoid
*indices
,
852 GET_CURRENT_CONTEXT(ctx
);
853 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
;
854 (void) indices
; (void)basevertex
;
856 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
859 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
861 GET_CURRENT_CONTEXT(ctx
);
862 (void) mode
; (void) start
; (void) count
;
863 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
866 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
868 GET_CURRENT_CONTEXT(ctx
);
869 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
870 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
873 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
875 GET_CURRENT_CONTEXT(ctx
);
876 (void) mode
; (void) i1
; (void) i2
;
877 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
880 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
883 GET_CURRENT_CONTEXT(ctx
);
884 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
885 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
888 static void GLAPIENTRY
_save_Begin( GLenum mode
)
890 GET_CURRENT_CONTEXT( ctx
);
892 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
896 /* Unlike the functions above, these are to be hooked into the vtxfmt
897 * maintained in ctx->ListState, active when the list is known or
898 * suspected to be outside any begin/end primitive.
900 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
902 GET_CURRENT_CONTEXT(ctx
);
903 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
904 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
905 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
906 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
907 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
908 CALL_End(GET_DISPATCH(), ());
912 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
914 GET_CURRENT_CONTEXT(ctx
);
917 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
922 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
924 for (i
= 0; i
< count
; i
++)
925 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
926 CALL_End(GET_DISPATCH(), ());
928 _ae_unmap_vbos( ctx
);
931 /* Could do better by copying the arrays and element list intact and
932 * then emitting an indexed prim at runtime.
934 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
935 const GLvoid
*indices
)
937 GET_CURRENT_CONTEXT(ctx
);
940 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
, 0 ))
945 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
946 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
948 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
951 case GL_UNSIGNED_BYTE
:
952 for (i
= 0 ; i
< count
; i
++)
953 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
955 case GL_UNSIGNED_SHORT
:
956 for (i
= 0 ; i
< count
; i
++)
957 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
959 case GL_UNSIGNED_INT
:
960 for (i
= 0 ; i
< count
; i
++)
961 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
964 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
968 CALL_End(GET_DISPATCH(), ());
970 _ae_unmap_vbos( ctx
);
973 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
974 GLuint start
, GLuint end
,
975 GLsizei count
, GLenum type
,
976 const GLvoid
*indices
)
978 GET_CURRENT_CONTEXT(ctx
);
979 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
981 count
, type
, indices
, 0 ))
982 _save_OBE_DrawElements( mode
, count
, type
, indices
);
989 static void _save_vtxfmt_init( GLcontext
*ctx
)
991 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
992 GLvertexformat
*vfmt
= &save
->vtxfmt
;
994 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
996 vfmt
->Begin
= _save_Begin
;
997 vfmt
->Color3f
= _save_Color3f
;
998 vfmt
->Color3fv
= _save_Color3fv
;
999 vfmt
->Color4f
= _save_Color4f
;
1000 vfmt
->Color4fv
= _save_Color4fv
;
1001 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1002 vfmt
->End
= _save_End
;
1003 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1004 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1005 vfmt
->Indexf
= _save_Indexf
;
1006 vfmt
->Indexfv
= _save_Indexfv
;
1007 vfmt
->Materialfv
= _save_Materialfv
;
1008 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1009 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1010 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1011 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1012 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1013 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1014 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1015 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1016 vfmt
->Normal3f
= _save_Normal3f
;
1017 vfmt
->Normal3fv
= _save_Normal3fv
;
1018 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1019 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1020 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1021 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1022 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1023 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1024 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1025 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1026 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1027 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1028 vfmt
->Vertex2f
= _save_Vertex2f
;
1029 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1030 vfmt
->Vertex3f
= _save_Vertex3f
;
1031 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1032 vfmt
->Vertex4f
= _save_Vertex4f
;
1033 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1034 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1035 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1036 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1037 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1038 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1039 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1040 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1041 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1043 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1044 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1045 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1046 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1047 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1048 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1049 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1050 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1052 /* This will all require us to fallback to saving the list as opcodes:
1054 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1056 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1058 /* These are all errors as we at least know we are in some sort of
1061 vfmt
->Begin
= _save_Begin
;
1062 vfmt
->Rectf
= _save_Rectf
;
1063 vfmt
->DrawArrays
= _save_DrawArrays
;
1064 vfmt
->DrawElements
= _save_DrawElements
;
1065 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1066 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1067 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1068 /* Loops back into vfmt->DrawElements */
1069 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1070 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1074 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
1076 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1078 /* Noop when we are actually active:
1080 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1081 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1084 if (save
->vert_count
||
1086 _save_compile_vertex_list( ctx
);
1088 _save_copy_to_current( ctx
);
1089 _save_reset_vertex( ctx
);
1090 _save_reset_counters( ctx
);
1091 ctx
->Driver
.SaveNeedFlush
= 0;
1094 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1096 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1098 (void) list
; (void) mode
;
1100 if (!save
->prim_store
)
1101 save
->prim_store
= alloc_prim_store( ctx
);
1103 if (!save
->vertex_store
)
1104 save
->vertex_store
= alloc_vertex_store( ctx
);
1106 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1108 _save_reset_vertex( ctx
);
1109 _save_reset_counters( ctx
);
1110 ctx
->Driver
.SaveNeedFlush
= 0;
1113 void vbo_save_EndList( GLcontext
*ctx
)
1115 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1117 /* EndList called inside a (saved) Begin/End pair?
1119 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1121 if (save
->prim_count
> 0) {
1122 GLint i
= save
->prim_count
- 1;
1123 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1124 save
->prim
[i
].end
= 0;
1125 save
->prim
[i
].count
= (save
->vert_count
-
1126 save
->prim
[i
].start
);
1129 /* Make sure this vertex list gets replayed by the "loopback"
1132 save
->dangling_attr_ref
= 1;
1133 vbo_save_SaveFlushVertices( ctx
);
1135 /* Swap out this vertex format while outside begin/end. Any color,
1136 * etc. received between here and the next begin will be compiled
1139 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1142 unmap_vertex_store( ctx
, save
->vertex_store
);
1144 assert(save
->vertex_size
== 0);
1147 void vbo_save_BeginCallList( GLcontext
*ctx
, struct gl_display_list
*dlist
)
1149 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1150 save
->replay_flags
|= dlist
->Flags
;
1153 void vbo_save_EndCallList( GLcontext
*ctx
)
1155 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1157 if (ctx
->ListState
.CallDepth
== 1) {
1158 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1159 * flag, if it is set:
1161 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1166 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1168 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1171 if ( --node
->vertex_store
->refcount
== 0 )
1172 free_vertex_store( ctx
, node
->vertex_store
);
1174 if ( --node
->prim_store
->refcount
== 0 )
1175 FREE( node
->prim_store
);
1177 if (node
->current_data
) {
1178 FREE(node
->current_data
);
1179 node
->current_data
= NULL
;
1184 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1186 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1190 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1195 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1196 struct _mesa_prim
*prim
= &node
->prim
[i
];
1197 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1199 _mesa_lookup_prim_by_nr(prim
->mode
),
1200 prim
->weak
? " (weak)" : "",
1202 prim
->start
+ prim
->count
,
1203 (prim
->begin
) ? "BEGIN" : "(wrap)",
1204 (prim
->end
) ? "END" : "(wrap)");
1209 static void _save_current_init( GLcontext
*ctx
)
1211 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1214 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1215 const GLuint j
= i
- VBO_ATTRIB_POS
;
1216 ASSERT(j
< VERT_ATTRIB_MAX
);
1217 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1218 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1221 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1222 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1223 ASSERT(j
< MAT_ATTRIB_MAX
);
1224 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1225 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1230 * Initialize the display list compiler
1232 void vbo_save_api_init( struct vbo_save_context
*save
)
1234 GLcontext
*ctx
= save
->ctx
;
1237 save
->opcode_vertex_list
=
1238 _mesa_dlist_alloc_opcode( ctx
,
1239 sizeof(struct vbo_save_vertex_list
),
1240 vbo_save_playback_vertex_list
,
1241 vbo_destroy_vertex_list
,
1242 vbo_print_vertex_list
);
1244 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1246 _save_vtxfmt_init( ctx
);
1247 _save_current_init( ctx
);
1249 /* These will actually get set again when binding/drawing */
1250 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1251 save
->inputs
[i
] = &save
->arrays
[i
];
1253 /* Hook our array functions into the outside-begin-end vtxfmt in
1256 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1257 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1258 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1259 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1260 /* loops back into _save_OBE_DrawElements */
1261 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1262 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1263 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);