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
;
448 /* Recalculate all the attrptr[] values:
450 for (i
= 0, tmp
= tnl
->save
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
451 if (tnl
->save
.attrsz
[i
]) {
452 tnl
->save
.attrptr
[i
] = tmp
;
453 tmp
+= tnl
->save
.attrsz
[i
];
456 tnl
->save
.attrptr
[i
] = 0; /* will not be dereferenced. */
459 /* Copy from current to repopulate the vertex with correct values.
461 _save_copy_from_current( ctx
);
464 /* Replay stored vertices to translate them to new format here.
466 * If there are copied vertices and the new (upgraded) attribute
467 * has not been defined before, this list is somewhat degenerate,
468 * and will need fixup at runtime.
470 if (tnl
->save
.copied
.nr
)
472 GLfloat
*data
= tnl
->save
.copied
.buffer
;
473 GLfloat
*dest
= tnl
->save
.buffer
;
476 /* Need to note this and fix up at runtime (or loopback):
478 if (tnl
->save
.currentsz
[attr
] == 0) {
480 tnl
->save
.dangling_attr_ref
= GL_TRUE
;
481 _mesa_debug(0, "_save_upgrade_vertex: dangling reference attr %d\n",
485 /* The current strategy is to punt these degenerate cases
486 * through _tnl_loopback_vertex_list(), a lower-performance
487 * option. To minimize the impact of this, artificially
488 * reduce the size of this vertex_list.
490 if (t
->save
.counter
> 10) {
491 t
->save
.initial_counter
= 10;
492 t
->save
.counter
= 10;
497 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
498 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
499 if (tnl
->save
.attrsz
[j
]) {
501 ASSIGN_4V( dest
, 0, 0, 0, 1 );
502 COPY_SZ_4V( dest
, oldsz
, data
);
507 GLint sz
= tnl
->save
.attrsz
[j
];
508 COPY_SZ_4V( dest
, sz
, data
);
516 tnl
->save
.vbptr
= dest
;
517 tnl
->save
.counter
-= tnl
->save
.copied
.nr
;
524 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
525 * entrypoint is called for the first time.
527 static void do_choose( GLuint attr
, GLuint sz
,
528 void (*attr_func
)( const GLfloat
*),
529 void (*choose1
)( const GLfloat
*),
530 void (*choose2
)( const GLfloat
*),
531 void (*choose3
)( const GLfloat
*),
532 void (*choose4
)( const GLfloat
*),
535 GET_CURRENT_CONTEXT( ctx
);
536 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
537 static GLfloat id
[4] = { 0, 0, 0, 1 };
540 if (tnl
->save
.attrsz
[attr
] < sz
) {
541 /* New size is larger. Need to flush existing vertices and get
542 * an enlarged vertex format.
544 _save_upgrade_vertex( ctx
, attr
, sz
);
547 /* New size is equal or smaller - just need to fill in some
550 for (i
= sz
; i
<= tnl
->save
.attrsz
[attr
] ; i
++)
551 tnl
->save
.attrptr
[attr
][i
-1] = id
[i
-1];
554 /* Reset any active pointers for this attribute
556 tnl
->save
.tabfv
[attr
][0] = choose1
;
557 tnl
->save
.tabfv
[attr
][1] = choose2
;
558 tnl
->save
.tabfv
[attr
][2] = choose3
;
559 tnl
->save
.tabfv
[attr
][3] = choose4
;
561 /* Update the secondary dispatch table with the new function
563 tnl
->save
.tabfv
[attr
][sz
-1] = attr_func
;
570 /* Only one size for each attribute may be active at once. Eg. if
571 * Color3f is installed/active, then Color4f may not be, even if the
572 * vertex actually contains 4 color coordinates. This is because the
573 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
574 * of the chooser function when switching between Color4f and Color3f.
576 #define ATTRFV( ATTR, N ) \
577 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
579 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
581 GET_CURRENT_CONTEXT( ctx ); \
582 TNLcontext *tnl = TNL_CONTEXT(ctx); \
587 if (N>0) tnl->save.vbptr[0] = v[0]; \
588 if (N>1) tnl->save.vbptr[1] = v[1]; \
589 if (N>2) tnl->save.vbptr[2] = v[2]; \
590 if (N>3) tnl->save.vbptr[3] = v[3]; \
592 for (i = N; i < tnl->save.vertex_size; i++) \
593 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
595 tnl->save.vbptr += tnl->save.vertex_size; \
597 if (--tnl->save.counter == 0) \
598 _save_wrap_filled_vertex( ctx ); \
601 GLfloat *dest = tnl->save.attrptr[ATTR]; \
602 if (N>0) dest[0] = v[0]; \
603 if (N>1) dest[1] = v[1]; \
604 if (N>2) dest[2] = v[2]; \
605 if (N>3) dest[3] = v[3]; \
609 #define CHOOSE( ATTR, N ) \
610 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
613 save_attrib_##ATTR##_##N, \
614 save_choose_##ATTR##_1, \
615 save_choose_##ATTR##_2, \
616 save_choose_##ATTR##_3, \
617 save_choose_##ATTR##_4, \
622 static void save_init_##ATTR( TNLcontext *tnl ) \
624 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
625 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
626 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
627 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
630 #define ATTRS( ATTRIB ) \
631 ATTRFV( ATTRIB, 1 ) \
632 ATTRFV( ATTRIB, 2 ) \
633 ATTRFV( ATTRIB, 3 ) \
634 ATTRFV( ATTRIB, 4 ) \
635 CHOOSE( ATTRIB, 1 ) \
636 CHOOSE( ATTRIB, 2 ) \
637 CHOOSE( ATTRIB, 3 ) \
638 CHOOSE( ATTRIB, 4 ) \
642 /* Generate a lot of functions. These are the actual worker
643 * functions, which are equivalent to those generated via codegen
664 static void _save_reset_vertex( GLcontext
*ctx
)
666 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
686 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
687 tnl
->save
.attrsz
[i
] = 0;
689 tnl
->save
.vertex_size
= 0;
690 tnl
->save
.have_materials
= 0;
692 _save_reset_counters( ctx
);
697 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
698 * of glMultTexCoord and glProgramParamterNV by routing all these
699 * through a second level dispatch table.
701 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
703 GET_CURRENT_CONTEXT( ctx ); \
704 TNLcontext *tnl = TNL_CONTEXT(ctx); \
705 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
708 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
709 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
710 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
711 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
713 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
715 #define DISPATCH_ATTR2F( ATTR, S,T ) \
718 v[0] = S; v[1] = T; \
719 DISPATCH_ATTR2FV( ATTR, v ); \
721 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
724 v[0] = S; v[1] = T; v[2] = R; \
725 DISPATCH_ATTR3FV( ATTR, v ); \
727 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
730 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
731 DISPATCH_ATTR4FV( ATTR, v ); \
735 static void enum_error( void )
737 GET_CURRENT_CONTEXT( ctx
);
738 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
741 static void GLAPIENTRY
_save_Vertex2f( GLfloat x
, GLfloat y
)
743 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
746 static void GLAPIENTRY
_save_Vertex2fv( const GLfloat
*v
)
748 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
751 static void GLAPIENTRY
_save_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
753 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
756 static void GLAPIENTRY
_save_Vertex3fv( const GLfloat
*v
)
758 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
761 static void GLAPIENTRY
_save_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
763 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
766 static void GLAPIENTRY
_save_Vertex4fv( const GLfloat
*v
)
768 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
771 static void GLAPIENTRY
_save_TexCoord1f( GLfloat x
)
773 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
776 static void GLAPIENTRY
_save_TexCoord1fv( const GLfloat
*v
)
778 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
781 static void GLAPIENTRY
_save_TexCoord2f( GLfloat x
, GLfloat y
)
783 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
786 static void GLAPIENTRY
_save_TexCoord2fv( const GLfloat
*v
)
788 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
791 static void GLAPIENTRY
_save_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
793 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
796 static void GLAPIENTRY
_save_TexCoord3fv( const GLfloat
*v
)
798 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
801 static void GLAPIENTRY
_save_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
803 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
806 static void GLAPIENTRY
_save_TexCoord4fv( const GLfloat
*v
)
808 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
811 static void GLAPIENTRY
_save_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
813 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
816 static void GLAPIENTRY
_save_Normal3fv( const GLfloat
*v
)
818 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
821 static void GLAPIENTRY
_save_FogCoordfEXT( GLfloat x
)
823 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
826 static void GLAPIENTRY
_save_FogCoordfvEXT( const GLfloat
*v
)
828 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
831 static void GLAPIENTRY
_save_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
833 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
836 static void GLAPIENTRY
_save_Color3fv( const GLfloat
*v
)
838 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
841 static void GLAPIENTRY
_save_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
843 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
846 static void GLAPIENTRY
_save_Color4fv( const GLfloat
*v
)
848 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
851 static void GLAPIENTRY
_save_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
853 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
856 static void GLAPIENTRY
_save_SecondaryColor3fvEXT( const GLfloat
*v
)
858 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
861 static void GLAPIENTRY
_save_MultiTexCoord1f( GLenum target
, GLfloat x
)
863 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
864 DISPATCH_ATTR1F( attr
, x
);
867 static void GLAPIENTRY
_save_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
869 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
870 DISPATCH_ATTR1FV( attr
, v
);
873 static void GLAPIENTRY
_save_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
875 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
876 DISPATCH_ATTR2F( attr
, x
, y
);
879 static void GLAPIENTRY
_save_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
881 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
882 DISPATCH_ATTR2FV( attr
, v
);
885 static void GLAPIENTRY
_save_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
888 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
889 DISPATCH_ATTR3F( attr
, x
, y
, z
);
892 static void GLAPIENTRY
_save_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
894 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
895 DISPATCH_ATTR3FV( attr
, v
);
898 static void GLAPIENTRY
_save_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
899 GLfloat z
, GLfloat w
)
901 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
902 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
905 static void GLAPIENTRY
_save_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
907 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
908 DISPATCH_ATTR4FV( attr
, v
);
911 static void GLAPIENTRY
_save_VertexAttrib1fNV( GLuint index
, GLfloat x
)
913 if (index
< VERT_ATTRIB_MAX
)
914 DISPATCH_ATTR1F( index
, x
);
919 static void GLAPIENTRY
_save_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
921 if (index
< VERT_ATTRIB_MAX
)
922 DISPATCH_ATTR1FV( index
, v
);
927 static void GLAPIENTRY
_save_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
929 if (index
< VERT_ATTRIB_MAX
)
930 DISPATCH_ATTR2F( index
, x
, y
);
935 static void GLAPIENTRY
_save_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
937 if (index
< VERT_ATTRIB_MAX
)
938 DISPATCH_ATTR2FV( index
, v
);
943 static void GLAPIENTRY
_save_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
946 if (index
< VERT_ATTRIB_MAX
)
947 DISPATCH_ATTR3F( index
, x
, y
, z
);
952 static void GLAPIENTRY
_save_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
954 if (index
< VERT_ATTRIB_MAX
)
955 DISPATCH_ATTR3FV( index
, v
);
960 static void GLAPIENTRY
_save_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
961 GLfloat z
, GLfloat w
)
963 if (index
< VERT_ATTRIB_MAX
)
964 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
969 static void GLAPIENTRY
_save_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
971 if (index
< VERT_ATTRIB_MAX
)
972 DISPATCH_ATTR4FV( index
, v
);
980 * These are treated as per-vertex attributes, at indices above where
981 * the NV_vertex_program leaves off. There are a lot of good things
982 * about treating materials this way.
984 * However: I don't want to double the number of generated functions
985 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
986 * ATTRF into this function, and dispense with codegen and
987 * second-level dispatch.
989 * There is no aliasing of material attributes with other entrypoints.
991 #define MAT_ATTR( A, N, params ) \
993 if (tnl->save.attrsz[A] < N) { \
994 _save_upgrade_vertex( ctx, A, N ); \
995 tnl->save.have_materials = GL_TRUE; \
999 GLfloat *dest = tnl->save.attrptr[A]; \
1000 if (N>0) dest[0] = params[0]; \
1001 if (N>1) dest[1] = params[1]; \
1002 if (N>2) dest[2] = params[2]; \
1003 if (N>3) dest[3] = params[3]; \
1008 #define MAT( ATTR, N, face, params ) \
1010 if (face != GL_BACK) \
1011 MAT_ATTR( ATTR, N, params ); /* front */ \
1012 if (face != GL_FRONT) \
1013 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1017 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1018 * later on - in the meantime just store everything.
1020 static void GLAPIENTRY
_save_Materialfv( GLenum face
, GLenum pname
,
1021 const GLfloat
*params
)
1023 GET_CURRENT_CONTEXT( ctx
);
1024 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1028 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
1031 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1034 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1037 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
1040 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
1042 case GL_COLOR_INDEXES
:
1043 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
1045 case GL_AMBIENT_AND_DIFFUSE
:
1046 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1047 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1050 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
1056 #define IDX_ATTR( A, IDX ) \
1058 GET_CURRENT_CONTEXT( ctx ); \
1059 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1061 if (tnl->save.attrsz[A] < 1) { \
1062 _save_upgrade_vertex( ctx, A, 1 ); \
1066 GLfloat *dest = tnl->save.attrptr[A]; \
1072 static void GLAPIENTRY
_save_EdgeFlag( GLboolean b
)
1074 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
1077 static void GLAPIENTRY
_save_EdgeFlagv( const GLboolean
*v
)
1079 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)(v
[0]) );
1082 static void GLAPIENTRY
_save_Indexf( GLfloat f
)
1084 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
1087 static void GLAPIENTRY
_save_Indexfv( const GLfloat
*f
)
1089 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
[0] );
1095 /* Cope with EvalCoord/CallList called within a begin/end object:
1096 * -- Flush current buffer
1097 * -- Fallback to opcodes for the rest of the begin/end object.
1099 #define FALLBACK(ctx) \
1101 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1103 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1105 if (tnl->save.initial_counter != tnl->save.counter || \
1106 tnl->save.prim_count) \
1107 _save_compile_vertex_list( ctx ); \
1109 _save_copy_to_current( ctx ); \
1110 _save_reset_vertex( ctx ); \
1111 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1112 ctx->Driver.SaveNeedFlush = 0; \
1115 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
1117 GET_CURRENT_CONTEXT(ctx
);
1119 ctx
->Save
->EvalCoord1f( u
);
1122 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
1124 GET_CURRENT_CONTEXT(ctx
);
1126 ctx
->Save
->EvalCoord1fv( v
);
1129 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
1131 GET_CURRENT_CONTEXT(ctx
);
1133 ctx
->Save
->EvalCoord2f( u
, v
);
1136 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
1138 GET_CURRENT_CONTEXT(ctx
);
1140 ctx
->Save
->EvalCoord2fv( v
);
1143 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
1145 GET_CURRENT_CONTEXT(ctx
);
1147 ctx
->Save
->EvalPoint1( i
);
1150 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
1152 GET_CURRENT_CONTEXT(ctx
);
1154 ctx
->Save
->EvalPoint2( i
, j
);
1157 static void GLAPIENTRY
_save_CallList( GLuint l
)
1159 GET_CURRENT_CONTEXT(ctx
);
1161 ctx
->Save
->CallList( l
);
1164 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
1166 GET_CURRENT_CONTEXT(ctx
);
1168 ctx
->Save
->CallLists( n
, type
, v
);
1174 /* This begin is hooked into ... Updating of
1175 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1177 static GLboolean
_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
1179 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1182 GLuint i
= tnl
->save
.prim_count
++;
1184 assert(i
< tnl
->save
.prim_max
);
1185 tnl
->save
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1186 tnl
->save
.prim
[i
].start
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
1187 tnl
->save
.prim
[i
].count
= 0;
1189 _mesa_install_save_vtxfmt( ctx
, &tnl
->save_vtxfmt
);
1190 ctx
->Driver
.SaveNeedFlush
= 1;
1199 static void GLAPIENTRY
_save_End( void )
1201 GET_CURRENT_CONTEXT( ctx
);
1202 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1203 GLint i
= tnl
->save
.prim_count
- 1;
1205 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1206 tnl
->save
.prim
[i
].mode
|= PRIM_END
;
1207 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
1208 tnl
->save
.prim
[i
].start
);
1210 if (i
== (GLint
) tnl
->save
.prim_max
- 1) {
1211 _save_compile_vertex_list( ctx
);
1212 assert(tnl
->save
.copied
.nr
== 0);
1215 /* Swap out this vertex format while outside begin/end. Any color,
1216 * etc. received between here and the next begin will be compiled
1219 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1223 /* These are all errors as this vtxfmt is only installed inside
1226 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1227 const GLvoid
*indices
)
1229 GET_CURRENT_CONTEXT(ctx
);
1230 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
1234 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
1235 GLuint start
, GLuint end
,
1236 GLsizei count
, GLenum type
,
1237 const GLvoid
*indices
)
1239 GET_CURRENT_CONTEXT(ctx
);
1240 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
1243 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1245 GET_CURRENT_CONTEXT(ctx
);
1246 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
1249 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1251 GET_CURRENT_CONTEXT(ctx
);
1252 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
1255 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
1257 GET_CURRENT_CONTEXT(ctx
);
1258 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
1261 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
1262 GLint j1
, GLint j2
)
1264 GET_CURRENT_CONTEXT(ctx
);
1265 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
1268 static void GLAPIENTRY
_save_Begin( GLenum mode
)
1270 GET_CURRENT_CONTEXT( ctx
);
1271 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
1275 /* Unlike the functions above, these are to be hooked into the vtxfmt
1276 * maintained in ctx->ListState, active when the list is known or
1277 * suspected to be outside any begin/end primitive.
1279 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1281 GET_CURRENT_CONTEXT(ctx
);
1282 _save_NotifyBegin( ctx
, GL_QUADS
| PRIM_WEAK
);
1283 _glapi_Dispatch
->Vertex2f( x1
, y1
);
1284 _glapi_Dispatch
->Vertex2f( x2
, y1
);
1285 _glapi_Dispatch
->Vertex2f( x2
, y2
);
1286 _glapi_Dispatch
->Vertex2f( x1
, y2
);
1287 _glapi_Dispatch
->End();
1291 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1293 GET_CURRENT_CONTEXT(ctx
);
1296 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
1299 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1300 for (i
= start
; i
< count
; i
++)
1301 _glapi_Dispatch
->ArrayElement( i
);
1302 _glapi_Dispatch
->End();
1306 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1307 const GLvoid
*indices
)
1309 GET_CURRENT_CONTEXT(ctx
);
1312 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
1315 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1318 case GL_UNSIGNED_BYTE
:
1319 for (i
= 0 ; i
< count
; i
++)
1320 _glapi_Dispatch
->ArrayElement( ((GLubyte
*)indices
)[i
] );
1322 case GL_UNSIGNED_SHORT
:
1323 for (i
= 0 ; i
< count
; i
++)
1324 _glapi_Dispatch
->ArrayElement( ((GLushort
*)indices
)[i
] );
1326 case GL_UNSIGNED_INT
:
1327 for (i
= 0 ; i
< count
; i
++)
1328 _glapi_Dispatch
->ArrayElement( ((GLuint
*)indices
)[i
] );
1331 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
1335 _glapi_Dispatch
->End();
1338 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
1339 GLuint start
, GLuint end
,
1340 GLsizei count
, GLenum type
,
1341 const GLvoid
*indices
)
1343 GET_CURRENT_CONTEXT(ctx
);
1344 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1346 count
, type
, indices
))
1347 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1354 static void _save_vtxfmt_init( GLcontext
*ctx
)
1356 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1357 GLvertexformat
*vfmt
= &tnl
->save_vtxfmt
;
1359 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1360 vfmt
->Begin
= _save_Begin
;
1361 vfmt
->Color3f
= _save_Color3f
;
1362 vfmt
->Color3fv
= _save_Color3fv
;
1363 vfmt
->Color4f
= _save_Color4f
;
1364 vfmt
->Color4fv
= _save_Color4fv
;
1365 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1366 vfmt
->EdgeFlagv
= _save_EdgeFlagv
;
1367 vfmt
->End
= _save_End
;
1368 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1369 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1370 vfmt
->Indexf
= _save_Indexf
;
1371 vfmt
->Indexfv
= _save_Indexfv
;
1372 vfmt
->Materialfv
= _save_Materialfv
;
1373 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1374 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1375 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1376 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1377 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1378 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1379 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1380 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1381 vfmt
->Normal3f
= _save_Normal3f
;
1382 vfmt
->Normal3fv
= _save_Normal3fv
;
1383 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1384 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1385 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1386 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1387 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1388 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1389 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1390 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1391 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1392 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1393 vfmt
->Vertex2f
= _save_Vertex2f
;
1394 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1395 vfmt
->Vertex3f
= _save_Vertex3f
;
1396 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1397 vfmt
->Vertex4f
= _save_Vertex4f
;
1398 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1399 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1400 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1401 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1402 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1403 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1404 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1405 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1406 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1408 /* This will all require us to fallback to saving the list as opcodes:
1410 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1411 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1412 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1413 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1414 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1415 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1416 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1417 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1419 /* These are all errors as we at least know we are in some sort of
1422 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1423 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1424 vfmt
->Begin
= _save_Begin
;
1425 vfmt
->Rectf
= _save_Rectf
;
1426 vfmt
->DrawArrays
= _save_DrawArrays
;
1427 vfmt
->DrawElements
= _save_DrawElements
;
1428 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1433 void _tnl_SaveFlushVertices( GLcontext
*ctx
)
1435 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1437 /* Noop when we are actually active:
1439 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1440 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1443 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
||
1444 tnl
->save
.prim_count
)
1445 _save_compile_vertex_list( ctx
);
1447 _save_copy_to_current( ctx
);
1448 _save_reset_vertex( ctx
);
1449 ctx
->Driver
.SaveNeedFlush
= 0;
1452 void _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1454 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1456 if (!tnl
->save
.prim_store
)
1457 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
1459 if (!tnl
->save
.vertex_store
) {
1460 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
1461 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
1464 _save_reset_vertex( ctx
);
1465 ctx
->Driver
.SaveNeedFlush
= 0;
1468 void _tnl_EndList( GLcontext
*ctx
)
1470 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1471 assert(tnl
->save
.vertex_size
== 0);
1474 void _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
1478 void _tnl_EndCallList( GLcontext
*ctx
)
1483 static void _tnl_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1485 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1487 if ( --node
->vertex_store
->refcount
== 0 )
1488 FREE( node
->vertex_store
);
1490 if ( --node
->prim_store
->refcount
== 0 )
1491 FREE( node
->prim_store
);
1493 if ( node
->normal_lengths
)
1494 FREE( node
->normal_lengths
);
1498 static void _tnl_print_vertex_list( GLcontext
*ctx
, void *data
)
1500 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1503 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1508 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1509 struct tnl_prim
*prim
= &node
->prim
[i
];
1510 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1512 _mesa_lookup_enum_by_nr(prim
->mode
& PRIM_MODE_MASK
),
1514 prim
->start
+ prim
->count
,
1515 (prim
->mode
& PRIM_BEGIN
) ? "BEGIN" : "(wrap)",
1516 (prim
->mode
& PRIM_END
) ? "END" : "(wrap)");
1521 static void _save_current_init( GLcontext
*ctx
)
1523 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1526 for (i
= 0; i
< _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1527 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[i
];
1528 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentAttrib
[i
];
1531 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
< _TNL_ATTRIB_INDEX
; i
++) {
1532 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[i
];
1533 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentMaterial
[i
];
1536 tnl
->save
.currentsz
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.ActiveIndex
;
1537 tnl
->save
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.CurrentIndex
;
1539 /* Current edgeflag is handled individually */
1543 * Initialize the display list compiler
1545 void _tnl_save_init( GLcontext
*ctx
)
1547 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1548 struct tnl_vertex_arrays
*tmp
= &tnl
->save_inputs
;
1552 for (i
= 0; i
< _TNL_ATTRIB_MAX
; i
++)
1553 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1555 tnl
->save
.opcode_vertex_list
=
1556 _mesa_alloc_opcode( ctx
,
1557 sizeof(struct tnl_vertex_list
),
1558 _tnl_playback_vertex_list
,
1559 _tnl_destroy_vertex_list
,
1560 _tnl_print_vertex_list
);
1562 ctx
->Driver
.NotifySaveBegin
= _save_NotifyBegin
;
1564 _save_vtxfmt_init( ctx
);
1565 _save_current_init( ctx
);
1567 /* Hook our array functions into the outside-begin-end vtxfmt in
1570 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1571 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1572 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1573 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1574 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1579 * Deallocate the immediate-mode buffer for the given context, if
1580 * its reference count goes to zero.
1582 void _tnl_save_destroy( GLcontext
*ctx
)