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