Subversion Repositories shark

Rev

Rev 56 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 pj 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 "api_noop.h"
35
#include "api_arrayelt.h"
36
#include "context.h"
37
#include "imports.h"
38
#include "mmath.h"
39
#include "mtypes.h"
40
#include "enums.h"
41
#include "glapi.h"
42
#include "colormac.h"
43
#include "light.h"
44
#include "state.h"
45
#include "vtxfmt.h"
46
 
72 giacomo 47
#include "tnl.h"
48
#include "t_context.h"
49
#include "t_array_api.h"
56 pj 50
 
51
static void _tnl_FlushVertices( GLcontext *, GLuint );
52
 
53
 
54
void tnl_copy_to_current( GLcontext *ctx )
55
{
56
   TNLcontext *tnl = TNL_CONTEXT(ctx);
57
   GLuint flag = tnl->vertex_format;
58
   GLint i;
59
 
60
   assert(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT);
61
 
62
   for (i = 0 ; i < 16 ; i++)
63
      if (flag & (1<<i))
64
         COPY_4FV( ctx->Current.Attrib[i], tnl->attribptr[i] );
65
 
66
   if (flag & VERT_BIT_INDEX)
67
      ctx->Current.Index = tnl->indexptr[0];
68
 
69
   if (flag & VERT_BIT_EDGEFLAG)
70
      ctx->Current.EdgeFlag = tnl->edgeflagptr[0];
71
 
72
   if (flag & VERT_BIT_MATERIAL) {
73
      _mesa_update_material( ctx,
74
                          IM->Material[IM->LastMaterial],
75
                          IM->MaterialOrMask );
76
 
77
      tnl->Driver.NotifyMaterialChange( ctx );
78
   }
79
 
80
 
81
   ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
82
}
83
 
84
static GLboolean discreet_gl_prim[GL_POLYGON+1] = {
85
   1,                           /* 0 points */
86
   1,                           /* 1 lines */
87
   0,                           /* 2 line_strip */
88
   0,                           /* 3 line_loop */
89
   1,                           /* 4 tris */
90
   0,                           /* 5 tri_fan */
91
   0,                           /* 6 tri_strip */
92
   1,                           /* 7 quads */
93
   0,                           /* 8 quadstrip */
94
   0,                           /* 9 poly */
95
};
96
 
97
/* Optimize the primitive list:  ONLY FOR EXECUTE ATM
98
 */
99
static void optimize_prims( TNLcontext *tnl )
100
{
101
   int i, j;
102
 
103
   if (tnl->nrprims <= 1)
104
      return;
105
 
106
   for (j = 0, i = 1 ; i < tnl->nrprims; i++) {
107
      int pj = tnl->primlist[j].prim & 0xf;
108
      int pi = tnl->primlist[i].prim & 0xf;
109
 
110
      if (pj == pi && discreet_gl_prim[pj] &&
111
          tnl->primlist[i].start == tnl->primlist[j].end) {
112
         tnl->primlist[j].end = tnl->primlist[i].end;
113
      }
114
      else {
115
         j++;
116
         if (j != i) tnl->primlist[j] = tnl->primlist[i];
117
      }
118
   }
119
 
120
   tnl->nrprims = j+1;
121
}
122
 
123
 
124
/* Bind vertex buffer pointers, run pipeline:
125
 */
126
static void flush_prims( TNLcontext *tnl )
127
{
128
   int i,j;
129
 
130
   tnl->dma.current.ptr = tnl->dma.current.start +=
131
      (tnl->initial_counter - tnl->counter) * tnl->vertex_size * 4;
132
 
133
   tnl->tcl.vertex_format = tnl->vertex_format;
134
   tnl->tcl.aos_components[0] = &tmp;
135
   tnl->tcl.nr_aos_components = 1;
136
   tnl->dma.flush = 0;
137
 
138
   tnl->Driver.RunPipeline( ... );
139
 
140
   tnl->nrprims = 0;
141
}
142
 
143
 
