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 attrfv_func choose
[_TNL_MAX_ATTR_CODEGEN
+1][4]; /* +1 for ERROR_ATTRIB */
49 static 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 void _tnl_wrap_filled_vertex( GLcontext
*ctx
)
108 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
109 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
112 /* Run pipeline on current vertices, copy wrapped vertices
115 _tnl_wrap_buffers( ctx
);
117 /* Copy stored stored vertices to start of new list.
119 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
121 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
122 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
123 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
124 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
125 data
+= tnl
->vtx
.vertex_size
;
129 tnl
->vtx
.copied
.nr
= 0;
134 * Copy the active vertex's values to the ctx->Current fields.
136 static void _tnl_copy_to_current( GLcontext
*ctx
)
138 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
141 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
142 if (tnl
->vtx
.attrsz
[i
]) {
143 /* Note: the tnl->vtx.current[i] pointers points to
144 * the ctx->Current fields. The first 16 or so, anyway.
146 ASSIGN_4V( tnl
->vtx
.current
[i
], 0, 0, 0, 1 );
147 COPY_SZ_4V(tnl
->vtx
.current
[i
],
149 tnl
->vtx
.attrptr
[i
]);
152 /* Edgeflag requires special treatment:
154 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
155 ctx
->Current
.EdgeFlag
=
156 (tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
159 /* Colormaterial -- this kindof sucks.
161 if (ctx
->Light
.ColorMaterialEnabled
) {
162 _mesa_update_color_material(ctx
,
163 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
166 if (tnl
->vtx
.have_materials
) {
167 tnl
->Driver
.NotifyMaterialChange( ctx
);
170 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
174 static void _tnl_copy_from_current( GLcontext
*ctx
)
176 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
179 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
180 switch (tnl
->vtx
.attrsz
[i
]) {
181 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
182 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
183 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
184 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
188 /* Edgeflag requires special treatment:
190 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
191 tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
192 (GLfloat
)ctx
->Current
.EdgeFlag
;
195 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
199 /* Flush existing data, set new attrib size, replay copied vertices.
201 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
205 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
209 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
211 /* Run pipeline on current vertices, copy wrapped vertices
212 * to tnl->vtx.copied.
214 _tnl_wrap_buffers( ctx
);
217 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
218 * when the attribute already exists in the vertex and is having
219 * its size increased.
221 _tnl_copy_to_current( ctx
);
224 /* Heuristic: Attempt to isolate attributes received outside
225 * begin/end so that they don't bloat the vertices.
227 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
228 tnl
->vtx
.attrsz
[attr
] == 0 &&
230 tnl
->vtx
.vertex_size
) {
236 oldsz
= tnl
->vtx
.attrsz
[attr
];
237 tnl
->vtx
.attrsz
[attr
] = newsz
;
239 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
240 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
241 ctx
->Const
.MaxArrayLockSize
);
242 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
243 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
246 /* Recalculate all the attrptr[] values
248 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
249 if (tnl
->vtx
.attrsz
[i
]) {
250 tnl
->vtx
.attrptr
[i
] = tmp
;
251 tmp
+= tnl
->vtx
.attrsz
[i
];
254 tnl
->vtx
.attrptr
[i
] = 0; /* will not be dereferenced */
257 /* Copy from current to repopulate the vertex with correct values.
259 _tnl_copy_from_current( ctx
);
261 /* Replay stored vertices to translate them
262 * to new format here.
264 * -- No need to replay - just copy piecewise
266 if (tnl
->vtx
.copied
.nr
)
268 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
269 GLfloat
*dest
= tnl
->vtx
.buffer
;
272 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
273 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
274 if (tnl
->vtx
.attrsz
[j
]) {
276 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
277 COPY_SZ_4V( dest
, oldsz
, data
);
282 GLuint sz
= tnl
->vtx
.attrsz
[j
];
283 COPY_SZ_4V( dest
, sz
, data
);
291 tnl
->vtx
.vbptr
= dest
;
292 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
293 tnl
->vtx
.copied
.nr
= 0;
296 /* For codegen - attrptr's may have changed, so need to redo
297 * codegen. Might be a reasonable place to try & detect attributes
298 * in the vertex which aren't being submitted any more.
300 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
301 if (tnl
->vtx
.attrsz
[i
]) {
302 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
304 if (i
< _TNL_MAX_ATTR_CODEGEN
)
305 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
311 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
313 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
314 static const GLfloat id
[4] = { 0, 0, 0, 1 };
317 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
318 /* New size is larger. Need to flush existing vertices and get
319 * an enlarged vertex format.
321 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
323 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
324 /* New size is smaller - just need to fill in some
325 * zeros. Don't need to flush or wrap.
327 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
328 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
333 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
335 struct _tnl_dynfn
*f
;
346 static attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
348 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
349 struct _tnl_dynfn
*dfn
= 0;
352 GLuint key
= tnl
->vtx
.vertex_size
;
354 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
357 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
360 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
362 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
365 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
369 return (attrfv_func
) dfn
->code
;
374 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
375 * entrypoint is called for the first time.
378 static attrfv_func
do_choose( GLuint attr
, GLuint sz
)
380 GET_CURRENT_CONTEXT( ctx
);
381 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
382 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
384 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
387 /* Reset any active pointers for this attribute
390 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
392 _tnl_fixup_vertex( ctx
, attr
, sz
);
394 /* Does setting NeedFlush belong here? Necessitates resetting
395 * vtxfmt on each flush (otherwise flags won't get reset
399 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
401 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
405 /* Try to use codegen:
408 if (tnl
->AllowCodegen
)
409 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
412 tnl
->vtx
.tabfv
[attr
][sz
-1] = 0;
414 /* Else use generic version:
416 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
417 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
419 return tnl
->vtx
.tabfv
[attr
][sz
-1];
424 #define CHOOSE( ATTR, N ) \
425 static void choose_##ATTR##_##N( const GLfloat *v ) \
427 attrfv_func f = do_choose(ATTR, N); \
431 #define CHOOSERS( ATTRIB ) \
432 CHOOSE( ATTRIB, 1 ) \
433 CHOOSE( ATTRIB, 2 ) \
434 CHOOSE( ATTRIB, 3 ) \
435 CHOOSE( ATTRIB, 4 ) \
438 #define INIT_CHOOSERS(ATTR) \
439 choose[ATTR][0] = choose_##ATTR##_1; \
440 choose[ATTR][1] = choose_##ATTR##_2; \
441 choose[ATTR][2] = choose_##ATTR##_3; \
442 choose[ATTR][3] = choose_##ATTR##_4;
461 static void error_attrib( const GLfloat
*unused
)
463 GET_CURRENT_CONTEXT( ctx
);
465 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
470 static void reset_attrfv( TNLcontext
*tnl
)
474 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
475 if (tnl
->vtx
.attrsz
[i
]) {
476 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
477 tnl
->vtx
.attrsz
[i
] = 0;
479 if (i
< _TNL_MAX_ATTR_CODEGEN
)
480 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
483 tnl
->vtx
.vertex_size
= 0;
484 tnl
->vtx
.have_materials
= 0;
491 * These are treated as per-vertex attributes, at indices above where
492 * the NV_vertex_program leaves off. There are a lot of good things
493 * about treating materials this way.
495 * However: I don't want to double the number of generated functions
496 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
497 * ATTRF into this function, and dispense with codegen and
498 * second-level dispatch.
500 * There is no aliasing of material attributes with other entrypoints.
502 #define OTHER_ATTR( A, N, params ) \
504 if (tnl->vtx.attrsz[A] != N) { \
505 _tnl_fixup_vertex( ctx, A, N ); \
509 GLfloat *dest = tnl->vtx.attrptr[A]; \
510 if (N>0) dest[0] = (params)[0]; \
511 if (N>1) dest[1] = (params)[1]; \
512 if (N>2) dest[2] = (params)[2]; \
513 if (N>3) dest[3] = (params)[3]; \
514 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
519 #define MAT( ATTR, N, face, params ) \
521 if (face != GL_BACK) \
522 OTHER_ATTR( ATTR, N, params ); /* front */ \
523 if (face != GL_FRONT) \
524 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
528 /* Colormaterial is dealt with later on.
530 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
531 const GLfloat
*params
)
533 GET_CURRENT_CONTEXT( ctx
);
534 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
539 case GL_FRONT_AND_BACK
:
543 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
549 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
552 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
555 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
558 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
561 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
563 case GL_COLOR_INDEXES
:
564 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
566 case GL_AMBIENT_AND_DIFFUSE
:
567 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
568 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
571 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
575 tnl
->vtx
.have_materials
= GL_TRUE
;
579 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
581 GET_CURRENT_CONTEXT( ctx
);
582 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
583 GLfloat f
= (GLfloat
)b
;
585 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
588 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
590 GET_CURRENT_CONTEXT( ctx
);
591 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
592 GLfloat f
= (GLfloat
)v
[0];
594 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
597 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
599 GET_CURRENT_CONTEXT( ctx
);
600 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
602 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, &f
);
605 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
607 GET_CURRENT_CONTEXT( ctx
);
608 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
610 OTHER_ATTR( _TNL_ATTRIB_INDEX
, 1, v
);
615 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
617 GET_CURRENT_CONTEXT( ctx
);
618 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
620 /* TODO: use a CHOOSE() function for this: */
623 if (tnl
->vtx
.eval
.new_state
)
624 _tnl_update_eval( ctx
);
626 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
627 if (tnl
->vtx
.eval
.map1
[i
].map
)
628 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map1
[i
].sz
)
629 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
634 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
635 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
637 _tnl_do_EvalCoord1f( ctx
, u
);
639 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
640 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
643 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
645 GET_CURRENT_CONTEXT( ctx
);
646 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
648 /* TODO: use a CHOOSE() function for this: */
651 if (tnl
->vtx
.eval
.new_state
)
652 _tnl_update_eval( ctx
);
654 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
655 if (tnl
->vtx
.eval
.map2
[i
].map
)
656 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map2
[i
].sz
)
657 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
660 if (ctx
->Eval
.AutoNormal
)
661 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] < 3)
662 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
665 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
666 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
668 _tnl_do_EvalCoord2f( ctx
, u
, v
);
670 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
671 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
674 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
676 _tnl_EvalCoord1f( u
[0] );
679 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
681 _tnl_EvalCoord2f( u
[0], u
[1] );
684 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
686 GET_CURRENT_CONTEXT( ctx
);
687 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
688 (GLfloat
) ctx
->Eval
.MapGrid1un
);
689 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
691 _tnl_EvalCoord1f( u
);
695 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
697 GET_CURRENT_CONTEXT( ctx
);
698 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
699 (GLfloat
) ctx
->Eval
.MapGrid2un
);
700 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
701 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
702 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
703 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
705 _tnl_EvalCoord2f( u
, v
);
709 /* Build a list of primitives on the fly. Keep
710 * ctx->Driver.CurrentExecPrimitive uptodate as well.
712 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
714 GET_CURRENT_CONTEXT( ctx
);
716 if ((ctx
->VertexProgram
.Enabled
717 && !ctx
->VertexProgram
.Current
->Instructions
) ||
718 (ctx
->FragmentProgram
.Enabled
719 && !ctx
->FragmentProgram
.Current
->Instructions
)) {
720 _mesa_error(ctx
, GL_INVALID_OPERATION
,
721 "glBegin (invalid vertex/fragment program)");
725 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
726 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
730 _mesa_update_state( ctx
);
731 if (!(tnl
->Driver
.NotifyBegin
&&
732 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
733 ctx
->Exec
->Begin(mode
);
737 /* Heuristic: attempt to isolate attributes occuring outside
740 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
741 _tnl_FlushVertices( ctx
, ~0 );
743 i
= tnl
->vtx
.prim_count
++;
744 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
745 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
746 tnl
->vtx
.prim
[i
].count
= 0;
748 ctx
->Driver
.CurrentExecPrimitive
= mode
;
751 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
755 static void GLAPIENTRY
_tnl_End( void )
757 GET_CURRENT_CONTEXT( ctx
);
759 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
760 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
761 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
762 int i
= tnl
->vtx
.prim_count
- 1;
764 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
765 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
767 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
769 /* Two choices which effect the way vertex attributes are
770 * carried over (or not) between adjacent primitives.
773 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
774 _tnl_FlushVertices( ctx
, ~0 );
776 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
777 _tnl_flush_vtx( ctx
);
782 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
786 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
788 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
790 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
791 vfmt
->Begin
= _tnl_Begin
;
792 vfmt
->CallList
= _mesa_CallList
;
793 vfmt
->CallLists
= _mesa_CallLists
;
794 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
795 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
796 vfmt
->End
= _tnl_End
;
797 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
798 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
799 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
800 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
801 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
802 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
803 vfmt
->Indexf
= _tnl_Indexf
;
804 vfmt
->Indexfv
= _tnl_Indexfv
;
805 vfmt
->Materialfv
= _tnl_Materialfv
;
807 vfmt
->Rectf
= _mesa_noop_Rectf
;
808 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
809 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
814 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
816 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
818 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
821 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
822 _tnl_flush_vtx( ctx
);
825 if (tnl
->vtx
.vertex_size
) {
826 _tnl_copy_to_current( ctx
);
830 ctx
->Driver
.NeedFlush
= 0;
834 static void _tnl_current_init( GLcontext
*ctx
)
836 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
839 /* setup the pointers for the typical 16 vertex attributes */
840 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
841 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
843 /* setup pointers for the 12 material attributes */
844 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
845 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
846 ctx
->Light
.Material
.Attrib
[i
];
848 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
851 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
856 void _tnl_vtx_init( GLcontext
*ctx
)
858 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
859 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
861 static int firsttime
= 1;
883 choose
[ERROR_ATTRIB
][0] = error_attrib
;
884 choose
[ERROR_ATTRIB
][1] = error_attrib
;
885 choose
[ERROR_ATTRIB
][2] = error_attrib
;
886 choose
[ERROR_ATTRIB
][3] = error_attrib
;
889 if (tnl
->AllowCodegen
) {
890 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
894 _tnl_generic_attr_table_init( generic_attr_func
);
897 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
898 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
900 for (i
= 0; i
< 4; i
++) {
901 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
902 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
903 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
904 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
908 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
911 _tnl_current_init( ctx
);
912 _tnl_exec_vtxfmt_init( ctx
);
913 _tnl_generic_exec_vtxfmt_init( ctx
);
915 if (tnl
->AllowCodegen
) {
916 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
920 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
922 memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
924 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
925 tnl
->vtx
.attrsz
[i
] = 0;
927 tnl
->vtx
.vertex_size
= 0;
928 tnl
->vtx
.have_materials
= 0;
931 static void free_funcs( struct _tnl_dynfn
*l
)
933 struct _tnl_dynfn
*f
, *tmp
;
934 foreach_s (f
, tmp
, l
) {
935 remove_from_list( f
);
936 ALIGN_FREE( f
->code
);
942 void _tnl_vtx_destroy( GLcontext
*ctx
)
944 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
947 for (i
= 0; i
< 4; i
++) {
948 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
949 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );