Remove some internal dumps.
[panamaz] / test-vulkan / generate-vulkan
1 #!/usr/bin/perl
2
3 # -*- Mode:perl; perl-indent-level:4;tab-width:4; -*-
4
5 # TODO: upcalls are just done manually, see template/PFN*
6 # TODO: check the extension function pointer setup/splitting is correct
7 # TODO: things that take a Memory.*Array probably don't need to also take a count, if one is defined in the registry
8 # TODO: the api constants, where to?
9 # TODO: vkDestroyDevice and vkDestroyInstance should close the ResourceScope they have
10
11 use Data::Dumper;
12 use File::Path qw(make_path);
13
14 require XML::Parser;
15
16 # these can't really be changed yet
17 $targetDirectory = "api";
18 $targetPackage = "zvk";
19
20 while (@ARGV) {
21         my $cmd = shift(@ARGV);
22
23         if ($cmd eq "-t") {
24                 $targetPackage = shift(@ARGV);
25     } elsif ($cmd eq "-d") {
26                 $targetDirectory = shift(@ARGV);
27     } elsif ($cmd eq "-v") {
28                 $verbose++;
29         }
30 }
31
32 $xml = XML::Parser->new(Style => 'Objects');
33 $doc = $xml->parsefile('/usr/share/vulkan/registry/vk.xml');
34
35 $registry = @{$doc}[0];
36
37 %toDrop = (
38     VkBaseInStructure => 1,
39     VkBaseOutStructure => 1,
40     vkEnumeratePhysicalDeviceGroups => 1,
41     vkEnumeratePhysicalDevices => 1,
42     VkPhysicalDeviceGroupProperties => 1,
43     vkAllocateCommandBuffers => 1,
44     vkMapMemory => 1,
45     );
46
47 my %accessMode = (
48     'VkDebugUtilsMessengerCallbackDataEXT' => 3, # actually read-only?
49     'VkClearColorValue' => 3,
50     'VkCommandBufferAllocateInfo' => 3
51     );
52
53
54 # unused but this documents all INSTANCE creation functions
55 %dynamicInit = (
56     vkCreateInstance => 1,
57     vkEnumeratePhysicalDevices => VkInstance,
58     vkCreateDevice => VkPhysicalDevice,
59     vkAllocateCommandBuffers => VkDevice,
60     vkGetDeviceQueue => VkDevice,
61     vkGetDeviceQueue2 => VkDevice,
62
63     VkInstance => 'instance',
64     VkPhysicalDevice => 'instance,device',# dunno how that works
65     VkCommandBuffer => 'instance,device', # instance is only debugutils
66     VkDevice => 'instance,device',        # instance is only debugutils
67     VkQueue => 'instance,device'          # instance is only debugutils
68
69     );
70
71 %typeToJavaPrimitive = (
72     uint8_t => 'byte', char => 'byte',
73     uint16_t => 'short',
74     int32_t => 'int', uint32_t => 'int', int => 'int',
75     int64_t => 'long', uint64_t => 'long', size_t => 'long',
76     float => 'float',
77     double => 'double'
78     );
79
80 # must only include java primitives
81 %typeSizePrimitive = (
82     "byte" => 8,
83     "short" => 16,
84     "int" => 32,
85     "long" => 64,
86     "float" => 32,
87     "double" => 64
88     );
89
90 # pre-load types from external header files
91 %data = (
92     'VisualID' => { category => 'basetype', name => 'VisualID', type => 'uint64_t' },
93     'Window' => { category => 'basetype', name => 'Window', type => 'uint64_t' },
94     'xcb_visualid_t' => { category => 'basetype', name => 'xcb_visualid_t', type => 'uint32_t' },
95     'xcb_window_t' => { category => 'basetype', name => 'xcb_window_t', type => 'uint32_t' },
96     'HANDLE' => { category => 'basetype', name => 'HANDLE', type => 'VK_DEFINE_NON_DISPATCHABLE_HANDLE' },
97     'RROutput' => { category => 'basetype', name => 'RROutput', type => 'uint32_t' },
98     'zx_handle_t' => { category => 'basetype', name => 'zx_handle_t', type => 'uint64_t' },
99     );
100 # from API Constants section
101 %apiConstants = ();
102 %alias = ();
103 %commands = ();
104 @commandsList = ();
105 @features = ();
106 @extensions = ();
107 @bitmaskTypes = ();
108
109 %commandsExported = ();
110
111 # get something of the form
112 # <node>... <type> xxx</type> ... <name>xxx</name></node>
113 sub scanMember {
114     my $n = shift @_;
115     my $baseType = "";
116     my $fullType = "";
117     my $name = "";
118
119     # enum is for array sizes
120     foreach $p (@{$n->{Kids}}) {
121                 if ($p->isa('Characters')) {
122                         $fullType .= $p->{Text};
123                 } elsif ($p->isa('type')) {
124                         $baseType = @{$p->{Kids}}[0]->{Text};
125                         $fullType .= $baseType;
126                 } elsif ($p->isa('name')) {
127                         $name = @{$p->{Kids}}[0]->{Text};
128                 } elsif ($p->isa('enum')) {
129                         $fullType .= @{$p->{Kids}}[0]->{Text};
130                 }
131     }
132
133     $fullType =~ s/^\s+|\s+$//g;
134
135     my %member = (
136                 name => $name,
137                 baseType => $baseType,
138                 fullType => $fullType
139                 );
140
141     $member{len} = $n->{len} if (defined $n->{len});
142     $member{altlen} = $n->{altlen} if (defined $n->{altlen});
143     $member{optional} = $n->{optional} if (defined $n->{optional});
144     $member{values} = $n->{values} if (defined $n->{values});
145
146     return \%member;
147 }
148
149 sub addRequire {
150     my $list = shift @_;
151     my $z = shift @_;
152     my $sourceName = shift @_;
153     my $source = shift @_;
154     my %req = (
155                 name => $z->{name},
156                 $sourceName => $source
157                 );
158
159     $req{comment} = $z->{comment} if (defined($z->{comment}));
160
161     if ($z->isa('type')) {
162                 $req{category} = 'type';
163                 push @$list, \%req;
164     } elsif ($z->isa('command')) {
165                 $req{category} = 'command';
166                 push @$list, \%req;
167     } elsif ($z->isa('enum')) {
168                 $req{category} = "enum";
169                 $req{alias} = $z->{alias} if (defined($z->{alias}));
170                 $req{bitpos} = $z->{bitpos} if (defined($z->{bitpos}));
171                 $req{dir} = $z->{dir} if (defined($z->{dir}));
172                 $req{extends} = $z->{extends} if (defined($z->{extends}));
173                 $req{extnumber} = $z->{extnumber} if (defined($z->{extnumber}));
174                 $req{offset} = $z->{offset} if (defined($z->{offset}));
175                 $req{value} = $z->{value} if (defined($z->{value}));
176                 push @$list, \%req;
177     }
178 }
179
180 foreach $x (grep  { $_->isa('types') } @{$registry->{Kids}}) {
181     foreach $t (grep { $_->isa('type') } @{$x->{Kids}}) {
182                 if (!defined($t->{alias})) {
183                         my $category = $t->{category};
184
185                         if ($category eq 'struct' || $category eq 'union') {
186                                 my @members = ();
187
188                                 foreach $m (grep { $_->isa('member') } @{$t->{Kids}}) {
189                                         push @members,scanMember($m);
190                                 }
191
192                                 my %struct = (
193                                         category => $category,
194                                         name => $t->{name},
195                                         members => \@members,
196                                         bitAlignment => 64
197                                         );
198
199                                 $data{$struct{name}} = \%struct;
200                         } elsif ($category eq "handle") {
201                                 my $info = scanMember($t);
202                                 my %struct = (
203                                         category => $category,
204                                         name => $info->{name},
205                                         parent => $t->{parent},
206                                         objtypeenum => $t->{objtypeenum},
207                                         type => $info->{baseType},
208
209                                         bitSize => 64,
210                                         bitAlignment => 64
211                                         );
212
213                                 $data{$struct{name}} = \%struct;
214                         } elsif ($category eq "bitmask") {
215                                 # these map enums to the basic types but we can't use it yet, save for later
216                                 my %struct = ();
217                                 my $info = scanMember($t);
218
219                                 $struct{category} = "enum:bitmask";
220                                 $struct{name} = $info->{name};
221                                 $struct{type} = $info->{baseType};
222                                 # fuck knows what the difference is
223                                 $struct{requires} = $t->{requires} if (defined $t->{requires});
224                                 $struct{bitvalues} = $t->{bitvalues} if (defined $t->{bitvalues});
225
226                                 push @bitmaskTypes, \%struct;
227                                 # added to %data later
228                         } elsif ($category eq "basetype") {
229                                 my %struct = ();
230                                 my $info = scanMember($t);
231
232                                 if ($info->{baseType}) {
233                                         $struct{category} = $category;
234                                         $struct{name} = $info->{name};
235                                         $struct{type} = $info->{baseType};
236
237                                         # set holders here?
238                                         # TODO: fuck this off i think, it's not useful enough?
239                                         if ($info->{baseType} eq "uint32_t") {
240                                                 $struct{bitSize} = 32;
241                                                 $struct{bitAlignment} = 32;
242                                         } elsif ($info->{baseType} eq "uint64_t") {
243                                                 $struct{bitSize} = 64;
244                                                 $struct{bitAlignment} = 64;
245                                         } elsif ($info->{fullType} eq 'typedef void* ;') {
246                                                 $struct{bitSize} = 64;
247                                                 $struct{bitAlignment} = 64;
248                                         } else {
249                                                 print "$info->{name} '$info->{baseType}' '$info->{fullType}'\n";
250                                                 die();
251                                         }
252
253                                         $data{$struct{name}} = \%struct;
254                                 }
255                         } elsif ($category eq 'funcpointer') {
256                                 # <type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkInternalAllocationNotification</name>)(
257                                 # <type>void</type>*                                       pUserData,
258                                 # <type>size_t</type>                                      size,
259                                 # <type>VkInternalAllocationType</type>                    allocationType,
260                                 # <type>VkSystemAllocationScope</type>                     allocationScope);</type>
261                                 my %struct = ();
262                                 my $fullType = "";
263                                 my @oaramTypes = ();
264
265                                 foreach $p (@{$t->{Kids}}) {
266                                         if ($p->isa('Characters')) {
267                                                 $fullType .= $p->{Text};
268                                         } elsif ($p->isa('type')) {
269                                                 push @paramTypes, @{$p->{Kids}}[0]->{Text};
270                                                 $fullType .= @{$p->{Kids}}[0]->{Text};
271                                         } elsif ($p->isa('name')) {
272                                                 $struct{name} = @{$p->{Kids}}[0]->{Text};
273                                                 $fullType .= @{$p->{Kids}}[0]->{Text};
274                                         }
275                                 }
276                                 $fullType =~ s/^\s+|\s+$//g;
277                                 $fullType =~ s/\n|VKAPI_PTR//g;
278                                 $fullType =~ s/ +/ /g;
279                                 $fullType =~ s/\( +/\(/g;
280
281                                 $struct{prototype} = $fullType;
282                                 $data{$struct{name}} = \%struct;
283
284                                 %struct = ();
285                                 $struct{prototype} = $fullType;
286                                 $fullType =~ m/typedef (.*) \(\*(.*)\)\((.*)\)/;
287                                 $struct{result} = $1;
288                                 $struct{name} = $2;
289                                 $struct{args} = $3;
290                                 foreach $arg (split /,/,$struct{args}) {
291                                         $arg =~ m/^([^\*]+)(\*)? (.+)$/;
292                                         push @{$struct{params}}, { name => $3, fullType => $1.$2, baseType=>$1 };
293                                 }
294                                 #print Dumper(\%struct);
295                         }
296                 } else {
297                         $alias{$t->{name}} = $t->{alias};
298                 }
299     }
300 }
301
302 foreach $x (grep  { $_->isa('enums') } @{$registry->{Kids}}) {
303     if ($x->{type} eq "enum") {
304                 my @members = ();
305                 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
306                         my %info = (
307                                 name => $t->{name}
308                                 );
309                         $info{value} = $t->{value} if (defined($t->{value}));
310                         $info{comment} = $t->{comment} if (defined($t->{comment}));
311                         $info{alias} = $t->{alias} if (defined($t->{alias}));
312                         push @members, \%info;
313                 }
314                 my %enum = (
315                         category => 'enum',
316                         name => $x->{name},
317                         members => \@members
318                         );
319                 $data{$enum{name}} = \%enum;
320     } elsif ($x->{type} eq 'bitmask') {
321                 my @members = ();
322                 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
323                         my %info = ( name => $t->{name} );
324
325                         # FIXME: handle alias
326                         $info{alias} = $t->{alias} if (defined($t->{alias}));
327                         $info{comment} = $t->{comment} if (defined($t->{comment}));
328                         $info{value} = $t->{value} if (defined($t->{value}));
329                         $info{value} = "".(1<<$t->{bitpos}) if (defined($t->{bitpos}));
330
331                         push @members, \%info;
332                 }
333                 my %enum = (
334                         category => "enum:bitmask",
335                         name => $x->{name},
336                         members => \@members
337                         );
338                 $data{$enum{name}} = \%enum;
339     } else {
340                 #defines here
341                 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
342                         if (!defined($t->{alias})) {
343                                 my %enum = (
344                                         category => 'enum:define',
345                                         name => $t->{name},
346                                         value => $t->{value},
347                                         type => $t->{type}
348                                         );
349                                 $enum{comment} = $t->{comment} if (defined($t->{comment}));
350                                 $data{$enum{name}} = \%enum;
351                                 $apiConstants{$enum{name}} = \%enum;
352                         } else {
353                                 $alias{$t->{name}} = $t->{alias};
354                         }
355                 }
356     }
357 }
358
359 foreach $x (grep  { $_->isa('commands') } @{$registry->{Kids}}) {
360     foreach $y (grep  { $_->isa('command') } @{$x->{Kids}}) {
361                 if (!defined($y->{alias})) {
362                         my %cmd = ();
363                         my @params = ();
364
365                         $cmd{successcodes} = $y->{successcodes} if (defined $y->{successcodes});
366                         $cmd{errorcodes} = $y->{errorcodes} if (defined $y->{errorcodes});
367
368                         foreach $z (@{$y->{Kids}}) {
369                                 if ($z->isa('proto')) {
370                                         $cmd{proto} = scanMember($z);
371                                 } elsif ($z->isa('param')) {
372                                         push @params, scanMember($z);
373                                 }
374                         }
375
376                         $cmd{params} = \@params;
377
378                         my $name = $cmd{proto}->{name};
379
380                         if ($cmd{proto}->{fullType} eq "") {
381                                 print Dumper($y);
382                                 die();
383                         }
384                         $cmd{name} = $name;
385                         $commands{$cmd{name}} = \%cmd;
386                         push @commandsList, \%cmd;
387
388                 } else {
389                         # want forward ref or not?
390                         $alias{$y->{name}} = $y->{alias};
391                 }
392     }
393 }
394
395 foreach $x (grep  { $_->isa('feature') } @{$registry->{Kids}}) {
396     my %feature = (
397                 api => $x->{api},
398                 name => $x->{name},
399                 number => $x->{number},
400                 comment => $x->{comment}
401                 );
402     my @requires = ();
403     foreach $y (grep  { $_->isa('require') } @{$x->{Kids}}) {
404                 foreach $z (@{$y->{Kids}}) {
405                         addRequire(\@requires, $z, 'feature', \%feature);
406                 }
407     }
408     $feature{requires} = \@requires;
409
410     push @features, \%feature;
411 }
412
413 foreach $x (grep  { $_->isa('extensions') } @{$registry->{Kids}}) {
414     foreach $y (grep  { $_->isa('extension') } @{$x->{Kids}}) {
415                 my %extension = (
416                         name => $y->{name},
417                         number => $y->{number},
418                         supported => $y->{supported},
419                         type => $y->{type}
420                         );
421                 my @requires = ();
422
423                 $extension{requiresExtension} = $y->{requires} if (defined($y->{requires}));
424                 $extension{platform} = $y->{platform} if (defined($y->{platform}));
425
426                 foreach $z (grep  { $_->isa('require') } @{$y->{Kids}}) {
427                         foreach $a (@{$z->{Kids}}) {
428                                 addRequire(\@requires, $a, 'extension', \%extension);
429                         }
430                 }
431
432                 $extension{requires} = \@requires;
433
434                 push @extensions,\%extension;
435     }
436 }
437
438 my %dump = ();
439
440 sub patchRequires {
441     my $x = shift @_;
442     my $r = shift @_;
443
444     if ($r->{category} eq "type") {
445                 $dump{$r->{name}} = $r;
446     } elsif ($r->{category} eq "command") {
447                 $dump{$r->{name}} = $r;
448     } elsif ($r->{category} eq "enum") {
449                 if ($r->{extends}) {
450                         my $type = $data{$r->{extends}};
451                         my %info = ( name => $r->{name} );
452
453                         $info{comment} = $r->{comment} if (defined($r->{comment}));
454                         if (defined($r->{value})) {
455                                 $info{value} = $r->{value};
456                         } elsif (defined($r->{bitpos})) {
457                                 $info{value} = "".(1<<$r->{bitpos}) if (defined($r->{bitpos}));
458                         } elsif (defined($r->{extnumber})) {
459                                 $info{value} = "".(1000000000 + 1000 * ($r->{extnumber} - 1) + $r->{offset});
460                         } elsif (defined($r->{offset})) {
461                                 $info{value} = $r->{dir}."".(1000000000 + 1000 * ($x->{number} - 1) + $r->{offset});
462                         } elsif (defined($r->{alias})) {
463                                 #print "ignoring enum alias: '$r->{alias}' -> '$r->{name}'\n";
464                                 $info{alias} = $r->{alias};
465                         } else {
466                                 print Dumper($r);
467                                 die();
468                         }
469
470                         push @{$type->{members}}, \%info;
471                         $dump{$r->{extends}} = { category => 'enum', name => $r->{extends} };
472                 } else {
473                         my %enum = ( name => $r->{name} );
474
475                         # this is only needed for two values, one int, the other a string
476                         $enum{value} = $r->{value};
477                         $enum{category} = 'enum:define';
478                         $enum{type} = 'const char *' if ($r->{value} =~ m/^".*"$/);
479                         $enum{type} = 'uint32_t' if ($r->{value} =~ m/^[0-9]*$/);
480                         $enum{extension} = $x->{name};
481
482                         die() if (!defined($enum{type}));
483
484                         # extension?  do i care?
485                         $dump{$enum{name}} = { category => 'enum:define', name => $enum{name} };
486                         $data{$enum{name}} = \%enum;
487
488                 }
489     } else {
490                 die();
491     }
492 }
493
494 # collate types in each interface
495 # TODO: versions separated?  or define one version?
496 foreach $x (@features) {
497         my @requires = @{$x->{requires}};
498
499         foreach $r (@requires) {
500                 patchRequires($x, $r);
501         }
502 }
503
504 # patch extensions in and collate all types to include in output
505 # TODO: there's various versioning crap here too
506 foreach $x (grep { $_->{supported} eq 'vulkan'
507                                            && (!defined($_->{platform}) || $_->{platform} =~ m/xlib|wayland|xcb/) } @extensions) {
508     my @requires = @{$x->{requires}};
509
510     foreach $r (@requires) {
511                 patchRequires($x, $r);
512     }
513 }
514
515 # fix up bitmask type bases
516 foreach $x (@bitmaskTypes) {
517     if (defined $x->{requires}) {
518                 if (defined $data{$x->{requires}}) {
519                         my $struct = $data{$x->{requires}};
520                         $struct->{type} = $x->{type};
521                 } else {
522                         print "unknown bitmask enum requires $x->{requires}\n";
523                 }
524                 # somehow redirect flags to requires?
525                 $alias{$x->{name}} = $x->{requires};
526     } elsif (defined $x->{bitvalues}) {
527                 if (defined $data{$x->{bitvalues}}) {
528                         my $struct = $data{$x->{bitvalues}};
529                         $struct->{type} = $x->{type};
530                 } else {
531                         print "unknown bitmask enum bitvalues $x->{bitvalues}\n";
532                 }
533                 # somehow redirect flags to requires?
534                 $alias{$x->{name}} = $x->{bitvalues};
535     } elsif (defined $data{$x->{name}}) {
536                 my $struct = $data{$x->{name}};
537                 $struct->{type} = $x->{type};
538     } else {
539                 # these are referenced but don't have any definitions
540                 my %enum = (
541                         category => $x->{category},
542                         name => $x->{name},
543                         members => \@members,
544                         type => $x->{type}
545                         );
546                 $data{$enum{name}} = \%enum;
547     }
548 }
549
550 # Analyse length optioons
551 foreach $x (sort keys %dump) {
552     my $d = $dump{$x};
553     my $name = $d->{name};
554
555     if ($d->{category} eq "command") {
556                 analyseLengthParameters($commands{$name});
557     } elsif ($d->{category} eq "struct") {
558                 analyseLengthMembers($data{$name});
559     }
560 }
561
562 # This splits functions into class-based groups
563 # i.e. those with a handle as first argument
564 # the remaining ones are all VkInstance related static methods.
565 %functionSets = ( static => [] );
566 foreach $x (sort keys %dump) {
567     my $d = $dump{$x};
568
569     if ($d->{category} eq "command") {
570                 my $name = $d->{name};
571
572                 $name = $alias{$name} if (defined $alias{$name});
573
574                 my $cmd = $commands{$name};
575                 my @params = @{$cmd->{params}};
576
577                 if ($#params >= 0 && defined($data{$params[0]->{fullType}}->{type})) {
578                         my $t = $params[0]->{fullType};
579
580                         if (defined($functionSets{$t})) {
581                                 push @{$functionSets{$t}}, $d->{name};
582                         } else {
583                                 my @list = ( $d->{name} );
584                                 $functionSets{$t} = \@list;
585                         }
586                         #$set{$params[0]->{fullType}} = 1;
587                         #push @{$set{$params[0]->{fullType}}}, $d->{name};
588                 } else {
589                         #print Dumper($d);
590                         push @{$functionSets{static}}, $d->{name};
591                 }
592     }
593 }
594
595 # create list of extensions by type - instance or device - and set extensionType on each function
596 %functionByExtensionType = ();
597 foreach $y (keys %functionSets) {
598     my $x = $functionSets{$y};
599     foreach $c (@{$x}) {
600                 next if ($alias{$c});
601                 my $cmd = $commands{$c};
602
603                 my $d = $dump{$cmd->{name}};
604                 my $ext = $d->{extension};
605                 if (defined $ext) {
606                         my $type = $ext->{type};
607
608                         # sigh, some physicaldevice or instance calls come from device extensions... but it's parent is only the instance
609                         # so make sure they're actually in that type
610
611                         my @params = @{$cmd->{params}};
612                         if ($params[0]->{baseType} =~ m/^VkInstance|VkPhysicalDevice$/) {
613                                 $type = "instance";
614                         }
615
616                         push @{$functionByExtensionType{$type}}, $c;
617                         $cmd->{extensionType} = $type;
618                         $cmd->{extensionSource} = $ext->{type};
619                         $cmd->{extensionName} = $ext->{name};
620                 }
621     }
622 }
623
624
625 # TODO: unused
626 sub findType {
627     my $next = shift @_;
628     my $type;
629
630     #  basetypes?
631
632     print"search $next\n";
633     do {
634                 $type = $next;
635                 if (defined($alias{$type})) {
636                         $next = $alias{$type};
637                         print "  goto alias\n";
638                 } elsif (defined($data{$type})) {
639                         my $d = $data{$type};
640
641                         if ($d->{category} eq "struct") {
642                                 return $d;
643                         } elsif ($d->{category} eq "enum") {
644                                 return $d;
645                         } elsif ($d->{category} eq "basetype") {
646                                 return $d;
647                         } else {
648                                 print "category: $d->{category}\n";
649                                 die("fuckoff");
650                         }
651                 } else {
652                         return $type;
653                 }
654                 print"  $next\n";
655     } while (defined $next);
656
657     return undefined;
658 }
659
660 sub functionDescriptorType {
661     my $p = shift @_;
662     my $baseType = $p->{baseType};
663     my $fullType = $p->{fullType};
664
665     if ($fullType =~ m/\*/) {
666                 return "Memory.POINTER";
667     } else {
668                 my $type;
669
670                 # FIXME: This loops to handle a double-alias for some flag types
671                 # FIXME: FlagsNV -> FlagsKHR -> FlagBitsKHR
672                 # FIXME: maybe fix it elsewhere
673                 do {
674                         $baseType = $alias{$baseType} if (defined($alias{$baseType}));
675                         $type = $data{$baseType};
676
677                         #print "\n\n$baseType = ".Dumper($type)."\n\n";
678
679                         if (defined $type->{type}) {
680                                 $baseType = $type->{type};
681                                 #print "  has subtype -> $baseType\n";
682                         } elsif ($type->{category} eq "enum" || $type->{category} eq "enum:bitmask") {
683                                 $baseType = "int32_t";
684                                 #print "  is normal enm -> $baseType\n";
685                         }
686                 } while ($baseType =~ m/Flags/ && defined($alias{$baseType}));
687
688                 return 'Memory.'.uc($typeToJavaPrimitive{$baseType}) if ($typeToJavaPrimitive{$baseType});
689
690                 # handles and some hacks
691                 if ($baseType =~ m/^PFN_/) {
692                         return "Memory.POINTER";
693                 } elsif ($baseType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
694                         return "Memory.POINTER";
695                 } elsif ($baseType eq "VK_DEFINE_HANDLE") {
696                         return "Memory.POINTER";
697                 } elsif ($baseType eq "VkFlags") {
698                         return 'Memory.INT';
699                 } elsif ($baseType eq "VkFlags64") {
700                         return 'Memory.LONG';
701                 }
702
703                 $type = $data{$baseType};
704
705                 #print "    ** Unhandled base type $baseType  full=$fullType nextalias=$alias{$baseType} orig=$p->{baseType}\n";
706                 #print Dumper($type);
707                 #die();
708
709                 return "$type->{name}.LAYOUT";
710                 #die();
711     }
712 }
713
714 # yuck
715 sub functionJavaType {
716     my $p = shift @_;
717     my $baseType = $p->{baseType};
718     my $fullType = $p->{fullType};
719     my $type;
720     my $deref = $fullType =~ tr/*/*/;
721
722     if ($deref > 0 || $fullType =~ m/\[.*\]/) {
723
724                 if ($p->{len} == 'null-terminated' && $fullType eq 'const char*') {
725                         return 'String';
726                 } elsif ($fullType eq "void*") {
727                         return "MemoryAddress";
728                 } elsif ($p->{len} && $fullType eq 'const char* const*') {
729                         return 'String[]';
730                 }
731
732                 $baseType = $alias{$baseType} if (defined($alias{$baseType}));
733                 $type = $data{$baseType};
734
735                 # TODO: if len or altlen set, then it's probably an array otherwise it's a holder/pointer
736
737                 if (defined $type->{type}) {
738                         $baseType = $type->{type};
739                         #print "  has subtype -> $baseType\n";
740                 } elsif ($type->{category} eq "enum" || $type->{category} eq "enum:bitmask") {
741                         $baseType = "int32_t";
742                         #print "  is normal enm -> $baseType\n";
743                 }
744
745                 # alias?
746                 return 'Memory.'.ucfirst($typeToJavaPrimitive{$baseType}).'Array' if (defined $typeToJavaPrimitive{$baseType});
747
748                 # handles and some hacks
749                 if ($baseType eq "void") {
750                         return "Memory.PointerArray";
751                         #return "void";
752                 } elsif ($baseType =~ m/^PFN_/) {
753                         return "MemoryAddress";
754                         #return $type->{name};
755                 } elsif ($baseType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
756                         # typed array?
757                         # We actually just want the same type since it's also an array if required
758                         return "Memory.HandleArray<$p->{baseType}>";
759                         #return $type->{name};
760                 } elsif ($baseType eq "VK_DEFINE_HANDLE") {
761                         # could be more typed
762                         return "Memory.HandleArray<$p->{baseType}>";
763                         #return "Memory.PointerArray";
764                         #return $type->{name};
765                 } elsif ($baseType eq "VkFlags") {
766                         return 'Memory.IntArray';
767                 } elsif ($baseType eq "VkFlags64") {
768                         return 'Memory.LongArray';
769                 }
770
771                 if (defined($alias{$baseType})) {
772                         $baseType = $alias{$baseType};
773                 }
774                 $type = $data{$baseType};
775
776                 # TODO: function poitners?
777                 #print "lookup $fullType -> unhandled base type $baseType -> $type->{name}\n";
778
779                 if (defined($type->{name})) {
780                         return $type->{name};
781                 } else {
782                         return "MemorySegment";
783                 }
784     } else {
785                 # FIXME: This loops to handle a double-alias for some flag types
786                 # FIXME: FlagsNV -> FlagsKHR -> FlagBitsKHR
787                 # FIXME: maybe fix it elsewhere
788                 do {
789                         $baseType = $alias{$baseType} if (defined($alias{$baseType}));
790                         $type = $data{$baseType};
791
792                         #print "\n\n$baseType = ".Dumper($type)."\n\n";
793
794                         if (defined $type->{type}) {
795                                 $baseType = $type->{type};
796                                 #print "  has subtype -> $baseType\n";
797                         } elsif ($type->{category} eq "enum" || $type->{category} eq "enum:bitmask") {
798                                 $baseType = "int32_t";
799                                 #print "  is normal enm -> $baseType\n";
800                         }
801                 } while ($baseType =~ m/Flags/ && defined($alias{$baseType}));
802
803                 return $typeToJavaPrimitive{$baseType} if (defined $typeToJavaPrimitive{$baseType});
804
805                 # handles and some hacks
806                 if ($baseType eq "void") {
807                         return "void";
808                 } elsif ($baseType =~ m/^PFN_/) {
809                         return "MemoryAddress";
810                         #return $type->{name};
811                 } elsif ($baseType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
812                         return $type->{name};
813                 } elsif ($baseType eq "VK_DEFINE_HANDLE") {
814                         return $type->{name};
815                 } elsif ($baseType eq "VkFlags") {
816                         return 'int';
817                 } elsif ($baseType eq "VkFlags64") {
818                         return 'long';
819                 }
820
821                 if (defined($alias{$baseType})) {
822                         $baseType = $alias{$baseType};
823                 }
824                 $type = $data{$baseType};
825
826                 # TODO: function poitners?
827                 #print "lookup $fullType -> unhandled base type $baseType -> $type->{name}\n";
828
829                 if (defined($type->{name})) {
830                         return $type->{name};
831                 } else {
832                         return "Object";
833                 }
834     }
835 }
836
837 sub formatFunctionDescriptor {
838     my $cmd = shift @_;
839     my $proto = $cmd->{proto};
840     my @params = @{$cmd->{params}};
841
842     my $type = $data{$proto->{baseType}};
843     my $nargs = 0;
844     my $desc;
845
846     if ($proto->{fullType} eq "void") {
847                 $desc = "FunctionDescriptor.ofVoid(";
848     } else {
849                 $desc = "FunctionDescriptor.of(";
850                 $desc .= functionDescriptorType($proto);
851                 $nargs++;
852     }
853
854     foreach $param (@params) {
855                 $desc .= "," if ($nargs++ > 0);
856                 $desc .= functionDescriptorType($param);
857                 $desc .= ".withName(\"$param->{name}\")";
858     }
859     $desc .= ")";
860     return prettyFormat($desc);
861 }
862
863 sub find {
864     my $n = shift @_;
865     my @list = @{shift @_};
866
867     foreach $p (@list) {
868                 return $p if ($p->{name} eq $n);
869     }
870     return;
871 }
872
873 # return the core root type, will be VK_DEFINE_HANDLE for handles, etc
874 sub getRootType {
875     my $baseType = shift @_;
876     my $type;
877
878     $baseType = $alias{$baseType} if (defined($alias{$baseType}));
879     $type = $data{$baseType};
880
881     if (defined $type->{type}) {
882                 $baseType = $type->{type};
883                 #print "  has subtype -> $baseType\n";
884     } elsif ($type->{category} eq "enum" || $type->{category} eq "enum:bitmask") {
885                 $baseType = "int32_t";
886                 #print "  is normal enm -> $baseType\n";
887     }
888
889     return $baseType;
890 }
891
892 sub analyseLengthParameters {
893     my $cmd = shift @_;
894     my @params = @{$cmd->{params}};
895
896     foreach $param (@params) {
897                 if ($param->{len} eq 'null-terminated') {
898                         if ($param->{fullType} eq 'const char*') {
899                                 $param->{lenType} = 'string';
900                         } else {
901                                 die ("unsupported function length type $param->{fullType}");
902                         }
903                 } elsif ($param->{len} =~ m/^(.+),?/) {
904                         my $count = $1;
905                         my $src = find($count, \@params);
906
907                         $src->{lenTarget} = $param->{name};
908
909                         # if count is a pointer then it's for returns
910                         # find out target type to determine structure of parameter
911                         my $rootType = getRootType($param->{baseType});
912                         my $fullType = $param->{fullType};
913                         my $nderef = $fullType =~ tr/*/*/;
914                         my $lenType = 'raw';
915
916                         if ($nderef == 1 && defined $typeToJavaPrimitive{$rootType}) {
917                                 $lenType = 'primitive-array';
918                         } elsif ($rootType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
919                                 $lenType = 'handle-array';
920                         } elsif ($rootType eq "VK_DEFINE_HANDLE") {
921                                 $lenType = 'handle-array';
922                         } elsif ($nderef == 2) {
923                                 $lenType = 'pointer-array';
924                         } else {
925                                 $lenType = 'struct-array';
926                         }
927
928                         $src->{lenType} = $lenType.'-count';
929                         $param->{lenType} = $lenType;
930                 }
931     }
932 }
933
934 # can merge with above?
935 # not used yet tho
936 sub analyseLengthMembers {
937     my $cmd = shift @_;
938     my @params = @{$cmd->{members}};
939
940     foreach $param (@params) {
941                 if ($param->{len} eq 'null-terminated') {
942                         if ($param->{fullType} eq 'const char*') {
943                                 $param->{lenType} = 'string';
944                         } else {
945                                 die ("unsupported function length type $param->{fullType}");
946                         }
947                 } elsif ($param->{len} =~ m/^(.+),?/) {
948                         my $count = $1;
949                         my $src = find($count, \@params);
950
951                         $src->{lenTarget} = $param->{name};
952
953                         # find out target type to determine structure of parameter
954                         my $rootType = getRootType($param->{baseType});
955                         my $fullType = $param->{fullType};
956                         my $nderef = $fullType =~ tr/*/*/;
957                         my $lenType = 'raw';
958
959                         if ($nderef == 1 && defined $typeToJavaPrimitive{$rootType}) {
960                                 $lenType = 'primitive-array';
961                         } elsif ($rootType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
962                                 $lenType = 'handle-array';
963                         } elsif ($rootType eq "VK_DEFINE_HANDLE") {
964                                 $lenType = 'handle-array';
965                         } elsif ($nderef == 2) {
966                                 $lenType = 'pointer-array';
967                         } else {
968                                 $lenType = 'struct-array';
969                         }
970
971                         $src->{lenType} = $lenType.'-count';
972                         $param->{lenType} = $lenType;
973                 }
974     }
975 }
976
977 # TBD
978 sub dumpFunctionPrototype {
979     my $cmd = shift @_;
980     my $proto = $cmd->{proto};
981     my @params = @{$cmd->{params}};
982
983     my $type = $data{$proto->{baseType}};
984     my $nargs = 0;
985
986     if ($proto->{fullType} eq "void") {
987                 print "void";
988     } else {
989                 print functionJavaType($proto);
990     }
991     print " $proto->{name}(";
992
993     foreach $param (@params) {
994                 my $lenType = $param->{lenType};
995                 my $fullType = $param->{fullType};
996                 my $cderef = ($fullType =~ tr/*/*/);
997
998                 #print "\n[ $param->{name} lentype=$lenType ]\n";
999
1000                 next if ($cderef == 0 && $lenType eq 'primitive-array-count');
1001                 next if ($cderef == 0 && $lenType eq 'handle-array-count');
1002                 # keep raw-count, struct-array-count and output counts
1003
1004                 print ', ' if ($nargs++ > 0);
1005
1006
1007                 if ($lenType =~ m/-count$/ && $cderef > 0) {
1008                         # count is an output
1009                         print $typeToJavaPrimitive{getRootType($param->{baseType})}.'[]';
1010                 } elsif ($lenType eq 'string') {
1011                         print 'String';
1012                 } elsif ($lenType eq 'handle-array') {
1013                         # alias?
1014                         print $param->{baseType}.'[]';
1015                 } elsif ($lenType eq 'primitive-array') {
1016                         print $typeToJavaPrimitive{getRootType($param->{baseType})}.'[]';
1017                 } elsif ($lenType eq 'pointer-array') {
1018                         # what do i want here, MemoryAddress[]?
1019                         # or just MemorySegment
1020                         print 'MemorySegment';
1021                 } elsif ($lenType eq 'struct-array') {
1022                         print 'MemorySegment';
1023                 } else {
1024                         print functionJavaType($param);
1025                 }
1026                 print ' ';
1027                 print $param->{name};
1028     }
1029     print ')';
1030 }
1031
1032 sub formatPrototype {
1033     my $cmd = shift @_;
1034     my $static = shift @_;
1035
1036     my $proto = $cmd->{proto};
1037     my @params = @{$cmd->{params}};
1038
1039     my $nargs = 0;
1040     my $jrtype = proto->{fullType} eq 'void' ? 'void' : functionJavaType($proto);
1041     my $desc;
1042
1043     # TODO: don't include return type if it's success
1044     $desc = ($cmd->{successcodes} eq 'VK_SUCCESS') ? $desc = 'void' : $jrtype;
1045     $desc .= " $proto->{name}(";
1046
1047     # TODO: static or not
1048     foreach $param (@params [($static ? 0 : 1) .. $#params]) {
1049                 my $fullType = $param->{fullType};
1050                 my $deref = ($fullType =~ tr/*/*/);
1051
1052                 # implied counts
1053                 next if ($deref == 0 && $lenType eq 'primitive-array-count');
1054                 next if ($deref == 0 && $lenType eq 'handle-array-count');
1055
1056                 $desc .= ', ' if ($nargs++ > 0);
1057
1058                 my $tname = functionJavaType($param);
1059                 $tname = $alias{$tname} if (defined $alias{$tname});
1060
1061                 $desc .= "$tname $param->{name}";
1062     }
1063     $desc .= ')';
1064
1065     return ($jrtype, $desc);
1066 }
1067
1068 # TODO: merge with above, maybe pass in params list for different rnage
1069 # TODO: also return type type
1070 sub formatCreatePrototype {
1071     my $cmd = shift @_;
1072     my $static = shift @_;
1073
1074     my $proto = $cmd->{proto};
1075     my @params = @{$cmd->{params}};
1076
1077     my $nargs = 0;
1078     my $jrtype = proto->{fullType} eq 'void' ? 'void' : functionJavaType($proto);
1079     my $desc;
1080
1081     # TODO: don't include return type if it's success
1082     #$desc = ($cmd->{successcodes} eq 'VK_SUCCESS') ? $desc = 'void' : $jrtype;
1083     $desc = $params[$#params]->{baseType};
1084     $desc .= " $proto->{name}(";
1085
1086     # TODO: static or not
1087     foreach $param (@params [($static ? 0 : 1) ..$#params-1]) {
1088                 my $fullType = $param->{fullType};
1089                 my $deref = ($fullType =~ tr/*/*/);
1090
1091                 # implied counts
1092                 next if ($deref == 0 && $lenType eq 'primitive-array-count');
1093                 next if ($deref == 0 && $lenType eq 'handle-array-count');
1094
1095                 $desc .= ', ' if ($nargs++ > 0);
1096
1097                 my $tname = functionJavaType($param);
1098                 $tname = $alias{$tname} if (defined $alias{$tname});
1099
1100                 $desc .= "$tname $param->{name}";
1101     }
1102     $desc .= ')';
1103
1104     return ($jrtype, $desc);
1105 }
1106
1107 # exports a non-static member function
1108 # TODO: handle static too
1109 sub exportFunction {
1110     my $f = shift @_;
1111     my $cmd = shift @_;
1112     my $static = shift @_;
1113     my ($jrtype, $prototype) = formatPrototype($cmd, $static);
1114     my $index = 0;
1115     my @params = @{$cmd->{params}};
1116
1117     $commandsExported{$cmd->{proto}->{name}} = 1;
1118     #print "$jrtype\n";
1119     #print Dumper($cmd);
1120
1121     die("cannot have static extensions") if ($static && $cmd->{extensionType});
1122
1123     print $f "\tpublic ";
1124     print $f "static " if $static;
1125     print $f $prototype;
1126     print $f "throws Exception" if ($cmd->{successcodes});
1127     print $f " {\n";
1128
1129     # TODO: only create frame if required?
1130
1131     print $f "\t\t$jrtype res\$code;\n" if ($jrtype ne 'void');
1132     print $f "\t\ttry (Frame frame = Memory.createFrame()) {\n";
1133
1134     # setup
1135     foreach $param (@params[($static ? 0 : 1) .. $#params]) {
1136                 my $tname = functionJavaType($param);
1137                 $tname = $alias{$tname} if (defined $alias{$tname});
1138
1139                 # TODO: if it's an output only then don't copy the count?
1140                 if ($tname eq 'String') {
1141                         print $f "\t\t\tMemorySegment $param->{name}\$h = frame.copy($param->{name});\n";
1142                 }
1143     }
1144     # invoke
1145     print $f "\t\t\t";
1146     print $f "res\$code = ($jrtype)" if ($jrtype ne 'void');
1147     print $f "$cmd->{extensionType}Dispatch." if ($cmd->{extensionType});
1148     print $f "$cmd->{name}\$FH.invokeExact(\n";
1149
1150     $index = 0;
1151     if (!$static) {
1152                 print $f "\t\t\t\t(Addressable)address()";
1153                 print $f ",\n" if ($index++ > 0);
1154     }
1155
1156     foreach $param (@params[($static ? 0 : 1) .. $#params]) {
1157                 my $tname = functionJavaType($param);
1158                 $tname = $alias{$tname} if (defined $alias{$tname});
1159
1160                 print $f ",\n" if ($index++ > 0);
1161
1162                 if ($tname eq 'String') {
1163                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name}\$h)";
1164                 } elsif ($tname =~ m/Memory\..*Array/) {
1165                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1166                 } elsif ($data{$tname}) {
1167                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1168                 } elsif ($tname eq 'MemorySegment' || $tname eq 'MemoryAddress') {
1169                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1170                 } else {
1171                         print $f "\t\t\t\t($tname)$param->{name}";
1172                 }
1173     }
1174     print $f ");\n";
1175
1176     # TODO: create functions how???
1177
1178     # copy any output data back
1179     foreach $param (@params) {
1180                 my $tname = functionJavaType($param);
1181                 $tname = $alias{$tname} if (defined $alias{$tname});
1182
1183                 next if ($param->{fullType} =~ m/const/);
1184
1185                 if ($tname =~ m/\[\]$/) {
1186                         print $f "\t\t\tMemorySegment.ofArray($param->{name}).copyFrom($param->{name}\$h);\n";
1187                 }
1188     }
1189
1190     if ($cmd->{successcodes}) {
1191                 my $returnStatement = ($cmd->{successcodes} eq 'VK_SUCCESS') ? 'return' : 'return res$code';
1192                 foreach $r (split /,/, $cmd->{successcodes}) {
1193                         print $f "\t\t\tif (res\$code == VkResult.$r) $returnStatement;\n";
1194                 }
1195     } elsif ($jrtype ne "void") {
1196                 print $f "\t\t\treturn res\$code;\n";
1197     }
1198
1199     print $f "\t\t} catch (Throwable t) { throw new RuntimeException(t); }\n";
1200     if ($cmd->{successcodes}) {
1201         # fixme, some exception type(s)
1202                 print $f "\t\tthrow new Exception(String.format(\"failcode %d\", res\$code));\n";
1203     }
1204
1205     print $f "\t}\n";
1206 }
1207
1208 # create functions return a handle in their last argument
1209 sub exportCreateFunction {
1210     my $f = shift @_;
1211     my $cmd = shift @_;
1212     my $static = shift @_;
1213     my ($jrtype, $prototype) = formatCreatePrototype($cmd, $static);
1214     my $index = 0;
1215     my @params = @{$cmd->{params}};
1216     my $instanceType = $params[$#params]->{baseType};
1217
1218     $commandsExported{$cmd->{proto}->{name}} = 1;
1219
1220     # CHANGE: static
1221     print $f "\tpublic ";
1222     print $f 'static ' if ($static);
1223     print $f $prototype;
1224     print $f "throws Exception" if ($cmd->{successcodes});
1225     print $f " {\n";
1226
1227     print $f "\t\t$jrtype res\$code;\n" if ($jrtype ne 'void');
1228     print $f "\t\ttry (Frame frame = Memory.createFrame()) {\n";
1229
1230     # setup
1231     # CHANGE: return holder
1232     print $f "\t\t\tMemorySegment instance\$h = frame.allocatePointer();\n";
1233
1234     # CHANGE: range
1235     foreach $param (@params[($static ? 0 : 1) .. $#params-1]) {
1236                 my $tname = functionJavaType($param);
1237                 $tname = $alias{$tname} if (defined $alias{$tname});
1238
1239                 # TODO: if it's an output only then don't copy the count?
1240                 if ($tname eq 'String') {
1241                         print $f "\t\t\tMemorySegment $param->{name}\$h = frame.copy($param->{name});\n";
1242                 }
1243     }
1244     # invoke
1245     print $f "\t\t\t";
1246     print $f "res\$code = ($jrtype)" if ($jrtype ne 'void');
1247     print $f "$cmd->{extensionType}Dispatch." if ($cmd->{extensionType});
1248     print $f "$cmd->{name}\$FH.invokeExact(\n";
1249
1250     $index = 0;
1251     # CHANGE: no 'this'
1252     if (!$static) {
1253                 print $f "\t\t\t\t(Addressable)address()";
1254                 print $f ",\n" if ($index++ > 0);
1255     }
1256
1257     # CHANGE: range
1258     foreach $param (@params[($static ? 0 : 1) .. $#params-1]) {
1259                 my $tname = functionJavaType($param);
1260                 $tname = $alias{$tname} if (defined $alias{$tname});
1261
1262                 print $f ",\n" if ($index++ > 0);
1263
1264                 if ($tname eq 'String') {
1265                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name}\$h)";
1266                 } elsif ($tname =~ m/Memory\..*Array/) {
1267                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1268                 } elsif ($data{$tname}) {
1269                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1270                 } elsif ($tname eq 'MemorySegment' || $tname eq 'MemoryAddress') {
1271                         print $f "\t\t\t\t(Addressable)Memory.address($param->{name})";
1272                 } else {
1273                         print $f "\t\t\t\t($tname)$param->{name}";
1274                 }
1275     }
1276     # CHANGE: return pointer
1277     print $f ",\n" if ($index++ > 0);
1278     print $f "\t\t\t\t(Addressable)instance\$h.address()";
1279
1280     print $f ");\n";
1281
1282     # CHANGE: no output data
1283     # # copy any output data back
1284     # foreach $param (@params) {
1285     #   my $tname = functionJavaType($param);
1286     #   $tname = $alias{$tname} if (defined $alias{$tname});
1287
1288     #   next if ($param->{fullType} =~ m/const/);
1289
1290     #   if ($tname =~ m/\[\]$/) {
1291     #       print $f "\t\t\tMemorySegment.ofArray($param->{name}).copyFrom($param->{name}\$h);\n";
1292     #   }
1293     # }
1294
1295     # CHANGE: different return code processing
1296     # if ($cmd->{successcodes}) {
1297     #   my $returnStatement = ($cmd->{successcodes} eq 'VK_SUCCESS') ? 'return' : 'return res$code';
1298     #   foreach $r (split /,/, $cmd->{successcodes}) {
1299     #       print $f "\t\tif (res\$code == VkResult.$r) $returnStatement;\n";
1300     #   }
1301     # } else {
1302     #   print $f "\t\treturn $res\$code;\n";
1303     # }
1304
1305     # FIXME: see vkCreateGraphicsPipelines multiple 'success' types
1306     # This might cause leaks?
1307     print $f "\t\t\tif (res\$code == VkResult.VK_SUCCESS)\n\t" if ($jrtype ne 'void');
1308
1309     # initialise extension function tables if required
1310     if ($data{$instanceType}->{type} eq "VK_DEFINE_HANDLE") {
1311                 if ($instanceType eq "VkInstance") {
1312                         print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0));\n";
1313                 } elsif ($instanceType =~ m/^VkDevice|VkPhysicalDevice$/) {
1314                         print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0), instanceDispatch);\n";
1315                 } else {
1316                         print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0), instanceDispatch, deviceDispatch);\n";
1317                 }
1318     } else {
1319                 print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0));\n";
1320     }
1321
1322     print $f "\t\t} catch (Throwable t) { throw new RuntimeException(t); }\n";
1323
1324     # CHANGE: different return code processing
1325     # if ($cmd->{successcodes}) {
1326     #   # fixme, some exception type(s)
1327     #   print $f "\t\tthrow new Exception(String.format(\"failcode %d\", res\$code));\n";
1328     # }
1329
1330     print $f "\t\tthrow new Exception(String.format(\"failcode %d\", res\$code));\n" if ($jrtype ne 'void');
1331
1332     print $f "\t}\n";
1333 }
1334
1335 %descToSize = (
1336     'Memory.BYTE' => 8,
1337     'Memory.SHORT' => 16,
1338     'Memory.INT' => 32,
1339     'Memory.LONG' => 64,
1340     'Memory.FLOAT' => 32,
1341     'Memory.DOUBLE' => 64,
1342     'Memory.POINTER' => 64
1343     );
1344
1345 sub calcMemberSize {
1346     my $m = shift @_;
1347     my $desc = functionDescriptorType($m);
1348     my $size;
1349     my $align = 1;
1350
1351     if (defined $descToSize{$desc}) {
1352                 $size = $descToSize{$desc};
1353                 $align = $size;
1354     } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1355                 #print "\n$desc\n";
1356                 ($size, $align) = calcSize($data{$1});
1357                 #print "\n";
1358     } else {
1359                 print Dumper($m);
1360                 print "description='$desc'\n";
1361                 die("unknown size");
1362     }
1363
1364     # handle array types
1365     if ($m->{fullType} =~ m/\[(\d+)\]/) {
1366                 #print "array size $m->{fullType} = $1\n";
1367                 $size *= $1;
1368     } elsif ($m->{fullType} =~ m/\[(.+)\]/) {
1369                 my $value = $apiConstants{$1}->{value};
1370                 #print "array size $m->{fullType} = $1 = $value\n";
1371                 $size *= $value;
1372     }
1373
1374     #print "member $m->{name} size=$size align=$align\n";
1375     #print Dumper($m);
1376     #my $sizeb = $size / 8;
1377     #my $alignb = $align / 8;
1378     #print "size=$size ($sizeb) align=$align ($alignb) desc=$desc\n\n";
1379
1380     return ($size, $align);
1381 }
1382
1383 sub calcSize {
1384     my $s = shift @_;
1385     my $sizeof = 0;
1386
1387     return ($s->{bitSize}, $s->{bitAlign}) if (defined $s->{bitSize});
1388
1389     if ($s->{category} eq "struct") {
1390                 my $maxAlign = 1;
1391
1392                 for $m (@{$s->{members}}) {
1393                         my ($size, $align) = calcMemberSize($m);
1394
1395                         # my $desc = functionDescriptorType($m);
1396                         # my $size;
1397                         # my $align = 1;
1398
1399                         # if (defined $descToSize{$desc}) {
1400                         #       $size = $descToSize{$desc};
1401                         # } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1402                         #       $size = calcSize($data{$1});
1403                         # }
1404
1405                         $maxAlign = $align if $align > $maxAlign;
1406
1407                         #           if ($size >=8 && $size <= 64) {
1408                         #               $align = $size;
1409                         #           } elsif ($size > 64) {
1410                         #               $align = 64;
1411                         #           } else {
1412                         #               $align = 1;
1413                         #           }
1414
1415                         $sizeof = ($sizeof + $align - 1) & ~($align - 1);
1416                         $sizeof += $size;
1417                 }
1418
1419                 $sizeof = ($sizeof + $maxAlign - 1) & ~($maxAlign-1);
1420                 $s->{bitAlign} = $maxAlign;
1421                 $s->{bitSize} = $sizeof;
1422     } elsif ($s->{category} eq "union") {
1423                 my $maxAlign = 1;
1424
1425                 for $m (@{$s->{members}}) {
1426                         my $desc = functionDescriptorType($m);
1427                         my $size;
1428                         my $align = 1;
1429
1430                         if (defined $descToSize{$desc}) {
1431                                 $size = $descToSize{$desc};
1432                         } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1433                                 $size = calcSize($data{$1});
1434                         }
1435
1436                         $sizeof = $size if ($size > $sizeof);
1437                 }
1438
1439                 # FIXME: probably wrong
1440                 $sizeof = ($sizeof + 63) & ~(63);
1441                 $s->{bitAlign} = 64;
1442                 $s->{bitSize} = $sizeof;
1443     } elsif ($s->{category} eq "enum:bitmask" || $s->{category} eq "enum") {
1444                 # hmm,?
1445                 if ($s->{type} eq "VkFlags64") {
1446                         $s->{bitSize} = 64;
1447                         $s->{bitAlign} = 64;
1448                 } else {
1449                         $s->{bitSize} = 32;
1450                         $s->{bitAlign} = 32;
1451                 }
1452     } else {
1453                 print Dumper($s);
1454                 die();
1455     }
1456
1457     return ($s->{bitSize}, $s->{bitAlign});
1458 }
1459
1460 sub formatLayout {
1461     my $s = shift @_;
1462     my $layout;
1463
1464     if ($s->{category} eq 'struct') {
1465                 my $sizeof = 0;
1466                 my $index = 0;
1467
1468                 $layout = 'MemoryLayout.structLayout(';
1469                 for $m (@{$s->{members}}) {
1470                         my $type = functionDescriptorType($m);
1471                         my ($size, $align) = calcMemberSize($m);
1472                         my $pad = $sizeof & ($align - 1);
1473
1474                         if ($pad) {
1475                                 $layout .= ',' if ($index++ > 0);
1476                                 $layout .= "MemoryLayout.paddingLayout($pad)";
1477                                 $sizeof += $pad;
1478                         }
1479
1480                         #if ($type =~ m/\.LAYOUT$/) {
1481                         {
1482                                 if ($m->{fullType} =~ m/\[(\d+)\]/) {
1483                                         my $value = $1;
1484                                         #print "s array size $s->{name}.$m->{name} $m->{fullType} = $1\n";
1485                                         $type = "MemoryLayout.sequenceLayout($value,\t$type)";
1486                                 } elsif ($m->{fullType} =~ m/\[(.+)\]/) {
1487                                         my $value = $apiConstants{$1}->{value};
1488                                         #print "s array size $s->{name}.$m->{name} $m->{fullType} = $1 = $value\n";
1489                                         $type = "MemoryLayout.sequenceLayout($value,\t$type)";
1490                                 }
1491                         }
1492
1493                         $layout .= ',' if ($index++ > 0);
1494                         $layout .= $type.".withName(\"$m->{name}\")";
1495                         $sizeof += $size;
1496                 }
1497                 my $pad = $sizeof & 63;
1498                 $layout .= ',' if ($pad);
1499                 $layout .= "MemoryLayout.paddingLayout($pad)" if ($pad);
1500                 $layout .= ')';
1501     } elsif ($s->{category} eq "union") {
1502                 my $index = 0;
1503
1504                 $layout = 'MemoryLayout.unionLayout(';
1505                 for $m (@{$s->{members}}) {
1506                         my $type = functionDescriptorType($m);
1507                         my ($size, $align) = calcMemberSize($m);
1508
1509                         # not used
1510                         #if ($type =~ m/\.LAYOUT$/) {
1511                         {
1512                                 if ($m->{fullType} =~ m/\[(\d+)\]/) {
1513                                         my $value = $1;
1514                                         #print "u array size $s->{name}.$m->{name} $m->{fullType} = $1\n";
1515                                         $type = "MemoryLayout.sequenceLayout($value, $type)";
1516                                 } elsif ($m->{fullType} =~ m/\[(.+)\]/) {
1517                                         my $value = $apiConstants{$1}->{value};
1518                                         #print "u array size $s->{name}.$m->{name} $m->{fullType} = $1 = $value\n";
1519                                         $type = "MemoryLayout.sequenceLayout($value, $type)";
1520                                 }
1521                         }
1522                         $layout .= ',' if ($index++ > 0);
1523                         $layout .= $type.".withName(\"$m->{name}\")";
1524                         $sizeof = $size if ($size > $sizeof);
1525                 }
1526                 my $pad = $sizeof & 63;
1527                 $layout .= ',' if ($pad);
1528                 $layout .= "MemoryLayout.paddingLayout($pad)" if ($pad);
1529                 $layout .= ')';
1530     } elsif ($s->{category} eq "enum") {
1531     } elsif ($s->{category} eq "enum:bitmask") {
1532     } else {
1533                 #print "X $s->{category}\n";
1534     }
1535
1536     return prettyFormat($layout);
1537 }
1538
1539 sub prettyFormat {
1540     my $java = shift @_;
1541
1542     $java =~ s/\(/\(\n\t/;
1543     $java =~ s/,/,\n\t/g;
1544
1545     return $java;
1546 }
1547
1548 #
1549
1550 #print 'VkAccelerationStructureGeometryTrianglesDataKHR'."\n";
1551
1552 # print formatLayout($data{'VkDeviceOrHostAddressConstKHR'});
1553
1554 # print formatLayout($data{'VkAccelerationStructureGeometryTrianglesDataKHR'});
1555 # print formatLayout($data{'VkApplicationInfo'});
1556 # print "\n";
1557
1558 # ($size,$align) = calcSize($data{'VkAccelerationStructureGeometryTrianglesDataKHR'});
1559 # $bytes = $size / 8;
1560 # print "bytes=$bytes bits=$size align=$align\n";
1561 # exit 0;
1562
1563 if (0) {
1564     foreach $k (sort keys %functionSets) {
1565                 my $list = $functionSets{$k};
1566
1567                 print "first: $k\n";
1568
1569                 foreach $c (@$list) {
1570                         print " $c\n";
1571                 }
1572     }
1573 }
1574
1575
1576 sub updateAccess {
1577     my $name = shift @_;
1578     my $callType = shift @_;
1579
1580     $name = $alias{$name} if (defined $alias{$name});
1581
1582     my $type = $data{$name};
1583     if ($type->{category} eq 'struct' || $type->{category} eq 'union') {
1584                 if ($callType =~ m/const/) {
1585                         $accessMode{$name} |= 2;
1586                 } else {
1587                         $accessMode{$name} |= 1;
1588                 }
1589
1590                 # handle any nested types too for this parameter
1591                 foreach $p (@{$type->{members}}) {
1592                         updateAccess($p->{baseType}, $callType);
1593                 }
1594     }
1595 }
1596
1597 # determine which structures are input only or output only
1598 # i.e. const or not-const
1599 foreach $x (values %functionSets) {
1600     foreach $y (@{$x}) {
1601                 my $cmd = $commands{$y};
1602
1603                 foreach $p (@{$cmd->{params}}) {
1604                         updateAccess($p->{baseType}, $p->{fullType});
1605                 }
1606     }
1607 }
1608
1609 # look for all 'create' functions - last parameter is a writeable handle*
1610 # also work out which ones are static or not - first parameter is (dispatchable?) handle
1611 %functionCreate = ();
1612 foreach $x (values %functionSets) {
1613     foreach $y (@{$x}) {
1614                 my $cmd = $commands{$y};
1615                 my @params = @{$cmd->{params}};
1616
1617                 my $first = $params[0];
1618                 my $last = $params[$#params];
1619
1620                 # handle parent also?
1621                 my $firstFullType = $first->{fullType};
1622                 my $lastFullType = $last->{fullType};
1623
1624                 next if !defined $data{$first->{baseType}};
1625                 next if !defined $data{$last->{baseType}};
1626
1627                 my $static = !($data{$first->{baseType}}->{type} eq 'VK_DEFINE_HANDLE'
1628                                            && ($firstFullType =~ tr/*/*/ == 0));
1629                 my $create = (!($lastFullType =~ m/const/)
1630                                           && ($lastFullType =~ tr/*/*/ == 1)
1631                                           && !$last->{len}
1632                                           && ($data{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE'
1633                                                   || $data{$last->{baseType}}->{type} eq 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'));
1634
1635                 if ($create) {
1636                         # print "Create function $y\n";
1637                         # print "  static\n" if $static;
1638                         # print '$data{$last->{baseType}}->{type} = ';
1639                         # print "$data{$last->{baseType}}->{type}\n";
1640                         # print Dumper($cmd);
1641                         # print "first ".Dumper($first);
1642                         # print "last ".Dumper($last);
1643                         $functionCreate{$cmd->{proto}->{name}} = {
1644                                 create => $create,
1645                                 static => $static
1646                         };
1647                 }
1648     }
1649 }
1650
1651 # dump all to-dump types
1652 if (0) {
1653     foreach $x (sort keys %dump) {
1654                 my $d = $dump{$x};
1655                 my $name = $d->{name};
1656
1657                 $name = $alias{$name} if (defined $alias{$name});
1658
1659                 print "----\n";
1660                 print Dumper($d);
1661
1662                 if ($d->{category} eq "command") {
1663                         print Dumper($commands{$name});
1664                 } else {
1665                         print Dumper($data{$name});
1666                 }
1667                 print "\n";
1668     }
1669 }
1670
1671
1672
1673 # debug shit
1674 #exportFunction(STDOUT, $commands{'vkGetDeviceProcAddr'});
1675
1676 if (0) {
1677     print "layout\n";
1678     print formatLayout($data{'VkAccelerationStructureInfoNV'});
1679     print "\n";
1680     $name = 'VkAccelerationStructureInfoNV';
1681     while (defined($name)) {
1682                 my $s = $data{$name};
1683
1684                 print "$name:\n";
1685                 print Dumper($s);
1686                 $name = $alias{$name};
1687     }
1688     exit 0;
1689 }
1690
1691 # ######################################################################
1692 # The main output routine
1693
1694 #my $cmd = $commands{'vkGetQueueCheckpointDataNV'};
1695 #print Dumper($cmd);
1696 #dumpFunctionPrototype($cmd);
1697 #exit 0;
1698
1699 $baseDir = $targetPackage;
1700 $baseDir =~ s@\.@.@g;
1701 $baseDir = $targetDirectory.'/'.$baseDir;
1702
1703 make_path($baseDir);
1704
1705 # dump all structure (and enum?) types
1706 foreach $x (sort keys %dump) {
1707     my $d = $dump{$x};
1708
1709     next if $toDrop{$d->{name}};
1710     next if ($d->{category} eq 'command');
1711
1712     my $name = $d->{name};
1713     my $s = $data{$name};
1714
1715     if ($s->{category} eq "struct" || $s->{category} eq 'union') {
1716                 my @members = @{$s->{members}};
1717                 my $isTyped = $#members >= 1
1718                         && $members[0]->{name} eq "sType"
1719                         && $members[1]->{name} eq "pNext";
1720
1721                 # TODO: handle 'len' and 'altlen' for accessor setup
1722                 # TODO: find out which are input and which are output values
1723                 # TODO: could use the function parameters
1724
1725                 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
1726
1727                 # look for complete override
1728                 if (open(my $template, "<", "template/$s->{name}.java")) {
1729                         print $f "// << inserted from: 'template/$s->{name}.java'\n";
1730                         while (<$template>) {
1731                                 print $f $_;
1732                         }
1733                         close ($template);
1734                         next;
1735                 }
1736
1737                 print $f "package $targetPackage;\n";
1738                 print $f "import jdk.incubator.foreign.*;\n";
1739                 print $f "import java.lang.invoke.*;\n";
1740
1741                 print $f "public final class $s->{name} implements Memory.Addressable {\n";
1742
1743                 print $f "\tfinal MemorySegment segment;\n";
1744
1745                 print $f "\t$s->{name}(MemorySegment segment) {\n";
1746                 print $f "\t\tthis.segment = segment;\n";
1747                 if ($isTyped && $members[0]->{values}) {
1748                         print $f "\t\tsegment.set(Memory.INT, 0, VkStructureType.$members[0]->{values});\n";
1749                 }
1750                 print $f "\t}\n";
1751
1752                 print $f "\tpublic final MemoryAddress address() { return segment.address(); }\n";
1753
1754                 # basic factory methods
1755                 print $f "\tpublic static $s->{name} create(Frame frame) {\n";
1756                 print $f "\t\treturn new $s->{name}(frame.allocate(LAYOUT));\n";
1757                 print $f "\t}\n\n";
1758
1759                 if (!$isTyped) {
1760                         print $f "\tpublic static $s->{name} createArray(Frame frame, long count) {\n";
1761                         print $f "\t\treturn new $s->{name}(frame.allocateArray(LAYOUT, count));\n";
1762                         print $f "\t}\n\n";
1763                 }
1764
1765                 print $f "\tpublic static $s->{name} create(ResourceScope scope) {\n";
1766                 print $f "\t\treturn new $s->{name}(MemorySegment.allocateNative(LAYOUT, scope));\n";
1767                 print $f "\t}\n\n";
1768
1769                 if (!$isTyped) {
1770                         print $f "\tpublic static $s->{name} createArray(ResourceScope scope, long count) {\n";
1771                         print $f "\t\treturn new $s->{name}(MemorySegment.allocateNative(LAYOUT.byteSize() * count, scope));\n";
1772                         print $f "\t}\n\n";
1773                 }
1774
1775                 # factory for all arguments for non-readonly types
1776                 # This should only be for typed types i think
1777                 # actually it should be always for typed types?
1778
1779                 # FIXME: embedded arrays are ignored and only accessed via getters
1780                 #        ... but if they're primitive arrays they should probably be included as basically inlined
1781
1782                 #if ($isTyped && $#members > 1  && (!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 2))) {
1783                 if (!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 2)) {
1784                         # ignore next two here
1785                         my @range = @members[($isTyped ? 2 : 0) .. $#members];
1786                         # analyse first TODO: put elsewhere
1787                         my $totalArgs = 0;
1788
1789                         foreach $m (@range) {
1790                                 my $jtype = functionJavaType($m);
1791
1792                                 # hmm, only if short?
1793                                 if ($jtype eq 'String[]' && $m->{len} =~ m/([^,]+),?/) {
1794                                         my $count = find($1, \@range);
1795
1796                                         if (defined($count)) {
1797                                                 $count->{lenType} = 'implied-count';
1798                                                 $m->{lenType} = 'implied';
1799                                                 $m->{lenTarget} = $count->{name};
1800                                         }
1801                                 }
1802
1803                                 $m->{functionJavaType} = $jtype;
1804                                 $m->{functionDescriptor} = functionDescriptorType($m);
1805
1806                                 if ($m->{fullType} =~ m/\[(.+)\]/) {
1807                                         my $prim = $typeToJavaPrimitive{$m->{baseType}};
1808                                         my $repeat = $1;
1809
1810                                         $repeat = $apiConstants{$repeat} if defined $apiConstants{$repeat};
1811
1812                                         if ($prim && $repeat <= 9) {
1813                                                 $m->{shortPrimitiveArrayLength} = $repeat;
1814                                                 $m->{shortPrimitiveArrayType} = $prim;
1815                                                 $totalArgs += $repeat;
1816                                         }
1817                                 } elsif (!($m->{functionDescriptor} =~ m/\.LAYOUT$/)) {
1818                                         $totalArgs += 1;
1819                                 }
1820                         }
1821
1822                         # complex factories()
1823                         if ($totalArgs > 0 && $s->{category} eq 'struct') {
1824                                 print $f "\tpublic static $s->{name} create(\n";
1825                                 print $f "\t\tFrame frame";
1826                                 foreach $m (@range) {
1827                                         my $jtype = functionJavaType($m);
1828
1829                                         next if ($m->{lenType} eq 'implied-count');
1830                                         # ignore embedded structs and handle arrays
1831                                         next if ($m->{functionDescriptor} =~ m/\.LAYOUT$/);
1832
1833                                         if ($m->{shortPrimitiveArrayLength}) {
1834                                                 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1835                                                         print $f ",\n";
1836                                                         print $f "\t\t$m->{shortPrimitiveArrayType} $m->{name}\$$i";
1837                                                 }
1838                                         } else {
1839                                                 print $f ",\n";
1840                                                 print $f "\t\t$jtype $m->{name}";
1841                                         }
1842                                 }
1843                                 print $f ") {\n";
1844                                 print $f "\t\t$s->{name} self = create(frame);\n";
1845
1846                                 # Should probably just call set methods, but that's a pain to do here
1847                                 foreach $m (@range) {
1848                                         my $jtype = functionJavaType($m);
1849
1850                                         next if ($m->{lenType} eq 'implied-count');
1851                                         # ignore embedded structs and arrays
1852                                         next if ($m->{functionDescriptor} =~ m/\.LAYOUT$/);
1853                                         next if ($m->{fullType} =~ m/\[.*\]/ && !$m->{shortPrimitiveArrayLength});
1854
1855                                         if ($jtype eq 'String' || $jtype eq 'String[]') {
1856                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, frame.copy($m->{name}).address());\n";
1857                                                 if ($m->{lenType} eq 'implied') {
1858                                                         print $f "\t\t$m->{lenTarget}\$VH.set(self.segment, $m->{name} != null ? $m->{name}.length : 0);\n";
1859                                                 }
1860                                         } elsif (defined($data{$jtype})) {
1861                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1862                                         } elsif ($m->{shortPrimitiveArrayLength}) {
1863                                                 print $f "$jtype $m->{name}\$array = self.get".ucfirst($m->{name})."();\n";
1864                                                 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1865                                                         print $f "$m->{name}\$array.setAtIndex($i, $m->{name}\$$i);\n";
1866                                                 }
1867                                         } elsif ($jtype =~ m/$Memory.*Array/) {
1868                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1869                                         } elsif ($jtype =~ m/^MemoryAddress|MemorySegment$/) {
1870                                                 # or maybe not, force the caller to use MemoryAddress.NULL?
1871                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1872                                         } else {
1873                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, $m->{name});\n";
1874                                         }
1875                                 }
1876                                 print $f "\t\treturn self;\n";
1877                                 print $f "\t}\n";
1878                         }
1879
1880                         if ($totalArgs > 0 && $s->{category} eq 'union') {
1881                                 for $m (@range) {
1882                                         next if ($m->{lenType} eq 'implied-count');
1883                                         # ignore embedded structs and handle arrays
1884                                         next if ($m->{functionDescriptor} =~ m/\.LAYOUT$/);
1885                                         next if ($m->{fullType} =~ m/\[.*\]/ && !$m->{shortPrimitiveArrayLength});
1886
1887                                         print $f "\tpublic static $s->{name} create".ucfirst($m->{name})."(\n";
1888                                         print $f "\t\tFrame frame";
1889                                         my $jtype = functionJavaType($m);
1890
1891                                         if ($m->{shortPrimitiveArrayLength}) {
1892                                                 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1893                                                         print $f ",\n";
1894                                                         print $f "\t\t$m->{shortPrimitiveArrayType} $m->{name}\$$i";
1895                                                 }
1896                                         } else {
1897                                                 print $f ",\n";
1898                                                 print $f "\t\t$jtype $m->{name}";
1899                                         }
1900
1901                                         print $f ") {\n";
1902                                         print $f "\t\t$s->{name} self = create(frame);\n";
1903
1904                                         print $f "// $jtype\n";
1905                                         if ($jtype eq 'String' || $jtype eq 'String[]') {
1906                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, frame.copy($m->{name}).address());\n";
1907                                                 if ($m->{lenType} eq 'implied') {
1908                                                         print $f "\t\t$m->{lenTarget}\$VH.set(self.segment, $m->{name} != null ? $m->{name}.length : 0);\n";
1909                                                 }
1910                                         } elsif (defined($data{$jtype})) {
1911                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1912                                         } elsif ($m->{shortPrimitiveArrayLength}) {
1913                                                 print $f "$jtype array = self.get".ucfirst($m->{name})."();\n";
1914                                                 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1915                                                         print $f "array.setAtIndex($i, $m->{name}\$$i);\n";
1916                                                 }
1917                                         } elsif ($jtype =~ m/$Memory.*Array/) {
1918                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1919                                         } elsif ($jtype =~ m/^MemoryAddress|MemorySegment$/) {
1920                                                 # or maybe not, force the caller to use MemoryAddress.NULL?
1921                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, Memory.address($m->{name}));\n";
1922                                         } else {
1923                                                 print $f "\t\t$m->{name}\$VH.set(self.segment, $m->{name});\n";
1924                                         }
1925                                         print $f "\t\treturn self;\n";
1926                                         print $f "\t}\n";
1927                                 }
1928                         }
1929                 }
1930
1931
1932                 # accessors
1933                 my @range = $isTyped ? @members[1..$#members] : @members;
1934
1935                 # for arrays of structs, must obviously be sized properly
1936                 print $f "public long length() { return segment.byteSize() / LAYOUT.byteSize(); }\n";
1937
1938                 foreach $m (@range) {
1939                         my $name = $m->{name};
1940                         my $fullType = $m->{fullType};
1941                         my $strip = $fullType =~ tr/*/*/;
1942
1943                         my $jtype = functionJavaType($m);
1944                         my $needFrame = $jtype =~ m/String/;
1945
1946                         # hack
1947                         if ($s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR'
1948                                 && $m->{name} eq 'pGeometries') {
1949                                 $name = 'pGeometries0';
1950                         }
1951
1952                         # cleanup name for setCamelCase()
1953                         $name = ucfirst(substr $name,$strip);
1954
1955                         # FIXME: MemoryAddress types
1956
1957                         if ((!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 2))
1958                                 && !(functionDescriptorType($m) =~ m/\.LAYOUT$/ || $m->{fullType} =~ m/\[.*\]/)) {
1959                                 # non-index
1960                                 print $f "\tpublic void set$name(";
1961                                 print $f "Frame frame, " if ($needFrame);
1962                                 print $f "$jtype value) {\n";
1963                                 if ($jtype eq 'String' || $jtype eq 'String[]') {
1964                                         print $f "\t\t$m->{name}\$VH.set(segment, frame.copy(value).address());\n";
1965                                         # auto-set length of a String[]
1966                                         if ($jtype eq 'String[]' && $m->{len} =~ m/([^,]+),?/) {
1967                                                 my $src = $1;
1968                                                 print $f "\t\t$src\$VH.set(segment, value != null ? value.length : 0);\n";
1969                                         }
1970                                 } elsif (defined($data{$jtype})) {
1971                                         print $f "\t\t$m->{name}\$VH.set(segment, Memory.address(value));\n";
1972                                 } elsif ($jtype =~ m/$Memory.*Array/) {
1973                                         print $f "\t\t$m->{name}\$VH.set(segment, Memory.address(value));\n";
1974                                 } else {
1975                                         print $f "\t\t$m->{name}\$VH.set(segment, value);\n";
1976                                 }
1977                                 print $f "\t}\n";
1978
1979                                 # indexed accessor
1980                                 print $f "\tpublic void set$name(";
1981                                 print $f "Frame frame, " if ($needFrame);
1982                                 print $f "long index, $jtype value) {\n";
1983                                 print $f "\t\tMemorySegment seg = segment.asSlice(index * LAYOUT.byteSize(), LAYOUT.byteSize());\n";
1984                                 if ($jtype eq 'String' || $jtype eq 'String[]') {
1985                                         print $f "\t\t$m->{name}\$VH.set(seg, frame.copy(value).address());\n";
1986                                         # auto-set length of a String[]
1987                                         if ($jtype eq 'String[]' && $m->{len} =~ m/([^,]+),?/) {
1988                                                 my $src = $1;
1989                                                 print $f "\t\t$src\$VH.set(seg, value != null ? value.length : 0);\n";
1990                                         }
1991                                 } elsif (defined($data{$jtype})) {
1992                                         print $f "\t\t$m->{name}\$VH.set(segment, Memory.address(value));\n";
1993                                 } elsif ($jtype =~ m/$Memory.*Array/) {
1994                                         print $f "\t\t$m->{name}\$VH.set(segment, Memory.address(value));\n";
1995                                 } else {
1996                                         print $f "\t\t$m->{name}\$VH.set(segment, value);\n";
1997                                 }
1998                                 print $f "\t}\n";
1999                         }
2000
2001                         if (!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 1) || $m->{fullType} =~ m/\[.*\]/ || functionDescriptorType($m) =~ m/\.LAYOUT$/) {
2002                                 # non-index
2003                                 print $f "\tpublic $jtype get$name() {\n";
2004                                 if ($jtype eq 'String') {
2005                                         print $f "\t\tMemoryAddress ptr = (MemoryAddress)$m->{name}\$VH.get(segment);\n";
2006                                         print $f "\t\treturn ptr.getUtf8String(0);\n";
2007                                 } elsif ($jtype eq 'String[]') {
2008                                         die("not implemented");
2009                                 } elsif (functionDescriptorType($m) =~ m/\.LAYOUT$/) {
2010                                         print $f "\t\tMemoryLayout.PathElement pe = MemoryLayout.PathElement.groupElement(\"$m->{name}\");\n";
2011                                         print $f "\t\treturn new $jtype(segment.asSlice(LAYOUT.byteOffset(pe), LAYOUT.select(pe).byteSize()));\n";
2012                                 } elsif ($m->{fullType} =~ m/\[.+\]/) {
2013                                         print $f "\t\tMemoryLayout.PathElement pe = MemoryLayout.PathElement.groupElement(\"$m->{name}\");\n";
2014                                         print $f "\t\tMemorySegment seg = segment.asSlice(LAYOUT.byteOffset(pe), LAYOUT.select(pe).byteSize());\n";
2015                                         if ($jtype =~ m/^Memory.HandleArray/) {
2016                                                 print $f "\t\treturn new $jtype($m->{baseType}::new, seg);\n";
2017                                         } else {
2018                                                 print $f "\t\treturn new $jtype(seg);\n";
2019                                         }
2020                                 } else {
2021                                         print $f "\t\treturn ($jtype)$m->{name}\$VH.get(segment);\n";
2022                                 }
2023                                 print $f "\t}\n";
2024
2025                                 # indexed accessor FIXME: just run above parameterised with slice offset
2026                                 # alternative something like:
2027                                 # VarHandle getFlagsAtIndex = MemoryLayout.sequenceLayout(VkQueueFamilyProperties.LAYOUT)
2028                                 #    .varHandle(PathElement.sequenceElement(), PathElement.groupElement("queueFlags"));
2029                                 # int flags = (int)getFlagsAtIndex.get(famprops.address(), (long)j);
2030
2031                                 print $f "\tpublic $jtype get$name(long index) {\n";
2032                                 if ($jtype eq 'String') {
2033                                         # FIXME: This looks ... really wrong
2034                                         print $f "\t\tMemoryAddress ptr = (MemoryAddress)$m->{name}\$VH.get(segment.asSlice(index * LAYOUT.byteSize(), LAYOUT.byteSize()));\n";
2035                                         print $f "\t\treturn ptr.getUtf8String(0);\n";
2036                                 } elsif ($jtype eq 'String[]') {
2037                                         die("not implemented");
2038                                 } elsif (functionDescriptorType($m) =~ m/\.LAYOUT$/) {
2039                                         print $f "\t\tMemoryLayout.PathElement pe = MemoryLayout.PathElement.groupElement(\"$m->{name}\");\n";
2040                                         print $f "\t\treturn new $jtype(segment.asSlice(index * LAYOUT.byteSize() + LAYOUT.byteOffset(pe), LAYOUT.select(pe).byteSize()));\n";
2041                                 } elsif ($m->{fullType} =~ m/\[.+\]/) {
2042                                         print $f "\t\tMemoryLayout.PathElement pe = MemoryLayout.PathElement.groupElement(\"$m->{name}\");\n";
2043                                         print $f "\t\tMemorySegment seg = segment.asSlice(index * LAYOUT.byteSize() + LAYOUT.byteOffset(pe), LAYOUT.select(pe).byteSize());\n";
2044                                         if ($jtype =~ m/^Memory.HandleArray/) {
2045                                                 print $f "\t\treturn new $jtype($m->{baseType}::new, seg);\n";
2046                                         } else {
2047                                                 print $f "\t\treturn new $jtype(seg);\n";
2048                                         }
2049                                 } else {
2050                                         print $f "\t\treturn ($jtype)$m->{name}\$VH.get(segment.asSlice(index * LAYOUT.byteSize(), LAYOUT.byteSize()));\n";
2051                                 }
2052                                 print $f "\t}\n";
2053                         }
2054                 }
2055
2056                 # insert template parts
2057                 if (open(my $template, "<", "template/$s->{name}-part.java")) {
2058                         print $f "// << inserted from: 'template/$s->{name}-part.java'\n";
2059                         while (<$template>) {
2060                                 print $f $_;
2061                         }
2062                         close ($template);
2063                 }
2064
2065                 # layout
2066                 foreach $m (@members) {
2067                         print $f "\t// $m->{fullType} $m->{name}\n";
2068                 }
2069
2070                 print $f "\tpublic static final GroupLayout LAYOUT = ";
2071                 print $f formatLayout($s);
2072                 print $f ";\n";
2073                 # varhandles
2074                 foreach $m (@members) {
2075                         # embedded structs are handled as offsets in the accessors
2076                         if (functionDescriptorType($m) =~ m/\.LAYOUT$/) {
2077                                 print $f "\t// static final VarHandle $m->{name}\$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement(\"$m->{name}\"));\n";
2078                         } else {
2079                                 print $f "\tstatic final VarHandle $m->{name}\$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement(\"$m->{name}\"));\n";
2080                         }
2081                 }
2082
2083                 print $f "}\n";
2084                 close($f);
2085     } elsif ($s->{category} eq "enum" || $s->{category} eq 'enum:bitmask') {
2086                 my @members = @{$s->{members}};
2087                 my $type = calcSize($s) == 32 ? "int" : "long";
2088                 my $L = $type eq "long" ? "L" : "";
2089                 my %seen = ();
2090
2091                 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
2092
2093                 print $f "package $targetPackage;\n";
2094                 print $f "public class $s->{name} {\n";
2095
2096                 my $tries = 0;
2097                 do {
2098                         my @later = ();
2099                         foreach $m (@members) {
2100                                 next if ($seen{$m->{name}});
2101
2102                                 if (defined($m->{value})) {
2103                                         print $f "\t/**\n\t * $m->{comment}\n\t*/\n" if ($m->{comment});
2104                                         print $f "\tpublic static final $type $m->{name} = $m->{value}$L;\n";
2105                                         $seen{$m->{name}} = $m;
2106                                 } elsif (defined($m->{alias})) {
2107                                         if ($seen{$m->{alias}}) {
2108                                                 print $f "\t/**\n\t * $m->{comment}\n\t*/\n" if ($m->{comment});
2109                                                 print $f "\tpublic static final $type $m->{name} = $m->{alias};\n";
2110                                                 $seen{$m->{name}} = $m;
2111                                         } else {
2112                                                 push @later, $m;
2113                                         }
2114                                 } else {
2115                                         print Dumper($s);
2116                                         print Dumper($m);
2117                                         die();
2118                                 }
2119                         }
2120                         @members = (@later);
2121                 } while ($#members >= 0 && $tries++ < 5);
2122
2123                 if ($#members >= 0) {
2124                         print Dumper($s);
2125                         print "Left over\n";
2126                         foreach $m (@members) {
2127                                 print Dumper($m);
2128                         }
2129                         print "seen\n";
2130                         foreach $m (keys %seen) {
2131                                 print Dumper($seen{$m});
2132                         }
2133                         die("unable to resolve aliases");
2134                 }
2135
2136                 # FIXME: this shouldn't be necessary, the other generators should just use the right primitive types
2137                 if ($type eq "int") {
2138                         print $f "final static jdk.incubator.foreign.ValueLayout.OfInt LAYOUT = Memory.INT;\n";
2139                 } else {
2140                         print $f "final static jdk.incubator.foreign.ValueLayout.OfLong LAYOUT = Memory.LONG;\n";
2141                 }
2142
2143                 print $f "}\n";
2144                 close($f);
2145
2146     } elsif ($s->{category} eq 'handle') {
2147                 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
2148
2149                 print $f "package $targetPackage;\n";
2150
2151                 print $f "import jdk.incubator.foreign.*;\n";
2152                 print $f "import java.lang.invoke.*;\n";
2153
2154                 print $f "public final class $s->{name} implements Memory.Addressable {\n";
2155
2156                 print $f "\tfinal MemoryAddress address;\n";
2157
2158                 # instances use a different constructor
2159                 if ($s->{type} eq 'VK_DEFINE_HANDLE') {
2160                         print $f "\tfinal DispatchInstance instanceDispatch;\n";
2161                         if ($s->{name} eq "VkInstance") {
2162                                 print $f "\t$s->{name}(MemoryAddress address) {\n";
2163                                 print $f "\t\tthis.address = address;\n";
2164                                 print $f "\t\tthis.instanceDispatch = new DispatchInstance(this, Memory.sharedScope());\n";
2165                                 print $f "\t}\n";
2166
2167                                 print $f "\tpublic static $s->{name} create(MemoryAddress address) {\n";
2168                                 print $f "\t\treturn address != MemoryAddress.NULL ? new $s->{name}(address) : null;\n";
2169                                 print $f "\t}\n\n";
2170                         } elsif ($s->{name} =~ m/^VkPhysicalDevice/) {
2171                                 print $f "\t$s->{name}(MemoryAddress address, DispatchInstance instanceDispatch) {\n";
2172                                 print $f "\t\tthis.address = address;\n";
2173                                 print $f "\t\tthis.instanceDispatch = instanceDispatch;\n";
2174                                 print $f "\t}\n";
2175
2176                                 print $f "\tpublic static $s->{name} create(MemoryAddress address, DispatchInstance instanceDispatch) {\n";
2177                                 print $f "\t\treturn address != MemoryAddress.NULL ? new $s->{name}(address, instanceDispatch) : null;\n";
2178                                 print $f "\t}\n\n";
2179                         } elsif ($s->{name} =~ m/^VkDevice/) {
2180                                 print $f "\tfinal DispatchDevice deviceDispatch;\n";
2181                                 print $f "\t$s->{name}(MemoryAddress address, DispatchInstance instanceDispatch) {\n";
2182                                 print $f "\t\tthis.address = address;\n";
2183                                 print $f "\t\tthis.instanceDispatch = instanceDispatch;\n";
2184                                 print $f "\t\tthis.deviceDispatch = new DispatchDevice(this, Memory.sharedScope());\n";
2185                                 print $f "\t}\n";
2186
2187                                 print $f "\tpublic static $s->{name} create(MemoryAddress address, DispatchInstance instanceDispatch) {\n";
2188                                 print $f "\t\treturn address != MemoryAddress.NULL ? new $s->{name}(address, instanceDispatch) : null;\n";
2189                                 print $f "\t}\n\n";
2190                         } else {
2191                                 print $f "\tfinal DispatchDevice deviceDispatch;\n";
2192                                 print $f "\t$s->{name}(MemoryAddress address, DispatchInstance instanceDispatch, DispatchDevice deviceDispatch) {\n";
2193                                 print $f "\t\tthis.address = address;\n";
2194                                 print $f "\t\tthis.instanceDispatch = instanceDispatch;\n";
2195                                 print $f "\t\tthis.deviceDispatch = deviceDispatch;\n";
2196                                 print $f "\t}\n";
2197
2198                                 print $f "\tpublic static $s->{name} create(MemoryAddress address, DispatchInstance instanceDispatch, DispatchDevice deviceDispatch) {\n";
2199                                 print $f "\t\treturn address != MemoryAddress.NULL ? new $s->{name}(address, instanceDispatch, deviceDispatch) : null;\n";
2200                                 print $f "\t}\n\n";
2201                         }
2202                 } else {
2203                         print $f "\t$s->{name}(MemoryAddress address) {\n";
2204                         print $f "\t\tthis.address = address;\n";
2205                         print $f "\t}\n";
2206
2207                         print $f "\tpublic static $s->{name} create(MemoryAddress address) {\n";
2208                         print $f "\t\treturn address != MemoryAddress.NULL ? new $s->{name}(address) : null;\n";
2209                         print $f "\t}\n\n";
2210
2211                         print $f "\tpublic static Memory.HandleArray<$s->{name}> createArray(Frame frame, long count) {\n";
2212                         print $f "\t\treturn new Memory.HandleArray<>(frame, $s->{name}::new, count);\n";
2213                         print $f "\t}\n\n";
2214
2215                         print $f "\tpublic static Memory.HandleArray<$s->{name}> createArray(ResourceScope scope, long count) {\n";
2216                         print $f "\t\treturn new Memory.HandleArray<>($s->{name}::new, MemorySegment.allocateNative(Memory.POINTER.byteSize() * count, Memory.POINTER.byteAlignment(), scope));\n";
2217                         print $f "\t}\n\n";
2218                 }
2219
2220                 print $f "\tpublic final MemoryAddress address() { return address; }\n";
2221
2222                 # add all methods who take this as the first argument
2223                 if ($s->{type} eq 'VK_DEFINE_HANDLE') {
2224                         print "Handle: $s->{name}\n";
2225
2226                         foreach $c (@{$functionSets{$s->{name}}}) {
2227                                 next if ($alias{$c} || $toDrop{$c});
2228
2229                                 my $cmd = $commands{$c};
2230                                 my $desc = formatFunctionDescriptor($cmd);
2231
2232                                 $desc =~ s/^/\t\t/mg;
2233                                 #print "// MethodHandle $cmd->{name}\n";
2234                                 #print Dumper($cmd);
2235
2236                                 if (!defined $cmd->{extensionType}) {
2237                                         print $f "\tstatic final MethodHandle $cmd->{name}\$FH = Memory.downcall(\n\t\t\"$cmd->{name}\",\n";
2238                                         print $f $desc;
2239                                         print $f ");\n";
2240                                 }
2241
2242                                 print $f "\t/**\n\t * $cmd->{proto}->{fullType} $cmd->{name} (";
2243                                 foreach $m (@{$cmd->{params}}) {
2244                                         print $f " $m->{fullType}";
2245                                 }
2246                                 print $f " )\n";
2247                                 print $f "\t * Requires $cmd->{extensionSource} extension \"$cmd->{extensionName}\"\n" if ($cmd->{extensionType});
2248                                 print $f "\t * Success Codes: $cmd->{successcodes}\n", if $cmd->{successcodes};
2249                                 print $f "\t *   Error Codes: $cmd->{errorcodes}\n", if $cmd->{errorcodes};
2250                                 print $f "\t */\n";
2251
2252                                 if ($functionCreate{$c}) {
2253                                         -                   exportCreateFunction($f, $cmd, 0)
2254                                 } else {
2255                                         exportFunction($f, $cmd, 0);
2256                                 }
2257
2258                                 # if ($c =~ m/^vkCreateDevice|vkGetDeviceQueue$/) {
2259                                 #     exportCreateFunction($f, $cmd, 0);
2260                                 # }
2261                         }
2262
2263                         # and dump the static functions here too
2264                         if ($s->{name} eq "VkInstance") {
2265                                 foreach $c (@{$functionSets{static}}) {
2266                                         next if ($alias{$c} || $toDrop{$c});
2267
2268                                         my $cmd = $commands{$c};
2269                                         my $desc = formatFunctionDescriptor($cmd);
2270
2271                                         $desc =~ s/^/\t\t/mg;
2272
2273                                         #print "// static MethodHandle $cmd->{name}\n";
2274                                         #print Dumper($cmd);
2275
2276                                         print $f "\t// $cmd->{proto}->{fullType} $cmd->{name} (";
2277                                         foreach $m (@{$cmd->{params}}) {
2278                                                 print $f " $m->{fullType}";
2279                                         }
2280                                         print $f " )\n";
2281
2282                                         print $f "\tstatic final MethodHandle $cmd->{name}\$FH = Memory.downcall(\n\t\t\"$cmd->{name}\",\n";
2283                                         print $f $desc;
2284                                         print $f ");\n";
2285
2286                                         # FIXME: need to make these non-static/init at startup, or probably - depending on extensions requested
2287                                         my $d = $dump{$cmd->{name}};
2288                                         if ($d->{extension}) {
2289                                                 print $f "\t// EXTENSION $d->{extension}->{name}\n";
2290                                         }
2291
2292                                         if ($functionCreate{$c}) {
2293                                                 exportCreateFunction($f, $cmd, 1);
2294                                         } else {
2295                                                 exportFunction($f, $cmd, 1);
2296                                         }
2297                                         # if ($c eq 'vkCreateInstance') {
2298                                         #       exportCreateFunction($f, $cmd, 1);
2299                                         # }
2300                                 }
2301                         }
2302
2303                         if (open(my $template, "<", "template/$s->{name}-part.java")) {
2304                                 print $f "// << inserted from: 'template/$s->{name}-part.java'\n";
2305                                 while (<$template>) {
2306                                         print $f $_;
2307                                 }
2308                                 close ($template);
2309                         }
2310                 }
2311
2312                 print $f "}\n";
2313                 close($f);
2314     } else {
2315                 #print "X $s->{category}\n";
2316     }
2317
2318 }
2319
2320 # ###################################################################### #
2321 # create extension handles
2322 my %byExtension = ();
2323 my %byType = ();
2324 my %byHandle = ();
2325 foreach $y (keys %functionSets) {
2326     my $x = $functionSets{$y};
2327     foreach $c (@{$x}) {
2328                 next if ($alias{$c});
2329                 my $cmd = $commands{$c};
2330
2331                 my $d = $dump{$cmd->{name}};
2332                 my $ext = $d->{extension};
2333                 if (defined $ext) {
2334                         push @{$byExtension{$ext->{name}}}, $c;
2335                         push @{$byType{$ext->{type}}}, $c;
2336                         push @{$byHandle{$y}}, "$ext->{type} $c";
2337                 }
2338     }
2339 }
2340
2341 if (0) {
2342         foreach $ext (sort keys %byHandle) {
2343                 print "extension $ext\n";
2344                 foreach $c (sort @{$byHandle{$ext}}) {
2345                         print " $c\n";
2346                 }
2347         }
2348 }
2349
2350 foreach $ext (sort keys %functionByExtensionType) {
2351     my @list = @{$functionByExtensionType{$ext}};
2352     my $className = 'Dispatch'.ucfirst($ext);
2353     my $typeName = ucfirst($ext);
2354
2355     open(my $f, ">", "$baseDir/$className.java") || die("unable to open $baseDir/$s->{name}.java");
2356
2357     print $f "package $targetPackage;\n";
2358
2359     print $f "import jdk.incubator.foreign.*;\n";
2360     print $f "import java.lang.invoke.*;\n";
2361
2362     print $f "final class $className {\n";
2363
2364     my @inits = ();
2365     my $index = 'a';
2366
2367     foreach $c (sort @list) {
2368                 my $cmd = $commands{$c};
2369
2370                 print $f " final MethodHandle $cmd->{name}\$FH;\n";
2371     }
2372
2373     my $count = 0;
2374
2375     print $f " $className(Vk$typeName o, ResourceScope scope) {\n";
2376
2377     foreach $c (sort @list) {
2378                 my $cmd = $commands{$c};
2379                 my $desc = formatFunctionDescriptor($cmd);
2380
2381                 # if ($count == 0) {
2382                 #     print $f " private void init_$index($typeName o, ResourceScope scope) {\n";
2383                 #     push @inits,"init_$index";
2384                 #     $index++;
2385                 # }
2386                 print $f "  $cmd->{name}\$FH = Memory.downcall(\n";
2387                 print $f "    \"$cmd->{name}\",\n";
2388                 print $f "    o.vkGet$typeName"."ProcAddr(\"$cmd->{name}\"),\n";
2389                 print $f $desc;
2390                 print $f ",\n    scope);\n";
2391
2392                 # if ($count++ == 100) {
2393                 #     print $f " }\n";
2394                 #     $count = 0;
2395                 # }
2396     }
2397
2398     #print $f " }\n" if $count;
2399
2400     # foreach $init (@inits) {
2401     #   print $f "  $init(o, scope);\n";
2402     # }
2403     print $f " }\n";
2404
2405     print $f "}\n";
2406 }
2407
2408 if (0) {
2409         print "unexported functions:\n";
2410         foreach $x (values %functionSets) {
2411                 foreach $y (@{$x}) {
2412                         print " $y alias=$alias{$y}\n" if !$commandsExported{$y};
2413                 }
2414         }
2415 }
2416 exit 0;
2417
2418 # functions tst
2419 foreach $x (sort keys %dump) {
2420     my $d = $dump{$x};
2421     my $name = $d->{name};
2422
2423     # use this to check if it's in an alias function, just call the real one
2424     #$name = $alias{$name} if (defined $alias{$name});
2425
2426     if ($d->{category} eq "command") {
2427                 my $cmd = $commands{$name};
2428
2429                 if (defined($cmd)) {
2430                         #print Dumper($d);
2431                         #print Dumper($cmd);
2432                         if (0) {
2433                                 print "\tstatic final MethodHandle $cmd->{name}\$FH = NativeZ.downcall(\n\t\t\"$cmd->{name}\",\n\t\t";
2434                                 dumpFunctionDescriptor($cmd);
2435                                 print ");\n";
2436                         }
2437                         print "\tpublic static ";
2438                         dumpFunctionPrototype($cmd);
2439                         print " {}\n";
2440                         print "\n";
2441                 }
2442     }
2443 }