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"
83 * NOTE: Old 'parity' issue is gone, but copying can still be
84 * wrong-footed on replay.
86 static GLuint
_save_copy_vertices( GLcontext
*ctx
,
87 const struct tnl_vertex_list
*node
)
89 TNLcontext
*tnl
= TNL_CONTEXT( ctx
);
90 const struct tnl_prim
*prim
= &node
->prim
[node
->prim_count
-1];
91 GLuint nr
= prim
->count
;
92 GLuint sz
= tnl
->save
.vertex_size
;
93 const GLfloat
*src
= node
->buffer
+ prim
->start
* sz
;
94 GLfloat
*dst
= tnl
->save
.copied
.buffer
;
97 if (prim
->mode
& PRIM_END
)
100 switch( prim
->mode
& PRIM_MODE_MASK
)
106 for (i
= 0 ; i
< ovf
; i
++)
107 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
111 for (i
= 0 ; i
< ovf
; i
++)
112 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
116 for (i
= 0 ; i
< ovf
; i
++)
117 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
123 _mesa_memcpy( dst
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
127 case GL_TRIANGLE_FAN
:
132 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
135 _mesa_memcpy( dst
, src
+0, sz
*sizeof(GLfloat
) );
136 _mesa_memcpy( dst
+sz
, src
+(nr
-1)*sz
, sz
*sizeof(GLfloat
) );
139 case GL_TRIANGLE_STRIP
:
142 case 0: ovf
= 0; break;
143 case 1: ovf
= 1; break;
144 default: ovf
= 2 + (nr
&1); break;
146 for (i
= 0 ; i
< ovf
; i
++)
147 _mesa_memcpy( dst
+i
*sz
, src
+(nr
-ovf
+i
)*sz
, sz
*sizeof(GLfloat
) );
157 build_normal_lengths( struct tnl_vertex_list
*node
)
161 GLfloat
*n
= node
->buffer
;
162 GLuint stride
= node
->vertex_size
;
163 GLuint count
= node
->count
;
165 len
= node
->normal_lengths
= (GLfloat
*) MALLOC( count
* sizeof(GLfloat
) );
169 /* Find the normal of the first vertex:
171 for (i
= 0 ; i
< _TNL_ATTRIB_NORMAL
; i
++)
172 n
+= node
->attrsz
[i
];
174 for (i
= 0 ; i
< count
; i
++, n
+= stride
) {
175 len
[i
] = LEN_3FV( n
);
176 if (len
[i
] > 0.0F
) len
[i
] = 1.0F
/ len
[i
];
180 static struct tnl_vertex_store
*alloc_vertex_store( GLcontext
*ctx
)
182 struct tnl_vertex_store
*store
= MALLOC_STRUCT(tnl_vertex_store
);
189 static struct tnl_primitive_store
*alloc_prim_store( GLcontext
*ctx
)
191 struct tnl_primitive_store
*store
= MALLOC_STRUCT(tnl_primitive_store
);
198 static void _save_reset_counters( GLcontext
*ctx
)
200 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
202 tnl
->save
.prim
= tnl
->save
.prim_store
->buffer
+ tnl
->save
.prim_store
->used
;
203 tnl
->save
.buffer
= (tnl
->save
.vertex_store
->buffer
+
204 tnl
->save
.vertex_store
->used
);
206 if (tnl
->save
.vertex_size
)
207 tnl
->save
.initial_counter
= ((SAVE_BUFFER_SIZE
-
208 tnl
->save
.vertex_store
->used
) /
209 tnl
->save
.vertex_size
);
211 tnl
->save
.initial_counter
= 0;
213 if (tnl
->save
.initial_counter
> ctx
->Const
.MaxArrayLockSize
)
214 tnl
->save
.initial_counter
= ctx
->Const
.MaxArrayLockSize
;
216 tnl
->save
.counter
= tnl
->save
.initial_counter
;
217 tnl
->save
.prim_count
= 0;
218 tnl
->save
.prim_max
= SAVE_PRIM_SIZE
- tnl
->save
.prim_store
->used
;
219 tnl
->save
.copied
.nr
= 0;
220 tnl
->save
.dangling_attr_ref
= 0;
224 /* Insert the active immediate struct onto the display list currently
227 static void _save_compile_vertex_list( GLcontext
*ctx
)
229 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
230 struct tnl_vertex_list
*node
;
232 /* Allocate space for this structure in the display list currently
235 node
= (struct tnl_vertex_list
*)
236 _mesa_alloc_instruction(ctx
, tnl
->save
.opcode_vertex_list
, sizeof(*node
));
241 /* Duplicate our template, increment refcounts to the storage structs:
243 _mesa_memcpy(node
->attrsz
, tnl
->save
.attrsz
, sizeof(node
->attrsz
));
244 node
->vertex_size
= tnl
->save
.vertex_size
;
245 node
->buffer
= tnl
->save
.buffer
;
246 node
->count
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
247 node
->wrap_count
= tnl
->save
.copied
.nr
;
248 node
->have_materials
= tnl
->save
.have_materials
;
249 node
->dangling_attr_ref
= tnl
->save
.dangling_attr_ref
;
250 node
->normal_lengths
= NULL
;
251 node
->prim
= tnl
->save
.prim
;
252 node
->prim_count
= tnl
->save
.prim_count
;
253 node
->vertex_store
= tnl
->save
.vertex_store
;
254 node
->prim_store
= tnl
->save
.prim_store
;
256 node
->vertex_store
->refcount
++;
257 node
->prim_store
->refcount
++;
259 assert(node
->attrsz
[_TNL_ATTRIB_POS
] != 0 ||
262 if (tnl
->save
.dangling_attr_ref
)
263 ctx
->ListState
.CurrentList
->flags
|= MESA_DLIST_DANGLING_REFS
;
265 /* Maybe calculate normal lengths:
267 if (tnl
->CalcDListNormalLengths
&&
268 node
->attrsz
[_TNL_ATTRIB_NORMAL
] == 3 &&
269 !(ctx
->ListState
.CurrentList
->flags
& MESA_DLIST_DANGLING_REFS
))
270 build_normal_lengths( node
);
273 tnl
->save
.vertex_store
->used
+= tnl
->save
.vertex_size
* node
->count
;
274 tnl
->save
.prim_store
->used
+= node
->prim_count
;
276 /* Decide whether the storage structs are full, or can be used for
277 * the next vertex lists as well.
279 if (tnl
->save
.vertex_store
->used
>
280 SAVE_BUFFER_SIZE
- 16 * (tnl
->save
.vertex_size
+ 4)) {
282 tnl
->save
.vertex_store
->refcount
--;
283 assert(tnl
->save
.vertex_store
->refcount
!= 0);
284 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
285 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
288 if (tnl
->save
.prim_store
->used
> SAVE_PRIM_SIZE
- 6) {
289 tnl
->save
.prim_store
->refcount
--;
290 assert(tnl
->save
.prim_store
->refcount
!= 0);
291 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
294 /* Reset our structures for the next run of vertices:
296 _save_reset_counters( ctx
);
298 /* Copy duplicated vertices
300 tnl
->save
.copied
.nr
= _save_copy_vertices( ctx
, node
);
303 /* Deal with GL_COMPILE_AND_EXECUTE:
305 if (ctx
->ExecuteFlag
) {
306 _tnl_playback_vertex_list( ctx
, (void *) node
);
311 /* TODO -- If no new vertices have been stored, don't bother saving
314 static void _save_wrap_buffers( GLcontext
*ctx
)
316 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
317 GLint i
= tnl
->save
.prim_count
- 1;
320 assert(i
< (GLint
) tnl
->save
.prim_max
);
323 /* Close off in-progress primitive.
325 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
326 tnl
->save
.prim
[i
].start
);
327 mode
= tnl
->save
.prim
[i
].mode
& ~(PRIM_BEGIN
|PRIM_END
);
329 /* store the copied vertices, and allocate a new list.
331 _save_compile_vertex_list( ctx
);
333 /* Restart interrupted primitive
335 tnl
->save
.prim
[0].mode
= mode
;
336 tnl
->save
.prim
[0].start
= 0;
337 tnl
->save
.prim
[0].count
= 0;
338 tnl
->save
.prim_count
= 1;
343 /* Called only when buffers are wrapped as the result of filling the
344 * vertex_store struct.
346 static void _save_wrap_filled_vertex( GLcontext
*ctx
)
348 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
349 GLfloat
*data
= tnl
->save
.copied
.buffer
;
352 /* Emit a glEnd to close off the last vertex list.
354 _save_wrap_buffers( ctx
);
356 /* Copy stored stored vertices to start of new list.
358 assert(tnl
->save
.counter
> tnl
->save
.copied
.nr
);
360 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
361 _mesa_memcpy( tnl
->save
.vbptr
, data
, tnl
->save
.vertex_size
* sizeof(GLfloat
));
362 data
+= tnl
->save
.vertex_size
;
363 tnl
->save
.vbptr
+= tnl
->save
.vertex_size
;
369 static void _save_copy_to_current( GLcontext
*ctx
)
371 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
374 /* XXX Use _TNL_FIRST_* and _TNL_LAST_* values instead? */
375 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_EDGEFLAG
; i
++) {
376 if (tnl
->save
.attrsz
[i
]) {
377 tnl
->save
.currentsz
[i
][0] = tnl
->save
.attrsz
[i
];
378 COPY_CLEAN_4V(tnl
->save
.current
[i
],
380 tnl
->save
.attrptr
[i
]);
384 /* Edgeflag requires special treatment:
386 * TODO: change edgeflag to GLfloat in Mesa.
388 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
389 ctx
->ListState
.ActiveEdgeFlag
= 1;
390 tnl
->save
.CurrentFloatEdgeFlag
=
391 tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0];
392 ctx
->ListState
.CurrentEdgeFlag
=
393 (tnl
->save
.CurrentFloatEdgeFlag
== 1.0);
398 static void _save_copy_from_current( GLcontext
*ctx
)
400 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
403 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_EDGEFLAG
; i
++)
404 switch (tnl
->save
.attrsz
[i
]) {
405 case 4: tnl
->save
.attrptr
[i
][3] = tnl
->save
.current
[i
][3];
406 case 3: tnl
->save
.attrptr
[i
][2] = tnl
->save
.current
[i
][2];
407 case 2: tnl
->save
.attrptr
[i
][1] = tnl
->save
.current
[i
][1];
408 case 1: tnl
->save
.attrptr
[i
][0] = tnl
->save
.current
[i
][0];
412 /* Edgeflag requires special treatment:
414 if (tnl
->save
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
415 tnl
->save
.CurrentFloatEdgeFlag
= (GLfloat
)ctx
->ListState
.CurrentEdgeFlag
;
416 tnl
->save
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] = tnl
->save
.CurrentFloatEdgeFlag
;
423 /* Flush existing data, set new attrib size, replay copied vertices.
425 static void _save_upgrade_vertex( GLcontext
*ctx
,
429 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
434 /* Store the current run of vertices, and emit a GL_END. Emit a
435 * BEGIN in the new buffer.
437 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
)
438 _save_wrap_buffers( ctx
);
440 assert( tnl
->save
.copied
.nr
== 0 );
442 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
443 * when the attribute already exists in the vertex and is having
444 * its size increased.
446 _save_copy_to_current( ctx
);
450 oldsz
= tnl
->save
.attrsz
[attr
];
451 tnl
->save
.attrsz
[attr
] = newsz
;
453 tnl
->save
.vertex_size
+= newsz
- oldsz
;
454 tnl
->save
.counter
= ((SAVE_BUFFER_SIZE
- tnl
->save
.vertex_store
->used
) /
455 tnl
->save
.vertex_size
);
456 if (tnl
->save
.counter
> ctx
->Const
.MaxArrayLockSize
)
457 tnl
->save
.counter
= ctx
->Const
.MaxArrayLockSize
;
458 tnl
->save
.initial_counter
= tnl
->save
.counter
;
460 /* Recalculate all the attrptr[] values:
462 for (i
= 0, tmp
= tnl
->save
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
463 if (tnl
->save
.attrsz
[i
]) {
464 tnl
->save
.attrptr
[i
] = tmp
;
465 tmp
+= tnl
->save
.attrsz
[i
];
468 tnl
->save
.attrptr
[i
] = NULL
; /* will not be dereferenced. */
471 /* Copy from current to repopulate the vertex with correct values.
473 _save_copy_from_current( ctx
);
475 /* Replay stored vertices to translate them to new format here.
477 * If there are copied vertices and the new (upgraded) attribute
478 * has not been defined before, this list is somewhat degenerate,
479 * and will need fixup at runtime.
481 if (tnl
->save
.copied
.nr
)
483 GLfloat
*data
= tnl
->save
.copied
.buffer
;
484 GLfloat
*dest
= tnl
->save
.buffer
;
487 /* Need to note this and fix up at runtime (or loopback):
489 if (tnl
->save
.currentsz
[attr
][0] == 0) {
491 tnl
->save
.dangling_attr_ref
= GL_TRUE
;
493 /* _mesa_debug(NULL, "_save_upgrade_vertex: dangling reference attr %d\n", */
497 /* The current strategy is to punt these degenerate cases
498 * through _tnl_loopback_vertex_list(), a lower-performance
499 * option. To minimize the impact of this, artificially
500 * reduce the size of this vertex_list.
502 if (t
->save
.counter
> 10) {
503 t
->save
.initial_counter
= 10;
504 t
->save
.counter
= 10;
509 for (i
= 0 ; i
< tnl
->save
.copied
.nr
; i
++) {
510 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
511 if (tnl
->save
.attrsz
[j
]) {
514 COPY_CLEAN_4V( dest
, oldsz
, data
);
519 COPY_SZ_4V( dest
, newsz
, tnl
->save
.current
[attr
] );
524 GLint sz
= tnl
->save
.attrsz
[j
];
525 COPY_SZ_4V( dest
, sz
, data
);
533 tnl
->save
.vbptr
= dest
;
534 tnl
->save
.counter
-= tnl
->save
.copied
.nr
;
541 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
542 * entrypoint is called for the first time.
544 static void do_choose( GLuint attr
, GLuint sz
,
545 void (*attr_func
)( const GLfloat
*),
546 void (*choose1
)( const GLfloat
*),
547 void (*choose2
)( const GLfloat
*),
548 void (*choose3
)( const GLfloat
*),
549 void (*choose4
)( const GLfloat
*),
552 GET_CURRENT_CONTEXT( ctx
);
553 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
554 static GLfloat id
[4] = { 0, 0, 0, 1 };
557 if (tnl
->save
.attrsz
[attr
] < sz
) {
558 /* New size is larger. Need to flush existing vertices and get
559 * an enlarged vertex format.
561 _save_upgrade_vertex( ctx
, attr
, sz
);
564 /* New size is equal or smaller - just need to fill in some
567 for (i
= sz
; i
<= tnl
->save
.attrsz
[attr
] ; i
++)
568 tnl
->save
.attrptr
[attr
][i
-1] = id
[i
-1];
571 /* Reset any active pointers for this attribute
573 tnl
->save
.tabfv
[attr
][0] = choose1
;
574 tnl
->save
.tabfv
[attr
][1] = choose2
;
575 tnl
->save
.tabfv
[attr
][2] = choose3
;
576 tnl
->save
.tabfv
[attr
][3] = choose4
;
578 /* Update the secondary dispatch table with the new function
580 tnl
->save
.tabfv
[attr
][sz
-1] = attr_func
;
587 /* Only one size for each attribute may be active at once. Eg. if
588 * Color3f is installed/active, then Color4f may not be, even if the
589 * vertex actually contains 4 color coordinates. This is because the
590 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
591 * of the chooser function when switching between Color4f and Color3f.
593 #define ATTRFV( ATTR, N ) \
594 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
596 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
598 GET_CURRENT_CONTEXT( ctx ); \
599 TNLcontext *tnl = TNL_CONTEXT(ctx); \
604 if (N>0) tnl->save.vbptr[0] = v[0]; \
605 if (N>1) tnl->save.vbptr[1] = v[1]; \
606 if (N>2) tnl->save.vbptr[2] = v[2]; \
607 if (N>3) tnl->save.vbptr[3] = v[3]; \
609 for (i = N; i < tnl->save.vertex_size; i++) \
610 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
612 tnl->save.vbptr += tnl->save.vertex_size; \
614 if (--tnl->save.counter == 0) \
615 _save_wrap_filled_vertex( ctx ); \
618 GLfloat *dest = tnl->save.attrptr[ATTR]; \
619 if (N>0) dest[0] = v[0]; \
620 if (N>1) dest[1] = v[1]; \
621 if (N>2) dest[2] = v[2]; \
622 if (N>3) dest[3] = v[3]; \
626 #define CHOOSE( ATTR, N ) \
627 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
630 save_attrib_##ATTR##_##N, \
631 save_choose_##ATTR##_1, \
632 save_choose_##ATTR##_2, \
633 save_choose_##ATTR##_3, \
634 save_choose_##ATTR##_4, \
639 static void save_init_##ATTR( TNLcontext *tnl ) \
641 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
642 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
643 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
644 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
647 #define ATTRS( ATTRIB ) \
648 ATTRFV( ATTRIB, 1 ) \
649 ATTRFV( ATTRIB, 2 ) \
650 ATTRFV( ATTRIB, 3 ) \
651 ATTRFV( ATTRIB, 4 ) \
652 CHOOSE( ATTRIB, 1 ) \
653 CHOOSE( ATTRIB, 2 ) \
654 CHOOSE( ATTRIB, 3 ) \
655 CHOOSE( ATTRIB, 4 ) \
659 /* Generate a lot of functions. These are the actual worker
660 * functions, which are equivalent to those generated via codegen
681 static void _save_reset_vertex( GLcontext
*ctx
)
683 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
703 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
704 tnl
->save
.attrsz
[i
] = 0;
706 tnl
->save
.vertex_size
= 0;
707 tnl
->save
.have_materials
= 0;
709 _save_reset_counters( ctx
);
714 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
715 * of glMultTexCoord and glProgramParamterNV by routing all these
716 * through a second level dispatch table.
718 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
720 GET_CURRENT_CONTEXT( ctx ); \
721 TNLcontext *tnl = TNL_CONTEXT(ctx); \
722 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
725 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
726 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
727 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
728 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
730 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
732 #if defined(USE_X86_ASM) && 0 /* will break register calling convention */
735 #define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
736 #define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
737 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
741 #define DISPATCH_ATTR2F( ATTR, S,T ) \
744 v[0] = S; v[1] = T; \
745 DISPATCH_ATTR2FV( ATTR, v ); \
747 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
750 v[0] = S; v[1] = T; v[2] = R; \
751 DISPATCH_ATTR3FV( ATTR, v ); \
753 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
756 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
757 DISPATCH_ATTR4FV( ATTR, v ); \
762 static void enum_error( void )
764 GET_CURRENT_CONTEXT( ctx
);
765 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
768 static void GLAPIENTRY
_save_Vertex2f( GLfloat x
, GLfloat y
)
770 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
773 static void GLAPIENTRY
_save_Vertex2fv( const GLfloat
*v
)
775 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
778 static void GLAPIENTRY
_save_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
780 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
783 static void GLAPIENTRY
_save_Vertex3fv( const GLfloat
*v
)
785 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
788 static void GLAPIENTRY
_save_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
790 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
793 static void GLAPIENTRY
_save_Vertex4fv( const GLfloat
*v
)
795 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
798 static void GLAPIENTRY
_save_TexCoord1f( GLfloat x
)
800 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
803 static void GLAPIENTRY
_save_TexCoord1fv( const GLfloat
*v
)
805 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
808 static void GLAPIENTRY
_save_TexCoord2f( GLfloat x
, GLfloat y
)
810 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
813 static void GLAPIENTRY
_save_TexCoord2fv( const GLfloat
*v
)
815 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
818 static void GLAPIENTRY
_save_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
820 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
823 static void GLAPIENTRY
_save_TexCoord3fv( const GLfloat
*v
)
825 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
828 static void GLAPIENTRY
_save_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
830 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
833 static void GLAPIENTRY
_save_TexCoord4fv( const GLfloat
*v
)
835 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
838 static void GLAPIENTRY
_save_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
840 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
843 static void GLAPIENTRY
_save_Normal3fv( const GLfloat
*v
)
845 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
848 static void GLAPIENTRY
_save_FogCoordfEXT( GLfloat x
)
850 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
853 static void GLAPIENTRY
_save_FogCoordfvEXT( const GLfloat
*v
)
855 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
858 static void GLAPIENTRY
_save_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
860 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
863 static void GLAPIENTRY
_save_Color3fv( const GLfloat
*v
)
865 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
868 static void GLAPIENTRY
_save_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
870 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
873 static void GLAPIENTRY
_save_Color4fv( const GLfloat
*v
)
875 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
878 static void GLAPIENTRY
_save_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
880 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
883 static void GLAPIENTRY
_save_SecondaryColor3fvEXT( const GLfloat
*v
)
885 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
888 static void GLAPIENTRY
_save_MultiTexCoord1f( GLenum target
, GLfloat x
)
890 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
891 DISPATCH_ATTR1F( attr
, x
);
894 static void GLAPIENTRY
_save_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
896 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
897 DISPATCH_ATTR1FV( attr
, v
);
900 static void GLAPIENTRY
_save_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
902 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
903 DISPATCH_ATTR2F( attr
, x
, y
);
906 static void GLAPIENTRY
_save_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
908 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
909 DISPATCH_ATTR2FV( attr
, v
);
912 static void GLAPIENTRY
_save_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
915 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
916 DISPATCH_ATTR3F( attr
, x
, y
, z
);
919 static void GLAPIENTRY
_save_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
921 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
922 DISPATCH_ATTR3FV( attr
, v
);
925 static void GLAPIENTRY
_save_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
926 GLfloat z
, GLfloat w
)
928 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
929 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
932 static void GLAPIENTRY
_save_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
934 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
935 DISPATCH_ATTR4FV( attr
, v
);
938 static void GLAPIENTRY
_save_VertexAttrib1fNV( GLuint index
, GLfloat x
)
940 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
941 DISPATCH_ATTR1F( index
, x
);
946 static void GLAPIENTRY
_save_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
948 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
949 DISPATCH_ATTR1FV( index
, v
);
954 static void GLAPIENTRY
_save_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
956 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
957 DISPATCH_ATTR2F( index
, x
, y
);
962 static void GLAPIENTRY
_save_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
964 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
965 DISPATCH_ATTR2FV( index
, v
);
970 static void GLAPIENTRY
_save_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
973 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
974 DISPATCH_ATTR3F( index
, x
, y
, z
);
979 static void GLAPIENTRY
_save_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
981 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
982 DISPATCH_ATTR3FV( index
, v
);
987 static void GLAPIENTRY
_save_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
988 GLfloat z
, GLfloat w
)
990 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
991 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
996 static void GLAPIENTRY
_save_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
998 if (index
< MAX_VERTEX_PROGRAM_ATTRIBS
)
999 DISPATCH_ATTR4FV( index
, v
);
1005 static void GLAPIENTRY
1006 _save_VertexAttrib1fARB( GLuint index
, GLfloat x
)
1008 if (index
< MAX_VERTEX_ATTRIBS
)
1009 DISPATCH_ATTR1F( index
, x
);
1014 static void GLAPIENTRY
1015 _save_VertexAttrib1fvARB( GLuint index
, const GLfloat
*v
)
1017 if (index
< MAX_VERTEX_ATTRIBS
)
1018 DISPATCH_ATTR1FV( index
, v
);
1023 static void GLAPIENTRY
1024 _save_VertexAttrib2fARB( GLuint index
, GLfloat x
, GLfloat y
)
1026 if (index
< MAX_VERTEX_ATTRIBS
)
1027 DISPATCH_ATTR2F( index
, x
, y
);
1032 static void GLAPIENTRY
1033 _save_VertexAttrib2fvARB( GLuint index
, const GLfloat
*v
)
1035 if (index
< MAX_VERTEX_ATTRIBS
)
1036 DISPATCH_ATTR2FV( index
, v
);
1041 static void GLAPIENTRY
1042 _save_VertexAttrib3fARB( GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
)
1044 if (index
< MAX_VERTEX_ATTRIBS
)
1045 DISPATCH_ATTR3F( index
, x
, y
, z
);
1050 static void GLAPIENTRY
1051 _save_VertexAttrib3fvARB( GLuint index
, const GLfloat
*v
)
1053 if (index
< MAX_VERTEX_ATTRIBS
)
1054 DISPATCH_ATTR3FV( index
, v
);
1059 static void GLAPIENTRY
1060 _save_VertexAttrib4fARB( GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1062 if (index
< MAX_VERTEX_ATTRIBS
)
1063 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
1068 static void GLAPIENTRY
1069 _save_VertexAttrib4fvARB( GLuint index
, const GLfloat
*v
)
1071 if (index
< MAX_VERTEX_ATTRIBS
)
1072 DISPATCH_ATTR4FV( index
, v
);
1080 * These are treated as per-vertex attributes, at indices above where
1081 * the NV_vertex_program leaves off. There are a lot of good things
1082 * about treating materials this way.
1084 * However: I don't want to double the number of generated functions
1085 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
1086 * ATTRF into this function, and dispense with codegen and
1087 * second-level dispatch.
1089 * There is no aliasing of material attributes with other entrypoints.
1091 #define MAT_ATTR( A, N, params ) \
1093 if (tnl->save.attrsz[A] < N) { \
1094 _save_upgrade_vertex( ctx, A, N ); \
1095 tnl->save.have_materials = GL_TRUE; \
1099 GLfloat *dest = tnl->save.attrptr[A]; \
1100 if (N>0) dest[0] = params[0]; \
1101 if (N>1) dest[1] = params[1]; \
1102 if (N>2) dest[2] = params[2]; \
1103 if (N>3) dest[3] = params[3]; \
1108 #define MAT( ATTR, N, face, params ) \
1110 if (face != GL_BACK) \
1111 MAT_ATTR( ATTR, N, params ); /* front */ \
1112 if (face != GL_FRONT) \
1113 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1117 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1118 * later on - in the meantime just store everything.
1120 static void GLAPIENTRY
_save_Materialfv( GLenum face
, GLenum pname
,
1121 const GLfloat
*params
)
1123 GET_CURRENT_CONTEXT( ctx
);
1124 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1128 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
1131 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1134 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1137 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
1140 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
1142 case GL_COLOR_INDEXES
:
1143 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
1145 case GL_AMBIENT_AND_DIFFUSE
:
1146 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
1147 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
1150 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
1156 #define IDX_ATTR( A, IDX ) \
1158 GET_CURRENT_CONTEXT( ctx ); \
1159 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1161 if (tnl->save.attrsz[A] < 1) { \
1162 _save_upgrade_vertex( ctx, A, 1 ); \
1166 GLfloat *dest = tnl->save.attrptr[A]; \
1172 static void GLAPIENTRY
_save_EdgeFlag( GLboolean b
)
1174 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
1178 static void GLAPIENTRY
_save_Indexf( GLfloat f
)
1180 IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX
, f
);
1183 static void GLAPIENTRY
_save_Indexfv( const GLfloat
*f
)
1185 IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX
, f
[0] );
1191 /* Cope with EvalCoord/CallList called within a begin/end object:
1192 * -- Flush current buffer
1193 * -- Fallback to opcodes for the rest of the begin/end object.
1195 #define FALLBACK(ctx) \
1197 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1199 if (tnl->save.initial_counter != tnl->save.counter || \
1200 tnl->save.prim_count) \
1201 _save_compile_vertex_list( ctx ); \
1203 _save_copy_to_current( ctx ); \
1204 _save_reset_vertex( ctx ); \
1205 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1206 ctx->Driver.SaveNeedFlush = 0; \
1209 static void GLAPIENTRY
_save_EvalCoord1f( GLfloat u
)
1211 GET_CURRENT_CONTEXT(ctx
);
1213 CALL_EvalCoord1f(ctx
->Save
, ( u
));
1216 static void GLAPIENTRY
_save_EvalCoord1fv( const GLfloat
*v
)
1218 GET_CURRENT_CONTEXT(ctx
);
1220 CALL_EvalCoord1fv(ctx
->Save
, ( v
));
1223 static void GLAPIENTRY
_save_EvalCoord2f( GLfloat u
, GLfloat v
)
1225 GET_CURRENT_CONTEXT(ctx
);
1227 CALL_EvalCoord2f(ctx
->Save
, ( u
, v
));
1230 static void GLAPIENTRY
_save_EvalCoord2fv( const GLfloat
*v
)
1232 GET_CURRENT_CONTEXT(ctx
);
1234 CALL_EvalCoord2fv(ctx
->Save
, ( v
));
1237 static void GLAPIENTRY
_save_EvalPoint1( GLint i
)
1239 GET_CURRENT_CONTEXT(ctx
);
1241 CALL_EvalPoint1(ctx
->Save
, ( i
));
1244 static void GLAPIENTRY
_save_EvalPoint2( GLint i
, GLint j
)
1246 GET_CURRENT_CONTEXT(ctx
);
1248 CALL_EvalPoint2(ctx
->Save
, ( i
, j
));
1251 static void GLAPIENTRY
_save_CallList( GLuint l
)
1253 GET_CURRENT_CONTEXT(ctx
);
1255 CALL_CallList(ctx
->Save
, ( l
));
1258 static void GLAPIENTRY
_save_CallLists( GLsizei n
, GLenum type
, const GLvoid
*v
)
1260 GET_CURRENT_CONTEXT(ctx
);
1262 CALL_CallLists(ctx
->Save
, ( n
, type
, v
));
1268 /* This begin is hooked into ... Updating of
1269 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1271 static GLboolean
_save_NotifyBegin( GLcontext
*ctx
, GLenum mode
)
1273 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1276 GLuint i
= tnl
->save
.prim_count
++;
1278 assert(i
< tnl
->save
.prim_max
);
1279 tnl
->save
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1280 tnl
->save
.prim
[i
].start
= tnl
->save
.initial_counter
- tnl
->save
.counter
;
1281 tnl
->save
.prim
[i
].count
= 0;
1283 _mesa_install_save_vtxfmt( ctx
, &tnl
->save_vtxfmt
);
1284 ctx
->Driver
.SaveNeedFlush
= 1;
1293 static void GLAPIENTRY
_save_End( void )
1295 GET_CURRENT_CONTEXT( ctx
);
1296 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1297 GLint i
= tnl
->save
.prim_count
- 1;
1299 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
1300 tnl
->save
.prim
[i
].mode
|= PRIM_END
;
1301 tnl
->save
.prim
[i
].count
= ((tnl
->save
.initial_counter
- tnl
->save
.counter
) -
1302 tnl
->save
.prim
[i
].start
);
1304 if (i
== (GLint
) tnl
->save
.prim_max
- 1) {
1305 _save_compile_vertex_list( ctx
);
1306 assert(tnl
->save
.copied
.nr
== 0);
1309 /* Swap out this vertex format while outside begin/end. Any color,
1310 * etc. received between here and the next begin will be compiled
1313 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1317 /* These are all errors as this vtxfmt is only installed inside
1320 static void GLAPIENTRY
_save_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1321 const GLvoid
*indices
)
1323 GET_CURRENT_CONTEXT(ctx
);
1324 (void) mode
; (void) count
; (void) type
; (void) indices
;
1325 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawElements" );
1329 static void GLAPIENTRY
_save_DrawRangeElements(GLenum mode
,
1330 GLuint start
, GLuint end
,
1331 GLsizei count
, GLenum type
,
1332 const GLvoid
*indices
)
1334 GET_CURRENT_CONTEXT(ctx
);
1335 (void) mode
; (void) start
; (void) end
; (void) count
; (void) type
; (void) indices
;
1336 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawRangeElements" );
1339 static void GLAPIENTRY
_save_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1341 GET_CURRENT_CONTEXT(ctx
);
1342 (void) mode
; (void) start
; (void) count
;
1343 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glDrawArrays" );
1346 static void GLAPIENTRY
_save_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1348 GET_CURRENT_CONTEXT(ctx
);
1349 (void) x1
; (void) y1
; (void) x2
; (void) y2
;
1350 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glRectf" );
1353 static void GLAPIENTRY
_save_EvalMesh1( GLenum mode
, GLint i1
, GLint i2
)
1355 GET_CURRENT_CONTEXT(ctx
);
1356 (void) mode
; (void) i1
; (void) i2
;
1357 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh1" );
1360 static void GLAPIENTRY
_save_EvalMesh2( GLenum mode
, GLint i1
, GLint i2
,
1361 GLint j1
, GLint j2
)
1363 GET_CURRENT_CONTEXT(ctx
);
1364 (void) mode
; (void) i1
; (void) i2
; (void) j1
; (void) j2
;
1365 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "glEvalMesh2" );
1368 static void GLAPIENTRY
_save_Begin( GLenum mode
)
1370 GET_CURRENT_CONTEXT( ctx
);
1372 _mesa_compile_error( ctx
, GL_INVALID_OPERATION
, "Recursive glBegin" );
1376 /* Unlike the functions above, these are to be hooked into the vtxfmt
1377 * maintained in ctx->ListState, active when the list is known or
1378 * suspected to be outside any begin/end primitive.
1380 static void GLAPIENTRY
_save_OBE_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1382 GET_CURRENT_CONTEXT(ctx
);
1383 _save_NotifyBegin( ctx
, GL_QUADS
| PRIM_WEAK
);
1384 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y1
));
1385 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y1
));
1386 CALL_Vertex2f(GET_DISPATCH(), ( x2
, y2
));
1387 CALL_Vertex2f(GET_DISPATCH(), ( x1
, y2
));
1388 CALL_End(GET_DISPATCH(), ());
1392 static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode
, GLint start
, GLsizei count
)
1394 GET_CURRENT_CONTEXT(ctx
);
1397 if (!_mesa_validate_DrawArrays( ctx
, mode
, start
, count
))
1400 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1401 for (i
= 0; i
< count
; i
++)
1402 CALL_ArrayElement(GET_DISPATCH(), (start
+ i
));
1403 CALL_End(GET_DISPATCH(), ());
1407 static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
1408 const GLvoid
*indices
)
1410 GET_CURRENT_CONTEXT(ctx
);
1413 if (!_mesa_validate_DrawElements( ctx
, mode
, count
, type
, indices
))
1416 _save_NotifyBegin( ctx
, mode
| PRIM_WEAK
);
1419 case GL_UNSIGNED_BYTE
:
1420 for (i
= 0 ; i
< count
; i
++)
1421 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte
*)indices
)[i
] ));
1423 case GL_UNSIGNED_SHORT
:
1424 for (i
= 0 ; i
< count
; i
++)
1425 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort
*)indices
)[i
] ));
1427 case GL_UNSIGNED_INT
:
1428 for (i
= 0 ; i
< count
; i
++)
1429 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint
*)indices
)[i
] ));
1432 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawElements(type)" );
1436 CALL_End(GET_DISPATCH(), ());
1439 static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode
,
1440 GLuint start
, GLuint end
,
1441 GLsizei count
, GLenum type
,
1442 const GLvoid
*indices
)
1444 GET_CURRENT_CONTEXT(ctx
);
1445 if (_mesa_validate_DrawRangeElements( ctx
, mode
,
1447 count
, type
, indices
))
1448 _save_OBE_DrawElements( mode
, count
, type
, indices
);
1455 static void _save_vtxfmt_init( GLcontext
*ctx
)
1457 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1458 GLvertexformat
*vfmt
= &tnl
->save_vtxfmt
;
1460 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1461 vfmt
->Begin
= _save_Begin
;
1462 vfmt
->Color3f
= _save_Color3f
;
1463 vfmt
->Color3fv
= _save_Color3fv
;
1464 vfmt
->Color4f
= _save_Color4f
;
1465 vfmt
->Color4fv
= _save_Color4fv
;
1466 vfmt
->EdgeFlag
= _save_EdgeFlag
;
1467 vfmt
->End
= _save_End
;
1468 vfmt
->FogCoordfEXT
= _save_FogCoordfEXT
;
1469 vfmt
->FogCoordfvEXT
= _save_FogCoordfvEXT
;
1470 vfmt
->Indexf
= _save_Indexf
;
1471 vfmt
->Indexfv
= _save_Indexfv
;
1472 vfmt
->Materialfv
= _save_Materialfv
;
1473 vfmt
->MultiTexCoord1fARB
= _save_MultiTexCoord1f
;
1474 vfmt
->MultiTexCoord1fvARB
= _save_MultiTexCoord1fv
;
1475 vfmt
->MultiTexCoord2fARB
= _save_MultiTexCoord2f
;
1476 vfmt
->MultiTexCoord2fvARB
= _save_MultiTexCoord2fv
;
1477 vfmt
->MultiTexCoord3fARB
= _save_MultiTexCoord3f
;
1478 vfmt
->MultiTexCoord3fvARB
= _save_MultiTexCoord3fv
;
1479 vfmt
->MultiTexCoord4fARB
= _save_MultiTexCoord4f
;
1480 vfmt
->MultiTexCoord4fvARB
= _save_MultiTexCoord4fv
;
1481 vfmt
->Normal3f
= _save_Normal3f
;
1482 vfmt
->Normal3fv
= _save_Normal3fv
;
1483 vfmt
->SecondaryColor3fEXT
= _save_SecondaryColor3fEXT
;
1484 vfmt
->SecondaryColor3fvEXT
= _save_SecondaryColor3fvEXT
;
1485 vfmt
->TexCoord1f
= _save_TexCoord1f
;
1486 vfmt
->TexCoord1fv
= _save_TexCoord1fv
;
1487 vfmt
->TexCoord2f
= _save_TexCoord2f
;
1488 vfmt
->TexCoord2fv
= _save_TexCoord2fv
;
1489 vfmt
->TexCoord3f
= _save_TexCoord3f
;
1490 vfmt
->TexCoord3fv
= _save_TexCoord3fv
;
1491 vfmt
->TexCoord4f
= _save_TexCoord4f
;
1492 vfmt
->TexCoord4fv
= _save_TexCoord4fv
;
1493 vfmt
->Vertex2f
= _save_Vertex2f
;
1494 vfmt
->Vertex2fv
= _save_Vertex2fv
;
1495 vfmt
->Vertex3f
= _save_Vertex3f
;
1496 vfmt
->Vertex3fv
= _save_Vertex3fv
;
1497 vfmt
->Vertex4f
= _save_Vertex4f
;
1498 vfmt
->Vertex4fv
= _save_Vertex4fv
;
1499 vfmt
->VertexAttrib1fNV
= _save_VertexAttrib1fNV
;
1500 vfmt
->VertexAttrib1fvNV
= _save_VertexAttrib1fvNV
;
1501 vfmt
->VertexAttrib2fNV
= _save_VertexAttrib2fNV
;
1502 vfmt
->VertexAttrib2fvNV
= _save_VertexAttrib2fvNV
;
1503 vfmt
->VertexAttrib3fNV
= _save_VertexAttrib3fNV
;
1504 vfmt
->VertexAttrib3fvNV
= _save_VertexAttrib3fvNV
;
1505 vfmt
->VertexAttrib4fNV
= _save_VertexAttrib4fNV
;
1506 vfmt
->VertexAttrib4fvNV
= _save_VertexAttrib4fvNV
;
1507 vfmt
->VertexAttrib1fARB
= _save_VertexAttrib1fARB
;
1508 vfmt
->VertexAttrib1fvARB
= _save_VertexAttrib1fvARB
;
1509 vfmt
->VertexAttrib2fARB
= _save_VertexAttrib2fARB
;
1510 vfmt
->VertexAttrib2fvARB
= _save_VertexAttrib2fvARB
;
1511 vfmt
->VertexAttrib3fARB
= _save_VertexAttrib3fARB
;
1512 vfmt
->VertexAttrib3fvARB
= _save_VertexAttrib3fvARB
;
1513 vfmt
->VertexAttrib4fARB
= _save_VertexAttrib4fARB
;
1514 vfmt
->VertexAttrib4fvARB
= _save_VertexAttrib4fvARB
;
1516 /* This will all require us to fallback to saving the list as opcodes:
1518 vfmt
->CallList
= _save_CallList
; /* inside begin/end */
1519 vfmt
->CallLists
= _save_CallLists
; /* inside begin/end */
1520 vfmt
->EvalCoord1f
= _save_EvalCoord1f
;
1521 vfmt
->EvalCoord1fv
= _save_EvalCoord1fv
;
1522 vfmt
->EvalCoord2f
= _save_EvalCoord2f
;
1523 vfmt
->EvalCoord2fv
= _save_EvalCoord2fv
;
1524 vfmt
->EvalPoint1
= _save_EvalPoint1
;
1525 vfmt
->EvalPoint2
= _save_EvalPoint2
;
1527 /* These are all errors as we at least know we are in some sort of
1530 vfmt
->EvalMesh1
= _save_EvalMesh1
;
1531 vfmt
->EvalMesh2
= _save_EvalMesh2
;
1532 vfmt
->Begin
= _save_Begin
;
1533 vfmt
->Rectf
= _save_Rectf
;
1534 vfmt
->DrawArrays
= _save_DrawArrays
;
1535 vfmt
->DrawElements
= _save_DrawElements
;
1536 vfmt
->DrawRangeElements
= _save_DrawRangeElements
;
1541 void _tnl_SaveFlushVertices( GLcontext
*ctx
)
1543 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1545 /* Noop when we are actually active:
1547 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_INSIDE_UNKNOWN_PRIM
||
1548 ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
)
1551 if (tnl
->save
.initial_counter
!= tnl
->save
.counter
||
1552 tnl
->save
.prim_count
)
1553 _save_compile_vertex_list( ctx
);
1555 _save_copy_to_current( ctx
);
1556 _save_reset_vertex( ctx
);
1557 ctx
->Driver
.SaveNeedFlush
= 0;
1560 void _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
1562 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1564 (void) list
; (void) mode
;
1566 if (!tnl
->save
.prim_store
)
1567 tnl
->save
.prim_store
= alloc_prim_store( ctx
);
1569 if (!tnl
->save
.vertex_store
) {
1570 tnl
->save
.vertex_store
= alloc_vertex_store( ctx
);
1571 tnl
->save
.vbptr
= tnl
->save
.vertex_store
->buffer
;
1574 _save_reset_vertex( ctx
);
1575 ctx
->Driver
.SaveNeedFlush
= 0;
1578 void _tnl_EndList( GLcontext
*ctx
)
1581 assert(TNL_CONTEXT(ctx
)->save
.vertex_size
== 0);
1584 void _tnl_BeginCallList( GLcontext
*ctx
, struct mesa_display_list
*dlist
)
1586 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1587 tnl
->save
.replay_flags
|= dlist
->flags
;
1588 tnl
->save
.replay_flags
|= tnl
->LoopbackDListCassettes
;
1591 void _tnl_EndCallList( GLcontext
*ctx
)
1593 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1595 if (ctx
->ListState
.CallDepth
== 1)
1596 tnl
->save
.replay_flags
= 0;
1600 static void _tnl_destroy_vertex_list( GLcontext
*ctx
, void *data
)
1602 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1605 if ( --node
->vertex_store
->refcount
== 0 )
1606 FREE( node
->vertex_store
);
1608 if ( --node
->prim_store
->refcount
== 0 )
1609 FREE( node
->prim_store
);
1611 if ( node
->normal_lengths
)
1612 FREE( node
->normal_lengths
);
1616 static void _tnl_print_vertex_list( GLcontext
*ctx
, void *data
)
1618 struct tnl_vertex_list
*node
= (struct tnl_vertex_list
*)data
;
1622 _mesa_debug(NULL
, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1627 for (i
= 0 ; i
< node
->prim_count
; i
++) {
1628 struct tnl_prim
*prim
= &node
->prim
[i
];
1629 _mesa_debug(NULL
, " prim %d: %s %d..%d %s %s\n",
1631 _mesa_lookup_enum_by_nr(prim
->mode
& PRIM_MODE_MASK
),
1633 prim
->start
+ prim
->count
,
1634 (prim
->mode
& PRIM_BEGIN
) ? "BEGIN" : "(wrap)",
1635 (prim
->mode
& PRIM_END
) ? "END" : "(wrap)");
1640 static void _save_current_init( GLcontext
*ctx
)
1642 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1645 for (i
= 0; i
< _TNL_ATTRIB_MAT_FRONT_AMBIENT
; i
++) {
1646 ASSERT(i
< VERT_ATTRIB_MAX
);
1647 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveAttribSize
[i
];
1648 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentAttrib
[i
];
1651 for (i
= _TNL_FIRST_MAT
; i
<= _TNL_LAST_MAT
; i
++) {
1652 const GLuint j
= i
- _TNL_FIRST_MAT
;
1653 ASSERT(j
< MAT_ATTRIB_MAX
);
1654 tnl
->save
.currentsz
[i
] = &ctx
->ListState
.ActiveMaterialSize
[j
];
1655 tnl
->save
.current
[i
] = ctx
->ListState
.CurrentMaterial
[j
];
1658 tnl
->save
.currentsz
[_TNL_ATTRIB_EDGEFLAG
] = &ctx
->ListState
.ActiveEdgeFlag
;
1659 tnl
->save
.current
[_TNL_ATTRIB_EDGEFLAG
] = &tnl
->save
.CurrentFloatEdgeFlag
;
1663 * Initialize the display list compiler
1665 void _tnl_save_init( GLcontext
*ctx
)
1667 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1668 struct tnl_vertex_arrays
*tmp
= &tnl
->save_inputs
;
1672 for (i
= 0; i
< _TNL_ATTRIB_MAX
; i
++)
1673 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, NULL
);
1675 tnl
->save
.opcode_vertex_list
=
1676 _mesa_alloc_opcode( ctx
,
1677 sizeof(struct tnl_vertex_list
),
1678 _tnl_playback_vertex_list
,
1679 _tnl_destroy_vertex_list
,
1680 _tnl_print_vertex_list
);
1682 ctx
->Driver
.NotifySaveBegin
= _save_NotifyBegin
;
1684 _save_vtxfmt_init( ctx
);
1685 _save_current_init( ctx
);
1687 /* Hook our array functions into the outside-begin-end vtxfmt in
1690 ctx
->ListState
.ListVtxfmt
.Rectf
= _save_OBE_Rectf
;
1691 ctx
->ListState
.ListVtxfmt
.DrawArrays
= _save_OBE_DrawArrays
;
1692 ctx
->ListState
.ListVtxfmt
.DrawElements
= _save_OBE_DrawElements
;
1693 ctx
->ListState
.ListVtxfmt
.DrawRangeElements
= _save_OBE_DrawRangeElements
;
1694 _mesa_install_save_vtxfmt( ctx
, &ctx
->ListState
.ListVtxfmt
);
1699 * Deallocate the immediate-mode buffer for the given context, if
1700 * its reference count goes to zero.
1702 void _tnl_save_destroy( GLcontext
*ctx
)
1704 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1706 /* Decrement the refcounts. References may still be held by
1707 * display lists yet to be destroyed, so it may not yet be time to
1710 if (tnl
->save
.prim_store
&&
1711 --tnl
->save
.prim_store
->refcount
== 0 )
1712 FREE( tnl
->save
.prim_store
);
1714 if (tnl
->save
.vertex_store
&&
1715 --tnl
->save
.vertex_store
->refcount
== 0 )
1716 FREE( tnl
->save
.vertex_store
);