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
;
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 last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
79 /* Execute the buffer and save copied vertices.
81 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
)
82 _tnl_flush_vtx( ctx
);
84 tnl
->vtx
.prim_count
= 0;
85 tnl
->vtx
.copied
.nr
= 0;
88 /* Emit a glBegin to start the new list.
90 assert(tnl
->vtx
.prim_count
== 0);
92 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
93 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
94 tnl
->vtx
.prim
[0].start
= 0;
95 tnl
->vtx
.prim
[0].count
= 0;
96 tnl
->vtx
.prim_count
++;
98 if (tnl
->vtx
.copied
.nr
== last_count
)
99 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
105 /* Deal with buffer wrapping where provoked by the vertex buffer
106 * filling up, as opposed to upgrade_vertex().
108 * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
110 void GLAPIENTRY
_tnl_wrap_filled_vertex( GLcontext
*ctx
)
112 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
113 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
116 /* Run pipeline on current vertices, copy wrapped vertices
119 _tnl_wrap_buffers( ctx
);
121 /* Copy stored stored vertices to start of new list.
123 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
125 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
126 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
127 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
128 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
129 data
+= tnl
->vtx
.vertex_size
;
133 tnl
->vtx
.copied
.nr
= 0;
138 * Copy the active vertex's values to the ctx->Current fields.
140 static void _tnl_copy_to_current( GLcontext
*ctx
)
142 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
145 for (i
= _TNL_ATTRIB_POS
+1 ; i
< _TNL_ATTRIB_INDEX
; i
++) {
146 if (tnl
->vtx
.attrsz
[i
]) {
147 /* Note: the tnl->vtx.current[i] pointers points to
148 * the ctx->Current fields. The first 16 or so, anyway.
150 COPY_CLEAN_4V(tnl
->vtx
.current
[i
],
152 tnl
->vtx
.attrptr
[i
]);
156 /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
157 * will trash adjacent memory!)
159 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_INDEX
]) {
160 ctx
->Current
.Index
= tnl
->vtx
.attrptr
[_TNL_ATTRIB_INDEX
][0];
163 /* Edgeflag requires additional treatment:
165 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
166 ctx
->Current
.EdgeFlag
=
167 (tnl
->vtx
.CurrentFloatEdgeFlag
== 1.0);
170 /* Colormaterial -- this kindof sucks.
172 if (ctx
->Light
.ColorMaterialEnabled
) {
173 _mesa_update_color_material(ctx
,
174 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
177 if (tnl
->vtx
.have_materials
) {
178 tnl
->Driver
.NotifyMaterialChange( ctx
);
181 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
185 static void _tnl_copy_from_current( GLcontext
*ctx
)
187 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
190 /* Edgeflag requires additional treatment:
192 tnl
->vtx
.CurrentFloatEdgeFlag
=
193 (GLfloat
)ctx
->Current
.EdgeFlag
;
195 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_MAX
; i
++)
196 switch (tnl
->vtx
.attrsz
[i
]) {
197 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
198 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
199 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
200 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
204 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
208 /* Flush existing data, set new attrib size, replay copied vertices.
210 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
214 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
218 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
220 /* Run pipeline on current vertices, copy wrapped vertices
221 * to tnl->vtx.copied.
223 _tnl_wrap_buffers( ctx
);
226 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
227 * when the attribute already exists in the vertex and is having
228 * its size increased.
230 _tnl_copy_to_current( ctx
);
233 /* Heuristic: Attempt to isolate attributes received outside
234 * begin/end so that they don't bloat the vertices.
236 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
237 tnl
->vtx
.attrsz
[attr
] == 0 &&
239 tnl
->vtx
.vertex_size
) {
245 oldsz
= tnl
->vtx
.attrsz
[attr
];
246 tnl
->vtx
.attrsz
[attr
] = newsz
;
248 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
249 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
250 ctx
->Const
.MaxArrayLockSize
);
251 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
252 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
255 /* Recalculate all the attrptr[] values
257 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
258 if (tnl
->vtx
.attrsz
[i
]) {
259 tnl
->vtx
.attrptr
[i
] = tmp
;
260 tmp
+= tnl
->vtx
.attrsz
[i
];
263 tnl
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
266 /* Copy from current to repopulate the vertex with correct values.
268 _tnl_copy_from_current( ctx
);
270 /* Replay stored vertices to translate them
271 * to new format here.
273 * -- No need to replay - just copy piecewise
275 if (tnl
->vtx
.copied
.nr
)
277 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
278 GLfloat
*dest
= tnl
->vtx
.buffer
;
281 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
282 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
283 if (tnl
->vtx
.attrsz
[j
]) {
286 COPY_CLEAN_4V( dest
, oldsz
, data
);
290 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
295 GLuint sz
= tnl
->vtx
.attrsz
[j
];
296 COPY_SZ_4V( dest
, sz
, data
);
304 tnl
->vtx
.vbptr
= dest
;
305 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
306 tnl
->vtx
.copied
.nr
= 0;
309 /* For codegen - attrptr's may have changed, so need to redo
310 * codegen. Might be a reasonable place to try & detect attributes
311 * in the vertex which aren't being submitted any more.
313 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
314 if (tnl
->vtx
.attrsz
[i
]) {
315 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
317 if (i
< _TNL_MAX_ATTR_CODEGEN
)
318 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
324 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
326 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
327 static const GLfloat id
[4] = { 0, 0, 0, 1 };
330 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
331 /* New size is larger. Need to flush existing vertices and get
332 * an enlarged vertex format.
334 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
336 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
337 /* New size is smaller - just need to fill in some
338 * zeros. Don't need to flush or wrap.
340 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
341 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
344 /* Does setting NeedFlush belong here? Necessitates resetting
345 * vtxfmt on each flush (otherwise flags won't get reset
349 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
351 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
356 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
358 struct _tnl_dynfn
*f
;
369 static tnl_attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
371 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
372 struct _tnl_dynfn
*dfn
= NULL
;
375 GLuint key
= tnl
->vtx
.vertex_size
;
377 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
380 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
383 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
385 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
388 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
392 return *(tnl_attrfv_func
*) &dfn
->code
;
397 #endif /* USE_X86_ASM */
399 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
400 * entrypoint is called for the first time.
403 static tnl_attrfv_func
do_choose( GLuint attr
, GLuint sz
)
405 GET_CURRENT_CONTEXT( ctx
);
406 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
407 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
409 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
412 /* Reset any active pointers for this attribute
415 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
417 _tnl_fixup_vertex( ctx
, attr
, sz
);
422 /* Try to use codegen:
425 if (tnl
->AllowCodegen
)
426 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
429 tnl
->vtx
.tabfv
[attr
][sz
-1] = NULL
;
431 /* Else use generic version:
433 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
434 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
436 return tnl
->vtx
.tabfv
[attr
][sz
-1];
441 #define CHOOSE( ATTR, N ) \
442 static void choose_##ATTR##_##N( const GLfloat *v ) \
444 tnl_attrfv_func f = do_choose(ATTR, N); \
448 #define CHOOSERS( ATTRIB ) \
449 CHOOSE( ATTRIB, 1 ) \
450 CHOOSE( ATTRIB, 2 ) \
451 CHOOSE( ATTRIB, 3 ) \
452 CHOOSE( ATTRIB, 4 ) \
455 #define INIT_CHOOSERS(ATTR) \
456 choose[ATTR][0] = choose_##ATTR##_1; \
457 choose[ATTR][1] = choose_##ATTR##_2; \
458 choose[ATTR][2] = choose_##ATTR##_3; \
459 choose[ATTR][3] = choose_##ATTR##_4;
478 static void error_attrib( const GLfloat
*unused
)
480 GET_CURRENT_CONTEXT( ctx
);
482 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
487 static void reset_attrfv( TNLcontext
*tnl
)
491 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
492 if (tnl
->vtx
.attrsz
[i
]) {
493 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
494 tnl
->vtx
.attrsz
[i
] = 0;
496 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
498 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
504 tnl
->vtx
.vertex_size
= 0;
505 tnl
->vtx
.have_materials
= 0;
512 * These are treated as per-vertex attributes, at indices above where
513 * the NV_vertex_program leaves off. There are a lot of good things
514 * about treating materials this way.
516 * However: I don't want to double the number of generated functions
517 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
518 * ATTRF into this function, and dispense with codegen and
519 * second-level dispatch.
521 * There is no aliasing of material attributes with other entrypoints.
523 #define OTHER_ATTR( A, N, params ) \
525 if (tnl->vtx.attrsz[A] != N) { \
526 _tnl_fixup_vertex( ctx, A, N ); \
530 GLfloat *dest = tnl->vtx.attrptr[A]; \
531 if (N>0) dest[0] = (params)[0]; \
532 if (N>1) dest[1] = (params)[1]; \
533 if (N>2) dest[2] = (params)[2]; \
534 if (N>3) dest[3] = (params)[3]; \
539 #define MAT( ATTR, N, face, params ) \
541 if (face != GL_BACK) \
542 OTHER_ATTR( ATTR, N, params ); /* front */ \
543 if (face != GL_FRONT) \
544 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
548 /* Colormaterial is dealt with later on.
550 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
551 const GLfloat
*params
)
553 GET_CURRENT_CONTEXT( ctx
);
554 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
559 case GL_FRONT_AND_BACK
:
563 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
569 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
572 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
575 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
578 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
581 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
583 case GL_COLOR_INDEXES
:
584 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
586 case GL_AMBIENT_AND_DIFFUSE
:
587 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
588 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
591 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
595 tnl
->vtx
.have_materials
= GL_TRUE
;
599 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
601 GET_CURRENT_CONTEXT( ctx
);
602 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
603 GLfloat f
= (GLfloat
)b
;
605 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
608 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
610 GET_CURRENT_CONTEXT( ctx
);
611 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
612 GLfloat f
= (GLfloat
)v
[0];
614 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
617 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
619 GET_CURRENT_CONTEXT( ctx
);
620 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
622 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, &f
);
625 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
627 GET_CURRENT_CONTEXT( ctx
);
628 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
630 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, v
);
635 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
637 GET_CURRENT_CONTEXT( ctx
);
638 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
640 /* TODO: use a CHOOSE() function for this: */
643 if (tnl
->vtx
.eval
.new_state
)
644 _tnl_update_eval( ctx
);
646 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
647 if (tnl
->vtx
.eval
.map1
[i
].map
)
648 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
649 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
654 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
655 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
657 _tnl_do_EvalCoord1f( ctx
, u
);
659 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
660 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
663 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
665 GET_CURRENT_CONTEXT( ctx
);
666 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
668 /* TODO: use a CHOOSE() function for this: */
671 if (tnl
->vtx
.eval
.new_state
)
672 _tnl_update_eval( ctx
);
674 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
675 if (tnl
->vtx
.eval
.map2
[i
].map
)
676 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
677 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
680 if (ctx
->Eval
.AutoNormal
)
681 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] != 3)
682 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
685 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
686 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
688 _tnl_do_EvalCoord2f( ctx
, u
, v
);
690 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
691 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
694 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
696 _tnl_EvalCoord1f( u
[0] );
699 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
701 _tnl_EvalCoord2f( u
[0], u
[1] );
704 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
706 GET_CURRENT_CONTEXT( ctx
);
707 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
708 (GLfloat
) ctx
->Eval
.MapGrid1un
);
709 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
711 _tnl_EvalCoord1f( u
);
715 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
717 GET_CURRENT_CONTEXT( ctx
);
718 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
719 (GLfloat
) ctx
->Eval
.MapGrid2un
);
720 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
721 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
722 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
723 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
725 _tnl_EvalCoord2f( u
, v
);
729 /* Build a list of primitives on the fly. Keep
730 * ctx->Driver.CurrentExecPrimitive uptodate as well.
732 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
734 GET_CURRENT_CONTEXT( ctx
);
736 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
737 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
741 _mesa_update_state( ctx
);
743 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
744 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
745 _mesa_error(ctx
, GL_INVALID_OPERATION
,
746 "glBegin (invalid vertex/fragment program)");
750 if (!(tnl
->Driver
.NotifyBegin
&&
751 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
752 ctx
->Exec
->Begin(mode
);
756 /* Heuristic: attempt to isolate attributes occuring outside
759 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
760 _tnl_FlushVertices( ctx
, ~0 );
762 i
= tnl
->vtx
.prim_count
++;
763 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
764 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
765 tnl
->vtx
.prim
[i
].count
= 0;
767 ctx
->Driver
.CurrentExecPrimitive
= mode
;
770 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
774 static void GLAPIENTRY
_tnl_End( void )
776 GET_CURRENT_CONTEXT( ctx
);
778 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
779 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
780 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
781 int i
= tnl
->vtx
.prim_count
- 1;
783 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
784 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
786 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
788 /* Two choices which effect the way vertex attributes are
789 * carried over (or not) between adjacent primitives.
792 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
793 _tnl_FlushVertices( ctx
, ~0 );
795 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
796 _tnl_flush_vtx( ctx
);
801 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
805 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
807 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
809 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
810 vfmt
->Begin
= _tnl_Begin
;
811 vfmt
->CallList
= _mesa_CallList
;
812 vfmt
->CallLists
= _mesa_CallLists
;
813 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
814 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
815 vfmt
->End
= _tnl_End
;
816 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
817 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
818 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
819 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
820 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
821 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
822 vfmt
->Indexf
= _tnl_Indexf
;
823 vfmt
->Indexfv
= _tnl_Indexfv
;
824 vfmt
->Materialfv
= _tnl_Materialfv
;
826 vfmt
->Rectf
= _mesa_noop_Rectf
;
827 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
828 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
833 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
835 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
838 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
841 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
842 _tnl_flush_vtx( ctx
);
845 if (tnl
->vtx
.vertex_size
) {
846 _tnl_copy_to_current( ctx
);
850 ctx
->Driver
.NeedFlush
= 0;
854 static void _tnl_current_init( GLcontext
*ctx
)
856 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
859 /* setup the pointers for the typical 16 vertex attributes */
860 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
861 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
863 /* setup pointers for the 12 material attributes */
864 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
865 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
866 ctx
->Light
.Material
.Attrib
[i
];
868 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
869 tnl
->vtx
.current
[_TNL_ATTRIB_EDGEFLAG
] = &tnl
->vtx
.CurrentFloatEdgeFlag
;
872 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
874 (void) ctx
; (void) key
;
878 void _tnl_vtx_init( GLcontext
*ctx
)
880 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
881 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
883 static int firsttime
= 1;
905 choose
[ERROR_ATTRIB
][0] = error_attrib
;
906 choose
[ERROR_ATTRIB
][1] = error_attrib
;
907 choose
[ERROR_ATTRIB
][2] = error_attrib
;
908 choose
[ERROR_ATTRIB
][3] = error_attrib
;
911 if (tnl
->AllowCodegen
) {
912 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
916 _tnl_generic_attr_table_init( generic_attr_func
);
919 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
920 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, NULL
);
922 for (i
= 0; i
< 4; i
++) {
923 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
924 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
925 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
926 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
930 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
933 _tnl_current_init( ctx
);
934 _tnl_exec_vtxfmt_init( ctx
);
935 _tnl_generic_exec_vtxfmt_init( ctx
);
937 if (tnl
->AllowCodegen
) {
938 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
942 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
944 memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
946 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
947 tnl
->vtx
.attrsz
[i
] = 0;
949 tnl
->vtx
.vertex_size
= 0;
950 tnl
->vtx
.have_materials
= 0;
953 static void free_funcs( struct _tnl_dynfn
*l
)
955 struct _tnl_dynfn
*f
, *tmp
;
956 foreach_s (f
, tmp
, l
) {
957 remove_from_list( f
);
958 ALIGN_FREE( f
->code
);
964 void _tnl_vtx_destroy( GLcontext
*ctx
)
966 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
969 for (i
= 0; i
< 4; i
++) {
970 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
971 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );