2 * Copyright 2003 Tungsten Graphics, inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 * Keith Whitwell <keithw@tungstengraphics.com>
32 #include "t_context.h"
36 /* Build and manage clipspace/ndc/window vertices.
38 * Another new mechanism designed and crying out for codegen. Before
39 * that, it would be very interesting to investigate the merger of
40 * these vertices and those built in t_vtx_*.
49 * These functions take the NDC coordinates pointed to by 'in', apply the
50 * NDC->Viewport mapping and store the results at 'v'.
53 static INLINE
void insert_4f_viewport_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
56 GLfloat
*out
= (GLfloat
*)v
;
57 const GLfloat
* const vp
= a
->vp
;
59 out
[0] = vp
[0] * in
[0] + vp
[12];
60 out
[1] = vp
[5] * in
[1] + vp
[13];
61 out
[2] = vp
[10] * in
[2] + vp
[14];
65 static INLINE
void insert_4f_viewport_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
68 GLfloat
*out
= (GLfloat
*)v
;
69 const GLfloat
* const vp
= a
->vp
;
71 out
[0] = vp
[0] * in
[0] + vp
[12];
72 out
[1] = vp
[5] * in
[1] + vp
[13];
73 out
[2] = vp
[10] * in
[2] + vp
[14];
77 static INLINE
void insert_4f_viewport_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
80 GLfloat
*out
= (GLfloat
*)v
;
81 const GLfloat
* const vp
= a
->vp
;
83 out
[0] = vp
[0] * in
[0] + vp
[12];
84 out
[1] = vp
[5] * in
[1] + vp
[13];
89 static INLINE
void insert_4f_viewport_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
92 GLfloat
*out
= (GLfloat
*)v
;
93 const GLfloat
* const vp
= a
->vp
;
95 out
[0] = vp
[0] * in
[0] + vp
[12];
101 static INLINE
void insert_3f_viewport_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
104 GLfloat
*out
= (GLfloat
*)v
;
105 const GLfloat
* const vp
= a
->vp
;
107 out
[0] = vp
[0] * in
[0] + vp
[12];
108 out
[1] = vp
[5] * in
[1] + vp
[13];
109 out
[2] = vp
[10] * in
[2] + vp
[14];
112 static INLINE
void insert_3f_viewport_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
115 GLfloat
*out
= (GLfloat
*)v
;
116 const GLfloat
* const vp
= a
->vp
;
118 out
[0] = vp
[0] * in
[0] + vp
[12];
119 out
[1] = vp
[5] * in
[1] + vp
[13];
120 out
[2] = vp
[10] * in
[2] + vp
[14];
123 static INLINE
void insert_3f_viewport_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
126 GLfloat
*out
= (GLfloat
*)v
;
127 const GLfloat
* const vp
= a
->vp
;
129 out
[0] = vp
[0] * in
[0] + vp
[12];
134 static INLINE
void insert_2f_viewport_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
137 GLfloat
*out
= (GLfloat
*)v
;
138 const GLfloat
* const vp
= a
->vp
;
140 out
[0] = vp
[0] * in
[0] + vp
[12];
141 out
[1] = vp
[5] * in
[1] + vp
[13];
144 static INLINE
void insert_2f_viewport_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
147 GLfloat
*out
= (GLfloat
*)v
;
148 const GLfloat
* const vp
= a
->vp
;
150 out
[0] = vp
[0] * in
[0] + vp
[12];
156 * These functions do the same as above, except for the viewport mapping.
159 static INLINE
void insert_4f_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
161 GLfloat
*out
= (GLfloat
*)(v
);
170 static INLINE
void insert_4f_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
172 GLfloat
*out
= (GLfloat
*)(v
);
181 static INLINE
void insert_4f_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
183 GLfloat
*out
= (GLfloat
*)(v
);
192 static INLINE
void insert_4f_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
194 GLfloat
*out
= (GLfloat
*)(v
);
203 static INLINE
void insert_3f_xyw_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
205 GLfloat
*out
= (GLfloat
*)(v
);
213 static INLINE
void insert_3f_xyw_err( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
215 (void) a
; (void) v
; (void) in
;
219 static INLINE
void insert_3f_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
221 GLfloat
*out
= (GLfloat
*)(v
);
229 static INLINE
void insert_3f_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
231 GLfloat
*out
= (GLfloat
*)(v
);
239 static INLINE
void insert_3f_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
241 GLfloat
*out
= (GLfloat
*)(v
);
250 static INLINE
void insert_2f_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
252 GLfloat
*out
= (GLfloat
*)(v
);
259 static INLINE
void insert_2f_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
261 GLfloat
*out
= (GLfloat
*)(v
);
268 static INLINE
void insert_1f_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
270 GLfloat
*out
= (GLfloat
*)(v
);
276 static INLINE
void insert_null( const struct tnl_clipspace_attr
*a
, GLubyte
*v
, const GLfloat
*in
)
278 (void) a
; (void) v
; (void) in
;
281 static INLINE
void insert_4chan_4f_rgba_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
284 GLchan
*c
= (GLchan
*)v
;
286 UNCLAMPED_FLOAT_TO_CHAN(c
[0], in
[0]);
287 UNCLAMPED_FLOAT_TO_CHAN(c
[1], in
[1]);
288 UNCLAMPED_FLOAT_TO_CHAN(c
[2], in
[2]);
289 UNCLAMPED_FLOAT_TO_CHAN(c
[3], in
[3]);
292 static INLINE
void insert_4chan_4f_rgba_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
295 GLchan
*c
= (GLchan
*)v
;
297 UNCLAMPED_FLOAT_TO_CHAN(c
[0], in
[0]);
298 UNCLAMPED_FLOAT_TO_CHAN(c
[1], in
[1]);
299 UNCLAMPED_FLOAT_TO_CHAN(c
[2], in
[2]);
303 static INLINE
void insert_4chan_4f_rgba_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
306 GLchan
*c
= (GLchan
*)v
;
308 UNCLAMPED_FLOAT_TO_CHAN(c
[0], in
[0]);
309 UNCLAMPED_FLOAT_TO_CHAN(c
[1], in
[1]);
314 static INLINE
void insert_4chan_4f_rgba_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
317 GLchan
*c
= (GLchan
*)v
;
319 UNCLAMPED_FLOAT_TO_CHAN(c
[0], in
[0]);
325 static INLINE
void insert_4ub_4f_rgba_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
329 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
330 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
331 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[2]);
332 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[3]);
335 static INLINE
void insert_4ub_4f_rgba_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
339 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
340 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
341 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[2]);
345 static INLINE
void insert_4ub_4f_rgba_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
349 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
350 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
355 static INLINE
void insert_4ub_4f_rgba_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
359 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
365 static INLINE
void insert_4ub_4f_bgra_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
369 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
370 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
371 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[2]);
372 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[3]);
375 static INLINE
void insert_4ub_4f_bgra_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
379 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
380 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
381 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[2]);
385 static INLINE
void insert_4ub_4f_bgra_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
389 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
390 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
395 static INLINE
void insert_4ub_4f_bgra_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
399 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
405 static INLINE
void insert_4ub_4f_argb_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
409 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[0]);
410 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
411 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[2]);
412 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[3]);
415 static INLINE
void insert_4ub_4f_argb_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
419 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[0]);
420 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
421 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[2]);
425 static INLINE
void insert_4ub_4f_argb_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
429 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[0]);
430 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
435 static INLINE
void insert_4ub_4f_argb_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
439 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[0]);
445 static INLINE
void insert_4ub_4f_abgr_4( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
449 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[0]);
450 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
451 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[2]);
452 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[3]);
455 static INLINE
void insert_4ub_4f_abgr_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
459 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[0]);
460 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
461 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[2]);
465 static INLINE
void insert_4ub_4f_abgr_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
469 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[0]);
470 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[1]);
475 static INLINE
void insert_4ub_4f_abgr_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
479 UNCLAMPED_FLOAT_TO_UBYTE(v
[3], in
[0]);
485 static INLINE
void insert_3ub_3f_rgb_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
489 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
490 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
491 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[2]);
494 static INLINE
void insert_3ub_3f_rgb_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
498 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
499 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
503 static INLINE
void insert_3ub_3f_rgb_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
507 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
512 static INLINE
void insert_3ub_3f_bgr_3( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
516 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
517 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
518 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[2]);
521 static INLINE
void insert_3ub_3f_bgr_2( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
525 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
526 UNCLAMPED_FLOAT_TO_UBYTE(v
[1], in
[1]);
530 static INLINE
void insert_3ub_3f_bgr_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
534 UNCLAMPED_FLOAT_TO_UBYTE(v
[2], in
[0]);
540 static INLINE
void insert_1ub_1f_1( const struct tnl_clipspace_attr
*a
, GLubyte
*v
,
544 UNCLAMPED_FLOAT_TO_UBYTE(v
[0], in
[0]);
548 /***********************************************************************
549 * Functions to perform the reverse operations to the above, for
550 * swrast translation and clip-interpolation.
552 * Currently always extracts a full 4 floats.
555 static void extract_4f_viewport( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
558 const GLfloat
*in
= (const GLfloat
*)v
;
559 const GLfloat
* const vp
= a
->vp
;
561 /* Although included for completeness, the position coordinate is
562 * usually handled differently during clipping.
564 out
[0] = (in
[0] - vp
[12]) / vp
[0];
565 out
[1] = (in
[1] - vp
[13]) / vp
[5];
566 out
[2] = (in
[2] - vp
[14]) / vp
[10];
570 static void extract_3f_viewport( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
573 const GLfloat
*in
= (const GLfloat
*)v
;
574 const GLfloat
* const vp
= a
->vp
;
576 out
[0] = (in
[0] - vp
[12]) / vp
[0];
577 out
[1] = (in
[1] - vp
[13]) / vp
[5];
578 out
[2] = (in
[2] - vp
[14]) / vp
[10];
583 static void extract_2f_viewport( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
586 const GLfloat
*in
= (const GLfloat
*)v
;
587 const GLfloat
* const vp
= a
->vp
;
589 out
[0] = (in
[0] - vp
[12]) / vp
[0];
590 out
[1] = (in
[1] - vp
[13]) / vp
[5];
596 static void extract_4f( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
598 const GLfloat
*in
= (const GLfloat
*)v
;
607 static void extract_3f_xyw( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
609 const GLfloat
*in
= (const GLfloat
*)v
;
619 static void extract_3f( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
621 const GLfloat
*in
= (const GLfloat
*)v
;
631 static void extract_2f( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
633 const GLfloat
*in
= (const GLfloat
*)v
;
642 static void extract_1f( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
644 const GLfloat
*in
= (const GLfloat
*)v
;
653 static void extract_4chan_4f_rgba( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
656 GLchan
*c
= (GLchan
*)v
;
659 out
[0] = CHAN_TO_FLOAT(c
[0]);
660 out
[1] = CHAN_TO_FLOAT(c
[1]);
661 out
[2] = CHAN_TO_FLOAT(c
[2]);
662 out
[3] = CHAN_TO_FLOAT(c
[3]);
665 static void extract_4ub_4f_rgba( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
669 out
[0] = UBYTE_TO_FLOAT(v
[0]);
670 out
[1] = UBYTE_TO_FLOAT(v
[1]);
671 out
[2] = UBYTE_TO_FLOAT(v
[2]);
672 out
[3] = UBYTE_TO_FLOAT(v
[3]);
675 static void extract_4ub_4f_bgra( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
679 out
[2] = UBYTE_TO_FLOAT(v
[0]);
680 out
[1] = UBYTE_TO_FLOAT(v
[1]);
681 out
[0] = UBYTE_TO_FLOAT(v
[2]);
682 out
[3] = UBYTE_TO_FLOAT(v
[3]);
685 static void extract_4ub_4f_argb( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
689 out
[3] = UBYTE_TO_FLOAT(v
[0]);
690 out
[0] = UBYTE_TO_FLOAT(v
[1]);
691 out
[1] = UBYTE_TO_FLOAT(v
[2]);
692 out
[2] = UBYTE_TO_FLOAT(v
[3]);
695 static void extract_4ub_4f_abgr( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
699 out
[3] = UBYTE_TO_FLOAT(v
[0]);
700 out
[2] = UBYTE_TO_FLOAT(v
[1]);
701 out
[1] = UBYTE_TO_FLOAT(v
[2]);
702 out
[0] = UBYTE_TO_FLOAT(v
[3]);
705 static void extract_3ub_3f_rgb( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
709 out
[0] = UBYTE_TO_FLOAT(v
[0]);
710 out
[1] = UBYTE_TO_FLOAT(v
[1]);
711 out
[2] = UBYTE_TO_FLOAT(v
[2]);
715 static void extract_3ub_3f_bgr( const struct tnl_clipspace_attr
*a
, GLfloat
*out
,
719 out
[2] = UBYTE_TO_FLOAT(v
[0]);
720 out
[1] = UBYTE_TO_FLOAT(v
[1]);
721 out
[0] = UBYTE_TO_FLOAT(v
[2]);
725 static void extract_1ub_1f( const struct tnl_clipspace_attr
*a
, GLfloat
*out
, const GLubyte
*v
)
728 out
[0] = UBYTE_TO_FLOAT(v
[0]);
735 static const struct {
737 tnl_extract_func extract
;
738 tnl_insert_func insert
[4];
739 const GLuint attrsize
;
740 } format_info
[EMIT_MAX
] = {
744 { insert_1f_1
, insert_1f_1
, insert_1f_1
, insert_1f_1
},
749 { insert_2f_1
, insert_2f_2
, insert_2f_2
, insert_2f_2
},
750 2 * sizeof(GLfloat
) },
754 { insert_3f_1
, insert_3f_2
, insert_3f_3
, insert_3f_3
},
755 3 * sizeof(GLfloat
) },
759 { insert_4f_1
, insert_4f_2
, insert_4f_3
, insert_4f_4
},
760 4 * sizeof(GLfloat
) },
764 { insert_2f_viewport_1
, insert_2f_viewport_2
, insert_2f_viewport_2
,
765 insert_2f_viewport_2
},
766 2 * sizeof(GLfloat
) },
770 { insert_3f_viewport_1
, insert_3f_viewport_2
, insert_3f_viewport_3
,
771 insert_3f_viewport_3
},
772 3 * sizeof(GLfloat
) },
776 { insert_4f_viewport_1
, insert_4f_viewport_2
, insert_4f_viewport_3
,
777 insert_4f_viewport_4
},
778 4 * sizeof(GLfloat
) },
782 { insert_3f_xyw_err
, insert_3f_xyw_err
, insert_3f_xyw_err
,
784 3 * sizeof(GLfloat
) },
788 { insert_1ub_1f_1
, insert_1ub_1f_1
, insert_1ub_1f_1
, insert_1ub_1f_1
},
793 { insert_3ub_3f_rgb_1
, insert_3ub_3f_rgb_2
, insert_3ub_3f_rgb_3
,
794 insert_3ub_3f_rgb_3
},
795 3 * sizeof(GLubyte
) },
799 { insert_3ub_3f_bgr_1
, insert_3ub_3f_bgr_2
, insert_3ub_3f_bgr_3
,
800 insert_3ub_3f_bgr_3
},
801 3 * sizeof(GLubyte
) },
805 { insert_4ub_4f_rgba_1
, insert_4ub_4f_rgba_2
, insert_4ub_4f_rgba_3
,
806 insert_4ub_4f_rgba_4
},
807 4 * sizeof(GLubyte
) },
811 { insert_4ub_4f_bgra_1
, insert_4ub_4f_bgra_2
, insert_4ub_4f_bgra_3
,
812 insert_4ub_4f_bgra_4
},
813 4 * sizeof(GLubyte
) },
817 { insert_4ub_4f_argb_1
, insert_4ub_4f_argb_2
, insert_4ub_4f_argb_3
,
818 insert_4ub_4f_argb_4
},
819 4 * sizeof(GLubyte
) },
823 { insert_4ub_4f_abgr_1
, insert_4ub_4f_abgr_2
, insert_4ub_4f_abgr_3
,
824 insert_4ub_4f_abgr_4
},
825 4 * sizeof(GLubyte
) },
828 extract_4chan_4f_rgba
,
829 { insert_4chan_4f_rgba_1
, insert_4chan_4f_rgba_2
, insert_4chan_4f_rgba_3
,
830 insert_4chan_4f_rgba_4
},
831 4 * sizeof(GLchan
) },
835 { NULL
, NULL
, NULL
, NULL
},
843 /***********************************************************************
844 * Hardwired fastpaths for emitting whole vertices or groups of
847 static void choose_emit_func( GLcontext
*ctx
, GLuint count
, GLubyte
*dest
);
850 #define EMIT5(NR, F0, F1, F2, F3, F4, NAME) \
851 static void NAME( GLcontext *ctx, \
855 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); \
856 struct tnl_clipspace_attr *a = vtx->attr; \
859 if (vtx->attr_count != NR || \
860 (NR > 0 && a[0].emit != F0) || \
861 (NR > 1 && a[1].emit != F1) || \
862 (NR > 2 && a[2].emit != F2) || \
863 (NR > 3 && a[3].emit != F3) || \
864 (NR > 4 && a[4].emit != F4)) { \
865 choose_emit_func( ctx, count, v ); \
869 for (i = 0 ; i < count ; i++, v += vtx->vertex_size) { \
871 F0( &a[0], v + a[0].vertoffset, (GLfloat *)a[0].inputptr ); \
872 a[0].inputptr += a[0].inputstride; \
876 F1( &a[1], v + a[1].vertoffset, (GLfloat *)a[1].inputptr ); \
877 a[1].inputptr += a[1].inputstride; \
881 F2( &a[2], v + a[2].vertoffset, (GLfloat *)a[2].inputptr ); \
882 a[2].inputptr += a[2].inputstride; \
886 F3( &a[3], v + a[3].vertoffset, (GLfloat *)a[3].inputptr ); \
887 a[3].inputptr += a[3].inputstride; \
891 F4( &a[4], v + a[4].vertoffset, (GLfloat *)a[4].inputptr ); \
892 a[4].inputptr += a[4].inputstride; \
898 #define EMIT2(F0, F1, NAME) EMIT5(2, F0, F1, insert_null, \
899 insert_null, insert_null, NAME)
901 #define EMIT3(F0, F1, F2, NAME) EMIT5(3, F0, F1, F2, insert_null, \
904 #define EMIT4(F0, F1, F2, F3, NAME) EMIT5(4, F0, F1, F2, F3, \
908 EMIT2(insert_3f_viewport_3
, insert_4ub_4f_rgba_4
, emit_viewport3_rgba4
)
909 EMIT2(insert_3f_viewport_3
, insert_4ub_4f_bgra_4
, emit_viewport3_bgra4
)
910 EMIT2(insert_3f_3
, insert_4ub_4f_rgba_4
, emit_xyz3_rgba4
)
912 EMIT3(insert_4f_viewport_4
, insert_4ub_4f_rgba_4
, insert_2f_2
, emit_viewport4_rgba4_st2
)
913 EMIT3(insert_4f_viewport_4
, insert_4ub_4f_bgra_4
, insert_2f_2
, emit_viewport4_bgra4_st2
)
914 EMIT3(insert_4f_4
, insert_4ub_4f_rgba_4
, insert_2f_2
, emit_xyzw4_rgba4_st2
)
916 EMIT4(insert_4f_viewport_4
, insert_4ub_4f_rgba_4
, insert_2f_2
, insert_2f_2
, emit_viewport4_rgba4_st2_st2
)
917 EMIT4(insert_4f_viewport_4
, insert_4ub_4f_bgra_4
, insert_2f_2
, insert_2f_2
, emit_viewport4_bgra4_st2_st2
)
918 EMIT4(insert_4f_4
, insert_4ub_4f_rgba_4
, insert_2f_2
, insert_2f_2
, emit_xyzw4_rgba4_st2_st2
)
924 /***********************************************************************
925 * Generic (non-codegen) functions for whole vertices or groups of
929 static void generic_emit( GLcontext
*ctx
,
933 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
934 struct tnl_clipspace_attr
*a
= vtx
->attr
;
935 const GLuint attr_count
= vtx
->attr_count
;
936 const GLuint stride
= vtx
->vertex_size
;
939 for (i
= 0 ; i
< count
; i
++, v
+= stride
) {
940 for (j
= 0; j
< attr_count
; j
++) {
941 GLfloat
*in
= (GLfloat
*)a
[j
].inputptr
;
942 a
[j
].inputptr
+= a
[j
].inputstride
;
943 a
[j
].emit( &a
[j
], v
+ a
[j
].vertoffset
, in
);
949 static void generic_interp( GLcontext
*ctx
,
951 GLuint edst
, GLuint eout
, GLuint ein
,
952 GLboolean force_boundary
)
954 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
955 struct vertex_buffer
*VB
= &tnl
->vb
;
956 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
957 const GLubyte
*vin
= vtx
->vertex_buf
+ ein
* vtx
->vertex_size
;
958 const GLubyte
*vout
= vtx
->vertex_buf
+ eout
* vtx
->vertex_size
;
959 GLubyte
*vdst
= vtx
->vertex_buf
+ edst
* vtx
->vertex_size
;
960 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
961 const GLuint attr_count
= vtx
->attr_count
;
963 (void) force_boundary
;
965 if (tnl
->NeedNdcCoords
) {
966 const GLfloat
*dstclip
= VB
->ClipPtr
->data
[edst
];
967 if (dstclip
[3] != 0.0) {
968 const GLfloat w
= 1.0f
/ dstclip
[3];
971 pos
[0] = dstclip
[0] * w
;
972 pos
[1] = dstclip
[1] * w
;
973 pos
[2] = dstclip
[2] * w
;
976 a
[0].insert
[4-1]( &a
[0], vdst
, pos
);
980 a
[0].insert
[4-1]( &a
[0], vdst
, VB
->ClipPtr
->data
[edst
] );
984 for (j
= 1; j
< attr_count
; j
++) {
985 GLfloat fin
[4], fout
[4], fdst
[4];
987 a
[j
].extract( &a
[j
], fin
, vin
+ a
[j
].vertoffset
);
988 a
[j
].extract( &a
[j
], fout
, vout
+ a
[j
].vertoffset
);
990 INTERP_F( t
, fdst
[3], fout
[3], fin
[3] );
991 INTERP_F( t
, fdst
[2], fout
[2], fin
[2] );
992 INTERP_F( t
, fdst
[1], fout
[1], fin
[1] );
993 INTERP_F( t
, fdst
[0], fout
[0], fin
[0] );
995 a
[j
].insert
[4-1]( &a
[j
], vdst
+ a
[j
].vertoffset
, fdst
);
1000 /* Extract color attributes from one vertex and insert them into
1001 * another. (Shortcircuit extract/insert with memcpy).
1003 static void generic_copy_pv( GLcontext
*ctx
, GLuint edst
, GLuint esrc
)
1005 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1006 GLubyte
*vsrc
= vtx
->vertex_buf
+ esrc
* vtx
->vertex_size
;
1007 GLubyte
*vdst
= vtx
->vertex_buf
+ edst
* vtx
->vertex_size
;
1008 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
1009 const GLuint attr_count
= vtx
->attr_count
;
1012 for (j
= 0; j
< attr_count
; j
++) {
1013 if (a
[j
].attrib
== VERT_ATTRIB_COLOR0
||
1014 a
[j
].attrib
== VERT_ATTRIB_COLOR1
) {
1016 _mesa_memcpy( vdst
+ a
[j
].vertoffset
,
1017 vsrc
+ a
[j
].vertoffset
,
1018 a
[j
].vertattrsize
);
1024 /* Helper functions for hardware which doesn't put back colors and/or
1025 * edgeflags into vertices.
1027 static void generic_interp_extras( GLcontext
*ctx
,
1029 GLuint dst
, GLuint out
, GLuint in
,
1030 GLboolean force_boundary
)
1032 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
1034 /* If stride is zero, ColorPtr[1] is constant across the VB, so
1035 * there is no point interpolating between two values as they will
1036 * be identical. In all other cases, this value is generated by
1037 * t_vb_lighttmp.h and has a stride of 4 dwords.
1039 if (VB
->ColorPtr
[1] && VB
->ColorPtr
[1]->stride
) {
1040 assert(VB
->ColorPtr
[1]->stride
== 4 * sizeof(GLfloat
));
1043 VB
->ColorPtr
[1]->data
[dst
],
1044 VB
->ColorPtr
[1]->data
[out
],
1045 VB
->ColorPtr
[1]->data
[in
] );
1048 if (VB
->SecondaryColorPtr
[1]) {
1049 assert(VB
->SecondaryColorPtr
[1]->stride
== 4 * sizeof(GLfloat
));
1052 VB
->SecondaryColorPtr
[1]->data
[dst
],
1053 VB
->SecondaryColorPtr
[1]->data
[out
],
1054 VB
->SecondaryColorPtr
[1]->data
[in
] );
1057 if (VB
->IndexPtr
[1]) {
1058 VB
->IndexPtr
[1]->data
[dst
][0] = LINTERP( t
,
1059 VB
->IndexPtr
[1]->data
[out
][0],
1060 VB
->IndexPtr
[1]->data
[in
][0] );
1064 VB
->EdgeFlag
[dst
] = VB
->EdgeFlag
[out
] || force_boundary
;
1067 generic_interp(ctx
, t
, dst
, out
, in
, force_boundary
);
1070 static void generic_copy_pv_extras( GLcontext
*ctx
,
1071 GLuint dst
, GLuint src
)
1073 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
1075 /* See above comment:
1077 if (VB
->ColorPtr
[1] && VB
->ColorPtr
[1]->stride
) {
1078 COPY_4FV( VB
->ColorPtr
[1]->data
[dst
],
1079 VB
->ColorPtr
[1]->data
[src
] );
1082 if (VB
->SecondaryColorPtr
[1]) {
1083 COPY_4FV( VB
->SecondaryColorPtr
[1]->data
[dst
],
1084 VB
->SecondaryColorPtr
[1]->data
[src
] );
1087 if (VB
->IndexPtr
[1]) {
1088 VB
->IndexPtr
[1]->data
[dst
][0] = VB
->IndexPtr
[1]->data
[src
][0];
1091 generic_copy_pv(ctx
, dst
, src
);
1097 /***********************************************************************
1098 * Build codegen functions or return generic ones:
1102 static void choose_emit_func( GLcontext
*ctx
, GLuint count
, GLubyte
*dest
)
1104 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1105 struct tnl_clipspace_attr
*a
= vtx
->attr
;
1106 const GLuint attr_count
= vtx
->attr_count
;
1111 vtx
->emit
= _tnl_codegen_emit(ctx
);
1113 /* Does it fit a hardwired fastpath? Help! this is growing out of
1116 switch (attr_count
) {
1118 if (a
[0].emit
== insert_3f_viewport_3
) {
1119 if (a
[1].emit
== insert_4ub_4f_bgra_4
)
1120 vtx
->emit
= emit_viewport3_bgra4
;
1121 else if (a
[1].emit
== insert_4ub_4f_rgba_4
)
1122 vtx
->emit
= emit_viewport3_rgba4
;
1124 else if (a
[0].emit
== insert_3f_3
&&
1125 a
[1].emit
== insert_4ub_4f_rgba_4
) {
1126 vtx
->emit
= emit_xyz3_rgba4
;
1130 if (a
[2].emit
== insert_2f_2
) {
1131 if (a
[1].emit
== insert_4ub_4f_rgba_4
) {
1132 if (a
[0].emit
== insert_4f_viewport_4
)
1133 vtx
->emit
= emit_viewport4_rgba4_st2
;
1134 else if (a
[0].emit
== insert_4f_4
)
1135 vtx
->emit
= emit_xyzw4_rgba4_st2
;
1137 else if (a
[1].emit
== insert_4ub_4f_bgra_4
&&
1138 a
[0].emit
== insert_4f_viewport_4
)
1139 vtx
->emit
= emit_viewport4_bgra4_st2
;
1143 if (a
[2].emit
== insert_2f_2
&&
1144 a
[3].emit
== insert_2f_2
) {
1145 if (a
[1].emit
== insert_4ub_4f_rgba_4
) {
1146 if (a
[0].emit
== insert_4f_viewport_4
)
1147 vtx
->emit
= emit_viewport4_rgba4_st2_st2
;
1148 else if (a
[0].emit
== insert_4f_4
)
1149 vtx
->emit
= emit_xyzw4_rgba4_st2_st2
;
1151 else if (a
[1].emit
== insert_4ub_4f_bgra_4
&&
1152 a
[0].emit
== insert_4f_viewport_4
)
1153 vtx
->emit
= emit_viewport4_bgra4_st2_st2
;
1158 /* Otherwise use the generic version:
1161 vtx
->emit
= generic_emit
;
1163 vtx
->emit( ctx
, count
, dest
);
1168 static void choose_interp_func( GLcontext
*ctx
,
1170 GLuint edst
, GLuint eout
, GLuint ein
,
1171 GLboolean force_boundary
)
1173 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1175 if (vtx
->need_extras
&&
1176 (ctx
->_TriangleCaps
& (DD_TRI_LIGHT_TWOSIDE
|DD_TRI_UNFILLED
))) {
1177 vtx
->interp
= generic_interp_extras
;
1179 vtx
->interp
= generic_interp
;
1182 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
1186 static void choose_copy_pv_func( GLcontext
*ctx
, GLuint edst
, GLuint esrc
)
1188 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1190 if (vtx
->need_extras
&&
1191 (ctx
->_TriangleCaps
& (DD_TRI_LIGHT_TWOSIDE
|DD_TRI_UNFILLED
))) {
1192 vtx
->copy_pv
= generic_copy_pv_extras
;
1194 vtx
->copy_pv
= generic_copy_pv
;
1197 vtx
->copy_pv( ctx
, edst
, esrc
);
1201 /***********************************************************************
1202 * Public entrypoints, mostly dispatch to the above:
1206 /* Interpolate between two vertices to produce a third:
1208 void _tnl_interp( GLcontext
*ctx
,
1210 GLuint edst
, GLuint eout
, GLuint ein
,
1211 GLboolean force_boundary
)
1213 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1214 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
1217 /* Copy colors from one vertex to another:
1219 void _tnl_copy_pv( GLcontext
*ctx
, GLuint edst
, GLuint esrc
)
1221 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1222 vtx
->copy_pv( ctx
, edst
, esrc
);
1226 /* Extract a named attribute from a hardware vertex. Will have to
1227 * reverse any viewport transformation, swizzling or other conversions
1228 * which may have been applied:
1230 void _tnl_get_attr( GLcontext
*ctx
, const void *vin
,
1231 GLenum attr
, GLfloat
*dest
)
1233 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1234 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
1235 const GLuint attr_count
= vtx
->attr_count
;
1238 for (j
= 0; j
< attr_count
; j
++) {
1239 if (a
[j
].attrib
== attr
) {
1240 a
[j
].extract( &a
[j
], dest
, (GLubyte
*)vin
+ a
[j
].vertoffset
);
1245 /* Else return the value from ctx->Current.
1247 _mesa_memcpy( dest
, ctx
->Current
.Attrib
[attr
], 4*sizeof(GLfloat
));
1251 /* Complementary operation to the above.
1253 void _tnl_set_attr( GLcontext
*ctx
, void *vout
,
1254 GLenum attr
, const GLfloat
*src
)
1256 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1257 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
1258 const GLuint attr_count
= vtx
->attr_count
;
1261 for (j
= 0; j
< attr_count
; j
++) {
1262 if (a
[j
].attrib
== attr
) {
1263 a
[j
].insert
[4-1]( &a
[j
], (GLubyte
*)vout
+ a
[j
].vertoffset
, src
);
1270 void *_tnl_get_vertex( GLcontext
*ctx
, GLuint nr
)
1272 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1274 return vtx
->vertex_buf
+ nr
* vtx
->vertex_size
;
1277 void _tnl_invalidate_vertex_state( GLcontext
*ctx
, GLuint new_state
)
1279 if (new_state
& (_DD_NEW_TRI_LIGHT_TWOSIDE
|_DD_NEW_TRI_UNFILLED
) ) {
1280 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1281 vtx
->new_inputs
= ~0;
1282 vtx
->interp
= choose_interp_func
;
1283 vtx
->copy_pv
= choose_copy_pv_func
;
1288 GLuint
_tnl_install_attrs( GLcontext
*ctx
, const struct tnl_attr_map
*map
,
1289 GLuint nr
, const GLfloat
*vp
,
1290 GLuint unpacked_size
)
1292 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1296 assert(nr
< _TNL_ATTRIB_MAX
);
1297 assert(nr
== 0 || map
[0].attrib
== VERT_ATTRIB_POS
);
1299 if (vtx
->emit
== generic_emit
)
1300 vtx
->emit
= choose_emit_func
;
1302 vtx
->interp
= choose_interp_func
;
1303 vtx
->copy_pv
= choose_copy_pv_func
;
1304 vtx
->new_inputs
= ~0;
1306 for (j
= 0, i
= 0; i
< nr
; i
++) {
1307 const GLuint format
= map
[i
].format
;
1308 if (format
== EMIT_PAD
) {
1310 fprintf(stderr, "%d: pad %d, offset %d\n", i,
1311 map[i].offset, offset);
1313 offset
+= map
[i
].offset
;
1317 vtx
->attr
[j
].attrib
= map
[i
].attrib
;
1318 vtx
->attr
[j
].format
= format
;
1319 vtx
->attr
[j
].vp
= vp
;
1320 vtx
->attr
[j
].insert
= format_info
[format
].insert
;
1321 vtx
->attr
[j
].extract
= format_info
[format
].extract
;
1322 vtx
->attr
[j
].vertattrsize
= format_info
[format
].attrsize
;
1325 vtx
->attr
[j
].vertoffset
= map
[i
].offset
;
1327 vtx
->attr
[j
].vertoffset
= offset
;
1330 fprintf(stderr, "%d: %s, vp %p, offset %d\n", i,
1331 format_info[format].name, (void *)vp,
1332 vtx->attr[j].vertoffset);
1334 offset
+= format_info
[format
].attrsize
;
1339 vtx
->attr_count
= j
;
1342 vtx
->vertex_size
= unpacked_size
;
1344 vtx
->vertex_size
= offset
;
1346 assert(vtx
->vertex_size
<= vtx
->max_vertex_size
);
1348 return vtx
->vertex_size
;
1353 void _tnl_invalidate_vertices( GLcontext
*ctx
, GLuint newinputs
)
1355 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1356 vtx
->new_inputs
|= newinputs
;
1360 void _tnl_build_vertices( GLcontext
*ctx
,
1365 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1367 newinputs
|= vtx
->new_inputs
;
1368 vtx
->new_inputs
= 0;
1371 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
1372 struct tnl_clipspace_attr
*a
= vtx
->attr
;
1373 const GLuint stride
= vtx
->vertex_size
;
1374 const GLuint count
= vtx
->attr_count
;
1377 for (j
= 0; j
< count
; j
++) {
1378 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
1379 a
[j
].inputstride
= vptr
->stride
;
1380 a
[j
].inputptr
= ((GLubyte
*)vptr
->data
) + start
* vptr
->stride
;
1381 a
[j
].emit
= a
[j
].insert
[vptr
->size
- 1];
1384 vtx
->emit( ctx
, end
- start
,
1385 (GLubyte
*)vtx
->vertex_buf
+ start
* stride
);
1389 /* Emit VB vertices start..end to dest. Note that VB vertex at
1390 * postion start will be emitted to dest at position zero.
1392 void *_tnl_emit_vertices_to_buffer( GLcontext
*ctx
,
1397 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1398 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
1399 struct tnl_clipspace_attr
*a
= vtx
->attr
;
1400 const GLuint count
= vtx
->attr_count
;
1403 for (j
= 0; j
< count
; j
++) {
1404 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
1405 a
[j
].inputstride
= vptr
->stride
;
1406 a
[j
].inputptr
= ((GLubyte
*)vptr
->data
) + start
* vptr
->stride
;
1407 a
[j
].emit
= a
[j
].insert
[vptr
->size
- 1];
1410 /* Note: dest should not be adjusted for non-zero 'start' values:
1412 vtx
->emit( ctx
, end
- start
, dest
);
1414 return (void *)((GLubyte
*)dest
+ vtx
->vertex_size
* (end
- start
));
1418 void _tnl_init_vertices( GLcontext
*ctx
,
1420 GLuint max_vertex_size
)
1422 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1424 _tnl_install_attrs( ctx
, NULL
, 0, NULL
, 0 );
1426 vtx
->need_extras
= GL_TRUE
;
1427 if (max_vertex_size
> vtx
->max_vertex_size
) {
1428 _tnl_free_vertices( ctx
);
1429 vtx
->max_vertex_size
= max_vertex_size
;
1430 vtx
->vertex_buf
= (GLubyte
*)ALIGN_CALLOC(vb_size
* max_vertex_size
, 32 );
1431 vtx
->emit
= choose_emit_func
;
1434 _tnl_init_c_codegen( &vtx
->codegen
);
1438 void _tnl_free_vertices( GLcontext
*ctx
)
1440 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
1441 if (vtx
->vertex_buf
) {
1442 ALIGN_FREE(vtx
->vertex_buf
);
1443 vtx
->vertex_buf
= NULL
;
1446 _tnl_free_c_codegen( &vtx
->codegen
);