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 struct tnl_vertex_list
*node
)
88 TNLcontext
*tnl
= TNL_CONTEXT( ctx
);
89 struct tnl_prim
*prim
= &node
->prim
[node
->prim_count
-1];
90 GLuint nr
= prim
->count
;
91 GLuint sz
= tnl
->save
.vertex_size
;
92 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 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
110 for (i
= 0 ; i
< ovf
; i
++)
111 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
115 for (i
= 0 ; i
< ovf
; i
++)
116 memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
122 memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
126 case GL_TRIANGLE_FAN
:
131 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
134 memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
135 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 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 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 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 tnl
->save
.initial_counter
= tnl
->save
.counter
;
446 /* Recalculate all the attrptr[] values:
448 for (i
= 0, tmp
= tnl
->save
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
449 if (tnl
->save
.attrsz
[i
]) {
450 tnl
->save
.attrptr
[i
] = tmp
;
451 tmp
+= tnl
->save
.attrsz
[i
];
454 tnl
->save
.attrptr
[i
] = 0; /* will not be dereferenced. */
457 /* Copy from current to repopulate the vertex with correct values.
459 _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) {
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
]) {
499 ASSIGN_4V( dest
, 0, 0, 0, 1 );
500 COPY_SZ_4V( dest
, oldsz
, data
);
505 GLint sz
= tnl
->save
.attrsz
[j
];
506 COPY_SZ_4V( dest
, sz
, data
);
514 tnl
->save
.vbptr
= dest
;
515 tnl
->save
.counter
-= tnl
->save
.copied
.nr
;
522 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
523 * entrypoint is called for the first time.
525 static void do_choose( GLuint attr
, GLuint sz
,
526 void (*attr_func
)( const GLfloat
*),
527 void (*choose1
)( const GLfloat
*),
528 void (*choose2
)( const GLfloat
*),
529 void (*choose3
)( const GLfloat
*),
530 void (*choose4
)( const GLfloat
*),
533 GET_CURRENT_CONTEXT( ctx
);
534 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
535 static GLfloat id
[4] = { 0, 0, 0, 1 };
538 if (tnl
->save
.attrsz
[attr
] < sz
) {
539 /* New size is larger. Need to flush existing vertices and get
540 * an enlarged vertex format.
542 _save_upgrade_vertex( ctx
, attr
, sz
);
545 /* New size is equal or smaller - just need to fill in some
548 for (i
= sz
; i
<= tnl
->save
.attrsz
[attr
] ; i
++)
549 tnl
->save
.attrptr
[attr
][i
-1] = id
[i
-1];
552 /* Reset any active pointers for this attribute
554 tnl
->save
.tabfv
[attr
][0] = choose1
;
555 tnl
->save
.tabfv
[attr
][1] = choose2
;
556 tnl
->save
.tabfv
[attr
][2] = choose3
;
557 tnl
->save
.tabfv
[attr
][3] = choose4
;
559 /* Update the secondary dispatch table with the new function
561 tnl
->save
.tabfv
[attr
][sz
-1] = attr_func
;
568 /* Only one size for each attribute may be active at once. Eg. if
569 * Color3f is installed/active, then Color4f may not be, even if the
570 * vertex actually contains 4 color coordinates. This is because the
571 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
572 * of the chooser function when switching between Color4f and Color3f.
574 #define ATTRFV( ATTR, N ) \
575 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
577 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
579 GET_CURRENT_CONTEXT( ctx ); \
580 TNLcontext *tnl = TNL_CONTEXT(ctx); \
585 if (N>0) tnl->save.vbptr[0] = v[0]; \
586 if (N>1) tnl->save.vbptr[1] = v[1]; \
587 if (N>2) tnl->save.vbptr[2] = v[2]; \
588 if (N>3) tnl->save.vbptr[3] = v[3]; \
590 for (i = N; i < tnl->save.vertex_size; i++) \
591 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
593 tnl->save.vbptr += tnl->save.vertex_size; \
595 if (--tnl->save.counter == 0) \
596 _save_wrap_filled_vertex( ctx ); \
599 GLfloat *dest = tnl->save.attrptr[ATTR]; \
600 if (N>0) dest[0] = v[0]; \
601 if (N>1) dest[1] = v[1]; \
602 if (N>2) dest[2] = v[2]; \
603 if (N>3) dest[3] = v[3]; \
607 #define CHOOSE( ATTR, N ) \
608 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
611 save_attrib_##ATTR##_##N, \
612 save_choose_##ATTR##_1, \
613 save_choose_##ATTR##_2, \
614 save_choose_##ATTR##_3, \
615 save_choose_##ATTR##_4, \
620 static void save_init_##ATTR( TNLcontext *tnl ) \
622 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
623 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
624 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
625 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
628 #define ATTRS( ATTRIB ) \
629 ATTRFV( ATTRIB, 1 ) \
630 ATTRFV( ATTRIB, 2 ) \
631 ATTRFV( ATTRIB, 3 ) \
632 ATTRFV( ATTRIB, 4 ) \
633 CHOOSE( ATTRIB, 1 ) \
634 CHOOSE( ATTRIB, 2 ) \
635 CHOOSE( ATTRIB, 3 ) \
636 CHOOSE( ATTRIB, 4 ) \
640 /* Generate a lot of functions. These are the actual worker
641 * functions, which are equivalent to those generated via codegen
662 static void _save_reset_vertex( GLcontext
*ctx
)
664 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
684 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
685 tnl
->save
.attrsz
[i
] = 0;
687 tnl
->save
.vertex_size
= 0;
688 tnl
->save
.have_materials
= 0;
690 _save_reset_counters( ctx
);
695 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
696 * of glMultTexCoord and glProgramParamterNV by routing all these
697 * through a second level dispatch table.
699 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
701 GET_CURRENT_CONTEXT( ctx ); \
702 TNLcontext *tnl = TNL_CONTEXT(ctx); \
703 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
706 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
707 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
708 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
709 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
711 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
713 #define DISPATCH_ATTR2F( ATTR, S,T ) \
716 v[0] = S; v[1] = T; \
717 DISPATCH_ATTR2FV( ATTR, v ); \
719 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
722 v[0] = S; v[1] = T; v[2] = R; \
723 DISPATCH_ATTR3FV( ATTR, v ); \
725 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
728 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
729 DISPATCH_ATTR4FV( ATTR, v ); \
733 static void enum_error( void )
735 GET_CURRENT_CONTEXT( ctx
);
736 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
739 static void GLAPIENTRY
_save_Vertex2f( GLfloat x
, GLfloat y
)
741 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
744 static void GLAPIENTRY
_save_Vertex2fv( const GLfloat
*v
)
746 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
749 static void GLAPIENTRY
_save_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
751 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
754 static void GLAPIENTRY
_save_Vertex3fv( const GLfloat
*v
)
756 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
759 static void GLAPIENTRY
_save_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
761 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
764 static void GLAPIENTRY
_save_Vertex4fv( const GLfloat
*v
)
766 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
769 static void GLAPIENTRY
_save_TexCoord1f( GLfloat x
)
771 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
774 static void GLAPIENTRY
_save_TexCoord1fv( const GLfloat
*v
)
776 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
779 static void GLAPIENTRY
_save_TexCoord2f( GLfloat x
, GLfloat y
)
781 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
784 static void GLAPIENTRY
_save_TexCoord2fv( const GLfloat
*v
)
786 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
789 static void GLAPIENTRY
_save_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
791 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
794 static void GLAPIENTRY
_save_TexCoord3fv( const GLfloat
*v
)
796 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
799 static void GLAPIENTRY
_save_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
801 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
804 static void GLAPIENTRY
_save_TexCoord4fv( const GLfloat
*v
)
806 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
809 static void GLAPIENTRY
_save_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
811 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
814 static void GLAPIENTRY
_save_Normal3fv( const GLfloat
*v
)
816 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
819 static void GLAPIENTRY
_save_FogCoordfEXT( GLfloat x
)
821 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
824 static void GLAPIENTRY
_save_FogCoordfvEXT( const GLfloat
*v
)
826 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
829 static void GLAPIENTRY
_save_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
831 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
834 static void GLAPIENTRY
_save_Color3fv( const GLfloat
*v
)
836 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
839 static void GLAPIENTRY
_save_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
841 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
844 static void GLAPIENTRY
_save_Color4fv( const GLfloat
*v
)
846 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
849 static void GLAPIENTRY
_save_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
851 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
854 static void GLAPIENTRY
_save_SecondaryColor3fvEXT( const GLfloat
*v
)
856 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
859 static void GLAPIENTRY
_save_MultiTexCoord1f( GLenum target
, GLfloat x
)
861 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
862 DISPATCH_ATTR1F( attr
, x
);
865 static void GLAPIENTRY
_save_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
867 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
868 DISPATCH_ATTR1FV( attr
, v
);
871 static void GLAPIENTRY
_save_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
873 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
874 DISPATCH_ATTR2F( attr
, x
, y
);
877 static void GLAPIENTRY
_save_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
879 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
880 DISPATCH_ATTR2FV( attr
, v
);
883 static void GLAPIENTRY
_save_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
886 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
887 DISPATCH_ATTR3F( attr
, x
, y
, z
);
890 static void GLAPIENTRY
_save_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
892 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
893 DISPATCH_ATTR3FV( attr
, v
);
896 static void GLAPIENTRY
_save_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
897 GLfloat z
, GLfloat w
)
899 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
900 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
903 static void GLAPIENTRY
_save_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
905 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
906 DISPATCH_ATTR4FV( attr
, v
);
909 static void GLAPIENTRY
_save_VertexAttrib1fNV( GLuint index
, GLfloat x
)
911 if (index
< VERT_ATTRIB_MAX
)
912 DISPATCH_ATTR1F( index
, x
);
917 static void GLAPIENTRY
_save_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
919 if (index
< VERT_ATTRIB_MAX
)
920 DISPATCH_ATTR1FV( index
, v
);
925 static void GLAPIENTRY
_save_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
927 if (index
< VERT_ATTRIB_MAX
)
928 DISPATCH_ATTR2F( index
, x
, y
);
933 static void GLAPIENTRY
_save_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
935 if (index
< VERT_ATTRIB_MAX
)
936 DISPATCH_ATTR2FV( index
, v
);
941 static void GLAPIENTRY
_save_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
944 if (index
< VERT_ATTRIB_MAX
)
945 DISPATCH_ATTR3F( index
, x
, y
, z
);
950 static void GLAPIENTRY
_save_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
952 if (index
< VERT_ATTRIB_MAX
)
953 DISPATCH_ATTR3FV( index
, v
);
958 static void GLAPIENTRY
_save_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
959 GLfloat z
, GLfloat w
)
961 if (index
< VERT_ATTRIB_MAX
)
962 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
967 static void GLAPIENTRY
_save_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
969 if (index
< VERT_ATTRIB_MAX
)
970 DISPATCH_ATTR4FV( index
, v
);
978 * These are treated as per-vertex attributes, at indices above where
979 * the NV_vertex_program leaves off. There are a lot of good things
980 * about treating materials this way.
982 * However: I don't want to double the number of generated functions
983 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
984 * ATTRF into this function, and dispense with codegen and
985 * second-level dispatch.
987 * There is no aliasing of material attributes with other entrypoints.
989 #define MAT_ATTR( A, N, params ) \
991 if (tnl->save.attrsz[A] < N) { \
992 _save_upgrade_vertex( ctx, A, N ); \
993 tnl->save.have_materials = GL_TRUE; \
997 GLfloat *dest = tnl->save.attrptr[A]; \
998 if (N>0) dest[0] = params[0]; \
999 if (N>1) dest[1] = params[1]; \
1000 if (N>2) dest[2] = params[2]; \
1001 if (N>3) dest[3] = params[3]; \
1006 #define MAT( ATTR, N, face, params ) \
1008 if (face != GL_BACK) \
1009 MAT_ATTR( ATTR, N, params ); /* front */ \
1010 if (face != GL_FRONT) \
1011 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1015 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1016 * later on - in the meantime just store everything.
1018 static void GLAPIENTRY
_save_Materialfv( GLenum face
, GLenum pname
,
1019 const GLfloat
*params
)
1021 GET_CURRENT_CONTEXT( ctx
);
1022 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1026 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
1029 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1032 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1035 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
1038 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
1040 case GL_COLOR_INDEXES
:
1041 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
1043 case GL_AMBIENT_AND_DIFFUSE
:
1044 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1045 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1048 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
1054 #define IDX_ATTR( A, IDX ) \
1056 GET_CURRENT_CONTEXT( ctx ); \
1057 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1059 if (tnl->save.attrsz[A] < 1) { \
1060 _save_upgrade_vertex( ctx, A, 1 ); \
1064 GLfloat *dest = tnl->save.attrptr[A]; \
1070 static void GLAPIENTRY
_save_EdgeFlag( GLboolean b
)
1072 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
1075 static void GLAPIENTRY
_save_EdgeFlagv( const GLboolean
*v
)
1077 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)(v
[0]) );
1080 static void GLAPIENTRY
_save_Indexf( GLfloat f
)
1082 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
1085 static void GLAPIENTRY
_save_Indexfv( const GLfloat
*f
)
1087 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
[0] );
1093 /* Cope with EvalCoord/CallList called within a begin/end object:
1094 * -- Flush current buffer
1095 * -- Fallback to opcodes for the rest of the begin/end object.
1097 #define FALLBACK(ctx) \
1099 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1101 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1103 if (tnl->save.initial_counter != tnl->save.counter || \
1104 tnl->save.prim_count) \
1105 _save_compile_vertex_list( ctx ); \
1107 _save_copy_to_current( ctx ); \
1108 _save_reset_vertex( ctx ); \
1109 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1110 ctx->Driver.SaveNeedFlush = 0; \
1113 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
1115 GET_CURRENT_CONTEXT(ctx
);
1117 ctx
->Save
->EvalCoord1f( u
);
1120 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
1122 GET_CURRENT_CONTEXT(ctx
);
1124 ctx
->Save
->EvalCoord1fv( v
);
1127 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
1129 GET_CURRENT_CONTEXT(ctx
);
1131 ctx
->Save
->EvalCoord2f( u
, v
);
1134 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
1136 GET_CURRENT_CONTEXT(ctx
);
1138 ctx
->Save
->EvalCoord2fv( v
);
1141 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
1143 GET_CURRENT_CONTEXT(ctx
);
1145 ctx
->Save
->EvalPoint1( i
);
1148 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
1150 GET_CURRENT_CONTEXT(ctx
);
1152 ctx
->Save
->EvalPoint2( i
, j
);
1155 static void GLAPIENTRY
_save_CallList( GLuint l
)
1157 GET_CURRENT_CONTEXT(ctx
);
1159 ctx
->Save
->CallList( l
);
1162 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
1164 GET_CURRENT_CONTEXT(ctx
);
1166 ctx
->Save
->CallLists( n
, type
, v
);
1172 /* This begin is hooked into ... Updating of
1173 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1175 static GLboolean
_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
1177 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1180 GLuint i
= tnl
->save
.prim_count
++;
1182 assert(i
< tnl
->save
.prim_max
);
1183 tnl
->save
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1184 tnl
->save
.prim
[i
].start
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
1185 tnl
->save
.prim
[i
].count
= 0;
1187 _mesa_install_save_vtxfmt( ctx
, &tnl
->save_vtxfmt
);
1188 ctx
->Driver
.SaveNeedFlush
= 1;
1197 static void GLAPIENTRY
_save_End( void )
1199 GET_CURRENT_CONTEXT( ctx
);
1200 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1201 GLint i
= tnl
->save
.prim_count
- 1;
1203 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1204 tnl
->save
.prim
[i
].mode
|= PRIM_END
;
1205 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
1206 tnl
->save
.prim
[i
].start
);
1208 if (i
== (GLint
) tnl
->save
.prim_max
- 1) {
1209 _save_compile_vertex_list( ctx
);
1210 assert(tnl
->save
.copied
.nr
== 0);
1213 /* Swap out this vertex format while outside begin/end. Any color,
1214 * etc. received between here and the next begin will be compiled
1217 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1221 /* These are all errors as this vtxfmt is only installed inside
1224 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1225 const GLvoid
*indices
)
1227 GET_CURRENT_CONTEXT(ctx
);
1228 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
1232 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
1233 GLuint start
, GLuint end
,
1234 GLsizei count
, GLenum type
,
1235 const GLvoid
*indices
)
1237 GET_CURRENT_CONTEXT(ctx
);
1238 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
1241 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1243 GET_CURRENT_CONTEXT(ctx
);
1244 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
1247 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1249 GET_CURRENT_CONTEXT(ctx
);
1250 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
1253 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
1255 GET_CURRENT_CONTEXT(ctx
);
1256 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
1259 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
1260 GLint j1
, GLint j2
)
1262 GET_CURRENT_CONTEXT(ctx
);
1263 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
1266 static void GLAPIENTRY
_save_Begin( GLenum mode
)
1268 GET_CURRENT_CONTEXT( ctx
);
1269 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
1273 /* Unlike the functions above, these are to be hooked into the vtxfmt
1274 * maintained in ctx->ListState, active when the list is known or
1275 * suspected to be outside any begin/end primitive.
1277 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1279 GET_CURRENT_CONTEXT(ctx
);
1280 _save_NotifyBegin( ctx
, GL_QUADS
| PRIM_WEAK
);
1281 glVertex2f( x1
, y1
);
1282 glVertex2f( x2
, y1
);
1283 glVertex2f( x2
, y2
);
1284 glVertex2f( x1
, y2
);
1289 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1291 GET_CURRENT_CONTEXT(ctx
);
1294 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
1297 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1298 for (i
= start
; i
< count
; i
++)
1299 glArrayElement( i
);
1304 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1305 const GLvoid
*indices
)
1307 GET_CURRENT_CONTEXT(ctx
);
1310 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
1313 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1316 case GL_UNSIGNED_BYTE
:
1317 for (i
= 0 ; i
< count
; i
++)
1318 glArrayElement( ((GLubyte
*)indices
)[i
] );
1320 case GL_UNSIGNED_SHORT
:
1321 for (i
= 0 ; i
< count
; i
++)
1322 glArrayElement( ((GLushort
*)indices
)[i
] );
1324 case GL_UNSIGNED_INT
:
1325 for (i
= 0 ; i
< count
; i
++)
1326 glArrayElement( ((GLuint
*)indices
)[i
] );
1329 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
1336 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
1337 GLuint start
, GLuint end
,
1338 GLsizei count
, GLenum type
,
1339 const GLvoid
*indices
)
1341 GET_CURRENT_CONTEXT(ctx
);
1342 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1344 count
, type
, indices
))
1345 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1352 static void _save_vtxfmt_init( GLcontext
*ctx
)
1354 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1355 GLvertexformat
*vfmt
= &tnl
->save_vtxfmt
;
1357 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1358 vfmt
->Begin
= _save_Begin
;
1359 vfmt
->Color3f
= _save_Color3f
;
1360 vfmt
->Color3fv
= _save_Color3fv
;
1361 vfmt
->Color4f
= _save_Color4f
;
1362 vfmt
->Color4fv
= _save_Color4fv
;
1363 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1364 vfmt
->EdgeFlagv
= _save_EdgeFlagv
;
1365 vfmt
->End
= _save_End
;
1366 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1367 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1368 vfmt
->Indexf
= _save_Indexf
;
1369 vfmt
->Indexfv
= _save_Indexfv
;
1370 vfmt
->Materialfv
= _save_Materialfv
;
1371 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1372 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1373 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1374 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1375 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1376 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1377 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1378 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1379 vfmt
->Normal3f
= _save_Normal3f
;
1380 vfmt
->Normal3fv
= _save_Normal3fv
;
1381 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1382 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1383 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1384 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1385 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1386 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1387 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1388 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1389 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1390 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1391 vfmt
->Vertex2f
= _save_Vertex2f
;
1392 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1393 vfmt
->Vertex3f
= _save_Vertex3f
;
1394 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1395 vfmt
->Vertex4f
= _save_Vertex4f
;
1396 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1397 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1398 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1399 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1400 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1401 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1402 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1403 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1404 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1406 /* This will all require us to fallback to saving the list as opcodes:
1408 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1409 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1410 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1411 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1412 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1413 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1414 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1415 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1417 /* These are all errors as we at least know we are in some sort of
1420 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1421 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1422 vfmt
->Begin
= _save_Begin
;
1423 vfmt
->Rectf
= _save_Rectf
;
1424 vfmt
->DrawArrays
= _save_DrawArrays
;
1425 vfmt
->DrawElements
= _save_DrawElements
;
1426 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1431 void _tnl_SaveFlushVertices( GLcontext
*ctx
)
1433 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1435 /* Noop when we are actually active:
1437 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1438 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1441 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
||
1442 tnl
->save
.prim_count
)
1443 _save_compile_vertex_list( ctx
);
1445 _save_copy_to_current( ctx
);
1446 _save_reset_vertex( ctx
);
1447 ctx
->Driver
.SaveNeedFlush
= 0;
1450 void _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1452 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1454 if (!tnl
->save
.prim_store
)
1455 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
1457 if (!tnl
->save
.vertex_store
) {
1458 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
1459 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
1462 _save_reset_vertex( ctx
);
1463 ctx
->Driver
.SaveNeedFlush
= 0;
1466 void _tnl_EndList( GLcontext
*ctx
)
1468 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1469 assert(tnl
->save
.vertex_size
== 0);
1472 void _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
1476 void _tnl_EndCallList( GLcontext
*ctx
)
1481 static void _tnl_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1483 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1485 if ( --node
->vertex_store
->refcount
== 0 )
1486 FREE( node
->vertex_store
);
1488 if ( --node
->prim_store
->refcount
== 0 )
1489 FREE( node
->prim_store
);
1491 if ( node
->normal_lengths
)
1492 FREE( node
->normal_lengths
);
1496 static void _tnl_print_vertex_list( GLcontext
*ctx
, void *data
)
1498 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1501 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1506 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1507 struct tnl_prim
*prim
= &node
->prim
[i
];
1508 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1510 _mesa_lookup_enum_by_nr(prim
->mode
& PRIM_MODE_MASK
),
1512 prim
->start
+ prim
->count
,
1513 (prim
->mode
& PRIM_BEGIN
) ? "BEGIN" : "(wrap)",
1514 (prim
->mode
& PRIM_END
) ? "END" : "(wrap)");
1519 static void _save_current_init( GLcontext
*ctx
)
1521 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1524 for (i
= 0; i
< _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1525 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[i
];
1526 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentAttrib
[i
];
1529 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
< _TNL_ATTRIB_INDEX
; i
++) {
1530 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[i
];
1531 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentMaterial
[i
];
1534 tnl
->save
.currentsz
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.ActiveIndex
;
1535 tnl
->save
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.CurrentIndex
;
1537 /* Current edgeflag is handled individually */
1541 * Initialize the display list compiler
1543 void _tnl_save_init( GLcontext
*ctx
)
1545 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1546 struct tnl_vertex_arrays
*tmp
= &tnl
->save_inputs
;
1550 for (i
= 0; i
< _TNL_ATTRIB_MAX
; i
++)
1551 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1553 tnl
->save
.opcode_vertex_list
=
1554 _mesa_alloc_opcode( ctx
,
1555 sizeof(struct tnl_vertex_list
),
1556 _tnl_playback_vertex_list
,
1557 _tnl_destroy_vertex_list
,
1558 _tnl_print_vertex_list
);
1560 ctx
->Driver
.NotifySaveBegin
= _save_NotifyBegin
;
1562 _save_vtxfmt_init( ctx
);
1563 _save_current_init( ctx
);
1565 /* Hook our array functions into the outside-begin-end vtxfmt in
1568 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1569 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1570 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1571 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1572 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1577 * Deallocate the immediate-mode buffer for the given context, if
1578 * its reference count goes to zero.
1580 void _tnl_save_destroy( GLcontext
*ctx
)