1 /**************************************************************************
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/api_noop.h"
78 #include "main/api_validate.h"
79 #include "main/api_arrayelt.h"
80 #include "main/vtxfmt.h"
81 #include "glapi/dispatch.h"
83 #include "vbo_context.h"
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID 12345
96 * NOTE: Old 'parity' issue is gone, but copying can still be
97 * wrong-footed on replay.
99 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
100 const struct vbo_save_vertex_list
*node
,
101 const GLfloat
*src_buffer
)
103 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
104 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
105 GLuint nr
= prim
->count
;
106 GLuint sz
= save
->vertex_size
;
107 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
108 GLfloat
*dst
= save
->copied
.buffer
;
120 for (i
= 0 ; i
< ovf
; i
++)
121 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
125 for (i
= 0 ; i
< ovf
; i
++)
126 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
130 for (i
= 0 ; i
< ovf
; i
++)
131 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
137 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
141 case GL_TRIANGLE_FAN
:
146 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
149 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
150 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
153 case GL_TRIANGLE_STRIP
:
156 case 0: ovf
= 0; break;
157 case 1: ovf
= 1; break;
158 default: ovf
= 2 + (nr
&1); break;
160 for (i
= 0 ; i
< ovf
; i
++)
161 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
170 static struct vbo_save_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
172 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
174 /* obj->Name needs to be non-zero, but won't ever be examined more
175 * closely than that. In particular these buffers won't be entered
176 * into the hash and can never be confused with ones visible to the
177 * user. Perhaps there could be a special number for internal
180 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
182 GL_ARRAY_BUFFER_ARB
);
184 ctx
->Driver
.BufferData( ctx
,
186 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
189 vertex_store
->bufferobj
);
191 vertex_store
->buffer
= NULL
;
192 vertex_store
->used
= 0;
193 vertex_store
->refcount
= 1;
198 static void free_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
200 assert(!vertex_store
->buffer
);
202 if (vertex_store
->bufferobj
) {
203 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
206 FREE( vertex_store
);
209 static GLfloat
*map_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
211 assert(vertex_store
->bufferobj
);
212 assert(!vertex_store
->buffer
);
213 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
214 GL_ARRAY_BUFFER_ARB
, /* not used */
215 GL_WRITE_ONLY
, /* not used */
216 vertex_store
->bufferobj
);
218 assert(vertex_store
->buffer
);
219 return vertex_store
->buffer
+ vertex_store
->used
;
222 static void unmap_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
224 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
225 vertex_store
->buffer
= NULL
;
229 static struct vbo_save_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
231 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
238 static void _save_reset_counters( GLcontext
*ctx
)
240 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
242 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
243 save
->buffer
= (save
->vertex_store
->buffer
+
244 save
->vertex_store
->used
);
246 assert(save
->buffer
== save
->buffer_ptr
);
248 if (save
->vertex_size
)
249 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
254 save
->vert_count
= 0;
255 save
->prim_count
= 0;
256 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
257 save
->dangling_attr_ref
= 0;
261 /* Insert the active immediate struct onto the display list currently
264 static void _save_compile_vertex_list( GLcontext
*ctx
)
266 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
267 struct vbo_save_vertex_list
*node
;
269 /* Allocate space for this structure in the display list currently
272 node
= (struct vbo_save_vertex_list
*)
273 _mesa_alloc_instruction(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
278 /* Duplicate our template, increment refcounts to the storage structs:
280 _mesa_memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
281 node
->vertex_size
= save
->vertex_size
;
282 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
283 node
->count
= save
->vert_count
;
284 node
->wrap_count
= save
->copied
.nr
;
285 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
286 node
->prim
= save
->prim
;
287 node
->prim_count
= save
->prim_count
;
288 node
->vertex_store
= save
->vertex_store
;
289 node
->prim_store
= save
->prim_store
;
291 node
->vertex_store
->refcount
++;
292 node
->prim_store
->refcount
++;
295 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
296 node
->current_data
= NULL
;
298 if (node
->current_size
) {
299 /* If the malloc fails, we just pull the data out of the VBO
302 node
->current_data
= MALLOC( node
->current_size
* sizeof(GLfloat
) );
303 if (node
->current_data
) {
304 const char *buffer
= (const char *)save
->vertex_store
->buffer
;
305 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
306 unsigned vertex_offset
= 0;
309 vertex_offset
= (node
->count
-1) * node
->vertex_size
* sizeof(GLfloat
);
311 memcpy( node
->current_data
,
312 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
313 node
->current_size
* sizeof(GLfloat
) );
319 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
322 if (save
->dangling_attr_ref
)
323 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
325 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
326 save
->prim_store
->used
+= node
->prim_count
;
329 /* Copy duplicated vertices
331 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
334 /* Deal with GL_COMPILE_AND_EXECUTE:
336 if (ctx
->ExecuteFlag
) {
337 struct _glapi_table
*dispatch
= GET_DISPATCH();
339 _glapi_set_dispatch(ctx
->Exec
);
341 vbo_loopback_vertex_list( ctx
,
342 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
343 node
->buffer_offset
),
350 _glapi_set_dispatch(dispatch
);
354 /* Decide whether the storage structs are full, or can be used for
355 * the next vertex lists as well.
357 if (save
->vertex_store
->used
>
358 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
362 unmap_vertex_store( ctx
, save
->vertex_store
);
364 /* Release old reference:
366 save
->vertex_store
->refcount
--;
367 assert(save
->vertex_store
->refcount
!= 0);
368 save
->vertex_store
= NULL
;
370 /* Allocate and map new store:
372 save
->vertex_store
= alloc_vertex_store( ctx
);
373 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
376 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
377 save
->prim_store
->refcount
--;
378 assert(save
->prim_store
->refcount
!= 0);
379 save
->prim_store
= alloc_prim_store( ctx
);
382 /* Reset our structures for the next run of vertices:
384 _save_reset_counters( ctx
);
388 /* TODO -- If no new vertices have been stored, don't bother saving
391 static void _save_wrap_buffers( GLcontext
*ctx
)
393 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
394 GLint i
= save
->prim_count
- 1;
398 assert(i
< (GLint
) save
->prim_max
);
401 /* Close off in-progress primitive.
403 save
->prim
[i
].count
= (save
->vert_count
-
404 save
->prim
[i
].start
);
405 mode
= save
->prim
[i
].mode
;
406 weak
= save
->prim
[i
].weak
;
408 /* store the copied vertices, and allocate a new list.
410 _save_compile_vertex_list( ctx
);
412 /* Restart interrupted primitive
414 save
->prim
[0].mode
= mode
;
415 save
->prim
[0].weak
= weak
;
416 save
->prim
[0].begin
= 0;
417 save
->prim
[0].end
= 0;
418 save
->prim
[0].pad
= 0;
419 save
->prim
[0].start
= 0;
420 save
->prim
[0].count
= 0;
421 save
->prim_count
= 1;
426 /* Called only when buffers are wrapped as the result of filling the
427 * vertex_store struct.
429 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
431 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
432 GLfloat
*data
= save
->copied
.buffer
;
435 /* Emit a glEnd to close off the last vertex list.
437 _save_wrap_buffers( ctx
);
439 /* Copy stored stored vertices to start of new list.
441 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
443 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
444 _mesa_memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
445 data
+= save
->vertex_size
;
446 save
->buffer_ptr
+= save
->vertex_size
;
452 static void _save_copy_to_current( GLcontext
*ctx
)
454 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
457 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
458 if (save
->attrsz
[i
]) {
459 save
->currentsz
[i
][0] = save
->attrsz
[i
];
460 COPY_CLEAN_4V(save
->current
[i
],
468 static void _save_copy_from_current( GLcontext
*ctx
)
470 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
473 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
474 switch (save
->attrsz
[i
]) {
475 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
476 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
477 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
478 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
487 /* Flush existing data, set new attrib size, replay copied vertices.
489 static void _save_upgrade_vertex( GLcontext
*ctx
,
493 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
498 /* Store the current run of vertices, and emit a GL_END. Emit a
499 * BEGIN in the new buffer.
501 if (save
->vert_count
)
502 _save_wrap_buffers( ctx
);
504 assert( save
->copied
.nr
== 0 );
506 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
507 * when the attribute already exists in the vertex and is having
508 * its size increased.
510 _save_copy_to_current( ctx
);
514 oldsz
= save
->attrsz
[attr
];
515 save
->attrsz
[attr
] = newsz
;
517 save
->vertex_size
+= newsz
- oldsz
;
518 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
520 save
->vert_count
= 0;
522 /* Recalculate all the attrptr[] values:
524 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
525 if (save
->attrsz
[i
]) {
526 save
->attrptr
[i
] = tmp
;
527 tmp
+= save
->attrsz
[i
];
530 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
533 /* Copy from current to repopulate the vertex with correct values.
535 _save_copy_from_current( ctx
);
537 /* Replay stored vertices to translate them to new format here.
539 * If there are copied vertices and the new (upgraded) attribute
540 * has not been defined before, this list is somewhat degenerate,
541 * and will need fixup at runtime.
545 GLfloat
*data
= save
->copied
.buffer
;
546 GLfloat
*dest
= save
->buffer
;
549 /* Need to note this and fix up at runtime (or loopback):
551 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
553 save
->dangling_attr_ref
= GL_TRUE
;
556 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
557 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
558 if (save
->attrsz
[j
]) {
561 COPY_CLEAN_4V( dest
, oldsz
, data
);
566 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
571 GLint sz
= save
->attrsz
[j
];
572 COPY_SZ_4V( dest
, sz
, data
);
580 save
->buffer_ptr
= dest
;
581 save
->vert_count
+= save
->copied
.nr
;
585 static void save_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
587 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
589 if (sz
> save
->attrsz
[attr
]) {
590 /* New size is larger. Need to flush existing vertices and get
591 * an enlarged vertex format.
593 _save_upgrade_vertex( ctx
, attr
, sz
);
595 else if (sz
< save
->active_sz
[attr
]) {
596 static GLfloat id
[4] = { 0, 0, 0, 1 };
599 /* New size is equal or smaller - just need to fill in some
602 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
603 save
->attrptr
[attr
][i
-1] = id
[i
-1];
606 save
->active_sz
[attr
] = sz
;
609 static void _save_reset_vertex( GLcontext
*ctx
)
611 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
614 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
616 save
->active_sz
[i
] = 0;
619 save
->vertex_size
= 0;
624 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
627 /* Only one size for each attribute may be active at once. Eg. if
628 * Color3f is installed/active, then Color4f may not be, even if the
629 * vertex actually contains 4 color coordinates. This is because the
630 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
631 * of the chooser function when switching between Color4f and Color3f.
633 #define ATTR( A, N, V0, V1, V2, V3 ) \
635 struct vbo_save_context *save = &vbo_context(ctx)->save; \
637 if (save->active_sz[A] != N) \
638 save_fixup_vertex(ctx, A, N); \
641 GLfloat *dest = save->attrptr[A]; \
642 if (N>0) dest[0] = V0; \
643 if (N>1) dest[1] = V1; \
644 if (N>2) dest[2] = V2; \
645 if (N>3) dest[3] = V3; \
651 for (i = 0; i < save->vertex_size; i++) \
652 save->buffer_ptr[i] = save->vertex[i]; \
654 save->buffer_ptr += save->vertex_size; \
656 if (++save->vert_count >= save->max_vert) \
657 _save_wrap_filled_vertex( ctx ); \
661 #define TAG(x) _save_##x
663 #include "vbo_attrib_tmp.h"
668 /* Cope with EvalCoord/CallList called within a begin/end object:
669 * -- Flush current buffer
670 * -- Fallback to opcodes for the rest of the begin/end object.
672 static void DO_FALLBACK( GLcontext
*ctx
)
674 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
676 if (save
->vert_count
|| save
->prim_count
) {
677 GLint i
= save
->prim_count
- 1;
679 /* Close off in-progress primitive.
681 save
->prim
[i
].count
= (save
->vert_count
-
682 save
->prim
[i
].start
);
684 /* Need to replay this display list with loopback,
685 * unfortunately, otherwise this primitive won't be handled
688 save
->dangling_attr_ref
= 1;
690 _save_compile_vertex_list( ctx
);
693 _save_copy_to_current( ctx
);
694 _save_reset_vertex( ctx
);
695 _save_reset_counters( ctx
);
696 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
697 ctx
->Driver
.SaveNeedFlush
= 0;
700 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
702 GET_CURRENT_CONTEXT(ctx
);
704 ctx
->Save
->EvalCoord1f( u
);
707 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
709 GET_CURRENT_CONTEXT(ctx
);
711 ctx
->Save
->EvalCoord1fv( v
);
714 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
716 GET_CURRENT_CONTEXT(ctx
);
718 ctx
->Save
->EvalCoord2f( u
, v
);
721 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
723 GET_CURRENT_CONTEXT(ctx
);
725 ctx
->Save
->EvalCoord2fv( v
);
728 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
730 GET_CURRENT_CONTEXT(ctx
);
732 ctx
->Save
->EvalPoint1( i
);
735 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
737 GET_CURRENT_CONTEXT(ctx
);
739 ctx
->Save
->EvalPoint2( i
, j
);
742 static void GLAPIENTRY
_save_CallList( GLuint l
)
744 GET_CURRENT_CONTEXT(ctx
);
746 ctx
->Save
->CallList( l
);
749 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
751 GET_CURRENT_CONTEXT(ctx
);
753 ctx
->Save
->CallLists( n
, type
, v
);
759 /* This begin is hooked into ... Updating of
760 * ctx->Driver.CurrentSavePrimitive is already taken care of.
762 GLboolean
vbo_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
764 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
766 GLuint i
= save
->prim_count
++;
768 assert(i
< save
->prim_max
);
769 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
770 save
->prim
[i
].begin
= 1;
771 save
->prim
[i
].end
= 0;
772 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
773 save
->prim
[i
].pad
= 0;
774 save
->prim
[i
].start
= save
->vert_count
;
775 save
->prim
[i
].count
= 0;
777 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
778 ctx
->Driver
.SaveNeedFlush
= 1;
784 static void GLAPIENTRY
_save_End( void )
786 GET_CURRENT_CONTEXT( ctx
);
787 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
788 GLint i
= save
->prim_count
- 1;
790 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
791 save
->prim
[i
].end
= 1;
792 save
->prim
[i
].count
= (save
->vert_count
-
793 save
->prim
[i
].start
);
795 if (i
== (GLint
) save
->prim_max
- 1) {
796 _save_compile_vertex_list( ctx
);
797 assert(save
->copied
.nr
== 0);
800 /* Swap out this vertex format while outside begin/end. Any color,
801 * etc. received between here and the next begin will be compiled
804 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
808 /* These are all errors as this vtxfmt is only installed inside
811 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
812 const GLvoid
*indices
)
814 GET_CURRENT_CONTEXT(ctx
);
815 (void) mode
; (void) count
; (void) type
; (void) indices
;
816 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
820 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
821 GLuint start
, GLuint end
,
822 GLsizei count
, GLenum type
,
823 const GLvoid
*indices
)
825 GET_CURRENT_CONTEXT(ctx
);
826 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
827 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
830 static void GLAPIENTRY
_save_DrawElementsBaseVertex(GLenum mode
,
833 const GLvoid
*indices
,
836 GET_CURRENT_CONTEXT(ctx
);
837 (void) mode
; (void) count
; (void) type
; (void) indices
; (void)basevertex
;
839 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
842 static void GLAPIENTRY
_save_DrawRangeElementsBaseVertex(GLenum mode
,
847 const GLvoid
*indices
,
850 GET_CURRENT_CONTEXT(ctx
);
851 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
;
852 (void) indices
; (void)basevertex
;
854 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
857 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
859 GET_CURRENT_CONTEXT(ctx
);
860 (void) mode
; (void) start
; (void) count
;
861 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
864 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
866 GET_CURRENT_CONTEXT(ctx
);
867 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
868 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
871 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
873 GET_CURRENT_CONTEXT(ctx
);
874 (void) mode
; (void) i1
; (void) i2
;
875 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
878 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
881 GET_CURRENT_CONTEXT(ctx
);
882 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
883 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
886 static void GLAPIENTRY
_save_Begin( GLenum mode
)
888 GET_CURRENT_CONTEXT( ctx
);
890 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
894 /* Unlike the functions above, these are to be hooked into the vtxfmt
895 * maintained in ctx->ListState, active when the list is known or
896 * suspected to be outside any begin/end primitive.
898 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
900 GET_CURRENT_CONTEXT(ctx
);
901 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
902 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
903 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
904 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
905 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
906 CALL_End(GET_DISPATCH(), ());
910 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
912 GET_CURRENT_CONTEXT(ctx
);
915 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
920 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
922 for (i
= 0; i
< count
; i
++)
923 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
924 CALL_End(GET_DISPATCH(), ());
926 _ae_unmap_vbos( ctx
);
929 /* Could do better by copying the arrays and element list intact and
930 * then emitting an indexed prim at runtime.
932 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
933 const GLvoid
*indices
)
935 GET_CURRENT_CONTEXT(ctx
);
938 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
, 0 ))
943 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
944 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
946 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
949 case GL_UNSIGNED_BYTE
:
950 for (i
= 0 ; i
< count
; i
++)
951 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
953 case GL_UNSIGNED_SHORT
:
954 for (i
= 0 ; i
< count
; i
++)
955 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
957 case GL_UNSIGNED_INT
:
958 for (i
= 0 ; i
< count
; i
++)
959 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
962 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
966 CALL_End(GET_DISPATCH(), ());
968 _ae_unmap_vbos( ctx
);
971 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
972 GLuint start
, GLuint end
,
973 GLsizei count
, GLenum type
,
974 const GLvoid
*indices
)
976 GET_CURRENT_CONTEXT(ctx
);
977 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
979 count
, type
, indices
, 0 ))
980 _save_OBE_DrawElements( mode
, count
, type
, indices
);
987 static void _save_vtxfmt_init( GLcontext
*ctx
)
989 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
990 GLvertexformat
*vfmt
= &save
->vtxfmt
;
992 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
994 vfmt
->Begin
= _save_Begin
;
995 vfmt
->Color3f
= _save_Color3f
;
996 vfmt
->Color3fv
= _save_Color3fv
;
997 vfmt
->Color4f
= _save_Color4f
;
998 vfmt
->Color4fv
= _save_Color4fv
;
999 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1000 vfmt
->End
= _save_End
;
1001 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1002 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1003 vfmt
->Indexf
= _save_Indexf
;
1004 vfmt
->Indexfv
= _save_Indexfv
;
1005 vfmt
->Materialfv
= _save_Materialfv
;
1006 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1007 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1008 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1009 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1010 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1011 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1012 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1013 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1014 vfmt
->Normal3f
= _save_Normal3f
;
1015 vfmt
->Normal3fv
= _save_Normal3fv
;
1016 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1017 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1018 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1019 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1020 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1021 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1022 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1023 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1024 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1025 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1026 vfmt
->Vertex2f
= _save_Vertex2f
;
1027 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1028 vfmt
->Vertex3f
= _save_Vertex3f
;
1029 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1030 vfmt
->Vertex4f
= _save_Vertex4f
;
1031 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1032 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1033 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1034 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1035 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1036 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1037 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1038 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1039 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1041 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1042 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1043 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1044 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1045 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1046 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1047 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1048 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1050 /* This will all require us to fallback to saving the list as opcodes:
1052 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1053 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1055 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1057 /* These are all errors as we at least know we are in some sort of
1060 vfmt
->Begin
= _save_Begin
;
1061 vfmt
->Rectf
= _save_Rectf
;
1062 vfmt
->DrawArrays
= _save_DrawArrays
;
1063 vfmt
->DrawElements
= _save_DrawElements
;
1064 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1065 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1066 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1067 /* Loops back into vfmt->DrawElements */
1068 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1069 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1073 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
1075 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1077 /* Noop when we are actually active:
1079 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1080 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1083 if (save
->vert_count
||
1085 _save_compile_vertex_list( ctx
);
1087 _save_copy_to_current( ctx
);
1088 _save_reset_vertex( ctx
);
1089 _save_reset_counters( ctx
);
1090 ctx
->Driver
.SaveNeedFlush
= 0;
1093 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1095 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1097 (void) list
; (void) mode
;
1099 if (!save
->prim_store
)
1100 save
->prim_store
= alloc_prim_store( ctx
);
1102 if (!save
->vertex_store
)
1103 save
->vertex_store
= alloc_vertex_store( ctx
);
1105 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1107 _save_reset_vertex( ctx
);
1108 _save_reset_counters( ctx
);
1109 ctx
->Driver
.SaveNeedFlush
= 0;
1112 void vbo_save_EndList( GLcontext
*ctx
)
1114 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1116 /* EndList called inside a (saved) Begin/End pair?
1118 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1120 if (save
->prim_count
> 0) {
1121 GLint i
= save
->prim_count
- 1;
1122 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1123 save
->prim
[i
].end
= 0;
1124 save
->prim
[i
].count
= (save
->vert_count
-
1125 save
->prim
[i
].start
);
1128 /* Make sure this vertex list gets replayed by the "loopback"
1131 save
->dangling_attr_ref
= 1;
1132 vbo_save_SaveFlushVertices( ctx
);
1134 /* Swap out this vertex format while outside begin/end. Any color,
1135 * etc. received between here and the next begin will be compiled
1138 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1141 unmap_vertex_store( ctx
, save
->vertex_store
);
1143 assert(save
->vertex_size
== 0);
1146 void vbo_save_BeginCallList( GLcontext
*ctx
, struct gl_display_list
*dlist
)
1148 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1149 save
->replay_flags
|= dlist
->Flags
;
1152 void vbo_save_EndCallList( GLcontext
*ctx
)
1154 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1156 if (ctx
->ListState
.CallDepth
== 1) {
1157 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1158 * flag, if it is set:
1160 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1165 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1167 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1170 if ( --node
->vertex_store
->refcount
== 0 )
1171 free_vertex_store( ctx
, node
->vertex_store
);
1173 if ( --node
->prim_store
->refcount
== 0 )
1174 FREE( node
->prim_store
);
1176 if (node
->current_data
) {
1177 FREE(node
->current_data
);
1178 node
->current_data
= NULL
;
1183 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1185 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1189 _mesa_printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1194 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1195 struct _mesa_prim
*prim
= &node
->prim
[i
];
1196 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1198 _mesa_lookup_prim_by_nr(prim
->mode
),
1199 prim
->weak
? " (weak)" : "",
1201 prim
->start
+ prim
->count
,
1202 (prim
->begin
) ? "BEGIN" : "(wrap)",
1203 (prim
->end
) ? "END" : "(wrap)");
1208 static void _save_current_init( GLcontext
*ctx
)
1210 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1213 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1214 const GLuint j
= i
- VBO_ATTRIB_POS
;
1215 ASSERT(j
< VERT_ATTRIB_MAX
);
1216 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1217 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1220 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1221 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1222 ASSERT(j
< MAT_ATTRIB_MAX
);
1223 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1224 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1229 * Initialize the display list compiler
1231 void vbo_save_api_init( struct vbo_save_context
*save
)
1233 GLcontext
*ctx
= save
->ctx
;
1236 save
->opcode_vertex_list
=
1237 _mesa_alloc_opcode( ctx
,
1238 sizeof(struct vbo_save_vertex_list
),
1239 vbo_save_playback_vertex_list
,
1240 vbo_destroy_vertex_list
,
1241 vbo_print_vertex_list
);
1243 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1245 _save_vtxfmt_init( ctx
);
1246 _save_current_init( ctx
);
1248 /* These will actually get set again when binding/drawing */
1249 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1250 save
->inputs
[i
] = &save
->arrays
[i
];
1252 /* Hook our array functions into the outside-begin-end vtxfmt in
1255 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1256 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1257 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1258 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1259 /* loops back into _save_OBE_DrawElements */
1260 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1261 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1262 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);