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