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
.MapBufferRange(ctx
, 0,
236 vertex_store
->bufferobj
->Size
,
237 GL_MAP_WRITE_BIT
, /* not used */
238 vertex_store
->bufferobj
);
240 assert(vertex_store
->buffer
);
241 return vertex_store
->buffer
+ vertex_store
->used
;
246 unmap_vertex_store(struct gl_context
*ctx
,
247 struct vbo_save_vertex_store
*vertex_store
)
249 ctx
->Driver
.UnmapBuffer(ctx
, vertex_store
->bufferobj
);
250 vertex_store
->buffer
= NULL
;
254 static struct vbo_save_primitive_store
*
255 alloc_prim_store(struct gl_context
*ctx
)
257 struct vbo_save_primitive_store
*store
=
258 CALLOC_STRUCT(vbo_save_primitive_store
);
267 _save_reset_counters(struct gl_context
*ctx
)
269 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
271 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
272 save
->buffer
= save
->vertex_store
->buffer
+ save
->vertex_store
->used
;
274 assert(save
->buffer
== save
->buffer_ptr
);
276 if (save
->vertex_size
)
277 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
282 save
->vert_count
= 0;
283 save
->prim_count
= 0;
284 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
285 save
->dangling_attr_ref
= 0;
290 * Insert the active immediate struct onto the display list currently
294 _save_compile_vertex_list(struct gl_context
*ctx
)
296 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
297 struct vbo_save_vertex_list
*node
;
299 /* Allocate space for this structure in the display list currently
302 node
= (struct vbo_save_vertex_list
*)
303 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
308 /* Duplicate our template, increment refcounts to the storage structs:
310 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
311 node
->vertex_size
= save
->vertex_size
;
312 node
->buffer_offset
=
313 (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
314 node
->count
= save
->vert_count
;
315 node
->wrap_count
= save
->copied
.nr
;
316 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
317 node
->prim
= save
->prim
;
318 node
->prim_count
= save
->prim_count
;
319 node
->vertex_store
= save
->vertex_store
;
320 node
->prim_store
= save
->prim_store
;
322 node
->vertex_store
->refcount
++;
323 node
->prim_store
->refcount
++;
325 if (node
->prim
[0].no_current_update
) {
326 node
->current_size
= 0;
327 node
->current_data
= NULL
;
330 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
331 node
->current_data
= NULL
;
333 if (node
->current_size
) {
334 /* If the malloc fails, we just pull the data out of the VBO
337 node
->current_data
= MALLOC(node
->current_size
* sizeof(GLfloat
));
338 if (node
->current_data
) {
339 const char *buffer
= (const char *) save
->vertex_store
->buffer
;
340 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
341 unsigned vertex_offset
= 0;
345 (node
->count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
347 memcpy(node
->current_data
,
348 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
349 node
->current_size
* sizeof(GLfloat
));
354 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->count
== 0);
356 if (save
->dangling_attr_ref
)
357 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
359 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
360 save
->prim_store
->used
+= node
->prim_count
;
362 /* Copy duplicated vertices
364 save
->copied
.nr
= _save_copy_vertices(ctx
, node
, save
->buffer
);
366 /* Deal with GL_COMPILE_AND_EXECUTE:
368 if (ctx
->ExecuteFlag
) {
369 struct _glapi_table
*dispatch
= GET_DISPATCH();
371 _glapi_set_dispatch(ctx
->Exec
);
373 vbo_loopback_vertex_list(ctx
,
374 (const GLfloat
*) ((const char *) save
->
375 vertex_store
->buffer
+
376 node
->buffer_offset
),
377 node
->attrsz
, node
->prim
, node
->prim_count
,
378 node
->wrap_count
, node
->vertex_size
);
380 _glapi_set_dispatch(dispatch
);
383 /* Decide whether the storage structs are full, or can be used for
384 * the next vertex lists as well.
386 if (save
->vertex_store
->used
>
387 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
391 unmap_vertex_store(ctx
, save
->vertex_store
);
393 /* Release old reference:
395 save
->vertex_store
->refcount
--;
396 assert(save
->vertex_store
->refcount
!= 0);
397 save
->vertex_store
= NULL
;
399 /* Allocate and map new store:
401 save
->vertex_store
= alloc_vertex_store(ctx
);
402 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
405 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
406 save
->prim_store
->refcount
--;
407 assert(save
->prim_store
->refcount
!= 0);
408 save
->prim_store
= alloc_prim_store(ctx
);
411 /* Reset our structures for the next run of vertices:
413 _save_reset_counters(ctx
);
418 * TODO -- If no new vertices have been stored, don't bother saving it.
421 _save_wrap_buffers(struct gl_context
*ctx
)
423 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
424 GLint i
= save
->prim_count
- 1;
427 GLboolean no_current_update
;
429 assert(i
< (GLint
) save
->prim_max
);
432 /* Close off in-progress primitive.
434 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
435 mode
= save
->prim
[i
].mode
;
436 weak
= save
->prim
[i
].weak
;
437 no_current_update
= save
->prim
[i
].no_current_update
;
439 /* store the copied vertices, and allocate a new list.
441 _save_compile_vertex_list(ctx
);
443 /* Restart interrupted primitive
445 save
->prim
[0].mode
= mode
;
446 save
->prim
[0].weak
= weak
;
447 save
->prim
[0].no_current_update
= no_current_update
;
448 save
->prim
[0].begin
= 0;
449 save
->prim
[0].end
= 0;
450 save
->prim
[0].pad
= 0;
451 save
->prim
[0].start
= 0;
452 save
->prim
[0].count
= 0;
453 save
->prim
[0].num_instances
= 1;
454 save
->prim_count
= 1;
459 * Called only when buffers are wrapped as the result of filling the
460 * vertex_store struct.
463 _save_wrap_filled_vertex(struct gl_context
*ctx
)
465 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
466 GLfloat
*data
= save
->copied
.buffer
;
469 /* Emit a glEnd to close off the last vertex list.
471 _save_wrap_buffers(ctx
);
473 /* Copy stored stored vertices to start of new list.
475 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
477 for (i
= 0; i
< save
->copied
.nr
; i
++) {
478 memcpy(save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
479 data
+= save
->vertex_size
;
480 save
->buffer_ptr
+= save
->vertex_size
;
487 _save_copy_to_current(struct gl_context
*ctx
)
489 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
492 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
493 if (save
->attrsz
[i
]) {
494 save
->currentsz
[i
][0] = save
->attrsz
[i
];
495 COPY_CLEAN_4V(save
->current
[i
], save
->attrsz
[i
], save
->attrptr
[i
]);
502 _save_copy_from_current(struct gl_context
*ctx
)
504 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
507 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
508 switch (save
->attrsz
[i
]) {
510 save
->attrptr
[i
][3] = save
->current
[i
][3];
512 save
->attrptr
[i
][2] = save
->current
[i
][2];
514 save
->attrptr
[i
][1] = save
->current
[i
][1];
516 save
->attrptr
[i
][0] = save
->current
[i
][0];
524 /* Flush existing data, set new attrib size, replay copied vertices.
527 _save_upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
529 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
534 /* Store the current run of vertices, and emit a GL_END. Emit a
535 * BEGIN in the new buffer.
537 if (save
->vert_count
)
538 _save_wrap_buffers(ctx
);
540 assert(save
->copied
.nr
== 0);
542 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
543 * when the attribute already exists in the vertex and is having
544 * its size increased.
546 _save_copy_to_current(ctx
);
550 oldsz
= save
->attrsz
[attr
];
551 save
->attrsz
[attr
] = newsz
;
553 save
->vertex_size
+= newsz
- oldsz
;
554 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
556 save
->vert_count
= 0;
558 /* Recalculate all the attrptr[] values:
560 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
561 if (save
->attrsz
[i
]) {
562 save
->attrptr
[i
] = tmp
;
563 tmp
+= save
->attrsz
[i
];
566 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
570 /* Copy from current to repopulate the vertex with correct values.
572 _save_copy_from_current(ctx
);
574 /* Replay stored vertices to translate them to new format here.
576 * If there are copied vertices and the new (upgraded) attribute
577 * has not been defined before, this list is somewhat degenerate,
578 * and will need fixup at runtime.
580 if (save
->copied
.nr
) {
581 GLfloat
*data
= save
->copied
.buffer
;
582 GLfloat
*dest
= save
->buffer
;
585 /* Need to note this and fix up at runtime (or loopback):
587 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
589 save
->dangling_attr_ref
= GL_TRUE
;
592 for (i
= 0; i
< save
->copied
.nr
; i
++) {
593 for (j
= 0; j
< VBO_ATTRIB_MAX
; j
++) {
594 if (save
->attrsz
[j
]) {
597 COPY_CLEAN_4V(dest
, oldsz
, data
);
602 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
607 GLint sz
= save
->attrsz
[j
];
608 COPY_SZ_4V(dest
, sz
, data
);
616 save
->buffer_ptr
= dest
;
617 save
->vert_count
+= save
->copied
.nr
;
623 save_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
625 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
627 if (sz
> save
->attrsz
[attr
]) {
628 /* New size is larger. Need to flush existing vertices and get
629 * an enlarged vertex format.
631 _save_upgrade_vertex(ctx
, attr
, sz
);
633 else if (sz
< save
->active_sz
[attr
]) {
634 static GLfloat id
[4] = { 0, 0, 0, 1 };
637 /* New size is equal or smaller - just need to fill in some
640 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
641 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
644 save
->active_sz
[attr
] = sz
;
649 _save_reset_vertex(struct gl_context
*ctx
)
651 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
654 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
656 save
->active_sz
[i
] = 0;
659 save
->vertex_size
= 0;
664 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
667 /* Only one size for each attribute may be active at once. Eg. if
668 * Color3f is installed/active, then Color4f may not be, even if the
669 * vertex actually contains 4 color coordinates. This is because the
670 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
671 * of the chooser function when switching between Color4f and Color3f.
673 #define ATTR(A, N, V0, V1, V2, V3) \
675 struct vbo_save_context *save = &vbo_context(ctx)->save; \
677 if (save->active_sz[A] != N) \
678 save_fixup_vertex(ctx, A, N); \
681 GLfloat *dest = save->attrptr[A]; \
682 if (N>0) dest[0] = V0; \
683 if (N>1) dest[1] = V1; \
684 if (N>2) dest[2] = V2; \
685 if (N>3) dest[3] = V3; \
691 for (i = 0; i < save->vertex_size; i++) \
692 save->buffer_ptr[i] = save->vertex[i]; \
694 save->buffer_ptr += save->vertex_size; \
696 if (++save->vert_count >= save->max_vert) \
697 _save_wrap_filled_vertex(ctx); \
701 #define TAG(x) _save_##x
703 #include "vbo_attrib_tmp.h"
708 /* Cope with EvalCoord/CallList called within a begin/end object:
709 * -- Flush current buffer
710 * -- Fallback to opcodes for the rest of the begin/end object.
713 dlist_fallback(struct gl_context
*ctx
)
715 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
717 if (save
->vert_count
|| save
->prim_count
) {
718 if (save
->prim_count
> 0) {
719 /* Close off in-progress primitive. */
720 GLint i
= save
->prim_count
- 1;
721 save
->prim
[i
].count
= save
->vert_count
- save
->prim
[i
].start
;
724 /* Need to replay this display list with loopback,
725 * unfortunately, otherwise this primitive won't be handled
728 save
->dangling_attr_ref
= 1;
730 _save_compile_vertex_list(ctx
);
733 _save_copy_to_current(ctx
);
734 _save_reset_vertex(ctx
);
735 _save_reset_counters(ctx
);
736 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
737 ctx
->Driver
.SaveNeedFlush
= 0;
741 static void GLAPIENTRY
742 _save_EvalCoord1f(GLfloat u
)
744 GET_CURRENT_CONTEXT(ctx
);
746 CALL_EvalCoord1f(ctx
->Save
, (u
));
749 static void GLAPIENTRY
750 _save_EvalCoord1fv(const GLfloat
* v
)
752 GET_CURRENT_CONTEXT(ctx
);
754 CALL_EvalCoord1fv(ctx
->Save
, (v
));
757 static void GLAPIENTRY
758 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
760 GET_CURRENT_CONTEXT(ctx
);
762 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
765 static void GLAPIENTRY
766 _save_EvalCoord2fv(const GLfloat
* v
)
768 GET_CURRENT_CONTEXT(ctx
);
770 CALL_EvalCoord2fv(ctx
->Save
, (v
));
773 static void GLAPIENTRY
774 _save_EvalPoint1(GLint i
)
776 GET_CURRENT_CONTEXT(ctx
);
778 CALL_EvalPoint1(ctx
->Save
, (i
));
781 static void GLAPIENTRY
782 _save_EvalPoint2(GLint i
, GLint j
)
784 GET_CURRENT_CONTEXT(ctx
);
786 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
789 static void GLAPIENTRY
790 _save_CallList(GLuint l
)
792 GET_CURRENT_CONTEXT(ctx
);
794 CALL_CallList(ctx
->Save
, (l
));
797 static void GLAPIENTRY
798 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
800 GET_CURRENT_CONTEXT(ctx
);
802 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
807 /* This begin is hooked into ... Updating of
808 * ctx->Driver.CurrentSavePrimitive is already taken care of.
811 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
813 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
815 GLuint i
= save
->prim_count
++;
817 assert(i
< save
->prim_max
);
818 save
->prim
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
819 save
->prim
[i
].begin
= 1;
820 save
->prim
[i
].end
= 0;
821 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
822 save
->prim
[i
].no_current_update
=
823 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
824 save
->prim
[i
].pad
= 0;
825 save
->prim
[i
].start
= save
->vert_count
;
826 save
->prim
[i
].count
= 0;
827 save
->prim
[i
].num_instances
= 1;
829 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
830 ctx
->Driver
.SaveNeedFlush
= 1;
835 static void GLAPIENTRY
838 GET_CURRENT_CONTEXT(ctx
);
839 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
840 GLint i
= save
->prim_count
- 1;
842 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
843 save
->prim
[i
].end
= 1;
844 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
846 if (i
== (GLint
) save
->prim_max
- 1) {
847 _save_compile_vertex_list(ctx
);
848 assert(save
->copied
.nr
== 0);
851 /* Swap out this vertex format while outside begin/end. Any color,
852 * etc. received between here and the next begin will be compiled
855 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
859 /* These are all errors as this vtxfmt is only installed inside
862 static void GLAPIENTRY
863 _save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
864 const GLvoid
* indices
)
866 GET_CURRENT_CONTEXT(ctx
);
871 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawElements");
875 static void GLAPIENTRY
876 _save_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
877 GLsizei count
, GLenum type
, const GLvoid
* indices
)
879 GET_CURRENT_CONTEXT(ctx
);
886 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements");
890 static void GLAPIENTRY
891 _save_DrawElementsBaseVertex(GLenum mode
, GLsizei count
, GLenum type
,
892 const GLvoid
* indices
, GLint basevertex
)
894 GET_CURRENT_CONTEXT(ctx
);
900 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawElements");
904 static void GLAPIENTRY
905 _save_DrawRangeElementsBaseVertex(GLenum mode
,
910 const GLvoid
* indices
, GLint basevertex
)
912 GET_CURRENT_CONTEXT(ctx
);
920 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements");
924 static void GLAPIENTRY
925 _save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
927 GET_CURRENT_CONTEXT(ctx
);
931 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawArrays");
935 static void GLAPIENTRY
936 _save_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
938 GET_CURRENT_CONTEXT(ctx
);
943 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glRectf");
947 static void GLAPIENTRY
948 _save_EvalMesh1(GLenum mode
, GLint i1
, GLint i2
)
950 GET_CURRENT_CONTEXT(ctx
);
954 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh1");
958 static void GLAPIENTRY
959 _save_EvalMesh2(GLenum mode
, GLint i1
, GLint i2
, GLint j1
, GLint j2
)
961 GET_CURRENT_CONTEXT(ctx
);
967 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh2");
971 static void GLAPIENTRY
972 _save_Begin(GLenum mode
)
974 GET_CURRENT_CONTEXT(ctx
);
976 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
980 static void GLAPIENTRY
981 _save_PrimitiveRestartNV(void)
984 GET_CURRENT_CONTEXT(ctx
);
986 curPrim
= ctx
->Driver
.CurrentSavePrimitive
;
989 _save_Begin(curPrim
);
993 /* Unlike the functions above, these are to be hooked into the vtxfmt
994 * maintained in ctx->ListState, active when the list is known or
995 * suspected to be outside any begin/end primitive.
997 static void GLAPIENTRY
998 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1000 GET_CURRENT_CONTEXT(ctx
);
1001 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1002 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1003 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1004 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1005 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1006 CALL_End(GET_DISPATCH(), ());
1010 static void GLAPIENTRY
1011 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1013 GET_CURRENT_CONTEXT(ctx
);
1016 if (!_mesa_validate_DrawArrays(ctx
, mode
, start
, count
))
1021 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1022 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1024 for (i
= 0; i
< count
; i
++)
1025 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1026 CALL_End(GET_DISPATCH(), ());
1028 _ae_unmap_vbos(ctx
);
1032 /* Could do better by copying the arrays and element list intact and
1033 * then emitting an indexed prim at runtime.
1035 static void GLAPIENTRY
1036 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1037 const GLvoid
* indices
)
1039 GET_CURRENT_CONTEXT(ctx
);
1042 if (!_mesa_validate_DrawElements(ctx
, mode
, count
, type
, indices
, 0))
1047 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
1049 ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
1051 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1052 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1055 case GL_UNSIGNED_BYTE
:
1056 for (i
= 0; i
< count
; i
++)
1057 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte
*) indices
)[i
]));
1059 case GL_UNSIGNED_SHORT
:
1060 for (i
= 0; i
< count
; i
++)
1061 CALL_ArrayElement(GET_DISPATCH(), (((GLushort
*) indices
)[i
]));
1063 case GL_UNSIGNED_INT
:
1064 for (i
= 0; i
< count
; i
++)
1065 CALL_ArrayElement(GET_DISPATCH(), (((GLuint
*) indices
)[i
]));
1068 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1072 CALL_End(GET_DISPATCH(), ());
1074 _ae_unmap_vbos(ctx
);
1078 static void GLAPIENTRY
1079 _save_OBE_DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
,
1080 GLsizei count
, GLenum type
,
1081 const GLvoid
* indices
)
1083 GET_CURRENT_CONTEXT(ctx
);
1084 if (_mesa_validate_DrawRangeElements(ctx
, mode
,
1085 start
, end
, count
, type
, indices
, 0)) {
1086 _save_OBE_DrawElements(mode
, count
, type
, indices
);
1092 _save_vtxfmt_init(struct gl_context
*ctx
)
1094 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1095 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1097 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
1099 vfmt
->Begin
= _save_Begin
;
1100 vfmt
->Color3f
= _save_Color3f
;
1101 vfmt
->Color3fv
= _save_Color3fv
;
1102 vfmt
->Color4f
= _save_Color4f
;
1103 vfmt
->Color4fv
= _save_Color4fv
;
1104 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1105 vfmt
->End
= _save_End
;
1106 vfmt
->PrimitiveRestartNV
= _save_PrimitiveRestartNV
;
1107 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1108 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1109 vfmt
->Indexf
= _save_Indexf
;
1110 vfmt
->Indexfv
= _save_Indexfv
;
1111 vfmt
->Materialfv
= _save_Materialfv
;
1112 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1113 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1114 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1115 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1116 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1117 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1118 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1119 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1120 vfmt
->Normal3f
= _save_Normal3f
;
1121 vfmt
->Normal3fv
= _save_Normal3fv
;
1122 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1123 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1124 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1125 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1126 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1127 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1128 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1129 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1130 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1131 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1132 vfmt
->Vertex2f
= _save_Vertex2f
;
1133 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1134 vfmt
->Vertex3f
= _save_Vertex3f
;
1135 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1136 vfmt
->Vertex4f
= _save_Vertex4f
;
1137 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1138 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1139 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1140 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1141 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1142 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1143 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1144 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1145 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1147 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1148 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1149 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1150 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1151 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1152 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1153 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1154 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1156 /* integer-valued */
1157 vfmt
->VertexAttribI1i
= _save_VertexAttribI1i
;
1158 vfmt
->VertexAttribI2i
= _save_VertexAttribI2i
;
1159 vfmt
->VertexAttribI3i
= _save_VertexAttribI3i
;
1160 vfmt
->VertexAttribI4i
= _save_VertexAttribI4i
;
1161 vfmt
->VertexAttribI2iv
= _save_VertexAttribI2iv
;
1162 vfmt
->VertexAttribI3iv
= _save_VertexAttribI3iv
;
1163 vfmt
->VertexAttribI4iv
= _save_VertexAttribI4iv
;
1165 /* unsigned integer-valued */
1166 vfmt
->VertexAttribI1ui
= _save_VertexAttribI1ui
;
1167 vfmt
->VertexAttribI2ui
= _save_VertexAttribI2ui
;
1168 vfmt
->VertexAttribI3ui
= _save_VertexAttribI3ui
;
1169 vfmt
->VertexAttribI4ui
= _save_VertexAttribI4ui
;
1170 vfmt
->VertexAttribI2uiv
= _save_VertexAttribI2uiv
;
1171 vfmt
->VertexAttribI3uiv
= _save_VertexAttribI3uiv
;
1172 vfmt
->VertexAttribI4uiv
= _save_VertexAttribI4uiv
;
1174 /* This will all require us to fallback to saving the list as opcodes:
1176 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1178 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1180 /* These are all errors as we at least know we are in some sort of
1183 vfmt
->Begin
= _save_Begin
;
1184 vfmt
->Rectf
= _save_Rectf
;
1185 vfmt
->DrawArrays
= _save_DrawArrays
;
1186 vfmt
->DrawElements
= _save_DrawElements
;
1187 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1188 vfmt
->DrawElementsBaseVertex
= _save_DrawElementsBaseVertex
;
1189 vfmt
->DrawRangeElementsBaseVertex
= _save_DrawRangeElementsBaseVertex
;
1190 /* Loops back into vfmt->DrawElements */
1191 vfmt
->MultiDrawElementsEXT
= _mesa_noop_MultiDrawElements
;
1192 vfmt
->MultiDrawElementsBaseVertex
= _mesa_noop_MultiDrawElementsBaseVertex
;
1197 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1199 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1201 /* Noop when we are actually active:
1203 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1204 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1207 if (save
->vert_count
|| save
->prim_count
)
1208 _save_compile_vertex_list(ctx
);
1210 _save_copy_to_current(ctx
);
1211 _save_reset_vertex(ctx
);
1212 _save_reset_counters(ctx
);
1213 ctx
->Driver
.SaveNeedFlush
= 0;
1218 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1220 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1225 if (!save
->prim_store
)
1226 save
->prim_store
= alloc_prim_store(ctx
);
1228 if (!save
->vertex_store
)
1229 save
->vertex_store
= alloc_vertex_store(ctx
);
1231 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
1233 _save_reset_vertex(ctx
);
1234 _save_reset_counters(ctx
);
1235 ctx
->Driver
.SaveNeedFlush
= 0;
1240 vbo_save_EndList(struct gl_context
*ctx
)
1242 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1244 /* EndList called inside a (saved) Begin/End pair?
1246 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1248 if (save
->prim_count
> 0) {
1249 GLint i
= save
->prim_count
- 1;
1250 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1251 save
->prim
[i
].end
= 0;
1252 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
1255 /* Make sure this vertex list gets replayed by the "loopback"
1258 save
->dangling_attr_ref
= 1;
1259 vbo_save_SaveFlushVertices(ctx
);
1261 /* Swap out this vertex format while outside begin/end. Any color,
1262 * etc. received between here and the next begin will be compiled
1265 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1268 unmap_vertex_store(ctx
, save
->vertex_store
);
1270 assert(save
->vertex_size
== 0);
1275 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1277 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1278 save
->replay_flags
|= dlist
->Flags
;
1283 vbo_save_EndCallList(struct gl_context
*ctx
)
1285 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1287 if (ctx
->ListState
.CallDepth
== 1) {
1288 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1289 * flag, if it is set:
1291 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1297 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1299 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1302 if (--node
->vertex_store
->refcount
== 0)
1303 free_vertex_store(ctx
, node
->vertex_store
);
1305 if (--node
->prim_store
->refcount
== 0)
1306 FREE(node
->prim_store
);
1308 if (node
->current_data
) {
1309 FREE(node
->current_data
);
1310 node
->current_data
= NULL
;
1316 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
)
1318 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1322 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1323 node
->count
, node
->prim_count
, node
->vertex_size
);
1325 for (i
= 0; i
< node
->prim_count
; i
++) {
1326 struct _mesa_prim
*prim
= &node
->prim
[i
];
1327 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1329 _mesa_lookup_prim_by_nr(prim
->mode
),
1330 prim
->weak
? " (weak)" : "",
1332 prim
->start
+ prim
->count
,
1333 (prim
->begin
) ? "BEGIN" : "(wrap)",
1334 (prim
->end
) ? "END" : "(wrap)");
1340 _save_current_init(struct gl_context
*ctx
)
1342 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1345 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_GENERIC15
; i
++) {
1346 const GLuint j
= i
- VBO_ATTRIB_POS
;
1347 ASSERT(j
< VERT_ATTRIB_MAX
);
1348 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1349 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1352 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1353 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1354 ASSERT(j
< MAT_ATTRIB_MAX
);
1355 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1356 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1362 * Initialize the display list compiler
1365 vbo_save_api_init(struct vbo_save_context
*save
)
1367 struct gl_context
*ctx
= save
->ctx
;
1370 save
->opcode_vertex_list
=
1371 _mesa_dlist_alloc_opcode(ctx
,
1372 sizeof(struct vbo_save_vertex_list
),
1373 vbo_save_playback_vertex_list
,
1374 vbo_destroy_vertex_list
,
1375 vbo_print_vertex_list
);
1377 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1379 _save_vtxfmt_init(ctx
);
1380 _save_current_init(ctx
);
1382 /* These will actually get set again when binding/drawing */
1383 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1384 save
->inputs
[i
] = &save
->arrays
[i
];
1386 /* Hook our array functions into the outside-begin-end vtxfmt in
1389 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1390 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1391 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1392 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1393 /* loops back into _save_OBE_DrawElements */
1394 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsEXT
=
1395 _mesa_noop_MultiDrawElements
;
1396 ctx
->ListState
.ListVtxfmt
.MultiDrawElementsBaseVertex
=
1397 _mesa_noop_MultiDrawElementsBaseVertex
;
1398 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1402 #endif /* FEATURE_dlist */