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