1 /**************************************************************************
3 Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
35 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/mfeatures.h"
78 #include "main/api_noop.h"
79 #include "main/api_validate.h"
80 #include "main/api_arrayelt.h"
81 #include "main/vtxfmt.h"
82 #include "main/dispatch.h"
84 #include "vbo_context.h"
95 /* An interesting VBO number/name to help with debugging */
96 #define VBO_BUF_ID 12345
100 * NOTE: Old 'parity' issue is gone, but copying can still be
101 * wrong-footed on replay.
104 _save_copy_vertices(struct gl_context
*ctx
,
105 const struct vbo_save_vertex_list
*node
,
106 const GLfloat
* src_buffer
)
108 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
109 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
- 1];
110 GLuint nr
= prim
->count
;
111 GLuint sz
= save
->vertex_size
;
112 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
113 GLfloat
*dst
= save
->copied
.buffer
;
119 switch (prim
->mode
) {
124 for (i
= 0; i
< ovf
; i
++)
125 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
126 sz
* sizeof(GLfloat
));
130 for (i
= 0; i
< ovf
; i
++)
131 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
132 sz
* sizeof(GLfloat
));
136 for (i
= 0; i
< ovf
; i
++)
137 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
138 sz
* sizeof(GLfloat
));
144 memcpy(dst
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
148 case GL_TRIANGLE_FAN
:
153 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
157 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
158 memcpy(dst
+ sz
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
161 case GL_TRIANGLE_STRIP
:
174 for (i
= 0; i
< ovf
; i
++)
175 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
176 sz
* sizeof(GLfloat
));
185 static struct vbo_save_vertex_store
*
186 alloc_vertex_store(struct gl_context
*ctx
)
188 struct vbo_save_vertex_store
*vertex_store
=
189 CALLOC_STRUCT(vbo_save_vertex_store
);
191 /* obj->Name needs to be non-zero, but won't ever be examined more
192 * closely than that. In particular these buffers won't be entered
193 * into the hash and can never be confused with ones visible to the
194 * user. Perhaps there could be a special number for internal
197 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
199 GL_ARRAY_BUFFER_ARB
);
201 ctx
->Driver
.BufferData(ctx
,
203 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
204 NULL
, GL_STATIC_DRAW_ARB
, vertex_store
->bufferobj
);
206 vertex_store
->buffer
= NULL
;
207 vertex_store
->used
= 0;
208 vertex_store
->refcount
= 1;
215 free_vertex_store(struct gl_context
*ctx
,
216 struct vbo_save_vertex_store
*vertex_store
)
218 assert(!vertex_store
->buffer
);
220 if (vertex_store
->bufferobj
) {
221 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
229 map_vertex_store(struct gl_context
*ctx
,
230 struct vbo_save_vertex_store
*vertex_store
)
232 assert(vertex_store
->bufferobj
);
233 assert(!vertex_store
->buffer
);
234 vertex_store
->buffer
=
235 (GLfloat
*) ctx
->Driver
.MapBuffer(ctx
,
236 GL_ARRAY_BUFFER_ARB
, /* not used */
237 GL_WRITE_ONLY
, /* not used */
241 assert(vertex_store
->buffer
);
242 return vertex_store
->buffer
+ vertex_store
->used
;
247 unmap_vertex_store(struct gl_context
*ctx
,
248 struct vbo_save_vertex_store
*vertex_store
)
250 ctx
->Driver
.UnmapBuffer(ctx
, GL_ARRAY_BUFFER_ARB
, vertex_store
->bufferobj
);
251 vertex_store
->buffer
= NULL
;
255 static struct vbo_save_primitive_store
*
256 alloc_prim_store(struct gl_context
*ctx
)
258 struct vbo_save_primitive_store
*store
=
259 CALLOC_STRUCT(vbo_save_primitive_store
);
268 _save_reset_counters(struct gl_context
*ctx
)
270 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
272 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
273 save
->buffer
= save
->vertex_store
->buffer
+ save
->vertex_store
->used
;
275 assert(save
->buffer
== save
->buffer_ptr
);
277 if (save
->vertex_size
)
278 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
283 save
->vert_count
= 0;
284 save
->prim_count
= 0;
285 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
286 save
->dangling_attr_ref
= 0;
291 * Insert the active immediate struct onto the display list currently
295 _save_compile_vertex_list(struct gl_context
*ctx
)
297 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
298 struct vbo_save_vertex_list
*node
;
300 /* Allocate space for this structure in the display list currently
303 node
= (struct vbo_save_vertex_list
*)
304 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
309 /* Duplicate our template, increment refcounts to the storage structs:
311 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
312 node
->vertex_size
= save
->vertex_size
;
313 node
->buffer_offset
=
314 (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
315 node
->count
= save
->vert_count
;
316 node
->wrap_count
= save
->copied
.nr
;
317 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
318 node
->prim
= save
->prim
;
319 node
->prim_count
= save
->prim_count
;
320 node
->vertex_store
= save
->vertex_store
;
321 node
->prim_store
= save
->prim_store
;
323 node
->vertex_store
->refcount
++;
324 node
->prim_store
->refcount
++;
326 if (node
->prim
[0].no_current_update
) {
327 node
->current_size
= 0;
328 node
->current_data
= NULL
;
331 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
332 node
->current_data
= NULL
;
334 if (node
->current_size
) {
335 /* If the malloc fails, we just pull the data out of the VBO
338 node
->current_data
= MALLOC(node
->current_size
* sizeof(GLfloat
));
339 if (node
->current_data
) {
340 const char *buffer
= (const char *) save
->vertex_store
->buffer
;
341 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
342 unsigned vertex_offset
= 0;
346 (node
->count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
348 memcpy(node
->current_data
,
349 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
350 node
->current_size
* sizeof(GLfloat
));
355 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->count
== 0);
357 if (save
->dangling_attr_ref
)
358 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
360 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
361 save
->prim_store
->used
+= node
->prim_count
;
363 /* Copy duplicated vertices
365 save
->copied
.nr
= _save_copy_vertices(ctx
, node
, save
->buffer
);
367 /* Deal with GL_COMPILE_AND_EXECUTE:
369 if (ctx
->ExecuteFlag
) {
370 struct _glapi_table
*dispatch
= GET_DISPATCH();
372 _glapi_set_dispatch(ctx
->Exec
);
374 vbo_loopback_vertex_list(ctx
,
375 (const GLfloat
*) ((const char *) save
->
376 vertex_store
->buffer
+
377 node
->buffer_offset
),
378 node
->attrsz
, node
->prim
, node
->prim_count
,
379 node
->wrap_count
, node
->vertex_size
);
381 _glapi_set_dispatch(dispatch
);
384 /* Decide whether the storage structs are full, or can be used for
385 * the next vertex lists as well.
387 if (save
->vertex_store
->used
>
388 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
392 unmap_vertex_store(ctx
, save
->vertex_store
);
394 /* Release old reference:
396 save
->vertex_store
->refcount
--;
397 assert(save
->vertex_store
->refcount
!= 0);
398 save
->vertex_store
= NULL
;
400 /* Allocate and map new store:
402 save
->vertex_store
= alloc_vertex_store(ctx
);
403 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
406 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
407 save
->prim_store
->refcount
--;
408 assert(save
->prim_store
->refcount
!= 0);
409 save
->prim_store
= alloc_prim_store(ctx
);
412 /* Reset our structures for the next run of vertices:
414 _save_reset_counters(ctx
);
419 * TODO -- If no new vertices have been stored, don't bother saving it.
422 _save_wrap_buffers(struct gl_context
*ctx
)
424 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
425 GLint i
= save
->prim_count
- 1;
428 GLboolean no_current_update
;
430 assert(i
< (GLint
) save
->prim_max
);
433 /* Close off in-progress primitive.
435 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
436 mode
= save
->prim
[i
].mode
;
437 weak
= save
->prim
[i
].weak
;
438 no_current_update
= save
->prim
[i
].no_current_update
;
440 /* store the copied vertices, and allocate a new list.
442 _save_compile_vertex_list(ctx
);
444 /* Restart interrupted primitive
446 save
->prim
[0].mode
= mode
;
447 save
->prim
[0].weak
= weak
;
448 save
->prim
[0].no_current_update
= no_current_update
;
449 save
->prim
[0].begin
= 0;
450 save
->prim
[0].end
= 0;
451 save
->prim
[0].pad
= 0;
452 save
->prim
[0].start
= 0;
453 save
->prim
[0].count
= 0;
454 save
->prim
[0].num_instances
= 1;
455 save
->prim_count
= 1;
460 * Called only when buffers are wrapped as the result of filling the
461 * vertex_store struct.
464 _save_wrap_filled_vertex(struct gl_context
*ctx
)
466 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
467 GLfloat
*data
= save
->copied
.buffer
;
470 /* Emit a glEnd to close off the last vertex list.
472 _save_wrap_buffers(ctx
);
474 /* Copy stored stored vertices to start of new list.
476 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
478 for (i
= 0; i
< save
->copied
.nr
; i
++) {
479 memcpy(save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
480 data
+= save
->vertex_size
;
481 save
->buffer_ptr
+= save
->vertex_size
;
488 _save_copy_to_current(struct gl_context
*ctx
)
490 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
493 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
494 if (save
->attrsz
[i
]) {
495 save
->currentsz
[i
][0] = save
->attrsz
[i
];
496 COPY_CLEAN_4V(save
->current
[i
], save
->attrsz
[i
], save
->attrptr
[i
]);
503 _save_copy_from_current(struct gl_context
*ctx
)
505 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
508 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
509 switch (save
->attrsz
[i
]) {
511 save
->attrptr
[i
][3] = save
->current
[i
][3];
513 save
->attrptr
[i
][2] = save
->current
[i
][2];
515 save
->attrptr
[i
][1] = save
->current
[i
][1];
517 save
->attrptr
[i
][0] = save
->current
[i
][0];
525 /* Flush existing data, set new attrib size, replay copied vertices.
528 _save_upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
530 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
535 /* Store the current run of vertices, and emit a GL_END. Emit a
536 * BEGIN in the new buffer.
538 if (save
->vert_count
)
539 _save_wrap_buffers(ctx
);
541 assert(save
->copied
.nr
== 0);
543 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
544 * when the attribute already exists in the vertex and is having
545 * its size increased.
547 _save_copy_to_current(ctx
);
551 oldsz
= save
->attrsz
[attr
];
552 save
->attrsz
[attr
] = newsz
;
554 save
->vertex_size
+= newsz
- oldsz
;
555 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
557 save
->vert_count
= 0;
559 /* Recalculate all the attrptr[] values:
561 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
562 if (save
->attrsz
[i
]) {
563 save
->attrptr
[i
] = tmp
;
564 tmp
+= save
->attrsz
[i
];
567 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
571 /* Copy from current to repopulate the vertex with correct values.
573 _save_copy_from_current(ctx
);
575 /* Replay stored vertices to translate them to new format here.
577 * If there are copied vertices and the new (upgraded) attribute
578 * has not been defined before, this list is somewhat degenerate,
579 * and will need fixup at runtime.
581 if (save
->copied
.nr
) {
582 GLfloat
*data
= save
->copied
.buffer
;
583 GLfloat
*dest
= save
->buffer
;
586 /* Need to note this and fix up at runtime (or loopback):
588 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
590 save
->dangling_attr_ref
= GL_TRUE
;
593 for (i
= 0; i
< save
->copied
.nr
; i
++) {
594 for (j
= 0; j
< VBO_ATTRIB_MAX
; j
++) {
595 if (save
->attrsz
[j
]) {
598 COPY_CLEAN_4V(dest
, oldsz
, data
);
603 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
608 GLint sz
= save
->attrsz
[j
];
609 COPY_SZ_4V(dest
, sz
, data
);
617 save
->buffer_ptr
= dest
;
618 save
->vert_count
+= save
->copied
.nr
;
624 save_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
626 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
628 if (sz
> save
->attrsz
[attr
]) {
629 /* New size is larger. Need to flush existing vertices and get
630 * an enlarged vertex format.
632 _save_upgrade_vertex(ctx
, attr
, sz
);
634 else if (sz
< save
->active_sz
[attr
]) {
635 static GLfloat id
[4] = { 0, 0, 0, 1 };
638 /* New size is equal or smaller - just need to fill in some
641 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
642 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
645 save
->active_sz
[attr
] = sz
;
650 _save_reset_vertex(struct gl_context
*ctx
)
652 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
655 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
657 save
->active_sz
[i
] = 0;
660 save
->vertex_size
= 0;
665 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
668 /* Only one size for each attribute may be active at once. Eg. if
669 * Color3f is installed/active, then Color4f may not be, even if the
670 * vertex actually contains 4 color coordinates. This is because the
671 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
672 * of the chooser function when switching between Color4f and Color3f.
674 #define ATTR(A, N, V0, V1, V2, V3) \
676 struct vbo_save_context *save = &vbo_context(ctx)->save; \
678 if (save->active_sz[A] != N) \
679 save_fixup_vertex(ctx, A, N); \
682 GLfloat *dest = save->attrptr[A]; \
683 if (N>0) dest[0] = V0; \
684 if (N>1) dest[1] = V1; \
685 if (N>2) dest[2] = V2; \
686 if (N>3) dest[3] = V3; \
692 for (i = 0; i < save->vertex_size; i++) \
693 save->buffer_ptr[i] = save->vertex[i]; \
695 save->buffer_ptr += save->vertex_size; \
697 if (++save->vert_count >= save->max_vert) \
698 _save_wrap_filled_vertex(ctx); \
702 #define TAG(x) _save_##x
704 #include "vbo_attrib_tmp.h"
709 /* Cope with EvalCoord/CallList called within a begin/end object:
710 * -- Flush current buffer
711 * -- Fallback to opcodes for the rest of the begin/end object.
714 dlist_fallback(struct gl_context
*ctx
)
716 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
718 if (save
->vert_count
|| save
->prim_count
) {
719 if (save
->prim_count
> 0) {
720 /* Close off in-progress primitive. */
721 GLint i
= save
->prim_count
- 1;
722 save
->prim
[i
].count
= save
->vert_count
- save
->prim
[i
].start
;
725 /* Need to replay this display list with loopback,
726 * unfortunately, otherwise this primitive won't be handled
729 save
->dangling_attr_ref
= 1;
731 _save_compile_vertex_list(ctx
);
734 _save_copy_to_current(ctx
);
735 _save_reset_vertex(ctx
);
736 _save_reset_counters(ctx
);
737 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
738 ctx
->Driver
.SaveNeedFlush
= 0;
742 static void GLAPIENTRY
743 _save_EvalCoord1f(GLfloat u
)
745 GET_CURRENT_CONTEXT(ctx
);
747 CALL_EvalCoord1f(ctx
->Save
, (u
));
750 static void GLAPIENTRY
751 _save_EvalCoord1fv(const GLfloat
* v
)
753 GET_CURRENT_CONTEXT(ctx
);
755 CALL_EvalCoord1fv(ctx
->Save
, (v
));
758 static void GLAPIENTRY
759 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
761 GET_CURRENT_CONTEXT(ctx
);
763 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
766 static void GLAPIENTRY
767 _save_EvalCoord2fv(const GLfloat
* v
)
769 GET_CURRENT_CONTEXT(ctx
);
771 CALL_EvalCoord2fv(ctx
->Save
, (v
));
774 static void GLAPIENTRY
775 _save_EvalPoint1(GLint i
)
777 GET_CURRENT_CONTEXT(ctx
);
779 CALL_EvalPoint1(ctx
->Save
, (i
));
782 static void GLAPIENTRY
783 _save_EvalPoint2(GLint i
, GLint j
)
785 GET_CURRENT_CONTEXT(ctx
);
787 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
790 static void GLAPIENTRY
791 _save_CallList(GLuint l
)
793 GET_CURRENT_CONTEXT(ctx
);
795 CALL_CallList(ctx
->Save
, (l
));
798 static void GLAPIENTRY
799 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
801 GET_CURRENT_CONTEXT(ctx
);
803 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
808 /* This begin is hooked into ... Updating of
809 * ctx->Driver.CurrentSavePrimitive is already taken care of.
812 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
814 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
816 GLuint i
= save
->prim_count
++;
818 assert(i
< save
->prim_max
);
819 save
->prim
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
820 save
->prim
[i
].begin
= 1;
821 save
->prim
[i
].end
= 0;
822 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
823 save
->prim
[i
].no_current_update
=
824 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
825 save
->prim
[i
].pad
= 0;
826 save
->prim
[i
].start
= save
->vert_count
;
827 save
->prim
[i
].count
= 0;
828 save
->prim
[i
].num_instances
= 1;
830 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
831 ctx
->Driver
.SaveNeedFlush
= 1;
836 static void GLAPIENTRY
839 GET_CURRENT_CONTEXT(ctx
);
840 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
841 GLint i
= save
->prim_count
- 1;
843 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
844 save
->prim
[i
].end
= 1;
845 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
847 if (i
== (GLint
) save
->prim_max
- 1) {
848 _save_compile_vertex_list(ctx
);
849 assert(save
->copied
.nr
== 0);
852 /* Swap out this vertex format while outside begin/end. Any color,
853 * etc. received between here and the next begin will be compiled
856 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
860 /* These are all errors as this vtxfmt is only installed inside
863 static void GLAPIENTRY
864 _save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
865 const GLvoid
* indices
)
867 GET_CURRENT_CONTEXT(ctx
);
872 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawElements");
876 static void GLAPIENTRY
877 _save_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
878 GLsizei count
, GLenum type
, const GLvoid
* indices
)
880 GET_CURRENT_CONTEXT(ctx
);
887 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements");
891 static void GLAPIENTRY
892 _save_DrawElementsBaseVertex(GLenum mode
, GLsizei count
, GLenum type
,
893 const GLvoid
* indices
, GLint basevertex
)
895 GET_CURRENT_CONTEXT(ctx
);
901 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawElements");
905 static void GLAPIENTRY
906 _save_DrawRangeElementsBaseVertex(GLenum mode
,
911 const GLvoid
* indices
, GLint basevertex
)
913 GET_CURRENT_CONTEXT(ctx
);
921 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements");
925 static void GLAPIENTRY
926 _save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
928 GET_CURRENT_CONTEXT(ctx
);
932 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawArrays");
936 static void GLAPIENTRY
937 _save_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
939 GET_CURRENT_CONTEXT(ctx
);
944 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glRectf");
948 static void GLAPIENTRY
949 _save_EvalMesh1(GLenum mode
, GLint i1
, GLint i2
)
951 GET_CURRENT_CONTEXT(ctx
);
955 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh1");
959 static void GLAPIENTRY
960 _save_EvalMesh2(GLenum mode
, GLint i1
, GLint i2
, GLint j1
, GLint j2
)
962 GET_CURRENT_CONTEXT(ctx
);
968 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh2");
972 static void GLAPIENTRY
973 _save_Begin(GLenum mode
)
975 GET_CURRENT_CONTEXT(ctx
);
977 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
981 static void GLAPIENTRY
982 _save_PrimitiveRestartNV(void)
985 GET_CURRENT_CONTEXT(ctx
);
987 curPrim
= ctx
->Driver
.CurrentSavePrimitive
;
990 _save_Begin(curPrim
);
994 /* Unlike the functions above, these are to be hooked into the vtxfmt
995 * maintained in ctx->ListState, active when the list is known or
996 * suspected to be outside any begin/end primitive.
998 static void GLAPIENTRY
999 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1001 GET_CURRENT_CONTEXT(ctx
);
1002 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1003 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1004 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1005 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1006 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1007 CALL_End(GET_DISPATCH(), ());
1011 static void GLAPIENTRY
1012 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1014 GET_CURRENT_CONTEXT(ctx
);
1017 if (!_mesa_validate_DrawArrays(ctx
, mode
, start
, count
))
1022 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1023 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1025 for (i
= 0; i
< count
; i
++)
1026 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1027 CALL_End(GET_DISPATCH(), ());
1029 _ae_unmap_vbos(ctx
);
1033 /* Could do better by copying the arrays and element list intact and
1034 * then emitting an indexed prim at runtime.
1036 static void GLAPIENTRY
1037 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1038 const GLvoid
* indices
)
1040 GET_CURRENT_CONTEXT(ctx
);
1043 if (!_mesa_validate_DrawElements(ctx
, mode
, count
, type
, indices
, 0))
1048 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
1050 ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
1052 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1053 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1056 case GL_UNSIGNED_BYTE
:
1057 for (i
= 0; i
< count
; i
++)
1058 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte
*) indices
)[i
]));
1060 case GL_UNSIGNED_SHORT
:
1061 for (i
= 0; i
< count
; i
++)
1062 CALL_ArrayElement(GET_DISPATCH(), (((GLushort
*) indices
)[i
]));
1064 case GL_UNSIGNED_INT
:
1065 for (i
= 0; i
< count
; i
++)
1066 CALL_ArrayElement(GET_DISPATCH(), (((GLuint
*) indices
)[i
]));
1069 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1073 CALL_End(GET_DISPATCH(), ());
1075 _ae_unmap_vbos(ctx
);
1079 static void GLAPIENTRY
1080 _save_OBE_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
1081 GLsizei count
, GLenum type
,
1082 const GLvoid
* indices
)
1084 GET_CURRENT_CONTEXT(ctx
);
1085 if (_mesa_validate_DrawRangeElements(ctx
, mode
,
1086 start
, end
, count
, type
, indices
, 0)) {
1087 _save_OBE_DrawElements(mode
, count
, type
, indices
);
1093 _save_vtxfmt_init(struct gl_context
*ctx
)
1095 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1096 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1098 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
1100 vfmt
->Begin
= _save_Begin
;
1101 vfmt
->Color3f
= _save_Color3f
;
1102 vfmt
->Color3fv
= _save_Color3fv
;
1103 vfmt
->Color4f
= _save_Color4f
;
1104 vfmt
->Color4fv
= _save_Color4fv
;
1105 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1106 vfmt
->End
= _save_End
;
1107 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1108 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1109 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1110 vfmt
->Indexf
= _save_Indexf
;
1111 vfmt
->Indexfv
= _save_Indexfv
;
1112 vfmt
->Materialfv
= _save_Materialfv
;
1113 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1114 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1115 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1116 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1117 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1118 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1119 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1120 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1121 vfmt
->Normal3f
= _save_Normal3f
;
1122 vfmt
->Normal3fv
= _save_Normal3fv
;
1123 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1124 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1125 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1126 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1127 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1128 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1129 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1130 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1131 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1132 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1133 vfmt
->Vertex2f
= _save_Vertex2f
;
1134 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1135 vfmt
->Vertex3f
= _save_Vertex3f
;
1136 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1137 vfmt
->Vertex4f
= _save_Vertex4f
;
1138 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1139 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1140 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1141 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1142 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1143 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1144 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1145 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1146 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1148 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1149 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1150 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1151 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1152 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1153 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1154 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1155 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1157 /* integer-valued */
1158 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1159 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1160 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1161 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1162 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1163 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1164 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1166 /* unsigned integer-valued */
1167 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1168 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1169 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1170 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1171 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1172 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1173 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1175 /* This will all require us to fallback to saving the list as opcodes:
1177 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1179 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1181 /* These are all errors as we at least know we are in some sort of
1184 vfmt
->Begin
= _save_Begin
;
1185 vfmt
->Rectf
= _save_Rectf
;
1186 vfmt
->DrawArrays
= _save_DrawArrays
;
1187 vfmt
->DrawElements
= _save_DrawElements
;
1188 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1189 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1190 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1191 /* Loops back into vfmt->DrawElements */
1192 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1193 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1198 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1200 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1202 /* Noop when we are actually active:
1204 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1205 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1208 if (save
->vert_count
|| save
->prim_count
)
1209 _save_compile_vertex_list(ctx
);
1211 _save_copy_to_current(ctx
);
1212 _save_reset_vertex(ctx
);
1213 _save_reset_counters(ctx
);
1214 ctx
->Driver
.SaveNeedFlush
= 0;
1219 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1221 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1226 if (!save
->prim_store
)
1227 save
->prim_store
= alloc_prim_store(ctx
);
1229 if (!save
->vertex_store
)
1230 save
->vertex_store
= alloc_vertex_store(ctx
);
1232 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
1234 _save_reset_vertex(ctx
);
1235 _save_reset_counters(ctx
);
1236 ctx
->Driver
.SaveNeedFlush
= 0;
1241 vbo_save_EndList(struct gl_context
*ctx
)
1243 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1245 /* EndList called inside a (saved) Begin/End pair?
1247 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1249 if (save
->prim_count
> 0) {
1250 GLint i
= save
->prim_count
- 1;
1251 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1252 save
->prim
[i
].end
= 0;
1253 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
1256 /* Make sure this vertex list gets replayed by the "loopback"
1259 save
->dangling_attr_ref
= 1;
1260 vbo_save_SaveFlushVertices(ctx
);
1262 /* Swap out this vertex format while outside begin/end. Any color,
1263 * etc. received between here and the next begin will be compiled
1266 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1269 unmap_vertex_store(ctx
, save
->vertex_store
);
1271 assert(save
->vertex_size
== 0);
1276 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1278 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1279 save
->replay_flags
|= dlist
->Flags
;
1284 vbo_save_EndCallList(struct gl_context
*ctx
)
1286 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1288 if (ctx
->ListState
.CallDepth
== 1) {
1289 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1290 * flag, if it is set:
1292 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1298 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1300 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1303 if (--node
->vertex_store
->refcount
== 0)
1304 free_vertex_store(ctx
, node
->vertex_store
);
1306 if (--node
->prim_store
->refcount
== 0)
1307 FREE(node
->prim_store
);
1309 if (node
->current_data
) {
1310 FREE(node
->current_data
);
1311 node
->current_data
= NULL
;
1317 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
)
1319 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1323 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1324 node
->count
, node
->prim_count
, node
->vertex_size
);
1326 for (i
= 0; i
< node
->prim_count
; i
++) {
1327 struct _mesa_prim
*prim
= &node
->prim
[i
];
1328 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1330 _mesa_lookup_prim_by_nr(prim
->mode
),
1331 prim
->weak
? " (weak)" : "",
1333 prim
->start
+ prim
->count
,
1334 (prim
->begin
) ? "BEGIN" : "(wrap)",
1335 (prim
->end
) ? "END" : "(wrap)");
1341 _save_current_init(struct gl_context
*ctx
)
1343 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1346 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1347 const GLuint j
= i
- VBO_ATTRIB_POS
;
1348 ASSERT(j
< VERT_ATTRIB_MAX
);
1349 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1350 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1353 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1354 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1355 ASSERT(j
< MAT_ATTRIB_MAX
);
1356 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1357 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1363 * Initialize the display list compiler
1366 vbo_save_api_init(struct vbo_save_context
*save
)
1368 struct gl_context
*ctx
= save
->ctx
;
1371 save
->opcode_vertex_list
=
1372 _mesa_dlist_alloc_opcode(ctx
,
1373 sizeof(struct vbo_save_vertex_list
),
1374 vbo_save_playback_vertex_list
,
1375 vbo_destroy_vertex_list
,
1376 vbo_print_vertex_list
);
1378 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1380 _save_vtxfmt_init(ctx
);
1381 _save_current_init(ctx
);
1383 /* These will actually get set again when binding/drawing */
1384 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1385 save
->inputs
[i
] = &save
->arrays
[i
];
1387 /* Hook our array functions into the outside-begin-end vtxfmt in
1390 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1391 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1392 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1393 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1394 /* loops back into _save_OBE_DrawElements */
1395 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
=
1396 _mesa_noop_MultiDrawElements
;
1397 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
=
1398 _mesa_noop_MultiDrawElementsBaseVertex
;
1399 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1403 #endif /* FEATURE_dlist */