Added graphics vulkan demo.
[panamaz] / src / notzed.vulkan / gen / generate-vulkan
1 #!/usr/bin/perl
2
3 use Data::Dumper;
4
5 use File::Path qw(make_path);
6 use File::Basename;
7
8 use strict;
9
10 use Carp 'verbose';
11 use FindBin;
12 use lib "$FindBin::Bin", 'bin/linux-amd64/lib';
13
14 use vulkan;
15 use config;
16 use code;
17
18 $SIG{__DIE__} = sub { Carp::confess( @_ ) };
19 $SIG{'INT'} = sub { Carp::confess() };
20 $Data::Dumper::Indent = 1;
21
22 # ###################################################################### #
23
24 my $enumInfo = {
25         'uint32_t' => {
26                 type => 'int'
27         },
28                 'uint64_t' => {
29                         type => 'long',
30                         suffix => 'L'
31         },
32                 'float' => {
33                         type => 'float',
34                         suffix => 'f'
35         },
36         'const char *' => {
37                 type => 'String'
38         },
39 };
40
41 # ###################################################################### #
42 my $sys = {};
43
44 $sys->{output} = 'bin/gen/notzed.vulkan/classes';
45 $sys->{package} = 'vulkan';
46 $sys->{verbose} = 0;
47
48 my $vk = new vulkan($sys);
49
50 my $api = $vk->buildFeatures(
51         [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ],
52         [ 'xlib',
53           #'wayland',
54           'xcb' ]);
55
56 my $structTypes = loadTypes($api, 'struct-types.api');
57 my $commandTypes = loadTypes($api, 'command-types.api');
58
59 analyseTypes($vk, $api);
60
61 # for structs
62 my %defaultTemplate;
63
64 foreach my $s (values %{$api->{types}}) {
65         my $overrides = $structTypes->{overrides};
66         my $types = $structTypes->{types};
67
68         next if (defined($overrides->{$s->{name}}));
69
70         my %lengths;
71         map { $lengths{$_->{lengthfrom}}++ if $_->{lengthfrom} } @{$s->{items}};
72
73         foreach my $m (@{$s->{items}}) {
74                 my $nstar = $m->{deref} =~ tr/*/*/;
75
76                 # FIXME: this belongs in analyse
77                 if ($m->{lengthfrom} && $lengths{$m->{lengthfrom}} != 1) {
78                         $m->{'set-length'} = '';
79                 }
80
81                 if ($m->{lengthfor} && $nstar == 0 && $lengths{$m->{name}} == 1) {
82                         $overrides->{$s->{name}}->{$m->{name}}->{type} = $m->{deref}.'-implied';
83                 }
84                 if ($m->{deref} eq 'struct*-length') {
85                         $defaultTemplate{$m->{baseType}}->{array} = 1;
86                 } elsif ($m->{deref} eq 'struct[]') {
87                         $defaultTemplate{$m->{baseType}}->{array} = 1;
88                 }
89         }
90
91         if ($s->{returnedonly} eq 'true') {
92                 $defaultTemplate{$s->{name}}->{name} = 'struct-readonly';
93         }
94 }
95
96 # build default overrides for commands
97 foreach my $s (values %{$api->{commands}}) {
98         my $overrides = $commandTypes->{overrides};
99         my $types = $commandTypes->{types};
100
101         # check type updates anyway
102         foreach my $m (@{$s->{items}}) {
103                 if ($m->{deref} eq 'struct*-length') {
104                         $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
105                         $defaultTemplate{$m->{baseType}}->{array} = 1;
106                 } elsif ($m->{deref} eq 'struct*') {
107                         $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
108                 }
109         }
110
111         next if (defined($overrides->{$s->{name}}));
112
113         my $first = $s->{items}->[0];
114         my $last = $s->{items}->[$#{$s->{items}}];
115         my $result = $s->{proto};
116         my $index = $s->{index};
117
118         #map { $index->{$_->{name}} = $_ } @{$s->{items}};
119
120         my $override = {};
121
122         # force handles to be instance types
123         if ($first->{deref} eq 'handle') {
124                 $override->{$first->{name}}->{type} = 'instance';
125         }
126
127         # extension functions
128         if (defined($s->{extensions})) {
129                 $override->{template} = $commandTypes->{templates}->{'method-extension'};
130         }
131
132         if ($last->{deref} eq 'handle*') {
133                 if (!$last->{len}) {
134                         my $t = $api->{handles}->{$last->{baseType}};
135                         print "constructor: $s->{name}\n" if $sys->{verbose};
136                         $override->{$last->{name}}->{type} =
137                                 $t->{type} eq 'VK_DEFINE_HANDLE' && $t->{name} ne 'VkInstance' ?
138                                 'dispatch*-output' : 'handle*-output';
139                 } elsif ($index->{$last->{len}}) {
140                         print "constructor?: $s->{name}\n";# if $sys->{verbose};
141                         die;
142                 } else {
143                         print "allocate-constructor?: $s->{name} $last->{len}\n";# if $sys->{verbose};
144                 }
145         }
146
147         # ones we care about with output
148         #       handle*-length
149         #       struct*-length
150         #       uint32_t*-length
151         #       void*-length
152
153         if ($s->{successcodes} =~ m/VK_INCOMPLETE/ && $last->{deref} =~ m/-length$/) {
154                 my $protoa = "$result->{fullType} $s->{name}("
155                         .join(', ', map { "$_->{fullType}" } @{$s->{items}})
156                         .")";
157                 my $protob = "$result->{deref} $s->{name}("
158                         .join(', ', map { $_->{len} ? "$_->{deref} \[$_->{len}\]" : $_->{deref} } @{$s->{items}})
159                         .")";
160
161                 print "array-constructor: $protoa\n" if $sys->{verbose} > 1;
162                 print "array-constructor: $protob\n" if $sys->{verbose} > 1;
163
164                 $override->{template} =
165                         defined($s->{extensions}) ?
166                         $commandTypes->{templates}->{'method-extension-query'} :
167                         $commandTypes->{templates}->{'method-query'};
168                 foreach my $m (@{$s->{items}}) {
169                         if ($m->{deref} =~ m/-length$/ && (my $len = $index->{$m->{len}})) {
170                                 my $type;
171
172                                 if ($m->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE') {
173                                         $type = 'dispatch*-length-query';
174                                 } else {
175                                         $type = $m->{deref}.'-query';
176                                 }
177
178                                 die "no template $m->{deref}-query" if !defined($commandTypes->{types}->{$type});
179                                 $override->{$m->{name}}->{type} = $type;
180
181                                 die "no template $len->{deref}-querysize" if !defined($commandTypes->{types}->{$len->{deref}.'-querylen'});
182                                 $override->{$len->{name}}->{type} = $len->{deref}.'-querylen';
183                         }
184                 }
185         }
186
187         # other per-item things
188         foreach my $m (@{$s->{items}}) {
189                 my $so = $structTypes->{overrides}->{$m->{baseType}};
190
191                 if ($so->{ignore}) {
192                         $m->{deref} .= '-ignore';
193                 }
194
195                 # All the vkCmd commands shouldn't imply any array lengths, maybe nothing should really?
196                 if ($first->{baseType} ne 'VkCommandBuffer' && $m->{lengthfor}) {
197                         my $nstar = $m->{deref} =~ tr/*/*/;
198                         if ($nstar == 0) {
199                                 die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
200                                 $override->{$m->{name}}->{type} = $m->{deref}.'-length';
201                         } else {
202                                 if (defined($s->{extensions})) {
203                                         #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-extension'};
204                                         print "length-extension: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
205                                 } else {
206                                         #die "No '$m->{deref}-output' type ".Dumper($s) if !defined $types->{$m->{deref}.'-otuput'};
207
208                                         #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-query'};
209                                         #$overrides->{$s->{name}}->{$m->{name}}->{type} = $types->{$m->{deref}.'-output'};
210
211                                         print "length: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
212                                 }
213
214                         }
215                         # TODO: implied return things
216                 }
217         }
218
219         $overrides->{$s->{name}} = $override if %{$override};
220 }
221
222 {
223         my $overrides = $structTypes->{overrides};
224         my $templates = $structTypes->{templates};
225
226         foreach my $k (keys %defaultTemplate) {
227                 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
228                 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
229
230                 my $t = $defaultTemplate{$k};
231                 my $name = $t->{name} || "struct-writeonly";
232
233                 $name .= "-array" if $t->{array};
234
235                 print "$name: $k\n" if $sys->{verbose} > 1;
236                 die "No override $k $name" if !$templates->{$name};
237                 $overrides->{$k}->{template} = $templates->{$name};
238         }
239 }
240
241
242 #$overrides->{$s->{name}}->{template} = $structTypes->{templates}->{'struct-readonly'};
243
244 #print Dumper({ types=>$types, templates=>$templates });
245 #print Dumper($vk);
246
247 if (0) {
248         open(my $f, '>', 'types.pm');
249         print $f Dumper($commandTypes, $structTypes);
250         close $f;
251 }
252
253 if (0) {
254         open(my $f, '>', 'api.pm');
255         print $f Dumper($api);
256         close $f;
257         die;
258 }
259
260 if (0) {
261         open(my $f, '>', 'data.pm');
262         print $f Dumper({
263                 'handles' => $api->{handles},
264                         'types' => $api->{types},
265                         'commands' => $api->{commands},
266                         'funcpointers' => $api->{funcpointers},
267                                         });
268         close $f;
269 }
270
271 exportEnums($vk, $api, 'VkConstants');
272
273 # dump out the extension function tables
274 {
275         my $f = openOutput($sys, 'DispatchInstance');
276         my $template = $structTypes->{templates}->{dispatch};
277         my @init = ();
278         my @fieldInit = ();
279
280         foreach my $k (sort keys %{$api->{commands}}) {
281                 my $c = $api->{commands}->{$k};
282
283                 next if !defined($c->{extensions});
284
285                 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
286                 push @init, code::formatTemplate($template->{'init'}, $c);
287
288         }
289
290         my $vars = {
291                 package => 'vulkan',
292                 Name => 'DispatchInstance',
293                 init => join("\n\t\t", @init),
294                 'field-init' => join("\n\t", @fieldInit),
295         };
296         print $f code::formatTemplateStream($template->{class}, $vars);
297
298         closeOutput($sys, 'DispatchInstance', $f);
299 }
300
301 # structs and unions
302 foreach my $k (sort keys %{$api->{types}}) {
303         my $s = $api->{data}->{$k};
304
305         die if !defined $s;
306         next if $s->{alias};
307
308         my $override = $structTypes->{overrides}->{$s->{name}};
309
310         next if $override->{ignore};
311
312         my $f = openOutput($sys, $s->{Name});
313         print $f formatStruct($vk, $api, $s);
314         closeOutput($sys, $s->{Name}, $f);
315 }
316
317 # handles
318 foreach my $k (sort keys %{$api->{handles}}) {
319         my $s = $api->{data}->{$k};
320
321         die if !defined $s;
322         next if $s->{alias};
323
324         my $f = openOutput($sys, $s->{name});
325         print $f formatHandle($vk, $api, $s);
326         closeOutput($sys, $s->{name}, $f);
327 }
328
329 # upcalls
330 foreach my $k (sort keys %{$api->{funcpointers}}) {
331         my $s = $api->{data}->{$k};
332
333         die if !defined $s;
334         next if $s->{alias};
335
336         my $override = $commandTypes->{overrides}->{$s->{name}};
337
338         next if $override->{ignore};
339
340         my $f = openOutput($sys, $s->{name});
341         print $f formatFunctionPointer($vk, $api, $s);
342         closeOutput($sys, $s->{name}, $f);
343 }
344
345 exit 0;
346
347 # ###################################################################### #
348
349 sub loadTypes {
350         my $api = shift;
351         my $file = shift;
352         my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
353
354         my $types = {};
355         my $templates = {};
356         my $overrides = {};
357
358         foreach my $t (@{$config->{objects}}) {
359                 if ($t->{type} eq 'type') {
360                         my $nopts = $#{$t->{options}};
361                         my $type = {};
362
363                         die ("No prototype provided/found for empty type ".Dumper($t)) if ($#{$t->{items}} < 0 && $#{$t->{options}} < 0);
364
365                         # Check options / load inherited values
366                         foreach my $o (@{$t->{options}}) {
367                                 if ($o =~ m/^accessor=(.*)$/o) {
368                                         die "No template $1" if !defined($templates->{$1});
369                                         $type->{accessor} = $templates->{$1};
370                                 } elsif ($o eq 'need-frame') {
371                                         $type->{'need-frame'} = 1;
372                                 } elsif ($o eq 'need-scope') {
373                                         $type->{'need-scope'} = 1;
374                                 } elsif ($o eq 'trampoline-scope') {
375                                         $type->{'trampoline-scope'} = 1;
376                                 } elsif ($o eq 'need-alloc') {
377                                         $type->{'need-alloc'} = 1;
378                                 } elsif ($o eq 'is-instance') {
379                                         $type->{'is-instance'} = 1;
380                                 } elsif (defined($types->{$o})) {
381                                         $type = { %$type, %{$types->{$o}} };
382                                 } else {
383                                         die "Unknown option '$o' in ".Dumper($t);
384                                 }
385                         }
386
387                         # Load the fields
388                         foreach my $s (@{$t->{items}}) {
389                                 # FIXME: maybe i don't want  struct here, as with templates
390                                 my $x = {
391                                         code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
392                                 };
393
394                                 $x->{eval} = 1 if config::optionFlag('eval', $s);
395
396                                 $type->{$s->{match}} = $x;
397                         }
398
399                         # Write to all aliases
400                         foreach my $k (split /,/,$t->{name}) {
401                                 $types->{$k} = $type;
402                         }
403                 } elsif ($t->{type} eq 'code') {
404                         my $code = {
405                                 insert => {},
406                         };
407
408                         foreach my $o (@{$t->{options}}) {
409                                 if ($o =~ m/insert=(.*)/) {
410                                         foreach my $t (split /,/,$1) {
411                                                 if ($t =~ m/(.*):(.*)/) {
412                                                         die if !defined $templates->{$1}->{$2};
413                                                         $code->{insert}->{$2} = $templates->{$1}->{$2};
414                                                 }
415                                         }
416                                 } elsif ($o =~ m/^fields=(.*)/) {
417                                         $code->{fields} = $1;
418                                 } else {
419                                         die ("Unknown option $o");
420                                 }
421                         }
422
423                         foreach my $s (@{$t->{items}}) {
424                                 $code->{$s->{match}} = $s->{literal};
425                                 $code->{$s->{match}} =~ s/^\t//gm;
426
427                                 # hack since the template is a string
428                                 $code->{"$s->{match}:eval"}->{eval} = 1 if config::optionFlag('eval', $s);
429                         }
430
431                         $templates->{$t->{name}} = $code;
432                 } elsif ($t->{type} eq 'override') {
433                         foreach my $s (@{$t->{items}}) {
434                                 my $c = { };
435                                 foreach my $o (@{$s->{options}}) {
436                                         if ($o =~ m/^(.*)=type:(.*)/) {
437                                                 die "No such type $s->{match} $2\n" if !defined $types->{$2};
438                                                 $c->{$1}->{type} = $2;
439                                         } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
440                                                 die "No accessor template $o" if !defined($templates->{$2});
441                                                 $c->{$1}->{accessor} = $templates->{$2};
442                                         } elsif ($o =~ m/^template=(.*)/) {
443                                                 die "No template $o" if !defined($templates->{$1});
444                                                 $c->{template} = $templates->{$1};
445                                         } elsif ($o eq 'ignore') {
446                                                 $c->{ignore} = 1;
447                                         }
448                                 }
449                                 $overrides->{$s->{match}} = $c;
450                         }
451                 }
452         }
453
454         # templates should probably just go in one
455         {
456                 types => $types,
457                 templates => $templates,
458                 overrides => $overrides,
459         };
460 }
461
462 sub uniq {
463   my %seen;
464   return grep { !$seen{$_}++ } @_;
465 }
466
467 sub exportEnums {
468         my $vk = shift;
469         my $api = shift;
470         my $name = shift;
471         my $seen = {};
472
473         my $f = openOutput($sys, $name);
474
475         print $f "package vulkan;\npublic interface VkConstants {\n";
476
477         # special case for api constants
478         # special case for api constants
479         {
480                 my $s = $api->{data}->{'API Constants'};
481
482                 print $f "\n\t// API Constants\n";
483
484                 foreach my $m (@{$s->{items}}) {
485                         next if defined($m->{alias});
486                         next if $seen->{$m->{name}}++;
487
488                         my $i = $enumInfo->{$m->{type}};
489                         my $v = $m->{value};
490
491                         # convert to java
492                         $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
493
494                         print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
495                 }
496         }
497
498         foreach my $k (sort keys %{$api->{enums}}) {
499                 my $s = $api->{data}->{$k};
500                 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
501                 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
502
503                 next if $s->{alias};
504
505                 print $f "\n\t// $s->{name} $type\n";
506
507                 foreach my $m (@{$s->{items}}) {
508                         next if defined($m->{alias});
509                         next if $seen->{$m->{name}}++;
510
511                         my $v = $m->{value};
512
513                         $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
514
515                         die Dumper("Ca't work out value", $m, $s) if !defined($v);
516                         print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
517                 }
518         }
519         print $f "}\n";
520
521         closeOutput($sys, $name, $f);
522 }
523
524 # ###################################################################### #
525 # class.name to class/name.java
526 sub classToPath {
527         my $sys = shift;
528         my $name = shift;
529
530         $name = $sys->{package}.'.'.$name;
531         $name =~ s@\.@/@g;
532         $name = $sys->{output}.'/'.$name.'.java';
533         $name;
534 }
535
536 sub closeOutput {
537         my $sys = shift;
538         my $name = shift;
539         my $f = shift;
540         my $path = classToPath($sys, $name);
541
542         close($f) || die;
543         rename($path.'~', $path) || die ("rename failed: $!");
544 }
545
546 sub openOutput {
547         my $sys = shift;
548         my $name = shift;
549
550         my $path = classToPath($sys, $name);
551         my $dir = dirname($path);
552
553         make_path($dir) if (!-d $dir);
554
555         open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
556         print "writing '$path'\n" if $sys->{verbose} > 0;
557         $f;
558 }
559
560
561 # Calculate canonical derefernce types for each field and parameter
562 sub analyseFields {
563         my $vk = shift;
564         my $api = shift;
565         my $seen = shift;
566         my $s = shift;
567
568         # what about const?
569         # FIXME: bitfields
570
571         my $index = {};
572
573         map { $index->{$_->{name}} = $_ } @_;
574
575         $s->{index} = $index;
576
577         foreach my $m (@_) {
578                 my $t = $api->{data}->{$m->{baseType}};
579                 my $nstar = $m->{fullType} =~ tr/*/*/;
580                 my $type;
581                 my $array = '';
582
583                 # Check array sizes
584                 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
585                         $array = '[][]';
586                         $m->{len1} = $1;
587                         $m->{len2} = $2;
588                 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
589                         my $isize = $1;
590                         my $size;
591                         if ($isize =~ m/^\d+$/n) {
592                                 $size = $isize;
593                         } else {
594                                 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
595                         }
596                         $array = '[]';
597                         $m->{len1} = $size;
598                 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
599                         die Dumper($m)
600                 }
601
602                 if (!defined($t)) {
603                         # will be primitive or external
604                         $type = $m->{baseType} if ($nstar == 0);
605                         $type = "$m->{baseType}*" if ($nstar == 1);
606                         $type = "$m->{baseType}**" if ($nstar == 2);
607                         die if $nstar > 2;
608                 } else {
609                         # unmap aliases
610                         while ($t->{alias}) {
611                                 print "alias $t->{name} -> $t->{alias}\n";
612                                 $t = $api->{data}->{$t->{alias}};
613                                 die if !defined $t;
614                                 $m->{baseType} = $t->{name};
615                         }
616
617                         if ($t->{category} =~ m/enum|bitmask/on) {
618                                 $t = $vk->{data}->{$t->{fullType}};
619                                 $type = $t->{type} if ($nstar == 0);
620                                 $type = "$t->{type}*" if ($nstar == 1);
621                                 die if $nstar > 1;
622                         } elsif ($t->{category} =~ m/struct|union/on) {
623                                 $m->{type} = $t->{name};
624                                 $type = 'struct' if ($nstar == 0);
625                                 $type = 'struct*' if ($nstar == 1);
626                                 $type = 'struct**' if ($nstar == 2);
627                                 die if $nstar > 2;
628                         } elsif ($t->{category} eq 'handle') {
629                                 $m->{type} = $t->{name};
630                                 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
631                                 #       $type = 'dhandle' if ($nstar == 0);
632                                 #       $type = 'dhandle*' if ($nstar == 1);
633                                 #} else {
634                                         $type = 'handle' if ($nstar == 0);
635                                         $type = 'handle*' if ($nstar == 1);
636                                 #}
637                                 die if $nstar > 1;
638                         } elsif ($t->{category} eq 'basetype') {
639                                 # ??
640                                 $type = $t->{type} if ($nstar == 0);
641                                 $type = "$t->{type}*" if ($nstar == 1);
642                                 die Dumper($m, $t) if $nstar > 1;
643                         } elsif ($t->{category} eq 'funcpointer') {
644                                 $m->{type} = $t->{name};
645                                 $type = "funcpointer" if ($nstar == 0);
646                                 die if $nstar > 0;
647                         } else {
648                                 die Dumper($m, $t);
649                         }
650                 }
651
652                 # an array type with a length
653                 if ($nstar > 0 && $m->{len}) {
654                         if ($s->{category} =~ m/struct|union/on) {
655                                 if ($m->{altlen}) {
656                                         if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
657                                                 $m->{length} = $1.'VkConstants.'.$2.$3;
658                                         } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
659                                                 my $len = $index->{$2};
660                                                 if (defined $len) {
661                                                         $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
662                                                         #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
663                                                         $m->{lengthfrom} = $len->{name};
664                                                 }
665                                         } else {
666                                                 die "Unhandled len/altlen: ".Dumper($m);
667                                         }
668                                 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
669                                         my $len = $index->{$1};
670                                         if (defined $len) {
671                                                 $m->{length} = "get$len->{Name}()";
672                                                 $m->{lengthfrom} = $len->{name};
673                                                 $len->{lengthfor} = $m->{name};
674                                                 $m->{'set-length'} = "set$len->{Name}((int)Memory.length($m->{name}))";
675                                         }
676                                 } elsif ($m->{len} eq 'null-terminated') {
677                                         # ignore
678                                 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
679                                         # ignore?
680                                 } else {
681                                         my $len = $index->{$m->{len}};
682                                         if (defined $len) {
683                                                 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
684
685                                                 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
686                                                 $m->{length} = "get$len->{Name}()";
687                                                 $m->{lengthfrom} = $len->{name};
688                                                 $len->{lengthfor} = $m->{name};
689                                                 $m->{'set-length'} = "set$len->{Name}($cast"."Memory.length($m->{name}))";
690                                         } else {
691                                                 die "what?".Dumper($m);
692                                         }
693                                 }
694                         } elsif ($s->{category} eq 'command') {
695                                 if ($m->{altlen}) {
696                                         die;
697                                 } else {
698                                         $m->{length} = $m->{len} if $index->{$m->{len}};
699                                         $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
700                                 }
701                         } else {
702                                 die Dumper($s);
703                         }
704                         $type = $type.'-length' if $m->{length};
705                 }
706
707                 $seen->{$m->{fullType}} = $type.$array;
708                 $m->{deref} = $type.$array;
709
710                 # Calculate name, with some fixup hacks
711                 my $name = $m->{name};
712                 #if ($s->{type} =~ m/struct|union/on)
713                 {
714                         # Strip leading 'p' for pointers
715                         if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
716                                 $name = 'PGeometries';
717                         } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
718                                 my $strip = $nstar;
719
720                                 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
721                                         $strip -= 1;
722                                 }
723
724                                 $name = substr $name, $strip;
725                         }
726
727                         $name =~ s/^pfn//o if $type eq 'funcpointer';
728                         # CamelCase
729                         $name =~ s/(?:^|_)(.)/\U$1/og;
730                 }
731                 $m->{Name} = $name;
732         }
733 }
734
735 sub analyseTypes {
736         my $vk = shift;
737         my $api = shift;
738         my $seen = {};
739
740         foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
741                 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
742
743                 my $name = $s->{name};
744                 $name =~ s/(?:^|_)(.)/\U$1/og;
745                 $s->{Name} = $name;
746
747                 my $first = $s->{items}->[0];
748                 my $second = $s->{items}->[1];
749
750                 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
751                         $first->{'no-setall'} = 1;
752                         $second->{'no-setall'} = 1;
753                         print "typed: $s->{name}\n" if $sys->{verbose} > 1;
754                 } else {
755                         print "untyped: $s->{name}\n" if $sys->{verbose} > 1;
756                 }
757         }
758
759         foreach my $c (values %{$api->{funcpointers}}) {
760                 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
761         }
762
763         foreach my $c (values %{$api->{commands}}) {
764                 $c->{proto}->{name} = 'result$';
765                 $c->{proto}->{Name} = 'result$';
766                 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
767
768                 # collect all member functions on handles
769                 my $first = $c->{items}->[0];
770                 my $last = $c->{items}->[$#{$c->{items}}];
771                 if ($first->{deref} eq 'handle') {
772                         my $t = $api->{handles}->{$first->{baseType}};
773                         while ($t->{alias}) {
774                                 $t = $api->{handles}->{$t->{alias}};
775                         }
776                         die "No handle found ".Dumper($c) if !defined $t;
777                         push @{$t->{commands}}, $c->{name};
778                 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
779                         push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
780                 } else {
781                         die "No owner for call ".Dumper($c);
782                 }
783         }
784
785         print "Unique Types:\n";
786         my $base = {};
787         map { $base->{$_} = 1 } values %$seen;
788
789         foreach my $k (sort keys %$base) {
790                 print "$k\n";
791         }
792 }
793
794 # what else?
795 # vk? api?
796 # this way-over-evaluates, probably only call once on every field and member instead
797 sub buildVars {
798         my $s = shift;
799         my $m = shift;
800         my $type = shift;
801         my $v = { %{$m} };
802
803         foreach my $k (keys %$type) {
804                 my $t = $type->{$k};
805
806                 if (ref($t) eq '') {
807                         $v->{$k} = $t;
808                 } elsif ($t->{eval}) {
809                         $v->{$k} = eval $t->{code};
810
811                         die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
812                 } elsif (defined($t->{code})) {
813                         $v->{$k} = $t->{code};
814                 }
815         }
816
817         $v;
818 }
819
820 sub formatStructLayout {
821         my $types = shift;
822         my $s = shift;
823         my $offset = 0;
824         my @fields = ();
825
826         # This doens't need to worry about overrides
827
828         if ($s->{category} eq 'struct') {
829                 foreach my $m (@{$s->{items}}) {
830                         my $type = $types->{$m->{deref}};
831                         my $diff = $m->{bitOffset} - $offset;
832
833                         push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
834
835                         if ($type) {
836                                 my $v = buildVars($s, $m, $type);
837
838                                 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
839                                 $offset = $m->{bitOffset} + $m->{bitSize};
840                         } else {
841                                 push @fields, "/* Missing: $m->{deref} $m->{name} */";
842                         }
843                 }
844         } else {
845                 foreach my $m (@{$s->{items}}) {
846                         my $type = $types->{$m->{deref}};
847
848                         if ($type) {
849                                 my $v = buildVars($s, $m, $type);
850
851                                 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
852                                 $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
853                         } else {
854                                 push @fields, "/* Missing: $m->{deref} $m->{name} */";
855                         }
856                 }
857         }
858
859         my $diff = $s->{bitSize} - $offset;
860
861         push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
862
863         return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
864 }
865
866 sub formatAccessorIf {
867         my $s = shift;
868         my $m = shift;
869         my $info = shift;
870         my $type = shift;
871         my $field = shift;
872         my $v = shift;
873         my $accessor = $type->{accessor};
874         my $template = $accessor->{$field};
875
876         if ($template) {
877                 $template = eval($template) if ($accessor->{"$field:eval"});
878
879                 die "Error executing template $field $accessor->{$field}: $@" if (!defined($template));
880
881                 push @{$info->{$field}}, code::formatTemplate($template, $v) if $template;
882         }
883 }
884
885 sub formatStruct {
886         my $vk = shift;
887         my $api = shift;
888         my $s = shift;
889         my $templates = $structTypes->{templates};
890         my $types = $structTypes->{types};
891         my $overrides = $structTypes->{overrides};
892
893         my $override = $overrides->{$s->{name}};
894         my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
895         my @fields = split(/,/, $template->{fields});
896         my $info;
897
898         map { $info->{$_} = [] } @fields;
899
900         my $setall = defined $info->{'java-setall'};
901
902         if ($setall) {
903                 if ($s->{category} eq 'struct') {
904                         $info->{create}->{create} = {
905                                 'setall-arg' => [ 'SegmentAllocator alloc$' ],
906                                 setall => [],
907                         };
908                 } elsif ($s->{category} eq 'union') {
909                         foreach my $m (@{$s->{items}}) {
910                                 $info->{create}->{"create$m->{Name}"} = {
911                                         'setall-arg' => [ 'SegmentAllocator alloc$' ],
912                                         setall => [],
913                                 };
914                         }
915                 } else {
916                         die;
917                 }
918         }
919
920         #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
921
922         # FIXME: unions need multiple constructors!
923
924         foreach my $m (@{$s->{items}}) {
925                 my $nstar = $m->{deref} =~ tr/*/*/;
926                 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
927                 my $type = $types->{$deref};
928
929                 die "No type $deref ".Dumper($m, $s) if !$type;
930
931                 if ($type->{accessor}) {
932                         my $v = buildVars($s, $m, $type);
933                         my @todump;
934
935                         if ($m->{values}) {
936                                 @todump = qw(init initat set setat);
937                         } else {
938                                 @todump = qw(get getat set setat getorset getorsetat);
939
940                                 # FIXME: something here is adding length parameters which are already handled by the setXX() calls
941                                 if ($setall && !$m->{'no-setall'}) {
942                                         my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
943                                         #push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
944                                         #push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
945                                         formatAccessorIf($s, $m, $create, $type, 'setall-arg', $v);
946                                         formatAccessorIf($s, $m, $create, $type, 'setall', $v);
947                                 }
948                         }
949
950                         push @{$info->{handle}}, code::formatTemplate($v->{handle}, $v)." /* $m->{name} $m->{fullType} ($m->{deref}) */" if $info->{handle} && $v->{handle};
951                         push @{$info->{handleat}}, code::formatTemplate($v->{handleat}, $v) if $info->{handleat} && $v->{handleat};
952
953                         foreach my $field (@todump) {
954                                 push @{$info->{$field}}, code::formatTemplate($type->{accessor}->{$field}, $v) if $info->{$field} && $type->{accessor}->{$field};
955                         }
956                 }
957         }
958
959         # create constructors
960         my $v = {
961                 package => 'vulkan',
962                 name => $s->{name},
963                 Name => $s->{Name},
964                 layout => formatStructLayout($types, $s),
965                 #init => join ("\n", @{$info->{init}}),
966                 #get => join ("\n", @{$info->{get}}),
967                 #set => join ("\n", @{$info->{set}}),
968                 #getorset => join ("\n", @{$info->{getorset}}),
969                 ##'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
970                 ##'java-setall' => join ("\n", @{$info->{setall}}),
971                 #varhandle => join ("\n", @{$info->{varhandle}}),
972         };
973
974         foreach my $field (@fields) {
975                 $v->{$field} = join("\n", @{$info->{$field}});
976         }
977
978         # build sub-components using the full $v
979         my @createAll = ();
980         foreach my $k (keys %{$template->{insert}}) {
981                 my $t = $template->{insert}->{$k};
982
983                 if ($k eq 'create-all') {
984                         if ($setall) {
985                                 foreach my $kk (keys %{$info->{create}}) {
986                                         my $create = $info->{create}->{$kk};
987
988                                         if ($#{$create->{'setall-arg'}} > 0) {
989                                                 my $v = {
990                                                         create => $kk,
991                                                         Name => $s->{Name},
992                                                         'java-setall-arguments' => join (', ', @{$create->{'setall-arg'}}),
993                                                         'java-setall' => join ("\n\t\t", @{$create->{setall}}),
994                                                 };
995                                                 push @createAll, code::formatTemplateStream($t, $v);
996                                         }
997                                 }
998                         }
999                 } else {
1000                         $v->{$k} = code::formatTemplate($t, $v);
1001                 }
1002         }
1003         $v->{'create-all'} = join("\n", @createAll) if $setall;
1004
1005         #die Dumper($info) if $s->{name} eq 'VkMemoryOpaqueCaptureAddressAllocateInfo';
1006
1007         join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1008                 code::formatTemplateStream($template->{class}, $v);
1009 }
1010
1011 # TODO: the template here could be mapped from types.api perhaps?
1012 # also same for the various fields, init/getset/etc.
1013 sub formatHandle {
1014         my $vk = shift;
1015         my $api = shift;
1016         my $s = shift;
1017         my $templates = $structTypes->{templates};
1018         my $overrides = $structTypes->{overrides};
1019         my $override = $overrides->{$s->{name}};
1020         my $template = $override->{template} ? $override->{template} : $templates->{handle};
1021
1022         my $info = {
1023                 init => [],
1024                 commands => [],
1025         };
1026
1027         if (defined $s->{commands}) {
1028                 foreach my $k (sort @{$s->{commands}}) {
1029                         my $c = $api->{commands}->{$k};
1030                         push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
1031                 }
1032         }
1033
1034         my $v = {
1035                 package => 'vulkan',
1036                 name => $s->{name},
1037                 Name => $s->{Name},
1038                 init => join ("\n", @{$info->{init}}),
1039                 commands => join ("\n", @{$info->{commands}}),
1040         };
1041
1042         code::formatTemplateStream($template->{class}, $v);
1043 }
1044
1045 sub formatSignature {
1046         my $s = shift;
1047         my $types = $commandTypes->{types};
1048         my $d = '(';
1049
1050         foreach my $m (@{$s->{items}}) {
1051                 my $x = $types->{$m->{deref}};
1052
1053                 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1054
1055                 $d .= $x->{sig}->{code};
1056         }
1057         $d .= ')';
1058
1059         my $m = $s->{proto};
1060         my $x = $types->{$m->{deref}};
1061         die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1062         $d .= $x->{sig}->{code};
1063 }
1064
1065 # TODO: only collect shit we need
1066 sub collectFunctionInfo {
1067         my $api = shift;
1068         my $ct = shift;
1069         my $s = shift;
1070         my $templates = $ct->{templates};
1071         my $types = $ct->{types};
1072         my $overrides = $ct->{overrides};
1073         my $void = $s->{proto}->{fullType} eq 'void';
1074         my $override = $overrides->{$s->{name}};
1075
1076         my @javaArgs = ();
1077         my @invokeArgs = ();
1078         my @nativeInit = ();
1079         my @queryInit = ();
1080         my @queryArgs = ();
1081
1082         my @nativeArgs = ();
1083         my @trampArgs = ();
1084
1085         my $info = {
1086                 rename => $s->{name},
1087                 name => $s->{name},
1088                 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1089                 'native-result-define' => '',
1090                 'native-result-assign' => '',
1091                 'native-result' => 'void',
1092                 'trampoline-result-define' => '',
1093                 'trampoline-result-assign' => '',
1094                 'trampoline-scope' => '',
1095                 'result-test' => '',
1096                 'create-frame' => '',
1097                 'java-result' => 'void',
1098                 'java-result-assign' => '',
1099                 'result-throw' => '',
1100
1101                 'java-result-return' => 'return;',
1102                 'trampoline-result-return' => 'return;',
1103         };
1104
1105         my $hasInstance = 0;
1106         my $needFrame = 0;
1107         my $needAlloc = 0;
1108         my $needScope = 0;
1109         my $trampScope = 0;
1110
1111         #return if !defined($override->{template});
1112         #return if ($s->{name} ne 'vkCmdUpdateBuffer');
1113
1114         my @arrayFields = qw(java-arg invoke-arg native-init query-init query-arg native-arg trampoline-arg);
1115         my @fixedFields = qw(java-result java-result-return java-result-assign);
1116
1117         map { $info->{$_} = [] } @arrayFields;
1118
1119         foreach my $m (@{$s->{items}}) {
1120                 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1121                 my $type = $types->{$deref};
1122
1123                 die "No type found ".Dumper($m, $s, $override) if !$type;
1124
1125                 my $v = buildVars($s, $m, $type);
1126
1127                 foreach my $field (@arrayFields) {
1128                         if ($v->{$field}) {
1129                                 push @{$info->{$field}}, code::formatTemplate($v->{$field}, $v);
1130                         } elsif ($field eq 'query-arg') {
1131                                 push @{$info->{$field}}, code::formatTemplate($v->{'invoke-arg'}, $v);
1132                         }
1133                 }
1134
1135                 foreach my $field (@fixedFields) {
1136                         $info->{$field} = code::formatTemplate($v->{$field}, $v) if ($v->{$field});
1137                 }
1138
1139                 if (0) {
1140                         push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
1141                         push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
1142
1143                         push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
1144                         push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
1145
1146                         if ($v->{'query-arg'}) {
1147                                 push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
1148                         } elsif ($v->{'invoke-arg'}) {
1149                                 push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
1150                         }
1151
1152                         push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
1153                         push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
1154
1155                         $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
1156                         $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
1157                         $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
1158                 }
1159
1160                 $needScope = 1 if $type->{'need-scope'};
1161                 $needFrame = 1 if $type->{'need-frame'};
1162                 $needAlloc = 1 if $type->{'need-alloc'};
1163                 $hasInstance = 1 if $type->{'is-instance'};
1164                 $trampScope = 1 if $type->{'trampoline-scope'};
1165         }
1166
1167         $info->{'static'} = $hasInstance ? '' : 'static ';
1168
1169         if ($s->{successcodes}) {
1170                 my @codes = split(/,/,$s->{successcodes});
1171
1172                 $info->{'native-result-define'} = 'int result$;';
1173                 $info->{'native-result-assign'} = 'result$ = (int)';
1174                 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1175                 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1176
1177                 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1178                         $info->{'java-result'} = 'int';
1179                         $info->{'java-result-return'} = 'return result$;';
1180                 }
1181
1182         } elsif ($s->{proto}->{fullType} ne 'void') {
1183                 my $m = $s->{proto};
1184                 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1185
1186                 die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
1187                 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1188
1189                 my $v = buildVars($s, $m, $type);
1190
1191                 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1192                 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1193                 #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1194                 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1195                 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
1196
1197                 $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
1198                 $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
1199                 $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
1200                 $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
1201
1202                 $needScope = 1 if $type->{'need-scope'};
1203         }
1204
1205         $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
1206         $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
1207
1208         push @{$info->{'java-arg'}}, 'SegmentAllocator alloc$' if $needAlloc;
1209         push @{$info->{'java-arg'}}, 'ResourceScope scope$' if $needScope;
1210
1211         foreach my $field (@arrayFields) {
1212                 my $with = $field =~ m/-arg$/n ? ",\n\t" : "\n\t";
1213                 $info->{$field} = join $with, @{$info->{$field}};
1214         }
1215
1216         if (0) {
1217                 $info->{'java-arguments'} = join ",\n\t", @javaArgs;
1218                 $info->{'native-init'} = join "\n\t", @nativeInit;
1219                 $info->{'invoke-arguments'} = join ", ", @invokeArgs;
1220                 $info->{'query-init'} = join "\n\t\t\t", @queryInit;
1221                 $info->{'query-arguments'} = join ", ", @queryArgs;
1222
1223                 $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
1224                 $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
1225         }
1226
1227         $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1228         $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1229
1230         if ($s->{category} eq 'funcpointer') {
1231                 $info->{'trampoline-signature'} = formatSignature($s);
1232         }
1233
1234         $info;
1235 }
1236
1237 sub formatFunctionPointer {
1238         my $vk = shift;
1239         my $api = shift;
1240         my $s = shift;
1241         my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
1242         my $info = collectFunctionInfo($api, $commandTypes, $s);
1243
1244         my $v = {
1245                 package => 'vulkan',
1246                 name => $s->{name},
1247                 Name => $s->{Name},
1248         };
1249
1250         foreach my $k (keys %{$template->{insert}}) {
1251                 my $t = $template->{insert}->{$k};
1252
1253                 $v->{$k} = code::formatTemplate($t, $info);
1254         }
1255
1256         code::formatTemplateStream($template->{class}, $v);
1257 }
1258
1259 sub formatFunctionDescriptor {
1260         my $ct = shift;
1261         my $s = shift;
1262
1263         my $templates = $ct->{templates};
1264         my $types = $ct->{types};
1265         my $overrides = $ct->{overrides};
1266
1267         my @fields = ();
1268         my $void = $s->{proto}->{fullType} eq 'void';
1269         my $override = $overrides->{$s->{name}};
1270
1271         foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1272                 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1273                 my $type = $types->{$deref};
1274
1275                 die "No type found ".Dumper($m, $s, $override) if !$type;
1276
1277                 my $v = buildVars($s, $m, $type);
1278
1279                 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1280         }
1281
1282         return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1283                 .join(",\n\t\t", @fields).')';
1284 }
1285
1286 sub formatFunction {
1287         my $api = shift;
1288         my $ct = shift;
1289         my $s = shift;
1290         my $templates = $ct->{templates};
1291         my $types = $ct->{types};
1292         my $overrides = $ct->{overrides};
1293         my $void = $s->{proto}->{fullType} eq 'void';
1294         my $override = $overrides->{$s->{name}};
1295         my $template = $override->{template} ? $override->{template} : $templates->{method};
1296
1297         my $info = collectFunctionInfo($api, $ct, $s);
1298
1299         #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1300         code::formatTemplate($template->{invoke}, $info);
1301 }