1 /**************************************************************************
3 Copyright 2002 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.
75 #include "api_validate.h"
76 #include "api_arrayelt.h"
80 #include "vbo_context.h"
85 * NOTE: Old 'parity' issue is gone, but copying can still be
86 * wrong-footed on replay.
88 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
89 const struct vbo_save_vertex_list
*node
,
90 const GLfloat
*src_buffer
)
92 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
93 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
94 GLuint nr
= prim
->count
;
95 GLuint sz
= save
->vertex_size
;
96 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
97 GLfloat
*dst
= save
->copied
.buffer
;
109 for (i
= 0 ; i
< ovf
; i
++)
110 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
114 for (i
= 0 ; i
< ovf
; i
++)
115 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
119 for (i
= 0 ; i
< ovf
; i
++)
120 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
126 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
130 case GL_TRIANGLE_FAN
:
135 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
138 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
139 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
142 case GL_TRIANGLE_STRIP
:
145 case 0: ovf
= 0; break;
146 case 1: ovf
= 1; break;
147 default: ovf
= 2 + (nr
&1); break;
149 for (i
= 0 ; i
< ovf
; i
++)
150 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
159 static struct vbo_save_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
161 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
163 /* obj->Name needs to be non-zero, but won't ever be examined more
164 * closely than that. In particular these buffers won't be entered
165 * into the hash and can never be confused with ones visible to the
166 * user. Perhaps there could be a special number for internal
169 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, 1, GL_ARRAY_BUFFER_ARB
);
171 ctx
->Driver
.BufferData( ctx
,
173 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
176 vertex_store
->bufferobj
);
178 vertex_store
->buffer
= NULL
;
179 vertex_store
->used
= 0;
180 vertex_store
->refcount
= 1;
185 static void free_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
187 assert(!vertex_store
->buffer
);
189 if (vertex_store
->bufferobj
)
190 ctx
->Driver
.DeleteBuffer( ctx
, vertex_store
->bufferobj
);
192 FREE( vertex_store
);
195 static GLfloat
*map_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
197 assert(vertex_store
->bufferobj
);
198 assert(!vertex_store
->buffer
);
199 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
200 GL_ARRAY_BUFFER_ARB
, /* not used */
201 GL_STATIC_DRAW_ARB
, /* not used */
202 vertex_store
->bufferobj
);
204 assert(vertex_store
->buffer
);
205 return vertex_store
->buffer
+ vertex_store
->used
;
208 static void unmap_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
210 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
211 vertex_store
->buffer
= NULL
;
215 static struct vbo_save_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
217 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
224 static void _save_reset_counters( GLcontext
*ctx
)
226 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
228 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
229 save
->buffer
= (save
->vertex_store
->buffer
+
230 save
->vertex_store
->used
);
232 assert(save
->buffer
== save
->vbptr
);
234 if (save
->vertex_size
)
235 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
240 save
->vert_count
= 0;
241 save
->prim_count
= 0;
242 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
243 save
->dangling_attr_ref
= 0;
247 /* Insert the active immediate struct onto the display list currently
250 static void _save_compile_vertex_list( GLcontext
*ctx
)
252 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
253 struct vbo_save_vertex_list
*node
;
255 /* Allocate space for this structure in the display list currently
258 node
= (struct vbo_save_vertex_list
*)
259 _mesa_alloc_instruction(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
264 /* Duplicate our template, increment refcounts to the storage structs:
266 _mesa_memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
267 node
->vertex_size
= save
->vertex_size
;
268 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
269 node
->count
= save
->vert_count
;
270 node
->wrap_count
= save
->copied
.nr
;
271 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
272 node
->prim
= save
->prim
;
273 node
->prim_count
= save
->prim_count
;
274 node
->vertex_store
= save
->vertex_store
;
275 node
->prim_store
= save
->prim_store
;
277 node
->vertex_store
->refcount
++;
278 node
->prim_store
->refcount
++;
280 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
283 if (save
->dangling_attr_ref
)
284 ctx
->ListState
.CurrentList
->flags
|= MESA_DLIST_DANGLING_REFS
;
286 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
287 save
->prim_store
->used
+= node
->prim_count
;
290 /* Copy duplicated vertices
292 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
295 /* Deal with GL_COMPILE_AND_EXECUTE:
297 if (ctx
->ExecuteFlag
) {
298 struct _glapi_table
*dispatch
= GET_DISPATCH();
300 _glapi_set_dispatch(ctx
->Exec
);
302 vbo_loopback_vertex_list( ctx
,
303 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
304 node
->buffer_offset
),
311 _glapi_set_dispatch(dispatch
);
315 /* Decide whether the storage structs are full, or can be used for
316 * the next vertex lists as well.
318 if (save
->vertex_store
->used
>
319 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
323 unmap_vertex_store( ctx
, save
->vertex_store
);
325 /* Release old reference:
327 save
->vertex_store
->refcount
--;
328 assert(save
->vertex_store
->refcount
!= 0);
329 save
->vertex_store
= NULL
;
331 /* Allocate and map new store:
333 save
->vertex_store
= alloc_vertex_store( ctx
);
334 save
->vbptr
= map_vertex_store( ctx
, save
->vertex_store
);
337 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
338 save
->prim_store
->refcount
--;
339 assert(save
->prim_store
->refcount
!= 0);
340 save
->prim_store
= alloc_prim_store( ctx
);
343 /* Reset our structures for the next run of vertices:
345 _save_reset_counters( ctx
);
349 /* TODO -- If no new vertices have been stored, don't bother saving
352 static void _save_wrap_buffers( GLcontext
*ctx
)
354 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
355 GLint i
= save
->prim_count
- 1;
359 assert(i
< (GLint
) save
->prim_max
);
362 /* Close off in-progress primitive.
364 save
->prim
[i
].count
= (save
->vert_count
-
365 save
->prim
[i
].start
);
366 mode
= save
->prim
[i
].mode
;
367 weak
= save
->prim
[i
].weak
;
369 /* store the copied vertices, and allocate a new list.
371 _save_compile_vertex_list( ctx
);
373 /* Restart interrupted primitive
375 save
->prim
[0].mode
= mode
;
376 save
->prim
[0].weak
= weak
;
377 save
->prim
[0].begin
= 0;
378 save
->prim
[0].end
= 0;
379 save
->prim
[0].pad
= 0;
380 save
->prim
[0].start
= 0;
381 save
->prim
[0].count
= 0;
382 save
->prim_count
= 1;
387 /* Called only when buffers are wrapped as the result of filling the
388 * vertex_store struct.
390 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
392 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
393 GLfloat
*data
= save
->copied
.buffer
;
396 /* Emit a glEnd to close off the last vertex list.
398 _save_wrap_buffers( ctx
);
400 /* Copy stored stored vertices to start of new list.
402 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
404 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
405 _mesa_memcpy( save
->vbptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
406 data
+= save
->vertex_size
;
407 save
->vbptr
+= save
->vertex_size
;
413 static void _save_copy_to_current( GLcontext
*ctx
)
415 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
418 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
419 if (save
->attrsz
[i
]) {
420 save
->currentsz
[i
][0] = save
->attrsz
[i
];
421 COPY_CLEAN_4V(save
->current
[i
],
429 static void _save_copy_from_current( GLcontext
*ctx
)
431 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
434 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
435 switch (save
->attrsz
[i
]) {
436 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
437 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
438 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
439 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
448 /* Flush existing data, set new attrib size, replay copied vertices.
450 static void _save_upgrade_vertex( GLcontext
*ctx
,
454 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
459 /* Store the current run of vertices, and emit a GL_END. Emit a
460 * BEGIN in the new buffer.
462 if (save
->vert_count
)
463 _save_wrap_buffers( ctx
);
465 assert( save
->copied
.nr
== 0 );
467 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
468 * when the attribute already exists in the vertex and is having
469 * its size increased.
471 _save_copy_to_current( ctx
);
475 oldsz
= save
->attrsz
[attr
];
476 save
->attrsz
[attr
] = newsz
;
478 save
->vertex_size
+= newsz
- oldsz
;
479 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
481 save
->vert_count
= 0;
483 /* Recalculate all the attrptr[] values:
485 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
486 if (save
->attrsz
[i
]) {
487 save
->attrptr
[i
] = tmp
;
488 tmp
+= save
->attrsz
[i
];
491 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
494 /* Copy from current to repopulate the vertex with correct values.
496 _save_copy_from_current( ctx
);
498 /* Replay stored vertices to translate them to new format here.
500 * If there are copied vertices and the new (upgraded) attribute
501 * has not been defined before, this list is somewhat degenerate,
502 * and will need fixup at runtime.
506 GLfloat
*data
= save
->copied
.buffer
;
507 GLfloat
*dest
= save
->buffer
;
510 /* Need to note this and fix up at runtime (or loopback):
512 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
514 save
->dangling_attr_ref
= GL_TRUE
;
517 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
518 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
519 if (save
->attrsz
[j
]) {
522 COPY_CLEAN_4V( dest
, oldsz
, data
);
527 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
532 GLint sz
= save
->attrsz
[j
];
533 COPY_SZ_4V( dest
, sz
, data
);
542 save
->vert_count
+= save
->copied
.nr
;
546 static void save_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
548 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
550 if (sz
> save
->attrsz
[attr
]) {
551 /* New size is larger. Need to flush existing vertices and get
552 * an enlarged vertex format.
554 _save_upgrade_vertex( ctx
, attr
, sz
);
556 else if (sz
< save
->active_sz
[attr
]) {
557 static GLfloat id
[4] = { 0, 0, 0, 1 };
560 /* New size is equal or smaller - just need to fill in some
563 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
564 save
->attrptr
[attr
][i
-1] = id
[i
-1];
567 save
->active_sz
[attr
] = sz
;
570 static void _save_reset_vertex( GLcontext
*ctx
)
572 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
575 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
577 save
->active_sz
[i
] = 0;
580 save
->vertex_size
= 0;
585 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
588 /* Only one size for each attribute may be active at once. Eg. if
589 * Color3f is installed/active, then Color4f may not be, even if the
590 * vertex actually contains 4 color coordinates. This is because the
591 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
592 * of the chooser function when switching between Color4f and Color3f.
594 #define ATTR( A, N, V0, V1, V2, V3 ) \
596 struct vbo_save_context *save = &vbo_context(ctx)->save; \
598 if (save->active_sz[A] != N) \
599 save_fixup_vertex(ctx, A, N); \
601 _mesa_printf("Attr %d, sz %d: %f %f %f %f\n", A, N, V0, V1, V2, V3 ); \
604 GLfloat *dest = save->attrptr[A]; \
605 if (N>0) dest[0] = V0; \
606 if (N>1) dest[1] = V1; \
607 if (N>2) dest[2] = V2; \
608 if (N>3) dest[3] = V3; \
614 for (i = 0; i < save->vertex_size; i++) \
615 save->vbptr[i] = save->vertex[i]; \
617 save->vbptr += save->vertex_size; \
619 if (++save->vert_count >= save->max_vert) \
620 _save_wrap_filled_vertex( ctx ); \
624 #define TAG(x) _save_##x
626 #include "vbo_attrib_tmp.h"
631 /* Cope with EvalCoord/CallList called within a begin/end object:
632 * -- Flush current buffer
633 * -- Fallback to opcodes for the rest of the begin/end object.
635 #define DO_FALLBACK(ctx) \
637 struct vbo_save_context *save = &vbo_context(ctx)->save; \
639 if (save->vert_count || save->prim_count) \
640 _save_compile_vertex_list( ctx ); \
642 _save_copy_to_current( ctx ); \
643 _save_reset_vertex( ctx ); \
644 _save_reset_counters( ctx ); \
645 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
646 ctx->Driver.SaveNeedFlush = 0; \
649 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
651 GET_CURRENT_CONTEXT(ctx
);
653 ctx
->Save
->EvalCoord1f( u
);
656 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
658 GET_CURRENT_CONTEXT(ctx
);
660 ctx
->Save
->EvalCoord1fv( v
);
663 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
665 GET_CURRENT_CONTEXT(ctx
);
667 ctx
->Save
->EvalCoord2f( u
, v
);
670 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
672 GET_CURRENT_CONTEXT(ctx
);
674 ctx
->Save
->EvalCoord2fv( v
);
677 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
679 GET_CURRENT_CONTEXT(ctx
);
681 ctx
->Save
->EvalPoint1( i
);
684 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
686 GET_CURRENT_CONTEXT(ctx
);
688 ctx
->Save
->EvalPoint2( i
, j
);
691 static void GLAPIENTRY
_save_CallList( GLuint l
)
693 GET_CURRENT_CONTEXT(ctx
);
695 ctx
->Save
->CallList( l
);
698 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
700 GET_CURRENT_CONTEXT(ctx
);
702 ctx
->Save
->CallLists( n
, type
, v
);
708 /* This begin is hooked into ... Updating of
709 * ctx->Driver.CurrentSavePrimitive is already taken care of.
711 GLboolean
vbo_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
713 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
715 GLuint i
= save
->prim_count
++;
717 assert(i
< save
->prim_max
);
718 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
719 save
->prim
[i
].begin
= 1;
720 save
->prim
[i
].end
= 0;
721 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
722 save
->prim
[i
].pad
= 0;
723 save
->prim
[i
].start
= save
->vert_count
;
724 save
->prim
[i
].count
= 0;
726 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
727 ctx
->Driver
.SaveNeedFlush
= 1;
733 static void GLAPIENTRY
_save_End( void )
735 GET_CURRENT_CONTEXT( ctx
);
736 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
737 GLint i
= save
->prim_count
- 1;
739 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
740 save
->prim
[i
].end
= 1;
741 save
->prim
[i
].count
= (save
->vert_count
-
742 save
->prim
[i
].start
);
744 if (i
== (GLint
) save
->prim_max
- 1) {
745 _save_compile_vertex_list( ctx
);
746 assert(save
->copied
.nr
== 0);
749 /* Swap out this vertex format while outside begin/end. Any color,
750 * etc. received between here and the next begin will be compiled
753 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
757 /* These are all errors as this vtxfmt is only installed inside
760 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
761 const GLvoid
*indices
)
763 GET_CURRENT_CONTEXT(ctx
);
764 (void) mode
; (void) count
; (void) type
; (void) indices
;
765 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
769 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
770 GLuint start
, GLuint end
,
771 GLsizei count
, GLenum type
,
772 const GLvoid
*indices
)
774 GET_CURRENT_CONTEXT(ctx
);
775 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
776 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
779 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
781 GET_CURRENT_CONTEXT(ctx
);
782 (void) mode
; (void) start
; (void) count
;
783 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
786 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
788 GET_CURRENT_CONTEXT(ctx
);
789 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
790 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
793 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
795 GET_CURRENT_CONTEXT(ctx
);
796 (void) mode
; (void) i1
; (void) i2
;
797 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
800 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
803 GET_CURRENT_CONTEXT(ctx
);
804 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
805 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
808 static void GLAPIENTRY
_save_Begin( GLenum mode
)
810 GET_CURRENT_CONTEXT( ctx
);
812 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
816 /* Unlike the functions above, these are to be hooked into the vtxfmt
817 * maintained in ctx->ListState, active when the list is known or
818 * suspected to be outside any begin/end primitive.
820 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
822 GET_CURRENT_CONTEXT(ctx
);
823 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
824 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
825 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
826 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
827 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
828 CALL_End(GET_DISPATCH(), ());
832 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
834 GET_CURRENT_CONTEXT(ctx
);
837 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
840 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
841 for (i
= 0; i
< count
; i
++)
842 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
843 CALL_End(GET_DISPATCH(), ());
846 /* Could do better by copying the arrays and element list intact and
847 * then emitting an indexed prim at runtime.
849 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
850 const GLvoid
*indices
)
852 GET_CURRENT_CONTEXT(ctx
);
855 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
858 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
861 case GL_UNSIGNED_BYTE
:
862 for (i
= 0 ; i
< count
; i
++)
863 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
865 case GL_UNSIGNED_SHORT
:
866 for (i
= 0 ; i
< count
; i
++)
867 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
869 case GL_UNSIGNED_INT
:
870 for (i
= 0 ; i
< count
; i
++)
871 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
874 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
878 CALL_End(GET_DISPATCH(), ());
881 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
882 GLuint start
, GLuint end
,
883 GLsizei count
, GLenum type
,
884 const GLvoid
*indices
)
886 GET_CURRENT_CONTEXT(ctx
);
887 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
889 count
, type
, indices
))
890 _save_OBE_DrawElements( mode
, count
, type
, indices
);
897 static void _save_vtxfmt_init( GLcontext
*ctx
)
899 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
900 GLvertexformat
*vfmt
= &save
->vtxfmt
;
902 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
903 vfmt
->Begin
= _save_Begin
;
904 vfmt
->Color3f
= _save_Color3f
;
905 vfmt
->Color3fv
= _save_Color3fv
;
906 vfmt
->Color4f
= _save_Color4f
;
907 vfmt
->Color4fv
= _save_Color4fv
;
908 vfmt
->EdgeFlag
= _save_EdgeFlag
;
909 vfmt
->End
= _save_End
;
910 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
911 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
912 vfmt
->Indexf
= _save_Indexf
;
913 vfmt
->Indexfv
= _save_Indexfv
;
914 vfmt
->Materialfv
= _save_Materialfv
;
915 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
916 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
917 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
918 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
919 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
920 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
921 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
922 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
923 vfmt
->Normal3f
= _save_Normal3f
;
924 vfmt
->Normal3fv
= _save_Normal3fv
;
925 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
926 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
927 vfmt
->TexCoord1f
= _save_TexCoord1f
;
928 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
929 vfmt
->TexCoord2f
= _save_TexCoord2f
;
930 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
931 vfmt
->TexCoord3f
= _save_TexCoord3f
;
932 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
933 vfmt
->TexCoord4f
= _save_TexCoord4f
;
934 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
935 vfmt
->Vertex2f
= _save_Vertex2f
;
936 vfmt
->Vertex2fv
= _save_Vertex2fv
;
937 vfmt
->Vertex3f
= _save_Vertex3f
;
938 vfmt
->Vertex3fv
= _save_Vertex3fv
;
939 vfmt
->Vertex4f
= _save_Vertex4f
;
940 vfmt
->Vertex4fv
= _save_Vertex4fv
;
941 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
942 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
943 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
944 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
945 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
946 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
947 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
948 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
950 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
951 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
952 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
953 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
954 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
955 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
956 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
957 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
959 /* This will all require us to fallback to saving the list as opcodes:
961 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
962 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
963 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
964 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
965 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
966 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
967 vfmt
->EvalPoint1
= _save_EvalPoint1
;
968 vfmt
->EvalPoint2
= _save_EvalPoint2
;
970 /* These are all errors as we at least know we are in some sort of
973 vfmt
->EvalMesh1
= _save_EvalMesh1
;
974 vfmt
->EvalMesh2
= _save_EvalMesh2
;
975 vfmt
->Begin
= _save_Begin
;
976 vfmt
->Rectf
= _save_Rectf
;
977 vfmt
->DrawArrays
= _save_DrawArrays
;
978 vfmt
->DrawElements
= _save_DrawElements
;
979 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
984 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
986 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
988 /* Noop when we are actually active:
990 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
991 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
994 if (save
->vert_count
||
996 _save_compile_vertex_list( ctx
);
998 _save_copy_to_current( ctx
);
999 _save_reset_vertex( ctx
);
1000 _save_reset_counters( ctx
);
1001 ctx
->Driver
.SaveNeedFlush
= 0;
1004 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1006 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1008 (void) list
; (void) mode
;
1010 if (!save
->prim_store
)
1011 save
->prim_store
= alloc_prim_store( ctx
);
1013 if (!save
->vertex_store
)
1014 save
->vertex_store
= alloc_vertex_store( ctx
);
1016 save
->vbptr
= map_vertex_store( ctx
, save
->vertex_store
);
1018 _save_reset_vertex( ctx
);
1019 _save_reset_counters( ctx
);
1020 ctx
->Driver
.SaveNeedFlush
= 0;
1023 void vbo_save_EndList( GLcontext
*ctx
)
1025 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1026 unmap_vertex_store( ctx
, save
->vertex_store
);
1028 assert(save
->vertex_size
== 0);
1031 void vbo_save_BeginCallList( GLcontext
*ctx
, struct mesa_display_list
*dlist
)
1033 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1034 save
->replay_flags
|= dlist
->flags
;
1037 void vbo_save_EndCallList( GLcontext
*ctx
)
1039 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1041 if (ctx
->ListState
.CallDepth
== 1) {
1042 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1043 * flag, if it is set:
1045 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1050 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1052 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1055 if ( --node
->vertex_store
->refcount
== 0 )
1056 free_vertex_store( ctx
, node
->vertex_store
);
1058 if ( --node
->prim_store
->refcount
== 0 )
1059 FREE( node
->prim_store
);
1063 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1065 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1069 _mesa_debug(NULL
, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1074 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1075 struct _mesa_prim
*prim
= &node
->prim
[i
];
1076 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1078 _mesa_lookup_enum_by_nr(prim
->mode
),
1079 prim
->weak
? " (weak)" : "",
1081 prim
->start
+ prim
->count
,
1082 (prim
->begin
) ? "BEGIN" : "(wrap)",
1083 (prim
->end
) ? "END" : "(wrap)");
1088 static void _save_current_init( GLcontext
*ctx
)
1090 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1093 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1094 const GLuint j
= i
- VBO_ATTRIB_POS
;
1095 ASSERT(j
< VERT_ATTRIB_MAX
);
1096 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1097 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1100 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1101 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1102 ASSERT(j
< MAT_ATTRIB_MAX
);
1103 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1104 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1109 * Initialize the display list compiler
1111 void vbo_save_api_init( struct vbo_save_context
*save
)
1113 GLcontext
*ctx
= save
->ctx
;
1116 save
->opcode_vertex_list
=
1117 _mesa_alloc_opcode( ctx
,
1118 sizeof(struct vbo_save_vertex_list
),
1119 vbo_save_playback_vertex_list
,
1120 vbo_destroy_vertex_list
,
1121 vbo_print_vertex_list
);
1123 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1125 _save_vtxfmt_init( ctx
);
1126 _save_current_init( ctx
);
1128 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1129 save
->inputs
[i
] = &save
->arrays
[i
];
1131 /* Hook our array functions into the outside-begin-end vtxfmt in
1134 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1135 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1136 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1137 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1138 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);