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 /** Note extra space for error index: */
51 static tnl_attrfv_func choose
[_TNL_ATTRIB_ERROR
+1][4];
52 static tnl_attrfv_func generic_attr_func
[_TNL_MAX_ATTR_CODEGEN
][4];
55 /* Close off the last primitive, execute the buffer, restart the
58 static void _tnl_wrap_buffers( GLcontext
*ctx
)
60 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
63 if (tnl
->vtx
.prim_count
== 0) {
64 tnl
->vtx
.copied
.nr
= 0;
65 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
66 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
69 GLuint last_prim
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].mode
;
72 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
73 GLint i
= tnl
->vtx
.prim_count
- 1;
75 tnl
->vtx
.prim
[i
].count
= ((tnl
->vtx
.initial_counter
-
77 tnl
->vtx
.prim
[i
].start
);
80 last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
82 /* Execute the buffer and save copied vertices.
84 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
)
85 _tnl_flush_vtx( ctx
);
87 tnl
->vtx
.prim_count
= 0;
88 tnl
->vtx
.copied
.nr
= 0;
91 /* Emit a glBegin to start the new list.
93 assert(tnl
->vtx
.prim_count
== 0);
95 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
96 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
97 tnl
->vtx
.prim
[0].start
= 0;
98 tnl
->vtx
.prim
[0].count
= 0;
99 tnl
->vtx
.prim_count
++;
101 if (tnl
->vtx
.copied
.nr
== last_count
)
102 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
108 /* Deal with buffer wrapping where provoked by the vertex buffer
109 * filling up, as opposed to upgrade_vertex().
111 * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
113 void GLAPIENTRY
_tnl_wrap_filled_vertex( GLcontext
*ctx
)
115 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
116 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
119 /* Run pipeline on current vertices, copy wrapped vertices
122 _tnl_wrap_buffers( ctx
);
124 /* Copy stored stored vertices to start of new list.
126 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
128 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
129 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
130 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
131 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
132 data
+= tnl
->vtx
.vertex_size
;
136 tnl
->vtx
.copied
.nr
= 0;
141 * Copy the active vertex's values to the ctx->Current fields.
143 static void _tnl_copy_to_current( GLcontext
*ctx
)
145 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
148 for (i
= _TNL_ATTRIB_POS
+1 ; i
< _TNL_ATTRIB_EDGEFLAG
; i
++) {
149 if (tnl
->vtx
.attrsz
[i
]) {
150 /* Note: the tnl->vtx.current[i] pointers points to
151 * the ctx->Current fields. The first 16 or so, anyway.
153 COPY_CLEAN_4V(tnl
->vtx
.current
[i
],
155 tnl
->vtx
.attrptr
[i
]);
159 /* Edgeflag requires additional treatment:
161 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
162 ctx
->Current
.EdgeFlag
=
163 (tnl
->vtx
.CurrentFloatEdgeFlag
== 1.0);
166 /* Colormaterial -- this kindof sucks.
168 if (ctx
->Light
.ColorMaterialEnabled
) {
169 _mesa_update_color_material(ctx
,
170 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
173 if (tnl
->vtx
.have_materials
) {
174 tnl
->Driver
.NotifyMaterialChange( ctx
);
177 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
181 static void _tnl_copy_from_current( GLcontext
*ctx
)
183 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
186 /* Edgeflag requires additional treatment:
188 tnl
->vtx
.CurrentFloatEdgeFlag
= (GLfloat
) ctx
->Current
.EdgeFlag
;
190 for (i
= _TNL_ATTRIB_POS
+1 ; i
< _TNL_ATTRIB_MAX
; i
++)
191 switch (tnl
->vtx
.attrsz
[i
]) {
192 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
193 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
194 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
195 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
199 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
203 /* Flush existing data, set new attrib size, replay copied vertices.
205 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
209 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
213 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
215 /* Run pipeline on current vertices, copy wrapped vertices
216 * to tnl->vtx.copied.
218 _tnl_wrap_buffers( ctx
);
221 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
222 * when the attribute already exists in the vertex and is having
223 * its size increased.
225 _tnl_copy_to_current( ctx
);
228 /* Heuristic: Attempt to isolate attributes received outside
229 * begin/end so that they don't bloat the vertices.
231 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
232 tnl
->vtx
.attrsz
[attr
] == 0 &&
234 tnl
->vtx
.vertex_size
) {
240 oldsz
= tnl
->vtx
.attrsz
[attr
];
241 tnl
->vtx
.attrsz
[attr
] = newsz
;
243 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
244 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
245 ctx
->Const
.MaxArrayLockSize
);
246 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
247 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
250 /* Recalculate all the attrptr[] values
252 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
253 if (tnl
->vtx
.attrsz
[i
]) {
254 tnl
->vtx
.attrptr
[i
] = tmp
;
255 tmp
+= tnl
->vtx
.attrsz
[i
];
258 tnl
->vtx
.attrptr
[i
] = NULL
; /* will not be dereferenced */
261 /* Copy from current to repopulate the vertex with correct values.
263 _tnl_copy_from_current( ctx
);
265 /* Replay stored vertices to translate them
266 * to new format here.
268 * -- No need to replay - just copy piecewise
270 if (tnl
->vtx
.copied
.nr
)
272 const GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
273 GLfloat
*dest
= tnl
->vtx
.buffer
;
276 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
277 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
278 if (tnl
->vtx
.attrsz
[j
]) {
281 COPY_CLEAN_4V( dest
, oldsz
, data
);
285 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
290 GLuint sz
= tnl
->vtx
.attrsz
[j
];
291 COPY_SZ_4V( dest
, sz
, data
);
299 tnl
->vtx
.vbptr
= dest
;
300 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
301 tnl
->vtx
.copied
.nr
= 0;
304 /* For codegen - attrptr's may have changed, so need to redo
305 * codegen. Might be a reasonable place to try & detect attributes
306 * in the vertex which aren't being submitted any more.
308 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
309 if (tnl
->vtx
.attrsz
[i
]) {
310 GLuint j
= tnl
->vtx
.attrsz
[i
] - 1;
312 if (i
< _TNL_MAX_ATTR_CODEGEN
)
313 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
319 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
321 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
322 static const GLfloat id
[4] = { 0, 0, 0, 1 };
325 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
326 /* New size is larger. Need to flush existing vertices and get
327 * an enlarged vertex format.
329 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
331 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
332 /* New size is smaller - just need to fill in some
333 * zeros. Don't need to flush or wrap.
335 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
336 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
339 /* Does setting NeedFlush belong here? Necessitates resetting
340 * vtxfmt on each flush (otherwise flags won't get reset
344 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
346 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
351 static struct _tnl_dynfn
*lookup( struct _tnl_dynfn
*l
, GLuint key
)
353 struct _tnl_dynfn
*f
;
364 static tnl_attrfv_func
do_codegen( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
366 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
367 struct _tnl_dynfn
*dfn
= NULL
;
370 GLuint key
= tnl
->vtx
.vertex_size
;
372 dfn
= lookup( &tnl
->vtx
.cache
.Vertex
[sz
-1], key
);
375 dfn
= tnl
->vtx
.gen
.Vertex
[sz
-1]( ctx
, key
);
378 GLuint key
= (GLuint
) tnl
->vtx
.attrptr
[attr
];
380 dfn
= lookup( &tnl
->vtx
.cache
.Attribute
[sz
-1], key
);
383 dfn
= tnl
->vtx
.gen
.Attribute
[sz
-1]( ctx
, key
);
387 return *(tnl_attrfv_func
*) &dfn
->code
;
392 #endif /* USE_X86_ASM */
394 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
395 * entrypoint is called for the first time.
398 static tnl_attrfv_func
do_choose( GLuint attr
, GLuint sz
)
400 GET_CURRENT_CONTEXT( ctx
);
401 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
402 GLuint oldsz
= tnl
->vtx
.attrsz
[attr
];
404 assert(attr
< _TNL_MAX_ATTR_CODEGEN
);
407 /* Reset any active pointers for this attribute
410 tnl
->vtx
.tabfv
[attr
][oldsz
-1] = choose
[attr
][oldsz
-1];
412 _tnl_fixup_vertex( ctx
, attr
, sz
);
417 /* Try to use codegen:
420 if (tnl
->AllowCodegen
)
421 tnl
->vtx
.tabfv
[attr
][sz
-1] = do_codegen( ctx
, attr
, sz
);
424 tnl
->vtx
.tabfv
[attr
][sz
-1] = NULL
;
426 /* Else use generic version:
428 if (!tnl
->vtx
.tabfv
[attr
][sz
-1])
429 tnl
->vtx
.tabfv
[attr
][sz
-1] = generic_attr_func
[attr
][sz
-1];
431 ASSERT(tnl
->vtx
.tabfv
[attr
][sz
-1]);
432 return tnl
->vtx
.tabfv
[attr
][sz
-1];
437 #define CHOOSE( ATTR, N ) \
438 static void choose_##ATTR##_##N( const GLfloat *v ) \
440 tnl_attrfv_func f = do_choose(ATTR, N); \
445 #define CHOOSERS( ATTRIB ) \
446 CHOOSE( ATTRIB, 1 ) \
447 CHOOSE( ATTRIB, 2 ) \
448 CHOOSE( ATTRIB, 3 ) \
449 CHOOSE( ATTRIB, 4 ) \
452 #define INIT_CHOOSERS(ATTR) \
453 ASSERT(ATTR <= _TNL_ATTRIB_ERROR);\
454 choose[ATTR][0] = choose_##ATTR##_1; \
455 choose[ATTR][1] = choose_##ATTR##_2; \
456 choose[ATTR][2] = choose_##ATTR##_3; \
457 choose[ATTR][3] = choose_##ATTR##_4;
459 /* conventional attributes */
477 /* generic attributes */
497 * This function will get called when glVertexAttribNV/ARB() is called
498 * with an invalid index parameter.
501 error_attrib(const GLfloat
*unused
)
503 GET_CURRENT_CONTEXT( ctx
);
505 _mesa_error( ctx
, GL_INVALID_VALUE
, "glVertexAttrib(index)" );
511 * Reset all the per-vertex functions pointers to point to the default
512 * "chooser" functions.
515 reset_attrfv(TNLcontext
*tnl
)
519 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
520 if (tnl
->vtx
.attrsz
[i
]) {
521 GLint j
= tnl
->vtx
.attrsz
[i
] - 1;
522 tnl
->vtx
.attrsz
[i
] = 0;
524 if (i
< _TNL_MAX_ATTR_CODEGEN
) {
526 tnl
->vtx
.tabfv
[i
][j
] = choose
[i
][j
];
532 tnl
->vtx
.vertex_size
= 0;
533 tnl
->vtx
.have_materials
= 0;
541 * These are treated as per-vertex attributes, at indices above where
542 * the NV_vertex_program leaves off. There are a lot of good things
543 * about treating materials this way.
545 * However: I don't want to double the number of generated functions
546 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
547 * ATTRF into this function, and dispense with codegen and
548 * second-level dispatch.
550 * There is no aliasing of material attributes with other entrypoints.
552 #define OTHER_ATTR( A, N, params ) \
554 if (tnl->vtx.attrsz[A] != N) { \
555 _tnl_fixup_vertex( ctx, A, N ); \
559 GLfloat *dest = tnl->vtx.attrptr[A]; \
560 if (N>0) dest[0] = (params)[0]; \
561 if (N>1) dest[1] = (params)[1]; \
562 if (N>2) dest[2] = (params)[2]; \
563 if (N>3) dest[3] = (params)[3]; \
568 #define MAT( ATTR, N, face, params ) \
570 if (face != GL_BACK) \
571 OTHER_ATTR( ATTR, N, params ); /* front */ \
572 if (face != GL_FRONT) \
573 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
578 * Called by glMaterialfv().
579 * Colormaterial is dealt with later on.
581 static void GLAPIENTRY
582 _tnl_Materialfv( GLenum face
, GLenum pname
, const GLfloat
*params
)
584 GET_CURRENT_CONTEXT( ctx
);
585 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
590 case GL_FRONT_AND_BACK
:
593 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
599 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
602 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
605 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
608 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
611 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
613 case GL_COLOR_INDEXES
:
614 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
616 case GL_AMBIENT_AND_DIFFUSE
:
617 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
618 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
621 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
625 tnl
->vtx
.have_materials
= GL_TRUE
;
629 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
631 GET_CURRENT_CONTEXT( ctx
);
632 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
633 GLfloat f
= (GLfloat
)b
;
635 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG
, 1, &f
);
641 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
643 GET_CURRENT_CONTEXT( ctx
);
644 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
646 /* TODO: use a CHOOSE() function for this: */
649 if (tnl
->vtx
.eval
.new_state
)
650 _tnl_update_eval( ctx
);
652 for (i
= 0 ; i
<= _TNL_ATTRIB_EDGEFLAG
; i
++) {
653 if (tnl
->vtx
.eval
.map1
[i
].map
)
654 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map1
[i
].sz
)
655 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
660 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
661 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
663 _tnl_do_EvalCoord1f( ctx
, u
);
665 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
666 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
669 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
671 GET_CURRENT_CONTEXT( ctx
);
672 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
674 /* TODO: use a CHOOSE() function for this: */
677 if (tnl
->vtx
.eval
.new_state
)
678 _tnl_update_eval( ctx
);
680 for (i
= 0 ; i
<= _TNL_ATTRIB_EDGEFLAG
; i
++) {
681 if (tnl
->vtx
.eval
.map2
[i
].map
)
682 if (tnl
->vtx
.attrsz
[i
] != tnl
->vtx
.eval
.map2
[i
].sz
)
683 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
686 if (ctx
->Eval
.AutoNormal
)
687 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] != 3)
688 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
691 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
692 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
694 _tnl_do_EvalCoord2f( ctx
, u
, v
);
696 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
697 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
700 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
702 _tnl_EvalCoord1f( u
[0] );
705 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
707 _tnl_EvalCoord2f( u
[0], u
[1] );
710 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
712 GET_CURRENT_CONTEXT( ctx
);
713 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
714 (GLfloat
) ctx
->Eval
.MapGrid1un
);
715 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
717 _tnl_EvalCoord1f( u
);
721 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
723 GET_CURRENT_CONTEXT( ctx
);
724 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
725 (GLfloat
) ctx
->Eval
.MapGrid2un
);
726 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
727 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
728 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
729 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
731 _tnl_EvalCoord2f( u
, v
);
736 * Called from glBegin.
737 * ctx->Driver.CurrentExecPrimitive will be set to <mode>.
739 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
741 GET_CURRENT_CONTEXT( ctx
);
743 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
) {
744 /* we're not inside a glBegin/End pair */
745 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
749 _mesa_update_state( ctx
);
751 if ((ctx
->VertexProgram
.Enabled
&& !ctx
->VertexProgram
._Enabled
) ||
752 (ctx
->FragmentProgram
.Enabled
&& !ctx
->FragmentProgram
._Enabled
)) {
753 _mesa_error(ctx
, GL_INVALID_OPERATION
,
754 "glBegin (invalid vertex/fragment program)");
755 tnl
->DiscardPrimitive
= GL_TRUE
;
759 if (ctx
->DrawBuffer
->_Status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
760 _mesa_error(ctx
, GL_INVALID_FRAMEBUFFER_OPERATION_EXT
,
761 "glBegin(incomplete framebuffer)");
762 tnl
->DiscardPrimitive
= GL_TRUE
;
766 tnl
->DiscardPrimitive
= GL_FALSE
;
768 if (!(tnl
->Driver
.NotifyBegin
&&
769 tnl
->Driver
.NotifyBegin( ctx
, mode
)))
770 CALL_Begin(ctx
->Exec
, (mode
));
774 /* Heuristic: attempt to isolate attributes occuring outside
777 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
778 _tnl_FlushVertices( ctx
, ~0 );
780 i
= tnl
->vtx
.prim_count
++;
781 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
782 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
783 tnl
->vtx
.prim
[i
].count
= 0;
785 ctx
->Driver
.CurrentExecPrimitive
= mode
;
788 /* already inside glBegin/End */
789 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
797 static void GLAPIENTRY
_tnl_End( void )
799 GET_CURRENT_CONTEXT( ctx
);
801 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
802 /* closing an open glBegin primitive */
803 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
804 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
805 int i
= tnl
->vtx
.prim_count
- 1;
807 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
808 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
810 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
812 /* Two choices which effect the way vertex attributes are
813 * carried over (or not) between adjacent primitives.
816 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
817 _tnl_FlushVertices( ctx
, ~0 );
819 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
820 _tnl_flush_vtx( ctx
);
825 /* glBegin hasn't been called! */
826 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
832 * XXX why aren't all members initialized here??
834 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
836 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
838 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
839 vfmt
->Begin
= _tnl_Begin
;
840 vfmt
->CallList
= _mesa_CallList
;
841 vfmt
->CallLists
= _mesa_CallLists
;
842 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
843 vfmt
->End
= _tnl_End
;
844 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
845 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
846 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
847 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
848 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
849 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
850 vfmt
->Materialfv
= _tnl_Materialfv
;
852 vfmt
->Rectf
= _mesa_noop_Rectf
;
853 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
854 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
859 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
861 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
864 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
865 /* still inside a glBegin/End pair. How'd we get here??? */
869 if (tnl
->DiscardPrimitive
) {
870 /* discard any primitives */
871 tnl
->vtx
.prim_count
= 0;
872 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
873 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
876 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
877 _tnl_flush_vtx( ctx
);
880 if (tnl
->vtx
.vertex_size
) {
881 _tnl_copy_to_current( ctx
);
885 ctx
->Driver
.NeedFlush
= 0;
890 * Init the tnl->vtx->current[] pointers to point to the corresponding
891 * fields in ctx->Current attribute group.
893 static void _tnl_current_init( GLcontext
*ctx
)
895 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
898 /* setup the pointers for the typical (32) vertex attributes */
899 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
900 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
902 /* setup pointers for the 12 material attributes */
903 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
904 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
905 ctx
->Light
.Material
.Attrib
[i
];
908 tnl
->vtx
.current
[_TNL_ATTRIB_EDGEFLAG
] = &tnl
->vtx
.CurrentFloatEdgeFlag
;
911 static struct _tnl_dynfn
*no_codegen( GLcontext
*ctx
, int key
)
913 (void) ctx
; (void) key
;
917 void _tnl_vtx_init( GLcontext
*ctx
)
919 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
920 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
922 static int firsttime
= 1;
927 /* conventional attributes */
945 /* generic attributes */
963 choose
[_TNL_ATTRIB_ERROR
][0] = error_attrib
;
964 choose
[_TNL_ATTRIB_ERROR
][1] = error_attrib
;
965 choose
[_TNL_ATTRIB_ERROR
][2] = error_attrib
;
966 choose
[_TNL_ATTRIB_ERROR
][3] = error_attrib
;
969 if (tnl
->AllowCodegen
) {
970 _tnl_x86choosers(choose
, do_choose
); /* x86 INIT_CHOOSERS */
974 _tnl_generic_attr_table_init( generic_attr_func
);
977 for (i
= 0; i
< _TNL_ATTRIB_EDGEFLAG
; i
++)
978 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, NULL
);
980 for (i
= 0; i
< 4; i
++) {
981 make_empty_list( &tnl
->vtx
.cache
.Vertex
[i
] );
982 make_empty_list( &tnl
->vtx
.cache
.Attribute
[i
] );
983 tnl
->vtx
.gen
.Vertex
[i
] = no_codegen
;
984 tnl
->vtx
.gen
.Attribute
[i
] = no_codegen
;
988 _tnl_InitX86Codegen( &tnl
->vtx
.gen
);
991 _tnl_current_init( ctx
);
992 _tnl_exec_vtxfmt_init( ctx
);
993 _tnl_generic_exec_vtxfmt_init( ctx
);
995 if (tnl
->AllowCodegen
) {
996 _tnl_x86_exec_vtxfmt_init( ctx
); /* x86 DISPATCH_ATTRFV */
1000 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
1002 _mesa_memcpy( tnl
->vtx
.tabfv
, choose
, sizeof(choose
) );
1004 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
1005 tnl
->vtx
.attrsz
[i
] = 0;
1007 tnl
->vtx
.vertex_size
= 0;
1008 tnl
->vtx
.have_materials
= 0;
1011 static void free_funcs( struct _tnl_dynfn
*l
)
1013 struct _tnl_dynfn
*f
, *tmp
;
1014 foreach_s (f
, tmp
, l
) {
1015 remove_from_list( f
);
1016 ALIGN_FREE( f
->code
);
1022 void _tnl_vtx_destroy( GLcontext
*ctx
)
1024 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1027 for (i
= 0; i
< 4; i
++) {
1028 free_funcs( &tnl
->vtx
.cache
.Vertex
[i
] );
1029 free_funcs( &tnl
->vtx
.cache
.Attribute
[i
] );