144
static void start_prim( TNLcontext *tnl, GLuint mode )
145
{
146
   if (MESA_VERBOSE & DEBUG_VFMT)
147
      _mesa_debug(NULL, "%s %d\n", __FUNCTION__,
148
              tnl->initial_counter - tnl->counter);
149
 
150
   tnl->primlist[tnl->nrprims].start = tnl->initial_counter - tnl->counter;
151
   tnl->primlist[tnl->nrprims].prim = mode;
152
}
153
 
154
static void note_last_prim( TNLcontext *tnl, GLuint flags )
155
{
156
   if (MESA_VERBOSE & DEBUG_VFMT)
157
      _mesa_debug(NULL, "%s %d\n", __FUNCTION__,
158
              tnl->initial_counter - tnl->counter);
159
 
160
   if (tnl->prim[0] != GL_POLYGON+1) {
161
      tnl->primlist[tnl->nrprims].prim |= flags;
162
      tnl->primlist[tnl->nrprims].end = tnl->initial_counter - tnl->counter;
163
 
164
      if (++tnl->nrprims == TNL_MAX_PRIMS)
165
         flush_prims( tnl );
166
   }
167
}
168
 
169
 
170
static void copy_vertex( TNLcontext *tnl, GLuint n, GLfloat *dst )
171
{
172
   GLuint i;
173
   GLfloat *src = (GLfloat *)(tnl->dma.current.address +
174
                              tnl->dma.current.ptr +
175
                              (tnl->primlist[tnl->nrprims].start + n) *
176
                              tnl->vertex_size * 4);
177
 
178
   if (MESA_VERBOSE & DEBUG_VFMT)
179
      _mesa_debug(NULL, "copy_vertex %d\n",
180
              tnl->primlist[tnl->nrprims].start + n);
181
 
182
   for (i = 0 ; i < tnl->vertex_size; i++) {
183
      dst[i] = src[i];
184
   }
185
}
186
 
187
static GLuint copy_wrapped_verts( TNLcontext *tnl, GLfloat (*tmp)[15] )
188
{
189
   GLuint ovf, i;
190
   GLuint nr = (tnl->initial_counter - tnl->counter) - tnl->primlist[tnl->nrprims].start;
191
 
192
   if (MESA_VERBOSE & DEBUG_VFMT)
193
      _mesa_debug(NULL, "%s %d verts\n", __FUNCTION__, nr);
194
 
195
   switch( tnl->prim[0] )
196
   {
197
   case GL_POINTS:
198
      return 0;
199
   case GL_LINES:
200
      ovf = nr&1;
201
      for (i = 0 ; i < ovf ; i++)
202
         copy_vertex( tnl, nr-ovf+i, tmp[i] );
203
      return i;
204
   case GL_TRIANGLES:
205
      ovf = nr%3;
206
      for (i = 0 ; i < ovf ; i++)
207
         copy_vertex( tnl, nr-ovf+i, tmp[i] );
208
      return i;
209
   case GL_QUADS:
210
      ovf = nr&3;
211
      for (i = 0 ; i < ovf ; i++)
212
         copy_vertex( tnl, nr-ovf+i, tmp[i] );
213
      return i;
214
   case GL_LINE_STRIP:
215
      if (nr == 0)
216
         return 0;
217
      copy_vertex( tnl, nr-1, tmp[0] );
218
      return 1;
219
   case GL_LINE_LOOP:
220
   case GL_TRIANGLE_FAN:
221
   case GL_POLYGON:
222
      if (nr == 0)
223
         return 0;
224
      else if (nr == 1) {
225
         copy_vertex( tnl, 0, tmp[0] );
226
         return 1;
227
      } else {
228
         copy_vertex( tnl, 0, tmp[0] );
229
         copy_vertex( tnl, nr-1, tmp[1] );
230
         return 2;
231
      }
232
   case GL_TRIANGLE_STRIP:
233
      ovf = MIN2( nr-1, 2 );
234
      for (i = 0 ; i < ovf ; i++)
235
         copy_vertex( tnl, nr-ovf+i, tmp[i] );
236
      return i;
237
   case GL_QUAD_STRIP:
238
      ovf = MIN2( nr-1, 2 );
239
      if (nr > 2) ovf += nr&1;
240
      for (i = 0 ; i < ovf ; i++)
241
         copy_vertex( tnl, nr-ovf+i, tmp[i] );
242
      return i;
243
   default:
244
      assert(0);
245
      return 0;
246
   }
247
}
248
 
249
 
250
 
251
/* Extend for vertex-format changes on wrap:
252
 */
253
static void wrap_buffer( void )
254
{
255
   TNLcontext *tnl = tnl->tnl;
256
   GLfloat tmp[3][15];
257
   GLuint i, nrverts;
258
 
259
   if (MESA_VERBOSE & (DEBUG_VFMT|DEBUG_PRIMS))
260
      _mesa_debug(NULL, "%s %d\n", __FUNCTION__,
261
              tnl->initial_counter - tnl->counter);
262
 
263
   /* Don't deal with parity.  *** WONT WORK FOR COMPILE
264
    */
265
   if ((((tnl->initial_counter - tnl->counter) -  
266
         tnl->primlist[tnl->nrprims].start) & 1)) {
267
      tnl->counter++;
268
      tnl->initial_counter++;
269
      return;
270
   }
271
 
272
   /* Copy vertices out of dma:
273
    */
274
   nrverts = copy_dma_verts( tnl, tmp );
275
 
276
   if (MESA_VERBOSE & DEBUG_VFMT)
277
      _mesa_debug(NULL, "%d vertices to copy\n", nrverts);
278
 
279
 
280
   /* Finish the prim at this point:
281
    */
282
   note_last_prim( tnl, 0 );
283
   flush_prims( tnl );
284
 
285
   /* Reset counter, dmaptr
286
    */
287
   tnl->dmaptr = (int *)(tnl->dma.current.ptr + tnl->dma.current.address);
288
   tnl->counter = (tnl->dma.current.end - tnl->dma.current.ptr) /
289
      (tnl->vertex_size * 4);
290
   tnl->counter--;
291
   tnl->initial_counter = tnl->counter;
292
   tnl->notify = wrap_buffer;
293
 
294
   tnl->dma.flush = flush_prims;
295
   start_prim( tnl, tnl->prim[0] );
296
 
297
 
298
   /* Reemit saved vertices
299
    * *** POSSIBLY IN NEW FORMAT
300
    *       --> Can't always extend at end of vertex?
301
    */
302
   for (i = 0 ; i < nrverts; i++) {
303
      if (MESA_VERBOSE & DEBUG_VERTS) {
304
         int j;
305
         _mesa_debug(NULL, "re-emit vertex %d to %p\n", i, tnl->dmaptr);
306
         if (MESA_VERBOSE & DEBUG_VERBOSE)
307
            for (j = 0 ; j < tnl->vertex_size; j++)
308
               _mesa_debug(NULL, "\t%08x/%f\n", *(int*)&tmp[i][j], tmp[i][j]);
309
      }
310
 
311
      memcpy( tnl->dmaptr, tmp[i], tnl->vertex_size * 4 );
312
      tnl->dmaptr += tnl->vertex_size;
313
      tnl->counter--;
314
   }
315
}
316
 
317
 
318
 
319
/* Always follow data, don't try to predict what's necessary.  
320
 */
