reindent, doxygen-style comments
[mesa.git] / src / mesa / tnl / t_vtx_api.c
1 /**************************************************************************
2
3 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 */
32
33 #include "glheader.h"
34 #include "context.h"
35 #include "macros.h"
36 #include "vtxfmt.h"
37 #include "dlist.h"
38 #include "state.h"
39 #include "light.h"
40 #include "api_arrayelt.h"
41 #include "api_noop.h"
42 #include "t_vtx_api.h"
43 #include "simple_list.h"
44
45 #include "dispatch.h"
46
47 static void reset_attrfv( TNLcontext *tnl );
48
49 /** Note extra space for error index: */
50 static tnl_attrfv_func choose[_TNL_ATTRIB_ERROR+1][4];
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_EDGEFLAG ; 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 /* Edgeflag requires additional treatment:
159 */
160 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
161 ctx->Current.EdgeFlag =
162 (tnl->vtx.CurrentFloatEdgeFlag == 1.0);
163 }
164
165 /* Colormaterial -- this kindof sucks.
166 */
167 if (ctx->Light.ColorMaterialEnabled) {
168 _mesa_update_color_material(ctx,
169 ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
170 }
171
172 if (tnl->vtx.have_materials) {
173 tnl->Driver.NotifyMaterialChange( ctx );
174 }
175
176 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
177
178 ctx->NewState |= _NEW_LIGHT;
179 }
180
181
182 static void _tnl_copy_from_current( GLcontext *ctx )
183 {
184 TNLcontext *tnl = TNL_CONTEXT(ctx);
185 GLint i;
186
187 /* Edgeflag requires additional treatment:
188 */
189 tnl->vtx.CurrentFloatEdgeFlag = (GLfloat) ctx->Current.EdgeFlag;
190
191 for (i = _TNL_ATTRIB_POS+1 ; i < _TNL_ATTRIB_MAX ; i++)
192 switch (tnl->vtx.attrsz[i]) {
193 case 4: tnl->vtx.attrptr[i][3] = tnl->vtx.current[i][3];
194 case 3: tnl->vtx.attrptr[i][2] = tnl->vtx.current[i][2];
195 case 2: tnl->vtx.attrptr[i][1] = tnl->vtx.current[i][1];
196 case 1: tnl->vtx.attrptr[i][0] = tnl->vtx.current[i][0];
197 break;
198 }
199
200 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
201 }
202
203
204 /* Flush existing data, set new attrib size, replay copied vertices.
205 */
206 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
207 GLuint attr,
208 GLuint newsz )
209 {
210 TNLcontext *tnl = TNL_CONTEXT(ctx);
211 GLuint oldsz;
212 GLuint i;
213 GLfloat *tmp;
214 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
215
216 /* Run pipeline on current vertices, copy wrapped vertices
217 * to tnl->vtx.copied.
218 */
219 _tnl_wrap_buffers( ctx );
220
221
222 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
223 * when the attribute already exists in the vertex and is having
224 * its size increased.
225 */
226 _tnl_copy_to_current( ctx );
227
228
229 /* Heuristic: Attempt to isolate attributes received outside
230 * begin/end so that they don't bloat the vertices.
231 */
232 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
233 tnl->vtx.attrsz[attr] == 0 &&
234 lastcount > 8 &&
235 tnl->vtx.vertex_size) {
236 reset_attrfv( tnl );
237 }
238
239 /* Fix up sizes:
240 */
241 oldsz = tnl->vtx.attrsz[attr];
242 tnl->vtx.attrsz[attr] = newsz;
243
244 tnl->vtx.vertex_size += newsz - oldsz;
245 tnl->vtx.counter = MIN2( VERT_BUFFER_SIZE / tnl->vtx.vertex_size,
246 ctx->Const.MaxArrayLockSize );
247 tnl->vtx.initial_counter = tnl->vtx.counter;
248 tnl->vtx.vbptr = tnl->vtx.buffer;
249
250
251 /* Recalculate all the attrptr[] values
252 */
253 for (i = 0, tmp = tnl->vtx.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
254 if (tnl->vtx.attrsz[i]) {
255 tnl->vtx.attrptr[i] = tmp;
256 tmp += tnl->vtx.attrsz[i];
257 }
258 else
259 tnl->vtx.attrptr[i] = NULL; /* will not be dereferenced */
260 }
261
262 /* Copy from current to repopulate the vertex with correct values.
263 */
264 _tnl_copy_from_current( ctx );
265
266 /* Replay stored vertices to translate them
267 * to new format here.
268 *
269 * -- No need to replay - just copy piecewise
270 */
271 if (tnl->vtx.copied.nr)
272 {
273 const GLfloat *data = tnl->vtx.copied.buffer;
274 GLfloat *dest = tnl->vtx.buffer;
275 GLuint j;
276
277 for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
278 for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
279 if (tnl->vtx.attrsz[j]) {
280 if (j == attr) {
281 if (oldsz) {
282 COPY_CLEAN_4V( dest, oldsz, data );
283 data += oldsz;
284 dest += newsz;
285 } else {
286 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
287 dest += newsz;
288 }
289 }
290 else {
291 GLuint sz = tnl->vtx.attrsz[j];
292 COPY_SZ_4V( dest, sz, data );
293 dest += sz;
294 data += sz;
295 }
296 }
297 }
298 }
299
300 tnl->vtx.vbptr = dest;
301 tnl->vtx.counter -= tnl->vtx.copied.nr;
302 tnl->vtx.copied.nr = 0;
303 }
304
305 /* For codegen - attrptr's may have changed, so need to redo
306 * codegen. Might be a reasonable place to try & detect attributes
307 * in the vertex which aren't being submitted any more.
308 */
309 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
310 if (tnl->vtx.attrsz[i]) {
311 GLuint j = tnl->vtx.attrsz[i] - 1;
312
313 if (i < _TNL_MAX_ATTR_CODEGEN)
314 tnl->vtx.tabfv[i][j] = choose[i][j];
315 }
316
317 }
318
319
320 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
321 {
322 TNLcontext *tnl = TNL_CONTEXT(ctx);
323 static const GLfloat id[4] = { 0, 0, 0, 1 };
324 int i;
325
326 if (0)
327 _mesa_printf("%s attr %d sz %d -> %d\n",
328 __FUNCTION__, attr, tnl->vtx.attrsz[attr], sz);
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 (sz < tnl->vtx.active_sz[attr]) {
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 tnl->vtx.active_sz[attr] = sz;
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.active_sz[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 ASSERT(tnl->vtx.tabfv[attr][sz-1]);
439 return tnl->vtx.tabfv[attr][sz-1];
440 }
441
442
443
444 #define CHOOSE( ATTR, N ) \
445 static void choose_##ATTR##_##N( const GLfloat *v ) \
446 { \
447 tnl_attrfv_func f = do_choose(ATTR, N); \
448 ASSERT(f); \
449 f( v ); \
450 }
451
452 #define CHOOSERS( ATTRIB ) \
453 CHOOSE( ATTRIB, 1 ) \
454 CHOOSE( ATTRIB, 2 ) \
455 CHOOSE( ATTRIB, 3 ) \
456 CHOOSE( ATTRIB, 4 ) \
457
458
459 #define INIT_CHOOSERS(ATTR) \
460 ASSERT(ATTR <= _TNL_ATTRIB_ERROR);\
461 choose[ATTR][0] = choose_##ATTR##_1; \
462 choose[ATTR][1] = choose_##ATTR##_2; \
463 choose[ATTR][2] = choose_##ATTR##_3; \
464 choose[ATTR][3] = choose_##ATTR##_4;
465
466 /* conventional attributes */
467 CHOOSERS( 0 )
468 CHOOSERS( 1 )
469 CHOOSERS( 2 )
470 CHOOSERS( 3 )
471 CHOOSERS( 4 )
472 CHOOSERS( 5 )
473 CHOOSERS( 6 )
474 CHOOSERS( 7 )
475 CHOOSERS( 8 )
476 CHOOSERS( 9 )
477 CHOOSERS( 10 )
478 CHOOSERS( 11 )
479 CHOOSERS( 12 )
480 CHOOSERS( 13 )
481 CHOOSERS( 14 )
482 CHOOSERS( 15 )
483
484 /* generic attributes */
485 CHOOSERS( 16 )
486 CHOOSERS( 17 )
487 CHOOSERS( 18 )
488 CHOOSERS( 19 )
489 CHOOSERS( 20 )
490 CHOOSERS( 21 )
491 CHOOSERS( 22 )
492 CHOOSERS( 23 )
493 CHOOSERS( 24 )
494 CHOOSERS( 25 )
495 CHOOSERS( 26 )
496 CHOOSERS( 27 )
497 CHOOSERS( 28 )
498 CHOOSERS( 29 )
499 CHOOSERS( 30 )
500 CHOOSERS( 31 )
501
502
503 /**
504 * This function will get called when glVertexAttribNV/ARB() is called
505 * with an invalid index parameter.
506 */
507 static void
508 error_attrib(const GLfloat *unused)
509 {
510 GET_CURRENT_CONTEXT( ctx );
511 (void) unused;
512 _mesa_error( ctx, GL_INVALID_VALUE, "glVertexAttrib(index)" );
513 }
514
515
516
517 /**
518 * Reset all the per-vertex functions pointers to point to the default
519 * "chooser" functions.
520 */
521 static void
522 reset_attrfv(TNLcontext *tnl)
523 {
524 GLuint i;
525
526 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
527 if (tnl->vtx.attrsz[i]) {
528 GLint j = tnl->vtx.attrsz[i] - 1;
529 tnl->vtx.attrsz[i] = 0;
530 tnl->vtx.active_sz[i] = 0;
531
532 if (i < _TNL_MAX_ATTR_CODEGEN) {
533 while (j >= 0) {
534 tnl->vtx.tabfv[i][j] = choose[i][j];
535 j--;
536 }
537 }
538 }
539
540 tnl->vtx.vertex_size = 0;
541 tnl->vtx.have_materials = 0;
542 }
543
544
545
546 /**
547 * Materials:
548 *
549 * These are treated as per-vertex attributes, at indices above where
550 * the NV_vertex_program leaves off. There are a lot of good things
551 * about treating materials this way.
552 *
553 * However: I don't want to double the number of generated functions
554 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
555 * ATTRF into this function, and dispense with codegen and
556 * second-level dispatch.
557 *
558 * There is no aliasing of material attributes with other entrypoints.
559 */
560 #define OTHER_ATTR( A, N, params ) \
561 do { \
562 if (tnl->vtx.active_sz[A] != N) { \
563 _tnl_fixup_vertex( ctx, A, N ); \
564 } \
565 \
566 { \
567 GLfloat *dest = tnl->vtx.attrptr[A]; \
568 if (N>0) dest[0] = (params)[0]; \
569 if (N>1) dest[1] = (params)[1]; \
570 if (N>2) dest[2] = (params)[2]; \
571 if (N>3) dest[3] = (params)[3]; \
572 } \
573 } while (0)
574
575
576 #define MAT( ATTR, N, face, params ) \
577 do { \
578 if (face != GL_BACK) \
579 OTHER_ATTR( ATTR, N, params ); /* front */ \
580 if (face != GL_FRONT) \
581 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
582 } while (0)
583
584
585 /**
586 * Called by glMaterialfv().
587 * Colormaterial is dealt with later on.
588 */
589 static void GLAPIENTRY
590 _tnl_Materialfv( GLenum face, GLenum pname, const GLfloat *params )
591 {
592 GET_CURRENT_CONTEXT( ctx );
593 TNLcontext *tnl = TNL_CONTEXT(ctx);
594
595 switch (face) {
596 case GL_FRONT:
597 case GL_BACK:
598 case GL_FRONT_AND_BACK:
599 break;
600 default:
601 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
602 return;
603 }
604
605 switch (pname) {
606 case GL_EMISSION:
607 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
608 break;
609 case GL_AMBIENT:
610 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
611 break;
612 case GL_DIFFUSE:
613 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
614 break;
615 case GL_SPECULAR:
616 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
617 break;
618 case GL_SHININESS:
619 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
620 break;
621 case GL_COLOR_INDEXES:
622 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
623 break;
624 case GL_AMBIENT_AND_DIFFUSE:
625 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
626 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
627 break;
628 default:
629 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
630 return;
631 }
632
633 tnl->vtx.have_materials = GL_TRUE;
634 }
635
636
637 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
638 {
639 GET_CURRENT_CONTEXT( ctx );
640 TNLcontext *tnl = TNL_CONTEXT(ctx);
641 GLfloat f = (GLfloat)b;
642
643 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
644 }
645
646
647 /* Eval
648 */
649 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
650 {
651 GET_CURRENT_CONTEXT( ctx );
652 TNLcontext *tnl = TNL_CONTEXT(ctx);
653
654 /* TODO: use a CHOOSE() function for this: */
655 {
656 GLint i;
657 if (tnl->vtx.eval.new_state)
658 _tnl_update_eval( ctx );
659
660 for (i = 0; i < _TNL_NUM_EVAL; i++) {
661 if (tnl->vtx.eval.map1[i].map)
662 if (tnl->vtx.active_sz[i] != tnl->vtx.eval.map1[i].sz)
663 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
664 }
665 }
666
667
668 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
669 tnl->vtx.vertex_size * sizeof(GLfloat));
670
671 _tnl_do_EvalCoord1f( ctx, u );
672
673 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
674 tnl->vtx.vertex_size * sizeof(GLfloat));
675 }
676
677 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
678 {
679 GET_CURRENT_CONTEXT( ctx );
680 TNLcontext *tnl = TNL_CONTEXT(ctx);
681
682 /* TODO: use a CHOOSE() function for this: */
683 {
684 GLint i;
685 if (tnl->vtx.eval.new_state)
686 _tnl_update_eval( ctx );
687
688 for (i = 0; i < _TNL_NUM_EVAL; i++) {
689 if (tnl->vtx.eval.map2[i].map)
690 if (tnl->vtx.active_sz[i] != tnl->vtx.eval.map2[i].sz)
691 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
692 }
693
694 if (ctx->Eval.AutoNormal)
695 if (tnl->vtx.active_sz[_TNL_ATTRIB_NORMAL] != 3)
696 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
697 }
698
699 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
700 tnl->vtx.vertex_size * sizeof(GLfloat));
701
702 _tnl_do_EvalCoord2f( ctx, u, v );
703
704 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
705 tnl->vtx.vertex_size * sizeof(GLfloat));
706 }
707
708 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
709 {
710 _tnl_EvalCoord1f( u[0] );
711 }
712
713 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
714 {
715 _tnl_EvalCoord2f( u[0], u[1] );
716 }
717
718 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
719 {
720 GET_CURRENT_CONTEXT( ctx );
721 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
722 (GLfloat) ctx->Eval.MapGrid1un);
723 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
724
725 _tnl_EvalCoord1f( u );
726 }
727
728
729 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
730 {
731 GET_CURRENT_CONTEXT( ctx );
732 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
733 (GLfloat) ctx->Eval.MapGrid2un);
734 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
735 (GLfloat) ctx->Eval.MapGrid2vn);
736 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
737 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
738
739 _tnl_EvalCoord2f( u, v );
740 }
741
742
743 /**
744 * Called from glBegin.
745 * ctx->Driver.CurrentExecPrimitive will be set to <mode>.
746 */
747 static void GLAPIENTRY _tnl_Begin( GLenum mode )
748 {
749 GET_CURRENT_CONTEXT( ctx );
750
751 if (mode > GL_POLYGON) {
752 _mesa_error(ctx, GL_INVALID_ENUM, "glBegin(mode)");
753 return;
754 }
755
756 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
757 /* we're not inside a glBegin/End pair */
758 TNLcontext *tnl = TNL_CONTEXT(ctx);
759 GLuint i;
760
761 if (ctx->NewState) {
762 _mesa_update_state( ctx );
763
764 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
765 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
766 _mesa_error(ctx, GL_INVALID_OPERATION,
767 "glBegin (invalid vertex/fragment program)");
768 tnl->DiscardPrimitive = GL_TRUE;
769 return;
770 }
771
772 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
773 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
774 "glBegin(incomplete framebuffer)");
775 tnl->DiscardPrimitive = GL_TRUE;
776 return;
777 }
778
779 tnl->DiscardPrimitive = GL_FALSE;
780
781 if (!(tnl->Driver.NotifyBegin &&
782 tnl->Driver.NotifyBegin( ctx, mode )))
783 CALL_Begin(ctx->Exec, (mode));
784 return;
785 }
786
787 /* Heuristic: attempt to isolate attributes occuring outside
788 * begin/end pairs.
789 */
790 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
791 _tnl_FlushVertices( ctx, ~0 );
792
793 i = tnl->vtx.prim_count++;
794 tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
795 tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
796 tnl->vtx.prim[i].count = 0;
797
798 ctx->Driver.CurrentExecPrimitive = mode;
799 }
800 else {
801 /* already inside glBegin/End */
802 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
803 }
804 }
805
806
807 /**
808 * Called from glEnd.
809 */
810 static void GLAPIENTRY _tnl_End( void )
811 {
812 GET_CURRENT_CONTEXT( ctx );
813
814 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
815 /* closing an open glBegin primitive */
816 TNLcontext *tnl = TNL_CONTEXT(ctx);
817 int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
818 int i = tnl->vtx.prim_count - 1;
819
820 tnl->vtx.prim[i].mode |= PRIM_END;
821 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
822
823 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
824
825 /* Two choices which effect the way vertex attributes are
826 * carried over (or not) between adjacent primitives.
827 */
828 #if 0
829 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
830 _tnl_FlushVertices( ctx, ~0 );
831 #else
832 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
833 _tnl_flush_vtx( ctx );
834 #endif
835
836 }
837 else {
838 /* glBegin hasn't been called! */
839 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
840 }
841 }
842
843
844 /**
845 * XXX why aren't all members initialized here??
846 */
847 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
848 {
849 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
850
851 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
852 vfmt->Begin = _tnl_Begin;
853 vfmt->CallList = _mesa_CallList;
854 vfmt->CallLists = _mesa_CallLists;
855 vfmt->EdgeFlag = _tnl_EdgeFlag;
856 vfmt->End = _tnl_End;
857 vfmt->EvalCoord1f = _tnl_EvalCoord1f;
858 vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
859 vfmt->EvalCoord2f = _tnl_EvalCoord2f;
860 vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
861 vfmt->EvalPoint1 = _tnl_EvalPoint1;
862 vfmt->EvalPoint2 = _tnl_EvalPoint2;
863 vfmt->Materialfv = _tnl_Materialfv;
864
865 vfmt->Rectf = _mesa_noop_Rectf;
866 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
867 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
868 }
869
870
871
872 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
873 {
874 TNLcontext *tnl = TNL_CONTEXT(ctx);
875 (void) flags;
876
877 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
878 /* still inside a glBegin/End pair. How'd we get here??? */
879 return;
880 }
881
882 if (tnl->DiscardPrimitive) {
883 /* discard any primitives */
884 tnl->vtx.prim_count = 0;
885 tnl->vtx.counter = tnl->vtx.initial_counter;
886 tnl->vtx.vbptr = tnl->vtx.buffer;
887 }
888
889 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
890 _tnl_flush_vtx( ctx );
891 }
892
893 if (tnl->vtx.vertex_size) {
894 _tnl_copy_to_current( ctx );
895 reset_attrfv( tnl );
896 }
897
898 ctx->Driver.NeedFlush = 0;
899 }
900
901
902 /**
903 * Init the tnl->vtx->current[] pointers to point to the corresponding
904 * fields in ctx->Current attribute group.
905 */
906 static void _tnl_current_init( GLcontext *ctx )
907 {
908 TNLcontext *tnl = TNL_CONTEXT(ctx);
909 GLint i;
910
911 /* setup the pointers for the typical (32) vertex attributes */
912 for (i = 0; i < VERT_ATTRIB_MAX; i++)
913 tnl->vtx.current[i] = ctx->Current.Attrib[i];
914
915 /* setup pointers for the 12 material attributes */
916 for (i = 0; i < MAT_ATTRIB_MAX; i++)
917 tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
918 ctx->Light.Material.Attrib[i];
919
920 /* special case */
921 tnl->vtx.current[_TNL_ATTRIB_EDGEFLAG] = &tnl->vtx.CurrentFloatEdgeFlag;
922 }
923
924 static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
925 {
926 (void) ctx; (void) key;
927 return NULL;
928 }
929
930 void _tnl_vtx_init( GLcontext *ctx )
931 {
932 TNLcontext *tnl = TNL_CONTEXT(ctx);
933 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
934 GLuint i;
935 static int firsttime = 1;
936
937 if (firsttime) {
938 firsttime = 0;
939
940 /* conventional attributes */
941 INIT_CHOOSERS( 0 );
942 INIT_CHOOSERS( 1 );
943 INIT_CHOOSERS( 2 );
944 INIT_CHOOSERS( 3 );
945 INIT_CHOOSERS( 4 );
946 INIT_CHOOSERS( 5 );
947 INIT_CHOOSERS( 6 );
948 INIT_CHOOSERS( 7 );
949 INIT_CHOOSERS( 8 );
950 INIT_CHOOSERS( 9 );
951 INIT_CHOOSERS( 10 );
952 INIT_CHOOSERS( 11 );
953 INIT_CHOOSERS( 12 );
954 INIT_CHOOSERS( 13 );
955 INIT_CHOOSERS( 14 );
956 INIT_CHOOSERS( 15 );
957
958 /* generic attributes */
959 INIT_CHOOSERS( 16 );
960 INIT_CHOOSERS( 17 );
961 INIT_CHOOSERS( 18 );
962 INIT_CHOOSERS( 19 );
963 INIT_CHOOSERS( 20 );
964 INIT_CHOOSERS( 21 );
965 INIT_CHOOSERS( 22 );
966 INIT_CHOOSERS( 23 );
967 INIT_CHOOSERS( 24 );
968 INIT_CHOOSERS( 25 );
969 INIT_CHOOSERS( 26 );
970 INIT_CHOOSERS( 27 );
971 INIT_CHOOSERS( 28 );
972 INIT_CHOOSERS( 29 );
973 INIT_CHOOSERS( 30 );
974 INIT_CHOOSERS( 31 );
975
976 choose[_TNL_ATTRIB_ERROR][0] = error_attrib;
977 choose[_TNL_ATTRIB_ERROR][1] = error_attrib;
978 choose[_TNL_ATTRIB_ERROR][2] = error_attrib;
979 choose[_TNL_ATTRIB_ERROR][3] = error_attrib;
980
981 #ifdef USE_X86_ASM
982 if (tnl->AllowCodegen) {
983 _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
984 }
985 #endif
986
987 _tnl_generic_attr_table_init( generic_attr_func );
988 }
989
990 for (i = 0; i < _TNL_ATTRIB_EDGEFLAG; i++)
991 _mesa_vector4f_init( &tmp->Attribs[i], 0, NULL);
992
993 for (i = 0; i < 4; i++) {
994 make_empty_list( &tnl->vtx.cache.Vertex[i] );
995 make_empty_list( &tnl->vtx.cache.Attribute[i] );
996 tnl->vtx.gen.Vertex[i] = no_codegen;
997 tnl->vtx.gen.Attribute[i] = no_codegen;
998 }
999
1000 #ifdef USE_X86_ASM
1001 _tnl_InitX86Codegen( &tnl->vtx.gen );
1002 #endif
1003
1004 _tnl_current_init( ctx );
1005 _tnl_exec_vtxfmt_init( ctx );
1006 _tnl_generic_exec_vtxfmt_init( ctx );
1007 #ifdef USE_X86_ASM
1008 if (tnl->AllowCodegen) {
1009 _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
1010 }
1011 #endif
1012
1013 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
1014
1015 _mesa_memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
1016
1017 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++) {
1018 tnl->vtx.attrsz[i] = 0;
1019 tnl->vtx.active_sz[i] = 0;
1020 }
1021
1022 tnl->vtx.vertex_size = 0;
1023 tnl->vtx.have_materials = 0;
1024 }
1025
1026 static void free_funcs( struct _tnl_dynfn *l )
1027 {
1028 struct _tnl_dynfn *f, *tmp;
1029 foreach_s (f, tmp, l) {
1030 remove_from_list( f );
1031 ALIGN_FREE( f->code );
1032 FREE( f );
1033 }
1034 }
1035
1036
1037 void _tnl_vtx_destroy( GLcontext *ctx )
1038 {
1039 TNLcontext *tnl = TNL_CONTEXT(ctx);
1040 GLuint i;
1041
1042 for (i = 0; i < 4; i++) {
1043 free_funcs( &tnl->vtx.cache.Vertex[i] );
1044 free_funcs( &tnl->vtx.cache.Attribute[i] );
1045 }
1046 }
1047