1 /**************************************************************************
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/macros.h"
76 #include "main/api_validate.h"
77 #include "main/api_arrayelt.h"
78 #include "main/vtxfmt.h"
79 #include "glapi/dispatch.h"
81 #include "vbo_context.h"
89 /* An interesting VBO number/name to help with debugging */
90 #define VBO_BUF_ID 12345
94 * NOTE: Old 'parity' issue is gone, but copying can still be
95 * wrong-footed on replay.
97 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
98 const struct vbo_save_vertex_list
*node
,
99 const GLfloat
*src_buffer
)
101 struct vbo_save_context
*save
= &vbo_context( ctx
)->save
;
102 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
-1];
103 GLuint nr
= prim
->count
;
104 GLuint sz
= save
->vertex_size
;
105 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
106 GLfloat
*dst
= save
->copied
.buffer
;
118 for (i
= 0 ; i
< ovf
; i
++)
119 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
123 for (i
= 0 ; i
< ovf
; i
++)
124 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
128 for (i
= 0 ; i
< ovf
; i
++)
129 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
135 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
139 case GL_TRIANGLE_FAN
:
144 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
147 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
148 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
151 case GL_TRIANGLE_STRIP
:
154 case 0: ovf
= 0; break;
155 case 1: ovf
= 1; break;
156 default: ovf
= 2 + (nr
&1); break;
158 for (i
= 0 ; i
< ovf
; i
++)
159 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
168 static struct vbo_save_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
170 struct vbo_save_vertex_store
*vertex_store
= CALLOC_STRUCT(vbo_save_vertex_store
);
172 /* obj->Name needs to be non-zero, but won't ever be examined more
173 * closely than that. In particular these buffers won't be entered
174 * into the hash and can never be confused with ones visible to the
175 * user. Perhaps there could be a special number for internal
178 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
180 GL_ARRAY_BUFFER_ARB
);
182 ctx
->Driver
.BufferData( ctx
,
184 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
187 vertex_store
->bufferobj
);
189 vertex_store
->buffer
= NULL
;
190 vertex_store
->used
= 0;
191 vertex_store
->refcount
= 1;
196 static void free_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
198 assert(!vertex_store
->buffer
);
200 if (vertex_store
->bufferobj
) {
201 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
204 FREE( vertex_store
);
207 static GLfloat
*map_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
209 assert(vertex_store
->bufferobj
);
210 assert(!vertex_store
->buffer
);
211 vertex_store
->buffer
= (GLfloat
*)ctx
->Driver
.MapBuffer(ctx
,
212 GL_ARRAY_BUFFER_ARB
, /* not used */
213 GL_WRITE_ONLY
, /* not used */
214 vertex_store
->bufferobj
);
216 assert(vertex_store
->buffer
);
217 return vertex_store
->buffer
+ vertex_store
->used
;
220 static void unmap_vertex_store( GLcontext
*ctx
, struct vbo_save_vertex_store
*vertex_store
)
222 ctx
->Driver
.UnmapBuffer( ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
223 vertex_store
->buffer
= NULL
;
227 static struct vbo_save_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
229 struct vbo_save_primitive_store
*store
= CALLOC_STRUCT(vbo_save_primitive_store
);
236 static void _save_reset_counters( GLcontext
*ctx
)
238 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
240 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
241 save
->buffer
= (save
->vertex_store
->buffer
+
242 save
->vertex_store
->used
);
244 assert(save
->buffer
== save
->buffer_ptr
);
246 if (save
->vertex_size
)
247 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
252 save
->vert_count
= 0;
253 save
->prim_count
= 0;
254 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
255 save
->dangling_attr_ref
= 0;
259 /* Insert the active immediate struct onto the display list currently
262 static void _save_compile_vertex_list( GLcontext
*ctx
)
264 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
265 struct vbo_save_vertex_list
*node
;
267 /* Allocate space for this structure in the display list currently
270 node
= (struct vbo_save_vertex_list
*)
271 _mesa_alloc_instruction(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
276 /* Duplicate our template, increment refcounts to the storage structs:
278 _mesa_memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
279 node
->vertex_size
= save
->vertex_size
;
280 node
->buffer_offset
= (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
281 node
->count
= save
->vert_count
;
282 node
->wrap_count
= save
->copied
.nr
;
283 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
284 node
->prim
= save
->prim
;
285 node
->prim_count
= save
->prim_count
;
286 node
->vertex_store
= save
->vertex_store
;
287 node
->prim_store
= save
->prim_store
;
289 node
->vertex_store
->refcount
++;
290 node
->prim_store
->refcount
++;
292 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 ||
295 if (save
->dangling_attr_ref
)
296 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
298 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
299 save
->prim_store
->used
+= node
->prim_count
;
302 /* Copy duplicated vertices
304 save
->copied
.nr
= _save_copy_vertices( ctx
, node
, save
->buffer
);
307 /* Deal with GL_COMPILE_AND_EXECUTE:
309 if (ctx
->ExecuteFlag
) {
310 struct _glapi_table
*dispatch
= GET_DISPATCH();
312 _glapi_set_dispatch(ctx
->Exec
);
314 vbo_loopback_vertex_list( ctx
,
315 (const GLfloat
*)((const char *)save
->vertex_store
->buffer
+
316 node
->buffer_offset
),
323 _glapi_set_dispatch(dispatch
);
327 /* Decide whether the storage structs are full, or can be used for
328 * the next vertex lists as well.
330 if (save
->vertex_store
->used
>
331 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
335 unmap_vertex_store( ctx
, save
->vertex_store
);
337 /* Release old reference:
339 save
->vertex_store
->refcount
--;
340 assert(save
->vertex_store
->refcount
!= 0);
341 save
->vertex_store
= NULL
;
343 /* Allocate and map new store:
345 save
->vertex_store
= alloc_vertex_store( ctx
);
346 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
349 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
350 save
->prim_store
->refcount
--;
351 assert(save
->prim_store
->refcount
!= 0);
352 save
->prim_store
= alloc_prim_store( ctx
);
355 /* Reset our structures for the next run of vertices:
357 _save_reset_counters( ctx
);
361 /* TODO -- If no new vertices have been stored, don't bother saving
364 static void _save_wrap_buffers( GLcontext
*ctx
)
366 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
367 GLint i
= save
->prim_count
- 1;
371 assert(i
< (GLint
) save
->prim_max
);
374 /* Close off in-progress primitive.
376 save
->prim
[i
].count
= (save
->vert_count
-
377 save
->prim
[i
].start
);
378 mode
= save
->prim
[i
].mode
;
379 weak
= save
->prim
[i
].weak
;
381 /* store the copied vertices, and allocate a new list.
383 _save_compile_vertex_list( ctx
);
385 /* Restart interrupted primitive
387 save
->prim
[0].mode
= mode
;
388 save
->prim
[0].weak
= weak
;
389 save
->prim
[0].begin
= 0;
390 save
->prim
[0].end
= 0;
391 save
->prim
[0].pad
= 0;
392 save
->prim
[0].start
= 0;
393 save
->prim
[0].count
= 0;
394 save
->prim_count
= 1;
399 /* Called only when buffers are wrapped as the result of filling the
400 * vertex_store struct.
402 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
404 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
405 GLfloat
*data
= save
->copied
.buffer
;
408 /* Emit a glEnd to close off the last vertex list.
410 _save_wrap_buffers( ctx
);
412 /* Copy stored stored vertices to start of new list.
414 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
416 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
417 _mesa_memcpy( save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
418 data
+= save
->vertex_size
;
419 save
->buffer_ptr
+= save
->vertex_size
;
425 static void _save_copy_to_current( GLcontext
*ctx
)
427 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
430 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
431 if (save
->attrsz
[i
]) {
432 save
->currentsz
[i
][0] = save
->attrsz
[i
];
433 COPY_CLEAN_4V(save
->current
[i
],
441 static void _save_copy_from_current( GLcontext
*ctx
)
443 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
446 for (i
= VBO_ATTRIB_POS
+1 ; i
< VBO_ATTRIB_MAX
; i
++) {
447 switch (save
->attrsz
[i
]) {
448 case 4: save
->attrptr
[i
][3] = save
->current
[i
][3];
449 case 3: save
->attrptr
[i
][2] = save
->current
[i
][2];
450 case 2: save
->attrptr
[i
][1] = save
->current
[i
][1];
451 case 1: save
->attrptr
[i
][0] = save
->current
[i
][0];
460 /* Flush existing data, set new attrib size, replay copied vertices.
462 static void _save_upgrade_vertex( GLcontext
*ctx
,
466 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
471 /* Store the current run of vertices, and emit a GL_END. Emit a
472 * BEGIN in the new buffer.
474 if (save
->vert_count
)
475 _save_wrap_buffers( ctx
);
477 assert( save
->copied
.nr
== 0 );
479 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
480 * when the attribute already exists in the vertex and is having
481 * its size increased.
483 _save_copy_to_current( ctx
);
487 oldsz
= save
->attrsz
[attr
];
488 save
->attrsz
[attr
] = newsz
;
490 save
->vertex_size
+= newsz
- oldsz
;
491 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
493 save
->vert_count
= 0;
495 /* Recalculate all the attrptr[] values:
497 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
498 if (save
->attrsz
[i
]) {
499 save
->attrptr
[i
] = tmp
;
500 tmp
+= save
->attrsz
[i
];
503 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
506 /* Copy from current to repopulate the vertex with correct values.
508 _save_copy_from_current( ctx
);
510 /* Replay stored vertices to translate them to new format here.
512 * If there are copied vertices and the new (upgraded) attribute
513 * has not been defined before, this list is somewhat degenerate,
514 * and will need fixup at runtime.
518 GLfloat
*data
= save
->copied
.buffer
;
519 GLfloat
*dest
= save
->buffer
;
522 /* Need to note this and fix up at runtime (or loopback):
524 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
526 save
->dangling_attr_ref
= GL_TRUE
;
529 for (i
= 0 ; i
< save
->copied
.nr
; i
++) {
530 for (j
= 0 ; j
< VBO_ATTRIB_MAX
; j
++) {
531 if (save
->attrsz
[j
]) {
534 COPY_CLEAN_4V( dest
, oldsz
, data
);
539 COPY_SZ_4V( dest
, newsz
, save
->current
[attr
] );
544 GLint sz
= save
->attrsz
[j
];
545 COPY_SZ_4V( dest
, sz
, data
);
553 save
->buffer_ptr
= dest
;
554 save
->vert_count
+= save
->copied
.nr
;
558 static void save_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
560 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
562 if (sz
> save
->attrsz
[attr
]) {
563 /* New size is larger. Need to flush existing vertices and get
564 * an enlarged vertex format.
566 _save_upgrade_vertex( ctx
, attr
, sz
);
568 else if (sz
< save
->active_sz
[attr
]) {
569 static GLfloat id
[4] = { 0, 0, 0, 1 };
572 /* New size is equal or smaller - just need to fill in some
575 for (i
= sz
; i
<= save
->attrsz
[attr
] ; i
++)
576 save
->attrptr
[attr
][i
-1] = id
[i
-1];
579 save
->active_sz
[attr
] = sz
;
582 static void _save_reset_vertex( GLcontext
*ctx
)
584 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
587 for (i
= 0 ; i
< VBO_ATTRIB_MAX
; i
++) {
589 save
->active_sz
[i
] = 0;
592 save
->vertex_size
= 0;
597 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
600 /* Only one size for each attribute may be active at once. Eg. if
601 * Color3f is installed/active, then Color4f may not be, even if the
602 * vertex actually contains 4 color coordinates. This is because the
603 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
604 * of the chooser function when switching between Color4f and Color3f.
606 #define ATTR( A, N, V0, V1, V2, V3 ) \
608 struct vbo_save_context *save = &vbo_context(ctx)->save; \
610 if (save->active_sz[A] != N) \
611 save_fixup_vertex(ctx, A, N); \
614 GLfloat *dest = save->attrptr[A]; \
615 if (N>0) dest[0] = V0; \
616 if (N>1) dest[1] = V1; \
617 if (N>2) dest[2] = V2; \
618 if (N>3) dest[3] = V3; \
624 for (i = 0; i < save->vertex_size; i++) \
625 save->buffer_ptr[i] = save->vertex[i]; \
627 save->buffer_ptr += save->vertex_size; \
629 if (++save->vert_count >= save->max_vert) \
630 _save_wrap_filled_vertex( ctx ); \
634 #define TAG(x) _save_##x
636 #include "vbo_attrib_tmp.h"
641 /* Cope with EvalCoord/CallList called within a begin/end object:
642 * -- Flush current buffer
643 * -- Fallback to opcodes for the rest of the begin/end object.
645 #define DO_FALLBACK(ctx) \
647 struct vbo_save_context *save = &vbo_context(ctx)->save; \
649 if (save->vert_count || save->prim_count) \
650 _save_compile_vertex_list( ctx ); \
652 _save_copy_to_current( ctx ); \
653 _save_reset_vertex( ctx ); \
654 _save_reset_counters( ctx ); \
655 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
656 ctx->Driver.SaveNeedFlush = 0; \
659 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
661 GET_CURRENT_CONTEXT(ctx
);
663 ctx
->Save
->EvalCoord1f( u
);
666 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
668 GET_CURRENT_CONTEXT(ctx
);
670 ctx
->Save
->EvalCoord1fv( v
);
673 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
675 GET_CURRENT_CONTEXT(ctx
);
677 ctx
->Save
->EvalCoord2f( u
, v
);
680 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
682 GET_CURRENT_CONTEXT(ctx
);
684 ctx
->Save
->EvalCoord2fv( v
);
687 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
689 GET_CURRENT_CONTEXT(ctx
);
691 ctx
->Save
->EvalPoint1( i
);
694 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
696 GET_CURRENT_CONTEXT(ctx
);
698 ctx
->Save
->EvalPoint2( i
, j
);
701 static void GLAPIENTRY
_save_CallList( GLuint l
)
703 GET_CURRENT_CONTEXT(ctx
);
705 ctx
->Save
->CallList( l
);
708 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
710 GET_CURRENT_CONTEXT(ctx
);
712 ctx
->Save
->CallLists( n
, type
, v
);
718 /* This begin is hooked into ... Updating of
719 * ctx->Driver.CurrentSavePrimitive is already taken care of.
721 GLboolean
vbo_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
723 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
725 GLuint i
= save
->prim_count
++;
727 assert(i
< save
->prim_max
);
728 save
->prim
[i
].mode
= mode
& ~VBO_SAVE_PRIM_WEAK
;
729 save
->prim
[i
].begin
= 1;
730 save
->prim
[i
].end
= 0;
731 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
732 save
->prim
[i
].pad
= 0;
733 save
->prim
[i
].start
= save
->vert_count
;
734 save
->prim
[i
].count
= 0;
736 _mesa_install_save_vtxfmt( ctx
, &save
->vtxfmt
);
737 ctx
->Driver
.SaveNeedFlush
= 1;
743 static void GLAPIENTRY
_save_End( void )
745 GET_CURRENT_CONTEXT( ctx
);
746 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
747 GLint i
= save
->prim_count
- 1;
749 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
750 save
->prim
[i
].end
= 1;
751 save
->prim
[i
].count
= (save
->vert_count
-
752 save
->prim
[i
].start
);
754 if (i
== (GLint
) save
->prim_max
- 1) {
755 _save_compile_vertex_list( ctx
);
756 assert(save
->copied
.nr
== 0);
759 /* Swap out this vertex format while outside begin/end. Any color,
760 * etc. received between here and the next begin will be compiled
763 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
767 /* These are all errors as this vtxfmt is only installed inside
770 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
771 const GLvoid
*indices
)
773 GET_CURRENT_CONTEXT(ctx
);
774 (void) mode
; (void) count
; (void) type
; (void) indices
;
775 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
779 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
780 GLuint start
, GLuint end
,
781 GLsizei count
, GLenum type
,
782 const GLvoid
*indices
)
784 GET_CURRENT_CONTEXT(ctx
);
785 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
786 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
789 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
791 GET_CURRENT_CONTEXT(ctx
);
792 (void) mode
; (void) start
; (void) count
;
793 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
796 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
798 GET_CURRENT_CONTEXT(ctx
);
799 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
800 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
803 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
805 GET_CURRENT_CONTEXT(ctx
);
806 (void) mode
; (void) i1
; (void) i2
;
807 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
810 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
813 GET_CURRENT_CONTEXT(ctx
);
814 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
815 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
818 static void GLAPIENTRY
_save_Begin( GLenum mode
)
820 GET_CURRENT_CONTEXT( ctx
);
822 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
826 /* Unlike the functions above, these are to be hooked into the vtxfmt
827 * maintained in ctx->ListState, active when the list is known or
828 * suspected to be outside any begin/end primitive.
830 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
832 GET_CURRENT_CONTEXT(ctx
);
833 vbo_save_NotifyBegin( ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
834 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
835 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
836 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
837 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
838 CALL_End(GET_DISPATCH(), ());
842 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
844 GET_CURRENT_CONTEXT(ctx
);
847 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
852 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
854 for (i
= 0; i
< count
; i
++)
855 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
856 CALL_End(GET_DISPATCH(), ());
858 _ae_unmap_vbos( ctx
);
861 /* Could do better by copying the arrays and element list intact and
862 * then emitting an indexed prim at runtime.
864 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
865 const GLvoid
*indices
)
867 GET_CURRENT_CONTEXT(ctx
);
870 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
875 if (ctx
->Array
.ElementArrayBufferObj
->Name
)
876 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
878 vbo_save_NotifyBegin( ctx
, mode
| VBO_SAVE_PRIM_WEAK
);
881 case GL_UNSIGNED_BYTE
:
882 for (i
= 0 ; i
< count
; i
++)
883 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
885 case GL_UNSIGNED_SHORT
:
886 for (i
= 0 ; i
< count
; i
++)
887 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
889 case GL_UNSIGNED_INT
:
890 for (i
= 0 ; i
< count
; i
++)
891 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
894 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
898 CALL_End(GET_DISPATCH(), ());
900 _ae_unmap_vbos( ctx
);
903 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
904 GLuint start
, GLuint end
,
905 GLsizei count
, GLenum type
,
906 const GLvoid
*indices
)
908 GET_CURRENT_CONTEXT(ctx
);
909 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
911 count
, type
, indices
))
912 _save_OBE_DrawElements( mode
, count
, type
, indices
);
919 static void _save_vtxfmt_init( GLcontext
*ctx
)
921 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
922 GLvertexformat
*vfmt
= &save
->vtxfmt
;
924 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
925 vfmt
->Begin
= _save_Begin
;
926 vfmt
->Color3f
= _save_Color3f
;
927 vfmt
->Color3fv
= _save_Color3fv
;
928 vfmt
->Color4f
= _save_Color4f
;
929 vfmt
->Color4fv
= _save_Color4fv
;
930 vfmt
->EdgeFlag
= _save_EdgeFlag
;
931 vfmt
->End
= _save_End
;
932 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
933 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
934 vfmt
->Indexf
= _save_Indexf
;
935 vfmt
->Indexfv
= _save_Indexfv
;
936 vfmt
->Materialfv
= _save_Materialfv
;
937 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
938 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
939 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
940 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
941 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
942 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
943 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
944 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
945 vfmt
->Normal3f
= _save_Normal3f
;
946 vfmt
->Normal3fv
= _save_Normal3fv
;
947 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
948 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
949 vfmt
->TexCoord1f
= _save_TexCoord1f
;
950 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
951 vfmt
->TexCoord2f
= _save_TexCoord2f
;
952 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
953 vfmt
->TexCoord3f
= _save_TexCoord3f
;
954 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
955 vfmt
->TexCoord4f
= _save_TexCoord4f
;
956 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
957 vfmt
->Vertex2f
= _save_Vertex2f
;
958 vfmt
->Vertex2fv
= _save_Vertex2fv
;
959 vfmt
->Vertex3f
= _save_Vertex3f
;
960 vfmt
->Vertex3fv
= _save_Vertex3fv
;
961 vfmt
->Vertex4f
= _save_Vertex4f
;
962 vfmt
->Vertex4fv
= _save_Vertex4fv
;
963 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
964 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
965 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
966 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
967 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
968 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
969 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
970 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
972 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
973 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
974 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
975 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
976 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
977 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
978 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
979 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
981 /* This will all require us to fallback to saving the list as opcodes:
983 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
984 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
985 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
986 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
987 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
988 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
989 vfmt
->EvalPoint1
= _save_EvalPoint1
;
990 vfmt
->EvalPoint2
= _save_EvalPoint2
;
992 /* These are all errors as we at least know we are in some sort of
995 vfmt
->EvalMesh1
= _save_EvalMesh1
;
996 vfmt
->EvalMesh2
= _save_EvalMesh2
;
997 vfmt
->Begin
= _save_Begin
;
998 vfmt
->Rectf
= _save_Rectf
;
999 vfmt
->DrawArrays
= _save_DrawArrays
;
1000 vfmt
->DrawElements
= _save_DrawElements
;
1001 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1006 void vbo_save_SaveFlushVertices( GLcontext
*ctx
)
1008 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1010 /* Noop when we are actually active:
1012 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1013 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1016 if (save
->vert_count
||
1018 _save_compile_vertex_list( ctx
);
1020 _save_copy_to_current( ctx
);
1021 _save_reset_vertex( ctx
);
1022 _save_reset_counters( ctx
);
1023 ctx
->Driver
.SaveNeedFlush
= 0;
1026 void vbo_save_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1028 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1030 (void) list
; (void) mode
;
1032 if (!save
->prim_store
)
1033 save
->prim_store
= alloc_prim_store( ctx
);
1035 if (!save
->vertex_store
)
1036 save
->vertex_store
= alloc_vertex_store( ctx
);
1038 save
->buffer_ptr
= map_vertex_store( ctx
, save
->vertex_store
);
1040 _save_reset_vertex( ctx
);
1041 _save_reset_counters( ctx
);
1042 ctx
->Driver
.SaveNeedFlush
= 0;
1045 void vbo_save_EndList( GLcontext
*ctx
)
1047 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1049 /* EndList called inside a (saved) Begin/End pair?
1051 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1053 if (save
->prim_count
> 0) {
1054 GLint i
= save
->prim_count
- 1;
1055 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1056 save
->prim
[i
].end
= 0;
1057 save
->prim
[i
].count
= (save
->vert_count
-
1058 save
->prim
[i
].start
);
1061 /* Make sure this vertex list gets replayed by the "loopback"
1064 save
->dangling_attr_ref
= 1;
1065 vbo_save_SaveFlushVertices( ctx
);
1067 /* Swap out this vertex format while outside begin/end. Any color,
1068 * etc. received between here and the next begin will be compiled
1071 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1074 unmap_vertex_store( ctx
, save
->vertex_store
);
1076 assert(save
->vertex_size
== 0);
1079 void vbo_save_BeginCallList( GLcontext
*ctx
, struct gl_display_list
*dlist
)
1081 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1082 save
->replay_flags
|= dlist
->Flags
;
1085 void vbo_save_EndCallList( GLcontext
*ctx
)
1087 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1089 if (ctx
->ListState
.CallDepth
== 1) {
1090 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1091 * flag, if it is set:
1093 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1098 static void vbo_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1100 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1103 if ( --node
->vertex_store
->refcount
== 0 )
1104 free_vertex_store( ctx
, node
->vertex_store
);
1106 if ( --node
->prim_store
->refcount
== 0 )
1107 FREE( node
->prim_store
);
1111 static void vbo_print_vertex_list( GLcontext
*ctx
, void *data
)
1113 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*)data
;
1117 _mesa_debug(NULL
, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1122 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1123 struct _mesa_prim
*prim
= &node
->prim
[i
];
1124 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1126 _mesa_lookup_enum_by_nr(prim
->mode
),
1127 prim
->weak
? " (weak)" : "",
1129 prim
->start
+ prim
->count
,
1130 (prim
->begin
) ? "BEGIN" : "(wrap)",
1131 (prim
->end
) ? "END" : "(wrap)");
1136 static void _save_current_init( GLcontext
*ctx
)
1138 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1141 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1142 const GLuint j
= i
- VBO_ATTRIB_POS
;
1143 ASSERT(j
< VERT_ATTRIB_MAX
);
1144 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1145 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1148 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1149 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1150 ASSERT(j
< MAT_ATTRIB_MAX
);
1151 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1152 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1157 * Initialize the display list compiler
1159 void vbo_save_api_init( struct vbo_save_context
*save
)
1161 GLcontext
*ctx
= save
->ctx
;
1164 save
->opcode_vertex_list
=
1165 _mesa_alloc_opcode( ctx
,
1166 sizeof(struct vbo_save_vertex_list
),
1167 vbo_save_playback_vertex_list
,
1168 vbo_destroy_vertex_list
,
1169 vbo_print_vertex_list
);
1171 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1173 _save_vtxfmt_init( ctx
);
1174 _save_current_init( ctx
);
1176 /* These will actually get set again when binding/drawing */
1177 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1178 save
->inputs
[i
] = &save
->arrays
[i
];
1180 /* Hook our array functions into the outside-begin-end vtxfmt in
1183 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1184 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1185 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1186 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1187 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);