321
static GLboolean check_vtx_fmt( GLcontext *ctx )
322
{
323
   TNLcontext *tnl = TNL_CONTEXT(ctx);
324
 
325
   if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
326
      ctx->Driver.FlushVertices( ctx, FLUSH_UPDATE_CURRENT );
327
 
328
 
329
   TNL_NEWPRIM(tnl);
330
   tnl->vertex_format = VERT_BIT_POS;
331
   tnl->prim = &ctx->Driver.CurrentExecPrimitive;
332
 
333
 
334
   /* Currently allow the full 4 components per attrib.  Can use the
335
    * mechanism from radeon driver color handling to reduce this (and
336
    * also to store ubyte colors where these are incoming).  This
337
    * won't work for compile mode.
338
    *
339
    * Only adding components when they are first received eliminates
340
    * the need for displaylist fixup, as there are no 'empty' slots
341
    * at the start of buffers.  
342
    */
343
   for (i = 0 ; i < 16 ; i++) {
344
      if (ind & (1<<i)) {
345
         tnl->attribptr[i] = &tnl->vertex[tnl->vertex_size].f;
346
         tnl->vertex_size += 4;
347
         tnl->attribptr[i][0] = ctx->Current.Attrib[i][0];
348
         tnl->attribptr[i][1] = ctx->Current.Attrib[i][1];
349
         tnl->attribptr[i][2] = ctx->Current.Attrib[i][2];
350
         tnl->attribptr[i][3] = ctx->Current.Attrib[i][3];
351
      }
352
      else
353
         tnl->attribptr[i] = ctx->Current.Attrib[i];
354
   }
355
 
356
   /* Edgeflag, Index:
357
    */
358
   for (i = 16 ; i < 18 ; i++)
359
      ;
360
 
361
   /* Materials:
362
    */
363
   for (i = 18 ; i < 28 ; i++)
364
      ;
365
 
366
   /* Eval:
367
    */
368
   for (i = 28 ; i < 29 ; i++)
369
      ;
370
 
371
 
372
   if (tnl->installed_vertex_format != tnl->vertex_format) {
373
      if (MESA_VERBOSE & DEBUG_VFMT)
374
         _mesa_debug(NULL, "reinstall on vertex_format change\n");
375
      _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
376
      tnl->installed_vertex_format = tnl->vertex_format;
377
   }
378
 
379
   return GL_TRUE;
380
}
381
 
382
 
383
void _tnl_InvalidateVtxfmt( GLcontext *ctx )
384
{
385
   tnl->recheck = GL_TRUE;
386
   tnl->fell_back = GL_FALSE;
387
}
388
 
389
 
390
 
391
 
392
static void _tnl_ValidateVtxfmt( GLcontext *ctx )
393
{
394
   if (MESA_VERBOSE & DEBUG_VFMT)
395
      _mesa_debug(NULL, "%s\n", __FUNCTION__);
396
 
397
   if (ctx->Driver.NeedFlush)
398
      ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush );
399
 
400
   tnl->recheck = GL_FALSE;
401
 
402
   if (check_vtx_fmt( ctx )) {
403
      if (!tnl->installed) {
404
         if (MESA_VERBOSE & DEBUG_VFMT)
405
            _mesa_debug(NULL, "reinstall (new install)\n");
406
 
407
         _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
408
         ctx->Driver.FlushVertices = _tnl_FlushVertices;
409
         tnl->installed = GL_TRUE;
410
      }
411
      else
412
         _mesa_debug(NULL, "%s: already installed", __FUNCTION__);
413
   }
414
   else {
415
      if (MESA_VERBOSE & DEBUG_VFMT)
416
         _mesa_debug(NULL, "%s: failed\n", __FUNCTION__);
417
 
418
      if (tnl->installed) {
419
         if (tnl->tnl->dma.flush)
420
            tnl->tnl->dma.flush( tnl->tnl );
421
         _tnl_wakeup_exec( ctx );
422
         tnl->installed = GL_FALSE;
423
      }
424
   }      
425
}
426
 
427
 
428
 
429
 
430
 
431
/* Begin/End
432
 */
433
static void _tnl_Begin( GLenum mode )
434
{
435
   GLcontext *ctx = tnl->context;
436
   TNLcontext *tnl = tnl->tnl;
437
 
438
   if (MESA_VERBOSE & DEBUG_VFMT)
439
      _mesa_debug(NULL, "%s\n", __FUNCTION__);
440
 
441
   if (mode > GL_POLYGON) {
442
      _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
443
      return;
444
   }
445
 
446
   if (tnl->prim[0] != GL_POLYGON+1) {
447
      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
448
      return;
449
   }
450
 
451
   if (ctx->NewState)
452
      _mesa_update_state( ctx );
453
 
454
   if (tnl->recheck)
455
      _tnl_ValidateVtxfmt( ctx );
456
 
457
   if (tnl->dma.flush && tnl->counter < 12) {
458
      if (MESA_VERBOSE & DEBUG_VFMT)
459
         _mesa_debug(NULL, "%s: flush almost-empty buffers\n", __FUNCTION__);
460
      flush_prims( tnl );
461
   }
462
 
463
   if (!tnl->dma.flush) {
464
      if (tnl->dma.current.ptr + 12*tnl->vertex_size*4 >
465
          tnl->dma.current.end) {
466
         TNL_NEWPRIM( tnl );
467
         _tnl_RefillCurrentDmaRegion( tnl );
468
      }
469
 
470
      tnl->dmaptr = (int *)(tnl->dma.current.address + tnl->dma.current.ptr);
471
      tnl->counter = (tnl->dma.current.end - tnl->dma.current.ptr) /
472
         (tnl->vertex_size * 4);
473
      tnl->counter--;
474
      tnl->initial_counter = tnl->counter;
475
      tnl->notify = wrap_buffer;
476
      tnl->dma.flush = flush_prims;
477
      tnl->context->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
478
   }
479
 
480
 
481
   tnl->prim[0] = mode;
482
   start_prim( tnl, mode | PRIM_BEGIN );
483
}
484
 
