Bug #1679: Link DRI drivers against DRI_LIB_DEPS, not GL_LIB_DEPS.
[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 #ifdef USE_X86_ASM
349
350 static struct _tnl_dynfn *lookup( struct _tnl_dynfn *l, GLuint key )
351 {
352 struct _tnl_dynfn *f;
353
354 foreach( f, l ) {
355 if (f->key == key)
356 return f;
357 }
358
359 return 0;
360 }
361
362
363 static tnl_attrfv_func do_codegen( GLcontext *ctx, GLuint attr, GLuint sz )
364 {
365 TNLcontext *tnl = TNL_CONTEXT(ctx);
366 struct _tnl_dynfn *dfn = 0;
367
368 if (attr == 0) {
369 GLuint key = tnl->vtx.vertex_size;
370
371 dfn = lookup( &tnl->vtx.cache.Vertex[sz-1], key );
372
373 if (!dfn)
374 dfn = tnl->vtx.gen.Vertex[sz-1]( ctx, key );
375 }
376 else {
377 GLuint key = (GLuint) tnl->vtx.attrptr[attr];
378
379 dfn = lookup( &tnl->vtx.cache.Attribute[sz-1], key );
380
381 if (!dfn)
382 dfn = tnl->vtx.gen.Attribute[sz-1]( ctx, key );
383 }
384
385 if (dfn)
386 return *(tnl_attrfv_func *) &dfn->code;
387 else
388 return 0;
389 }
390
391 #endif /* USE_X86_ASM */
392
393 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
394 * entrypoint is called for the first time.
395 */
396
397 static tnl_attrfv_func do_choose( GLuint attr, GLuint sz )
398 {
399 GET_CURRENT_CONTEXT( ctx );
400 TNLcontext *tnl = TNL_CONTEXT(ctx);
401 GLuint oldsz = tnl->vtx.attrsz[attr];
402
403 assert(attr < _TNL_MAX_ATTR_CODEGEN);
404
405 if (oldsz != sz) {
406 /* Reset any active pointers for this attribute
407 */
408 if (oldsz)
409 tnl->vtx.tabfv[attr][oldsz-1] = choose[attr][oldsz-1];
410
411 _tnl_fixup_vertex( ctx, attr, sz );
412
413 }
414
415
416 /* Try to use codegen:
417 */
418 #ifdef USE_X86_ASM
419 if (tnl->AllowCodegen)
420 tnl->vtx.tabfv[attr][sz-1] = do_codegen( ctx, attr, sz );
421 else
422 #endif
423 tnl->vtx.tabfv[attr][sz-1] = 0;
424
425 /* Else use generic version:
426 */
427 if (!tnl->vtx.tabfv[attr][sz-1])
428 tnl->vtx.tabfv[attr][sz-1] = generic_attr_func[attr][sz-1];
429
430 return tnl->vtx.tabfv[attr][sz-1];
431 }
432
433
434
435 #define CHOOSE( ATTR, N ) \
436 static void choose_##ATTR##_##N( const GLfloat *v ) \
437 { \
438 tnl_attrfv_func f = do_choose(ATTR, N); \
439 f( v ); \
440 }
441
442 #define CHOOSERS( ATTRIB ) \
443 CHOOSE( ATTRIB, 1 ) \
444 CHOOSE( ATTRIB, 2 ) \
445 CHOOSE( ATTRIB, 3 ) \
446 CHOOSE( ATTRIB, 4 ) \
447
448
449 #define INIT_CHOOSERS(ATTR) \
450 choose[ATTR][0] = choose_##ATTR##_1; \
451 choose[ATTR][1] = choose_##ATTR##_2; \
452 choose[ATTR][2] = choose_##ATTR##_3; \
453 choose[ATTR][3] = choose_##ATTR##_4;
454
455 CHOOSERS( 0 )
456 CHOOSERS( 1 )
457 CHOOSERS( 2 )
458 CHOOSERS( 3 )
459 CHOOSERS( 4 )
460 CHOOSERS( 5 )
461 CHOOSERS( 6 )
462 CHOOSERS( 7 )
463 CHOOSERS( 8 )
464 CHOOSERS( 9 )
465 CHOOSERS( 10 )
466 CHOOSERS( 11 )
467 CHOOSERS( 12 )
468 CHOOSERS( 13 )
469 CHOOSERS( 14 )
470 CHOOSERS( 15 )
471
472 static void error_attrib( const GLfloat *unused )
473 {
474 GET_CURRENT_CONTEXT( ctx );
475 (void) unused;
476 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
477 }
478
479
480
481 static void reset_attrfv( TNLcontext *tnl )
482 {
483 GLuint i;
484
485 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
486 if (tnl->vtx.attrsz[i]) {
487 GLint j = tnl->vtx.attrsz[i] - 1;
488 tnl->vtx.attrsz[i] = 0;
489
490 if (i < _TNL_MAX_ATTR_CODEGEN) {
491 while (j >= 0) {
492 tnl->vtx.tabfv[i][j] = choose[i][j];
493 j--;
494 }
495 }
496 }
497
498 tnl->vtx.vertex_size = 0;
499 tnl->vtx.have_materials = 0;
500 }
501
502
503
504 /* Materials:
505 *
506 * These are treated as per-vertex attributes, at indices above where
507 * the NV_vertex_program leaves off. There are a lot of good things
508 * about treating materials this way.
509 *
510 * However: I don't want to double the number of generated functions
511 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
512 * ATTRF into this function, and dispense with codegen and
513 * second-level dispatch.
514 *
515 * There is no aliasing of material attributes with other entrypoints.
516 */
517 #define OTHER_ATTR( A, N, params ) \
518 do { \
519 if (tnl->vtx.attrsz[A] != N) { \
520 _tnl_fixup_vertex( ctx, A, N ); \
521 } \
522 \
523 { \
524 GLfloat *dest = tnl->vtx.attrptr[A]; \
525 if (N>0) dest[0] = (params)[0]; \
526 if (N>1) dest[1] = (params)[1]; \
527 if (N>2) dest[2] = (params)[2]; \
528 if (N>3) dest[3] = (params)[3]; \
529 } \
530 } while (0)
531
532
533 #define MAT( ATTR, N, face, params ) \
534 do { \
535 if (face != GL_BACK) \
536 OTHER_ATTR( ATTR, N, params ); /* front */ \
537 if (face != GL_FRONT) \
538 OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
539 } while (0)
540
541
542 /* Colormaterial is dealt with later on.
543 */
544 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
545 const GLfloat *params )
546 {
547 GET_CURRENT_CONTEXT( ctx );
548 TNLcontext *tnl = TNL_CONTEXT(ctx);
549
550 switch (face) {
551 case GL_FRONT:
552 case GL_BACK:
553 case GL_FRONT_AND_BACK:
554 break;
555
556 default:
557 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
558 return;
559 }
560
561 switch (pname) {
562 case GL_EMISSION:
563 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
564 break;
565 case GL_AMBIENT:
566 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
567 break;
568 case GL_DIFFUSE:
569 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
570 break;
571 case GL_SPECULAR:
572 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
573 break;
574 case GL_SHININESS:
575 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
576 break;
577 case GL_COLOR_INDEXES:
578 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
579 break;
580 case GL_AMBIENT_AND_DIFFUSE:
581 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
582 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
583 break;
584 default:
585 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
586 return;
587 }
588
589 tnl->vtx.have_materials = GL_TRUE;
590 }
591
592
593 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
594 {
595 GET_CURRENT_CONTEXT( ctx );
596 TNLcontext *tnl = TNL_CONTEXT(ctx);
597 GLfloat f = (GLfloat)b;
598
599 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
600 }
601
602 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
603 {
604 GET_CURRENT_CONTEXT( ctx );
605 TNLcontext *tnl = TNL_CONTEXT(ctx);
606 GLfloat f = (GLfloat)v[0];
607
608 OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
609 }
610
611 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
612 {
613 GET_CURRENT_CONTEXT( ctx );
614 TNLcontext *tnl = TNL_CONTEXT(ctx);
615
616 OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, &f );
617 }
618
619 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
620 {
621 GET_CURRENT_CONTEXT( ctx );
622 TNLcontext *tnl = TNL_CONTEXT(ctx);
623
624 OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, v );
625 }
626
627 /* Eval
628 */
629 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
630 {
631 GET_CURRENT_CONTEXT( ctx );
632 TNLcontext *tnl = TNL_CONTEXT(ctx);
633
634 /* TODO: use a CHOOSE() function for this: */
635 {
636 GLint i;
637 if (tnl->vtx.eval.new_state)
638 _tnl_update_eval( ctx );
639
640 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
641 if (tnl->vtx.eval.map1[i].map)
642 if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map1[i].sz)
643 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
644 }
645 }
646
647
648 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
649 tnl->vtx.vertex_size * sizeof(GLfloat));
650
651 _tnl_do_EvalCoord1f( ctx, u );
652
653 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
654 tnl->vtx.vertex_size * sizeof(GLfloat));
655 }
656
657 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
658 {
659 GET_CURRENT_CONTEXT( ctx );
660 TNLcontext *tnl = TNL_CONTEXT(ctx);
661
662 /* TODO: use a CHOOSE() function for this: */
663 {
664 GLint i;
665 if (tnl->vtx.eval.new_state)
666 _tnl_update_eval( ctx );
667
668 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
669 if (tnl->vtx.eval.map2[i].map)
670 if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map2[i].sz)
671 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
672 }
673
674 if (ctx->Eval.AutoNormal)
675 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] != 3)
676 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
677 }
678
679 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
680 tnl->vtx.vertex_size * sizeof(GLfloat));
681
682 _tnl_do_EvalCoord2f( ctx, u, v );
683
684 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
685 tnl->vtx.vertex_size * sizeof(GLfloat));
686 }
687
688 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
689 {
690 _tnl_EvalCoord1f( u[0] );
691 }
692
693 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
694 {
695 _tnl_EvalCoord2f( u[0], u[1] );
696 }
697
698 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
699 {
700 GET_CURRENT_CONTEXT( ctx );
701 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
702 (GLfloat) ctx->Eval.MapGrid1un);
703 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
704
705 _tnl_EvalCoord1f( u );
706 }
707
708
709 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
710 {
711 GET_CURRENT_CONTEXT( ctx );
712 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
713 (GLfloat) ctx->Eval.MapGrid2un);
714 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
715 (GLfloat) ctx->Eval.MapGrid2vn);
716 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
717 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
718
719 _tnl_EvalCoord2f( u, v );
720 }
721
722
723 /* Build a list of primitives on the fly. Keep
724 * ctx->Driver.CurrentExecPrimitive uptodate as well.
725 */
726 static void GLAPIENTRY _tnl_Begin( GLenum mode )
727 {
728 GET_CURRENT_CONTEXT( ctx );
729
730 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
731 TNLcontext *tnl = TNL_CONTEXT(ctx);
732 int i;
733
734 if (ctx->NewState) {
735 _mesa_update_state( ctx );
736
737 if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
738 (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
739 _mesa_error(ctx, GL_INVALID_OPERATION,
740 "glBegin (invalid vertex/fragment program)");
741 return;
742 }
743
744 if (!(tnl->Driver.NotifyBegin &&
745 tnl->Driver.NotifyBegin( ctx, mode )))
746 ctx->Exec->Begin(mode);
747 return;
748 }
749
750 /* Heuristic: attempt to isolate attributes occuring outside
751 * begin/end pairs.
752 */
753 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
754 _tnl_FlushVertices( ctx, ~0 );
755
756 i = tnl->vtx.prim_count++;
757 tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
758 tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
759 tnl->vtx.prim[i].count = 0;
760
761 ctx->Driver.CurrentExecPrimitive = mode;
762 }
763 else
764 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
765
766 }
767
768 static void GLAPIENTRY _tnl_End( void )
769 {
770 GET_CURRENT_CONTEXT( ctx );
771
772 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
773 TNLcontext *tnl = TNL_CONTEXT(ctx);
774 int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
775 int i = tnl->vtx.prim_count - 1;
776
777 tnl->vtx.prim[i].mode |= PRIM_END;
778 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
779
780 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
781
782 /* Two choices which effect the way vertex attributes are
783 * carried over (or not) between adjacent primitives.
784 */
785 #if 0
786 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
787 _tnl_FlushVertices( ctx, ~0 );
788 #else
789 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
790 _tnl_flush_vtx( ctx );
791 #endif
792
793 }
794 else
795 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
796 }
797
798
799 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
800 {
801 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
802
803 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
804 vfmt->Begin = _tnl_Begin;
805 vfmt->CallList = _mesa_CallList;
806 vfmt->CallLists = _mesa_CallLists;
807 vfmt->EdgeFlag = _tnl_EdgeFlag;
808 vfmt->EdgeFlagv = _tnl_EdgeFlagv;
809 vfmt->End = _tnl_End;
810 vfmt->EvalCoord1f = _tnl_EvalCoord1f;
811 vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
812 vfmt->EvalCoord2f = _tnl_EvalCoord2f;
813 vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
814 vfmt->EvalPoint1 = _tnl_EvalPoint1;
815 vfmt->EvalPoint2 = _tnl_EvalPoint2;
816 vfmt->Indexf = _tnl_Indexf;
817 vfmt->Indexfv = _tnl_Indexfv;
818 vfmt->Materialfv = _tnl_Materialfv;
819
820 vfmt->Rectf = _mesa_noop_Rectf;
821 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
822 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
823 }
824
825
826
827 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
828 {
829 TNLcontext *tnl = TNL_CONTEXT(ctx);
830 (void) flags;
831
832 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
833 return;
834
835 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
836 _tnl_flush_vtx( ctx );
837 }
838
839 if (tnl->vtx.vertex_size) {
840 _tnl_copy_to_current( ctx );
841 reset_attrfv( tnl );
842 }
843
844 ctx->Driver.NeedFlush = 0;
845 }
846
847
848 static void _tnl_current_init( GLcontext *ctx )
849 {
850 TNLcontext *tnl = TNL_CONTEXT(ctx);
851 GLint i;
852
853 /* setup the pointers for the typical 16 vertex attributes */
854 for (i = 0; i < VERT_ATTRIB_MAX; i++)
855 tnl->vtx.current[i] = ctx->Current.Attrib[i];
856
857 /* setup pointers for the 12 material attributes */
858 for (i = 0; i < MAT_ATTRIB_MAX; i++)
859 tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
860 ctx->Light.Material.Attrib[i];
861
862 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
863 }
864
865 static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
866 {
867 (void) ctx; (void) key;
868 return 0;
869 }
870
871 void _tnl_vtx_init( GLcontext *ctx )
872 {
873 TNLcontext *tnl = TNL_CONTEXT(ctx);
874 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
875 GLuint i;
876 static int firsttime = 1;
877
878 if (firsttime) {
879 firsttime = 0;
880
881 INIT_CHOOSERS( 0 );
882 INIT_CHOOSERS( 1 );
883 INIT_CHOOSERS( 2 );
884 INIT_CHOOSERS( 3 );
885 INIT_CHOOSERS( 4 );
886 INIT_CHOOSERS( 5 );
887 INIT_CHOOSERS( 6 );
888 INIT_CHOOSERS( 7 );
889 INIT_CHOOSERS( 8 );
890 INIT_CHOOSERS( 9 );
891 INIT_CHOOSERS( 10 );
892 INIT_CHOOSERS( 11 );
893 INIT_CHOOSERS( 12 );
894 INIT_CHOOSERS( 13 );
895 INIT_CHOOSERS( 14 );
896 INIT_CHOOSERS( 15 );
897
898 choose[ERROR_ATTRIB][0] = error_attrib;
899 choose[ERROR_ATTRIB][1] = error_attrib;
900 choose[ERROR_ATTRIB][2] = error_attrib;
901 choose[ERROR_ATTRIB][3] = error_attrib;
902
903 #ifdef USE_X86_ASM
904 if (tnl->AllowCodegen) {
905 _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
906 }
907 #endif
908
909 _tnl_generic_attr_table_init( generic_attr_func );
910 }
911
912 for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
913 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
914
915 for (i = 0; i < 4; i++) {
916 make_empty_list( &tnl->vtx.cache.Vertex[i] );
917 make_empty_list( &tnl->vtx.cache.Attribute[i] );
918 tnl->vtx.gen.Vertex[i] = no_codegen;
919 tnl->vtx.gen.Attribute[i] = no_codegen;
920 }
921
922 #ifdef USE_X86_ASM
923 _tnl_InitX86Codegen( &tnl->vtx.gen );
924 #endif
925
926 _tnl_current_init( ctx );
927 _tnl_exec_vtxfmt_init( ctx );
928 _tnl_generic_exec_vtxfmt_init( ctx );
929 #ifdef USE_X86_ASM
930 if (tnl->AllowCodegen) {
931 _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
932 }
933 #endif
934
935 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
936
937 memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
938
939 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
940 tnl->vtx.attrsz[i] = 0;
941
942 tnl->vtx.vertex_size = 0;
943 tnl->vtx.have_materials = 0;
944 }
945
946 static void free_funcs( struct _tnl_dynfn *l )
947 {
948 struct _tnl_dynfn *f, *tmp;
949 foreach_s (f, tmp, l) {
950 remove_from_list( f );
951 ALIGN_FREE( f->code );
952 FREE( f );
953 }
954 }
955
956
957 void _tnl_vtx_destroy( GLcontext *ctx )
958 {
959 TNLcontext *tnl = TNL_CONTEXT(ctx);
960 GLuint i;
961
962 for (i = 0; i < 4; i++) {
963 free_funcs( &tnl->vtx.cache.Vertex[i] );
964 free_funcs( &tnl->vtx.cache.Attribute[i] );
965 }
966 }
967