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_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
831 GET_CURRENT_CONTEXT(ctx
);
832 (void) mode
; (void) start
; (void) count
;
833 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
836 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
838 GET_CURRENT_CONTEXT(ctx
);
839 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
840 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
843 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
845 GET_CURRENT_CONTEXT(ctx
);
846 (void) mode
; (void) i1
; (void) i2
;
847 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
850 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
853 GET_CURRENT_CONTEXT(ctx
);
854 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
855 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
858 static void GLAPIENTRY
_save_Begin( GLenum mode
)
860 GET_CURRENT_CONTEXT( ctx
);
862 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
866 /* Unlike the functions above, these are to be hooked into the vtxfmt
867 * maintained in ctx->ListState, active when the list is known or
868 * suspected to be outside any begin/end primitive.
870 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
872 GET_CURRENT_CONTEXT(ctx
);
873 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
874 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
875 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
876 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
877 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
878 CALL_End(GET_DISPATCH(), ());
882 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
884 GET_CURRENT_CONTEXT(ctx
);
887 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
892 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
894 for (i
= 0; i
< count
; i
++)
895 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
896 CALL_End(GET_DISPATCH(), ());
898 _ae_unmap_vbos( ctx
);
901 /* Could do better by copying the arrays and element list intact and
902 * then emitting an indexed prim at runtime.
904 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
905 const GLvoid
*indices
)
907 GET_CURRENT_CONTEXT(ctx
);
910 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
915 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
916 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
918 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
921 case GL_UNSIGNED_BYTE
:
922 for (i
= 0 ; i
< count
; i
++)
923 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
925 case GL_UNSIGNED_SHORT
:
926 for (i
= 0 ; i
< count
; i
++)
927 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
929 case GL_UNSIGNED_INT
:
930 for (i
= 0 ; i
< count
; i
++)
931 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
934 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
938 CALL_End(GET_DISPATCH(), ());
940 _ae_unmap_vbos( ctx
);
943 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
944 GLuint start
, GLuint end
,
945 GLsizei count
, GLenum type
,
946 const GLvoid
*indices
)
948 GET_CURRENT_CONTEXT(ctx
);
949 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
951 count
, type
, indices
))
952 _save_OBE_DrawElements( mode
, count
, type
, indices
);
959 static void _save_vtxfmt_init( GLcontext
*ctx
)
961 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
962 GLvertexformat
*vfmt
= &save
->vtxfmt
;
964 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
965 vfmt
->Begin
= _save_Begin
;
966 vfmt
->Color3f
= _save_Color3f
;
967 vfmt
->Color3fv
= _save_Color3fv
;
968 vfmt
->Color4f
= _save_Color4f
;
969 vfmt
->Color4fv
= _save_Color4fv
;
970 vfmt
->EdgeFlag
= _save_EdgeFlag
;
971 vfmt
->End
= _save_End
;
972 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
973 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
974 vfmt
->Indexf
= _save_Indexf
;
975 vfmt
->Indexfv
= _save_Indexfv
;
976 vfmt
->Materialfv
= _save_Materialfv
;
977 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
978 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
979 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
980 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
981 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
982 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
983 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
984 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
985 vfmt
->Normal3f
= _save_Normal3f
;
986 vfmt
->Normal3fv
= _save_Normal3fv
;
987 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
988 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
989 vfmt
->TexCoord1f
= _save_TexCoord1f
;
990 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
991 vfmt
->TexCoord2f
= _save_TexCoord2f
;
992 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
993 vfmt
->TexCoord3f
= _save_TexCoord3f
;
994 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
995 vfmt
->TexCoord4f
= _save_TexCoord4f
;
996 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
997 vfmt
->Vertex2f
= _save_Vertex2f
;
998 vfmt
->Vertex2fv
= _save_Vertex2fv
;
999 vfmt
->Vertex3f
= _save_Vertex3f
;
1000 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1001 vfmt
->Vertex4f
= _save_Vertex4f
;
1002 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1003 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1004 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1005 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1006 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1007 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1008 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1009 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1010 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1012 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1013 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1014 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1015 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1016 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1017 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1018 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1019 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1021 /* This will all require us to fallback to saving the list as opcodes:
1023 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1024 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1025 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1026 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1027 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1028 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1029 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1030 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1032 /* These are all errors as we at least know we are in some sort of
1035 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1036 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1037 vfmt
->Begin
= _save_Begin
;
1038 vfmt
->Rectf
= _save_Rectf
;
1039 vfmt
->DrawArrays
= _save_DrawArrays
;
1040 vfmt
->DrawElements
= _save_DrawElements
;
1041 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1042 /* Loops back into vfmt->DrawElements */
1043 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1048 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
1050 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1052 /* Noop when we are actually active:
1054 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1055 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1058 if (save
->vert_count
||
1060 _save_compile_vertex_list( ctx
);
1062 _save_copy_to_current( ctx
);
1063 _save_reset_vertex( ctx
);
1064 _save_reset_counters( ctx
);
1065 ctx
->Driver
.SaveNeedFlush
= 0;
1068 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1070 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1072 (void) list
; (void) mode
;
1074 if (!save
->prim_store
)
1075 save
->prim_store
= alloc_prim_store( ctx
);
1077 if (!save
->vertex_store
)
1078 save
->vertex_store
= alloc_vertex_store( ctx
);
1080 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1082 _save_reset_vertex( ctx
);
1083 _save_reset_counters( ctx
);
1084 ctx
->Driver
.SaveNeedFlush
= 0;
1087 void vbo_save_EndList( GLcontext
*ctx
)
1089 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1091 /* EndList called inside a (saved) Begin/End pair?
1093 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1095 if (save
->prim_count
> 0) {
1096 GLint i
= save
->prim_count
- 1;
1097 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1098 save
->prim
[i
].end
= 0;
1099 save
->prim
[i
].count
= (save
->vert_count
-
1100 save
->prim
[i
].start
);
1103 /* Make sure this vertex list gets replayed by the "loopback"
1106 save
->dangling_attr_ref
= 1;
1107 vbo_save_SaveFlushVertices( ctx
);
1109 /* Swap out this vertex format while outside begin/end. Any color,
1110 * etc. received between here and the next begin will be compiled
1113 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1116 unmap_vertex_store( ctx
, save
->vertex_store
);
1118 assert(save
->vertex_size
== 0);
1121 void vbo_save_BeginCallList( GLcontext
*ctx
, struct gl_display_list
*dlist
)
1123 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1124 save
->replay_flags
|= dlist
->Flags
;
1127 void vbo_save_EndCallList( GLcontext
*ctx
)
1129 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1131 if (ctx
->ListState
.CallDepth
== 1) {
1132 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1133 * flag, if it is set:
1135 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1140 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1142 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1145 if ( --node
->vertex_store
->refcount
== 0 )
1146 free_vertex_store( ctx
, node
->vertex_store
);
1148 if ( --node
->prim_store
->refcount
== 0 )
1149 FREE( node
->prim_store
);
1151 if (node
->current_data
) {
1152 FREE(node
->current_data
);
1153 node
->current_data
= NULL
;
1158 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1160 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1164 _mesa_printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1169 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1170 struct _mesa_prim
*prim
= &node
->prim
[i
];
1171 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1173 _mesa_lookup_prim_by_nr(prim
->mode
),
1174 prim
->weak
? " (weak)" : "",
1176 prim
->start
+ prim
->count
,
1177 (prim
->begin
) ? "BEGIN" : "(wrap)",
1178 (prim
->end
) ? "END" : "(wrap)");
1183 static void _save_current_init( GLcontext
*ctx
)
1185 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1188 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1189 const GLuint j
= i
- VBO_ATTRIB_POS
;
1190 ASSERT(j
< VERT_ATTRIB_MAX
);
1191 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1192 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1195 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1196 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1197 ASSERT(j
< MAT_ATTRIB_MAX
);
1198 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1199 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1204 * Initialize the display list compiler
1206 void vbo_save_api_init( struct vbo_save_context
*save
)
1208 GLcontext
*ctx
= save
->ctx
;
1211 save
->opcode_vertex_list
=
1212 _mesa_alloc_opcode( ctx
,
1213 sizeof(struct vbo_save_vertex_list
),
1214 vbo_save_playback_vertex_list
,
1215 vbo_destroy_vertex_list
,
1216 vbo_print_vertex_list
);
1218 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1220 _save_vtxfmt_init( ctx
);
1221 _save_current_init( ctx
);
1223 /* These will actually get set again when binding/drawing */
1224 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1225 save
->inputs
[i
] = &save
->arrays
[i
];
1227 /* Hook our array functions into the outside-begin-end vtxfmt in
1230 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1231 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1232 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1233 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1234 /* loops back into _save_OBE_DrawElements */
1235 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1236 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);