485
 
486
 
487
 
488
 
489
static void _tnl_End( void )
490
{
491
   TNLcontext *tnl = tnl->tnl;
492
   GLcontext *ctx = tnl->context;
493
 
494
   if (MESA_VERBOSE & DEBUG_VFMT)
495
      _mesa_debug(NULL, "%s\n", __FUNCTION__);
496
 
497
   if (tnl->prim[0] == GL_POLYGON+1) {
498
      _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
499
      return;
500
   }
501
 
502
   note_last_prim( tnl, PRIM_END );
503
   tnl->prim[0] = GL_POLYGON+1;
504
}
505
 
506
 
507
static void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
508
{
509
   if (MESA_VERBOSE & DEBUG_VFMT)
510
      _mesa_debug(NULL, "%s\n", __FUNCTION__);
511
 
512
   assert(tnl->installed);
513
 
514
   if (flags & FLUSH_UPDATE_CURRENT) {
515
      _tnl_copy_to_current( ctx );
516
      if (MESA_VERBOSE & DEBUG_VFMT)
517
         _mesa_debug(NULL, "reinstall on update_current\n");
518
      _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
519
      ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
520
   }
521
 
522
   if (flags & FLUSH_STORED_VERTICES) {
523
      TNLcontext *tnl = TNL_CONTEXT( ctx );
524
      assert (tnl->dma.flush == 0 ||
525
              tnl->dma.flush == flush_prims);
526
      if (tnl->dma.flush == flush_prims)
527
         flush_prims( TNL_CONTEXT( ctx ) );
528
      ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
529
   }
530
}
531
 
532
 
533
 
534
/* At this point, don't expect very many versions of each function to
535
 * be generated, so not concerned about freeing them?
536
 */
537
 
538
 
