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>
41 #include "api_arrayelt.h"
43 #include "t_vtx_api.h"
44 #include "simple_list.h"
46 static void reset_attrfv( TNLcontext
*tnl
);
48 static tnl_attrfv_func choose
[_TNL_MAX_ATTR_CODEGEN
+1][4]; /* +1 for ERROR_ATTRIB */
49 static tnl_attrfv_func generic_attr_func
[_TNL_MAX_ATTR_CODEGEN
][4];
52 /* Close off the last primitive, execute the buffer, restart the
55 static void _tnl_wrap_buffers( GLcontext
*ctx
)
57 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
60 if (tnl
->vtx
.prim_count
== 0) {
61 tnl
->vtx
.copied
.nr
= 0;
62 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
63 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
66 GLuint last_prim
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].mode
;
67 GLuint last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
69 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
70 GLint i
= tnl
->vtx
.prim_count
- 1;
72 tnl
->vtx
.prim
[i
].count
= ((tnl
->vtx
.initial_counter
-
74 tnl
->vtx
.prim
[i
].start
);
77 /* Execute the buffer and save copied vertices.
79 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
)
80 _tnl_flush_vtx( ctx
);
82 tnl
->vtx
.prim_count
= 0;
83 tnl
->vtx
.copied
.nr
= 0;
86 /* Emit a glBegin to start the new list.
88 assert(tnl
->vtx
.prim_count
== 0);
90 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
91 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
92 tnl
->vtx
.prim
[0].start
= 0;
93 tnl
->vtx
.prim
[0].count
= 0;
94 tnl
->vtx
.prim_count
++;
96 if (tnl
->vtx
.copied
.nr
== last_count
)
97 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
103 /* Deal with buffer wrapping where provoked by the vertex buffer
104 * filling up, as opposed to upgrade_vertex().
106 * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
108 void GLAPIENTRY
_tnl_wrap_filled_vertex( GLcontext
*ctx
)
110 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
111 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
114 /* Run pipeline on current vertices, copy wrapped vertices
117 _tnl_wrap_buffers( ctx
);
119 /* Copy stored stored vertices to start of new list.
121 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
123 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
124 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
125 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
126 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
127 data
+= tnl
->vtx
.vertex_size
;
131 tnl
->vtx
.copied
.nr
= 0;
136 * Copy the active vertex's values to the ctx->Current fields.
138 static void _tnl_copy_to_current( GLcontext
*ctx
)
140 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
143 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
144 if (tnl
->vtx
.attrsz
[i
]) {
145 /* Note: the tnl->vtx.current[i] pointers points to
146 * the ctx->Current fields. The first 16 or so, anyway.
148 ASSIGN_4V( tnl
->vtx
.current
[i
], 0, 0, 0, 1 );
149 COPY_SZ_4V(tnl
->vtx
.current
[i
],
151 tnl
->vtx
.attrptr
[i
]);
154 /* Edgeflag requires special treatment:
156 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
157 ctx
->Current
.EdgeFlag
=
158 (tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
161 /* Colormaterial -- this kindof sucks.
163 if (ctx
->Light
.ColorMaterialEnabled
) {
164 _mesa_update_color_material(ctx
,
165 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
168 if (tnl
->vtx
.have_materials
) {
169 tnl
->Driver
.NotifyMaterialChange( ctx
);
172 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
176 static void _tnl_copy_from_current( GLcontext
*ctx
)
178 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
181 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
182 switch (tnl
->vtx
.attrsz
[i
]) {
183 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
184 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
185 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
186 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
190 /* Edgeflag requires special treatment:
192 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
193 tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
194 (GLfloat
)ctx
->Current
.EdgeFlag
;
197 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
201 /* Flush existing data, set new attrib size, replay copied vertices.
203 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
207 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
211 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
213 /* Run pipeline on current vertices, copy wrapped vertices
214 * to tnl->vtx.copied.
216 _tnl_wrap_buffers( ctx
);
219 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
220 * when the attribute already exists in the vertex and is having
221 * its size increased.
223 _tnl_copy_to_current( ctx
);
226 /* Heuristic: Attempt to isolate attributes received outside
227 * begin/end so that they don't bloat the vertices.
229 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
230 tnl
->vtx
.attrsz
[attr
] == 0 &&
232 tnl
->vtx
.vertex_size
) {
238 oldsz
= tnl
->vtx
.attrsz
[attr
];
239 tnl
->vtx
.attrsz
[attr
] = newsz
;
241 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
242 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
243 ctx
->Const
.MaxArrayLockSize
);
244 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
245 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
248 /* Recalculate all the attrptr[] values
250 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
251 if (tnl
->vtx
.attrsz
[i
]) {
252 tnl
->vtx
.attrptr
[i
] = tmp
;
253 tmp
+= tnl
->vtx
.attrsz
[i
];
256 tnl
->vtx
.attrptr
[i
] = 0; /* will not be dereferenced */
259 /* Copy from current to repopulate the vertex with correct values.
261 _tnl_copy_from_current( ctx
);
263 /* Replay stored vertices to translate them
264 * to new format here.
266 * -- No need to replay - just copy piecewise
268 if (tnl
->vtx
.copied
.nr
)
270 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
271 GLfloat
*dest
= tnl
->vtx
.buffer
;
274 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
275 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
276 if (tnl
->vtx
.attrsz
[j
]) {
279 ASSIGN_4V( dest
, 0, 0, 0, 1 );
280 COPY_SZ_4V( dest
, oldsz
, data
);
284 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
289 GLuint sz
= tnl
->vtx
.attrsz
[j
];
290 COPY_SZ_4V( dest
, sz
, data
);
298 tnl
->vtx
.vbptr
= dest
;
299 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
300 tnl
->vtx
.copied
.nr
= 0;
303 /* For codegen - attrptr's may have changed, so need to redo
304 * codegen. Might be a reasonable place to try & detect attributes
305 * in the vertex which aren't being submitted any more.
307 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
308 if (tnl
->vtx
.attrsz
[i
]) {
309 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
311 if (i
< _TNL_MAX_ATTR_CODEGEN
)
312 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
318 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
320 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
321 static const GLfloat id
[4] = { 0, 0, 0, 1 };
324 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
325 /* New size is larger. Need to flush existing vertices and get
326 * an enlarged vertex format.
328 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
330 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
331 /* New size is smaller - just need to fill in some
332 * zeros. Don't need to flush or wrap.
334 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
335 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
338 /* Does setting NeedFlush belong here? Necessitates resetting
339 * vtxfmt on each flush (otherwise flags won't get reset
343 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
345 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
349 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
351 struct _tnl_dynfn
*f
;
362 static tnl_attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
364 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
365 struct _tnl_dynfn
*dfn
= 0;
368 GLuint key
= tnl
->vtx
.vertex_size
;
370 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
373 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
376 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
378 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
381 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
385 return (tnl_attrfv_func
) dfn
->code
;
390 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
391 * entrypoint is called for the first time.
394 static tnl_attrfv_func
do_choose( GLuint attr
, GLuint sz
)
396 GET_CURRENT_CONTEXT( ctx
);
397 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
398 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
400 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
403 /* Reset any active pointers for this attribute
406 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
408 _tnl_fixup_vertex( ctx
, attr
, sz
);
413 /* Try to use codegen:
416 if (tnl
->AllowCodegen
)
417 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
420 tnl
->vtx
.tabfv
[attr
][sz
-1] = 0;
422 /* Else use generic version:
424 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
425 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
427 return tnl
->vtx
.tabfv
[attr
][sz
-1];
432 #define CHOOSE( ATTR, N ) \
433 static void choose_##ATTR##_##N( const GLfloat *v ) \
435 tnl_attrfv_func f = do_choose(ATTR, N); \
439 #define CHOOSERS( ATTRIB ) \
440 CHOOSE( ATTRIB, 1 ) \
441 CHOOSE( ATTRIB, 2 ) \
442 CHOOSE( ATTRIB, 3 ) \
443 CHOOSE( ATTRIB, 4 ) \
446 #define INIT_CHOOSERS(ATTR) \
447 choose[ATTR][0] = choose_##ATTR##_1; \
448 choose[ATTR][1] = choose_##ATTR##_2; \
449 choose[ATTR][2] = choose_##ATTR##_3; \
450 choose[ATTR][3] = choose_##ATTR##_4;
469 static void error_attrib( const GLfloat
*unused
)
471 GET_CURRENT_CONTEXT( ctx
);
473 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
478 static void reset_attrfv( TNLcontext
*tnl
)
482 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
483 if (tnl
->vtx
.attrsz
[i
]) {
484 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
485 tnl
->vtx
.attrsz
[i
] = 0;
487 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
489 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
495 tnl
->vtx
.vertex_size
= 0;
496 tnl
->vtx
.have_materials
= 0;
503 * These are treated as per-vertex attributes, at indices above where
504 * the NV_vertex_program leaves off. There are a lot of good things
505 * about treating materials this way.
507 * However: I don't want to double the number of generated functions
508 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
509 * ATTRF into this function, and dispense with codegen and
510 * second-level dispatch.
512 * There is no aliasing of material attributes with other entrypoints.
514 #define OTHER_ATTR( A, N, params ) \
516 if (tnl->vtx.attrsz[A] != N) { \
517 _tnl_fixup_vertex( ctx, A, N ); \
521 GLfloat *dest = tnl->vtx.attrptr[A]; \
522 if (N>0) dest[0] = (params)[0]; \
523 if (N>1) dest[1] = (params)[1]; \
524 if (N>2) dest[2] = (params)[2]; \
525 if (N>3) dest[3] = (params)[3]; \
530 #define MAT( ATTR, N, face, params ) \
532 if (face != GL_BACK) \
533 OTHER_ATTR( ATTR, N, params ); /* front */ \
534 if (face != GL_FRONT) \
535 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
539 /* Colormaterial is dealt with later on.
541 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
542 const GLfloat
*params
)
544 GET_CURRENT_CONTEXT( ctx
);
545 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
550 case GL_FRONT_AND_BACK
:
554 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
560 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
563 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
566 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
569 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
572 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
574 case GL_COLOR_INDEXES
:
575 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
577 case GL_AMBIENT_AND_DIFFUSE
:
578 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
579 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
582 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
586 tnl
->vtx
.have_materials
= GL_TRUE
;
590 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
592 GET_CURRENT_CONTEXT( ctx
);
593 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
594 GLfloat f
= (GLfloat
)b
;
596 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
599 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
601 GET_CURRENT_CONTEXT( ctx
);
602 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
603 GLfloat f
= (GLfloat
)v
[0];
605 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
608 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
610 GET_CURRENT_CONTEXT( ctx
);
611 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
613 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, &f
);
616 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
618 GET_CURRENT_CONTEXT( ctx
);
619 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
621 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, v
);
626 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
628 GET_CURRENT_CONTEXT( ctx
);
629 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
631 /* TODO: use a CHOOSE() function for this: */
634 if (tnl
->vtx
.eval
.new_state
)
635 _tnl_update_eval( ctx
);
637 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
638 if (tnl
->vtx
.eval
.map1
[i
].map
)
639 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
640 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
645 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
646 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
648 _tnl_do_EvalCoord1f( ctx
, u
);
650 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
651 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
654 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
656 GET_CURRENT_CONTEXT( ctx
);
657 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
659 /* TODO: use a CHOOSE() function for this: */
662 if (tnl
->vtx
.eval
.new_state
)
663 _tnl_update_eval( ctx
);
665 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
666 if (tnl
->vtx
.eval
.map2
[i
].map
)
667 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
668 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
671 if (ctx
->Eval
.AutoNormal
)
672 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] != 3)
673 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
676 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
677 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
679 _tnl_do_EvalCoord2f( ctx
, u
, v
);
681 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
682 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
685 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
687 _tnl_EvalCoord1f( u
[0] );
690 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
692 _tnl_EvalCoord2f( u
[0], u
[1] );
695 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
697 GET_CURRENT_CONTEXT( ctx
);
698 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
699 (GLfloat
) ctx
->Eval
.MapGrid1un
);
700 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
702 _tnl_EvalCoord1f( u
);
706 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
708 GET_CURRENT_CONTEXT( ctx
);
709 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
710 (GLfloat
) ctx
->Eval
.MapGrid2un
);
711 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
712 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
713 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
714 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
716 _tnl_EvalCoord2f( u
, v
);
720 /* Build a list of primitives on the fly. Keep
721 * ctx->Driver.CurrentExecPrimitive uptodate as well.
723 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
725 GET_CURRENT_CONTEXT( ctx
);
727 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
728 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
732 _mesa_update_state( ctx
);
734 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
735 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
736 _mesa_error(ctx
, GL_INVALID_OPERATION
,
737 "glBegin (invalid vertex/fragment program)");
741 if (!(tnl
->Driver
.NotifyBegin
&&
742 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
743 ctx
->Exec
->Begin(mode
);
747 /* Heuristic: attempt to isolate attributes occuring outside
750 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
751 _tnl_FlushVertices( ctx
, ~0 );
753 i
= tnl
->vtx
.prim_count
++;
754 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
755 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
756 tnl
->vtx
.prim
[i
].count
= 0;
758 ctx
->Driver
.CurrentExecPrimitive
= mode
;
761 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
765 static void GLAPIENTRY
_tnl_End( void )
767 GET_CURRENT_CONTEXT( ctx
);
769 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
770 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
771 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
772 int i
= tnl
->vtx
.prim_count
- 1;
774 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
775 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
777 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
779 /* Two choices which effect the way vertex attributes are
780 * carried over (or not) between adjacent primitives.
783 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
784 _tnl_FlushVertices( ctx
, ~0 );
786 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
787 _tnl_flush_vtx( ctx
);
792 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
796 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
798 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
800 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
801 vfmt
->Begin
= _tnl_Begin
;
802 vfmt
->CallList
= _mesa_CallList
;
803 vfmt
->CallLists
= _mesa_CallLists
;
804 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
805 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
806 vfmt
->End
= _tnl_End
;
807 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
808 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
809 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
810 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
811 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
812 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
813 vfmt
->Indexf
= _tnl_Indexf
;
814 vfmt
->Indexfv
= _tnl_Indexfv
;
815 vfmt
->Materialfv
= _tnl_Materialfv
;
817 vfmt
->Rectf
= _mesa_noop_Rectf
;
818 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
819 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
824 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
826 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
828 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
831 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
832 _tnl_flush_vtx( ctx
);
835 if (tnl
->vtx
.vertex_size
) {
836 _tnl_copy_to_current( ctx
);
840 ctx
->Driver
.NeedFlush
= 0;
844 static void _tnl_current_init( GLcontext
*ctx
)
846 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
849 /* setup the pointers for the typical 16 vertex attributes */
850 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
851 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
853 /* setup pointers for the 12 material attributes */
854 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
855 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
856 ctx
->Light
.Material
.Attrib
[i
];
858 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
861 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
866 void _tnl_vtx_init( GLcontext
*ctx
)
868 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
869 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
871 static int firsttime
= 1;
893 choose
[ERROR_ATTRIB
][0] = error_attrib
;
894 choose
[ERROR_ATTRIB
][1] = error_attrib
;
895 choose
[ERROR_ATTRIB
][2] = error_attrib
;
896 choose
[ERROR_ATTRIB
][3] = error_attrib
;
899 if (tnl
->AllowCodegen
) {
900 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
904 _tnl_generic_attr_table_init( generic_attr_func
);
907 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
908 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
910 for (i
= 0; i
< 4; i
++) {
911 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
912 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
913 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
914 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
918 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
921 _tnl_current_init( ctx
);
922 _tnl_exec_vtxfmt_init( ctx
);
923 _tnl_generic_exec_vtxfmt_init( ctx
);
925 if (tnl
->AllowCodegen
) {
926 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
930 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
932 memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
934 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
935 tnl
->vtx
.attrsz
[i
] = 0;
937 tnl
->vtx
.vertex_size
= 0;
938 tnl
->vtx
.have_materials
= 0;
941 static void free_funcs( struct _tnl_dynfn
*l
)
943 struct _tnl_dynfn
*f
, *tmp
;
944 foreach_s (f
, tmp
, l
) {
945 remove_from_list( f
);
946 ALIGN_FREE( f
->code
);
952 void _tnl_vtx_destroy( GLcontext
*ctx
)
954 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
957 for (i
= 0; i
< 4; i
++) {
958 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
959 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );