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
;
350 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
352 struct _tnl_dynfn
*f
;
363 static tnl_attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
365 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
366 struct _tnl_dynfn
*dfn
= 0;
369 GLuint key
= tnl
->vtx
.vertex_size
;
371 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
374 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
377 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
379 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
382 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
386 return *(tnl_attrfv_func
*) &dfn
->code
;
391 #endif /* USE_X86_ASM */
393 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
394 * entrypoint is called for the first time.
397 static tnl_attrfv_func
do_choose( GLuint attr
, GLuint sz
)
399 GET_CURRENT_CONTEXT( ctx
);
400 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
401 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
403 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
406 /* Reset any active pointers for this attribute
409 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
411 _tnl_fixup_vertex( ctx
, attr
, sz
);
416 /* Try to use codegen:
419 if (tnl
->AllowCodegen
)
420 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
423 tnl
->vtx
.tabfv
[attr
][sz
-1] = 0;
425 /* Else use generic version:
427 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
428 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
430 return tnl
->vtx
.tabfv
[attr
][sz
-1];
435 #define CHOOSE( ATTR, N ) \
436 static void choose_##ATTR##_##N( const GLfloat *v ) \
438 tnl_attrfv_func f = do_choose(ATTR, N); \
442 #define CHOOSERS( ATTRIB ) \
443 CHOOSE( ATTRIB, 1 ) \
444 CHOOSE( ATTRIB, 2 ) \
445 CHOOSE( ATTRIB, 3 ) \
446 CHOOSE( ATTRIB, 4 ) \
449 #define INIT_CHOOSERS(ATTR) \
450 choose[ATTR][0] = choose_##ATTR##_1; \
451 choose[ATTR][1] = choose_##ATTR##_2; \
452 choose[ATTR][2] = choose_##ATTR##_3; \
453 choose[ATTR][3] = choose_##ATTR##_4;
472 static void error_attrib( const GLfloat
*unused
)
474 GET_CURRENT_CONTEXT( ctx
);
476 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
481 static void reset_attrfv( TNLcontext
*tnl
)
485 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
486 if (tnl
->vtx
.attrsz
[i
]) {
487 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
488 tnl
->vtx
.attrsz
[i
] = 0;
490 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
492 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
498 tnl
->vtx
.vertex_size
= 0;
499 tnl
->vtx
.have_materials
= 0;
506 * These are treated as per-vertex attributes, at indices above where
507 * the NV_vertex_program leaves off. There are a lot of good things
508 * about treating materials this way.
510 * However: I don't want to double the number of generated functions
511 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
512 * ATTRF into this function, and dispense with codegen and
513 * second-level dispatch.
515 * There is no aliasing of material attributes with other entrypoints.
517 #define OTHER_ATTR( A, N, params ) \
519 if (tnl->vtx.attrsz[A] != N) { \
520 _tnl_fixup_vertex( ctx, A, N ); \
524 GLfloat *dest = tnl->vtx.attrptr[A]; \
525 if (N>0) dest[0] = (params)[0]; \
526 if (N>1) dest[1] = (params)[1]; \
527 if (N>2) dest[2] = (params)[2]; \
528 if (N>3) dest[3] = (params)[3]; \
533 #define MAT( ATTR, N, face, params ) \
535 if (face != GL_BACK) \
536 OTHER_ATTR( ATTR, N, params ); /* front */ \
537 if (face != GL_FRONT) \
538 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
542 /* Colormaterial is dealt with later on.
544 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
545 const GLfloat
*params
)
547 GET_CURRENT_CONTEXT( ctx
);
548 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
553 case GL_FRONT_AND_BACK
:
557 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
563 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
566 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
569 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
572 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
575 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
577 case GL_COLOR_INDEXES
:
578 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
580 case GL_AMBIENT_AND_DIFFUSE
:
581 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
582 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
585 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
589 tnl
->vtx
.have_materials
= GL_TRUE
;
593 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
595 GET_CURRENT_CONTEXT( ctx
);
596 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
597 GLfloat f
= (GLfloat
)b
;
599 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
602 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
604 GET_CURRENT_CONTEXT( ctx
);
605 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
606 GLfloat f
= (GLfloat
)v
[0];
608 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
611 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
613 GET_CURRENT_CONTEXT( ctx
);
614 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
616 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, &f
);
619 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
621 GET_CURRENT_CONTEXT( ctx
);
622 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
624 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, v
);
629 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
631 GET_CURRENT_CONTEXT( ctx
);
632 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
634 /* TODO: use a CHOOSE() function for this: */
637 if (tnl
->vtx
.eval
.new_state
)
638 _tnl_update_eval( ctx
);
640 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
641 if (tnl
->vtx
.eval
.map1
[i
].map
)
642 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
643 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
648 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
649 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
651 _tnl_do_EvalCoord1f( ctx
, u
);
653 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
654 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
657 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
659 GET_CURRENT_CONTEXT( ctx
);
660 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
662 /* TODO: use a CHOOSE() function for this: */
665 if (tnl
->vtx
.eval
.new_state
)
666 _tnl_update_eval( ctx
);
668 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
669 if (tnl
->vtx
.eval
.map2
[i
].map
)
670 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
671 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
674 if (ctx
->Eval
.AutoNormal
)
675 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] != 3)
676 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
679 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
680 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
682 _tnl_do_EvalCoord2f( ctx
, u
, v
);
684 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
685 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
688 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
690 _tnl_EvalCoord1f( u
[0] );
693 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
695 _tnl_EvalCoord2f( u
[0], u
[1] );
698 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
700 GET_CURRENT_CONTEXT( ctx
);
701 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
702 (GLfloat
) ctx
->Eval
.MapGrid1un
);
703 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
705 _tnl_EvalCoord1f( u
);
709 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
711 GET_CURRENT_CONTEXT( ctx
);
712 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
713 (GLfloat
) ctx
->Eval
.MapGrid2un
);
714 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
715 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
716 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
717 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
719 _tnl_EvalCoord2f( u
, v
);
723 /* Build a list of primitives on the fly. Keep
724 * ctx->Driver.CurrentExecPrimitive uptodate as well.
726 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
728 GET_CURRENT_CONTEXT( ctx
);
730 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
731 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
735 _mesa_update_state( ctx
);
737 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
738 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
739 _mesa_error(ctx
, GL_INVALID_OPERATION
,
740 "glBegin (invalid vertex/fragment program)");
744 if (!(tnl
->Driver
.NotifyBegin
&&
745 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
746 ctx
->Exec
->Begin(mode
);
750 /* Heuristic: attempt to isolate attributes occuring outside
753 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
754 _tnl_FlushVertices( ctx
, ~0 );
756 i
= tnl
->vtx
.prim_count
++;
757 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
758 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
759 tnl
->vtx
.prim
[i
].count
= 0;
761 ctx
->Driver
.CurrentExecPrimitive
= mode
;
764 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
768 static void GLAPIENTRY
_tnl_End( void )
770 GET_CURRENT_CONTEXT( ctx
);
772 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
773 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
774 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
775 int i
= tnl
->vtx
.prim_count
- 1;
777 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
778 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
780 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
782 /* Two choices which effect the way vertex attributes are
783 * carried over (or not) between adjacent primitives.
786 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
787 _tnl_FlushVertices( ctx
, ~0 );
789 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
790 _tnl_flush_vtx( ctx
);
795 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
799 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
801 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
803 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
804 vfmt
->Begin
= _tnl_Begin
;
805 vfmt
->CallList
= _mesa_CallList
;
806 vfmt
->CallLists
= _mesa_CallLists
;
807 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
808 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
809 vfmt
->End
= _tnl_End
;
810 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
811 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
812 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
813 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
814 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
815 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
816 vfmt
->Indexf
= _tnl_Indexf
;
817 vfmt
->Indexfv
= _tnl_Indexfv
;
818 vfmt
->Materialfv
= _tnl_Materialfv
;
820 vfmt
->Rectf
= _mesa_noop_Rectf
;
821 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
822 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
827 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
829 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
832 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
835 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
836 _tnl_flush_vtx( ctx
);
839 if (tnl
->vtx
.vertex_size
) {
840 _tnl_copy_to_current( ctx
);
844 ctx
->Driver
.NeedFlush
= 0;
848 static void _tnl_current_init( GLcontext
*ctx
)
850 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
853 /* setup the pointers for the typical 16 vertex attributes */
854 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
855 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
857 /* setup pointers for the 12 material attributes */
858 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
859 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
860 ctx
->Light
.Material
.Attrib
[i
];
862 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
865 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
867 (void) ctx
; (void) key
;
871 void _tnl_vtx_init( GLcontext
*ctx
)
873 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
874 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
876 static int firsttime
= 1;
898 choose
[ERROR_ATTRIB
][0] = error_attrib
;
899 choose
[ERROR_ATTRIB
][1] = error_attrib
;
900 choose
[ERROR_ATTRIB
][2] = error_attrib
;
901 choose
[ERROR_ATTRIB
][3] = error_attrib
;
904 if (tnl
->AllowCodegen
) {
905 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
909 _tnl_generic_attr_table_init( generic_attr_func
);
912 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
913 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
915 for (i
= 0; i
< 4; i
++) {
916 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
917 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
918 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
919 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
923 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
926 _tnl_current_init( ctx
);
927 _tnl_exec_vtxfmt_init( ctx
);
928 _tnl_generic_exec_vtxfmt_init( ctx
);
930 if (tnl
->AllowCodegen
) {
931 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
935 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
937 memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
939 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
940 tnl
->vtx
.attrsz
[i
] = 0;
942 tnl
->vtx
.vertex_size
= 0;
943 tnl
->vtx
.have_materials
= 0;
946 static void free_funcs( struct _tnl_dynfn
*l
)
948 struct _tnl_dynfn
*f
, *tmp
;
949 foreach_s (f
, tmp
, l
) {
950 remove_from_list( f
);
951 ALIGN_FREE( f
->code
);
957 void _tnl_vtx_destroy( GLcontext
*ctx
)
959 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
962 for (i
= 0; i
< 4; i
++) {
963 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
964 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );