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"
48 static void reset_attrfv( TNLcontext
*tnl
);
50 static tnl_attrfv_func choose
[_TNL_MAX_ATTR_CODEGEN
+1][4]; /* +1 for ERROR_ATTRIB */
51 static tnl_attrfv_func generic_attr_func
[_TNL_MAX_ATTR_CODEGEN
][4];
54 /* Close off the last primitive, execute the buffer, restart the
57 static void _tnl_wrap_buffers( GLcontext
*ctx
)
59 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
62 if (tnl
->vtx
.prim_count
== 0) {
63 tnl
->vtx
.copied
.nr
= 0;
64 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
65 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
68 GLuint last_prim
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].mode
;
71 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
72 GLint i
= tnl
->vtx
.prim_count
- 1;
74 tnl
->vtx
.prim
[i
].count
= ((tnl
->vtx
.initial_counter
-
76 tnl
->vtx
.prim
[i
].start
);
79 last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
81 /* Execute the buffer and save copied vertices.
83 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
)
84 _tnl_flush_vtx( ctx
);
86 tnl
->vtx
.prim_count
= 0;
87 tnl
->vtx
.copied
.nr
= 0;
90 /* Emit a glBegin to start the new list.
92 assert(tnl
->vtx
.prim_count
== 0);
94 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
95 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
96 tnl
->vtx
.prim
[0].start
= 0;
97 tnl
->vtx
.prim
[0].count
= 0;
98 tnl
->vtx
.prim_count
++;
100 if (tnl
->vtx
.copied
.nr
== last_count
)
101 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
107 /* Deal with buffer wrapping where provoked by the vertex buffer
108 * filling up, as opposed to upgrade_vertex().
110 * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
112 void GLAPIENTRY
_tnl_wrap_filled_vertex( GLcontext
*ctx
)
114 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
115 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
118 /* Run pipeline on current vertices, copy wrapped vertices
121 _tnl_wrap_buffers( ctx
);
123 /* Copy stored stored vertices to start of new list.
125 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
127 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
128 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
129 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
130 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
131 data
+= tnl
->vtx
.vertex_size
;
135 tnl
->vtx
.copied
.nr
= 0;
140 * Copy the active vertex's values to the ctx->Current fields.
142 static void _tnl_copy_to_current( GLcontext
*ctx
)
144 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
147 for (i
= _TNL_ATTRIB_POS
+1 ; i
< _TNL_ATTRIB_INDEX
; i
++) {
148 if (tnl
->vtx
.attrsz
[i
]) {
149 /* Note: the tnl->vtx.current[i] pointers points to
150 * the ctx->Current fields. The first 16 or so, anyway.
152 COPY_CLEAN_4V(tnl
->vtx
.current
[i
],
154 tnl
->vtx
.attrptr
[i
]);
158 /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
159 * will trash adjacent memory!)
161 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_INDEX
]) {
162 ctx
->Current
.Index
= tnl
->vtx
.attrptr
[_TNL_ATTRIB_INDEX
][0];
165 /* Edgeflag requires additional treatment:
167 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
168 ctx
->Current
.EdgeFlag
=
169 (tnl
->vtx
.CurrentFloatEdgeFlag
== 1.0);
172 /* Colormaterial -- this kindof sucks.
174 if (ctx
->Light
.ColorMaterialEnabled
) {
175 _mesa_update_color_material(ctx
,
176 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
179 if (tnl
->vtx
.have_materials
) {
180 tnl
->Driver
.NotifyMaterialChange( ctx
);
183 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
187 static void _tnl_copy_from_current( GLcontext
*ctx
)
189 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
192 /* Edgeflag requires additional treatment:
194 tnl
->vtx
.CurrentFloatEdgeFlag
=
195 (GLfloat
)ctx
->Current
.EdgeFlag
;
197 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_MAX
; i
++)
198 switch (tnl
->vtx
.attrsz
[i
]) {
199 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
200 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
201 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
202 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
206 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
210 /* Flush existing data, set new attrib size, replay copied vertices.
212 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
216 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
220 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
222 /* Run pipeline on current vertices, copy wrapped vertices
223 * to tnl->vtx.copied.
225 _tnl_wrap_buffers( ctx
);
228 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
229 * when the attribute already exists in the vertex and is having
230 * its size increased.
232 _tnl_copy_to_current( ctx
);
235 /* Heuristic: Attempt to isolate attributes received outside
236 * begin/end so that they don't bloat the vertices.
238 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
239 tnl
->vtx
.attrsz
[attr
] == 0 &&
241 tnl
->vtx
.vertex_size
) {
247 oldsz
= tnl
->vtx
.attrsz
[attr
];
248 tnl
->vtx
.attrsz
[attr
] = newsz
;
250 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
251 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
252 ctx
->Const
.MaxArrayLockSize
);
253 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
254 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
257 /* Recalculate all the attrptr[] values
259 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
260 if (tnl
->vtx
.attrsz
[i
]) {
261 tnl
->vtx
.attrptr
[i
] = tmp
;
262 tmp
+= tnl
->vtx
.attrsz
[i
];
265 tnl
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
268 /* Copy from current to repopulate the vertex with correct values.
270 _tnl_copy_from_current( ctx
);
272 /* Replay stored vertices to translate them
273 * to new format here.
275 * -- No need to replay - just copy piecewise
277 if (tnl
->vtx
.copied
.nr
)
279 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
280 GLfloat
*dest
= tnl
->vtx
.buffer
;
283 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
284 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
285 if (tnl
->vtx
.attrsz
[j
]) {
288 COPY_CLEAN_4V( dest
, oldsz
, data
);
292 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
297 GLuint sz
= tnl
->vtx
.attrsz
[j
];
298 COPY_SZ_4V( dest
, sz
, data
);
306 tnl
->vtx
.vbptr
= dest
;
307 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
308 tnl
->vtx
.copied
.nr
= 0;
311 /* For codegen - attrptr's may have changed, so need to redo
312 * codegen. Might be a reasonable place to try & detect attributes
313 * in the vertex which aren't being submitted any more.
315 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
316 if (tnl
->vtx
.attrsz
[i
]) {
317 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
319 if (i
< _TNL_MAX_ATTR_CODEGEN
)
320 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
326 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
328 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
329 static const GLfloat id
[4] = { 0, 0, 0, 1 };
332 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
333 /* New size is larger. Need to flush existing vertices and get
334 * an enlarged vertex format.
336 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
338 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
339 /* New size is smaller - just need to fill in some
340 * zeros. Don't need to flush or wrap.
342 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
343 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
346 /* Does setting NeedFlush belong here? Necessitates resetting
347 * vtxfmt on each flush (otherwise flags won't get reset
351 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
353 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
358 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
360 struct _tnl_dynfn
*f
;
371 static tnl_attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
373 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
374 struct _tnl_dynfn
*dfn
= NULL
;
377 GLuint key
= tnl
->vtx
.vertex_size
;
379 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
382 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
385 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
387 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
390 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
394 return *(tnl_attrfv_func
*) &dfn
->code
;
399 #endif /* USE_X86_ASM */
401 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
402 * entrypoint is called for the first time.
405 static tnl_attrfv_func
do_choose( GLuint attr
, GLuint sz
)
407 GET_CURRENT_CONTEXT( ctx
);
408 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
409 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
411 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
414 /* Reset any active pointers for this attribute
417 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
419 _tnl_fixup_vertex( ctx
, attr
, sz
);
424 /* Try to use codegen:
427 if (tnl
->AllowCodegen
)
428 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
431 tnl
->vtx
.tabfv
[attr
][sz
-1] = NULL
;
433 /* Else use generic version:
435 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
436 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
438 return tnl
->vtx
.tabfv
[attr
][sz
-1];
443 #define CHOOSE( ATTR, N ) \
444 static void choose_##ATTR##_##N( const GLfloat *v ) \
446 tnl_attrfv_func f = do_choose(ATTR, N); \
450 #define CHOOSERS( ATTRIB ) \
451 CHOOSE( ATTRIB, 1 ) \
452 CHOOSE( ATTRIB, 2 ) \
453 CHOOSE( ATTRIB, 3 ) \
454 CHOOSE( ATTRIB, 4 ) \
457 #define INIT_CHOOSERS(ATTR) \
458 choose[ATTR][0] = choose_##ATTR##_1; \
459 choose[ATTR][1] = choose_##ATTR##_2; \
460 choose[ATTR][2] = choose_##ATTR##_3; \
461 choose[ATTR][3] = choose_##ATTR##_4;
480 static void error_attrib( const GLfloat
*unused
)
482 GET_CURRENT_CONTEXT( ctx
);
484 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
489 static void reset_attrfv( TNLcontext
*tnl
)
493 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
494 if (tnl
->vtx
.attrsz
[i
]) {
495 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
496 tnl
->vtx
.attrsz
[i
] = 0;
498 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
500 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
506 tnl
->vtx
.vertex_size
= 0;
507 tnl
->vtx
.have_materials
= 0;
514 * These are treated as per-vertex attributes, at indices above where
515 * the NV_vertex_program leaves off. There are a lot of good things
516 * about treating materials this way.
518 * However: I don't want to double the number of generated functions
519 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
520 * ATTRF into this function, and dispense with codegen and
521 * second-level dispatch.
523 * There is no aliasing of material attributes with other entrypoints.
525 #define OTHER_ATTR( A, N, params ) \
527 if (tnl->vtx.attrsz[A] != N) { \
528 _tnl_fixup_vertex( ctx, A, N ); \
532 GLfloat *dest = tnl->vtx.attrptr[A]; \
533 if (N>0) dest[0] = (params)[0]; \
534 if (N>1) dest[1] = (params)[1]; \
535 if (N>2) dest[2] = (params)[2]; \
536 if (N>3) dest[3] = (params)[3]; \
541 #define MAT( ATTR, N, face, params ) \
543 if (face != GL_BACK) \
544 OTHER_ATTR( ATTR, N, params ); /* front */ \
545 if (face != GL_FRONT) \
546 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
550 /* Colormaterial is dealt with later on.
552 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
553 const GLfloat
*params
)
555 GET_CURRENT_CONTEXT( ctx
);
556 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
561 case GL_FRONT_AND_BACK
:
565 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
571 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
574 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
577 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
580 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
583 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
585 case GL_COLOR_INDEXES
:
586 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
588 case GL_AMBIENT_AND_DIFFUSE
:
589 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
590 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
593 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
597 tnl
->vtx
.have_materials
= GL_TRUE
;
601 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
603 GET_CURRENT_CONTEXT( ctx
);
604 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
605 GLfloat f
= (GLfloat
)b
;
607 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
610 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
612 GET_CURRENT_CONTEXT( ctx
);
613 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
614 GLfloat f
= (GLfloat
)v
[0];
616 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
619 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
621 GET_CURRENT_CONTEXT( ctx
);
622 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
624 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, &f
);
627 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
629 GET_CURRENT_CONTEXT( ctx
);
630 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
632 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, v
);
637 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
639 GET_CURRENT_CONTEXT( ctx
);
640 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
642 /* TODO: use a CHOOSE() function for this: */
645 if (tnl
->vtx
.eval
.new_state
)
646 _tnl_update_eval( ctx
);
648 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
649 if (tnl
->vtx
.eval
.map1
[i
].map
)
650 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
651 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
656 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
657 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
659 _tnl_do_EvalCoord1f( ctx
, u
);
661 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
662 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
665 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
667 GET_CURRENT_CONTEXT( ctx
);
668 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
670 /* TODO: use a CHOOSE() function for this: */
673 if (tnl
->vtx
.eval
.new_state
)
674 _tnl_update_eval( ctx
);
676 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
677 if (tnl
->vtx
.eval
.map2
[i
].map
)
678 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
679 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
682 if (ctx
->Eval
.AutoNormal
)
683 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] != 3)
684 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
687 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
688 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
690 _tnl_do_EvalCoord2f( ctx
, u
, v
);
692 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
693 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
696 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
698 _tnl_EvalCoord1f( u
[0] );
701 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
703 _tnl_EvalCoord2f( u
[0], u
[1] );
706 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
708 GET_CURRENT_CONTEXT( ctx
);
709 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
710 (GLfloat
) ctx
->Eval
.MapGrid1un
);
711 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
713 _tnl_EvalCoord1f( u
);
717 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
719 GET_CURRENT_CONTEXT( ctx
);
720 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
721 (GLfloat
) ctx
->Eval
.MapGrid2un
);
722 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
723 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
724 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
725 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
727 _tnl_EvalCoord2f( u
, v
);
731 /* Build a list of primitives on the fly. Keep
732 * ctx->Driver.CurrentExecPrimitive uptodate as well.
734 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
736 GET_CURRENT_CONTEXT( ctx
);
738 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
739 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
743 _mesa_update_state( ctx
);
745 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
746 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
747 _mesa_error(ctx
, GL_INVALID_OPERATION
,
748 "glBegin (invalid vertex/fragment program)");
752 if (!(tnl
->Driver
.NotifyBegin
&&
753 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
754 CALL_Begin(ctx
->Exec
, (mode
));
758 /* Heuristic: attempt to isolate attributes occuring outside
761 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
762 _tnl_FlushVertices( ctx
, ~0 );
764 i
= tnl
->vtx
.prim_count
++;
765 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
766 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
767 tnl
->vtx
.prim
[i
].count
= 0;
769 ctx
->Driver
.CurrentExecPrimitive
= mode
;
772 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
776 static void GLAPIENTRY
_tnl_End( void )
778 GET_CURRENT_CONTEXT( ctx
);
780 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
781 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
782 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
783 int i
= tnl
->vtx
.prim_count
- 1;
785 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
786 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
788 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
790 /* Two choices which effect the way vertex attributes are
791 * carried over (or not) between adjacent primitives.
794 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
795 _tnl_FlushVertices( ctx
, ~0 );
797 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
798 _tnl_flush_vtx( ctx
);
803 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
807 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
809 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
811 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
812 vfmt
->Begin
= _tnl_Begin
;
813 vfmt
->CallList
= _mesa_CallList
;
814 vfmt
->CallLists
= _mesa_CallLists
;
815 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
816 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
817 vfmt
->End
= _tnl_End
;
818 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
819 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
820 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
821 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
822 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
823 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
824 vfmt
->Indexf
= _tnl_Indexf
;
825 vfmt
->Indexfv
= _tnl_Indexfv
;
826 vfmt
->Materialfv
= _tnl_Materialfv
;
828 vfmt
->Rectf
= _mesa_noop_Rectf
;
829 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
830 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
835 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
837 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
840 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
843 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
844 _tnl_flush_vtx( ctx
);
847 if (tnl
->vtx
.vertex_size
) {
848 _tnl_copy_to_current( ctx
);
852 ctx
->Driver
.NeedFlush
= 0;
856 static void _tnl_current_init( GLcontext
*ctx
)
858 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
861 /* setup the pointers for the typical 16 vertex attributes */
862 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
863 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
865 /* setup pointers for the 12 material attributes */
866 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
867 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
868 ctx
->Light
.Material
.Attrib
[i
];
870 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
871 tnl
->vtx
.current
[_TNL_ATTRIB_EDGEFLAG
] = &tnl
->vtx
.CurrentFloatEdgeFlag
;
874 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
876 (void) ctx
; (void) key
;
880 void _tnl_vtx_init( GLcontext
*ctx
)
882 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
883 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
885 static int firsttime
= 1;
907 choose
[ERROR_ATTRIB
][0] = error_attrib
;
908 choose
[ERROR_ATTRIB
][1] = error_attrib
;
909 choose
[ERROR_ATTRIB
][2] = error_attrib
;
910 choose
[ERROR_ATTRIB
][3] = error_attrib
;
913 if (tnl
->AllowCodegen
) {
914 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
918 _tnl_generic_attr_table_init( generic_attr_func
);
921 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
922 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, NULL
);
924 for (i
= 0; i
< 4; i
++) {
925 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
926 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
927 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
928 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
932 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
935 _tnl_current_init( ctx
);
936 _tnl_exec_vtxfmt_init( ctx
);
937 _tnl_generic_exec_vtxfmt_init( ctx
);
939 if (tnl
->AllowCodegen
) {
940 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
944 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
946 memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
948 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
949 tnl
->vtx
.attrsz
[i
] = 0;
951 tnl
->vtx
.vertex_size
= 0;
952 tnl
->vtx
.have_materials
= 0;
955 static void free_funcs( struct _tnl_dynfn
*l
)
957 struct _tnl_dynfn
*f
, *tmp
;
958 foreach_s (f
, tmp
, l
) {
959 remove_from_list( f
);
960 ALIGN_FREE( f
->code
);
966 void _tnl_vtx_destroy( GLcontext
*ctx
)
968 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
971 for (i
= 0; i
< 4; i
++) {
972 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
973 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );