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