2 /**************************************************************************
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Keith Whitwell <keith@tungstengraphics.com>
36 /* Display list compiler attempts to store lists of vertices with the
37 * same vertex layout. Additionally it attempts to minimize the need
38 * for execute-time fixup of these vertex lists, allowing them to be
41 * There are still some circumstances where this can be thwarted, for
42 * example by building a list that consists of one very long primitive
43 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
44 * from inside a different begin/end object (Begin(Lines), CallList,
47 * In that case the code will have to replay the list as individual
48 * commands through the Exec dispatch table, or fix up the copied
49 * vertices at execute-time.
51 * The other case where fixup is required is when a vertex attribute
52 * is introduced in the middle of a primitive. Eg:
54 * TexCoord1f() Vertex2f()
55 * TexCoord1f() Color3f() Vertex2f()
58 * If the current value of Color isn't known at compile-time, this
59 * primitive will require fixup.
62 * The list compiler currently doesn't attempt to compile lists
63 * containing EvalCoord or EvalPoint commands. On encountering one of
64 * these, compilation falls back to opcodes.
66 * This could be improved to fallback only when a mix of EvalCoord and
67 * Vertex commands are issued within a single primitive.
76 #include "api_validate.h"
77 #include "api_arrayelt.h"
79 #include "t_save_api.h"
82 * NOTE: Old 'parity' issue is gone, but copying can still be
83 * wrong-footed on replay.
85 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
86 const struct tnl_vertex_list
*node
)
88 TNLcontext
*tnl
= TNL_CONTEXT( ctx
);
89 const struct tnl_prim
*prim
= &node
->prim
[node
->prim_count
-1];
90 GLuint nr
= prim
->count
;
91 GLuint sz
= tnl
->save
.vertex_size
;
92 const GLfloat
*src
= node
->buffer
+ prim
->start
* sz
;
93 GLfloat
*dst
= tnl
->save
.copied
.buffer
;
96 if (prim
->mode
& PRIM_END
)
99 switch( prim
->mode
& PRIM_MODE_MASK
)
105 for (i
= 0 ; i
< ovf
; i
++)
106 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
110 for (i
= 0 ; i
< ovf
; i
++)
111 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
115 for (i
= 0 ; i
< ovf
; i
++)
116 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
122 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
126 case GL_TRIANGLE_FAN
:
131 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
134 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
135 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
138 case GL_TRIANGLE_STRIP
:
141 case 0: ovf
= 0; break;
142 case 1: ovf
= 1; break;
143 default: ovf
= 2 + (nr
&1); break;
145 for (i
= 0 ; i
< ovf
; i
++)
146 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
156 build_normal_lengths( struct tnl_vertex_list
*node
)
160 GLfloat
*n
= node
->buffer
;
161 GLuint stride
= node
->vertex_size
;
162 GLuint count
= node
->count
;
164 len
= node
->normal_lengths
= (GLfloat
*) MALLOC( count
* sizeof(GLfloat
) );
168 /* Find the normal of the first vertex:
170 for (i
= 0 ; i
< _TNL_ATTRIB_NORMAL
; i
++)
171 n
+= node
->attrsz
[i
];
173 for (i
= 0 ; i
< count
; i
++, n
+= stride
) {
174 len
[i
] = LEN_3FV( n
);
175 if (len
[i
] > 0.0F
) len
[i
] = 1.0F
/ len
[i
];
179 static struct tnl_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
181 struct tnl_vertex_store
*store
= MALLOC_STRUCT(tnl_vertex_store
);
187 static struct tnl_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
189 struct tnl_primitive_store
*store
= MALLOC_STRUCT(tnl_primitive_store
);
195 static void _save_reset_counters( GLcontext
*ctx
)
197 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
199 tnl
->save
.prim
= tnl
->save
.prim_store
->buffer
+ tnl
->save
.prim_store
->used
;
200 tnl
->save
.buffer
= (tnl
->save
.vertex_store
->buffer
+
201 tnl
->save
.vertex_store
->used
);
203 if (tnl
->save
.vertex_size
)
204 tnl
->save
.initial_counter
= ((SAVE_BUFFER_SIZE
-
205 tnl
->save
.vertex_store
->used
) /
206 tnl
->save
.vertex_size
);
208 tnl
->save
.initial_counter
= 0;
210 if (tnl
->save
.initial_counter
> ctx
->Const
.MaxArrayLockSize
)
211 tnl
->save
.initial_counter
= ctx
->Const
.MaxArrayLockSize
;
213 tnl
->save
.counter
= tnl
->save
.initial_counter
;
214 tnl
->save
.prim_count
= 0;
215 tnl
->save
.prim_max
= SAVE_PRIM_SIZE
- tnl
->save
.prim_store
->used
;
216 tnl
->save
.copied
.nr
= 0;
217 tnl
->save
.dangling_attr_ref
= 0;
221 /* Insert the active immediate struct onto the display list currently
224 static void _save_compile_vertex_list( GLcontext
*ctx
)
226 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
227 struct tnl_vertex_list
*node
;
229 /* Allocate space for this structure in the display list currently
232 node
= (struct tnl_vertex_list
*)
233 _mesa_alloc_instruction(ctx
, tnl
->save
.opcode_vertex_list
, sizeof(*node
));
238 /* Duplicate our template, increment refcounts to the storage structs:
240 _mesa_memcpy(node
->attrsz
, tnl
->save
.attrsz
, sizeof(node
->attrsz
));
241 node
->vertex_size
= tnl
->save
.vertex_size
;
242 node
->buffer
= tnl
->save
.buffer
;
243 node
->wrap_count
= tnl
->save
.copied
.nr
;
244 node
->count
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
245 node
->prim
= tnl
->save
.prim
;
246 node
->prim_count
= tnl
->save
.prim_count
;
247 node
->vertex_store
= tnl
->save
.vertex_store
;
248 node
->prim_store
= tnl
->save
.prim_store
;
249 node
->dangling_attr_ref
= tnl
->save
.dangling_attr_ref
;
250 node
->normal_lengths
= 0;
252 node
->vertex_store
->refcount
++;
253 node
->prim_store
->refcount
++;
255 assert(node
->attrsz
[_TNL_ATTRIB_POS
] != 0 ||
258 /* Maybe calculate normal lengths:
260 if (tnl
->CalcDListNormalLengths
&&
261 node
->attrsz
[_TNL_ATTRIB_NORMAL
] == 3 &&
262 !node
->dangling_attr_ref
)
263 build_normal_lengths( node
);
265 tnl
->save
.vertex_store
->used
+= tnl
->save
.vertex_size
* node
->count
;
266 tnl
->save
.prim_store
->used
+= node
->prim_count
;
268 /* Decide whether the storage structs are full, or can be used for
269 * the next vertex lists as well.
271 if (tnl
->save
.vertex_store
->used
>
272 SAVE_BUFFER_SIZE
- 16 * (tnl
->save
.vertex_size
+ 4)) {
274 tnl
->save
.vertex_store
->refcount
--;
275 assert(tnl
->save
.vertex_store
->refcount
!= 0);
276 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
277 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
280 if (tnl
->save
.prim_store
->used
> SAVE_PRIM_SIZE
- 6) {
281 tnl
->save
.prim_store
->refcount
--;
282 assert(tnl
->save
.prim_store
->refcount
!= 0);
283 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
286 /* Reset our structures for the next run of vertices:
288 _save_reset_counters( ctx
);
290 /* Copy duplicated vertices
292 tnl
->save
.copied
.nr
= _save_copy_vertices( ctx
, node
);
295 /* Deal with GL_COMPILE_AND_EXECUTE:
297 if (ctx
->ExecuteFlag
) {
298 _tnl_playback_vertex_list( ctx
, (void *) node
);
303 /* TODO -- If no new vertices have been stored, don't bother saving
306 static void _save_wrap_buffers( GLcontext
*ctx
)
308 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
309 GLint i
= tnl
->save
.prim_count
- 1;
312 assert(i
< (GLint
) tnl
->save
.prim_max
);
315 /* Close off in-progress primitive.
317 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
318 tnl
->save
.prim
[i
].start
);
319 mode
= tnl
->save
.prim
[i
].mode
& ~(PRIM_BEGIN
|PRIM_END
);
321 /* store the copied vertices, and allocate a new list.
323 _save_compile_vertex_list( ctx
);
325 /* Restart interrupted primitive
327 tnl
->save
.prim
[0].mode
= mode
;
328 tnl
->save
.prim
[0].start
= 0;
329 tnl
->save
.prim
[0].count
= 0;
330 tnl
->save
.prim_count
= 1;
335 /* Called only when buffers are wrapped as the result of filling the
336 * vertex_store struct.
338 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
340 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
341 GLfloat
*data
= tnl
->save
.copied
.buffer
;
344 /* Emit a glEnd to close off the last vertex list.
346 _save_wrap_buffers( ctx
);
348 /* Copy stored stored vertices to start of new list.
350 assert(tnl
->save
.counter
> tnl
->save
.copied
.nr
);
352 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
353 _mesa_memcpy( tnl
->save
.vbptr
, data
, tnl
->save
.vertex_size
* sizeof(GLfloat
));
354 data
+= tnl
->save
.vertex_size
;
355 tnl
->save
.vbptr
+= tnl
->save
.vertex_size
;
361 static void _save_copy_to_current( GLcontext
*ctx
)
363 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
366 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
367 if (tnl
->save
.attrsz
[i
]) {
368 tnl
->save
.currentsz
[i
][0] = tnl
->save
.attrsz
[i
];
369 ASSIGN_4V(tnl
->save
.current
[i
], 0, 0, 0, 1);
370 COPY_SZ_4V(tnl
->save
.current
[i
],
372 tnl
->save
.attrptr
[i
]);
376 /* Edgeflag requires special treatment:
378 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
379 ctx
->ListState
.ActiveEdgeFlag
= 1;
380 ctx
->ListState
.CurrentEdgeFlag
=
381 (tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
386 static void _save_copy_from_current( GLcontext
*ctx
)
388 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
391 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
392 switch (tnl
->save
.attrsz
[i
]) {
393 case 4: tnl
->save
.attrptr
[i
][3] = tnl
->save
.current
[i
][3];
394 case 3: tnl
->save
.attrptr
[i
][2] = tnl
->save
.current
[i
][2];
395 case 2: tnl
->save
.attrptr
[i
][1] = tnl
->save
.current
[i
][1];
396 case 1: tnl
->save
.attrptr
[i
][0] = tnl
->save
.current
[i
][0];
400 /* Edgeflag requires special treatment:
402 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
403 tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
404 (GLfloat
)ctx
->ListState
.CurrentEdgeFlag
;
410 /* Flush existing data, set new attrib size, replay copied vertices.
412 static void _save_upgrade_vertex( GLcontext
*ctx
,
416 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
421 /* Store the current run of vertices, and emit a GL_END. Emit a
422 * BEGIN in the new buffer.
424 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
)
425 _save_wrap_buffers( ctx
);
427 assert( tnl
->save
.copied
.nr
== 0 );
429 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
430 * when the attribute already exists in the vertex and is having
431 * its size increased.
433 _save_copy_to_current( ctx
);
437 oldsz
= tnl
->save
.attrsz
[attr
];
438 tnl
->save
.attrsz
[attr
] = newsz
;
440 tnl
->save
.vertex_size
+= newsz
- oldsz
;
441 tnl
->save
.counter
= ((SAVE_BUFFER_SIZE
- tnl
->save
.vertex_store
->used
) /
442 tnl
->save
.vertex_size
);
443 if (tnl
->save
.counter
> ctx
->Const
.MaxArrayLockSize
)
444 tnl
->save
.counter
= ctx
->Const
.MaxArrayLockSize
;
445 tnl
->save
.initial_counter
= tnl
->save
.counter
;
447 /* Recalculate all the attrptr[] values:
449 for (i
= 0, tmp
= tnl
->save
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
450 if (tnl
->save
.attrsz
[i
]) {
451 tnl
->save
.attrptr
[i
] = tmp
;
452 tmp
+= tnl
->save
.attrsz
[i
];
455 tnl
->save
.attrptr
[i
] = 0; /* will not be dereferenced. */
458 /* Copy from current to repopulate the vertex with correct values.
460 _save_copy_from_current( ctx
);
462 /* Replay stored vertices to translate them to new format here.
464 * If there are copied vertices and the new (upgraded) attribute
465 * has not been defined before, this list is somewhat degenerate,
466 * and will need fixup at runtime.
468 if (tnl
->save
.copied
.nr
)
470 GLfloat
*data
= tnl
->save
.copied
.buffer
;
471 GLfloat
*dest
= tnl
->save
.buffer
;
474 /* Need to note this and fix up at runtime (or loopback):
476 if (tnl
->save
.currentsz
[attr
][0] == 0) {
478 tnl
->save
.dangling_attr_ref
= GL_TRUE
;
479 _mesa_debug(0, "_save_upgrade_vertex: dangling reference attr %d\n",
483 /* The current strategy is to punt these degenerate cases
484 * through _tnl_loopback_vertex_list(), a lower-performance
485 * option. To minimize the impact of this, artificially
486 * reduce the size of this vertex_list.
488 if (t
->save
.counter
> 10) {
489 t
->save
.initial_counter
= 10;
490 t
->save
.counter
= 10;
495 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
496 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
497 if (tnl
->save
.attrsz
[j
]) {
500 ASSIGN_4V( dest
, 0, 0, 0, 1 );
501 COPY_SZ_4V( dest
, oldsz
, data
);
506 COPY_SZ_4V( dest
, newsz
, tnl
->save
.current
[attr
] );
511 GLint sz
= tnl
->save
.attrsz
[j
];
512 COPY_SZ_4V( dest
, sz
, data
);
520 tnl
->save
.vbptr
= dest
;
521 tnl
->save
.counter
-= tnl
->save
.copied
.nr
;
528 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
529 * entrypoint is called for the first time.
531 static void do_choose( GLuint attr
, GLuint sz
,
532 void (*attr_func
)( const GLfloat
*),
533 void (*choose1
)( const GLfloat
*),
534 void (*choose2
)( const GLfloat
*),
535 void (*choose3
)( const GLfloat
*),
536 void (*choose4
)( const GLfloat
*),
539 GET_CURRENT_CONTEXT( ctx
);
540 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
541 static GLfloat id
[4] = { 0, 0, 0, 1 };
544 if (tnl
->save
.attrsz
[attr
] < sz
) {
545 /* New size is larger. Need to flush existing vertices and get
546 * an enlarged vertex format.
548 _save_upgrade_vertex( ctx
, attr
, sz
);
551 /* New size is equal or smaller - just need to fill in some
554 for (i
= sz
; i
<= tnl
->save
.attrsz
[attr
] ; i
++)
555 tnl
->save
.attrptr
[attr
][i
-1] = id
[i
-1];
558 /* Reset any active pointers for this attribute
560 tnl
->save
.tabfv
[attr
][0] = choose1
;
561 tnl
->save
.tabfv
[attr
][1] = choose2
;
562 tnl
->save
.tabfv
[attr
][2] = choose3
;
563 tnl
->save
.tabfv
[attr
][3] = choose4
;
565 /* Update the secondary dispatch table with the new function
567 tnl
->save
.tabfv
[attr
][sz
-1] = attr_func
;
574 /* Only one size for each attribute may be active at once. Eg. if
575 * Color3f is installed/active, then Color4f may not be, even if the
576 * vertex actually contains 4 color coordinates. This is because the
577 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
578 * of the chooser function when switching between Color4f and Color3f.
580 #define ATTRFV( ATTR, N ) \
581 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
583 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
585 GET_CURRENT_CONTEXT( ctx ); \
586 TNLcontext *tnl = TNL_CONTEXT(ctx); \
591 if (N>0) tnl->save.vbptr[0] = v[0]; \
592 if (N>1) tnl->save.vbptr[1] = v[1]; \
593 if (N>2) tnl->save.vbptr[2] = v[2]; \
594 if (N>3) tnl->save.vbptr[3] = v[3]; \
596 for (i = N; i < tnl->save.vertex_size; i++) \
597 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
599 tnl->save.vbptr += tnl->save.vertex_size; \
601 if (--tnl->save.counter == 0) \
602 _save_wrap_filled_vertex( ctx ); \
605 GLfloat *dest = tnl->save.attrptr[ATTR]; \
606 if (N>0) dest[0] = v[0]; \
607 if (N>1) dest[1] = v[1]; \
608 if (N>2) dest[2] = v[2]; \
609 if (N>3) dest[3] = v[3]; \
613 #define CHOOSE( ATTR, N ) \
614 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
617 save_attrib_##ATTR##_##N, \
618 save_choose_##ATTR##_1, \
619 save_choose_##ATTR##_2, \
620 save_choose_##ATTR##_3, \
621 save_choose_##ATTR##_4, \
626 static void save_init_##ATTR( TNLcontext *tnl ) \
628 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
629 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
630 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
631 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
634 #define ATTRS( ATTRIB ) \
635 ATTRFV( ATTRIB, 1 ) \
636 ATTRFV( ATTRIB, 2 ) \
637 ATTRFV( ATTRIB, 3 ) \
638 ATTRFV( ATTRIB, 4 ) \
639 CHOOSE( ATTRIB, 1 ) \
640 CHOOSE( ATTRIB, 2 ) \
641 CHOOSE( ATTRIB, 3 ) \
642 CHOOSE( ATTRIB, 4 ) \
646 /* Generate a lot of functions. These are the actual worker
647 * functions, which are equivalent to those generated via codegen
668 static void _save_reset_vertex( GLcontext
*ctx
)
670 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
690 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
691 tnl
->save
.attrsz
[i
] = 0;
693 tnl
->save
.vertex_size
= 0;
694 tnl
->save
.have_materials
= 0;
696 _save_reset_counters( ctx
);
701 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
702 * of glMultTexCoord and glProgramParamterNV by routing all these
703 * through a second level dispatch table.
705 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
707 GET_CURRENT_CONTEXT( ctx ); \
708 TNLcontext *tnl = TNL_CONTEXT(ctx); \
709 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
712 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
713 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
714 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
715 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
717 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
719 #if defined(USE_X86_ASM) && 0 /* will break register calling convention */
722 #define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
723 #define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
724 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
728 #define DISPATCH_ATTR2F( ATTR, S,T ) \
731 v[0] = S; v[1] = T; \
732 DISPATCH_ATTR2FV( ATTR, v ); \
734 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
737 v[0] = S; v[1] = T; v[2] = R; \
738 DISPATCH_ATTR3FV( ATTR, v ); \
740 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
743 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
744 DISPATCH_ATTR4FV( ATTR, v ); \
749 static void enum_error( void )
751 GET_CURRENT_CONTEXT( ctx
);
752 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
755 static void GLAPIENTRY
_save_Vertex2f( GLfloat x
, GLfloat y
)
757 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
760 static void GLAPIENTRY
_save_Vertex2fv( const GLfloat
*v
)
762 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
765 static void GLAPIENTRY
_save_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
767 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
770 static void GLAPIENTRY
_save_Vertex3fv( const GLfloat
*v
)
772 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
775 static void GLAPIENTRY
_save_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
777 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
780 static void GLAPIENTRY
_save_Vertex4fv( const GLfloat
*v
)
782 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
785 static void GLAPIENTRY
_save_TexCoord1f( GLfloat x
)
787 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
790 static void GLAPIENTRY
_save_TexCoord1fv( const GLfloat
*v
)
792 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
795 static void GLAPIENTRY
_save_TexCoord2f( GLfloat x
, GLfloat y
)
797 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
800 static void GLAPIENTRY
_save_TexCoord2fv( const GLfloat
*v
)
802 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
805 static void GLAPIENTRY
_save_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
807 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
810 static void GLAPIENTRY
_save_TexCoord3fv( const GLfloat
*v
)
812 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
815 static void GLAPIENTRY
_save_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
817 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
820 static void GLAPIENTRY
_save_TexCoord4fv( const GLfloat
*v
)
822 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
825 static void GLAPIENTRY
_save_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
827 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
830 static void GLAPIENTRY
_save_Normal3fv( const GLfloat
*v
)
832 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
835 static void GLAPIENTRY
_save_FogCoordfEXT( GLfloat x
)
837 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
840 static void GLAPIENTRY
_save_FogCoordfvEXT( const GLfloat
*v
)
842 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
845 static void GLAPIENTRY
_save_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
847 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
850 static void GLAPIENTRY
_save_Color3fv( const GLfloat
*v
)
852 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
855 static void GLAPIENTRY
_save_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
857 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
860 static void GLAPIENTRY
_save_Color4fv( const GLfloat
*v
)
862 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
865 static void GLAPIENTRY
_save_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
867 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
870 static void GLAPIENTRY
_save_SecondaryColor3fvEXT( const GLfloat
*v
)
872 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
875 static void GLAPIENTRY
_save_MultiTexCoord1f( GLenum target
, GLfloat x
)
877 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
878 DISPATCH_ATTR1F( attr
, x
);
881 static void GLAPIENTRY
_save_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
883 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
884 DISPATCH_ATTR1FV( attr
, v
);
887 static void GLAPIENTRY
_save_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
889 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
890 DISPATCH_ATTR2F( attr
, x
, y
);
893 static void GLAPIENTRY
_save_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
895 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
896 DISPATCH_ATTR2FV( attr
, v
);
899 static void GLAPIENTRY
_save_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
902 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
903 DISPATCH_ATTR3F( attr
, x
, y
, z
);
906 static void GLAPIENTRY
_save_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
908 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
909 DISPATCH_ATTR3FV( attr
, v
);
912 static void GLAPIENTRY
_save_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
913 GLfloat z
, GLfloat w
)
915 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
916 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
919 static void GLAPIENTRY
_save_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
921 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
922 DISPATCH_ATTR4FV( attr
, v
);
925 static void GLAPIENTRY
_save_VertexAttrib1fNV( GLuint index
, GLfloat x
)
927 if (index
< VERT_ATTRIB_MAX
)
928 DISPATCH_ATTR1F( index
, x
);
933 static void GLAPIENTRY
_save_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
935 if (index
< VERT_ATTRIB_MAX
)
936 DISPATCH_ATTR1FV( index
, v
);
941 static void GLAPIENTRY
_save_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
943 if (index
< VERT_ATTRIB_MAX
)
944 DISPATCH_ATTR2F( index
, x
, y
);
949 static void GLAPIENTRY
_save_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
951 if (index
< VERT_ATTRIB_MAX
)
952 DISPATCH_ATTR2FV( index
, v
);
957 static void GLAPIENTRY
_save_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
960 if (index
< VERT_ATTRIB_MAX
)
961 DISPATCH_ATTR3F( index
, x
, y
, z
);
966 static void GLAPIENTRY
_save_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
968 if (index
< VERT_ATTRIB_MAX
)
969 DISPATCH_ATTR3FV( index
, v
);
974 static void GLAPIENTRY
_save_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
975 GLfloat z
, GLfloat w
)
977 if (index
< VERT_ATTRIB_MAX
)
978 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
983 static void GLAPIENTRY
_save_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
985 if (index
< VERT_ATTRIB_MAX
)
986 DISPATCH_ATTR4FV( index
, v
);
994 * These are treated as per-vertex attributes, at indices above where
995 * the NV_vertex_program leaves off. There are a lot of good things
996 * about treating materials this way.
998 * However: I don't want to double the number of generated functions
999 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
1000 * ATTRF into this function, and dispense with codegen and
1001 * second-level dispatch.
1003 * There is no aliasing of material attributes with other entrypoints.
1005 #define MAT_ATTR( A, N, params ) \
1007 if (tnl->save.attrsz[A] < N) { \
1008 _save_upgrade_vertex( ctx, A, N ); \
1009 tnl->save.have_materials = GL_TRUE; \
1013 GLfloat *dest = tnl->save.attrptr[A]; \
1014 if (N>0) dest[0] = params[0]; \
1015 if (N>1) dest[1] = params[1]; \
1016 if (N>2) dest[2] = params[2]; \
1017 if (N>3) dest[3] = params[3]; \
1022 #define MAT( ATTR, N, face, params ) \
1024 if (face != GL_BACK) \
1025 MAT_ATTR( ATTR, N, params ); /* front */ \
1026 if (face != GL_FRONT) \
1027 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1031 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1032 * later on - in the meantime just store everything.
1034 static void GLAPIENTRY
_save_Materialfv( GLenum face
, GLenum pname
,
1035 const GLfloat
*params
)
1037 GET_CURRENT_CONTEXT( ctx
);
1038 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1042 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
1045 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1048 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1051 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
1054 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
1056 case GL_COLOR_INDEXES
:
1057 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
1059 case GL_AMBIENT_AND_DIFFUSE
:
1060 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1061 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1064 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
1070 #define IDX_ATTR( A, IDX ) \
1072 GET_CURRENT_CONTEXT( ctx ); \
1073 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1075 if (tnl->save.attrsz[A] < 1) { \
1076 _save_upgrade_vertex( ctx, A, 1 ); \
1080 GLfloat *dest = tnl->save.attrptr[A]; \
1086 static void GLAPIENTRY
_save_EdgeFlag( GLboolean b
)
1088 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
1091 static void GLAPIENTRY
_save_EdgeFlagv( const GLboolean
*v
)
1093 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)(v
[0]) );
1096 static void GLAPIENTRY
_save_Indexf( GLfloat f
)
1098 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
1101 static void GLAPIENTRY
_save_Indexfv( const GLfloat
*f
)
1103 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
[0] );
1109 /* Cope with EvalCoord/CallList called within a begin/end object:
1110 * -- Flush current buffer
1111 * -- Fallback to opcodes for the rest of the begin/end object.
1113 #define FALLBACK(ctx) \
1115 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1117 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1119 if (tnl->save.initial_counter != tnl->save.counter || \
1120 tnl->save.prim_count) \
1121 _save_compile_vertex_list( ctx ); \
1123 _save_copy_to_current( ctx ); \
1124 _save_reset_vertex( ctx ); \
1125 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1126 ctx->Driver.SaveNeedFlush = 0; \
1129 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
1131 GET_CURRENT_CONTEXT(ctx
);
1133 ctx
->Save
->EvalCoord1f( u
);
1136 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
1138 GET_CURRENT_CONTEXT(ctx
);
1140 ctx
->Save
->EvalCoord1fv( v
);
1143 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
1145 GET_CURRENT_CONTEXT(ctx
);
1147 ctx
->Save
->EvalCoord2f( u
, v
);
1150 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
1152 GET_CURRENT_CONTEXT(ctx
);
1154 ctx
->Save
->EvalCoord2fv( v
);
1157 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
1159 GET_CURRENT_CONTEXT(ctx
);
1161 ctx
->Save
->EvalPoint1( i
);
1164 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
1166 GET_CURRENT_CONTEXT(ctx
);
1168 ctx
->Save
->EvalPoint2( i
, j
);
1171 static void GLAPIENTRY
_save_CallList( GLuint l
)
1173 GET_CURRENT_CONTEXT(ctx
);
1175 ctx
->Save
->CallList( l
);
1178 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
1180 GET_CURRENT_CONTEXT(ctx
);
1182 ctx
->Save
->CallLists( n
, type
, v
);
1188 /* This begin is hooked into ... Updating of
1189 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1191 static GLboolean
_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
1193 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1196 GLuint i
= tnl
->save
.prim_count
++;
1198 assert(i
< tnl
->save
.prim_max
);
1199 tnl
->save
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1200 tnl
->save
.prim
[i
].start
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
1201 tnl
->save
.prim
[i
].count
= 0;
1203 _mesa_install_save_vtxfmt( ctx
, &tnl
->save_vtxfmt
);
1204 ctx
->Driver
.SaveNeedFlush
= 1;
1213 static void GLAPIENTRY
_save_End( void )
1215 GET_CURRENT_CONTEXT( ctx
);
1216 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1217 GLint i
= tnl
->save
.prim_count
- 1;
1219 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1220 tnl
->save
.prim
[i
].mode
|= PRIM_END
;
1221 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
1222 tnl
->save
.prim
[i
].start
);
1224 if (i
== (GLint
) tnl
->save
.prim_max
- 1) {
1225 _save_compile_vertex_list( ctx
);
1226 assert(tnl
->save
.copied
.nr
== 0);
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
);
1237 /* These are all errors as this vtxfmt is only installed inside
1240 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1241 const GLvoid
*indices
)
1243 GET_CURRENT_CONTEXT(ctx
);
1244 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
1248 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
1249 GLuint start
, GLuint end
,
1250 GLsizei count
, GLenum type
,
1251 const GLvoid
*indices
)
1253 GET_CURRENT_CONTEXT(ctx
);
1254 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
1257 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1259 GET_CURRENT_CONTEXT(ctx
);
1260 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
1263 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1265 GET_CURRENT_CONTEXT(ctx
);
1266 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
1269 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
1271 GET_CURRENT_CONTEXT(ctx
);
1272 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
1275 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
1276 GLint j1
, GLint j2
)
1278 GET_CURRENT_CONTEXT(ctx
);
1279 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
1282 static void GLAPIENTRY
_save_Begin( GLenum mode
)
1284 GET_CURRENT_CONTEXT( ctx
);
1285 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
1289 /* Unlike the functions above, these are to be hooked into the vtxfmt
1290 * maintained in ctx->ListState, active when the list is known or
1291 * suspected to be outside any begin/end primitive.
1293 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1295 GET_CURRENT_CONTEXT(ctx
);
1296 _save_NotifyBegin( ctx
, GL_QUADS
| PRIM_WEAK
);
1297 GL_CALL(Vertex2f
)( x1
, y1
);
1298 GL_CALL(Vertex2f
)( x2
, y1
);
1299 GL_CALL(Vertex2f
)( x2
, y2
);
1300 GL_CALL(Vertex2f
)( x1
, y2
);
1305 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1307 GET_CURRENT_CONTEXT(ctx
);
1310 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
1313 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1314 for (i
= 0; i
< count
; i
++)
1315 GL_CALL(ArrayElement
)(start
+ i
);
1320 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1321 const GLvoid
*indices
)
1323 GET_CURRENT_CONTEXT(ctx
);
1326 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
1329 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1332 case GL_UNSIGNED_BYTE
:
1333 for (i
= 0 ; i
< count
; i
++)
1334 GL_CALL(ArrayElement
)( ((GLubyte
*)indices
)[i
] );
1336 case GL_UNSIGNED_SHORT
:
1337 for (i
= 0 ; i
< count
; i
++)
1338 GL_CALL(ArrayElement
)( ((GLushort
*)indices
)[i
] );
1340 case GL_UNSIGNED_INT
:
1341 for (i
= 0 ; i
< count
; i
++)
1342 GL_CALL(ArrayElement
)( ((GLuint
*)indices
)[i
] );
1345 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
1352 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
1353 GLuint start
, GLuint end
,
1354 GLsizei count
, GLenum type
,
1355 const GLvoid
*indices
)
1357 GET_CURRENT_CONTEXT(ctx
);
1358 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1360 count
, type
, indices
))
1361 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1368 static void _save_vtxfmt_init( GLcontext
*ctx
)
1370 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1371 GLvertexformat
*vfmt
= &tnl
->save_vtxfmt
;
1373 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1374 vfmt
->Begin
= _save_Begin
;
1375 vfmt
->Color3f
= _save_Color3f
;
1376 vfmt
->Color3fv
= _save_Color3fv
;
1377 vfmt
->Color4f
= _save_Color4f
;
1378 vfmt
->Color4fv
= _save_Color4fv
;
1379 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1380 vfmt
->EdgeFlagv
= _save_EdgeFlagv
;
1381 vfmt
->End
= _save_End
;
1382 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1383 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1384 vfmt
->Indexf
= _save_Indexf
;
1385 vfmt
->Indexfv
= _save_Indexfv
;
1386 vfmt
->Materialfv
= _save_Materialfv
;
1387 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1388 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1389 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1390 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1391 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1392 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1393 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1394 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1395 vfmt
->Normal3f
= _save_Normal3f
;
1396 vfmt
->Normal3fv
= _save_Normal3fv
;
1397 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1398 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1399 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1400 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1401 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1402 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1403 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1404 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1405 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1406 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1407 vfmt
->Vertex2f
= _save_Vertex2f
;
1408 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1409 vfmt
->Vertex3f
= _save_Vertex3f
;
1410 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1411 vfmt
->Vertex4f
= _save_Vertex4f
;
1412 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1413 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1414 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1415 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1416 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1417 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1418 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1419 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1420 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1422 /* This will all require us to fallback to saving the list as opcodes:
1424 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1425 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1426 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1427 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1428 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1429 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1430 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1431 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1433 /* These are all errors as we at least know we are in some sort of
1436 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1437 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1438 vfmt
->Begin
= _save_Begin
;
1439 vfmt
->Rectf
= _save_Rectf
;
1440 vfmt
->DrawArrays
= _save_DrawArrays
;
1441 vfmt
->DrawElements
= _save_DrawElements
;
1442 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1447 void _tnl_SaveFlushVertices( GLcontext
*ctx
)
1449 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1451 /* Noop when we are actually active:
1453 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1454 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1457 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
||
1458 tnl
->save
.prim_count
)
1459 _save_compile_vertex_list( ctx
);
1461 _save_copy_to_current( ctx
);
1462 _save_reset_vertex( ctx
);
1463 ctx
->Driver
.SaveNeedFlush
= 0;
1466 void _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1468 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1470 if (!tnl
->save
.prim_store
)
1471 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
1473 if (!tnl
->save
.vertex_store
) {
1474 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
1475 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
1478 _save_reset_vertex( ctx
);
1479 ctx
->Driver
.SaveNeedFlush
= 0;
1482 void _tnl_EndList( GLcontext
*ctx
)
1484 assert(TNL_CONTEXT(ctx
)->save
.vertex_size
== 0);
1487 void _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
1491 void _tnl_EndCallList( GLcontext
*ctx
)
1496 static void _tnl_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1498 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1500 if ( --node
->vertex_store
->refcount
== 0 )
1501 FREE( node
->vertex_store
);
1503 if ( --node
->prim_store
->refcount
== 0 )
1504 FREE( node
->prim_store
);
1506 if ( node
->normal_lengths
)
1507 FREE( node
->normal_lengths
);
1511 static void _tnl_print_vertex_list( GLcontext
*ctx
, void *data
)
1513 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1516 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1521 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1522 struct tnl_prim
*prim
= &node
->prim
[i
];
1523 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1525 _mesa_lookup_enum_by_nr(prim
->mode
& PRIM_MODE_MASK
),
1527 prim
->start
+ prim
->count
,
1528 (prim
->mode
& PRIM_BEGIN
) ? "BEGIN" : "(wrap)",
1529 (prim
->mode
& PRIM_END
) ? "END" : "(wrap)");
1534 static void _save_current_init( GLcontext
*ctx
)
1536 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1539 for (i
= 0; i
< _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1540 ASSERT(i
< VERT_ATTRIB_MAX
);
1541 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[i
];
1542 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentAttrib
[i
];
1545 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
< _TNL_ATTRIB_INDEX
; i
++) {
1546 const GLuint j
= i
- _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
1547 ASSERT(j
< MAT_ATTRIB_MAX
);
1548 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1549 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1552 tnl
->save
.currentsz
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.ActiveIndex
;
1553 tnl
->save
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.CurrentIndex
;
1555 /* Current edgeflag is handled individually */
1559 * Initialize the display list compiler
1561 void _tnl_save_init( GLcontext
*ctx
)
1563 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1564 struct tnl_vertex_arrays
*tmp
= &tnl
->save_inputs
;
1568 for (i
= 0; i
< _TNL_ATTRIB_MAX
; i
++)
1569 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1571 tnl
->save
.opcode_vertex_list
=
1572 _mesa_alloc_opcode( ctx
,
1573 sizeof(struct tnl_vertex_list
),
1574 _tnl_playback_vertex_list
,
1575 _tnl_destroy_vertex_list
,
1576 _tnl_print_vertex_list
);
1578 ctx
->Driver
.NotifySaveBegin
= _save_NotifyBegin
;
1580 _save_vtxfmt_init( ctx
);
1581 _save_current_init( ctx
);
1583 /* Hook our array functions into the outside-begin-end vtxfmt in
1586 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1587 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1588 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1589 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1590 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1595 * Deallocate the immediate-mode buffer for the given context, if
1596 * its reference count goes to zero.
1598 void _tnl_save_destroy( GLcontext
*ctx
)