1 /**************************************************************************
3 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Keith Whitwell <keith@tungstengraphics.com>
40 #include "api_arrayelt.h"
42 #include "t_vtx_api.h"
43 #include "simple_list.h"
47 static void reset_attrfv( TNLcontext
*tnl
);
49 /** Note extra space for error index: */
50 static tnl_attrfv_func choose
[_TNL_ATTRIB_ERROR
+1][4];
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
!= PRIM_OUTSIDE_BEGIN_END
) {
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
!= PRIM_OUTSIDE_BEGIN_END
) {
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_EDGEFLAG
; 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 /* Edgeflag requires additional treatment:
160 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
161 ctx
->Current
.EdgeFlag
=
162 (tnl
->vtx
.CurrentFloatEdgeFlag
== 1.0);
165 /* Colormaterial -- this kindof sucks.
167 if (ctx
->Light
.ColorMaterialEnabled
) {
168 _mesa_update_color_material(ctx
,
169 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
172 if (tnl
->vtx
.have_materials
) {
173 tnl
->Driver
.NotifyMaterialChange( ctx
);
176 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
178 ctx
->NewState
|= _NEW_LIGHT
;
182 static void _tnl_copy_from_current( GLcontext
*ctx
)
184 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
187 /* Edgeflag requires additional treatment:
189 tnl
->vtx
.CurrentFloatEdgeFlag
= (GLfloat
) ctx
->Current
.EdgeFlag
;
191 for (i
= _TNL_ATTRIB_POS
+1 ; i
< _TNL_ATTRIB_MAX
; i
++)
192 switch (tnl
->vtx
.attrsz
[i
]) {
193 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
194 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
195 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
196 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
200 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
204 /* Flush existing data, set new attrib size, replay copied vertices.
206 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
210 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
214 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
216 /* Run pipeline on current vertices, copy wrapped vertices
217 * to tnl->vtx.copied.
219 _tnl_wrap_buffers( ctx
);
222 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
223 * when the attribute already exists in the vertex and is having
224 * its size increased.
226 _tnl_copy_to_current( ctx
);
229 /* Heuristic: Attempt to isolate attributes received outside
230 * begin/end so that they don't bloat the vertices.
232 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
233 tnl
->vtx
.attrsz
[attr
] == 0 &&
235 tnl
->vtx
.vertex_size
) {
241 oldsz
= tnl
->vtx
.attrsz
[attr
];
242 tnl
->vtx
.attrsz
[attr
] = newsz
;
244 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
245 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
246 ctx
->Const
.MaxArrayLockSize
);
247 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
248 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
251 /* Recalculate all the attrptr[] values
253 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
254 if (tnl
->vtx
.attrsz
[i
]) {
255 tnl
->vtx
.attrptr
[i
] = tmp
;
256 tmp
+= tnl
->vtx
.attrsz
[i
];
259 tnl
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
262 /* Copy from current to repopulate the vertex with correct values.
264 _tnl_copy_from_current( ctx
);
266 /* Replay stored vertices to translate them
267 * to new format here.
269 * -- No need to replay - just copy piecewise
271 if (tnl
->vtx
.copied
.nr
)
273 const GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
274 GLfloat
*dest
= tnl
->vtx
.buffer
;
277 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
278 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
279 if (tnl
->vtx
.attrsz
[j
]) {
282 COPY_CLEAN_4V( dest
, oldsz
, data
);
286 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
291 GLuint sz
= tnl
->vtx
.attrsz
[j
];
292 COPY_SZ_4V( dest
, sz
, data
);
300 tnl
->vtx
.vbptr
= dest
;
301 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
302 tnl
->vtx
.copied
.nr
= 0;
305 /* For codegen - attrptr's may have changed, so need to redo
306 * codegen. Might be a reasonable place to try & detect attributes
307 * in the vertex which aren't being submitted any more.
309 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
310 if (tnl
->vtx
.attrsz
[i
]) {
311 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
313 if (i
< _TNL_MAX_ATTR_CODEGEN
)
314 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
320 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
322 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
323 static const GLfloat id
[4] = { 0, 0, 0, 1 };
327 _mesa_printf("%s attr %d sz %d -> %d\n",
328 __FUNCTION__
, attr
, tnl
->vtx
.attrsz
[attr
], sz
);
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 (sz
< tnl
->vtx
.active_sz
[attr
]) {
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 tnl
->vtx
.active_sz
[attr
] = sz
;
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
.active_sz
[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 ASSERT(tnl
->vtx
.tabfv
[attr
][sz
-1]);
439 return tnl
->vtx
.tabfv
[attr
][sz
-1];
444 #define CHOOSE( ATTR, N ) \
445 static void choose_##ATTR##_##N( const GLfloat *v ) \
447 tnl_attrfv_func f = do_choose(ATTR, N); \
452 #define CHOOSERS( ATTRIB ) \
453 CHOOSE( ATTRIB, 1 ) \
454 CHOOSE( ATTRIB, 2 ) \
455 CHOOSE( ATTRIB, 3 ) \
456 CHOOSE( ATTRIB, 4 ) \
459 #define INIT_CHOOSERS(ATTR) \
460 ASSERT(ATTR <= _TNL_ATTRIB_ERROR);\
461 choose[ATTR][0] = choose_##ATTR##_1; \
462 choose[ATTR][1] = choose_##ATTR##_2; \
463 choose[ATTR][2] = choose_##ATTR##_3; \
464 choose[ATTR][3] = choose_##ATTR##_4;
466 /* conventional attributes */
484 /* generic attributes */
504 * This function will get called when glVertexAttribNV/ARB() is called
505 * with an invalid index parameter.
508 error_attrib(const GLfloat
*unused
)
510 GET_CURRENT_CONTEXT( ctx
);
512 _mesa_error( ctx
, GL_INVALID_VALUE
, "glVertexAttrib(index)" );
518 * Reset all the per-vertex functions pointers to point to the default
519 * "chooser" functions.
522 reset_attrfv(TNLcontext
*tnl
)
526 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
527 if (tnl
->vtx
.attrsz
[i
]) {
528 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
529 tnl
->vtx
.attrsz
[i
] = 0;
530 tnl
->vtx
.active_sz
[i
] = 0;
532 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
534 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
540 tnl
->vtx
.vertex_size
= 0;
541 tnl
->vtx
.have_materials
= 0;
549 * These are treated as per-vertex attributes, at indices above where
550 * the NV_vertex_program leaves off. There are a lot of good things
551 * about treating materials this way.
553 * However: I don't want to double the number of generated functions
554 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
555 * ATTRF into this function, and dispense with codegen and
556 * second-level dispatch.
558 * There is no aliasing of material attributes with other entrypoints.
560 #define OTHER_ATTR( A, N, params ) \
562 if (tnl->vtx.active_sz[A] != N) { \
563 _tnl_fixup_vertex( ctx, A, N ); \
567 GLfloat *dest = tnl->vtx.attrptr[A]; \
568 if (N>0) dest[0] = (params)[0]; \
569 if (N>1) dest[1] = (params)[1]; \
570 if (N>2) dest[2] = (params)[2]; \
571 if (N>3) dest[3] = (params)[3]; \
576 #define MAT( ATTR, N, face, params ) \
578 if (face != GL_BACK) \
579 OTHER_ATTR( ATTR, N, params ); /* front */ \
580 if (face != GL_FRONT) \
581 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
586 * Called by glMaterialfv().
587 * Colormaterial is dealt with later on.
589 static void GLAPIENTRY
590 _tnl_Materialfv( GLenum face
, GLenum pname
, const GLfloat
*params
)
592 GET_CURRENT_CONTEXT( ctx
);
593 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
598 case GL_FRONT_AND_BACK
:
601 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
607 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
610 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
613 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
616 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
619 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
621 case GL_COLOR_INDEXES
:
622 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
624 case GL_AMBIENT_AND_DIFFUSE
:
625 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
626 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
629 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
633 tnl
->vtx
.have_materials
= GL_TRUE
;
637 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
639 GET_CURRENT_CONTEXT( ctx
);
640 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
641 GLfloat f
= (GLfloat
)b
;
643 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
649 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
651 GET_CURRENT_CONTEXT( ctx
);
652 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
654 /* TODO: use a CHOOSE() function for this: */
657 if (tnl
->vtx
.eval
.new_state
)
658 _tnl_update_eval( ctx
);
660 for (i
= 0; i
< _TNL_NUM_EVAL
; i
++) {
661 if (tnl
->vtx
.eval
.map1
[i
].map
)
662 if (tnl
->vtx
.active_sz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
663 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
668 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
669 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
671 _tnl_do_EvalCoord1f( ctx
, u
);
673 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
674 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
677 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
679 GET_CURRENT_CONTEXT( ctx
);
680 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
682 /* TODO: use a CHOOSE() function for this: */
685 if (tnl
->vtx
.eval
.new_state
)
686 _tnl_update_eval( ctx
);
688 for (i
= 0; i
< _TNL_NUM_EVAL
; i
++) {
689 if (tnl
->vtx
.eval
.map2
[i
].map
)
690 if (tnl
->vtx
.active_sz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
691 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
694 if (ctx
->Eval
.AutoNormal
)
695 if (tnl
->vtx
.active_sz
[_TNL_ATTRIB_NORMAL
] != 3)
696 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
699 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
700 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
702 _tnl_do_EvalCoord2f( ctx
, u
, v
);
704 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
705 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
708 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
710 _tnl_EvalCoord1f( u
[0] );
713 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
715 _tnl_EvalCoord2f( u
[0], u
[1] );
718 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
720 GET_CURRENT_CONTEXT( ctx
);
721 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
722 (GLfloat
) ctx
->Eval
.MapGrid1un
);
723 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
725 _tnl_EvalCoord1f( u
);
729 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
731 GET_CURRENT_CONTEXT( ctx
);
732 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
733 (GLfloat
) ctx
->Eval
.MapGrid2un
);
734 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
735 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
736 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
737 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
739 _tnl_EvalCoord2f( u
, v
);
744 * Called from glBegin.
745 * ctx->Driver.CurrentExecPrimitive will be set to <mode>.
747 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
749 GET_CURRENT_CONTEXT( ctx
);
751 if (mode
> GL_POLYGON
) {
752 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBegin(mode)");
756 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
757 /* we're not inside a glBegin/End pair */
758 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
762 _mesa_update_state( ctx
);
764 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
765 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
766 _mesa_error(ctx
, GL_INVALID_OPERATION
,
767 "glBegin (invalid vertex/fragment program)");
768 tnl
->DiscardPrimitive
= GL_TRUE
;
772 if (ctx
->DrawBuffer
->_Status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
773 _mesa_error(ctx
, GL_INVALID_FRAMEBUFFER_OPERATION_EXT
,
774 "glBegin(incomplete framebuffer)");
775 tnl
->DiscardPrimitive
= GL_TRUE
;
779 tnl
->DiscardPrimitive
= GL_FALSE
;
781 if (!(tnl
->Driver
.NotifyBegin
&&
782 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
783 CALL_Begin(ctx
->Exec
, (mode
));
787 /* Heuristic: attempt to isolate attributes occuring outside
790 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
791 _tnl_FlushVertices( ctx
, ~0 );
793 i
= tnl
->vtx
.prim_count
++;
794 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
795 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
796 tnl
->vtx
.prim
[i
].count
= 0;
798 ctx
->Driver
.CurrentExecPrimitive
= mode
;
801 /* already inside glBegin/End */
802 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
810 static void GLAPIENTRY
_tnl_End( void )
812 GET_CURRENT_CONTEXT( ctx
);
814 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
815 /* closing an open glBegin primitive */
816 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
817 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
818 int i
= tnl
->vtx
.prim_count
- 1;
820 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
821 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
823 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
825 /* Two choices which effect the way vertex attributes are
826 * carried over (or not) between adjacent primitives.
829 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
830 _tnl_FlushVertices( ctx
, ~0 );
832 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
833 _tnl_flush_vtx( ctx
);
838 /* glBegin hasn't been called! */
839 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
845 * XXX why aren't all members initialized here??
847 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
849 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
851 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
852 vfmt
->Begin
= _tnl_Begin
;
853 vfmt
->CallList
= _mesa_CallList
;
854 vfmt
->CallLists
= _mesa_CallLists
;
855 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
856 vfmt
->End
= _tnl_End
;
857 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
858 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
859 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
860 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
861 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
862 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
863 vfmt
->Materialfv
= _tnl_Materialfv
;
865 vfmt
->Rectf
= _mesa_noop_Rectf
;
866 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
867 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
872 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
874 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
877 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
878 /* still inside a glBegin/End pair. How'd we get here??? */
882 if (tnl
->DiscardPrimitive
) {
883 /* discard any primitives */
884 tnl
->vtx
.prim_count
= 0;
885 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
886 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
889 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
890 _tnl_flush_vtx( ctx
);
893 if (tnl
->vtx
.vertex_size
) {
894 _tnl_copy_to_current( ctx
);
898 ctx
->Driver
.NeedFlush
= 0;
903 * Init the tnl->vtx->current[] pointers to point to the corresponding
904 * fields in ctx->Current attribute group.
906 static void _tnl_current_init( GLcontext
*ctx
)
908 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
911 /* setup the pointers for the typical (32) vertex attributes */
912 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
913 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
915 /* setup pointers for the 12 material attributes */
916 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
917 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
918 ctx
->Light
.Material
.Attrib
[i
];
921 tnl
->vtx
.current
[_TNL_ATTRIB_EDGEFLAG
] = &tnl
->vtx
.CurrentFloatEdgeFlag
;
924 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
926 (void) ctx
; (void) key
;
930 void _tnl_vtx_init( GLcontext
*ctx
)
932 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
933 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
935 static int firsttime
= 1;
940 /* conventional attributes */
958 /* generic attributes */
976 choose
[_TNL_ATTRIB_ERROR
][0] = error_attrib
;
977 choose
[_TNL_ATTRIB_ERROR
][1] = error_attrib
;
978 choose
[_TNL_ATTRIB_ERROR
][2] = error_attrib
;
979 choose
[_TNL_ATTRIB_ERROR
][3] = error_attrib
;
982 if (tnl
->AllowCodegen
) {
983 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
987 _tnl_generic_attr_table_init( generic_attr_func
);
990 for (i
= 0; i
< _TNL_ATTRIB_EDGEFLAG
; i
++)
991 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, NULL
);
993 for (i
= 0; i
< 4; i
++) {
994 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
995 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
996 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
997 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
1001 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
1004 _tnl_current_init( ctx
);
1005 _tnl_exec_vtxfmt_init( ctx
);
1006 _tnl_generic_exec_vtxfmt_init( ctx
);
1008 if (tnl
->AllowCodegen
) {
1009 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
1013 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
1015 _mesa_memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
1017 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++) {
1018 tnl
->vtx
.attrsz
[i
] = 0;
1019 tnl
->vtx
.active_sz
[i
] = 0;
1022 tnl
->vtx
.vertex_size
= 0;
1023 tnl
->vtx
.have_materials
= 0;
1026 static void free_funcs( struct _tnl_dynfn
*l
)
1028 struct _tnl_dynfn
*f
, *tmp
;
1029 foreach_s (f
, tmp
, l
) {
1030 remove_from_list( f
);
1031 ALIGN_FREE( f
->code
);
1037 void _tnl_vtx_destroy( GLcontext
*ctx
)
1039 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1042 for (i
= 0; i
< 4; i
++) {
1043 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
1044 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );