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