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
);
188 static struct tnl_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
190 struct tnl_primitive_store
*store
= MALLOC_STRUCT(tnl_primitive_store
);
197 static void _save_reset_counters( GLcontext
*ctx
)
199 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
201 tnl
->save
.prim
= tnl
->save
.prim_store
->buffer
+ tnl
->save
.prim_store
->used
;
202 tnl
->save
.buffer
= (tnl
->save
.vertex_store
->buffer
+
203 tnl
->save
.vertex_store
->used
);
205 if (tnl
->save
.vertex_size
)
206 tnl
->save
.initial_counter
= ((SAVE_BUFFER_SIZE
-
207 tnl
->save
.vertex_store
->used
) /
208 tnl
->save
.vertex_size
);
210 tnl
->save
.initial_counter
= 0;
212 if (tnl
->save
.initial_counter
> ctx
->Const
.MaxArrayLockSize
)
213 tnl
->save
.initial_counter
= ctx
->Const
.MaxArrayLockSize
;
215 tnl
->save
.counter
= tnl
->save
.initial_counter
;
216 tnl
->save
.prim_count
= 0;
217 tnl
->save
.prim_max
= SAVE_PRIM_SIZE
- tnl
->save
.prim_store
->used
;
218 tnl
->save
.copied
.nr
= 0;
219 tnl
->save
.dangling_attr_ref
= 0;
223 /* Insert the active immediate struct onto the display list currently
226 static void _save_compile_vertex_list( GLcontext
*ctx
)
228 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
229 struct tnl_vertex_list
*node
;
231 /* Allocate space for this structure in the display list currently
234 node
= (struct tnl_vertex_list
*)
235 _mesa_alloc_instruction(ctx
, tnl
->save
.opcode_vertex_list
, sizeof(*node
));
240 /* Duplicate our template, increment refcounts to the storage structs:
242 _mesa_memcpy(node
->attrsz
, tnl
->save
.attrsz
, sizeof(node
->attrsz
));
243 node
->vertex_size
= tnl
->save
.vertex_size
;
244 node
->buffer
= tnl
->save
.buffer
;
245 node
->wrap_count
= tnl
->save
.copied
.nr
;
246 node
->count
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
247 node
->prim
= tnl
->save
.prim
;
248 node
->prim_count
= tnl
->save
.prim_count
;
249 node
->vertex_store
= tnl
->save
.vertex_store
;
250 node
->prim_store
= tnl
->save
.prim_store
;
251 node
->dangling_attr_ref
= tnl
->save
.dangling_attr_ref
;
252 node
->normal_lengths
= 0;
254 node
->vertex_store
->refcount
++;
255 node
->prim_store
->refcount
++;
257 assert(node
->attrsz
[_TNL_ATTRIB_POS
] != 0 ||
260 /* Maybe calculate normal lengths:
262 if (tnl
->CalcDListNormalLengths
&&
263 node
->attrsz
[_TNL_ATTRIB_NORMAL
] == 3 &&
264 !node
->dangling_attr_ref
)
265 build_normal_lengths( node
);
267 tnl
->save
.vertex_store
->used
+= tnl
->save
.vertex_size
* node
->count
;
268 tnl
->save
.prim_store
->used
+= node
->prim_count
;
270 /* Decide whether the storage structs are full, or can be used for
271 * the next vertex lists as well.
273 if (tnl
->save
.vertex_store
->used
>
274 SAVE_BUFFER_SIZE
- 16 * (tnl
->save
.vertex_size
+ 4)) {
276 tnl
->save
.vertex_store
->refcount
--;
277 assert(tnl
->save
.vertex_store
->refcount
!= 0);
278 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
279 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
282 if (tnl
->save
.prim_store
->used
> SAVE_PRIM_SIZE
- 6) {
283 tnl
->save
.prim_store
->refcount
--;
284 assert(tnl
->save
.prim_store
->refcount
!= 0);
285 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
288 /* Reset our structures for the next run of vertices:
290 _save_reset_counters( ctx
);
292 /* Copy duplicated vertices
294 tnl
->save
.copied
.nr
= _save_copy_vertices( ctx
, node
);
297 /* Deal with GL_COMPILE_AND_EXECUTE:
299 if (ctx
->ExecuteFlag
) {
300 _tnl_playback_vertex_list( ctx
, (void *) node
);
305 /* TODO -- If no new vertices have been stored, don't bother saving
308 static void _save_wrap_buffers( GLcontext
*ctx
)
310 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
311 GLint i
= tnl
->save
.prim_count
- 1;
314 assert(i
< (GLint
) tnl
->save
.prim_max
);
317 /* Close off in-progress primitive.
319 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
320 tnl
->save
.prim
[i
].start
);
321 mode
= tnl
->save
.prim
[i
].mode
& ~(PRIM_BEGIN
|PRIM_END
);
323 /* store the copied vertices, and allocate a new list.
325 _save_compile_vertex_list( ctx
);
327 /* Restart interrupted primitive
329 tnl
->save
.prim
[0].mode
= mode
;
330 tnl
->save
.prim
[0].start
= 0;
331 tnl
->save
.prim
[0].count
= 0;
332 tnl
->save
.prim_count
= 1;
337 /* Called only when buffers are wrapped as the result of filling the
338 * vertex_store struct.
340 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
342 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
343 GLfloat
*data
= tnl
->save
.copied
.buffer
;
346 /* Emit a glEnd to close off the last vertex list.
348 _save_wrap_buffers( ctx
);
350 /* Copy stored stored vertices to start of new list.
352 assert(tnl
->save
.counter
> tnl
->save
.copied
.nr
);
354 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
355 _mesa_memcpy( tnl
->save
.vbptr
, data
, tnl
->save
.vertex_size
* sizeof(GLfloat
));
356 data
+= tnl
->save
.vertex_size
;
357 tnl
->save
.vbptr
+= tnl
->save
.vertex_size
;
363 static void _save_copy_to_current( GLcontext
*ctx
)
365 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
368 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
369 if (tnl
->save
.attrsz
[i
]) {
370 tnl
->save
.currentsz
[i
][0] = tnl
->save
.attrsz
[i
];
371 ASSIGN_4V(tnl
->save
.current
[i
], 0, 0, 0, 1);
372 COPY_SZ_4V(tnl
->save
.current
[i
],
374 tnl
->save
.attrptr
[i
]);
378 /* Edgeflag requires special treatment:
380 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
381 ctx
->ListState
.ActiveEdgeFlag
= 1;
382 ctx
->ListState
.CurrentEdgeFlag
=
383 (tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
388 static void _save_copy_from_current( GLcontext
*ctx
)
390 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
393 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
394 switch (tnl
->save
.attrsz
[i
]) {
395 case 4: tnl
->save
.attrptr
[i
][3] = tnl
->save
.current
[i
][3];
396 case 3: tnl
->save
.attrptr
[i
][2] = tnl
->save
.current
[i
][2];
397 case 2: tnl
->save
.attrptr
[i
][1] = tnl
->save
.current
[i
][1];
398 case 1: tnl
->save
.attrptr
[i
][0] = tnl
->save
.current
[i
][0];
402 /* Edgeflag requires special treatment:
404 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
405 tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
406 (GLfloat
)ctx
->ListState
.CurrentEdgeFlag
;
412 /* Flush existing data, set new attrib size, replay copied vertices.
414 static void _save_upgrade_vertex( GLcontext
*ctx
,
418 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
423 /* Store the current run of vertices, and emit a GL_END. Emit a
424 * BEGIN in the new buffer.
426 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
)
427 _save_wrap_buffers( ctx
);
429 assert( tnl
->save
.copied
.nr
== 0 );
431 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
432 * when the attribute already exists in the vertex and is having
433 * its size increased.
435 _save_copy_to_current( ctx
);
439 oldsz
= tnl
->save
.attrsz
[attr
];
440 tnl
->save
.attrsz
[attr
] = newsz
;
442 tnl
->save
.vertex_size
+= newsz
- oldsz
;
443 tnl
->save
.counter
= ((SAVE_BUFFER_SIZE
- tnl
->save
.vertex_store
->used
) /
444 tnl
->save
.vertex_size
);
445 if (tnl
->save
.counter
> ctx
->Const
.MaxArrayLockSize
)
446 tnl
->save
.counter
= ctx
->Const
.MaxArrayLockSize
;
447 tnl
->save
.initial_counter
= tnl
->save
.counter
;
449 /* Recalculate all the attrptr[] values:
451 for (i
= 0, tmp
= tnl
->save
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
452 if (tnl
->save
.attrsz
[i
]) {
453 tnl
->save
.attrptr
[i
] = tmp
;
454 tmp
+= tnl
->save
.attrsz
[i
];
457 tnl
->save
.attrptr
[i
] = 0; /* will not be dereferenced. */
460 /* Copy from current to repopulate the vertex with correct values.
462 _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] == 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
]) {
502 ASSIGN_4V( dest
, 0, 0, 0, 1 );
503 COPY_SZ_4V( dest
, oldsz
, data
);
508 COPY_SZ_4V( dest
, newsz
, tnl
->save
.current
[attr
] );
513 GLint sz
= tnl
->save
.attrsz
[j
];
514 COPY_SZ_4V( dest
, sz
, data
);
522 tnl
->save
.vbptr
= dest
;
523 tnl
->save
.counter
-= tnl
->save
.copied
.nr
;
530 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
531 * entrypoint is called for the first time.
533 static void do_choose( GLuint attr
, GLuint sz
,
534 void (*attr_func
)( const GLfloat
*),
535 void (*choose1
)( const GLfloat
*),
536 void (*choose2
)( const GLfloat
*),
537 void (*choose3
)( const GLfloat
*),
538 void (*choose4
)( const GLfloat
*),
541 GET_CURRENT_CONTEXT( ctx
);
542 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
543 static GLfloat id
[4] = { 0, 0, 0, 1 };
546 if (tnl
->save
.attrsz
[attr
] < sz
) {
547 /* New size is larger. Need to flush existing vertices and get
548 * an enlarged vertex format.
550 _save_upgrade_vertex( ctx
, attr
, sz
);
553 /* New size is equal or smaller - just need to fill in some
556 for (i
= sz
; i
<= tnl
->save
.attrsz
[attr
] ; i
++)
557 tnl
->save
.attrptr
[attr
][i
-1] = id
[i
-1];
560 /* Reset any active pointers for this attribute
562 tnl
->save
.tabfv
[attr
][0] = choose1
;
563 tnl
->save
.tabfv
[attr
][1] = choose2
;
564 tnl
->save
.tabfv
[attr
][2] = choose3
;
565 tnl
->save
.tabfv
[attr
][3] = choose4
;
567 /* Update the secondary dispatch table with the new function
569 tnl
->save
.tabfv
[attr
][sz
-1] = attr_func
;
576 /* Only one size for each attribute may be active at once. Eg. if
577 * Color3f is installed/active, then Color4f may not be, even if the
578 * vertex actually contains 4 color coordinates. This is because the
579 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
580 * of the chooser function when switching between Color4f and Color3f.
582 #define ATTRFV( ATTR, N ) \
583 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
585 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
587 GET_CURRENT_CONTEXT( ctx ); \
588 TNLcontext *tnl = TNL_CONTEXT(ctx); \
593 if (N>0) tnl->save.vbptr[0] = v[0]; \
594 if (N>1) tnl->save.vbptr[1] = v[1]; \
595 if (N>2) tnl->save.vbptr[2] = v[2]; \
596 if (N>3) tnl->save.vbptr[3] = v[3]; \
598 for (i = N; i < tnl->save.vertex_size; i++) \
599 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
601 tnl->save.vbptr += tnl->save.vertex_size; \
603 if (--tnl->save.counter == 0) \
604 _save_wrap_filled_vertex( ctx ); \
607 GLfloat *dest = tnl->save.attrptr[ATTR]; \
608 if (N>0) dest[0] = v[0]; \
609 if (N>1) dest[1] = v[1]; \
610 if (N>2) dest[2] = v[2]; \
611 if (N>3) dest[3] = v[3]; \
615 #define CHOOSE( ATTR, N ) \
616 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
619 save_attrib_##ATTR##_##N, \
620 save_choose_##ATTR##_1, \
621 save_choose_##ATTR##_2, \
622 save_choose_##ATTR##_3, \
623 save_choose_##ATTR##_4, \
628 static void save_init_##ATTR( TNLcontext *tnl ) \
630 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
631 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
632 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
633 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
636 #define ATTRS( ATTRIB ) \
637 ATTRFV( ATTRIB, 1 ) \
638 ATTRFV( ATTRIB, 2 ) \
639 ATTRFV( ATTRIB, 3 ) \
640 ATTRFV( ATTRIB, 4 ) \
641 CHOOSE( ATTRIB, 1 ) \
642 CHOOSE( ATTRIB, 2 ) \
643 CHOOSE( ATTRIB, 3 ) \
644 CHOOSE( ATTRIB, 4 ) \
648 /* Generate a lot of functions. These are the actual worker
649 * functions, which are equivalent to those generated via codegen
670 static void _save_reset_vertex( GLcontext
*ctx
)
672 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
692 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
693 tnl
->save
.attrsz
[i
] = 0;
695 tnl
->save
.vertex_size
= 0;
696 tnl
->save
.have_materials
= 0;
698 _save_reset_counters( ctx
);
703 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
704 * of glMultTexCoord and glProgramParamterNV by routing all these
705 * through a second level dispatch table.
707 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
709 GET_CURRENT_CONTEXT( ctx ); \
710 TNLcontext *tnl = TNL_CONTEXT(ctx); \
711 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
714 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
715 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
716 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
717 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
719 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
721 #if defined(USE_X86_ASM) && 0 /* will break register calling convention */
724 #define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
725 #define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
726 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
730 #define DISPATCH_ATTR2F( ATTR, S,T ) \
733 v[0] = S; v[1] = T; \
734 DISPATCH_ATTR2FV( ATTR, v ); \
736 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
739 v[0] = S; v[1] = T; v[2] = R; \
740 DISPATCH_ATTR3FV( ATTR, v ); \
742 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
745 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
746 DISPATCH_ATTR4FV( ATTR, v ); \
751 static void enum_error( void )
753 GET_CURRENT_CONTEXT( ctx
);
754 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
757 static void GLAPIENTRY
_save_Vertex2f( GLfloat x
, GLfloat y
)
759 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
762 static void GLAPIENTRY
_save_Vertex2fv( const GLfloat
*v
)
764 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
767 static void GLAPIENTRY
_save_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
769 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
772 static void GLAPIENTRY
_save_Vertex3fv( const GLfloat
*v
)
774 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
777 static void GLAPIENTRY
_save_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
779 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
782 static void GLAPIENTRY
_save_Vertex4fv( const GLfloat
*v
)
784 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
787 static void GLAPIENTRY
_save_TexCoord1f( GLfloat x
)
789 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
792 static void GLAPIENTRY
_save_TexCoord1fv( const GLfloat
*v
)
794 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
797 static void GLAPIENTRY
_save_TexCoord2f( GLfloat x
, GLfloat y
)
799 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
802 static void GLAPIENTRY
_save_TexCoord2fv( const GLfloat
*v
)
804 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
807 static void GLAPIENTRY
_save_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
809 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
812 static void GLAPIENTRY
_save_TexCoord3fv( const GLfloat
*v
)
814 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
817 static void GLAPIENTRY
_save_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
819 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
822 static void GLAPIENTRY
_save_TexCoord4fv( const GLfloat
*v
)
824 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
827 static void GLAPIENTRY
_save_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
829 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
832 static void GLAPIENTRY
_save_Normal3fv( const GLfloat
*v
)
834 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
837 static void GLAPIENTRY
_save_FogCoordfEXT( GLfloat x
)
839 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
842 static void GLAPIENTRY
_save_FogCoordfvEXT( const GLfloat
*v
)
844 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
847 static void GLAPIENTRY
_save_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
849 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
852 static void GLAPIENTRY
_save_Color3fv( const GLfloat
*v
)
854 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
857 static void GLAPIENTRY
_save_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
859 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
862 static void GLAPIENTRY
_save_Color4fv( const GLfloat
*v
)
864 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
867 static void GLAPIENTRY
_save_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
869 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
872 static void GLAPIENTRY
_save_SecondaryColor3fvEXT( const GLfloat
*v
)
874 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
877 static void GLAPIENTRY
_save_MultiTexCoord1f( GLenum target
, GLfloat x
)
879 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
880 DISPATCH_ATTR1F( attr
, x
);
883 static void GLAPIENTRY
_save_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
885 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
886 DISPATCH_ATTR1FV( attr
, v
);
889 static void GLAPIENTRY
_save_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
891 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
892 DISPATCH_ATTR2F( attr
, x
, y
);
895 static void GLAPIENTRY
_save_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
897 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
898 DISPATCH_ATTR2FV( attr
, v
);
901 static void GLAPIENTRY
_save_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
904 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
905 DISPATCH_ATTR3F( attr
, x
, y
, z
);
908 static void GLAPIENTRY
_save_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
910 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
911 DISPATCH_ATTR3FV( attr
, v
);
914 static void GLAPIENTRY
_save_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
915 GLfloat z
, GLfloat w
)
917 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
918 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
921 static void GLAPIENTRY
_save_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
923 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
924 DISPATCH_ATTR4FV( attr
, v
);
927 static void GLAPIENTRY
_save_VertexAttrib1fNV( GLuint index
, GLfloat x
)
929 if (index
< VERT_ATTRIB_MAX
)
930 DISPATCH_ATTR1F( index
, x
);
935 static void GLAPIENTRY
_save_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
937 if (index
< VERT_ATTRIB_MAX
)
938 DISPATCH_ATTR1FV( index
, v
);
943 static void GLAPIENTRY
_save_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
945 if (index
< VERT_ATTRIB_MAX
)
946 DISPATCH_ATTR2F( index
, x
, y
);
951 static void GLAPIENTRY
_save_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
953 if (index
< VERT_ATTRIB_MAX
)
954 DISPATCH_ATTR2FV( index
, v
);
959 static void GLAPIENTRY
_save_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
962 if (index
< VERT_ATTRIB_MAX
)
963 DISPATCH_ATTR3F( index
, x
, y
, z
);
968 static void GLAPIENTRY
_save_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
970 if (index
< VERT_ATTRIB_MAX
)
971 DISPATCH_ATTR3FV( index
, v
);
976 static void GLAPIENTRY
_save_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
977 GLfloat z
, GLfloat w
)
979 if (index
< VERT_ATTRIB_MAX
)
980 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
985 static void GLAPIENTRY
_save_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
987 if (index
< VERT_ATTRIB_MAX
)
988 DISPATCH_ATTR4FV( index
, v
);
996 * These are treated as per-vertex attributes, at indices above where
997 * the NV_vertex_program leaves off. There are a lot of good things
998 * about treating materials this way.
1000 * However: I don't want to double the number of generated functions
1001 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
1002 * ATTRF into this function, and dispense with codegen and
1003 * second-level dispatch.
1005 * There is no aliasing of material attributes with other entrypoints.
1007 #define MAT_ATTR( A, N, params ) \
1009 if (tnl->save.attrsz[A] < N) { \
1010 _save_upgrade_vertex( ctx, A, N ); \
1011 tnl->save.have_materials = GL_TRUE; \
1015 GLfloat *dest = tnl->save.attrptr[A]; \
1016 if (N>0) dest[0] = params[0]; \
1017 if (N>1) dest[1] = params[1]; \
1018 if (N>2) dest[2] = params[2]; \
1019 if (N>3) dest[3] = params[3]; \
1024 #define MAT( ATTR, N, face, params ) \
1026 if (face != GL_BACK) \
1027 MAT_ATTR( ATTR, N, params ); /* front */ \
1028 if (face != GL_FRONT) \
1029 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1033 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1034 * later on - in the meantime just store everything.
1036 static void GLAPIENTRY
_save_Materialfv( GLenum face
, GLenum pname
,
1037 const GLfloat
*params
)
1039 GET_CURRENT_CONTEXT( ctx
);
1040 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1044 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
1047 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1050 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1053 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
1056 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
1058 case GL_COLOR_INDEXES
:
1059 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
1061 case GL_AMBIENT_AND_DIFFUSE
:
1062 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1063 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1066 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
1072 #define IDX_ATTR( A, IDX ) \
1074 GET_CURRENT_CONTEXT( ctx ); \
1075 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1077 if (tnl->save.attrsz[A] < 1) { \
1078 _save_upgrade_vertex( ctx, A, 1 ); \
1082 GLfloat *dest = tnl->save.attrptr[A]; \
1088 static void GLAPIENTRY
_save_EdgeFlag( GLboolean b
)
1090 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
1093 static void GLAPIENTRY
_save_EdgeFlagv( const GLboolean
*v
)
1095 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)(v
[0]) );
1098 static void GLAPIENTRY
_save_Indexf( GLfloat f
)
1100 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
1103 static void GLAPIENTRY
_save_Indexfv( const GLfloat
*f
)
1105 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
[0] );
1111 /* Cope with EvalCoord/CallList called within a begin/end object:
1112 * -- Flush current buffer
1113 * -- Fallback to opcodes for the rest of the begin/end object.
1115 #define FALLBACK(ctx) \
1117 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1119 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1121 if (tnl->save.initial_counter != tnl->save.counter || \
1122 tnl->save.prim_count) \
1123 _save_compile_vertex_list( ctx ); \
1125 _save_copy_to_current( ctx ); \
1126 _save_reset_vertex( ctx ); \
1127 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1128 ctx->Driver.SaveNeedFlush = 0; \
1131 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
1133 GET_CURRENT_CONTEXT(ctx
);
1135 ctx
->Save
->EvalCoord1f( u
);
1138 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
1140 GET_CURRENT_CONTEXT(ctx
);
1142 ctx
->Save
->EvalCoord1fv( v
);
1145 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
1147 GET_CURRENT_CONTEXT(ctx
);
1149 ctx
->Save
->EvalCoord2f( u
, v
);
1152 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
1154 GET_CURRENT_CONTEXT(ctx
);
1156 ctx
->Save
->EvalCoord2fv( v
);
1159 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
1161 GET_CURRENT_CONTEXT(ctx
);
1163 ctx
->Save
->EvalPoint1( i
);
1166 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
1168 GET_CURRENT_CONTEXT(ctx
);
1170 ctx
->Save
->EvalPoint2( i
, j
);
1173 static void GLAPIENTRY
_save_CallList( GLuint l
)
1175 GET_CURRENT_CONTEXT(ctx
);
1177 ctx
->Save
->CallList( l
);
1180 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
1182 GET_CURRENT_CONTEXT(ctx
);
1184 ctx
->Save
->CallLists( n
, type
, v
);
1190 /* This begin is hooked into ... Updating of
1191 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1193 static GLboolean
_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
1195 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1198 GLuint i
= tnl
->save
.prim_count
++;
1200 assert(i
< tnl
->save
.prim_max
);
1201 tnl
->save
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1202 tnl
->save
.prim
[i
].start
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
1203 tnl
->save
.prim
[i
].count
= 0;
1205 _mesa_install_save_vtxfmt( ctx
, &tnl
->save_vtxfmt
);
1206 ctx
->Driver
.SaveNeedFlush
= 1;
1215 static void GLAPIENTRY
_save_End( void )
1217 GET_CURRENT_CONTEXT( ctx
);
1218 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1219 GLint i
= tnl
->save
.prim_count
- 1;
1221 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1222 tnl
->save
.prim
[i
].mode
|= PRIM_END
;
1223 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
1224 tnl
->save
.prim
[i
].start
);
1226 if (i
== (GLint
) tnl
->save
.prim_max
- 1) {
1227 _save_compile_vertex_list( ctx
);
1228 assert(tnl
->save
.copied
.nr
== 0);
1231 /* Swap out this vertex format while outside begin/end. Any color,
1232 * etc. received between here and the next begin will be compiled
1235 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1239 /* These are all errors as this vtxfmt is only installed inside
1242 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1243 const GLvoid
*indices
)
1245 GET_CURRENT_CONTEXT(ctx
);
1246 (void) mode
; (void) count
; (void) type
; (void) indices
;
1247 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
1251 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
1252 GLuint start
, GLuint end
,
1253 GLsizei count
, GLenum type
,
1254 const GLvoid
*indices
)
1256 GET_CURRENT_CONTEXT(ctx
);
1257 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
1258 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
1261 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1263 GET_CURRENT_CONTEXT(ctx
);
1264 (void) mode
; (void) start
; (void) count
;
1265 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
1268 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1270 GET_CURRENT_CONTEXT(ctx
);
1271 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
1272 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
1275 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
1277 GET_CURRENT_CONTEXT(ctx
);
1278 (void) mode
; (void) i1
; (void) i2
;
1279 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
1282 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
1283 GLint j1
, GLint j2
)
1285 GET_CURRENT_CONTEXT(ctx
);
1286 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
1287 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
1290 static void GLAPIENTRY
_save_Begin( GLenum mode
)
1292 GET_CURRENT_CONTEXT( ctx
);
1294 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
1298 /* Unlike the functions above, these are to be hooked into the vtxfmt
1299 * maintained in ctx->ListState, active when the list is known or
1300 * suspected to be outside any begin/end primitive.
1302 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1304 GET_CURRENT_CONTEXT(ctx
);
1305 _save_NotifyBegin( ctx
, GL_QUADS
| PRIM_WEAK
);
1306 GL_CALL(Vertex2f
)( x1
, y1
);
1307 GL_CALL(Vertex2f
)( x2
, y1
);
1308 GL_CALL(Vertex2f
)( x2
, y2
);
1309 GL_CALL(Vertex2f
)( x1
, y2
);
1314 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1316 GET_CURRENT_CONTEXT(ctx
);
1319 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
1322 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1323 for (i
= 0; i
< count
; i
++)
1324 GL_CALL(ArrayElement
)(start
+ i
);
1329 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1330 const GLvoid
*indices
)
1332 GET_CURRENT_CONTEXT(ctx
);
1335 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
1338 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1341 case GL_UNSIGNED_BYTE
:
1342 for (i
= 0 ; i
< count
; i
++)
1343 GL_CALL(ArrayElement
)( ((GLubyte
*)indices
)[i
] );
1345 case GL_UNSIGNED_SHORT
:
1346 for (i
= 0 ; i
< count
; i
++)
1347 GL_CALL(ArrayElement
)( ((GLushort
*)indices
)[i
] );
1349 case GL_UNSIGNED_INT
:
1350 for (i
= 0 ; i
< count
; i
++)
1351 GL_CALL(ArrayElement
)( ((GLuint
*)indices
)[i
] );
1354 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
1361 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
1362 GLuint start
, GLuint end
,
1363 GLsizei count
, GLenum type
,
1364 const GLvoid
*indices
)
1366 GET_CURRENT_CONTEXT(ctx
);
1367 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1369 count
, type
, indices
))
1370 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1377 static void _save_vtxfmt_init( GLcontext
*ctx
)
1379 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1380 GLvertexformat
*vfmt
= &tnl
->save_vtxfmt
;
1382 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1383 vfmt
->Begin
= _save_Begin
;
1384 vfmt
->Color3f
= _save_Color3f
;
1385 vfmt
->Color3fv
= _save_Color3fv
;
1386 vfmt
->Color4f
= _save_Color4f
;
1387 vfmt
->Color4fv
= _save_Color4fv
;
1388 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1389 vfmt
->EdgeFlagv
= _save_EdgeFlagv
;
1390 vfmt
->End
= _save_End
;
1391 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1392 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1393 vfmt
->Indexf
= _save_Indexf
;
1394 vfmt
->Indexfv
= _save_Indexfv
;
1395 vfmt
->Materialfv
= _save_Materialfv
;
1396 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1397 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1398 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1399 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1400 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1401 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1402 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1403 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1404 vfmt
->Normal3f
= _save_Normal3f
;
1405 vfmt
->Normal3fv
= _save_Normal3fv
;
1406 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1407 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1408 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1409 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1410 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1411 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1412 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1413 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1414 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1415 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1416 vfmt
->Vertex2f
= _save_Vertex2f
;
1417 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1418 vfmt
->Vertex3f
= _save_Vertex3f
;
1419 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1420 vfmt
->Vertex4f
= _save_Vertex4f
;
1421 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1422 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1423 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1424 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1425 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1426 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1427 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1428 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1429 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1431 /* This will all require us to fallback to saving the list as opcodes:
1433 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1434 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1435 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1436 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1437 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1438 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1439 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1440 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1442 /* These are all errors as we at least know we are in some sort of
1445 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1446 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1447 vfmt
->Begin
= _save_Begin
;
1448 vfmt
->Rectf
= _save_Rectf
;
1449 vfmt
->DrawArrays
= _save_DrawArrays
;
1450 vfmt
->DrawElements
= _save_DrawElements
;
1451 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1456 void _tnl_SaveFlushVertices( GLcontext
*ctx
)
1458 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1460 /* Noop when we are actually active:
1462 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1463 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1466 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
||
1467 tnl
->save
.prim_count
)
1468 _save_compile_vertex_list( ctx
);
1470 _save_copy_to_current( ctx
);
1471 _save_reset_vertex( ctx
);
1472 ctx
->Driver
.SaveNeedFlush
= 0;
1475 void _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1477 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1479 (void) list
; (void) mode
;
1481 if (!tnl
->save
.prim_store
)
1482 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
1484 if (!tnl
->save
.vertex_store
) {
1485 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
1486 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
1489 _save_reset_vertex( ctx
);
1490 ctx
->Driver
.SaveNeedFlush
= 0;
1493 void _tnl_EndList( GLcontext
*ctx
)
1496 assert(TNL_CONTEXT(ctx
)->save
.vertex_size
== 0);
1499 void _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
1501 (void) ctx
; (void) list
;
1504 void _tnl_EndCallList( GLcontext
*ctx
)
1510 static void _tnl_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1512 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1515 if ( --node
->vertex_store
->refcount
== 0 )
1516 FREE( node
->vertex_store
);
1518 if ( --node
->prim_store
->refcount
== 0 )
1519 FREE( node
->prim_store
);
1521 if ( node
->normal_lengths
)
1522 FREE( node
->normal_lengths
);
1526 static void _tnl_print_vertex_list( GLcontext
*ctx
, void *data
)
1528 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1532 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1537 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1538 struct tnl_prim
*prim
= &node
->prim
[i
];
1539 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1541 _mesa_lookup_enum_by_nr(prim
->mode
& PRIM_MODE_MASK
),
1543 prim
->start
+ prim
->count
,
1544 (prim
->mode
& PRIM_BEGIN
) ? "BEGIN" : "(wrap)",
1545 (prim
->mode
& PRIM_END
) ? "END" : "(wrap)");
1550 static void _save_current_init( GLcontext
*ctx
)
1552 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1555 for (i
= 0; i
< _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1556 ASSERT(i
< VERT_ATTRIB_MAX
);
1557 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[i
];
1558 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentAttrib
[i
];
1561 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
< _TNL_ATTRIB_INDEX
; i
++) {
1562 const GLuint j
= i
- _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
1563 ASSERT(j
< MAT_ATTRIB_MAX
);
1564 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1565 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1568 tnl
->save
.currentsz
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.ActiveIndex
;
1569 tnl
->save
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->ListState
.CurrentIndex
;
1571 /* Current edgeflag is handled individually */
1575 * Initialize the display list compiler
1577 void _tnl_save_init( GLcontext
*ctx
)
1579 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1580 struct tnl_vertex_arrays
*tmp
= &tnl
->save_inputs
;
1584 for (i
= 0; i
< _TNL_ATTRIB_MAX
; i
++)
1585 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1587 tnl
->save
.opcode_vertex_list
=
1588 _mesa_alloc_opcode( ctx
,
1589 sizeof(struct tnl_vertex_list
),
1590 _tnl_playback_vertex_list
,
1591 _tnl_destroy_vertex_list
,
1592 _tnl_print_vertex_list
);
1594 ctx
->Driver
.NotifySaveBegin
= _save_NotifyBegin
;
1596 _save_vtxfmt_init( ctx
);
1597 _save_current_init( ctx
);
1599 /* Hook our array functions into the outside-begin-end vtxfmt in
1602 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1603 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1604 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1605 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1606 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1611 * Deallocate the immediate-mode buffer for the given context, if
1612 * its reference count goes to zero.
1614 void _tnl_save_destroy( GLcontext
*ctx
)