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"
93 /* An interesting VBO number/name to help with debugging */
94 #define VBO_BUF_ID 12345
98 * NOTE: Old 'parity' issue is gone, but copying can still be
99 * wrong-footed on replay.
102 _save_copy_vertices(struct gl_context
*ctx
,
103 const struct vbo_save_vertex_list
*node
,
104 const fi_type
* src_buffer
)
106 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
107 const struct _mesa_prim
*prim
= &node
->prims
[node
->prim_count
- 1];
108 GLuint nr
= prim
->count
;
109 GLuint sz
= save
->vertex_size
;
110 const fi_type
*src
= src_buffer
+ prim
->start
* sz
;
111 fi_type
*dst
= save
->copied
.buffer
;
117 switch (prim
->mode
) {
122 for (i
= 0; i
< ovf
; i
++)
123 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
124 sz
* sizeof(GLfloat
));
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
));
142 memcpy(dst
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
146 case GL_TRIANGLE_FAN
:
151 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
155 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
156 memcpy(dst
+ sz
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
159 case GL_TRIANGLE_STRIP
:
172 for (i
= 0; i
< ovf
; i
++)
173 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
174 sz
* sizeof(GLfloat
));
183 static struct vbo_save_vertex_store
*
184 alloc_vertex_store(struct gl_context
*ctx
)
186 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
187 struct vbo_save_vertex_store
*vertex_store
=
188 CALLOC_STRUCT(vbo_save_vertex_store
);
190 /* obj->Name needs to be non-zero, but won't ever be examined more
191 * closely than that. In particular these buffers won't be entered
192 * into the hash and can never be confused with ones visible to the
193 * user. Perhaps there could be a special number for internal
196 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
, VBO_BUF_ID
);
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
,
204 GL_DYNAMIC_STORAGE_BIT
,
205 vertex_store
->bufferobj
);
208 save
->out_of_memory
= GL_TRUE
;
211 if (save
->out_of_memory
) {
212 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "internal VBO allocation");
213 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
216 vertex_store
->buffer_map
= NULL
;
217 vertex_store
->used
= 0;
218 vertex_store
->refcount
= 1;
225 free_vertex_store(struct gl_context
*ctx
,
226 struct vbo_save_vertex_store
*vertex_store
)
228 assert(!vertex_store
->buffer_map
);
230 if (vertex_store
->bufferobj
) {
231 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
239 vbo_save_map_vertex_store(struct gl_context
*ctx
,
240 struct vbo_save_vertex_store
*vertex_store
)
242 const GLbitfield access
= (GL_MAP_WRITE_BIT
|
243 GL_MAP_INVALIDATE_RANGE_BIT
|
244 GL_MAP_UNSYNCHRONIZED_BIT
|
245 GL_MAP_FLUSH_EXPLICIT_BIT
);
247 assert(vertex_store
->bufferobj
);
248 assert(!vertex_store
->buffer_map
); /* the buffer should not be mapped */
250 if (vertex_store
->bufferobj
->Size
> 0) {
251 /* Map the remaining free space in the VBO */
252 GLintptr offset
= vertex_store
->used
* sizeof(GLfloat
);
253 GLsizeiptr size
= vertex_store
->bufferobj
->Size
- offset
;
254 fi_type
*range
= (fi_type
*)
255 ctx
->Driver
.MapBufferRange(ctx
, offset
, size
, access
,
256 vertex_store
->bufferobj
,
259 /* compute address of start of whole buffer (needed elsewhere) */
260 vertex_store
->buffer_map
= range
- vertex_store
->used
;
261 assert(vertex_store
->buffer_map
);
265 vertex_store
->buffer_map
= NULL
;
270 /* probably ran out of memory for buffers */
277 vbo_save_unmap_vertex_store(struct gl_context
*ctx
,
278 struct vbo_save_vertex_store
*vertex_store
)
280 if (vertex_store
->bufferobj
->Size
> 0) {
282 GLsizeiptr length
= vertex_store
->used
* sizeof(GLfloat
)
283 - vertex_store
->bufferobj
->Mappings
[MAP_INTERNAL
].Offset
;
285 /* Explicitly flush the region we wrote to */
286 ctx
->Driver
.FlushMappedBufferRange(ctx
, offset
, length
,
287 vertex_store
->bufferobj
,
290 ctx
->Driver
.UnmapBuffer(ctx
, vertex_store
->bufferobj
, MAP_INTERNAL
);
292 vertex_store
->buffer_map
= NULL
;
296 static struct vbo_save_primitive_store
*
297 alloc_prim_store(void)
299 struct vbo_save_primitive_store
*store
=
300 CALLOC_STRUCT(vbo_save_primitive_store
);
308 _save_reset_counters(struct gl_context
*ctx
)
310 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
312 save
->prims
= save
->prim_store
->prims
+ save
->prim_store
->used
;
313 save
->buffer_map
= save
->vertex_store
->buffer_map
+ save
->vertex_store
->used
;
315 assert(save
->buffer_map
== save
->buffer_ptr
);
317 if (save
->vertex_size
)
318 save
->max_vert
= (VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
323 save
->vert_count
= 0;
324 save
->prim_count
= 0;
325 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
326 save
->dangling_attr_ref
= GL_FALSE
;
330 * For a list of prims, try merging prims that can just be extensions of the
334 merge_prims(struct _mesa_prim
*prim_list
,
338 struct _mesa_prim
*prev_prim
= prim_list
;
340 for (i
= 1; i
< *prim_count
; i
++) {
341 struct _mesa_prim
*this_prim
= prim_list
+ i
;
343 vbo_try_prim_conversion(this_prim
);
345 if (vbo_can_merge_prims(prev_prim
, this_prim
)) {
346 /* We've found a prim that just extend the previous one. Tack it
347 * onto the previous one, and let this primitive struct get dropped.
349 vbo_merge_prims(prev_prim
, this_prim
);
353 /* If any previous primitives have been dropped, then we need to copy
354 * this later one into the next available slot.
357 if (prev_prim
!= this_prim
)
358 *prev_prim
= *this_prim
;
361 *prim_count
= prev_prim
- prim_list
+ 1;
366 * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
367 * don't have to worry about handling the _mesa_prim::begin/end flags.
368 * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
371 convert_line_loop_to_strip(struct vbo_save_context
*save
,
372 struct vbo_save_vertex_list
*node
)
374 struct _mesa_prim
*prim
= &node
->prims
[node
->prim_count
- 1];
376 assert(prim
->mode
== GL_LINE_LOOP
);
379 /* Copy the 0th vertex to end of the buffer and extend the
380 * vertex count by one to finish the line loop.
382 const GLuint sz
= save
->vertex_size
;
384 const fi_type
*src
= save
->buffer_map
+ prim
->start
* sz
;
386 fi_type
*dst
= save
->buffer_map
+ (prim
->start
+ prim
->count
) * sz
;
388 memcpy(dst
, src
, sz
* sizeof(float));
391 node
->vertex_count
++;
393 save
->buffer_ptr
+= sz
;
394 save
->vertex_store
->used
+= sz
;
398 /* Drawing the second or later section of a long line loop.
399 * Skip the 0th vertex.
405 prim
->mode
= GL_LINE_STRIP
;
410 * Insert the active immediate struct onto the display list currently
414 _save_compile_vertex_list(struct gl_context
*ctx
)
416 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
417 struct vbo_save_vertex_list
*node
;
419 /* Allocate space for this structure in the display list currently
422 node
= (struct vbo_save_vertex_list
*)
423 _mesa_dlist_alloc_aligned(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
428 /* Make sure the pointer is aligned to the size of a pointer */
429 assert((GLintptr
) node
% sizeof(void *) == 0);
431 /* Duplicate our template, increment refcounts to the storage structs:
433 node
->enabled
= save
->enabled
;
434 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
435 memcpy(node
->attrtype
, save
->attrtype
, sizeof(node
->attrtype
));
436 node
->vertex_size
= save
->vertex_size
;
437 node
->buffer_offset
=
438 (save
->buffer_map
- save
->vertex_store
->buffer_map
) * sizeof(GLfloat
);
439 node
->vertex_count
= save
->vert_count
;
440 node
->wrap_count
= save
->copied
.nr
;
441 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
442 node
->prims
= save
->prims
;
443 node
->prim_count
= save
->prim_count
;
444 node
->vertex_store
= save
->vertex_store
;
445 node
->prim_store
= save
->prim_store
;
447 node
->vertex_store
->refcount
++;
448 node
->prim_store
->refcount
++;
450 if (node
->prims
[0].no_current_update
) {
451 node
->current_size
= 0;
452 node
->current_data
= NULL
;
455 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
456 node
->current_data
= NULL
;
458 if (node
->current_size
) {
459 /* If the malloc fails, we just pull the data out of the VBO
462 node
->current_data
= malloc(node
->current_size
* sizeof(GLfloat
));
463 if (node
->current_data
) {
464 const char *buffer
= (const char *) save
->vertex_store
->buffer_map
;
465 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
466 unsigned vertex_offset
= 0;
468 if (node
->vertex_count
)
470 (node
->vertex_count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
472 memcpy(node
->current_data
,
473 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
474 node
->current_size
* sizeof(GLfloat
));
479 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->vertex_count
== 0);
481 if (save
->dangling_attr_ref
)
482 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
484 save
->vertex_store
->used
+= save
->vertex_size
* node
->vertex_count
;
485 save
->prim_store
->used
+= node
->prim_count
;
487 /* Copy duplicated vertices
489 save
->copied
.nr
= _save_copy_vertices(ctx
, node
, save
->buffer_map
);
491 if (node
->prims
[node
->prim_count
- 1].mode
== GL_LINE_LOOP
) {
492 convert_line_loop_to_strip(save
, node
);
495 merge_prims(node
->prims
, &node
->prim_count
);
497 /* Deal with GL_COMPILE_AND_EXECUTE:
499 if (ctx
->ExecuteFlag
) {
500 struct _glapi_table
*dispatch
= GET_DISPATCH();
502 _glapi_set_dispatch(ctx
->Exec
);
504 vbo_loopback_vertex_list(ctx
,
505 (const GLfloat
*) ((const char *) save
->
506 vertex_store
->buffer_map
+
507 node
->buffer_offset
),
508 node
->attrsz
, node
->prims
, node
->prim_count
,
509 node
->wrap_count
, node
->vertex_size
);
511 _glapi_set_dispatch(dispatch
);
514 /* Decide whether the storage structs are full, or can be used for
515 * the next vertex lists as well.
517 if (save
->vertex_store
->used
>
518 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
522 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
524 /* Release old reference:
526 save
->vertex_store
->refcount
--;
527 assert(save
->vertex_store
->refcount
!= 0);
528 save
->vertex_store
= NULL
;
530 /* Allocate and map new store:
532 save
->vertex_store
= alloc_vertex_store(ctx
);
533 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
534 save
->out_of_memory
= save
->buffer_ptr
== NULL
;
537 /* update buffer_ptr for next vertex */
538 save
->buffer_ptr
= save
->vertex_store
->buffer_map
539 + save
->vertex_store
->used
;
542 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
543 save
->prim_store
->refcount
--;
544 assert(save
->prim_store
->refcount
!= 0);
545 save
->prim_store
= alloc_prim_store();
548 /* Reset our structures for the next run of vertices:
550 _save_reset_counters(ctx
);
555 * This is called when we fill a vertex buffer before we hit a glEnd().
557 * TODO -- If no new vertices have been stored, don't bother saving it.
560 _save_wrap_buffers(struct gl_context
*ctx
)
562 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
563 GLint i
= save
->prim_count
- 1;
566 GLboolean no_current_update
;
568 assert(i
< (GLint
) save
->prim_max
);
571 /* Close off in-progress primitive.
573 save
->prims
[i
].count
= (save
->vert_count
- save
->prims
[i
].start
);
574 mode
= save
->prims
[i
].mode
;
575 weak
= save
->prims
[i
].weak
;
576 no_current_update
= save
->prims
[i
].no_current_update
;
578 /* store the copied vertices, and allocate a new list.
580 _save_compile_vertex_list(ctx
);
582 /* Restart interrupted primitive
584 save
->prims
[0].mode
= mode
;
585 save
->prims
[0].weak
= weak
;
586 save
->prims
[0].no_current_update
= no_current_update
;
587 save
->prims
[0].begin
= 0;
588 save
->prims
[0].end
= 0;
589 save
->prims
[0].pad
= 0;
590 save
->prims
[0].start
= 0;
591 save
->prims
[0].count
= 0;
592 save
->prims
[0].num_instances
= 1;
593 save
->prims
[0].base_instance
= 0;
594 save
->prims
[0].is_indirect
= 0;
595 save
->prim_count
= 1;
600 * Called only when buffers are wrapped as the result of filling the
601 * vertex_store struct.
604 _save_wrap_filled_vertex(struct gl_context
*ctx
)
606 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
607 unsigned numComponents
;
609 /* Emit a glEnd to close off the last vertex list.
611 _save_wrap_buffers(ctx
);
613 /* Copy stored stored vertices to start of new list.
615 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
617 numComponents
= save
->copied
.nr
* save
->vertex_size
;
618 memcpy(save
->buffer_ptr
,
620 numComponents
* sizeof(fi_type
));
621 save
->buffer_ptr
+= numComponents
;
622 save
->vert_count
+= save
->copied
.nr
;
627 _save_copy_to_current(struct gl_context
*ctx
)
629 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
630 GLbitfield64 enabled
= save
->enabled
& (~BITFIELD64_BIT(VBO_ATTRIB_POS
));
633 const int i
= u_bit_scan64(&enabled
);
634 assert(save
->attrsz
[i
]);
636 save
->currentsz
[i
][0] = save
->attrsz
[i
];
637 COPY_CLEAN_4V_TYPE_AS_UNION(save
->current
[i
], save
->attrsz
[i
],
638 save
->attrptr
[i
], save
->attrtype
[i
]);
644 _save_copy_from_current(struct gl_context
*ctx
)
646 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
647 GLbitfield64 enabled
= save
->enabled
& (~BITFIELD64_BIT(VBO_ATTRIB_POS
));
650 const int i
= u_bit_scan64(&enabled
);
652 switch (save
->attrsz
[i
]) {
654 save
->attrptr
[i
][3] = save
->current
[i
][3];
656 save
->attrptr
[i
][2] = save
->current
[i
][2];
658 save
->attrptr
[i
][1] = save
->current
[i
][1];
660 save
->attrptr
[i
][0] = save
->current
[i
][0];
671 * Called when we increase the size of a vertex attribute. For example,
672 * if we've seen one or more glTexCoord2f() calls and now we get a
673 * glTexCoord3f() call.
674 * Flush existing data, set new attrib size, replay copied vertices.
677 _save_upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
679 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
684 /* Store the current run of vertices, and emit a GL_END. Emit a
685 * BEGIN in the new buffer.
687 if (save
->vert_count
)
688 _save_wrap_buffers(ctx
);
690 assert(save
->copied
.nr
== 0);
692 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
693 * when the attribute already exists in the vertex and is having
694 * its size increased.
696 _save_copy_to_current(ctx
);
700 oldsz
= save
->attrsz
[attr
];
701 save
->attrsz
[attr
] = newsz
;
702 save
->enabled
|= BITFIELD64_BIT(attr
);
704 save
->vertex_size
+= newsz
- oldsz
;
705 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
707 save
->vert_count
= 0;
709 /* Recalculate all the attrptr[] values:
712 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
713 if (save
->attrsz
[i
]) {
714 save
->attrptr
[i
] = tmp
;
715 tmp
+= save
->attrsz
[i
];
718 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
722 /* Copy from current to repopulate the vertex with correct values.
724 _save_copy_from_current(ctx
);
726 /* Replay stored vertices to translate them to new format here.
728 * If there are copied vertices and the new (upgraded) attribute
729 * has not been defined before, this list is somewhat degenerate,
730 * and will need fixup at runtime.
732 if (save
->copied
.nr
) {
733 const fi_type
*data
= save
->copied
.buffer
;
734 fi_type
*dest
= save
->buffer_map
;
736 /* Need to note this and fix up at runtime (or loopback):
738 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
740 save
->dangling_attr_ref
= GL_TRUE
;
743 for (i
= 0; i
< save
->copied
.nr
; i
++) {
744 GLbitfield64 enabled
= save
->enabled
;
746 const int j
= u_bit_scan64(&enabled
);
747 assert(save
->attrsz
[j
]);
750 COPY_CLEAN_4V_TYPE_AS_UNION(dest
, oldsz
, data
,
756 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
761 GLint sz
= save
->attrsz
[j
];
762 COPY_SZ_4V(dest
, sz
, data
);
769 save
->buffer_ptr
= dest
;
770 save
->vert_count
+= save
->copied
.nr
;
776 * This is called when the size of a vertex attribute changes.
777 * For example, after seeing one or more glTexCoord2f() calls we
778 * get a glTexCoord4f() or glTexCoord1f() call.
781 save_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
783 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
785 if (sz
> save
->attrsz
[attr
]) {
786 /* New size is larger. Need to flush existing vertices and get
787 * an enlarged vertex format.
789 _save_upgrade_vertex(ctx
, attr
, sz
);
791 else if (sz
< save
->active_sz
[attr
]) {
793 const fi_type
*id
= vbo_get_default_vals_as_union(save
->attrtype
[attr
]);
795 /* New size is equal or smaller - just need to fill in some
798 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
799 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
802 save
->active_sz
[attr
] = sz
;
807 * Reset the current size of all vertex attributes to the default
808 * value of 0. This signals that we haven't yet seen any per-vertex
809 * commands such as glNormal3f() or glTexCoord2f().
812 _save_reset_vertex(struct gl_context
*ctx
)
814 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
816 while (save
->enabled
) {
817 const int i
= u_bit_scan64(&save
->enabled
);
818 assert(save
->attrsz
[i
]);
820 save
->active_sz
[i
] = 0;
823 save
->vertex_size
= 0;
828 #define ERROR(err) _mesa_compile_error(ctx, err, __func__);
831 /* Only one size for each attribute may be active at once. Eg. if
832 * Color3f is installed/active, then Color4f may not be, even if the
833 * vertex actually contains 4 color coordinates. This is because the
834 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
835 * of the chooser function when switching between Color4f and Color3f.
837 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \
839 struct vbo_save_context *save = &vbo_context(ctx)->save; \
841 if (save->active_sz[A] != N) \
842 save_fixup_vertex(ctx, A, N); \
845 C *dest = (C *)save->attrptr[A]; \
846 if (N>0) dest[0] = V0; \
847 if (N>1) dest[1] = V1; \
848 if (N>2) dest[2] = V2; \
849 if (N>3) dest[3] = V3; \
850 save->attrtype[A] = T; \
856 for (i = 0; i < save->vertex_size; i++) \
857 save->buffer_ptr[i] = save->vertex[i]; \
859 save->buffer_ptr += save->vertex_size; \
861 if (++save->vert_count >= save->max_vert) \
862 _save_wrap_filled_vertex(ctx); \
866 #define TAG(x) _save_##x
868 #include "vbo_attrib_tmp.h"
872 #define MAT( ATTR, N, face, params ) \
874 if (face != GL_BACK) \
875 MAT_ATTR( ATTR, N, params ); /* front */ \
876 if (face != GL_FRONT) \
877 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
882 * Save a glMaterial call found between glBegin/End.
883 * glMaterial calls outside Begin/End are handled in dlist.c.
885 static void GLAPIENTRY
886 _save_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
888 GET_CURRENT_CONTEXT(ctx
);
890 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
891 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(face)");
897 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
900 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
903 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
906 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
909 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
910 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glMaterial(shininess)");
913 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
916 case GL_COLOR_INDEXES
:
917 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
919 case GL_AMBIENT_AND_DIFFUSE
:
920 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
921 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
924 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(pname)");
930 /* Cope with EvalCoord/CallList called within a begin/end object:
931 * -- Flush current buffer
932 * -- Fallback to opcodes for the rest of the begin/end object.
935 dlist_fallback(struct gl_context
*ctx
)
937 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
939 if (save
->vert_count
|| save
->prim_count
) {
940 if (save
->prim_count
> 0) {
941 /* Close off in-progress primitive. */
942 GLint i
= save
->prim_count
- 1;
943 save
->prims
[i
].count
= save
->vert_count
- save
->prims
[i
].start
;
946 /* Need to replay this display list with loopback,
947 * unfortunately, otherwise this primitive won't be handled
950 save
->dangling_attr_ref
= GL_TRUE
;
952 _save_compile_vertex_list(ctx
);
955 _save_copy_to_current(ctx
);
956 _save_reset_vertex(ctx
);
957 _save_reset_counters(ctx
);
958 if (save
->out_of_memory
) {
959 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
962 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
964 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
968 static void GLAPIENTRY
969 _save_EvalCoord1f(GLfloat u
)
971 GET_CURRENT_CONTEXT(ctx
);
973 CALL_EvalCoord1f(ctx
->Save
, (u
));
976 static void GLAPIENTRY
977 _save_EvalCoord1fv(const GLfloat
* v
)
979 GET_CURRENT_CONTEXT(ctx
);
981 CALL_EvalCoord1fv(ctx
->Save
, (v
));
984 static void GLAPIENTRY
985 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
987 GET_CURRENT_CONTEXT(ctx
);
989 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
992 static void GLAPIENTRY
993 _save_EvalCoord2fv(const GLfloat
* v
)
995 GET_CURRENT_CONTEXT(ctx
);
997 CALL_EvalCoord2fv(ctx
->Save
, (v
));
1000 static void GLAPIENTRY
1001 _save_EvalPoint1(GLint i
)
1003 GET_CURRENT_CONTEXT(ctx
);
1004 dlist_fallback(ctx
);
1005 CALL_EvalPoint1(ctx
->Save
, (i
));
1008 static void GLAPIENTRY
1009 _save_EvalPoint2(GLint i
, GLint j
)
1011 GET_CURRENT_CONTEXT(ctx
);
1012 dlist_fallback(ctx
);
1013 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
1016 static void GLAPIENTRY
1017 _save_CallList(GLuint l
)
1019 GET_CURRENT_CONTEXT(ctx
);
1020 dlist_fallback(ctx
);
1021 CALL_CallList(ctx
->Save
, (l
));
1024 static void GLAPIENTRY
1025 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
1027 GET_CURRENT_CONTEXT(ctx
);
1028 dlist_fallback(ctx
);
1029 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
1035 * Called when a glBegin is getting compiled into a display list.
1036 * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1039 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
1041 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1042 const GLuint i
= save
->prim_count
++;
1044 assert(i
< save
->prim_max
);
1045 save
->prims
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
1046 save
->prims
[i
].begin
= 1;
1047 save
->prims
[i
].end
= 0;
1048 save
->prims
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
1049 save
->prims
[i
].no_current_update
=
1050 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
1051 save
->prims
[i
].pad
= 0;
1052 save
->prims
[i
].start
= save
->vert_count
;
1053 save
->prims
[i
].count
= 0;
1054 save
->prims
[i
].num_instances
= 1;
1055 save
->prims
[i
].base_instance
= 0;
1056 save
->prims
[i
].is_indirect
= 0;
1058 if (save
->out_of_memory
) {
1059 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
1062 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
1065 /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1066 ctx
->Driver
.SaveNeedFlush
= GL_TRUE
;
1070 static void GLAPIENTRY
1073 GET_CURRENT_CONTEXT(ctx
);
1074 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1075 const GLint i
= save
->prim_count
- 1;
1077 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1078 save
->prims
[i
].end
= 1;
1079 save
->prims
[i
].count
= (save
->vert_count
- save
->prims
[i
].start
);
1081 if (i
== (GLint
) save
->prim_max
- 1) {
1082 _save_compile_vertex_list(ctx
);
1083 assert(save
->copied
.nr
== 0);
1086 /* Swap out this vertex format while outside begin/end. Any color,
1087 * etc. received between here and the next begin will be compiled
1090 if (save
->out_of_memory
) {
1091 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
1094 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1099 static void GLAPIENTRY
1100 _save_Begin(GLenum mode
)
1102 GET_CURRENT_CONTEXT(ctx
);
1104 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
1108 static void GLAPIENTRY
1109 _save_PrimitiveRestartNV(void)
1111 GET_CURRENT_CONTEXT(ctx
);
1112 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1114 if (save
->prim_count
== 0) {
1115 /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1118 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
,
1119 "glPrimitiveRestartNV called outside glBegin/End");
1121 /* get current primitive mode */
1122 GLenum curPrim
= save
->prims
[save
->prim_count
- 1].mode
;
1124 /* restart primitive */
1125 CALL_End(GET_DISPATCH(), ());
1126 vbo_save_NotifyBegin(ctx
, curPrim
);
1131 /* Unlike the functions above, these are to be hooked into the vtxfmt
1132 * maintained in ctx->ListState, active when the list is known or
1133 * suspected to be outside any begin/end primitive.
1134 * Note: OBE = Outside Begin/End
1136 static void GLAPIENTRY
1137 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1139 GET_CURRENT_CONTEXT(ctx
);
1140 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1141 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1142 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1143 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1144 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1145 CALL_End(GET_DISPATCH(), ());
1149 static void GLAPIENTRY
1150 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1152 GET_CURRENT_CONTEXT(ctx
);
1153 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1156 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1157 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawArrays(mode)");
1161 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawArrays(count<0)");
1165 if (save
->out_of_memory
)
1168 /* Make sure to process any VBO binding changes */
1169 _mesa_update_state(ctx
);
1173 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1174 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1176 for (i
= 0; i
< count
; i
++)
1177 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1178 CALL_End(GET_DISPATCH(), ());
1180 _ae_unmap_vbos(ctx
);
1184 static void GLAPIENTRY
1185 _save_OBE_MultiDrawArrays(GLenum mode
, const GLint
*first
,
1186 const GLsizei
*count
, GLsizei primcount
)
1188 GET_CURRENT_CONTEXT(ctx
);
1191 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1192 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMultiDrawArrays(mode)");
1196 if (primcount
< 0) {
1197 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1198 "glMultiDrawArrays(primcount<0)");
1202 for (i
= 0; i
< primcount
; i
++) {
1204 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1205 "glMultiDrawArrays(count[i]<0)");
1210 for (i
= 0; i
< primcount
; i
++) {
1212 _save_OBE_DrawArrays(mode
, first
[i
], count
[i
]);
1218 /* Could do better by copying the arrays and element list intact and
1219 * then emitting an indexed prim at runtime.
1221 static void GLAPIENTRY
1222 _save_OBE_DrawElementsBaseVertex(GLenum mode
, GLsizei count
, GLenum type
,
1223 const GLvoid
* indices
, GLint basevertex
)
1225 GET_CURRENT_CONTEXT(ctx
);
1226 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1227 struct gl_buffer_object
*indexbuf
= ctx
->Array
.VAO
->IndexBufferObj
;
1230 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1231 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(mode)");
1235 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1238 if (type
!= GL_UNSIGNED_BYTE
&&
1239 type
!= GL_UNSIGNED_SHORT
&&
1240 type
!= GL_UNSIGNED_INT
) {
1241 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glDrawElements(count<0)");
1245 if (save
->out_of_memory
)
1248 /* Make sure to process any VBO binding changes */
1249 _mesa_update_state(ctx
);
1253 if (_mesa_is_bufferobj(indexbuf
))
1255 ADD_POINTERS(indexbuf
->Mappings
[MAP_INTERNAL
].Pointer
, indices
);
1257 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1258 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1261 case GL_UNSIGNED_BYTE
:
1262 for (i
= 0; i
< count
; i
++)
1263 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLubyte
*) indices
)[i
]));
1265 case GL_UNSIGNED_SHORT
:
1266 for (i
= 0; i
< count
; i
++)
1267 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLushort
*) indices
)[i
]));
1269 case GL_UNSIGNED_INT
:
1270 for (i
= 0; i
< count
; i
++)
1271 CALL_ArrayElement(GET_DISPATCH(), (basevertex
+ ((GLuint
*) indices
)[i
]));
1274 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1278 CALL_End(GET_DISPATCH(), ());
1280 _ae_unmap_vbos(ctx
);
1283 static void GLAPIENTRY
1284 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1285 const GLvoid
* indices
)
1287 _save_OBE_DrawElementsBaseVertex(mode
, count
, type
, indices
, 0);
1291 static void GLAPIENTRY
1292 _save_OBE_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
1293 GLsizei count
, GLenum type
,
1294 const GLvoid
* indices
)
1296 GET_CURRENT_CONTEXT(ctx
);
1297 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1299 if (!_mesa_is_valid_prim_mode(ctx
, mode
)) {
1300 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(mode)");
1304 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1305 "glDrawRangeElements(count<0)");
1308 if (type
!= GL_UNSIGNED_BYTE
&&
1309 type
!= GL_UNSIGNED_SHORT
&&
1310 type
!= GL_UNSIGNED_INT
) {
1311 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glDrawRangeElements(type)");
1315 _mesa_compile_error(ctx
, GL_INVALID_VALUE
,
1316 "glDrawRangeElements(end < start)");
1320 if (save
->out_of_memory
)
1323 _save_OBE_DrawElements(mode
, count
, type
, indices
);
1327 static void GLAPIENTRY
1328 _save_OBE_MultiDrawElements(GLenum mode
, const GLsizei
*count
, GLenum type
,
1329 const GLvoid
* const *indices
, GLsizei primcount
)
1333 for (i
= 0; i
< primcount
; i
++) {
1335 CALL_DrawElements(GET_DISPATCH(), (mode
, count
[i
], type
, indices
[i
]));
1341 static void GLAPIENTRY
1342 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode
, const GLsizei
*count
,
1344 const GLvoid
* const *indices
,
1346 const GLint
*basevertex
)
1350 for (i
= 0; i
< primcount
; i
++) {
1352 CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode
, count
[i
], type
,
1361 _save_vtxfmt_init(struct gl_context
*ctx
)
1363 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1364 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1366 vfmt
->ArrayElement
= _ae_ArrayElement
;
1368 vfmt
->Color3f
= _save_Color3f
;
1369 vfmt
->Color3fv
= _save_Color3fv
;
1370 vfmt
->Color4f
= _save_Color4f
;
1371 vfmt
->Color4fv
= _save_Color4fv
;
1372 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1373 vfmt
->End
= _save_End
;
1374 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1375 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1376 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1377 vfmt
->Indexf
= _save_Indexf
;
1378 vfmt
->Indexfv
= _save_Indexfv
;
1379 vfmt
->Materialfv
= _save_Materialfv
;
1380 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1381 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1382 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1383 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1384 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1385 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1386 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1387 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1388 vfmt
->Normal3f
= _save_Normal3f
;
1389 vfmt
->Normal3fv
= _save_Normal3fv
;
1390 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1391 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1392 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1393 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1394 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1395 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1396 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1397 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1398 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1399 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1400 vfmt
->Vertex2f
= _save_Vertex2f
;
1401 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1402 vfmt
->Vertex3f
= _save_Vertex3f
;
1403 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1404 vfmt
->Vertex4f
= _save_Vertex4f
;
1405 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1406 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1407 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1408 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1409 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1410 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1411 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1412 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1413 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1415 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1416 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1417 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1418 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1419 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1420 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1421 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1422 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1424 /* integer-valued */
1425 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1426 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1427 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1428 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1429 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1430 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1431 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1433 /* unsigned integer-valued */
1434 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1435 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1436 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1437 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1438 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1439 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1440 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1442 vfmt
->VertexP2ui
= _save_VertexP2ui
;
1443 vfmt
->VertexP3ui
= _save_VertexP3ui
;
1444 vfmt
->VertexP4ui
= _save_VertexP4ui
;
1445 vfmt
->VertexP2uiv
= _save_VertexP2uiv
;
1446 vfmt
->VertexP3uiv
= _save_VertexP3uiv
;
1447 vfmt
->VertexP4uiv
= _save_VertexP4uiv
;
1449 vfmt
->TexCoordP1ui
= _save_TexCoordP1ui
;
1450 vfmt
->TexCoordP2ui
= _save_TexCoordP2ui
;
1451 vfmt
->TexCoordP3ui
= _save_TexCoordP3ui
;
1452 vfmt
->TexCoordP4ui
= _save_TexCoordP4ui
;
1453 vfmt
->TexCoordP1uiv
= _save_TexCoordP1uiv
;
1454 vfmt
->TexCoordP2uiv
= _save_TexCoordP2uiv
;
1455 vfmt
->TexCoordP3uiv
= _save_TexCoordP3uiv
;
1456 vfmt
->TexCoordP4uiv
= _save_TexCoordP4uiv
;
1458 vfmt
->MultiTexCoordP1ui
= _save_MultiTexCoordP1ui
;
1459 vfmt
->MultiTexCoordP2ui
= _save_MultiTexCoordP2ui
;
1460 vfmt
->MultiTexCoordP3ui
= _save_MultiTexCoordP3ui
;
1461 vfmt
->MultiTexCoordP4ui
= _save_MultiTexCoordP4ui
;
1462 vfmt
->MultiTexCoordP1uiv
= _save_MultiTexCoordP1uiv
;
1463 vfmt
->MultiTexCoordP2uiv
= _save_MultiTexCoordP2uiv
;
1464 vfmt
->MultiTexCoordP3uiv
= _save_MultiTexCoordP3uiv
;
1465 vfmt
->MultiTexCoordP4uiv
= _save_MultiTexCoordP4uiv
;
1467 vfmt
->NormalP3ui
= _save_NormalP3ui
;
1468 vfmt
->NormalP3uiv
= _save_NormalP3uiv
;
1470 vfmt
->ColorP3ui
= _save_ColorP3ui
;
1471 vfmt
->ColorP4ui
= _save_ColorP4ui
;
1472 vfmt
->ColorP3uiv
= _save_ColorP3uiv
;
1473 vfmt
->ColorP4uiv
= _save_ColorP4uiv
;
1475 vfmt
->SecondaryColorP3ui
= _save_SecondaryColorP3ui
;
1476 vfmt
->SecondaryColorP3uiv
= _save_SecondaryColorP3uiv
;
1478 vfmt
->VertexAttribP1ui
= _save_VertexAttribP1ui
;
1479 vfmt
->VertexAttribP2ui
= _save_VertexAttribP2ui
;
1480 vfmt
->VertexAttribP3ui
= _save_VertexAttribP3ui
;
1481 vfmt
->VertexAttribP4ui
= _save_VertexAttribP4ui
;
1483 vfmt
->VertexAttribP1uiv
= _save_VertexAttribP1uiv
;
1484 vfmt
->VertexAttribP2uiv
= _save_VertexAttribP2uiv
;
1485 vfmt
->VertexAttribP3uiv
= _save_VertexAttribP3uiv
;
1486 vfmt
->VertexAttribP4uiv
= _save_VertexAttribP4uiv
;
1488 vfmt
->VertexAttribL1d
= _save_VertexAttribL1d
;
1489 vfmt
->VertexAttribL2d
= _save_VertexAttribL2d
;
1490 vfmt
->VertexAttribL3d
= _save_VertexAttribL3d
;
1491 vfmt
->VertexAttribL4d
= _save_VertexAttribL4d
;
1493 vfmt
->VertexAttribL1dv
= _save_VertexAttribL1dv
;
1494 vfmt
->VertexAttribL2dv
= _save_VertexAttribL2dv
;
1495 vfmt
->VertexAttribL3dv
= _save_VertexAttribL3dv
;
1496 vfmt
->VertexAttribL4dv
= _save_VertexAttribL4dv
;
1498 vfmt
->VertexAttribL1ui64ARB
= _save_VertexAttribL1ui64ARB
;
1499 vfmt
->VertexAttribL1ui64vARB
= _save_VertexAttribL1ui64vARB
;
1501 /* This will all require us to fallback to saving the list as opcodes:
1503 vfmt
->CallList
= _save_CallList
;
1504 vfmt
->CallLists
= _save_CallLists
;
1506 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1507 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1508 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1509 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1510 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1511 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1513 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1514 * only used when we're inside a glBegin/End pair.
1516 vfmt
->Begin
= _save_Begin
;
1521 * Initialize the dispatch table with the VBO functions for display
1525 vbo_initialize_save_dispatch(const struct gl_context
*ctx
,
1526 struct _glapi_table
*exec
)
1528 SET_DrawArrays(exec
, _save_OBE_DrawArrays
);
1529 SET_MultiDrawArrays(exec
, _save_OBE_MultiDrawArrays
);
1530 SET_DrawElements(exec
, _save_OBE_DrawElements
);
1531 SET_DrawElementsBaseVertex(exec
, _save_OBE_DrawElementsBaseVertex
);
1532 SET_DrawRangeElements(exec
, _save_OBE_DrawRangeElements
);
1533 SET_MultiDrawElementsEXT(exec
, _save_OBE_MultiDrawElements
);
1534 SET_MultiDrawElementsBaseVertex(exec
, _save_OBE_MultiDrawElementsBaseVertex
);
1535 SET_Rectf(exec
, _save_OBE_Rectf
);
1536 /* Note: other glDraw functins aren't compiled into display lists */
1542 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1544 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1546 /* Noop when we are actually active:
1548 if (ctx
->Driver
.CurrentSavePrimitive
<= PRIM_MAX
)
1551 if (save
->vert_count
|| save
->prim_count
)
1552 _save_compile_vertex_list(ctx
);
1554 _save_copy_to_current(ctx
);
1555 _save_reset_vertex(ctx
);
1556 _save_reset_counters(ctx
);
1557 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1562 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1564 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1569 if (!save
->prim_store
)
1570 save
->prim_store
= alloc_prim_store();
1572 if (!save
->vertex_store
)
1573 save
->vertex_store
= alloc_vertex_store(ctx
);
1575 save
->buffer_ptr
= vbo_save_map_vertex_store(ctx
, save
->vertex_store
);
1577 _save_reset_vertex(ctx
);
1578 _save_reset_counters(ctx
);
1579 ctx
->Driver
.SaveNeedFlush
= GL_FALSE
;
1584 vbo_save_EndList(struct gl_context
*ctx
)
1586 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1588 /* EndList called inside a (saved) Begin/End pair?
1590 if (_mesa_inside_dlist_begin_end(ctx
)) {
1591 if (save
->prim_count
> 0) {
1592 GLint i
= save
->prim_count
- 1;
1593 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1594 save
->prims
[i
].end
= 0;
1595 save
->prims
[i
].count
= save
->vert_count
- save
->prims
[i
].start
;
1598 /* Make sure this vertex list gets replayed by the "loopback"
1601 save
->dangling_attr_ref
= GL_TRUE
;
1602 vbo_save_SaveFlushVertices(ctx
);
1604 /* Swap out this vertex format while outside begin/end. Any color,
1605 * etc. received between here and the next begin will be compiled
1608 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1611 vbo_save_unmap_vertex_store(ctx
, save
->vertex_store
);
1613 assert(save
->vertex_size
== 0);
1618 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1620 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1621 save
->replay_flags
|= dlist
->Flags
;
1626 vbo_save_EndCallList(struct gl_context
*ctx
)
1628 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1630 if (ctx
->ListState
.CallDepth
== 1) {
1631 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1632 * flag, if it is set:
1634 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1640 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1642 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1645 if (--node
->vertex_store
->refcount
== 0)
1646 free_vertex_store(ctx
, node
->vertex_store
);
1648 if (--node
->prim_store
->refcount
== 0)
1649 free(node
->prim_store
);
1651 free(node
->current_data
);
1652 node
->current_data
= NULL
;
1657 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
, FILE *f
)
1659 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1661 struct gl_buffer_object
*buffer
= node
->vertex_store
?
1662 node
->vertex_store
->bufferobj
: NULL
;
1665 fprintf(f
, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1667 node
->vertex_count
, node
->prim_count
, node
->vertex_size
,
1670 for (i
= 0; i
< node
->prim_count
; i
++) {
1671 struct _mesa_prim
*prim
= &node
->prims
[i
];
1672 fprintf(f
, " prim %d: %s%s %d..%d %s %s\n",
1674 _mesa_lookup_prim_by_nr(prim
->mode
),
1675 prim
->weak
? " (weak)" : "",
1677 prim
->start
+ prim
->count
,
1678 (prim
->begin
) ? "BEGIN" : "(wrap)",
1679 (prim
->end
) ? "END" : "(wrap)");
1685 * Called during context creation/init.
1688 _save_current_init(struct gl_context
*ctx
)
1690 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1693 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1694 const GLuint j
= i
- VBO_ATTRIB_POS
;
1695 assert(j
< VERT_ATTRIB_MAX
);
1696 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1697 save
->current
[i
] = (fi_type
*) ctx
->ListState
.CurrentAttrib
[j
];
1700 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1701 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1702 assert(j
< MAT_ATTRIB_MAX
);
1703 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1704 save
->current
[i
] = (fi_type
*) ctx
->ListState
.CurrentMaterial
[j
];
1710 * Initialize the display list compiler. Called during context creation.
1713 vbo_save_api_init(struct vbo_save_context
*save
)
1715 struct gl_context
*ctx
= save
->ctx
;
1718 save
->opcode_vertex_list
=
1719 _mesa_dlist_alloc_opcode(ctx
,
1720 sizeof(struct vbo_save_vertex_list
),
1721 vbo_save_playback_vertex_list
,
1722 vbo_destroy_vertex_list
,
1723 vbo_print_vertex_list
);
1725 _save_vtxfmt_init(ctx
);
1726 _save_current_init(ctx
);
1727 _mesa_noop_vtxfmt_init(&save
->vtxfmt_noop
);
1729 /* These will actually get set again when binding/drawing */
1730 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1731 save
->inputs
[i
] = &save
->arrays
[i
];