change an assertion
[mesa.git] / src / mesa / tnl / t_vtx_api.c
1 /* $XFree86$ */
2 /**************************************************************************
3
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
5
6 All Rights Reserved.
7
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:
14
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
17 Software.
18
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.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell <keith@tungstengraphics.com>
32 */
33
34 #include "glheader.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "vtxfmt.h"
38 #include "dlist.h"
39 #include "state.h"
40 #include "light.h"
41 #include "api_arrayelt.h"
42 #include "api_noop.h"
43 #include "t_vtx_api.h"
44 #include "simple_list.h"
45
46 #include "dispatch.h"
47
48 static void reset_attrfv( TNLcontext *tnl );
49
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];
52
53
54 /* Close off the last primitive, execute the buffer, restart the
55 * primitive.
56 */
57 static void _tnl_wrap_buffers( GLcontext *ctx )
58 {
59 TNLcontext *tnl = TNL_CONTEXT(ctx);
60
61
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;
66 }
67 else {
68 GLuint last_prim = tnl->vtx.prim[tnl->vtx.prim_count-1].mode;
69 GLuint last_count;
70
71 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
72 GLint i = tnl->vtx.prim_count - 1;
73 assert(i >= 0);
74 tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter -
75 tnl->vtx.counter) -
76 tnl->vtx.prim[i].start);
77 }
78
79 last_count = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
80
81 /* Execute the buffer and save copied vertices.
82 */
83 if (tnl->vtx.counter != tnl->vtx.initial_counter)
84 _tnl_flush_vtx( ctx );
85 else {
86 tnl->vtx.prim_count = 0;
87 tnl->vtx.copied.nr = 0;
88 }
89
90 /* Emit a glBegin to start the new list.
91 */
92 assert(tnl->vtx.prim_count == 0);
93
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++;
99
100 if (tnl->vtx.copied.nr == last_count)
101 tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
102 }
103 }
104 }
105
106
107 /* Deal with buffer wrapping where provoked by the vertex buffer
108 * filling up, as opposed to upgrade_vertex().
109 *
110 * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
111 */
112 void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx )
113 {
114 TNLcontext *tnl = TNL_CONTEXT(ctx);
115 GLfloat *data = tnl->vtx.copied.buffer;
116 GLuint i;
117
118 /* Run pipeline on current vertices, copy wrapped vertices
119 * to tnl->copied.
120 */
121 _tnl_wrap_buffers( ctx );
122
123 /* Copy stored stored vertices to start of new list.
124 */
125 assert(tnl->vtx.counter > tnl->vtx.copied.nr);
126
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;
132 tnl->vtx.counter--;
133 }
134
135 tnl->vtx.copied.nr = 0;
136 }
137
138
139 /*
140 * Copy the active vertex's values to the ctx->Current fields.
141 */
142 static void _tnl_copy_to_current( GLcontext *ctx )
143 {
144 TNLcontext *tnl = TNL_CONTEXT(ctx);
145 GLuint i;
146
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.
151 */
152 COPY_CLEAN_4V(tnl->vtx.current[i],
153 tnl->vtx.attrsz[i],
154 tnl->vtx.attrptr[i]);
155 }
156 }
157
158 /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
159 * will trash adjacent memory!)
160 */
161 if (tnl->vtx.attrsz[_TNL_ATTRIB_INDEX]) {
162 ctx->Current.Index = tnl->vtx.attrptr[_TNL_ATTRIB_INDEX][0];
163 }
164
165 /* Edgeflag requires additional treatment:
166 */
167 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
168 ctx->Current.EdgeFlag =
169 (tnl->vtx.CurrentFloatEdgeFlag == 1.0);
170 }
171
172 /* Colormaterial -- this kindof sucks.
173 */
174 if (ctx->Light.ColorMaterialEnabled) {
175 _mesa_update_color_material(ctx,
176 ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
177 }
178
179 if (tnl->vtx.have_materials) {
180 tnl->Driver.NotifyMaterialChange( ctx );
181 }
182
183 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
184 }
185
186
187 static void _tnl_copy_from_current( GLcontext *ctx )
188 {
189 TNLcontext *tnl = TNL_CONTEXT(ctx);
190 GLint i;
191
192 /* Edgeflag requires additional treatment:
193 */
194 tnl->vtx.CurrentFloatEdgeFlag =
195 (GLfloat)ctx->Current.EdgeFlag;
196
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];
203 break;
204 }
205
206 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
207 }
208
209
210 /* Flush existing data, set new attrib size, replay copied vertices.
211 */
212 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
213 GLuint attr,
214 GLuint newsz )
215 {
216 TNLcontext *tnl = TNL_CONTEXT(ctx);
217 GLuint oldsz;
218 GLuint i;
219 GLfloat *tmp;
220 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
221
222 /* Run pipeline on current vertices, copy wrapped vertices
223 * to tnl->vtx.copied.
224 */
225 _tnl_wrap_buffers( ctx );
226
227
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.
231 */
232 _tnl_copy_to_current( ctx );
233
234
235 /* Heuristic: Attempt to isolate attributes received outside
236 * begin/end so that they don't bloat the vertices.
237 */
238 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
239 tnl->vtx.attrsz[attr] == 0 &&
240 lastcount > 8 &&
241 tnl->vtx.vertex_size) {
242 reset_attrfv( tnl );
243 }
244
245 /* Fix up sizes:
246 */
247 oldsz = tnl->vtx.attrsz[attr];
248 tnl->vtx.attrsz[attr] = newsz;
249
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;
255
256
257 /* Recalculate all the attrptr[] values
258 */
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];
263 }
264 else
265 tnl->vtx.attrptr[i] = NULL; /* will not be dereferenced */
266 }
267
268 /* Copy from current to repopulate the vertex with correct values.
269 */
270 _tnl_copy_from_current( ctx );
271
272 /* Replay stored vertices to translate them
273 * to new format here.
274 *
275 * -- No need to replay - just copy piecewise
276 */
277 if (tnl->vtx.copied.nr)
278 {
279 GLfloat *data = tnl->vtx.copied.buffer;
280 GLfloat *dest = tnl->vtx.buffer;
281 GLuint j;
282
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]) {
286 if (j == attr) {
287 if (oldsz) {
288 COPY_CLEAN_4V( dest, oldsz, data );
289 data += oldsz;
290 dest += newsz;
291 } else {
292 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
293 dest += newsz;
294 }
295 }
296 else {
297 GLuint sz = tnl->vtx.attrsz[j];
298 COPY_SZ_4V( dest, sz, data );
299 dest += sz;
300 data += sz;
301 }
302 }
303 }
304 }
305
306 tnl->vtx.vbptr = dest;
307 tnl->vtx.counter -= tnl->vtx.copied.nr;
308 tnl->vtx.copied.nr = 0;
309 }
310
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.
314 */
315 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
316 if (tnl->vtx.attrsz[i]) {
317 GLuint j = tnl->vtx.attrsz[i] - 1;
318
319 if (i < _TNL_MAX_ATTR_CODEGEN)
320 tnl->vtx.tabfv[i][j] = choose[i][j];
321 }
322
323 }
324
325
326 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
327 {
328 TNLcontext *tnl = TNL_CONTEXT(ctx);
329 static const GLfloat id[4] = { 0, 0, 0, 1 };
330 int i;
331
332 if (tnl->vtx.attrsz[attr] < sz) {
333 /* New size is larger. Need to flush existing vertices and get
334 * an enlarged vertex format.
335 */
336 _tnl_wrap_upgrade_vertex( ctx, attr, sz );
337 }
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.
341 */
342 for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
343 tnl->vtx.attrptr[attr][i-1] = id[i-1];
344 }
345
346 /* Does setting NeedFlush belong here? Necessitates resetting
347 * vtxfmt on each flush (otherwise flags won't get reset
348 * afterwards).
349 */
350 if (attr == 0)
351 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
352 else
353 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
354 }
355
356 #ifdef USE_X86_ASM
357
358 static struct _tnl_dynfn *lookup( struct _tnl_dynfn *l, GLuint key )
359 {
360 struct _tnl_dynfn *f;
361
362 foreach( f, l ) {
363 if (f->key == key)
364 return f;
365 }
366
367 return NULL;
368 }
369
370
371 static tnl_attrfv_func do_codegen( GLcontext *ctx, GLuint attr, GLuint sz )
372 {
373 TNLcontext *tnl = TNL_CONTEXT(ctx);
374 struct _tnl_dynfn *dfn = NULL;
375
376 if (attr == 0) {
377 GLuint key = tnl->vtx.vertex_size;
378
379 dfn = lookup( &tnl->vtx.cache.Vertex[sz-1], key );
380
381 if (!dfn)
382 dfn = tnl->vtx.gen.Vertex[sz-1]( ctx, key );
383 }
384 else {
385 GLuint key = (GLuint) tnl->vtx.attrptr[attr];
386
387 dfn = lookup( &tnl->vtx.cache.Attribute[sz-1], key );
388
389 if (!dfn)
390 dfn = tnl->vtx.gen.Attribute[sz-1]( ctx, key );
391 }
392
393 if (dfn)
394 return *(tnl_attrfv_func *) &dfn->code;
395 else
396 return NULL;
397 }
398
399 #endif /* USE_X86_ASM */
400
401 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
402 * entrypoint is called for the first time.
403 */
404
405 static tnl_attrfv_func do_choose( GLuint attr, GLuint sz )
406 {
407 GET_CURRENT_CONTEXT( ctx );
408 TNLcontext *tnl = TNL_CONTEXT(ctx);
409 GLuint oldsz = tnl->vtx.attrsz[attr];
410
411 assert(attr < _TNL_MAX_ATTR_CODEGEN);
412
413 if (oldsz != sz) {
414 /* Reset any active pointers for this attribute
415 */
416 if (oldsz)
417 tnl->vtx.tabfv[attr][oldsz-1] = choose[attr][oldsz-1];
418
419 _tnl_fixup_vertex( ctx, attr, sz );
420
421 }
422
423
424 /* Try to use codegen:
425 */
426 #ifdef USE_X86_ASM
427 if (tnl->AllowCodegen)
428 tnl->vtx.tabfv[attr][sz-1] = do_codegen( ctx, attr, sz );
429 else
430 #endif
431 tnl->vtx.tabfv[attr][sz-1] = NULL;
432
433 /* Else use generic version:
434 */
435 if (!tnl->vtx.tabfv[attr][sz-1])
436 tnl->vtx.tabfv[attr][sz-1] = generic_attr_func[attr][sz-1];
437
438 return tnl->vtx.tabfv[attr][sz-1];
439 }
440
441
442
443 #define CHOOSE( ATTR, N ) \
444 static void choose_##ATTR##_##N( const GLfloat *v ) \
445 { \
446 tnl_attrfv_func f = do_choose(ATTR, N); \
447 f( v ); \
448 }
449
450 #define CHOOSERS( ATTRIB ) \
451 CHOOSE( ATTRIB, 1 ) \
452 CHOOSE( ATTRIB, 2 ) \
453 CHOOSE( ATTRIB, 3 ) \
454 CHOOSE( ATTRIB, 4 ) \
455
456
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;
462
463 CHOOSERS( 0 )
464 CHOOSERS( 1 )
465 CHOOSERS( 2 )
466 CHOOSERS( 3 )
467 CHOOSERS( 4 )
468 CHOOSERS( 5 )
469 CHOOSERS( 6 )
470 CHOOSERS( 7 )
471 CHOOSERS( 8 )
472 CHOOSERS( 9 )
473 CHOOSERS( 10 )
474 CHOOSERS( 11 )
475 CHOOSERS( 12 )
476 CHOOSERS( 13 )
477 CHOOSERS( 14 )
478 CHOOSERS( 15 )
479
480 static void error_attrib( const GLfloat *unused )
481 {
482 GET_CURRENT_CONTEXT( ctx );
483 (void) unused;
484 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
485 }
486
487
488
489 static void reset_attrfv( TNLcontext *tnl )
490 {
491 GLuint i;
492
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;
497
498 if (i < _TNL_MAX_ATTR_CODEGEN) {
499 while (j >= 0) {
500 tnl->vtx.tabfv[i][j] = choose[i][j];
501 j--;
502 }
503 }
504 }
505
506 tnl->vtx.vertex_size = 0;
507 tnl->vtx.have_materials = 0;
508 }
509
510
511
512 /* Materials:
513 *
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.
517 *
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.
522 *
523 * There is no aliasing of material attributes with other entrypoints.
524 */
525 #define OTHER_ATTR( A, N, params ) \
526 do { \
527 if (tnl->vtx.attrsz[A] != N) { \
528 _tnl_fixup_vertex( ctx, A, N ); \
529 } \
530 \
531 { \
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]; \
537 } \
538 } while (0)
539
540
541 #define MAT( ATTR, N, face, params ) \
542 do { \
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 */ \
547 } while (0)
548
549
550 /* Colormaterial is dealt with later on.
551 */
552 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
553 const GLfloat *params )
554 {
555 GET_CURRENT_CONTEXT( ctx );
556 TNLcontext *tnl = TNL_CONTEXT(ctx);
557
558 switch (face) {
559 case GL_FRONT:
560 case GL_BACK:
561 case GL_FRONT_AND_BACK:
562 break;
563
564 default:
565 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
566 return;
567 }
568
569 switch (pname) {
570 case GL_EMISSION:
571 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
572 break;
573 case GL_AMBIENT:
574 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
575 break;
576 case GL_DIFFUSE:
577 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
578 break;
579 case GL_SPECULAR:
580 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
581 break;
582 case GL_SHININESS:
583 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
584 break;
585 case GL_COLOR_INDEXES:
586 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
587 break;
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 );
591 break;
592 default:
593 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
594 return;
595 }
596
597 tnl->vtx.have_materials = GL_TRUE;
598 }
599
600
601 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
602 {
603 GET_CURRENT_CONTEXT( ctx );
604 TNLcontext *tnl = TNL_CONTEXT(ctx);
605 GLfloat f = (GLfloat)b;
606
607 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
608 }
609
610 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
611 {
612 GET_CURRENT_CONTEXT( ctx );
613 TNLcontext *tnl = TNL_CONTEXT(ctx);
614 GLfloat f = (GLfloat)v[0];
615
616 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
617 }
618
619 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
620 {
621 GET_CURRENT_CONTEXT( ctx );
622 TNLcontext *tnl = TNL_CONTEXT(ctx);
623
624 OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, &f );
625 }
626
627 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
628 {
629 GET_CURRENT_CONTEXT( ctx );
630 TNLcontext *tnl = TNL_CONTEXT(ctx);
631
632 OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, v );
633 }
634
635 /* Eval
636 */
637 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
638 {
639 GET_CURRENT_CONTEXT( ctx );
640 TNLcontext *tnl = TNL_CONTEXT(ctx);
641
642 /* TODO: use a CHOOSE() function for this: */
643 {
644 GLint i;
645 if (tnl->vtx.eval.new_state)
646 _tnl_update_eval( ctx );
647
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 );
652 }
653 }
654
655
656 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
657 tnl->vtx.vertex_size * sizeof(GLfloat));
658
659 _tnl_do_EvalCoord1f( ctx, u );
660
661 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
662 tnl->vtx.vertex_size * sizeof(GLfloat));
663 }
664
665 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
666 {
667 GET_CURRENT_CONTEXT( ctx );
668 TNLcontext *tnl = TNL_CONTEXT(ctx);
669
670 /* TODO: use a CHOOSE() function for this: */
671 {
672 GLint i;
673 if (tnl->vtx.eval.new_state)
674 _tnl_update_eval( ctx );
675
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 );
680 }
681
682 if (ctx->Eval.AutoNormal)
683 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] != 3)
684 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
685 }
686
687 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
688 tnl->vtx.vertex_size * sizeof(GLfloat));
689
690 _tnl_do_EvalCoord2f( ctx, u, v );
691
692 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
693 tnl->vtx.vertex_size * sizeof(GLfloat));
694 }
695
696 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
697 {
698 _tnl_EvalCoord1f( u[0] );
699 }
700
701 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
702 {
703 _tnl_EvalCoord2f( u[0], u[1] );
704 }
705
706 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
707 {
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;
712
713 _tnl_EvalCoord1f( u );
714 }
715
716
717 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
718 {
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;
726
727 _tnl_EvalCoord2f( u, v );
728 }
729
730
731 /* Build a list of primitives on the fly. Keep
732 * ctx->Driver.CurrentExecPrimitive uptodate as well.
733 */
734 static void GLAPIENTRY _tnl_Begin( GLenum mode )
735 {
736 GET_CURRENT_CONTEXT( ctx );
737
738 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
739 /* we're not inside a glBegin/End pair */
740 TNLcontext *tnl = TNL_CONTEXT(ctx);
741 int i;
742
743 if (ctx->NewState) {
744 _mesa_update_state( ctx );
745
746 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
747 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
748 _mesa_error(ctx, GL_INVALID_OPERATION,
749 "glBegin (invalid vertex/fragment program)");
750 return;
751 }
752
753 if (!(tnl->Driver.NotifyBegin &&
754 tnl->Driver.NotifyBegin( ctx, mode )))
755 CALL_Begin(ctx->Exec, (mode));
756 return;
757 }
758
759 /* Heuristic: attempt to isolate attributes occuring outside
760 * begin/end pairs.
761 */
762 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
763 _tnl_FlushVertices( ctx, ~0 );
764
765 i = tnl->vtx.prim_count++;
766 tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
767 tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
768 tnl->vtx.prim[i].count = 0;
769
770 ctx->Driver.CurrentExecPrimitive = mode;
771 }
772 else {
773 /* already inside glBegin/End */
774 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
775 }
776 }
777
778
779 static void GLAPIENTRY _tnl_End( void )
780 {
781 GET_CURRENT_CONTEXT( ctx );
782
783 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
784 TNLcontext *tnl = TNL_CONTEXT(ctx);
785 int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
786 int i = tnl->vtx.prim_count - 1;
787
788 tnl->vtx.prim[i].mode |= PRIM_END;
789 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
790
791 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
792
793 /* Two choices which effect the way vertex attributes are
794 * carried over (or not) between adjacent primitives.
795 */
796 #if 0
797 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
798 _tnl_FlushVertices( ctx, ~0 );
799 #else
800 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
801 _tnl_flush_vtx( ctx );
802 #endif
803
804 }
805 else
806 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
807 }
808
809
810 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
811 {
812 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
813
814 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
815 vfmt->Begin = _tnl_Begin;
816 vfmt->CallList = _mesa_CallList;
817 vfmt->CallLists = _mesa_CallLists;
818 vfmt->EdgeFlag = _tnl_EdgeFlag;
819 vfmt->EdgeFlagv = _tnl_EdgeFlagv;
820 vfmt->End = _tnl_End;
821 vfmt->EvalCoord1f = _tnl_EvalCoord1f;
822 vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
823 vfmt->EvalCoord2f = _tnl_EvalCoord2f;
824 vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
825 vfmt->EvalPoint1 = _tnl_EvalPoint1;
826 vfmt->EvalPoint2 = _tnl_EvalPoint2;
827 vfmt->Indexf = _tnl_Indexf;
828 vfmt->Indexfv = _tnl_Indexfv;
829 vfmt->Materialfv = _tnl_Materialfv;
830
831 vfmt->Rectf = _mesa_noop_Rectf;
832 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
833 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
834 }
835
836
837
838 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
839 {
840 TNLcontext *tnl = TNL_CONTEXT(ctx);
841 (void) flags;
842
843 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
844 return;
845
846 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
847 _tnl_flush_vtx( ctx );
848 }
849
850 if (tnl->vtx.vertex_size) {
851 _tnl_copy_to_current( ctx );
852 reset_attrfv( tnl );
853 }
854
855 ctx->Driver.NeedFlush = 0;
856 }
857
858
859 static void _tnl_current_init( GLcontext *ctx )
860 {
861 TNLcontext *tnl = TNL_CONTEXT(ctx);
862 GLint i;
863
864 /* setup the pointers for the typical 16 vertex attributes */
865 for (i = 0; i < VERT_ATTRIB_MAX; i++)
866 tnl->vtx.current[i] = ctx->Current.Attrib[i];
867
868 /* setup pointers for the 12 material attributes */
869 for (i = 0; i < MAT_ATTRIB_MAX; i++)
870 tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
871 ctx->Light.Material.Attrib[i];
872
873 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
874 tnl->vtx.current[_TNL_ATTRIB_EDGEFLAG] = &tnl->vtx.CurrentFloatEdgeFlag;
875 }
876
877 static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
878 {
879 (void) ctx; (void) key;
880 return NULL;
881 }
882
883 void _tnl_vtx_init( GLcontext *ctx )
884 {
885 TNLcontext *tnl = TNL_CONTEXT(ctx);
886 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
887 GLuint i;
888 static int firsttime = 1;
889
890 if (firsttime) {
891 firsttime = 0;
892
893 INIT_CHOOSERS( 0 );
894 INIT_CHOOSERS( 1 );
895 INIT_CHOOSERS( 2 );
896 INIT_CHOOSERS( 3 );
897 INIT_CHOOSERS( 4 );
898 INIT_CHOOSERS( 5 );
899 INIT_CHOOSERS( 6 );
900 INIT_CHOOSERS( 7 );
901 INIT_CHOOSERS( 8 );
902 INIT_CHOOSERS( 9 );
903 INIT_CHOOSERS( 10 );
904 INIT_CHOOSERS( 11 );
905 INIT_CHOOSERS( 12 );
906 INIT_CHOOSERS( 13 );
907 INIT_CHOOSERS( 14 );
908 INIT_CHOOSERS( 15 );
909
910 choose[ERROR_ATTRIB][0] = error_attrib;
911 choose[ERROR_ATTRIB][1] = error_attrib;
912 choose[ERROR_ATTRIB][2] = error_attrib;
913 choose[ERROR_ATTRIB][3] = error_attrib;
914
915 #ifdef USE_X86_ASM
916 if (tnl->AllowCodegen) {
917 _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
918 }
919 #endif
920
921 _tnl_generic_attr_table_init( generic_attr_func );
922 }
923
924 for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
925 _mesa_vector4f_init( &tmp->Attribs[i], 0, NULL);
926
927 for (i = 0; i < 4; i++) {
928 make_empty_list( &tnl->vtx.cache.Vertex[i] );
929 make_empty_list( &tnl->vtx.cache.Attribute[i] );
930 tnl->vtx.gen.Vertex[i] = no_codegen;
931 tnl->vtx.gen.Attribute[i] = no_codegen;
932 }
933
934 #ifdef USE_X86_ASM
935 _tnl_InitX86Codegen( &tnl->vtx.gen );
936 #endif
937
938 _tnl_current_init( ctx );
939 _tnl_exec_vtxfmt_init( ctx );
940 _tnl_generic_exec_vtxfmt_init( ctx );
941 #ifdef USE_X86_ASM
942 if (tnl->AllowCodegen) {
943 _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
944 }
945 #endif
946
947 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
948
949 _mesa_memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
950
951 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
952 tnl->vtx.attrsz[i] = 0;
953
954 tnl->vtx.vertex_size = 0;
955 tnl->vtx.have_materials = 0;
956 }
957
958 static void free_funcs( struct _tnl_dynfn *l )
959 {
960 struct _tnl_dynfn *f, *tmp;
961 foreach_s (f, tmp, l) {
962 remove_from_list( f );
963 ALIGN_FREE( f->code );
964 FREE( f );
965 }
966 }
967
968
969 void _tnl_vtx_destroy( GLcontext *ctx )
970 {
971 TNLcontext *tnl = TNL_CONTEXT(ctx);
972 GLuint i;
973
974 for (i = 0; i < 4; i++) {
975 free_funcs( &tnl->vtx.cache.Vertex[i] );
976 free_funcs( &tnl->vtx.cache.Attribute[i] );
977 }
978 }
979