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