539
static void _tnl_InitVtxfmt( GLcontext *ctx )
540
{
541
   GLvertexformat *vfmt = &(tnl->vtxfmt);
542
 
543
   MEMSET( vfmt, 0, sizeof(GLvertexformat) );
544
 
545
   /* Hook in chooser functions for codegen, etc:
546
    */
547
   _tnl_InitVtxfmtChoosers( vfmt );
548
 
549
   /* Handled fully in supported states, but no codegen:
550
    */
551
   vfmt->ArrayElement = _ae_loopback_array_elt;         /* generic helper */
552
   vfmt->Rectf = _mesa_noop_Rectf;                      /* generic helper */
553
   vfmt->Begin = _tnl_Begin;
554
   vfmt->End = _tnl_End;
555
 
556
   tnl->context = ctx;
557
   tnl->tnl = TNL_CONTEXT(ctx);
558
   tnl->prim = &ctx->Driver.CurrentExecPrimitive;
559
   tnl->primflags = 0;
560
 
561
   make_empty_list( &tnl->dfn_cache.Vertex2f );
562
   make_empty_list( &tnl->dfn_cache.Vertex2fv );
563
   make_empty_list( &tnl->dfn_cache.Vertex3f );
564
   make_empty_list( &tnl->dfn_cache.Vertex3fv );
565
   make_empty_list( &tnl->dfn_cache.Color4ub );
566
   make_empty_list( &tnl->dfn_cache.Color4ubv );
567
   make_empty_list( &tnl->dfn_cache.Color3ub );
568
   make_empty_list( &tnl->dfn_cache.Color3ubv );
569
   make_empty_list( &tnl->dfn_cache.Color4f );
570
   make_empty_list( &tnl->dfn_cache.Color4fv );
571
   make_empty_list( &tnl->dfn_cache.Color3f );
572
   make_empty_list( &tnl->dfn_cache.Color3fv );
573
   make_empty_list( &tnl->dfn_cache.SecondaryColor3fEXT );
574
   make_empty_list( &tnl->dfn_cache.SecondaryColor3fvEXT );
575
   make_empty_list( &tnl->dfn_cache.SecondaryColor3ubEXT );
576
   make_empty_list( &tnl->dfn_cache.SecondaryColor3ubvEXT );
577
   make_empty_list( &tnl->dfn_cache.Normal3f );
578
   make_empty_list( &tnl->dfn_cache.Normal3fv );
579
   make_empty_list( &tnl->dfn_cache.TexCoord2f );
580
   make_empty_list( &tnl->dfn_cache.TexCoord2fv );
581
   make_empty_list( &tnl->dfn_cache.TexCoord1f );
582
   make_empty_list( &tnl->dfn_cache.TexCoord1fv );
583
   make_empty_list( &tnl->dfn_cache.MultiTexCoord2fARB );
584
   make_empty_list( &tnl->dfn_cache.MultiTexCoord2fvARB );
585
   make_empty_list( &tnl->dfn_cache.MultiTexCoord1fARB );
586
   make_empty_list( &tnl->dfn_cache.MultiTexCoord1fvARB );
587
 
588
   _tnl_InitCodegen( &tnl->codegen );
589
}
590
 
591
static void free_funcs( struct dynfn *l )
592
{
593
   struct dynfn *f, *tmp;
594
   foreach_s (f, tmp, l) {
595
      remove_from_list( f );
596
      ALIGN_FREE( f->code );
597
      FREE( f );
598
   }
599
}
600
 
601
 
602
static void _tnl_DestroyVtxfmt( GLcontext *ctx )
603
{
604
   count_funcs();
605
   free_funcs( &tnl->dfn_cache.Vertex2f );
606
   free_funcs( &tnl->dfn_cache.Vertex2fv );
607
   free_funcs( &tnl->dfn_cache.Vertex3f );
608
   free_funcs( &tnl->dfn_cache.Vertex3fv );
609
   free_funcs( &tnl->dfn_cache.Color4ub );
610
   free_funcs( &tnl->dfn_cache.Color4ubv );
611
   free_funcs( &tnl->dfn_cache.Color3ub );
612
   free_funcs( &tnl->dfn_cache.Color3ubv );
613
   free_funcs( &tnl->dfn_cache.Color4f );
614
   free_funcs( &tnl->dfn_cache.Color4fv );
615
   free_funcs( &tnl->dfn_cache.Color3f );
616
   free_funcs( &tnl->dfn_cache.Color3fv );
617
   free_funcs( &tnl->dfn_cache.SecondaryColor3ubEXT );
618
   free_funcs( &tnl->dfn_cache.SecondaryColor3ubvEXT );
619
   free_funcs( &tnl->dfn_cache.SecondaryColor3fEXT );
620
   free_funcs( &tnl->dfn_cache.SecondaryColor3fvEXT );
621
   free_funcs( &tnl->dfn_cache.Normal3f );
622
   free_funcs( &tnl->dfn_cache.Normal3fv );
623
   free_funcs( &tnl->dfn_cache.TexCoord2f );
624
   free_funcs( &tnl->dfn_cache.TexCoord2fv );
625
   free_funcs( &tnl->dfn_cache.TexCoord1f );
626
   free_funcs( &tnl->dfn_cache.TexCoord1fv );
627
   free_funcs( &tnl->dfn_cache.MultiTexCoord2fARB );
628
   free_funcs( &tnl->dfn_cache.MultiTexCoord2fvARB );
629
   free_funcs( &tnl->dfn_cache.MultiTexCoord1fARB );
630
   free_funcs( &tnl->dfn_cache.MultiTexCoord1fvARB );
631
}
632