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/mfeatures.h"
78 #include "main/api_noop.h"
79 #include "main/api_validate.h"
80 #include "main/api_arrayelt.h"
81 #include "main/vtxfmt.h"
82 #include "main/dispatch.h"
84 #include "vbo_context.h"
95 /* An interesting VBO number/name to help with debugging */
96 #define VBO_BUF_ID 12345
100 * NOTE: Old 'parity' issue is gone, but copying can still be
101 * wrong-footed on replay.
103 static GLuint
_save_copy_vertices( struct gl_context
*ctx
,
104 const struct vbo_save_vertex_list
*node
,
105 const GLfloat
*src_buffer
)
107 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
108 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
109 GLuint nr
= prim
->count
;
110 GLuint sz
= save
->vertex_size
;
111 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
112 GLfloat
*dst
= save
->copied
.buffer
;
124 for (i
= 0 ; i
< ovf
; i
++)
125 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
129 for (i
= 0 ; i
< ovf
; i
++)
130 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
134 for (i
= 0 ; i
< ovf
; i
++)
135 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
141 memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
145 case GL_TRIANGLE_FAN
:
150 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
153 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
154 memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
157 case GL_TRIANGLE_STRIP
:
160 case 0: ovf
= 0; break;
161 case 1: ovf
= 1; break;
162 default: ovf
= 2 + (nr
&1); break;
164 for (i
= 0 ; i
< ovf
; i
++)
165 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
174 static struct vbo_save_vertex_store
*alloc_vertex_store( struct gl_context
*ctx
)
176 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
178 /* obj->Name needs to be non-zero, but won't ever be examined more
179 * closely than that. In particular these buffers won't be entered
180 * into the hash and can never be confused with ones visible to the
181 * user. Perhaps there could be a special number for internal
184 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
186 GL_ARRAY_BUFFER_ARB
);
188 ctx
->Driver
.BufferData( ctx
,
190 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
193 vertex_store
->bufferobj
);
195 vertex_store
->buffer
= NULL
;
196 vertex_store
->used
= 0;
197 vertex_store
->refcount
= 1;
202 static void free_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
204 assert(!vertex_store
->buffer
);
206 if (vertex_store
->bufferobj
) {
207 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
210 FREE( vertex_store
);
213 static GLfloat
*map_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
215 assert(vertex_store
->bufferobj
);
216 assert(!vertex_store
->buffer
);
217 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
218 GL_ARRAY_BUFFER_ARB
, /* not used */
219 GL_WRITE_ONLY
, /* not used */
220 vertex_store
->bufferobj
);
222 assert(vertex_store
->buffer
);
223 return vertex_store
->buffer
+ vertex_store
->used
;
226 static void unmap_vertex_store( struct gl_context
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
228 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
229 vertex_store
->buffer
= NULL
;
233 static struct vbo_save_primitive_store
*alloc_prim_store( struct gl_context
*ctx
)
235 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
242 static void _save_reset_counters( struct gl_context
*ctx
)
244 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
246 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
247 save
->buffer
= (save
->vertex_store
->buffer
+
248 save
->vertex_store
->used
);
250 assert(save
->buffer
== save
->buffer_ptr
);
252 if (save
->vertex_size
)
253 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
258 save
->vert_count
= 0;
259 save
->prim_count
= 0;
260 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
261 save
->dangling_attr_ref
= 0;
265 /* Insert the active immediate struct onto the display list currently
268 static void _save_compile_vertex_list( struct gl_context
*ctx
)
270 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
271 struct vbo_save_vertex_list
*node
;
273 /* Allocate space for this structure in the display list currently
276 node
= (struct vbo_save_vertex_list
*)
277 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
282 /* Duplicate our template, increment refcounts to the storage structs:
284 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
285 node
->vertex_size
= save
->vertex_size
;
286 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
287 node
->count
= save
->vert_count
;
288 node
->wrap_count
= save
->copied
.nr
;
289 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
290 node
->prim
= save
->prim
;
291 node
->prim_count
= save
->prim_count
;
292 node
->vertex_store
= save
->vertex_store
;
293 node
->prim_store
= save
->prim_store
;
295 node
->vertex_store
->refcount
++;
296 node
->prim_store
->refcount
++;
298 if (node
->prim
[0].no_current_update
) {
299 node
->current_size
= 0;
300 node
->current_data
= NULL
;
302 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
303 node
->current_data
= NULL
;
305 if (node
->current_size
) {
306 /* If the malloc fails, we just pull the data out of the VBO
309 node
->current_data
= MALLOC( node
->current_size
* sizeof(GLfloat
) );
310 if (node
->current_data
) {
311 const char *buffer
= (const char *)save
->vertex_store
->buffer
;
312 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
313 unsigned vertex_offset
= 0;
316 vertex_offset
= (node
->count
-1) * node
->vertex_size
* sizeof(GLfloat
);
318 memcpy( node
->current_data
,
319 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
320 node
->current_size
* sizeof(GLfloat
) );
327 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
330 if (save
->dangling_attr_ref
)
331 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
333 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
334 save
->prim_store
->used
+= node
->prim_count
;
337 /* Copy duplicated vertices
339 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
342 /* Deal with GL_COMPILE_AND_EXECUTE:
344 if (ctx
->ExecuteFlag
) {
345 struct _glapi_table
*dispatch
= GET_DISPATCH();
347 _glapi_set_dispatch(ctx
->Exec
);
349 vbo_loopback_vertex_list( ctx
,
350 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
351 node
->buffer_offset
),
358 _glapi_set_dispatch(dispatch
);
362 /* Decide whether the storage structs are full, or can be used for
363 * the next vertex lists as well.
365 if (save
->vertex_store
->used
>
366 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
370 unmap_vertex_store( ctx
, save
->vertex_store
);
372 /* Release old reference:
374 save
->vertex_store
->refcount
--;
375 assert(save
->vertex_store
->refcount
!= 0);
376 save
->vertex_store
= NULL
;
378 /* Allocate and map new store:
380 save
->vertex_store
= alloc_vertex_store( ctx
);
381 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
384 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
385 save
->prim_store
->refcount
--;
386 assert(save
->prim_store
->refcount
!= 0);
387 save
->prim_store
= alloc_prim_store( ctx
);
390 /* Reset our structures for the next run of vertices:
392 _save_reset_counters( ctx
);
396 /* TODO -- If no new vertices have been stored, don't bother saving
399 static void _save_wrap_buffers( struct gl_context
*ctx
)
401 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
402 GLint i
= save
->prim_count
- 1;
405 GLboolean no_current_update
;
407 assert(i
< (GLint
) save
->prim_max
);
410 /* Close off in-progress primitive.
412 save
->prim
[i
].count
= (save
->vert_count
-
413 save
->prim
[i
].start
);
414 mode
= save
->prim
[i
].mode
;
415 weak
= save
->prim
[i
].weak
;
416 no_current_update
= save
->prim
[i
].no_current_update
;
418 /* store the copied vertices, and allocate a new list.
420 _save_compile_vertex_list( ctx
);
422 /* Restart interrupted primitive
424 save
->prim
[0].mode
= mode
;
425 save
->prim
[0].weak
= weak
;
426 save
->prim
[0].no_current_update
= no_current_update
;
427 save
->prim
[0].begin
= 0;
428 save
->prim
[0].end
= 0;
429 save
->prim
[0].pad
= 0;
430 save
->prim
[0].start
= 0;
431 save
->prim
[0].count
= 0;
432 save
->prim
[0].num_instances
= 1;
433 save
->prim_count
= 1;
438 /* Called only when buffers are wrapped as the result of filling the
439 * vertex_store struct.
441 static void _save_wrap_filled_vertex( struct gl_context
*ctx
)
443 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
444 GLfloat
*data
= save
->copied
.buffer
;
447 /* Emit a glEnd to close off the last vertex list.
449 _save_wrap_buffers( ctx
);
451 /* Copy stored stored vertices to start of new list.
453 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
455 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
456 memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
457 data
+= save
->vertex_size
;
458 save
->buffer_ptr
+= save
->vertex_size
;
464 static void _save_copy_to_current( struct gl_context
*ctx
)
466 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
469 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
470 if (save
->attrsz
[i
]) {
471 save
->currentsz
[i
][0] = save
->attrsz
[i
];
472 COPY_CLEAN_4V(save
->current
[i
],
480 static void _save_copy_from_current( struct gl_context
*ctx
)
482 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
485 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
486 switch (save
->attrsz
[i
]) {
487 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
488 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
489 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
490 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
499 /* Flush existing data, set new attrib size, replay copied vertices.
501 static void _save_upgrade_vertex( struct gl_context
*ctx
,
505 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
510 /* Store the current run of vertices, and emit a GL_END. Emit a
511 * BEGIN in the new buffer.
513 if (save
->vert_count
)
514 _save_wrap_buffers( ctx
);
516 assert( save
->copied
.nr
== 0 );
518 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
519 * when the attribute already exists in the vertex and is having
520 * its size increased.
522 _save_copy_to_current( ctx
);
526 oldsz
= save
->attrsz
[attr
];
527 save
->attrsz
[attr
] = newsz
;
529 save
->vertex_size
+= newsz
- oldsz
;
530 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
532 save
->vert_count
= 0;
534 /* Recalculate all the attrptr[] values:
536 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
537 if (save
->attrsz
[i
]) {
538 save
->attrptr
[i
] = tmp
;
539 tmp
+= save
->attrsz
[i
];
542 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
545 /* Copy from current to repopulate the vertex with correct values.
547 _save_copy_from_current( ctx
);
549 /* Replay stored vertices to translate them to new format here.
551 * If there are copied vertices and the new (upgraded) attribute
552 * has not been defined before, this list is somewhat degenerate,
553 * and will need fixup at runtime.
557 GLfloat
*data
= save
->copied
.buffer
;
558 GLfloat
*dest
= save
->buffer
;
561 /* Need to note this and fix up at runtime (or loopback):
563 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
565 save
->dangling_attr_ref
= GL_TRUE
;
568 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
569 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
570 if (save
->attrsz
[j
]) {
573 COPY_CLEAN_4V( dest
, oldsz
, data
);
578 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
583 GLint sz
= save
->attrsz
[j
];
584 COPY_SZ_4V( dest
, sz
, data
);
592 save
->buffer_ptr
= dest
;
593 save
->vert_count
+= save
->copied
.nr
;
597 static void save_fixup_vertex( struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
599 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
601 if (sz
> save
->attrsz
[attr
]) {
602 /* New size is larger. Need to flush existing vertices and get
603 * an enlarged vertex format.
605 _save_upgrade_vertex( ctx
, attr
, sz
);
607 else if (sz
< save
->active_sz
[attr
]) {
608 static GLfloat id
[4] = { 0, 0, 0, 1 };
611 /* New size is equal or smaller - just need to fill in some
614 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
615 save
->attrptr
[attr
][i
-1] = id
[i
-1];
618 save
->active_sz
[attr
] = sz
;
621 static void _save_reset_vertex( struct gl_context
*ctx
)
623 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
626 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
628 save
->active_sz
[i
] = 0;
631 save
->vertex_size
= 0;
636 #define ERROR(err) _mesa_compile_error( ctx, err, __FUNCTION__ );
639 /* Only one size for each attribute may be active at once. Eg. if
640 * Color3f is installed/active, then Color4f may not be, even if the
641 * vertex actually contains 4 color coordinates. This is because the
642 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
643 * of the chooser function when switching between Color4f and Color3f.
645 #define ATTR( A, N, V0, V1, V2, V3 ) \
647 struct vbo_save_context *save = &vbo_context(ctx)->save; \
649 if (save->active_sz[A] != N) \
650 save_fixup_vertex(ctx, A, N); \
653 GLfloat *dest = save->attrptr[A]; \
654 if (N>0) dest[0] = V0; \
655 if (N>1) dest[1] = V1; \
656 if (N>2) dest[2] = V2; \
657 if (N>3) dest[3] = V3; \
663 for (i = 0; i < save->vertex_size; i++) \
664 save->buffer_ptr[i] = save->vertex[i]; \
666 save->buffer_ptr += save->vertex_size; \
668 if (++save->vert_count >= save->max_vert) \
669 _save_wrap_filled_vertex( ctx ); \
673 #define TAG(x) _save_##x
675 #include "vbo_attrib_tmp.h"
680 /* Cope with EvalCoord/CallList called within a begin/end object:
681 * -- Flush current buffer
682 * -- Fallback to opcodes for the rest of the begin/end object.
684 static void DO_FALLBACK( struct gl_context
*ctx
)
686 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
688 if (save
->vert_count
|| save
->prim_count
) {
689 GLint i
= save
->prim_count
- 1;
691 /* Close off in-progress primitive.
693 save
->prim
[i
].count
= (save
->vert_count
-
694 save
->prim
[i
].start
);
696 /* Need to replay this display list with loopback,
697 * unfortunately, otherwise this primitive won't be handled
700 save
->dangling_attr_ref
= 1;
702 _save_compile_vertex_list( ctx
);
705 _save_copy_to_current( ctx
);
706 _save_reset_vertex( ctx
);
707 _save_reset_counters( ctx
);
708 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
709 ctx
->Driver
.SaveNeedFlush
= 0;
712 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
714 GET_CURRENT_CONTEXT(ctx
);
716 CALL_EvalCoord1f(ctx
->Save
, (u
));
719 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
721 GET_CURRENT_CONTEXT(ctx
);
723 CALL_EvalCoord1fv(ctx
->Save
, (v
));
726 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
728 GET_CURRENT_CONTEXT(ctx
);
730 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
733 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
735 GET_CURRENT_CONTEXT(ctx
);
737 CALL_EvalCoord2fv(ctx
->Save
, (v
));
740 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
742 GET_CURRENT_CONTEXT(ctx
);
744 CALL_EvalPoint1(ctx
->Save
, (i
));
747 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
749 GET_CURRENT_CONTEXT(ctx
);
751 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
754 static void GLAPIENTRY
_save_CallList( GLuint l
)
756 GET_CURRENT_CONTEXT(ctx
);
758 CALL_CallList(ctx
->Save
, (l
));
761 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
763 GET_CURRENT_CONTEXT(ctx
);
765 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
771 /* This begin is hooked into ... Updating of
772 * ctx->Driver.CurrentSavePrimitive is already taken care of.
774 GLboolean
vbo_save_NotifyBegin( struct gl_context
*ctx
, GLenum mode
)
776 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
778 GLuint i
= save
->prim_count
++;
780 assert(i
< save
->prim_max
);
781 save
->prim
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
782 save
->prim
[i
].begin
= 1;
783 save
->prim
[i
].end
= 0;
784 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
785 save
->prim
[i
].no_current_update
= (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
786 save
->prim
[i
].pad
= 0;
787 save
->prim
[i
].start
= save
->vert_count
;
788 save
->prim
[i
].count
= 0;
789 save
->prim
[i
].num_instances
= 1;
791 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
792 ctx
->Driver
.SaveNeedFlush
= 1;
798 static void GLAPIENTRY
_save_End( void )
800 GET_CURRENT_CONTEXT( ctx
);
801 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
802 GLint i
= save
->prim_count
- 1;
804 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
805 save
->prim
[i
].end
= 1;
806 save
->prim
[i
].count
= (save
->vert_count
-
807 save
->prim
[i
].start
);
809 if (i
== (GLint
) save
->prim_max
- 1) {
810 _save_compile_vertex_list( ctx
);
811 assert(save
->copied
.nr
== 0);
814 /* Swap out this vertex format while outside begin/end. Any color,
815 * etc. received between here and the next begin will be compiled
818 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
822 /* These are all errors as this vtxfmt is only installed inside
825 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
826 const GLvoid
*indices
)
828 GET_CURRENT_CONTEXT(ctx
);
829 (void) mode
; (void) count
; (void) type
; (void) indices
;
830 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
834 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
835 GLuint start
, GLuint end
,
836 GLsizei count
, GLenum type
,
837 const GLvoid
*indices
)
839 GET_CURRENT_CONTEXT(ctx
);
840 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
841 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
844 static void GLAPIENTRY
_save_DrawElementsBaseVertex(GLenum mode
,
847 const GLvoid
*indices
,
850 GET_CURRENT_CONTEXT(ctx
);
851 (void) mode
; (void) count
; (void) type
; (void) indices
; (void)basevertex
;
853 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
856 static void GLAPIENTRY
_save_DrawRangeElementsBaseVertex(GLenum mode
,
861 const GLvoid
*indices
,
864 GET_CURRENT_CONTEXT(ctx
);
865 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
;
866 (void) indices
; (void)basevertex
;
868 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
871 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
873 GET_CURRENT_CONTEXT(ctx
);
874 (void) mode
; (void) start
; (void) count
;
875 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
878 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
880 GET_CURRENT_CONTEXT(ctx
);
881 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
882 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
885 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
887 GET_CURRENT_CONTEXT(ctx
);
888 (void) mode
; (void) i1
; (void) i2
;
889 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
892 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
895 GET_CURRENT_CONTEXT(ctx
);
896 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
897 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
900 static void GLAPIENTRY
_save_Begin( GLenum mode
)
902 GET_CURRENT_CONTEXT( ctx
);
904 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
908 static void GLAPIENTRY
_save_PrimitiveRestartNV( void )
911 GET_CURRENT_CONTEXT( ctx
);
913 curPrim
= ctx
->Driver
.CurrentSavePrimitive
;
916 _save_Begin(curPrim
);
920 /* Unlike the functions above, these are to be hooked into the vtxfmt
921 * maintained in ctx->ListState, active when the list is known or
922 * suspected to be outside any begin/end primitive.
924 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
926 GET_CURRENT_CONTEXT(ctx
);
927 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
928 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
929 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
930 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
931 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
932 CALL_End(GET_DISPATCH(), ());
936 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
938 GET_CURRENT_CONTEXT(ctx
);
941 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
946 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
| VBO_SAVE_PRIM_NO_CURRENT_UPDATE
);
948 for (i
= 0; i
< count
; i
++)
949 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
950 CALL_End(GET_DISPATCH(), ());
952 _ae_unmap_vbos( ctx
);
955 /* Could do better by copying the arrays and element list intact and
956 * then emitting an indexed prim at runtime.
958 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
959 const GLvoid
*indices
)
961 GET_CURRENT_CONTEXT(ctx
);
964 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
, 0 ))
969 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
970 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
972 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
| VBO_SAVE_PRIM_NO_CURRENT_UPDATE
);
975 case GL_UNSIGNED_BYTE
:
976 for (i
= 0 ; i
< count
; i
++)
977 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
979 case GL_UNSIGNED_SHORT
:
980 for (i
= 0 ; i
< count
; i
++)
981 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
983 case GL_UNSIGNED_INT
:
984 for (i
= 0 ; i
< count
; i
++)
985 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
988 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
992 CALL_End(GET_DISPATCH(), ());
994 _ae_unmap_vbos( ctx
);
997 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
998 GLuint start
, GLuint end
,
999 GLsizei count
, GLenum type
,
1000 const GLvoid
*indices
)
1002 GET_CURRENT_CONTEXT(ctx
);
1003 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1005 count
, type
, indices
, 0 ))
1006 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1013 static void _save_vtxfmt_init( struct gl_context
*ctx
)
1015 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1016 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1018 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
1020 vfmt
->Begin
= _save_Begin
;
1021 vfmt
->Color3f
= _save_Color3f
;
1022 vfmt
->Color3fv
= _save_Color3fv
;
1023 vfmt
->Color4f
= _save_Color4f
;
1024 vfmt
->Color4fv
= _save_Color4fv
;
1025 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1026 vfmt
->End
= _save_End
;
1027 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1028 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1029 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1030 vfmt
->Indexf
= _save_Indexf
;
1031 vfmt
->Indexfv
= _save_Indexfv
;
1032 vfmt
->Materialfv
= _save_Materialfv
;
1033 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1034 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1035 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1036 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1037 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1038 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1039 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1040 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1041 vfmt
->Normal3f
= _save_Normal3f
;
1042 vfmt
->Normal3fv
= _save_Normal3fv
;
1043 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1044 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1045 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1046 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1047 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1048 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1049 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1050 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1051 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1052 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1053 vfmt
->Vertex2f
= _save_Vertex2f
;
1054 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1055 vfmt
->Vertex3f
= _save_Vertex3f
;
1056 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1057 vfmt
->Vertex4f
= _save_Vertex4f
;
1058 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1059 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1060 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1061 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1062 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1063 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1064 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1065 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1066 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1068 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1069 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1070 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1071 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1072 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1073 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1074 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1075 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1077 /* integer-valued */
1078 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1079 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1080 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1081 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1082 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1083 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1084 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1086 /* unsigned integer-valued */
1087 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1088 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1089 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1090 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1091 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1092 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1093 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1095 /* This will all require us to fallback to saving the list as opcodes:
1097 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1099 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1101 /* These are all errors as we at least know we are in some sort of
1104 vfmt
->Begin
= _save_Begin
;
1105 vfmt
->Rectf
= _save_Rectf
;
1106 vfmt
->DrawArrays
= _save_DrawArrays
;
1107 vfmt
->DrawElements
= _save_DrawElements
;
1108 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1109 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1110 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1111 /* Loops back into vfmt->DrawElements */
1112 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1113 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1117 void vbo_save_SaveFlushVertices( struct gl_context
*ctx
)
1119 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1121 /* Noop when we are actually active:
1123 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1124 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1127 if (save
->vert_count
||
1129 _save_compile_vertex_list( ctx
);
1131 _save_copy_to_current( ctx
);
1132 _save_reset_vertex( ctx
);
1133 _save_reset_counters( ctx
);
1134 ctx
->Driver
.SaveNeedFlush
= 0;
1137 void vbo_save_NewList( struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1139 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1141 (void) list
; (void) mode
;
1143 if (!save
->prim_store
)
1144 save
->prim_store
= alloc_prim_store( ctx
);
1146 if (!save
->vertex_store
)
1147 save
->vertex_store
= alloc_vertex_store( ctx
);
1149 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1151 _save_reset_vertex( ctx
);
1152 _save_reset_counters( ctx
);
1153 ctx
->Driver
.SaveNeedFlush
= 0;
1156 void vbo_save_EndList( struct gl_context
*ctx
)
1158 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1160 /* EndList called inside a (saved) Begin/End pair?
1162 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1164 if (save
->prim_count
> 0) {
1165 GLint i
= save
->prim_count
- 1;
1166 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1167 save
->prim
[i
].end
= 0;
1168 save
->prim
[i
].count
= (save
->vert_count
-
1169 save
->prim
[i
].start
);
1172 /* Make sure this vertex list gets replayed by the "loopback"
1175 save
->dangling_attr_ref
= 1;
1176 vbo_save_SaveFlushVertices( ctx
);
1178 /* Swap out this vertex format while outside begin/end. Any color,
1179 * etc. received between here and the next begin will be compiled
1182 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1185 unmap_vertex_store( ctx
, save
->vertex_store
);
1187 assert(save
->vertex_size
== 0);
1190 void vbo_save_BeginCallList( struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1192 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1193 save
->replay_flags
|= dlist
->Flags
;
1196 void vbo_save_EndCallList( struct gl_context
*ctx
)
1198 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1200 if (ctx
->ListState
.CallDepth
== 1) {
1201 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1202 * flag, if it is set:
1204 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1209 static void vbo_destroy_vertex_list( struct gl_context
*ctx
, void *data
)
1211 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1214 if ( --node
->vertex_store
->refcount
== 0 )
1215 free_vertex_store( ctx
, node
->vertex_store
);
1217 if ( --node
->prim_store
->refcount
== 0 )
1218 FREE( node
->prim_store
);
1220 if (node
->current_data
) {
1221 FREE(node
->current_data
);
1222 node
->current_data
= NULL
;
1227 static void vbo_print_vertex_list( struct gl_context
*ctx
, void *data
)
1229 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1233 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1238 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1239 struct _mesa_prim
*prim
= &node
->prim
[i
];
1240 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1242 _mesa_lookup_prim_by_nr(prim
->mode
),
1243 prim
->weak
? " (weak)" : "",
1245 prim
->start
+ prim
->count
,
1246 (prim
->begin
) ? "BEGIN" : "(wrap)",
1247 (prim
->end
) ? "END" : "(wrap)");
1252 static void _save_current_init( struct gl_context
*ctx
)
1254 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1257 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1258 const GLuint j
= i
- VBO_ATTRIB_POS
;
1259 ASSERT(j
< VERT_ATTRIB_MAX
);
1260 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1261 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1264 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1265 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1266 ASSERT(j
< MAT_ATTRIB_MAX
);
1267 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1268 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1273 * Initialize the display list compiler
1275 void vbo_save_api_init( struct vbo_save_context
*save
)
1277 struct gl_context
*ctx
= save
->ctx
;
1280 save
->opcode_vertex_list
=
1281 _mesa_dlist_alloc_opcode( ctx
,
1282 sizeof(struct vbo_save_vertex_list
),
1283 vbo_save_playback_vertex_list
,
1284 vbo_destroy_vertex_list
,
1285 vbo_print_vertex_list
);
1287 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1289 _save_vtxfmt_init( ctx
);
1290 _save_current_init( ctx
);
1292 /* These will actually get set again when binding/drawing */
1293 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1294 save
->inputs
[i
] = &save
->arrays
[i
];
1296 /* Hook our array functions into the outside-begin-end vtxfmt in
1299 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1300 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1301 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1302 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1303 /* loops back into _save_OBE_DrawElements */
1304 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1305 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1306 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1310 #endif /* FEATURE_dlist */