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.
79 /* An interesting VBO number/name to help with debugging */
80 #define VBO_BUF_ID 12345
84 * NOTE: Old 'parity' issue is gone, but copying can still be
85 * wrong-footed on replay.
88 _save_copy_vertices(struct gl_context
*ctx
,
89 const struct vbo_save_vertex_list
*node
,
90 const GLfloat
* src_buffer
)
92 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
93 const struct _mesa_prim
*prim
= &node
->prim
[node
->prim_count
- 1];
94 GLuint nr
= prim
->count
;
95 GLuint sz
= save
->vertex_size
;
96 const GLfloat
*src
= src_buffer
+ prim
->start
* sz
;
97 GLfloat
*dst
= save
->copied
.buffer
;
103 switch (prim
->mode
) {
108 for (i
= 0; i
< ovf
; i
++)
109 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
110 sz
* sizeof(GLfloat
));
114 for (i
= 0; i
< ovf
; i
++)
115 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
116 sz
* sizeof(GLfloat
));
120 for (i
= 0; i
< ovf
; i
++)
121 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
122 sz
* sizeof(GLfloat
));
128 memcpy(dst
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
132 case GL_TRIANGLE_FAN
:
137 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
141 memcpy(dst
, src
+ 0, sz
* sizeof(GLfloat
));
142 memcpy(dst
+ sz
, src
+ (nr
- 1) * sz
, sz
* sizeof(GLfloat
));
145 case GL_TRIANGLE_STRIP
:
158 for (i
= 0; i
< ovf
; i
++)
159 memcpy(dst
+ i
* sz
, src
+ (nr
- ovf
+ i
) * sz
,
160 sz
* sizeof(GLfloat
));
169 static struct vbo_save_vertex_store
*
170 alloc_vertex_store(struct gl_context
*ctx
)
172 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
173 struct vbo_save_vertex_store
*vertex_store
=
174 CALLOC_STRUCT(vbo_save_vertex_store
);
176 /* obj->Name needs to be non-zero, but won't ever be examined more
177 * closely than that. In particular these buffers won't be entered
178 * into the hash and can never be confused with ones visible to the
179 * user. Perhaps there could be a special number for internal
182 vertex_store
->bufferobj
= ctx
->Driver
.NewBufferObject(ctx
,
184 GL_ARRAY_BUFFER_ARB
);
185 if (vertex_store
->bufferobj
) {
186 save
->out_of_memory
=
187 !ctx
->Driver
.BufferData(ctx
,
189 VBO_SAVE_BUFFER_SIZE
* sizeof(GLfloat
),
190 NULL
, GL_STATIC_DRAW_ARB
,
191 vertex_store
->bufferobj
);
194 save
->out_of_memory
= GL_TRUE
;
197 if (save
->out_of_memory
) {
198 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "internal VBO allocation");
199 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
202 vertex_store
->buffer
= NULL
;
203 vertex_store
->used
= 0;
204 vertex_store
->refcount
= 1;
211 free_vertex_store(struct gl_context
*ctx
,
212 struct vbo_save_vertex_store
*vertex_store
)
214 assert(!vertex_store
->buffer
);
216 if (vertex_store
->bufferobj
) {
217 _mesa_reference_buffer_object(ctx
, &vertex_store
->bufferobj
, NULL
);
225 map_vertex_store(struct gl_context
*ctx
,
226 struct vbo_save_vertex_store
*vertex_store
)
228 assert(vertex_store
->bufferobj
);
229 assert(!vertex_store
->buffer
);
230 if (vertex_store
->bufferobj
->Size
> 0) {
231 vertex_store
->buffer
=
232 (GLfloat
*) ctx
->Driver
.MapBufferRange(ctx
, 0,
233 vertex_store
->bufferobj
->Size
,
234 GL_MAP_WRITE_BIT
, /* not used */
235 vertex_store
->bufferobj
);
236 assert(vertex_store
->buffer
);
237 return vertex_store
->buffer
+ vertex_store
->used
;
240 /* probably ran out of memory for buffers */
247 unmap_vertex_store(struct gl_context
*ctx
,
248 struct vbo_save_vertex_store
*vertex_store
)
250 if (vertex_store
->bufferobj
->Size
> 0) {
251 ctx
->Driver
.UnmapBuffer(ctx
, vertex_store
->bufferobj
);
253 vertex_store
->buffer
= NULL
;
257 static struct vbo_save_primitive_store
*
258 alloc_prim_store(struct gl_context
*ctx
)
260 struct vbo_save_primitive_store
*store
=
261 CALLOC_STRUCT(vbo_save_primitive_store
);
270 _save_reset_counters(struct gl_context
*ctx
)
272 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
274 save
->prim
= save
->prim_store
->buffer
+ save
->prim_store
->used
;
275 save
->buffer
= save
->vertex_store
->buffer
+ save
->vertex_store
->used
;
277 assert(save
->buffer
== save
->buffer_ptr
);
279 if (save
->vertex_size
)
280 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
285 save
->vert_count
= 0;
286 save
->prim_count
= 0;
287 save
->prim_max
= VBO_SAVE_PRIM_SIZE
- save
->prim_store
->used
;
288 save
->dangling_attr_ref
= 0;
293 * Insert the active immediate struct onto the display list currently
297 _save_compile_vertex_list(struct gl_context
*ctx
)
299 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
300 struct vbo_save_vertex_list
*node
;
302 /* Allocate space for this structure in the display list currently
305 node
= (struct vbo_save_vertex_list
*)
306 _mesa_dlist_alloc(ctx
, save
->opcode_vertex_list
, sizeof(*node
));
311 /* Duplicate our template, increment refcounts to the storage structs:
313 memcpy(node
->attrsz
, save
->attrsz
, sizeof(node
->attrsz
));
314 node
->vertex_size
= save
->vertex_size
;
315 node
->buffer_offset
=
316 (save
->buffer
- save
->vertex_store
->buffer
) * sizeof(GLfloat
);
317 node
->count
= save
->vert_count
;
318 node
->wrap_count
= save
->copied
.nr
;
319 node
->dangling_attr_ref
= save
->dangling_attr_ref
;
320 node
->prim
= save
->prim
;
321 node
->prim_count
= save
->prim_count
;
322 node
->vertex_store
= save
->vertex_store
;
323 node
->prim_store
= save
->prim_store
;
325 node
->vertex_store
->refcount
++;
326 node
->prim_store
->refcount
++;
328 if (node
->prim
[0].no_current_update
) {
329 node
->current_size
= 0;
330 node
->current_data
= NULL
;
333 node
->current_size
= node
->vertex_size
- node
->attrsz
[0];
334 node
->current_data
= NULL
;
336 if (node
->current_size
) {
337 /* If the malloc fails, we just pull the data out of the VBO
340 node
->current_data
= MALLOC(node
->current_size
* sizeof(GLfloat
));
341 if (node
->current_data
) {
342 const char *buffer
= (const char *) save
->vertex_store
->buffer
;
343 unsigned attr_offset
= node
->attrsz
[0] * sizeof(GLfloat
);
344 unsigned vertex_offset
= 0;
348 (node
->count
- 1) * node
->vertex_size
* sizeof(GLfloat
);
350 memcpy(node
->current_data
,
351 buffer
+ node
->buffer_offset
+ vertex_offset
+ attr_offset
,
352 node
->current_size
* sizeof(GLfloat
));
357 assert(node
->attrsz
[VBO_ATTRIB_POS
] != 0 || node
->count
== 0);
359 if (save
->dangling_attr_ref
)
360 ctx
->ListState
.CurrentList
->Flags
|= DLIST_DANGLING_REFS
;
362 save
->vertex_store
->used
+= save
->vertex_size
* node
->count
;
363 save
->prim_store
->used
+= node
->prim_count
;
365 /* Copy duplicated vertices
367 save
->copied
.nr
= _save_copy_vertices(ctx
, node
, save
->buffer
);
369 /* Deal with GL_COMPILE_AND_EXECUTE:
371 if (ctx
->ExecuteFlag
) {
372 struct _glapi_table
*dispatch
= GET_DISPATCH();
374 _glapi_set_dispatch(ctx
->Exec
);
376 vbo_loopback_vertex_list(ctx
,
377 (const GLfloat
*) ((const char *) save
->
378 vertex_store
->buffer
+
379 node
->buffer_offset
),
380 node
->attrsz
, node
->prim
, node
->prim_count
,
381 node
->wrap_count
, node
->vertex_size
);
383 _glapi_set_dispatch(dispatch
);
386 /* Decide whether the storage structs are full, or can be used for
387 * the next vertex lists as well.
389 if (save
->vertex_store
->used
>
390 VBO_SAVE_BUFFER_SIZE
- 16 * (save
->vertex_size
+ 4)) {
394 unmap_vertex_store(ctx
, save
->vertex_store
);
396 /* Release old reference:
398 save
->vertex_store
->refcount
--;
399 assert(save
->vertex_store
->refcount
!= 0);
400 save
->vertex_store
= NULL
;
402 /* Allocate and map new store:
404 save
->vertex_store
= alloc_vertex_store(ctx
);
405 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
406 save
->out_of_memory
= save
->buffer_ptr
== NULL
;
409 if (save
->prim_store
->used
> VBO_SAVE_PRIM_SIZE
- 6) {
410 save
->prim_store
->refcount
--;
411 assert(save
->prim_store
->refcount
!= 0);
412 save
->prim_store
= alloc_prim_store(ctx
);
415 /* Reset our structures for the next run of vertices:
417 _save_reset_counters(ctx
);
422 * TODO -- If no new vertices have been stored, don't bother saving it.
425 _save_wrap_buffers(struct gl_context
*ctx
)
427 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
428 GLint i
= save
->prim_count
- 1;
431 GLboolean no_current_update
;
433 assert(i
< (GLint
) save
->prim_max
);
436 /* Close off in-progress primitive.
438 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
439 mode
= save
->prim
[i
].mode
;
440 weak
= save
->prim
[i
].weak
;
441 no_current_update
= save
->prim
[i
].no_current_update
;
443 /* store the copied vertices, and allocate a new list.
445 _save_compile_vertex_list(ctx
);
447 /* Restart interrupted primitive
449 save
->prim
[0].mode
= mode
;
450 save
->prim
[0].weak
= weak
;
451 save
->prim
[0].no_current_update
= no_current_update
;
452 save
->prim
[0].begin
= 0;
453 save
->prim
[0].end
= 0;
454 save
->prim
[0].pad
= 0;
455 save
->prim
[0].start
= 0;
456 save
->prim
[0].count
= 0;
457 save
->prim
[0].num_instances
= 1;
458 save
->prim_count
= 1;
463 * Called only when buffers are wrapped as the result of filling the
464 * vertex_store struct.
467 _save_wrap_filled_vertex(struct gl_context
*ctx
)
469 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
470 GLfloat
*data
= save
->copied
.buffer
;
473 /* Emit a glEnd to close off the last vertex list.
475 _save_wrap_buffers(ctx
);
477 /* Copy stored stored vertices to start of new list.
479 assert(save
->max_vert
- save
->vert_count
> save
->copied
.nr
);
481 for (i
= 0; i
< save
->copied
.nr
; i
++) {
482 memcpy(save
->buffer_ptr
, data
, save
->vertex_size
* sizeof(GLfloat
));
483 data
+= save
->vertex_size
;
484 save
->buffer_ptr
+= save
->vertex_size
;
491 _save_copy_to_current(struct gl_context
*ctx
)
493 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
496 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
497 if (save
->attrsz
[i
]) {
498 save
->currentsz
[i
][0] = save
->attrsz
[i
];
499 COPY_CLEAN_4V(save
->current
[i
], save
->attrsz
[i
], save
->attrptr
[i
]);
506 _save_copy_from_current(struct gl_context
*ctx
)
508 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
511 for (i
= VBO_ATTRIB_POS
+ 1; i
< VBO_ATTRIB_MAX
; i
++) {
512 switch (save
->attrsz
[i
]) {
514 save
->attrptr
[i
][3] = save
->current
[i
][3];
516 save
->attrptr
[i
][2] = save
->current
[i
][2];
518 save
->attrptr
[i
][1] = save
->current
[i
][1];
520 save
->attrptr
[i
][0] = save
->current
[i
][0];
528 /* Flush existing data, set new attrib size, replay copied vertices.
531 _save_upgrade_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint newsz
)
533 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
538 /* Store the current run of vertices, and emit a GL_END. Emit a
539 * BEGIN in the new buffer.
541 if (save
->vert_count
)
542 _save_wrap_buffers(ctx
);
544 assert(save
->copied
.nr
== 0);
546 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
547 * when the attribute already exists in the vertex and is having
548 * its size increased.
550 _save_copy_to_current(ctx
);
554 oldsz
= save
->attrsz
[attr
];
555 save
->attrsz
[attr
] = newsz
;
557 save
->vertex_size
+= newsz
- oldsz
;
558 save
->max_vert
= ((VBO_SAVE_BUFFER_SIZE
- save
->vertex_store
->used
) /
560 save
->vert_count
= 0;
562 /* Recalculate all the attrptr[] values:
564 for (i
= 0, tmp
= save
->vertex
; i
< VBO_ATTRIB_MAX
; i
++) {
565 if (save
->attrsz
[i
]) {
566 save
->attrptr
[i
] = tmp
;
567 tmp
+= save
->attrsz
[i
];
570 save
->attrptr
[i
] = NULL
; /* will not be dereferenced. */
574 /* Copy from current to repopulate the vertex with correct values.
576 _save_copy_from_current(ctx
);
578 /* Replay stored vertices to translate them to new format here.
580 * If there are copied vertices and the new (upgraded) attribute
581 * has not been defined before, this list is somewhat degenerate,
582 * and will need fixup at runtime.
584 if (save
->copied
.nr
) {
585 GLfloat
*data
= save
->copied
.buffer
;
586 GLfloat
*dest
= save
->buffer
;
589 /* Need to note this and fix up at runtime (or loopback):
591 if (attr
!= VBO_ATTRIB_POS
&& save
->currentsz
[attr
][0] == 0) {
593 save
->dangling_attr_ref
= GL_TRUE
;
596 for (i
= 0; i
< save
->copied
.nr
; i
++) {
597 for (j
= 0; j
< VBO_ATTRIB_MAX
; j
++) {
598 if (save
->attrsz
[j
]) {
601 COPY_CLEAN_4V(dest
, oldsz
, data
);
606 COPY_SZ_4V(dest
, newsz
, save
->current
[attr
]);
611 GLint sz
= save
->attrsz
[j
];
612 COPY_SZ_4V(dest
, sz
, data
);
620 save
->buffer_ptr
= dest
;
621 save
->vert_count
+= save
->copied
.nr
;
627 save_fixup_vertex(struct gl_context
*ctx
, GLuint attr
, GLuint sz
)
629 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
631 if (sz
> save
->attrsz
[attr
]) {
632 /* New size is larger. Need to flush existing vertices and get
633 * an enlarged vertex format.
635 _save_upgrade_vertex(ctx
, attr
, sz
);
637 else if (sz
< save
->active_sz
[attr
]) {
638 static GLfloat id
[4] = { 0, 0, 0, 1 };
641 /* New size is equal or smaller - just need to fill in some
644 for (i
= sz
; i
<= save
->attrsz
[attr
]; i
++)
645 save
->attrptr
[attr
][i
- 1] = id
[i
- 1];
648 save
->active_sz
[attr
] = sz
;
653 _save_reset_vertex(struct gl_context
*ctx
)
655 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
658 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++) {
660 save
->active_sz
[i
] = 0;
663 save
->vertex_size
= 0;
668 #define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
671 /* Only one size for each attribute may be active at once. Eg. if
672 * Color3f is installed/active, then Color4f may not be, even if the
673 * vertex actually contains 4 color coordinates. This is because the
674 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
675 * of the chooser function when switching between Color4f and Color3f.
677 #define ATTR(A, N, V0, V1, V2, V3) \
679 struct vbo_save_context *save = &vbo_context(ctx)->save; \
681 if (save->active_sz[A] != N) \
682 save_fixup_vertex(ctx, A, N); \
685 GLfloat *dest = save->attrptr[A]; \
686 if (N>0) dest[0] = V0; \
687 if (N>1) dest[1] = V1; \
688 if (N>2) dest[2] = V2; \
689 if (N>3) dest[3] = V3; \
695 for (i = 0; i < save->vertex_size; i++) \
696 save->buffer_ptr[i] = save->vertex[i]; \
698 save->buffer_ptr += save->vertex_size; \
700 if (++save->vert_count >= save->max_vert) \
701 _save_wrap_filled_vertex(ctx); \
705 #define TAG(x) _save_##x
707 #include "vbo_attrib_tmp.h"
711 #define MAT( ATTR, N, face, params ) \
713 if (face != GL_BACK) \
714 MAT_ATTR( ATTR, N, params ); /* front */ \
715 if (face != GL_FRONT) \
716 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
721 * Save a glMaterial call found between glBegin/End.
722 * glMaterial calls outside Begin/End are handled in dlist.c.
724 static void GLAPIENTRY
725 _save_Materialfv(GLenum face
, GLenum pname
, const GLfloat
*params
)
727 GET_CURRENT_CONTEXT(ctx
);
729 if (face
!= GL_FRONT
&& face
!= GL_BACK
&& face
!= GL_FRONT_AND_BACK
) {
730 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(face)");
738 MAT(VBO_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
741 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
744 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
747 MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
750 if (*params
< 0 || *params
> ctx
->Const
.MaxShininess
) {
751 _mesa_compile_error(ctx
, GL_INVALID_VALUE
, "glMaterial(shininess)");
754 MAT(VBO_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
757 case GL_COLOR_INDEXES
:
758 MAT(VBO_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
760 case GL_AMBIENT_AND_DIFFUSE
:
761 MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
762 MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
765 _mesa_compile_error(ctx
, GL_INVALID_ENUM
, "glMaterial(pname)");
771 /* Cope with EvalCoord/CallList called within a begin/end object:
772 * -- Flush current buffer
773 * -- Fallback to opcodes for the rest of the begin/end object.
776 dlist_fallback(struct gl_context
*ctx
)
778 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
780 if (save
->vert_count
|| save
->prim_count
) {
781 if (save
->prim_count
> 0) {
782 /* Close off in-progress primitive. */
783 GLint i
= save
->prim_count
- 1;
784 save
->prim
[i
].count
= save
->vert_count
- save
->prim
[i
].start
;
787 /* Need to replay this display list with loopback,
788 * unfortunately, otherwise this primitive won't be handled
791 save
->dangling_attr_ref
= 1;
793 _save_compile_vertex_list(ctx
);
796 _save_copy_to_current(ctx
);
797 _save_reset_vertex(ctx
);
798 _save_reset_counters(ctx
);
799 if (save
->out_of_memory
) {
800 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
803 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
805 ctx
->Driver
.SaveNeedFlush
= 0;
809 static void GLAPIENTRY
810 _save_EvalCoord1f(GLfloat u
)
812 GET_CURRENT_CONTEXT(ctx
);
814 CALL_EvalCoord1f(ctx
->Save
, (u
));
817 static void GLAPIENTRY
818 _save_EvalCoord1fv(const GLfloat
* v
)
820 GET_CURRENT_CONTEXT(ctx
);
822 CALL_EvalCoord1fv(ctx
->Save
, (v
));
825 static void GLAPIENTRY
826 _save_EvalCoord2f(GLfloat u
, GLfloat v
)
828 GET_CURRENT_CONTEXT(ctx
);
830 CALL_EvalCoord2f(ctx
->Save
, (u
, v
));
833 static void GLAPIENTRY
834 _save_EvalCoord2fv(const GLfloat
* v
)
836 GET_CURRENT_CONTEXT(ctx
);
838 CALL_EvalCoord2fv(ctx
->Save
, (v
));
841 static void GLAPIENTRY
842 _save_EvalPoint1(GLint i
)
844 GET_CURRENT_CONTEXT(ctx
);
846 CALL_EvalPoint1(ctx
->Save
, (i
));
849 static void GLAPIENTRY
850 _save_EvalPoint2(GLint i
, GLint j
)
852 GET_CURRENT_CONTEXT(ctx
);
854 CALL_EvalPoint2(ctx
->Save
, (i
, j
));
857 static void GLAPIENTRY
858 _save_CallList(GLuint l
)
860 GET_CURRENT_CONTEXT(ctx
);
862 CALL_CallList(ctx
->Save
, (l
));
865 static void GLAPIENTRY
866 _save_CallLists(GLsizei n
, GLenum type
, const GLvoid
* v
)
868 GET_CURRENT_CONTEXT(ctx
);
870 CALL_CallLists(ctx
->Save
, (n
, type
, v
));
875 /* This begin is hooked into ... Updating of
876 * ctx->Driver.CurrentSavePrimitive is already taken care of.
879 vbo_save_NotifyBegin(struct gl_context
*ctx
, GLenum mode
)
881 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
883 GLuint i
= save
->prim_count
++;
885 assert(i
< save
->prim_max
);
886 save
->prim
[i
].mode
= mode
& VBO_SAVE_PRIM_MODE_MASK
;
887 save
->prim
[i
].begin
= 1;
888 save
->prim
[i
].end
= 0;
889 save
->prim
[i
].weak
= (mode
& VBO_SAVE_PRIM_WEAK
) ? 1 : 0;
890 save
->prim
[i
].no_current_update
=
891 (mode
& VBO_SAVE_PRIM_NO_CURRENT_UPDATE
) ? 1 : 0;
892 save
->prim
[i
].pad
= 0;
893 save
->prim
[i
].start
= save
->vert_count
;
894 save
->prim
[i
].count
= 0;
895 save
->prim
[i
].num_instances
= 1;
897 if (save
->out_of_memory
) {
898 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
901 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt
);
903 ctx
->Driver
.SaveNeedFlush
= 1;
908 static void GLAPIENTRY
911 GET_CURRENT_CONTEXT(ctx
);
912 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
913 GLint i
= save
->prim_count
- 1;
915 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
916 save
->prim
[i
].end
= 1;
917 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
919 if (i
== (GLint
) save
->prim_max
- 1) {
920 _save_compile_vertex_list(ctx
);
921 assert(save
->copied
.nr
== 0);
924 /* Swap out this vertex format while outside begin/end. Any color,
925 * etc. received between here and the next begin will be compiled
928 if (save
->out_of_memory
) {
929 _mesa_install_save_vtxfmt(ctx
, &save
->vtxfmt_noop
);
932 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
937 /* These are all errors as this vtxfmt is only installed inside
940 static void GLAPIENTRY
941 _save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
942 const GLvoid
* indices
)
944 GET_CURRENT_CONTEXT(ctx
);
949 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawElements");
953 static void GLAPIENTRY
954 _save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
956 GET_CURRENT_CONTEXT(ctx
);
960 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glDrawArrays");
964 static void GLAPIENTRY
965 _save_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
967 GET_CURRENT_CONTEXT(ctx
);
972 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glRectf");
976 static void GLAPIENTRY
977 _save_EvalMesh1(GLenum mode
, GLint i1
, GLint i2
)
979 GET_CURRENT_CONTEXT(ctx
);
983 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh1");
987 static void GLAPIENTRY
988 _save_EvalMesh2(GLenum mode
, GLint i1
, GLint i2
, GLint j1
, GLint j2
)
990 GET_CURRENT_CONTEXT(ctx
);
996 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "glEvalMesh2");
1000 static void GLAPIENTRY
1001 _save_Begin(GLenum mode
)
1003 GET_CURRENT_CONTEXT(ctx
);
1005 _mesa_compile_error(ctx
, GL_INVALID_OPERATION
, "Recursive glBegin");
1009 /* Unlike the functions above, these are to be hooked into the vtxfmt
1010 * maintained in ctx->ListState, active when the list is known or
1011 * suspected to be outside any begin/end primitive.
1012 * Note: OBE = Outside Begin/End
1014 static void GLAPIENTRY
1015 _save_OBE_Rectf(GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1017 GET_CURRENT_CONTEXT(ctx
);
1018 vbo_save_NotifyBegin(ctx
, GL_QUADS
| VBO_SAVE_PRIM_WEAK
);
1019 CALL_Vertex2f(GET_DISPATCH(), (x1
, y1
));
1020 CALL_Vertex2f(GET_DISPATCH(), (x2
, y1
));
1021 CALL_Vertex2f(GET_DISPATCH(), (x2
, y2
));
1022 CALL_Vertex2f(GET_DISPATCH(), (x1
, y2
));
1023 CALL_End(GET_DISPATCH(), ());
1027 static void GLAPIENTRY
1028 _save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1030 GET_CURRENT_CONTEXT(ctx
);
1031 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1034 if (!_mesa_validate_DrawArrays(ctx
, mode
, start
, count
))
1037 if (save
->out_of_memory
)
1042 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
1043 | VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1045 for (i
= 0; i
< count
; i
++)
1046 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1047 CALL_End(GET_DISPATCH(), ());
1049 _ae_unmap_vbos(ctx
);
1053 /* Could do better by copying the arrays and element list intact and
1054 * then emitting an indexed prim at runtime.
1056 static void GLAPIENTRY
1057 _save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1058 const GLvoid
* indices
)
1060 GET_CURRENT_CONTEXT(ctx
);
1061 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1064 if (!_mesa_validate_DrawElements(ctx
, mode
, count
, type
, indices
))
1067 if (save
->out_of_memory
)
1072 if (_mesa_is_bufferobj(ctx
->Array
.ElementArrayBufferObj
))
1073 indices
= ADD_POINTERS(ctx
->Array
.ElementArrayBufferObj
->Pointer
, indices
);
1075 vbo_save_NotifyBegin(ctx
, (mode
| VBO_SAVE_PRIM_WEAK
|
1076 VBO_SAVE_PRIM_NO_CURRENT_UPDATE
));
1079 case GL_UNSIGNED_BYTE
:
1080 for (i
= 0; i
< count
; i
++)
1081 CALL_ArrayElement(GET_DISPATCH(), (((GLubyte
*) indices
)[i
]));
1083 case GL_UNSIGNED_SHORT
:
1084 for (i
= 0; i
< count
; i
++)
1085 CALL_ArrayElement(GET_DISPATCH(), (((GLushort
*) indices
)[i
]));
1087 case GL_UNSIGNED_INT
:
1088 for (i
= 0; i
< count
; i
++)
1089 CALL_ArrayElement(GET_DISPATCH(), (((GLuint
*) indices
)[i
]));
1092 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawElements(type)");
1096 CALL_End(GET_DISPATCH(), ());
1098 _ae_unmap_vbos(ctx
);
1103 _save_vtxfmt_init(struct gl_context
*ctx
)
1105 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1106 GLvertexformat
*vfmt
= &save
->vtxfmt
;
1108 _MESA_INIT_ARRAYELT_VTXFMT(vfmt
, _ae_
);
1110 vfmt
->Begin
= _save_Begin
;
1111 vfmt
->Color3f
= _save_Color3f
;
1112 vfmt
->Color3fv
= _save_Color3fv
;
1113 vfmt
->Color4f
= _save_Color4f
;
1114 vfmt
->Color4fv
= _save_Color4fv
;
1115 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1116 vfmt
->End
= _save_End
;
1117 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1118 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1119 vfmt
->Indexf
= _save_Indexf
;
1120 vfmt
->Indexfv
= _save_Indexfv
;
1121 vfmt
->Materialfv
= _save_Materialfv
;
1122 vfmt
->Normal3f
= _save_Normal3f
;
1123 vfmt
->Normal3fv
= _save_Normal3fv
;
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
;
1139 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1140 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1141 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1142 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1143 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1144 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1145 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1146 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1148 /* This will all require us to fallback to saving the list as opcodes:
1150 _MESA_INIT_DLIST_VTXFMT(vfmt
, _save_
); /* inside begin/end */
1152 _MESA_INIT_EVAL_VTXFMT(vfmt
, _save_
);
1154 /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1155 * only used when we're inside a glBegin/End pair.
1157 vfmt
->Begin
= _save_Begin
;
1158 vfmt
->Rectf
= _save_Rectf
;
1159 vfmt
->DrawArrays
= _save_DrawArrays
;
1160 vfmt
->DrawElements
= _save_DrawElements
;
1165 vbo_save_SaveFlushVertices(struct gl_context
*ctx
)
1167 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1169 /* Noop when we are actually active:
1171 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1172 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1175 if (save
->vert_count
|| save
->prim_count
)
1176 _save_compile_vertex_list(ctx
);
1178 _save_copy_to_current(ctx
);
1179 _save_reset_vertex(ctx
);
1180 _save_reset_counters(ctx
);
1181 ctx
->Driver
.SaveNeedFlush
= 0;
1186 vbo_save_NewList(struct gl_context
*ctx
, GLuint list
, GLenum mode
)
1188 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1193 if (!save
->prim_store
)
1194 save
->prim_store
= alloc_prim_store(ctx
);
1196 if (!save
->vertex_store
)
1197 save
->vertex_store
= alloc_vertex_store(ctx
);
1199 save
->buffer_ptr
= map_vertex_store(ctx
, save
->vertex_store
);
1201 _save_reset_vertex(ctx
);
1202 _save_reset_counters(ctx
);
1203 ctx
->Driver
.SaveNeedFlush
= 0;
1208 vbo_save_EndList(struct gl_context
*ctx
)
1210 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1212 /* EndList called inside a (saved) Begin/End pair?
1214 if (ctx
->Driver
.CurrentSavePrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
1216 if (save
->prim_count
> 0) {
1217 GLint i
= save
->prim_count
- 1;
1218 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1219 save
->prim
[i
].end
= 0;
1220 save
->prim
[i
].count
= (save
->vert_count
- save
->prim
[i
].start
);
1223 /* Make sure this vertex list gets replayed by the "loopback"
1226 save
->dangling_attr_ref
= 1;
1227 vbo_save_SaveFlushVertices(ctx
);
1229 /* Swap out this vertex format while outside begin/end. Any color,
1230 * etc. received between here and the next begin will be compiled
1233 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1236 unmap_vertex_store(ctx
, save
->vertex_store
);
1238 assert(save
->vertex_size
== 0);
1243 vbo_save_BeginCallList(struct gl_context
*ctx
, struct gl_display_list
*dlist
)
1245 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1246 save
->replay_flags
|= dlist
->Flags
;
1251 vbo_save_EndCallList(struct gl_context
*ctx
)
1253 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1255 if (ctx
->ListState
.CallDepth
== 1) {
1256 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1257 * flag, if it is set:
1259 save
->replay_flags
&= VBO_SAVE_FALLBACK
;
1265 vbo_destroy_vertex_list(struct gl_context
*ctx
, void *data
)
1267 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1270 if (--node
->vertex_store
->refcount
== 0)
1271 free_vertex_store(ctx
, node
->vertex_store
);
1273 if (--node
->prim_store
->refcount
== 0)
1274 FREE(node
->prim_store
);
1276 if (node
->current_data
) {
1277 FREE(node
->current_data
);
1278 node
->current_data
= NULL
;
1284 vbo_print_vertex_list(struct gl_context
*ctx
, void *data
)
1286 struct vbo_save_vertex_list
*node
= (struct vbo_save_vertex_list
*) data
;
1290 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1291 node
->count
, node
->prim_count
, node
->vertex_size
);
1293 for (i
= 0; i
< node
->prim_count
; i
++) {
1294 struct _mesa_prim
*prim
= &node
->prim
[i
];
1295 _mesa_debug(NULL
, " prim %d: %s%s %d..%d %s %s\n",
1297 _mesa_lookup_prim_by_nr(prim
->mode
),
1298 prim
->weak
? " (weak)" : "",
1300 prim
->start
+ prim
->count
,
1301 (prim
->begin
) ? "BEGIN" : "(wrap)",
1302 (prim
->end
) ? "END" : "(wrap)");
1308 _save_current_init(struct gl_context
*ctx
)
1310 struct vbo_save_context
*save
= &vbo_context(ctx
)->save
;
1313 for (i
= VBO_ATTRIB_POS
; i
<= VBO_ATTRIB_POINT_SIZE
; i
++) {
1314 const GLuint j
= i
- VBO_ATTRIB_POS
;
1315 ASSERT(j
< VERT_ATTRIB_MAX
);
1316 save
->currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[j
];
1317 save
->current
[i
] = ctx
->ListState
.CurrentAttrib
[j
];
1320 for (i
= VBO_ATTRIB_FIRST_MATERIAL
; i
<= VBO_ATTRIB_LAST_MATERIAL
; i
++) {
1321 const GLuint j
= i
- VBO_ATTRIB_FIRST_MATERIAL
;
1322 ASSERT(j
< MAT_ATTRIB_MAX
);
1323 save
->currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1324 save
->current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1330 * Initialize the display list compiler
1333 vbo_save_api_init(struct vbo_save_context
*save
)
1335 struct gl_context
*ctx
= save
->ctx
;
1338 save
->opcode_vertex_list
=
1339 _mesa_dlist_alloc_opcode(ctx
,
1340 sizeof(struct vbo_save_vertex_list
),
1341 vbo_save_playback_vertex_list
,
1342 vbo_destroy_vertex_list
,
1343 vbo_print_vertex_list
);
1345 ctx
->Driver
.NotifySaveBegin
= vbo_save_NotifyBegin
;
1347 _save_vtxfmt_init(ctx
);
1348 _save_current_init(ctx
);
1349 _mesa_noop_vtxfmt_init(&save
->vtxfmt_noop
);
1351 /* These will actually get set again when binding/drawing */
1352 for (i
= 0; i
< VBO_ATTRIB_MAX
; i
++)
1353 save
->inputs
[i
] = &save
->arrays
[i
];
1355 /* Hook our array functions into the outside-begin-end vtxfmt in
1358 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1359 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1360 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1361 _mesa_install_save_vtxfmt(ctx
, &ctx
->ListState
.ListVtxfmt
);
1365 #endif /* FEATURE_dlist */