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_validate.h"
78 #include "main/api_arrayelt.h"
79 #include "main/vtxfmt.h"
80 #include "main/dispatch.h"
82 #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.
100 _save_copy_vertices(struct gl_context
*ctx
,
101 const struct vbo_save_vertex_list
*node
,
102 const GLfloat
* src_buffer
)
104 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
105 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
- 1];
106 GLuint nr
= prim
->count
;
107 GLuint sz
= save
->vertex_size
;
108 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
109 GLfloat
*dst
= save
->copied
.buffer
;
115 switch (prim
->mode
) {
120 for (i
= 0; i
< ovf
; i
++)
121 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
122 sz
* sizeof(GLfloat
));
126 for (i
= 0; i
< ovf
; i
++)
127 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
128 sz
* sizeof(GLfloat
));
132 for (i
= 0; i
< ovf
; i
++)
133 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
134 sz
* sizeof(GLfloat
));
140 memcpy(dst
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
144 case GL_TRIANGLE_FAN
:
149 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
153 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
154 memcpy(dst
+ sz
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
157 case GL_TRIANGLE_STRIP
:
170 for (i
= 0; i
< ovf
; i
++)
171 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
172 sz
* sizeof(GLfloat
));
181 static struct vbo_save_vertex_store
*
182 alloc_vertex_store(struct gl_context
*ctx
)
184 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
185 struct vbo_save_vertex_store
*vertex_store
=
186 CALLOC_STRUCT(vbo_save_vertex_store
);
188 /* obj->Name needs to be non-zero, but won't ever be examined more
189 * closely than that. In particular these buffers won't be entered
190 * into the hash and can never be confused with ones visible to the
191 * user. Perhaps there could be a special number for internal
194 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
196 GL_ARRAY_BUFFER_ARB
);
197 if (vertex_store
->bufferobj
) {
198 save
->out_of_memory
=
199 !ctx
->Driver
.BufferData(ctx
,
201 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
202 NULL
, GL_STATIC_DRAW_ARB
,
203 vertex_store
->bufferobj
);
206 save
->out_of_memory
= GL_TRUE
;
209 if (save
->out_of_memory
) {
210 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "internal VBO allocation");
211 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
214 vertex_store
->buffer
= NULL
;
215 vertex_store
->used
= 0;
216 vertex_store
->refcount
= 1;
223 free_vertex_store(struct gl_context
*ctx
,
224 struct vbo_save_vertex_store
*vertex_store
)
226 assert(!vertex_store
->buffer
);
228 if (vertex_store
->bufferobj
) {
229 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
237 vbo_save_map_vertex_store(struct gl_context
*ctx
,
238 struct vbo_save_vertex_store
*vertex_store
)
240 assert(vertex_store
->bufferobj
);
241 assert(!vertex_store
->buffer
);
242 if (vertex_store
->bufferobj
->Size
> 0) {
243 vertex_store
->buffer
=
244 (GLfloat
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
245 vertex_store
->bufferobj
->Size
,
246 GL_MAP_WRITE_BIT
, /* not used */
247 vertex_store
->bufferobj
);
248 assert(vertex_store
->buffer
);
249 return vertex_store
->buffer
+ vertex_store
->used
;
252 /* probably ran out of memory for buffers */
259 vbo_save_unmap_vertex_store(struct gl_context
*ctx
,
260 struct vbo_save_vertex_store
*vertex_store
)
262 if (vertex_store
->bufferobj
->Size
> 0) {
263 ctx
->Driver
.UnmapBuffer(ctx
, vertex_store
->bufferobj
);
265 vertex_store
->buffer
= NULL
;
269 static struct vbo_save_primitive_store
*
270 alloc_prim_store(struct gl_context
*ctx
)
272 struct vbo_save_primitive_store
*store
=
273 CALLOC_STRUCT(vbo_save_primitive_store
);
282 _save_reset_counters(struct gl_context
*ctx
)
284 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
286 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
287 save
->buffer
= save
->vertex_store
->buffer
+ save
->vertex_store
->used
;
289 assert(save
->buffer
== save
->buffer_ptr
);
291 if (save
->vertex_size
)
292 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
297 save
->vert_count
= 0;
298 save
->prim_count
= 0;
299 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
300 save
->dangling_attr_ref
= 0;
304 * For a list of prims, try merging prims that can just be extensions of the
308 merge_prims(struct gl_context
*ctx
,
309 struct _mesa_prim
*prim_list
,
313 struct _mesa_prim
*prev_prim
= prim_list
;
315 for (i
= 1; i
< *prim_count
; i
++) {
316 struct _mesa_prim
*this_prim
= prim_list
+ i
;
318 vbo_try_prim_conversion(this_prim
);
320 if (vbo_can_merge_prims(prev_prim
, this_prim
)) {
321 /* We've found a prim that just extend the previous one. Tack it
322 * onto the previous one, and let this primitive struct get dropped.
324 vbo_merge_prims(prev_prim
, this_prim
);
328 /* If any previous primitives have been dropped, then we need to copy
329 * this later one into the next available slot.
332 if (prev_prim
!= this_prim
)
333 *prev_prim
= *this_prim
;
336 *prim_count
= prev_prim
- prim_list
+ 1;
340 * Insert the active immediate struct onto the display list currently
344 _save_compile_vertex_list(struct gl_context
*ctx
)
346 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
347 struct vbo_save_vertex_list
*node
;
349 /* Allocate space for this structure in the display list currently
352 node
= (struct vbo_save_vertex_list
*)
353 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
358 /* Duplicate our template, increment refcounts to the storage structs:
360 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
361 memcpy(node
->attrtype
, save
->attrtype
, sizeof(node
->attrtype
));
362 node
->vertex_size
= save
->vertex_size
;
363 node
->buffer_offset
=
364 (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
365 node
->count
= save
->vert_count
;
366 node
->wrap_count
= save
->copied
.nr
;
367 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
368 node
->prim
= save
->prim
;
369 node
->prim_count
= save
->prim_count
;
370 node
->vertex_store
= save
->vertex_store
;
371 node
->prim_store
= save
->prim_store
;
373 node
->vertex_store
->refcount
++;
374 node
->prim_store
->refcount
++;
376 if (node
->prim
[0].no_current_update
) {
377 node
->current_size
= 0;
378 node
->current_data
= NULL
;
381 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
382 node
->current_data
= NULL
;
384 if (node
->current_size
) {
385 /* If the malloc fails, we just pull the data out of the VBO
388 node
->current_data
= malloc(node
->current_size
* sizeof(GLfloat
));
389 if (node
->current_data
) {
390 const char *buffer
= (const char *) save
->vertex_store
->buffer
;
391 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
392 unsigned vertex_offset
= 0;
396 (node
->count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
398 memcpy(node
->current_data
,
399 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
400 node
->current_size
* sizeof(GLfloat
));
405 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->count
== 0);
407 if (save
->dangling_attr_ref
)
408 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
410 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
411 save
->prim_store
->used
+= node
->prim_count
;
413 /* Copy duplicated vertices
415 save
->copied
.nr
= _save_copy_vertices(ctx
, node
, save
->buffer
);
417 merge_prims(ctx
, node
->prim
, &node
->prim_count
);
419 /* Deal with GL_COMPILE_AND_EXECUTE:
421 if (ctx
->ExecuteFlag
) {
422 struct _glapi_table
*dispatch
= GET_DISPATCH();
424 _glapi_set_dispatch(ctx
->Exec
);
426 vbo_loopback_vertex_list(ctx
,
427 (const GLfloat
*) ((const char *) save
->
428 vertex_store
->buffer
+
429 node
->buffer_offset
),
430 node
->attrsz
, node
->prim
, node
->prim_count
,
431 node
->wrap_count
, node
->vertex_size
);
433 _glapi_set_dispatch(dispatch
);
436 /* Decide whether the storage structs are full, or can be used for
437 * the next vertex lists as well.
439 if (save
->vertex_store
->used
>
440 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
444 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
446 /* Release old reference:
448 save
->vertex_store
->refcount
--;
449 assert(save
->vertex_store
->refcount
!= 0);
450 save
->vertex_store
= NULL
;
452 /* Allocate and map new store:
454 save
->vertex_store
= alloc_vertex_store(ctx
);
455 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
456 save
->out_of_memory
= save
->buffer_ptr
== NULL
;
459 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
460 save
->prim_store
->refcount
--;
461 assert(save
->prim_store
->refcount
!= 0);
462 save
->prim_store
= alloc_prim_store(ctx
);
465 /* Reset our structures for the next run of vertices:
467 _save_reset_counters(ctx
);
472 * TODO -- If no new vertices have been stored, don't bother saving it.
475 _save_wrap_buffers(struct gl_context
*ctx
)
477 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
478 GLint i
= save
->prim_count
- 1;
481 GLboolean no_current_update
;
483 assert(i
< (GLint
) save
->prim_max
);
486 /* Close off in-progress primitive.
488 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
489 mode
= save
->prim
[i
].mode
;
490 weak
= save
->prim
[i
].weak
;
491 no_current_update
= save
->prim
[i
].no_current_update
;
493 /* store the copied vertices, and allocate a new list.
495 _save_compile_vertex_list(ctx
);
497 /* Restart interrupted primitive
499 save
->prim
[0].mode
= mode
;
500 save
->prim
[0].weak
= weak
;
501 save
->prim
[0].no_current_update
= no_current_update
;
502 save
->prim
[0].begin
= 0;
503 save
->prim
[0].end
= 0;
504 save
->prim
[0].pad
= 0;
505 save
->prim
[0].start
= 0;
506 save
->prim
[0].count
= 0;
507 save
->prim
[0].num_instances
= 1;
508 save
->prim
[0].base_instance
= 0;
509 save
->prim_count
= 1;
514 * Called only when buffers are wrapped as the result of filling the
515 * vertex_store struct.
518 _save_wrap_filled_vertex(struct gl_context
*ctx
)
520 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
521 GLfloat
*data
= save
->copied
.buffer
;
524 /* Emit a glEnd to close off the last vertex list.
526 _save_wrap_buffers(ctx
);
528 /* Copy stored stored vertices to start of new list.
530 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
532 for (i
= 0; i
< save
->copied
.nr
; i
++) {
533 memcpy(save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
534 data
+= save
->vertex_size
;
535 save
->buffer_ptr
+= save
->vertex_size
;
542 _save_copy_to_current(struct gl_context
*ctx
)
544 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
547 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
548 if (save
->attrsz
[i
]) {
549 save
->currentsz
[i
][0] = save
->attrsz
[i
];
550 COPY_CLEAN_4V_TYPE_AS_FLOAT(save
->current
[i
], save
->attrsz
[i
],
551 save
->attrptr
[i
], save
->attrtype
[i
]);
558 _save_copy_from_current(struct gl_context
*ctx
)
560 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
563 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
564 switch (save
->attrsz
[i
]) {
566 save
->attrptr
[i
][3] = save
->current
[i
][3];
568 save
->attrptr
[i
][2] = save
->current
[i
][2];
570 save
->attrptr
[i
][1] = save
->current
[i
][1];
572 save
->attrptr
[i
][0] = save
->current
[i
][0];
580 /* Flush existing data, set new attrib size, replay copied vertices.
583 _save_upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
585 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
590 /* Store the current run of vertices, and emit a GL_END. Emit a
591 * BEGIN in the new buffer.
593 if (save
->vert_count
)
594 _save_wrap_buffers(ctx
);
596 assert(save
->copied
.nr
== 0);
598 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
599 * when the attribute already exists in the vertex and is having
600 * its size increased.
602 _save_copy_to_current(ctx
);
606 oldsz
= save
->attrsz
[attr
];
607 save
->attrsz
[attr
] = newsz
;
609 save
->vertex_size
+= newsz
- oldsz
;
610 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
612 save
->vert_count
= 0;
614 /* Recalculate all the attrptr[] values:
616 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
617 if (save
->attrsz
[i
]) {
618 save
->attrptr
[i
] = tmp
;
619 tmp
+= save
->attrsz
[i
];
622 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
626 /* Copy from current to repopulate the vertex with correct values.
628 _save_copy_from_current(ctx
);
630 /* Replay stored vertices to translate them to new format here.
632 * If there are copied vertices and the new (upgraded) attribute
633 * has not been defined before, this list is somewhat degenerate,
634 * and will need fixup at runtime.
636 if (save
->copied
.nr
) {
637 GLfloat
*data
= save
->copied
.buffer
;
638 GLfloat
*dest
= save
->buffer
;
641 /* Need to note this and fix up at runtime (or loopback):
643 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
645 save
->dangling_attr_ref
= GL_TRUE
;
648 for (i
= 0; i
< save
->copied
.nr
; i
++) {
649 for (j
= 0; j
< VBO_ATTRIB_MAX
; j
++) {
650 if (save
->attrsz
[j
]) {
653 COPY_CLEAN_4V_TYPE_AS_FLOAT(dest
, oldsz
, data
,
659 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
664 GLint sz
= save
->attrsz
[j
];
665 COPY_SZ_4V(dest
, sz
, data
);
673 save
->buffer_ptr
= dest
;
674 save
->vert_count
+= save
->copied
.nr
;
680 save_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
682 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
684 if (sz
> save
->attrsz
[attr
]) {
685 /* New size is larger. Need to flush existing vertices and get
686 * an enlarged vertex format.
688 _save_upgrade_vertex(ctx
, attr
, sz
);
690 else if (sz
< save
->active_sz
[attr
]) {
692 const GLfloat
*id
= vbo_get_default_vals_as_float(save
->attrtype
[attr
]);
694 /* New size is equal or smaller - just need to fill in some
697 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
698 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
701 save
->active_sz
[attr
] = sz
;
706 _save_reset_vertex(struct gl_context
*ctx
)
708 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
711 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
713 save
->active_sz
[i
] = 0;
716 save
->vertex_size
= 0;
721 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
724 /* Only one size for each attribute may be active at once. Eg. if
725 * Color3f is installed/active, then Color4f may not be, even if the
726 * vertex actually contains 4 color coordinates. This is because the
727 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
728 * of the chooser function when switching between Color4f and Color3f.
730 #define ATTR(A, N, T, V0, V1, V2, V3) \
732 struct vbo_save_context *save = &vbo_context(ctx)->save; \
734 if (save->active_sz[A] != N) \
735 save_fixup_vertex(ctx, A, N); \
738 GLfloat *dest = save->attrptr[A]; \
739 if (N>0) dest[0] = V0; \
740 if (N>1) dest[1] = V1; \
741 if (N>2) dest[2] = V2; \
742 if (N>3) dest[3] = V3; \
743 save->attrtype[A] = T; \
749 for (i = 0; i < save->vertex_size; i++) \
750 save->buffer_ptr[i] = save->vertex[i]; \
752 save->buffer_ptr += save->vertex_size; \
754 if (++save->vert_count >= save->max_vert) \
755 _save_wrap_filled_vertex(ctx); \
759 #define TAG(x) _save_##x
761 #include "vbo_attrib_tmp.h"
765 #define MAT( ATTR, N, face, params ) \
767 if (face != GL_BACK) \
768 MAT_ATTR( ATTR, N, params ); /* front */ \
769 if (face != GL_FRONT) \
770 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
775 * Save a glMaterial call found between glBegin/End.
776 * glMaterial calls outside Begin/End are handled in dlist.c.
778 static void GLAPIENTRY
779 _save_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
781 GET_CURRENT_CONTEXT(ctx
);
783 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
784 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(face)");
790 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
793 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
796 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
799 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
802 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
803 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glMaterial(shininess)");
806 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
809 case GL_COLOR_INDEXES
:
810 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
812 case GL_AMBIENT_AND_DIFFUSE
:
813 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
814 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
817 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(pname)");
823 /* Cope with EvalCoord/CallList called within a begin/end object:
824 * -- Flush current buffer
825 * -- Fallback to opcodes for the rest of the begin/end object.
828 dlist_fallback(struct gl_context
*ctx
)
830 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
832 if (save
->vert_count
|| save
->prim_count
) {
833 if (save
->prim_count
> 0) {
834 /* Close off in-progress primitive. */
835 GLint i
= save
->prim_count
- 1;
836 save
->prim
[i
].count
= save
->vert_count
- save
->prim
[i
].start
;
839 /* Need to replay this display list with loopback,
840 * unfortunately, otherwise this primitive won't be handled
843 save
->dangling_attr_ref
= 1;
845 _save_compile_vertex_list(ctx
);
848 _save_copy_to_current(ctx
);
849 _save_reset_vertex(ctx
);
850 _save_reset_counters(ctx
);
851 if (save
->out_of_memory
) {
852 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
855 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
857 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
861 static void GLAPIENTRY
862 _save_EvalCoord1f(GLfloat u
)
864 GET_CURRENT_CONTEXT(ctx
);
866 CALL_EvalCoord1f(ctx
->Save
, (u
));
869 static void GLAPIENTRY
870 _save_EvalCoord1fv(const GLfloat
* v
)
872 GET_CURRENT_CONTEXT(ctx
);
874 CALL_EvalCoord1fv(ctx
->Save
, (v
));
877 static void GLAPIENTRY
878 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
880 GET_CURRENT_CONTEXT(ctx
);
882 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
885 static void GLAPIENTRY
886 _save_EvalCoord2fv(const GLfloat
* v
)
888 GET_CURRENT_CONTEXT(ctx
);
890 CALL_EvalCoord2fv(ctx
->Save
, (v
));
893 static void GLAPIENTRY
894 _save_EvalPoint1(GLint i
)
896 GET_CURRENT_CONTEXT(ctx
);
898 CALL_EvalPoint1(ctx
->Save
, (i
));
901 static void GLAPIENTRY
902 _save_EvalPoint2(GLint i
, GLint j
)
904 GET_CURRENT_CONTEXT(ctx
);
906 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
909 static void GLAPIENTRY
910 _save_CallList(GLuint l
)
912 GET_CURRENT_CONTEXT(ctx
);
914 CALL_CallList(ctx
->Save
, (l
));
917 static void GLAPIENTRY
918 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
920 GET_CURRENT_CONTEXT(ctx
);
922 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
928 * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
929 * compiled into a display list.
930 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
933 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
935 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
937 GLuint i
= save
->prim_count
++;
939 assert(i
< save
->prim_max
);
940 save
->prim
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
941 save
->prim
[i
].begin
= 1;
942 save
->prim
[i
].end
= 0;
943 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
944 save
->prim
[i
].no_current_update
=
945 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
946 save
->prim
[i
].pad
= 0;
947 save
->prim
[i
].start
= save
->vert_count
;
948 save
->prim
[i
].count
= 0;
949 save
->prim
[i
].num_instances
= 1;
950 save
->prim
[i
].base_instance
= 0;
952 if (save
->out_of_memory
) {
953 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
956 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
959 /* We need to call SaveFlushVertices() if there's state change */
960 ctx
->Driver
.SaveNeedFlush
= GL_TRUE
;
962 /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
963 * opcode into the display list.
969 static void GLAPIENTRY
972 GET_CURRENT_CONTEXT(ctx
);
973 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
974 GLint i
= save
->prim_count
- 1;
976 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
977 save
->prim
[i
].end
= 1;
978 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
980 if (i
== (GLint
) save
->prim_max
- 1) {
981 _save_compile_vertex_list(ctx
);
982 assert(save
->copied
.nr
== 0);
985 /* Swap out this vertex format while outside begin/end. Any color,
986 * etc. received between here and the next begin will be compiled
989 if (save
->out_of_memory
) {
990 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
993 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
998 static void GLAPIENTRY
999 _save_Begin(GLenum mode
)
1001 GET_CURRENT_CONTEXT(ctx
);
1003 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
1007 static void GLAPIENTRY
1008 _save_PrimitiveRestartNV(void)
1011 GET_CURRENT_CONTEXT(ctx
);
1013 curPrim
= ctx
->Driver
.CurrentSavePrimitive
;
1016 _save_Begin(curPrim
);
1020 /* Unlike the functions above, these are to be hooked into the vtxfmt
1021 * maintained in ctx->ListState, active when the list is known or
1022 * suspected to be outside any begin/end primitive.
1023 * Note: OBE = Outside Begin/End
1025 static void GLAPIENTRY
1026 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1028 GET_CURRENT_CONTEXT(ctx
);
1029 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1030 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1031 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1032 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1033 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1034 CALL_End(GET_DISPATCH(), ());
1038 static void GLAPIENTRY
1039 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1041 GET_CURRENT_CONTEXT(ctx
);
1042 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1045 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1046 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawArrays(mode)");
1050 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawArrays(count<0)");
1054 if (save
->out_of_memory
)
1059 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1060 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1062 for (i
= 0; i
< count
; i
++)
1063 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1064 CALL_End(GET_DISPATCH(), ());
1066 _ae_unmap_vbos(ctx
);
1070 /* Could do better by copying the arrays and element list intact and
1071 * then emitting an indexed prim at runtime.
1073 static void GLAPIENTRY
1074 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1075 const GLvoid
* indices
)
1077 GET_CURRENT_CONTEXT(ctx
);
1078 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1081 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1082 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(mode)");
1086 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1089 if (type
!= GL_UNSIGNED_BYTE
&&
1090 type
!= GL_UNSIGNED_SHORT
&&
1091 type
!= GL_UNSIGNED_INT
) {
1092 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1096 if (save
->out_of_memory
)
1101 if (_mesa_is_bufferobj(ctx
->Array
.ArrayObj
->ElementArrayBufferObj
))
1103 ADD_POINTERS(ctx
->Array
.ArrayObj
->ElementArrayBufferObj
->Pointer
, indices
);
1105 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1106 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1109 case GL_UNSIGNED_BYTE
:
1110 for (i
= 0; i
< count
; i
++)
1111 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte
*) indices
)[i
]));
1113 case GL_UNSIGNED_SHORT
:
1114 for (i
= 0; i
< count
; i
++)
1115 CALL_ArrayElement(GET_DISPATCH(), (((GLushort
*) indices
)[i
]));
1117 case GL_UNSIGNED_INT
:
1118 for (i
= 0; i
< count
; i
++)
1119 CALL_ArrayElement(GET_DISPATCH(), (((GLuint
*) indices
)[i
]));
1122 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1126 CALL_End(GET_DISPATCH(), ());
1128 _ae_unmap_vbos(ctx
);
1132 static void GLAPIENTRY
1133 _save_OBE_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
1134 GLsizei count
, GLenum type
,
1135 const GLvoid
* indices
)
1137 GET_CURRENT_CONTEXT(ctx
);
1138 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1140 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1141 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(mode)");
1145 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1146 "glDrawRangeElements(count<0)");
1149 if (type
!= GL_UNSIGNED_BYTE
&&
1150 type
!= GL_UNSIGNED_SHORT
&&
1151 type
!= GL_UNSIGNED_INT
) {
1152 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(type)");
1156 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1157 "glDrawRangeElements(end < start)");
1161 if (save
->out_of_memory
)
1164 _save_OBE_DrawElements(mode
, count
, type
, indices
);
1168 static void GLAPIENTRY
1169 _save_OBE_MultiDrawElements(GLenum mode
, const GLsizei
*count
, GLenum type
,
1170 const GLvoid
**indices
, GLsizei primcount
)
1174 for (i
= 0; i
< primcount
; i
++) {
1176 CALL_DrawElements(GET_DISPATCH(), (mode
, count
[i
], type
, indices
[i
]));
1182 static void GLAPIENTRY
1183 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode
, const GLsizei
*count
,
1185 const GLvoid
* const *indices
,
1187 const GLint
*basevertex
)
1191 for (i
= 0; i
< primcount
; i
++) {
1193 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode
, count
[i
], type
,
1202 _save_vtxfmt_init(struct gl_context
*ctx
)
1204 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1205 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1207 vfmt
->ArrayElement
= _ae_ArrayElement
;
1209 vfmt
->Color3f
= _save_Color3f
;
1210 vfmt
->Color3fv
= _save_Color3fv
;
1211 vfmt
->Color4f
= _save_Color4f
;
1212 vfmt
->Color4fv
= _save_Color4fv
;
1213 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1214 vfmt
->End
= _save_End
;
1215 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1216 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1217 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1218 vfmt
->Indexf
= _save_Indexf
;
1219 vfmt
->Indexfv
= _save_Indexfv
;
1220 vfmt
->Materialfv
= _save_Materialfv
;
1221 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1222 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1223 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1224 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1225 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1226 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1227 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1228 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1229 vfmt
->Normal3f
= _save_Normal3f
;
1230 vfmt
->Normal3fv
= _save_Normal3fv
;
1231 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1232 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1233 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1234 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1235 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1236 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1237 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1238 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1239 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1240 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1241 vfmt
->Vertex2f
= _save_Vertex2f
;
1242 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1243 vfmt
->Vertex3f
= _save_Vertex3f
;
1244 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1245 vfmt
->Vertex4f
= _save_Vertex4f
;
1246 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1247 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1248 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1249 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1250 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1251 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1252 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1253 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1254 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1256 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1257 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1258 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1259 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1260 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1261 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1262 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1263 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1265 /* integer-valued */
1266 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1267 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1268 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1269 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1270 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1271 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1272 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1274 /* unsigned integer-valued */
1275 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1276 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1277 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1278 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1279 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1280 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1281 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1283 vfmt
->VertexP2ui
= _save_VertexP2ui
;
1284 vfmt
->VertexP3ui
= _save_VertexP3ui
;
1285 vfmt
->VertexP4ui
= _save_VertexP4ui
;
1286 vfmt
->VertexP2uiv
= _save_VertexP2uiv
;
1287 vfmt
->VertexP3uiv
= _save_VertexP3uiv
;
1288 vfmt
->VertexP4uiv
= _save_VertexP4uiv
;
1290 vfmt
->TexCoordP1ui
= _save_TexCoordP1ui
;
1291 vfmt
->TexCoordP2ui
= _save_TexCoordP2ui
;
1292 vfmt
->TexCoordP3ui
= _save_TexCoordP3ui
;
1293 vfmt
->TexCoordP4ui
= _save_TexCoordP4ui
;
1294 vfmt
->TexCoordP1uiv
= _save_TexCoordP1uiv
;
1295 vfmt
->TexCoordP2uiv
= _save_TexCoordP2uiv
;
1296 vfmt
->TexCoordP3uiv
= _save_TexCoordP3uiv
;
1297 vfmt
->TexCoordP4uiv
= _save_TexCoordP4uiv
;
1299 vfmt
->MultiTexCoordP1ui
= _save_MultiTexCoordP1ui
;
1300 vfmt
->MultiTexCoordP2ui
= _save_MultiTexCoordP2ui
;
1301 vfmt
->MultiTexCoordP3ui
= _save_MultiTexCoordP3ui
;
1302 vfmt
->MultiTexCoordP4ui
= _save_MultiTexCoordP4ui
;
1303 vfmt
->MultiTexCoordP1uiv
= _save_MultiTexCoordP1uiv
;
1304 vfmt
->MultiTexCoordP2uiv
= _save_MultiTexCoordP2uiv
;
1305 vfmt
->MultiTexCoordP3uiv
= _save_MultiTexCoordP3uiv
;
1306 vfmt
->MultiTexCoordP4uiv
= _save_MultiTexCoordP4uiv
;
1308 vfmt
->NormalP3ui
= _save_NormalP3ui
;
1309 vfmt
->NormalP3uiv
= _save_NormalP3uiv
;
1311 vfmt
->ColorP3ui
= _save_ColorP3ui
;
1312 vfmt
->ColorP4ui
= _save_ColorP4ui
;
1313 vfmt
->ColorP3uiv
= _save_ColorP3uiv
;
1314 vfmt
->ColorP4uiv
= _save_ColorP4uiv
;
1316 vfmt
->SecondaryColorP3ui
= _save_SecondaryColorP3ui
;
1317 vfmt
->SecondaryColorP3uiv
= _save_SecondaryColorP3uiv
;
1319 vfmt
->VertexAttribP1ui
= _save_VertexAttribP1ui
;
1320 vfmt
->VertexAttribP2ui
= _save_VertexAttribP2ui
;
1321 vfmt
->VertexAttribP3ui
= _save_VertexAttribP3ui
;
1322 vfmt
->VertexAttribP4ui
= _save_VertexAttribP4ui
;
1324 vfmt
->VertexAttribP1uiv
= _save_VertexAttribP1uiv
;
1325 vfmt
->VertexAttribP2uiv
= _save_VertexAttribP2uiv
;
1326 vfmt
->VertexAttribP3uiv
= _save_VertexAttribP3uiv
;
1327 vfmt
->VertexAttribP4uiv
= _save_VertexAttribP4uiv
;
1329 /* This will all require us to fallback to saving the list as opcodes:
1331 vfmt
->CallList
= _save_CallList
;
1332 vfmt
->CallLists
= _save_CallLists
;
1334 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1335 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1336 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1337 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1338 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1339 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1341 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1342 * only used when we're inside a glBegin/End pair.
1344 vfmt
->Begin
= _save_Begin
;
1349 * Initialize the dispatch table with the VBO functions for display
1353 vbo_initialize_save_dispatch(const struct gl_context
*ctx
,
1354 struct _glapi_table
*exec
)
1356 SET_DrawArrays(exec
, _save_OBE_DrawArrays
);
1357 SET_DrawElements(exec
, _save_OBE_DrawElements
);
1358 SET_DrawRangeElements(exec
, _save_OBE_DrawRangeElements
);
1359 SET_MultiDrawElementsEXT(exec
, _save_OBE_MultiDrawElements
);
1360 SET_MultiDrawElementsBaseVertex(exec
, _save_OBE_MultiDrawElementsBaseVertex
);
1361 SET_Rectf(exec
, _save_OBE_Rectf
);
1362 /* Note: other glDraw functins aren't compiled into display lists */
1368 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1370 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1372 /* Noop when we are actually active:
1374 if (ctx
->Driver
.CurrentSavePrimitive
<= PRIM_MAX
)
1377 if (save
->vert_count
|| save
->prim_count
)
1378 _save_compile_vertex_list(ctx
);
1380 _save_copy_to_current(ctx
);
1381 _save_reset_vertex(ctx
);
1382 _save_reset_counters(ctx
);
1383 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1388 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1390 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1395 if (!save
->prim_store
)
1396 save
->prim_store
= alloc_prim_store(ctx
);
1398 if (!save
->vertex_store
)
1399 save
->vertex_store
= alloc_vertex_store(ctx
);
1401 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
1403 _save_reset_vertex(ctx
);
1404 _save_reset_counters(ctx
);
1405 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1410 vbo_save_EndList(struct gl_context
*ctx
)
1412 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1414 /* EndList called inside a (saved) Begin/End pair?
1416 if (_mesa_inside_dlist_begin_end(ctx
)) {
1417 if (save
->prim_count
> 0) {
1418 GLint i
= save
->prim_count
- 1;
1419 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1420 save
->prim
[i
].end
= 0;
1421 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
1424 /* Make sure this vertex list gets replayed by the "loopback"
1427 save
->dangling_attr_ref
= 1;
1428 vbo_save_SaveFlushVertices(ctx
);
1430 /* Swap out this vertex format while outside begin/end. Any color,
1431 * etc. received between here and the next begin will be compiled
1434 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1437 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
1439 assert(save
->vertex_size
== 0);
1444 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1446 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1447 save
->replay_flags
|= dlist
->Flags
;
1452 vbo_save_EndCallList(struct gl_context
*ctx
)
1454 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1456 if (ctx
->ListState
.CallDepth
== 1) {
1457 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1458 * flag, if it is set:
1460 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1466 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1468 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1471 if (--node
->vertex_store
->refcount
== 0)
1472 free_vertex_store(ctx
, node
->vertex_store
);
1474 if (--node
->prim_store
->refcount
== 0)
1475 free(node
->prim_store
);
1477 free(node
->current_data
);
1478 node
->current_data
= NULL
;
1483 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
)
1485 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1489 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1490 node
->count
, node
->prim_count
, node
->vertex_size
);
1492 for (i
= 0; i
< node
->prim_count
; i
++) {
1493 struct _mesa_prim
*prim
= &node
->prim
[i
];
1494 printf(" prim %d: %s%s %d..%d %s %s\n",
1496 _mesa_lookup_prim_by_nr(prim
->mode
),
1497 prim
->weak
? " (weak)" : "",
1499 prim
->start
+ prim
->count
,
1500 (prim
->begin
) ? "BEGIN" : "(wrap)",
1501 (prim
->end
) ? "END" : "(wrap)");
1507 * Called during context creation/init.
1510 _save_current_init(struct gl_context
*ctx
)
1512 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1515 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1516 const GLuint j
= i
- VBO_ATTRIB_POS
;
1517 ASSERT(j
< VERT_ATTRIB_MAX
);
1518 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1519 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1522 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1523 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1524 ASSERT(j
< MAT_ATTRIB_MAX
);
1525 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1526 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1532 * Initialize the display list compiler. Called during context creation.
1535 vbo_save_api_init(struct vbo_save_context
*save
)
1537 struct gl_context
*ctx
= save
->ctx
;
1540 save
->opcode_vertex_list
=
1541 _mesa_dlist_alloc_opcode(ctx
,
1542 sizeof(struct vbo_save_vertex_list
),
1543 vbo_save_playback_vertex_list
,
1544 vbo_destroy_vertex_list
,
1545 vbo_print_vertex_list
);
1547 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1549 _save_vtxfmt_init(ctx
);
1550 _save_current_init(ctx
);
1551 _mesa_noop_vtxfmt_init(&save
->vtxfmt_noop
);
1553 /* These will actually get set again when binding/drawing */
1554 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1555 save
->inputs
[i
] = &save
->arrays
[i
];