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