1 /**************************************************************************
3 Copyright 2002-2008 VMware, Inc.
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 VMWARE 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 <keithw@vmware.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"
81 #include "main/state.h"
82 #include "util/bitscan.h"
84 #include "vbo_context.h"
86 #include "vbo_private.h"
94 * Display list flag only used by this VBO code.
96 #define DLIST_DANGLING_REFS 0x1
99 /* An interesting VBO number/name to help with debugging */
100 #define VBO_BUF_ID 12345
104 * NOTE: Old 'parity' issue is gone, but copying can still be
105 * wrong-footed on replay.
108 copy_vertices(struct gl_context
*ctx
,
109 const struct vbo_save_vertex_list
*node
,
110 const fi_type
* src_buffer
)
112 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
113 const struct _mesa_prim
*prim
= &node
->prims
[node
->prim_count
- 1];
114 GLuint nr
= prim
->count
;
115 GLuint sz
= save
->vertex_size
;
116 const fi_type
*src
= src_buffer
+ prim
->start
* sz
;
117 fi_type
*dst
= save
->copied
.buffer
;
123 switch (prim
->mode
) {
128 for (i
= 0; i
< ovf
; i
++)
129 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
130 sz
* sizeof(GLfloat
));
134 for (i
= 0; i
< ovf
; i
++)
135 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
136 sz
* sizeof(GLfloat
));
140 for (i
= 0; i
< ovf
; i
++)
141 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
142 sz
* sizeof(GLfloat
));
148 memcpy(dst
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
152 case GL_TRIANGLE_FAN
:
157 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
161 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
162 memcpy(dst
+ sz
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
165 case GL_TRIANGLE_STRIP
:
178 for (i
= 0; i
< ovf
; i
++)
179 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
180 sz
* sizeof(GLfloat
));
183 unreachable("Unexpected primitive type");
189 static struct vbo_save_vertex_store
*
190 alloc_vertex_store(struct gl_context
*ctx
)
192 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
193 struct vbo_save_vertex_store
*vertex_store
=
194 CALLOC_STRUCT(vbo_save_vertex_store
);
196 /* obj->Name needs to be non-zero, but won't ever be examined more
197 * closely than that. In particular these buffers won't be entered
198 * into the hash and can never be confused with ones visible to the
199 * user. Perhaps there could be a special number for internal
202 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, VBO_BUF_ID
);
203 if (vertex_store
->bufferobj
) {
204 save
->out_of_memory
=
205 !ctx
->Driver
.BufferData(ctx
,
207 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
208 NULL
, GL_STATIC_DRAW_ARB
,
210 GL_DYNAMIC_STORAGE_BIT
,
211 vertex_store
->bufferobj
);
214 save
->out_of_memory
= GL_TRUE
;
217 if (save
->out_of_memory
) {
218 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "internal VBO allocation");
219 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
222 vertex_store
->buffer_map
= NULL
;
223 vertex_store
->used
= 0;
224 vertex_store
->refcount
= 1;
231 free_vertex_store(struct gl_context
*ctx
,
232 struct vbo_save_vertex_store
*vertex_store
)
234 assert(!vertex_store
->buffer_map
);
236 if (vertex_store
->bufferobj
) {
237 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
245 vbo_save_map_vertex_store(struct gl_context
*ctx
,
246 struct vbo_save_vertex_store
*vertex_store
)
248 const GLbitfield access
= (GL_MAP_WRITE_BIT
|
249 GL_MAP_INVALIDATE_RANGE_BIT
|
250 GL_MAP_UNSYNCHRONIZED_BIT
|
251 GL_MAP_FLUSH_EXPLICIT_BIT
);
253 assert(vertex_store
->bufferobj
);
254 assert(!vertex_store
->buffer_map
); /* the buffer should not be mapped */
256 if (vertex_store
->bufferobj
->Size
> 0) {
257 /* Map the remaining free space in the VBO */
258 GLintptr offset
= vertex_store
->used
* sizeof(GLfloat
);
259 GLsizeiptr size
= vertex_store
->bufferobj
->Size
- offset
;
260 fi_type
*range
= (fi_type
*)
261 ctx
->Driver
.MapBufferRange(ctx
, offset
, size
, access
,
262 vertex_store
->bufferobj
,
265 /* compute address of start of whole buffer (needed elsewhere) */
266 vertex_store
->buffer_map
= range
- vertex_store
->used
;
267 assert(vertex_store
->buffer_map
);
271 vertex_store
->buffer_map
= NULL
;
276 /* probably ran out of memory for buffers */
283 vbo_save_unmap_vertex_store(struct gl_context
*ctx
,
284 struct vbo_save_vertex_store
*vertex_store
)
286 if (vertex_store
->bufferobj
->Size
> 0) {
288 GLsizeiptr length
= vertex_store
->used
* sizeof(GLfloat
)
289 - vertex_store
->bufferobj
->Mappings
[MAP_INTERNAL
].Offset
;
291 /* Explicitly flush the region we wrote to */
292 ctx
->Driver
.FlushMappedBufferRange(ctx
, offset
, length
,
293 vertex_store
->bufferobj
,
296 ctx
->Driver
.UnmapBuffer(ctx
, vertex_store
->bufferobj
, MAP_INTERNAL
);
298 vertex_store
->buffer_map
= NULL
;
302 static struct vbo_save_primitive_store
*
303 alloc_prim_store(void)
305 struct vbo_save_primitive_store
*store
=
306 CALLOC_STRUCT(vbo_save_primitive_store
);
314 reset_counters(struct gl_context
*ctx
)
316 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
318 save
->prims
= save
->prim_store
->prims
+ save
->prim_store
->used
;
319 save
->buffer_map
= save
->vertex_store
->buffer_map
+ save
->vertex_store
->used
;
321 assert(save
->buffer_map
== save
->buffer_ptr
);
323 if (save
->vertex_size
)
324 save
->max_vert
= (VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
329 save
->vert_count
= 0;
330 save
->prim_count
= 0;
331 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
332 save
->dangling_attr_ref
= GL_FALSE
;
336 * For a list of prims, try merging prims that can just be extensions of the
340 merge_prims(struct _mesa_prim
*prim_list
,
344 struct _mesa_prim
*prev_prim
= prim_list
;
346 for (i
= 1; i
< *prim_count
; i
++) {
347 struct _mesa_prim
*this_prim
= prim_list
+ i
;
349 vbo_try_prim_conversion(this_prim
);
351 if (vbo_can_merge_prims(prev_prim
, this_prim
)) {
352 /* We've found a prim that just extend the previous one. Tack it
353 * onto the previous one, and let this primitive struct get dropped.
355 vbo_merge_prims(prev_prim
, this_prim
);
359 /* If any previous primitives have been dropped, then we need to copy
360 * this later one into the next available slot.
363 if (prev_prim
!= this_prim
)
364 *prev_prim
= *this_prim
;
367 *prim_count
= prev_prim
- prim_list
+ 1;
372 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
373 * don't have to worry about handling the _mesa_prim::begin/end flags.
374 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
377 convert_line_loop_to_strip(struct vbo_save_context
*save
,
378 struct vbo_save_vertex_list
*node
)
380 struct _mesa_prim
*prim
= &node
->prims
[node
->prim_count
- 1];
382 assert(prim
->mode
== GL_LINE_LOOP
);
385 /* Copy the 0th vertex to end of the buffer and extend the
386 * vertex count by one to finish the line loop.
388 const GLuint sz
= save
->vertex_size
;
390 const fi_type
*src
= save
->buffer_map
+ prim
->start
* sz
;
392 fi_type
*dst
= save
->buffer_map
+ (prim
->start
+ prim
->count
) * sz
;
394 memcpy(dst
, src
, sz
* sizeof(float));
397 node
->vertex_count
++;
399 save
->buffer_ptr
+= sz
;
400 save
->vertex_store
->used
+= sz
;
404 /* Drawing the second or later section of a long line loop.
405 * Skip the 0th vertex.
411 prim
->mode
= GL_LINE_STRIP
;
416 * Insert the active immediate struct onto the display list currently
420 compile_vertex_list(struct gl_context
*ctx
)
422 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
423 struct vbo_save_vertex_list
*node
;
425 /* Allocate space for this structure in the display list currently
428 node
= (struct vbo_save_vertex_list
*)
429 _mesa_dlist_alloc_aligned(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
434 /* Make sure the pointer is aligned to the size of a pointer */
435 assert((GLintptr
) node
% sizeof(void *) == 0);
437 /* Duplicate our template, increment refcounts to the storage structs:
439 node
->enabled
= save
->enabled
;
440 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
441 memcpy(node
->attrtype
, save
->attrtype
, sizeof(node
->attrtype
));
442 node
->vertex_size
= save
->vertex_size
;
443 node
->buffer_offset
=
444 (save
->buffer_map
- save
->vertex_store
->buffer_map
) * sizeof(GLfloat
);
445 node
->vertex_count
= save
->vert_count
;
446 node
->wrap_count
= save
->copied
.nr
;
447 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
448 node
->prims
= save
->prims
;
449 node
->prim_count
= save
->prim_count
;
450 node
->vertex_store
= save
->vertex_store
;
451 node
->prim_store
= save
->prim_store
;
453 node
->vertex_store
->refcount
++;
454 node
->prim_store
->refcount
++;
456 if (node
->prims
[0].no_current_update
) {
457 node
->current_size
= 0;
458 node
->current_data
= NULL
;
461 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
462 node
->current_data
= NULL
;
464 if (node
->current_size
) {
465 /* If the malloc fails, we just pull the data out of the VBO
468 node
->current_data
= malloc(node
->current_size
* sizeof(GLfloat
));
469 if (node
->current_data
) {
470 const char *buffer
= (const char *) save
->vertex_store
->buffer_map
;
471 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
472 unsigned vertex_offset
= 0;
474 if (node
->vertex_count
)
476 (node
->vertex_count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
478 memcpy(node
->current_data
,
479 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
480 node
->current_size
* sizeof(GLfloat
));
485 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->vertex_count
== 0);
487 if (save
->dangling_attr_ref
)
488 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
490 save
->vertex_store
->used
+= save
->vertex_size
* node
->vertex_count
;
491 save
->prim_store
->used
+= node
->prim_count
;
493 /* Copy duplicated vertices
495 save
->copied
.nr
= copy_vertices(ctx
, node
, save
->buffer_map
);
497 if (node
->prims
[node
->prim_count
- 1].mode
== GL_LINE_LOOP
) {
498 convert_line_loop_to_strip(save
, node
);
501 merge_prims(node
->prims
, &node
->prim_count
);
503 /* Deal with GL_COMPILE_AND_EXECUTE:
505 if (ctx
->ExecuteFlag
) {
506 struct _glapi_table
*dispatch
= GET_DISPATCH();
508 _glapi_set_dispatch(ctx
->Exec
);
510 const GLfloat
*buffer
= (const GLfloat
*)
511 ((const char *) save
->vertex_store
->buffer_map
+
512 node
->buffer_offset
);
514 vbo_loopback_vertex_list(ctx
, buffer
,
515 node
->attrsz
, node
->prims
, node
->prim_count
,
516 node
->wrap_count
, node
->vertex_size
);
518 _glapi_set_dispatch(dispatch
);
521 /* Decide whether the storage structs are full, or can be used for
522 * the next vertex lists as well.
524 if (save
->vertex_store
->used
>
525 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
529 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
531 /* Release old reference:
533 save
->vertex_store
->refcount
--;
534 assert(save
->vertex_store
->refcount
!= 0);
535 save
->vertex_store
= NULL
;
537 /* Allocate and map new store:
539 save
->vertex_store
= alloc_vertex_store(ctx
);
540 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
541 save
->out_of_memory
= save
->buffer_ptr
== NULL
;
544 /* update buffer_ptr for next vertex */
545 save
->buffer_ptr
= save
->vertex_store
->buffer_map
546 + save
->vertex_store
->used
;
549 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
550 save
->prim_store
->refcount
--;
551 assert(save
->prim_store
->refcount
!= 0);
552 save
->prim_store
= alloc_prim_store();
556 * If the vertex buffer offset is a multiple of the vertex size,
557 * we can use the _mesa_prim::start value to indicate where the
558 * vertices starts, instead of the buffer offset. Also see the
559 * bind_vertex_list() function.
561 if (aligned_vertex_buffer_offset(node
)) {
562 const unsigned start_offset
=
563 node
->buffer_offset
/ (node
->vertex_size
* sizeof(GLfloat
));
564 for (unsigned i
= 0; i
< save
->prim_count
; i
++) {
565 save
->prims
[i
].start
+= start_offset
;
569 /* Reset our structures for the next run of vertices:
576 * This is called when we fill a vertex buffer before we hit a glEnd().
578 * TODO -- If no new vertices have been stored, don't bother saving it.
581 wrap_buffers(struct gl_context
*ctx
)
583 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
584 GLint i
= save
->prim_count
- 1;
587 GLboolean no_current_update
;
589 assert(i
< (GLint
) save
->prim_max
);
592 /* Close off in-progress primitive.
594 save
->prims
[i
].count
= (save
->vert_count
- save
->prims
[i
].start
);
595 mode
= save
->prims
[i
].mode
;
596 weak
= save
->prims
[i
].weak
;
597 no_current_update
= save
->prims
[i
].no_current_update
;
599 /* store the copied vertices, and allocate a new list.
601 compile_vertex_list(ctx
);
603 /* Restart interrupted primitive
605 save
->prims
[0].mode
= mode
;
606 save
->prims
[0].weak
= weak
;
607 save
->prims
[0].no_current_update
= no_current_update
;
608 save
->prims
[0].begin
= 0;
609 save
->prims
[0].end
= 0;
610 save
->prims
[0].pad
= 0;
611 save
->prims
[0].start
= 0;
612 save
->prims
[0].count
= 0;
613 save
->prims
[0].num_instances
= 1;
614 save
->prims
[0].base_instance
= 0;
615 save
->prims
[0].is_indirect
= 0;
616 save
->prim_count
= 1;
621 * Called only when buffers are wrapped as the result of filling the
622 * vertex_store struct.
625 wrap_filled_vertex(struct gl_context
*ctx
)
627 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
628 unsigned numComponents
;
630 /* Emit a glEnd to close off the last vertex list.
634 /* Copy stored stored vertices to start of new list.
636 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
638 numComponents
= save
->copied
.nr
* save
->vertex_size
;
639 memcpy(save
->buffer_ptr
,
641 numComponents
* sizeof(fi_type
));
642 save
->buffer_ptr
+= numComponents
;
643 save
->vert_count
+= save
->copied
.nr
;
648 copy_to_current(struct gl_context
*ctx
)
650 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
651 GLbitfield64 enabled
= save
->enabled
& (~BITFIELD64_BIT(VBO_ATTRIB_POS
));
654 const int i
= u_bit_scan64(&enabled
);
655 assert(save
->attrsz
[i
]);
657 save
->currentsz
[i
][0] = save
->attrsz
[i
];
658 COPY_CLEAN_4V_TYPE_AS_UNION(save
->current
[i
], save
->attrsz
[i
],
659 save
->attrptr
[i
], save
->attrtype
[i
]);
665 copy_from_current(struct gl_context
*ctx
)
667 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
668 GLbitfield64 enabled
= save
->enabled
& (~BITFIELD64_BIT(VBO_ATTRIB_POS
));
671 const int i
= u_bit_scan64(&enabled
);
673 switch (save
->attrsz
[i
]) {
675 save
->attrptr
[i
][3] = save
->current
[i
][3];
677 save
->attrptr
[i
][2] = save
->current
[i
][2];
679 save
->attrptr
[i
][1] = save
->current
[i
][1];
681 save
->attrptr
[i
][0] = save
->current
[i
][0];
684 unreachable("Unexpected vertex attribute size");
691 * Called when we increase the size of a vertex attribute. For example,
692 * if we've seen one or more glTexCoord2f() calls and now we get a
693 * glTexCoord3f() call.
694 * Flush existing data, set new attrib size, replay copied vertices.
697 upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
699 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
704 /* Store the current run of vertices, and emit a GL_END. Emit a
705 * BEGIN in the new buffer.
707 if (save
->vert_count
)
710 assert(save
->copied
.nr
== 0);
712 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
713 * when the attribute already exists in the vertex and is having
714 * its size increased.
716 copy_to_current(ctx
);
720 oldsz
= save
->attrsz
[attr
];
721 save
->attrsz
[attr
] = newsz
;
722 save
->enabled
|= BITFIELD64_BIT(attr
);
724 save
->vertex_size
+= newsz
- oldsz
;
725 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
727 save
->vert_count
= 0;
729 /* Recalculate all the attrptr[] values:
732 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
733 if (save
->attrsz
[i
]) {
734 save
->attrptr
[i
] = tmp
;
735 tmp
+= save
->attrsz
[i
];
738 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
742 /* Copy from current to repopulate the vertex with correct values.
744 copy_from_current(ctx
);
746 /* Replay stored vertices to translate them to new format here.
748 * If there are copied vertices and the new (upgraded) attribute
749 * has not been defined before, this list is somewhat degenerate,
750 * and will need fixup at runtime.
752 if (save
->copied
.nr
) {
753 const fi_type
*data
= save
->copied
.buffer
;
754 fi_type
*dest
= save
->buffer_map
;
756 /* Need to note this and fix up at runtime (or loopback):
758 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
760 save
->dangling_attr_ref
= GL_TRUE
;
763 for (i
= 0; i
< save
->copied
.nr
; i
++) {
764 GLbitfield64 enabled
= save
->enabled
;
766 const int j
= u_bit_scan64(&enabled
);
767 assert(save
->attrsz
[j
]);
770 COPY_CLEAN_4V_TYPE_AS_UNION(dest
, oldsz
, data
,
776 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
781 GLint sz
= save
->attrsz
[j
];
782 COPY_SZ_4V(dest
, sz
, data
);
789 save
->buffer_ptr
= dest
;
790 save
->vert_count
+= save
->copied
.nr
;
796 * This is called when the size of a vertex attribute changes.
797 * For example, after seeing one or more glTexCoord2f() calls we
798 * get a glTexCoord4f() or glTexCoord1f() call.
801 fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
803 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
805 if (sz
> save
->attrsz
[attr
]) {
806 /* New size is larger. Need to flush existing vertices and get
807 * an enlarged vertex format.
809 upgrade_vertex(ctx
, attr
, sz
);
811 else if (sz
< save
->active_sz
[attr
]) {
813 const fi_type
*id
= vbo_get_default_vals_as_union(save
->attrtype
[attr
]);
815 /* New size is equal or smaller - just need to fill in some
818 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
819 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
822 save
->active_sz
[attr
] = sz
;
827 * Reset the current size of all vertex attributes to the default
828 * value of 0. This signals that we haven't yet seen any per-vertex
829 * commands such as glNormal3f() or glTexCoord2f().
832 reset_vertex(struct gl_context
*ctx
)
834 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
836 while (save
->enabled
) {
837 const int i
= u_bit_scan64(&save
->enabled
);
838 assert(save
->attrsz
[i
]);
840 save
->active_sz
[i
] = 0;
843 save
->vertex_size
= 0;
848 #define ERROR(err) _mesa_compile_error(ctx, err, __func__);
851 /* Only one size for each attribute may be active at once. Eg. if
852 * Color3f is installed/active, then Color4f may not be, even if the
853 * vertex actually contains 4 color coordinates. This is because the
854 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
855 * of the chooser function when switching between Color4f and Color3f.
857 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \
859 struct vbo_save_context *save = &vbo_context(ctx)->save; \
861 if (save->active_sz[A] != N) \
862 fixup_vertex(ctx, A, N); \
865 C *dest = (C *)save->attrptr[A]; \
866 if (N>0) dest[0] = V0; \
867 if (N>1) dest[1] = V1; \
868 if (N>2) dest[2] = V2; \
869 if (N>3) dest[3] = V3; \
870 save->attrtype[A] = T; \
876 for (i = 0; i < save->vertex_size; i++) \
877 save->buffer_ptr[i] = save->vertex[i]; \
879 save->buffer_ptr += save->vertex_size; \
881 if (++save->vert_count >= save->max_vert) \
882 wrap_filled_vertex(ctx); \
886 #define TAG(x) _save_##x
888 #include "vbo_attrib_tmp.h"
892 #define MAT( ATTR, N, face, params ) \
894 if (face != GL_BACK) \
895 MAT_ATTR( ATTR, N, params ); /* front */ \
896 if (face != GL_FRONT) \
897 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
902 * Save a glMaterial call found between glBegin/End.
903 * glMaterial calls outside Begin/End are handled in dlist.c.
905 static void GLAPIENTRY
906 _save_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
908 GET_CURRENT_CONTEXT(ctx
);
910 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
911 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(face)");
917 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
920 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
923 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
926 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
929 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
930 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glMaterial(shininess)");
933 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
936 case GL_COLOR_INDEXES
:
937 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
939 case GL_AMBIENT_AND_DIFFUSE
:
940 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
941 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
944 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(pname)");
950 /* Cope with EvalCoord/CallList called within a begin/end object:
951 * -- Flush current buffer
952 * -- Fallback to opcodes for the rest of the begin/end object.
955 dlist_fallback(struct gl_context
*ctx
)
957 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
959 if (save
->vert_count
|| save
->prim_count
) {
960 if (save
->prim_count
> 0) {
961 /* Close off in-progress primitive. */
962 GLint i
= save
->prim_count
- 1;
963 save
->prims
[i
].count
= save
->vert_count
- save
->prims
[i
].start
;
966 /* Need to replay this display list with loopback,
967 * unfortunately, otherwise this primitive won't be handled
970 save
->dangling_attr_ref
= GL_TRUE
;
972 compile_vertex_list(ctx
);
975 copy_to_current(ctx
);
978 if (save
->out_of_memory
) {
979 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
982 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
984 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
988 static void GLAPIENTRY
989 _save_EvalCoord1f(GLfloat u
)
991 GET_CURRENT_CONTEXT(ctx
);
993 CALL_EvalCoord1f(ctx
->Save
, (u
));
996 static void GLAPIENTRY
997 _save_EvalCoord1fv(const GLfloat
* v
)
999 GET_CURRENT_CONTEXT(ctx
);
1000 dlist_fallback(ctx
);
1001 CALL_EvalCoord1fv(ctx
->Save
, (v
));
1004 static void GLAPIENTRY
1005 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
1007 GET_CURRENT_CONTEXT(ctx
);
1008 dlist_fallback(ctx
);
1009 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
1012 static void GLAPIENTRY
1013 _save_EvalCoord2fv(const GLfloat
* v
)
1015 GET_CURRENT_CONTEXT(ctx
);
1016 dlist_fallback(ctx
);
1017 CALL_EvalCoord2fv(ctx
->Save
, (v
));
1020 static void GLAPIENTRY
1021 _save_EvalPoint1(GLint i
)
1023 GET_CURRENT_CONTEXT(ctx
);
1024 dlist_fallback(ctx
);
1025 CALL_EvalPoint1(ctx
->Save
, (i
));
1028 static void GLAPIENTRY
1029 _save_EvalPoint2(GLint i
, GLint j
)
1031 GET_CURRENT_CONTEXT(ctx
);
1032 dlist_fallback(ctx
);
1033 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
1036 static void GLAPIENTRY
1037 _save_CallList(GLuint l
)
1039 GET_CURRENT_CONTEXT(ctx
);
1040 dlist_fallback(ctx
);
1041 CALL_CallList(ctx
->Save
, (l
));
1044 static void GLAPIENTRY
1045 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
1047 GET_CURRENT_CONTEXT(ctx
);
1048 dlist_fallback(ctx
);
1049 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
1055 * Called when a glBegin is getting compiled into a display list.
1056 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1059 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
1061 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1062 const GLuint i
= save
->prim_count
++;
1064 assert(i
< save
->prim_max
);
1065 save
->prims
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
1066 save
->prims
[i
].begin
= 1;
1067 save
->prims
[i
].end
= 0;
1068 save
->prims
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
1069 save
->prims
[i
].no_current_update
=
1070 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
1071 save
->prims
[i
].pad
= 0;
1072 save
->prims
[i
].start
= save
->vert_count
;
1073 save
->prims
[i
].count
= 0;
1074 save
->prims
[i
].num_instances
= 1;
1075 save
->prims
[i
].base_instance
= 0;
1076 save
->prims
[i
].is_indirect
= 0;
1078 if (save
->out_of_memory
) {
1079 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
1082 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
1085 /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1086 ctx
->Driver
.SaveNeedFlush
= GL_TRUE
;
1090 static void GLAPIENTRY
1093 GET_CURRENT_CONTEXT(ctx
);
1094 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1095 const GLint i
= save
->prim_count
- 1;
1097 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1098 save
->prims
[i
].end
= 1;
1099 save
->prims
[i
].count
= (save
->vert_count
- save
->prims
[i
].start
);
1101 if (i
== (GLint
) save
->prim_max
- 1) {
1102 compile_vertex_list(ctx
);
1103 assert(save
->copied
.nr
== 0);
1106 /* Swap out this vertex format while outside begin/end. Any color,
1107 * etc. received between here and the next begin will be compiled
1110 if (save
->out_of_memory
) {
1111 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
1114 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1119 static void GLAPIENTRY
1120 _save_Begin(GLenum mode
)
1122 GET_CURRENT_CONTEXT(ctx
);
1124 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
1128 static void GLAPIENTRY
1129 _save_PrimitiveRestartNV(void)
1131 GET_CURRENT_CONTEXT(ctx
);
1132 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1134 if (save
->prim_count
== 0) {
1135 /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1138 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
,
1139 "glPrimitiveRestartNV called outside glBegin/End");
1141 /* get current primitive mode */
1142 GLenum curPrim
= save
->prims
[save
->prim_count
- 1].mode
;
1144 /* restart primitive */
1145 CALL_End(GET_DISPATCH(), ());
1146 vbo_save_NotifyBegin(ctx
, curPrim
);
1151 /* Unlike the functions above, these are to be hooked into the vtxfmt
1152 * maintained in ctx->ListState, active when the list is known or
1153 * suspected to be outside any begin/end primitive.
1154 * Note: OBE = Outside Begin/End
1156 static void GLAPIENTRY
1157 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1159 GET_CURRENT_CONTEXT(ctx
);
1160 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1161 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1162 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1163 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1164 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1165 CALL_End(GET_DISPATCH(), ());
1169 static void GLAPIENTRY
1170 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1172 GET_CURRENT_CONTEXT(ctx
);
1173 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1176 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1177 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawArrays(mode)");
1181 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawArrays(count<0)");
1185 if (save
->out_of_memory
)
1188 /* Make sure to process any VBO binding changes */
1189 _mesa_update_state(ctx
);
1193 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1194 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1196 for (i
= 0; i
< count
; i
++)
1197 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1198 CALL_End(GET_DISPATCH(), ());
1200 _ae_unmap_vbos(ctx
);
1204 static void GLAPIENTRY
1205 _save_OBE_MultiDrawArrays(GLenum mode
, const GLint
*first
,
1206 const GLsizei
*count
, GLsizei primcount
)
1208 GET_CURRENT_CONTEXT(ctx
);
1211 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1212 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMultiDrawArrays(mode)");
1216 if (primcount
< 0) {
1217 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1218 "glMultiDrawArrays(primcount<0)");
1222 for (i
= 0; i
< primcount
; i
++) {
1224 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1225 "glMultiDrawArrays(count[i]<0)");
1230 for (i
= 0; i
< primcount
; i
++) {
1232 _save_OBE_DrawArrays(mode
, first
[i
], count
[i
]);
1238 /* Could do better by copying the arrays and element list intact and
1239 * then emitting an indexed prim at runtime.
1241 static void GLAPIENTRY
1242 _save_OBE_DrawElementsBaseVertex(GLenum mode
, GLsizei count
, GLenum type
,
1243 const GLvoid
* indices
, GLint basevertex
)
1245 GET_CURRENT_CONTEXT(ctx
);
1246 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1247 struct gl_buffer_object
*indexbuf
= ctx
->Array
.VAO
->IndexBufferObj
;
1250 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1251 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(mode)");
1255 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1258 if (type
!= GL_UNSIGNED_BYTE
&&
1259 type
!= GL_UNSIGNED_SHORT
&&
1260 type
!= GL_UNSIGNED_INT
) {
1261 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1265 if (save
->out_of_memory
)
1268 /* Make sure to process any VBO binding changes */
1269 _mesa_update_state(ctx
);
1273 if (_mesa_is_bufferobj(indexbuf
))
1275 ADD_POINTERS(indexbuf
->Mappings
[MAP_INTERNAL
].Pointer
, indices
);
1277 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1278 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1281 case GL_UNSIGNED_BYTE
:
1282 for (i
= 0; i
< count
; i
++)
1283 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLubyte
*) indices
)[i
]));
1285 case GL_UNSIGNED_SHORT
:
1286 for (i
= 0; i
< count
; i
++)
1287 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLushort
*) indices
)[i
]));
1289 case GL_UNSIGNED_INT
:
1290 for (i
= 0; i
< count
; i
++)
1291 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLuint
*) indices
)[i
]));
1294 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1298 CALL_End(GET_DISPATCH(), ());
1300 _ae_unmap_vbos(ctx
);
1303 static void GLAPIENTRY
1304 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1305 const GLvoid
* indices
)
1307 _save_OBE_DrawElementsBaseVertex(mode
, count
, type
, indices
, 0);
1311 static void GLAPIENTRY
1312 _save_OBE_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
1313 GLsizei count
, GLenum type
,
1314 const GLvoid
* indices
)
1316 GET_CURRENT_CONTEXT(ctx
);
1317 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1319 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1320 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(mode)");
1324 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1325 "glDrawRangeElements(count<0)");
1328 if (type
!= GL_UNSIGNED_BYTE
&&
1329 type
!= GL_UNSIGNED_SHORT
&&
1330 type
!= GL_UNSIGNED_INT
) {
1331 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(type)");
1335 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1336 "glDrawRangeElements(end < start)");
1340 if (save
->out_of_memory
)
1343 _save_OBE_DrawElements(mode
, count
, type
, indices
);
1347 static void GLAPIENTRY
1348 _save_OBE_MultiDrawElements(GLenum mode
, const GLsizei
*count
, GLenum type
,
1349 const GLvoid
* const *indices
, GLsizei primcount
)
1353 for (i
= 0; i
< primcount
; i
++) {
1355 CALL_DrawElements(GET_DISPATCH(), (mode
, count
[i
], type
, indices
[i
]));
1361 static void GLAPIENTRY
1362 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode
, const GLsizei
*count
,
1364 const GLvoid
* const *indices
,
1366 const GLint
*basevertex
)
1370 for (i
= 0; i
< primcount
; i
++) {
1372 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode
, count
[i
], type
,
1381 vtxfmt_init(struct gl_context
*ctx
)
1383 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1384 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1386 vfmt
->ArrayElement
= _ae_ArrayElement
;
1388 vfmt
->Color3f
= _save_Color3f
;
1389 vfmt
->Color3fv
= _save_Color3fv
;
1390 vfmt
->Color4f
= _save_Color4f
;
1391 vfmt
->Color4fv
= _save_Color4fv
;
1392 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1393 vfmt
->End
= _save_End
;
1394 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1395 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1396 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1397 vfmt
->Indexf
= _save_Indexf
;
1398 vfmt
->Indexfv
= _save_Indexfv
;
1399 vfmt
->Materialfv
= _save_Materialfv
;
1400 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1401 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1402 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1403 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1404 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1405 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1406 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1407 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1408 vfmt
->Normal3f
= _save_Normal3f
;
1409 vfmt
->Normal3fv
= _save_Normal3fv
;
1410 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1411 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1412 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1413 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1414 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1415 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1416 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1417 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1418 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1419 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1420 vfmt
->Vertex2f
= _save_Vertex2f
;
1421 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1422 vfmt
->Vertex3f
= _save_Vertex3f
;
1423 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1424 vfmt
->Vertex4f
= _save_Vertex4f
;
1425 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1426 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1427 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1428 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1429 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1430 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1431 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1432 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1433 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1435 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1436 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1437 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1438 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1439 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1440 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1441 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1442 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1444 /* integer-valued */
1445 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1446 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1447 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1448 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1449 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1450 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1451 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1453 /* unsigned integer-valued */
1454 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1455 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1456 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1457 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1458 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1459 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1460 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1462 vfmt
->VertexP2ui
= _save_VertexP2ui
;
1463 vfmt
->VertexP3ui
= _save_VertexP3ui
;
1464 vfmt
->VertexP4ui
= _save_VertexP4ui
;
1465 vfmt
->VertexP2uiv
= _save_VertexP2uiv
;
1466 vfmt
->VertexP3uiv
= _save_VertexP3uiv
;
1467 vfmt
->VertexP4uiv
= _save_VertexP4uiv
;
1469 vfmt
->TexCoordP1ui
= _save_TexCoordP1ui
;
1470 vfmt
->TexCoordP2ui
= _save_TexCoordP2ui
;
1471 vfmt
->TexCoordP3ui
= _save_TexCoordP3ui
;
1472 vfmt
->TexCoordP4ui
= _save_TexCoordP4ui
;
1473 vfmt
->TexCoordP1uiv
= _save_TexCoordP1uiv
;
1474 vfmt
->TexCoordP2uiv
= _save_TexCoordP2uiv
;
1475 vfmt
->TexCoordP3uiv
= _save_TexCoordP3uiv
;
1476 vfmt
->TexCoordP4uiv
= _save_TexCoordP4uiv
;
1478 vfmt
->MultiTexCoordP1ui
= _save_MultiTexCoordP1ui
;
1479 vfmt
->MultiTexCoordP2ui
= _save_MultiTexCoordP2ui
;
1480 vfmt
->MultiTexCoordP3ui
= _save_MultiTexCoordP3ui
;
1481 vfmt
->MultiTexCoordP4ui
= _save_MultiTexCoordP4ui
;
1482 vfmt
->MultiTexCoordP1uiv
= _save_MultiTexCoordP1uiv
;
1483 vfmt
->MultiTexCoordP2uiv
= _save_MultiTexCoordP2uiv
;
1484 vfmt
->MultiTexCoordP3uiv
= _save_MultiTexCoordP3uiv
;
1485 vfmt
->MultiTexCoordP4uiv
= _save_MultiTexCoordP4uiv
;
1487 vfmt
->NormalP3ui
= _save_NormalP3ui
;
1488 vfmt
->NormalP3uiv
= _save_NormalP3uiv
;
1490 vfmt
->ColorP3ui
= _save_ColorP3ui
;
1491 vfmt
->ColorP4ui
= _save_ColorP4ui
;
1492 vfmt
->ColorP3uiv
= _save_ColorP3uiv
;
1493 vfmt
->ColorP4uiv
= _save_ColorP4uiv
;
1495 vfmt
->SecondaryColorP3ui
= _save_SecondaryColorP3ui
;
1496 vfmt
->SecondaryColorP3uiv
= _save_SecondaryColorP3uiv
;
1498 vfmt
->VertexAttribP1ui
= _save_VertexAttribP1ui
;
1499 vfmt
->VertexAttribP2ui
= _save_VertexAttribP2ui
;
1500 vfmt
->VertexAttribP3ui
= _save_VertexAttribP3ui
;
1501 vfmt
->VertexAttribP4ui
= _save_VertexAttribP4ui
;
1503 vfmt
->VertexAttribP1uiv
= _save_VertexAttribP1uiv
;
1504 vfmt
->VertexAttribP2uiv
= _save_VertexAttribP2uiv
;
1505 vfmt
->VertexAttribP3uiv
= _save_VertexAttribP3uiv
;
1506 vfmt
->VertexAttribP4uiv
= _save_VertexAttribP4uiv
;
1508 vfmt
->VertexAttribL1d
= _save_VertexAttribL1d
;
1509 vfmt
->VertexAttribL2d
= _save_VertexAttribL2d
;
1510 vfmt
->VertexAttribL3d
= _save_VertexAttribL3d
;
1511 vfmt
->VertexAttribL4d
= _save_VertexAttribL4d
;
1513 vfmt
->VertexAttribL1dv
= _save_VertexAttribL1dv
;
1514 vfmt
->VertexAttribL2dv
= _save_VertexAttribL2dv
;
1515 vfmt
->VertexAttribL3dv
= _save_VertexAttribL3dv
;
1516 vfmt
->VertexAttribL4dv
= _save_VertexAttribL4dv
;
1518 vfmt
->VertexAttribL1ui64ARB
= _save_VertexAttribL1ui64ARB
;
1519 vfmt
->VertexAttribL1ui64vARB
= _save_VertexAttribL1ui64vARB
;
1521 /* This will all require us to fallback to saving the list as opcodes:
1523 vfmt
->CallList
= _save_CallList
;
1524 vfmt
->CallLists
= _save_CallLists
;
1526 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1527 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1528 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1529 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1530 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1531 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1533 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1534 * only used when we're inside a glBegin/End pair.
1536 vfmt
->Begin
= _save_Begin
;
1541 * Initialize the dispatch table with the VBO functions for display
1545 vbo_initialize_save_dispatch(const struct gl_context
*ctx
,
1546 struct _glapi_table
*exec
)
1548 SET_DrawArrays(exec
, _save_OBE_DrawArrays
);
1549 SET_MultiDrawArrays(exec
, _save_OBE_MultiDrawArrays
);
1550 SET_DrawElements(exec
, _save_OBE_DrawElements
);
1551 SET_DrawElementsBaseVertex(exec
, _save_OBE_DrawElementsBaseVertex
);
1552 SET_DrawRangeElements(exec
, _save_OBE_DrawRangeElements
);
1553 SET_MultiDrawElementsEXT(exec
, _save_OBE_MultiDrawElements
);
1554 SET_MultiDrawElementsBaseVertex(exec
, _save_OBE_MultiDrawElementsBaseVertex
);
1555 SET_Rectf(exec
, _save_OBE_Rectf
);
1556 /* Note: other glDraw functins aren't compiled into display lists */
1562 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1564 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1566 /* Noop when we are actually active:
1568 if (ctx
->Driver
.CurrentSavePrimitive
<= PRIM_MAX
)
1571 if (save
->vert_count
|| save
->prim_count
)
1572 compile_vertex_list(ctx
);
1574 copy_to_current(ctx
);
1576 reset_counters(ctx
);
1577 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1582 * Called from glNewList when we're starting to compile a display list.
1585 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1587 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1592 if (!save
->prim_store
)
1593 save
->prim_store
= alloc_prim_store();
1595 if (!save
->vertex_store
)
1596 save
->vertex_store
= alloc_vertex_store(ctx
);
1598 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
1601 reset_counters(ctx
);
1602 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1607 * Called from glEndList when we're finished compiling a display list.
1610 vbo_save_EndList(struct gl_context
*ctx
)
1612 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1614 /* EndList called inside a (saved) Begin/End pair?
1616 if (_mesa_inside_dlist_begin_end(ctx
)) {
1617 if (save
->prim_count
> 0) {
1618 GLint i
= save
->prim_count
- 1;
1619 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1620 save
->prims
[i
].end
= 0;
1621 save
->prims
[i
].count
= save
->vert_count
- save
->prims
[i
].start
;
1624 /* Make sure this vertex list gets replayed by the "loopback"
1627 save
->dangling_attr_ref
= GL_TRUE
;
1628 vbo_save_SaveFlushVertices(ctx
);
1630 /* Swap out this vertex format while outside begin/end. Any color,
1631 * etc. received between here and the next begin will be compiled
1634 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1637 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
1639 assert(save
->vertex_size
== 0);
1644 * Called from the display list code when we're about to execute a
1648 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1650 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1651 save
->replay_flags
|= dlist
->Flags
;
1656 * Called from the display list code when we're finished executing a
1660 vbo_save_EndCallList(struct gl_context
*ctx
)
1662 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1664 if (ctx
->ListState
.CallDepth
== 1) {
1665 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1666 * flag, if it is set:
1668 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1674 * Called by display list code when a display list is being deleted.
1677 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1679 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1682 if (--node
->vertex_store
->refcount
== 0)
1683 free_vertex_store(ctx
, node
->vertex_store
);
1685 if (--node
->prim_store
->refcount
== 0)
1686 free(node
->prim_store
);
1688 free(node
->current_data
);
1689 node
->current_data
= NULL
;
1694 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
, FILE *f
)
1696 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1698 struct gl_buffer_object
*buffer
= node
->vertex_store
?
1699 node
->vertex_store
->bufferobj
: NULL
;
1702 fprintf(f
, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1704 node
->vertex_count
, node
->prim_count
, node
->vertex_size
,
1707 for (i
= 0; i
< node
->prim_count
; i
++) {
1708 struct _mesa_prim
*prim
= &node
->prims
[i
];
1709 fprintf(f
, " prim %d: %s%s %d..%d %s %s\n",
1711 _mesa_lookup_prim_by_nr(prim
->mode
),
1712 prim
->weak
? " (weak)" : "",
1714 prim
->start
+ prim
->count
,
1715 (prim
->begin
) ? "BEGIN" : "(wrap)",
1716 (prim
->end
) ? "END" : "(wrap)");
1722 * Called during context creation/init.
1725 current_init(struct gl_context
*ctx
)
1727 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1730 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1731 const GLuint j
= i
- VBO_ATTRIB_POS
;
1732 assert(j
< VERT_ATTRIB_MAX
);
1733 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1734 save
->current
[i
] = (fi_type
*) ctx
->ListState
.CurrentAttrib
[j
];
1737 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1738 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1739 assert(j
< MAT_ATTRIB_MAX
);
1740 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1741 save
->current
[i
] = (fi_type
*) ctx
->ListState
.CurrentMaterial
[j
];
1747 * Initialize the display list compiler. Called during context creation.
1750 vbo_save_api_init(struct vbo_save_context
*save
)
1752 struct gl_context
*ctx
= save
->ctx
;
1755 save
->opcode_vertex_list
=
1756 _mesa_dlist_alloc_opcode(ctx
,
1757 sizeof(struct vbo_save_vertex_list
),
1758 vbo_save_playback_vertex_list
,
1759 vbo_destroy_vertex_list
,
1760 vbo_print_vertex_list
);
1764 _mesa_noop_vtxfmt_init(&save
->vtxfmt_noop
);
1766 /* These will actually get set again when binding/drawing */
1767 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1768 save
->inputs
[i
] = &save
->arrays
[i
];