3 # -*- Mode:perl; perl-indent-level:4;tab-width: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
12 use File::Path qw(make_path);
16 # these can't really be changed yet
17 $targetDirectory = "api";
18 $targetPackage = "zvk";
21 my $cmd = shift(@ARGV);
24 $targetPackage = shift(@ARGV);
25 } elsif ($cmd eq "-d") {
26 $targetDirectory = shift(@ARGV);
27 } elsif ($cmd eq "-v") {
32 $xml = XML::Parser->new(Style => 'Objects');
33 $doc = $xml->parsefile('/usr/share/vulkan/registry/vk.xml');
35 $registry = @{$doc}[0];
38 VkBaseInStructure => 1,
39 VkBaseOutStructure => 1,
40 vkEnumeratePhysicalDeviceGroups => 1,
41 vkEnumeratePhysicalDevices => 1,
42 VkPhysicalDeviceGroupProperties => 1,
43 vkAllocateCommandBuffers => 1,
48 'VkDebugUtilsMessengerCallbackDataEXT' => 3, # actually read-only?
49 'VkClearColorValue' => 3,
50 'VkCommandBufferAllocateInfo' => 3
54 # unused but this documents all INSTANCE creation functions
56 vkCreateInstance => 1,
57 vkEnumeratePhysicalDevices => VkInstance,
58 vkCreateDevice => VkPhysicalDevice,
59 vkAllocateCommandBuffers => VkDevice,
60 vkGetDeviceQueue => VkDevice,
61 vkGetDeviceQueue2 => VkDevice,
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
71 %typeToJavaPrimitive = (
72 uint8_t => 'byte', char => 'byte',
74 int32_t => 'int', uint32_t => 'int', int => 'int',
75 int64_t => 'long', uint64_t => 'long', size_t => 'long',
80 # must only include java primitives
81 %typeSizePrimitive = (
90 # pre-load types from external header files
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' },
100 # from API Constants section
109 %commandsExported = ();
111 # get something of the form
112 # <node>... <type> xxx</type> ... <name>xxx</name></node>
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};
133 $fullType =~ s/^\s+|\s+$//g;
137 baseType => $baseType,
138 fullType => $fullType
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});
152 my $sourceName = shift @_;
153 my $source = shift @_;
156 $sourceName => $source
159 $req{comment} = $z->{comment} if (defined($z->{comment}));
161 if ($z->isa('type')) {
162 $req{category} = 'type';
164 } elsif ($z->isa('command')) {
165 $req{category} = 'command';
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}));
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};
185 if ($category eq 'struct' || $category eq 'union') {
188 foreach $m (grep { $_->isa('member') } @{$t->{Kids}}) {
189 push @members,scanMember($m);
193 category => $category,
195 members => \@members,
199 $data{$struct{name}} = \%struct;
200 } elsif ($category eq "handle") {
201 my $info = scanMember($t);
203 category => $category,
204 name => $info->{name},
205 parent => $t->{parent},
206 objtypeenum => $t->{objtypeenum},
207 type => $info->{baseType},
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
217 my $info = scanMember($t);
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});
226 push @bitmaskTypes, \%struct;
227 # added to %data later
228 } elsif ($category eq "basetype") {
230 my $info = scanMember($t);
232 if ($info->{baseType}) {
233 $struct{category} = $category;
234 $struct{name} = $info->{name};
235 $struct{type} = $info->{baseType};
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;
249 print "$info->{name} '$info->{baseType}' '$info->{fullType}'\n";
253 $data{$struct{name}} = \%struct;
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>
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};
276 $fullType =~ s/^\s+|\s+$//g;
277 $fullType =~ s/\n|VKAPI_PTR//g;
278 $fullType =~ s/ +/ /g;
279 $fullType =~ s/\( +/\(/g;
281 $struct{prototype} = $fullType;
282 $data{$struct{name}} = \%struct;
285 $struct{prototype} = $fullType;
286 $fullType =~ m/typedef (.*) \(\*(.*)\)\((.*)\)/;
287 $struct{result} = $1;
290 foreach $arg (split /,/,$struct{args}) {
291 $arg =~ m/^([^\*]+)(\*)? (.+)$/;
292 push @{$struct{params}}, { name => $3, fullType => $1.$2, baseType=>$1 };
294 #print Dumper(\%struct);
297 $alias{$t->{name}} = $t->{alias};
302 foreach $x (grep { $_->isa('enums') } @{$registry->{Kids}}) {
303 if ($x->{type} eq "enum") {
305 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
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;
319 $data{$enum{name}} = \%enum;
320 } elsif ($x->{type} eq 'bitmask') {
322 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
323 my %info = ( name => $t->{name} );
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}));
331 push @members, \%info;
334 category => "enum:bitmask",
338 $data{$enum{name}} = \%enum;
341 foreach $t (grep { $_->isa('enum') } @{$x->{Kids}}) {
342 if (!defined($t->{alias})) {
344 category => 'enum:define',
346 value => $t->{value},
349 $enum{comment} = $t->{comment} if (defined($t->{comment}));
350 $data{$enum{name}} = \%enum;
351 $apiConstants{$enum{name}} = \%enum;
353 $alias{$t->{name}} = $t->{alias};
359 foreach $x (grep { $_->isa('commands') } @{$registry->{Kids}}) {
360 foreach $y (grep { $_->isa('command') } @{$x->{Kids}}) {
361 if (!defined($y->{alias})) {
365 $cmd{successcodes} = $y->{successcodes} if (defined $y->{successcodes});
366 $cmd{errorcodes} = $y->{errorcodes} if (defined $y->{errorcodes});
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);
376 $cmd{params} = \@params;
378 my $name = $cmd{proto}->{name};
380 if ($cmd{proto}->{fullType} eq "") {
385 $commands{$cmd{name}} = \%cmd;
386 push @commandsList, \%cmd;
389 # want forward ref or not?
390 $alias{$y->{name}} = $y->{alias};
395 foreach $x (grep { $_->isa('feature') } @{$registry->{Kids}}) {
399 number => $x->{number},
400 comment => $x->{comment}
403 foreach $y (grep { $_->isa('require') } @{$x->{Kids}}) {
404 foreach $z (@{$y->{Kids}}) {
405 addRequire(\@requires, $z, 'feature', \%feature);
408 $feature{requires} = \@requires;
410 push @features, \%feature;
413 foreach $x (grep { $_->isa('extensions') } @{$registry->{Kids}}) {
414 foreach $y (grep { $_->isa('extension') } @{$x->{Kids}}) {
417 number => $y->{number},
418 supported => $y->{supported},
423 $extension{requiresExtension} = $y->{requires} if (defined($y->{requires}));
424 $extension{platform} = $y->{platform} if (defined($y->{platform}));
426 foreach $z (grep { $_->isa('require') } @{$y->{Kids}}) {
427 foreach $a (@{$z->{Kids}}) {
428 addRequire(\@requires, $a, 'extension', \%extension);
432 $extension{requires} = \@requires;
434 push @extensions,\%extension;
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") {
450 my $type = $data{$r->{extends}};
451 my %info = ( name => $r->{name} );
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};
470 push @{$type->{members}}, \%info;
471 $dump{$r->{extends}} = { category => 'enum', name => $r->{extends} };
473 my %enum = ( name => $r->{name} );
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};
482 die() if (!defined($enum{type}));
484 # extension? do i care?
485 $dump{$enum{name}} = { category => 'enum:define', name => $enum{name} };
486 $data{$enum{name}} = \%enum;
494 # collate types in each interface
495 # TODO: versions separated? or define one version?
496 foreach $x (@features) {
497 my @requires = @{$x->{requires}};
499 foreach $r (@requires) {
500 patchRequires($x, $r);
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}};
510 foreach $r (@requires) {
511 patchRequires($x, $r);
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};
522 print "unknown bitmask enum requires $x->{requires}\n";
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};
531 print "unknown bitmask enum bitvalues $x->{bitvalues}\n";
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};
539 # these are referenced but don't have any definitions
541 category => $x->{category},
543 members => \@members,
546 $data{$enum{name}} = \%enum;
550 # Analyse length optioons
551 foreach $x (sort keys %dump) {
553 my $name = $d->{name};
555 if ($d->{category} eq "command") {
556 analyseLengthParameters($commands{$name});
557 } elsif ($d->{category} eq "struct") {
558 analyseLengthMembers($data{$name});
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) {
569 if ($d->{category} eq "command") {
570 my $name = $d->{name};
572 $name = $alias{$name} if (defined $alias{$name});
574 my $cmd = $commands{$name};
575 my @params = @{$cmd->{params}};
577 if ($#params >= 0 && defined($data{$params[0]->{fullType}}->{type})) {
578 my $t = $params[0]->{fullType};
580 if (defined($functionSets{$t})) {
581 push @{$functionSets{$t}}, $d->{name};
583 my @list = ( $d->{name} );
584 $functionSets{$t} = \@list;
586 #$set{$params[0]->{fullType}} = 1;
587 #push @{$set{$params[0]->{fullType}}}, $d->{name};
590 push @{$functionSets{static}}, $d->{name};
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};
600 next if ($alias{$c});
601 my $cmd = $commands{$c};
603 my $d = $dump{$cmd->{name}};
604 my $ext = $d->{extension};
606 my $type = $ext->{type};
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
611 my @params = @{$cmd->{params}};
612 if ($params[0]->{baseType} =~ m/^VkInstance|VkPhysicalDevice$/) {
616 push @{$functionByExtensionType{$type}}, $c;
617 $cmd->{extensionType} = $type;
618 $cmd->{extensionSource} = $ext->{type};
619 $cmd->{extensionName} = $ext->{name};
632 print"search $next\n";
635 if (defined($alias{$type})) {
636 $next = $alias{$type};
637 print " goto alias\n";
638 } elsif (defined($data{$type})) {
639 my $d = $data{$type};
641 if ($d->{category} eq "struct") {
643 } elsif ($d->{category} eq "enum") {
645 } elsif ($d->{category} eq "basetype") {
648 print "category: $d->{category}\n";
655 } while (defined $next);
660 sub functionDescriptorType {
662 my $baseType = $p->{baseType};
663 my $fullType = $p->{fullType};
665 if ($fullType =~ m/\*/) {
666 return "Memory.POINTER";
670 # FIXME: This loops to handle a double-alias for some flag types
671 # FIXME: FlagsNV -> FlagsKHR -> FlagBitsKHR
672 # FIXME: maybe fix it elsewhere
674 $baseType = $alias{$baseType} if (defined($alias{$baseType}));
675 $type = $data{$baseType};
677 #print "\n\n$baseType = ".Dumper($type)."\n\n";
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";
686 } while ($baseType =~ m/Flags/ && defined($alias{$baseType}));
688 return 'Memory.'.uc($typeToJavaPrimitive{$baseType}) if ($typeToJavaPrimitive{$baseType});
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") {
699 } elsif ($baseType eq "VkFlags64") {
700 return 'Memory.LONG';
703 $type = $data{$baseType};
705 #print " ** Unhandled base type $baseType full=$fullType nextalias=$alias{$baseType} orig=$p->{baseType}\n";
706 #print Dumper($type);
709 return "$type->{name}.LAYOUT";
715 sub functionJavaType {
717 my $baseType = $p->{baseType};
718 my $fullType = $p->{fullType};
720 my $deref = $fullType =~ tr/*/*/;
722 if ($deref > 0 || $fullType =~ m/\[.*\]/) {
724 if ($p->{len} == 'null-terminated' && $fullType eq 'const char*') {
726 } elsif ($fullType eq "void*") {
727 return "MemoryAddress";
728 } elsif ($p->{len} && $fullType eq 'const char* const*') {
732 $baseType = $alias{$baseType} if (defined($alias{$baseType}));
733 $type = $data{$baseType};
735 # TODO: if len or altlen set, then it's probably an array otherwise it's a holder/pointer
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";
746 return 'Memory.'.ucfirst($typeToJavaPrimitive{$baseType}).'Array' if (defined $typeToJavaPrimitive{$baseType});
748 # handles and some hacks
749 if ($baseType eq "void") {
750 return "Memory.PointerArray";
752 } elsif ($baseType =~ m/^PFN_/) {
753 return "MemoryAddress";
754 #return $type->{name};
755 } elsif ($baseType eq "VK_DEFINE_NON_DISPATCHABLE_HANDLE") {
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';
771 if (defined($alias{$baseType})) {
772 $baseType = $alias{$baseType};
774 $type = $data{$baseType};
776 # TODO: function poitners?
777 #print "lookup $fullType -> unhandled base type $baseType -> $type->{name}\n";
779 if (defined($type->{name})) {
780 return $type->{name};
782 return "MemorySegment";
785 # FIXME: This loops to handle a double-alias for some flag types
786 # FIXME: FlagsNV -> FlagsKHR -> FlagBitsKHR
787 # FIXME: maybe fix it elsewhere
789 $baseType = $alias{$baseType} if (defined($alias{$baseType}));
790 $type = $data{$baseType};
792 #print "\n\n$baseType = ".Dumper($type)."\n\n";
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";
801 } while ($baseType =~ m/Flags/ && defined($alias{$baseType}));
803 return $typeToJavaPrimitive{$baseType} if (defined $typeToJavaPrimitive{$baseType});
805 # handles and some hacks
806 if ($baseType eq "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") {
817 } elsif ($baseType eq "VkFlags64") {
821 if (defined($alias{$baseType})) {
822 $baseType = $alias{$baseType};
824 $type = $data{$baseType};
826 # TODO: function poitners?
827 #print "lookup $fullType -> unhandled base type $baseType -> $type->{name}\n";
829 if (defined($type->{name})) {
830 return $type->{name};
837 sub formatFunctionDescriptor {
839 my $proto = $cmd->{proto};
840 my @params = @{$cmd->{params}};
842 my $type = $data{$proto->{baseType}};
846 if ($proto->{fullType} eq "void") {
847 $desc = "FunctionDescriptor.ofVoid(";
849 $desc = "FunctionDescriptor.of(";
850 $desc .= functionDescriptorType($proto);
854 foreach $param (@params) {
855 $desc .= "," if ($nargs++ > 0);
856 $desc .= functionDescriptorType($param);
857 $desc .= ".withName(\"$param->{name}\")";
860 return prettyFormat($desc);
865 my @list = @{shift @_};
868 return $p if ($p->{name} eq $n);
873 # return the core root type, will be VK_DEFINE_HANDLE for handles, etc
875 my $baseType = shift @_;
878 $baseType = $alias{$baseType} if (defined($alias{$baseType}));
879 $type = $data{$baseType};
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";
892 sub analyseLengthParameters {
894 my @params = @{$cmd->{params}};
896 foreach $param (@params) {
897 if ($param->{len} eq 'null-terminated') {
898 if ($param->{fullType} eq 'const char*') {
899 $param->{lenType} = 'string';
901 die ("unsupported function length type $param->{fullType}");
903 } elsif ($param->{len} =~ m/^(.+),?/) {
905 my $src = find($count, \@params);
907 $src->{lenTarget} = $param->{name};
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/*/*/;
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';
925 $lenType = 'struct-array';
928 $src->{lenType} = $lenType.'-count';
929 $param->{lenType} = $lenType;
934 # can merge with above?
936 sub analyseLengthMembers {
938 my @params = @{$cmd->{members}};
940 foreach $param (@params) {
941 if ($param->{len} eq 'null-terminated') {
942 if ($param->{fullType} eq 'const char*') {
943 $param->{lenType} = 'string';
945 die ("unsupported function length type $param->{fullType}");
947 } elsif ($param->{len} =~ m/^(.+),?/) {
949 my $src = find($count, \@params);
951 $src->{lenTarget} = $param->{name};
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/*/*/;
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';
968 $lenType = 'struct-array';
971 $src->{lenType} = $lenType.'-count';
972 $param->{lenType} = $lenType;
978 sub dumpFunctionPrototype {
980 my $proto = $cmd->{proto};
981 my @params = @{$cmd->{params}};
983 my $type = $data{$proto->{baseType}};
986 if ($proto->{fullType} eq "void") {
989 print functionJavaType($proto);
991 print " $proto->{name}(";
993 foreach $param (@params) {
994 my $lenType = $param->{lenType};
995 my $fullType = $param->{fullType};
996 my $cderef = ($fullType =~ tr/*/*/);
998 #print "\n[ $param->{name} lentype=$lenType ]\n";
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
1004 print ', ' if ($nargs++ > 0);
1007 if ($lenType =~ m/-count$/ && $cderef > 0) {
1008 # count is an output
1009 print $typeToJavaPrimitive{getRootType($param->{baseType})}.'[]';
1010 } elsif ($lenType eq 'string') {
1012 } elsif ($lenType eq 'handle-array') {
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';
1024 print functionJavaType($param);
1027 print $param->{name};
1032 sub formatPrototype {
1034 my $static = shift @_;
1036 my $proto = $cmd->{proto};
1037 my @params = @{$cmd->{params}};
1040 my $jrtype = proto->{fullType} eq 'void' ? 'void' : functionJavaType($proto);
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}(";
1047 # TODO: static or not
1048 foreach $param (@params [($static ? 0 : 1) .. $#params]) {
1049 my $fullType = $param->{fullType};
1050 my $deref = ($fullType =~ tr/*/*/);
1053 next if ($deref == 0 && $lenType eq 'primitive-array-count');
1054 next if ($deref == 0 && $lenType eq 'handle-array-count');
1056 $desc .= ', ' if ($nargs++ > 0);
1058 my $tname = functionJavaType($param);
1059 $tname = $alias{$tname} if (defined $alias{$tname});
1061 $desc .= "$tname $param->{name}";
1065 return ($jrtype, $desc);
1068 # TODO: merge with above, maybe pass in params list for different rnage
1069 # TODO: also return type type
1070 sub formatCreatePrototype {
1072 my $static = shift @_;
1074 my $proto = $cmd->{proto};
1075 my @params = @{$cmd->{params}};
1078 my $jrtype = proto->{fullType} eq 'void' ? 'void' : functionJavaType($proto);
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}(";
1086 # TODO: static or not
1087 foreach $param (@params [($static ? 0 : 1) ..$#params-1]) {
1088 my $fullType = $param->{fullType};
1089 my $deref = ($fullType =~ tr/*/*/);
1092 next if ($deref == 0 && $lenType eq 'primitive-array-count');
1093 next if ($deref == 0 && $lenType eq 'handle-array-count');
1095 $desc .= ', ' if ($nargs++ > 0);
1097 my $tname = functionJavaType($param);
1098 $tname = $alias{$tname} if (defined $alias{$tname});
1100 $desc .= "$tname $param->{name}";
1104 return ($jrtype, $desc);
1107 # exports a non-static member function
1108 # TODO: handle static too
1109 sub exportFunction {
1112 my $static = shift @_;
1113 my ($jrtype, $prototype) = formatPrototype($cmd, $static);
1115 my @params = @{$cmd->{params}};
1117 $commandsExported{$cmd->{proto}->{name}} = 1;
1119 #print Dumper($cmd);
1121 die("cannot have static extensions") if ($static && $cmd->{extensionType});
1123 print $f "\tpublic ";
1124 print $f "static " if $static;
1125 print $f $prototype;
1126 print $f "throws Exception" if ($cmd->{successcodes});
1129 # TODO: only create frame if required?
1131 print $f "\t\t$jrtype res\$code;\n" if ($jrtype ne 'void');
1132 print $f "\t\ttry (Frame frame = Memory.createFrame()) {\n";
1135 foreach $param (@params[($static ? 0 : 1) .. $#params]) {
1136 my $tname = functionJavaType($param);
1137 $tname = $alias{$tname} if (defined $alias{$tname});
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";
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";
1152 print $f "\t\t\t\t(Addressable)address()";
1153 print $f ",\n" if ($index++ > 0);
1156 foreach $param (@params[($static ? 0 : 1) .. $#params]) {
1157 my $tname = functionJavaType($param);
1158 $tname = $alias{$tname} if (defined $alias{$tname});
1160 print $f ",\n" if ($index++ > 0);
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})";
1171 print $f "\t\t\t\t($tname)$param->{name}";
1176 # TODO: create functions how???
1178 # copy any output data back
1179 foreach $param (@params) {
1180 my $tname = functionJavaType($param);
1181 $tname = $alias{$tname} if (defined $alias{$tname});
1183 next if ($param->{fullType} =~ m/const/);
1185 if ($tname =~ m/\[\]$/) {
1186 print $f "\t\t\tMemorySegment.ofArray($param->{name}).copyFrom($param->{name}\$h);\n";
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";
1195 } elsif ($jrtype ne "void") {
1196 print $f "\t\t\treturn res\$code;\n";
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";
1208 # create functions return a handle in their last argument
1209 sub exportCreateFunction {
1212 my $static = shift @_;
1213 my ($jrtype, $prototype) = formatCreatePrototype($cmd, $static);
1215 my @params = @{$cmd->{params}};
1216 my $instanceType = $params[$#params]->{baseType};
1218 $commandsExported{$cmd->{proto}->{name}} = 1;
1221 print $f "\tpublic ";
1222 print $f 'static ' if ($static);
1223 print $f $prototype;
1224 print $f "throws Exception" if ($cmd->{successcodes});
1227 print $f "\t\t$jrtype res\$code;\n" if ($jrtype ne 'void');
1228 print $f "\t\ttry (Frame frame = Memory.createFrame()) {\n";
1231 # CHANGE: return holder
1232 print $f "\t\t\tMemorySegment instance\$h = frame.allocatePointer();\n";
1235 foreach $param (@params[($static ? 0 : 1) .. $#params-1]) {
1236 my $tname = functionJavaType($param);
1237 $tname = $alias{$tname} if (defined $alias{$tname});
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";
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";
1253 print $f "\t\t\t\t(Addressable)address()";
1254 print $f ",\n" if ($index++ > 0);
1258 foreach $param (@params[($static ? 0 : 1) .. $#params-1]) {
1259 my $tname = functionJavaType($param);
1260 $tname = $alias{$tname} if (defined $alias{$tname});
1262 print $f ",\n" if ($index++ > 0);
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})";
1273 print $f "\t\t\t\t($tname)$param->{name}";
1276 # CHANGE: return pointer
1277 print $f ",\n" if ($index++ > 0);
1278 print $f "\t\t\t\t(Addressable)instance\$h.address()";
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});
1288 # next if ($param->{fullType} =~ m/const/);
1290 # if ($tname =~ m/\[\]$/) {
1291 # print $f "\t\t\tMemorySegment.ofArray($param->{name}).copyFrom($param->{name}\$h);\n";
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";
1302 # print $f "\t\treturn $res\$code;\n";
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');
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";
1316 print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0), instanceDispatch, deviceDispatch);\n";
1319 print $f "\t\t\treturn $instanceType.create(instance\$h.get(Memory.POINTER, 0));\n";
1322 print $f "\t\t} catch (Throwable t) { throw new RuntimeException(t); }\n";
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";
1330 print $f "\t\tthrow new Exception(String.format(\"failcode %d\", res\$code));\n" if ($jrtype ne 'void');
1337 'Memory.SHORT' => 16,
1339 'Memory.LONG' => 64,
1340 'Memory.FLOAT' => 32,
1341 'Memory.DOUBLE' => 64,
1342 'Memory.POINTER' => 64
1345 sub calcMemberSize {
1347 my $desc = functionDescriptorType($m);
1351 if (defined $descToSize{$desc}) {
1352 $size = $descToSize{$desc};
1354 } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1356 ($size, $align) = calcSize($data{$1});
1360 print "description='$desc'\n";
1361 die("unknown size");
1364 # handle array types
1365 if ($m->{fullType} =~ m/\[(\d+)\]/) {
1366 #print "array size $m->{fullType} = $1\n";
1368 } elsif ($m->{fullType} =~ m/\[(.+)\]/) {
1369 my $value = $apiConstants{$1}->{value};
1370 #print "array size $m->{fullType} = $1 = $value\n";
1374 #print "member $m->{name} size=$size align=$align\n";
1376 #my $sizeb = $size / 8;
1377 #my $alignb = $align / 8;
1378 #print "size=$size ($sizeb) align=$align ($alignb) desc=$desc\n\n";
1380 return ($size, $align);
1387 return ($s->{bitSize}, $s->{bitAlign}) if (defined $s->{bitSize});
1389 if ($s->{category} eq "struct") {
1392 for $m (@{$s->{members}}) {
1393 my ($size, $align) = calcMemberSize($m);
1395 # my $desc = functionDescriptorType($m);
1399 # if (defined $descToSize{$desc}) {
1400 # $size = $descToSize{$desc};
1401 # } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1402 # $size = calcSize($data{$1});
1405 $maxAlign = $align if $align > $maxAlign;
1407 # if ($size >=8 && $size <= 64) {
1409 # } elsif ($size > 64) {
1415 $sizeof = ($sizeof + $align - 1) & ~($align - 1);
1419 $sizeof = ($sizeof + $maxAlign - 1) & ~($maxAlign-1);
1420 $s->{bitAlign} = $maxAlign;
1421 $s->{bitSize} = $sizeof;
1422 } elsif ($s->{category} eq "union") {
1425 for $m (@{$s->{members}}) {
1426 my $desc = functionDescriptorType($m);
1430 if (defined $descToSize{$desc}) {
1431 $size = $descToSize{$desc};
1432 } elsif ($desc =~ m/^(.+)\.LAYOUT/) {
1433 $size = calcSize($data{$1});
1436 $sizeof = $size if ($size > $sizeof);
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") {
1445 if ($s->{type} eq "VkFlags64") {
1447 $s->{bitAlign} = 64;
1450 $s->{bitAlign} = 32;
1457 return ($s->{bitSize}, $s->{bitAlign});
1464 if ($s->{category} eq 'struct') {
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);
1475 $layout .= ',' if ($index++ > 0);
1476 $layout .= "MemoryLayout.paddingLayout($pad)";
1480 #if ($type =~ m/\.LAYOUT$/) {
1482 if ($m->{fullType} =~ m/\[(\d+)\]/) {
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)";
1493 $layout .= ',' if ($index++ > 0);
1494 $layout .= $type.".withName(\"$m->{name}\")";
1497 my $pad = $sizeof & 63;
1498 $layout .= ',' if ($pad);
1499 $layout .= "MemoryLayout.paddingLayout($pad)" if ($pad);
1501 } elsif ($s->{category} eq "union") {
1504 $layout = 'MemoryLayout.unionLayout(';
1505 for $m (@{$s->{members}}) {
1506 my $type = functionDescriptorType($m);
1507 my ($size, $align) = calcMemberSize($m);
1510 #if ($type =~ m/\.LAYOUT$/) {
1512 if ($m->{fullType} =~ m/\[(\d+)\]/) {
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)";
1522 $layout .= ',' if ($index++ > 0);
1523 $layout .= $type.".withName(\"$m->{name}\")";
1524 $sizeof = $size if ($size > $sizeof);
1526 my $pad = $sizeof & 63;
1527 $layout .= ',' if ($pad);
1528 $layout .= "MemoryLayout.paddingLayout($pad)" if ($pad);
1530 } elsif ($s->{category} eq "enum") {
1531 } elsif ($s->{category} eq "enum:bitmask") {
1533 #print "X $s->{category}\n";
1536 return prettyFormat($layout);
1540 my $java = shift @_;
1542 $java =~ s/\(/\(\n\t/;
1543 $java =~ s/,/,\n\t/g;
1550 #print 'VkAccelerationStructureGeometryTrianglesDataKHR'."\n";
1552 # print formatLayout($data{'VkDeviceOrHostAddressConstKHR'});
1554 # print formatLayout($data{'VkAccelerationStructureGeometryTrianglesDataKHR'});
1555 # print formatLayout($data{'VkApplicationInfo'});
1558 # ($size,$align) = calcSize($data{'VkAccelerationStructureGeometryTrianglesDataKHR'});
1559 # $bytes = $size / 8;
1560 # print "bytes=$bytes bits=$size align=$align\n";
1564 foreach $k (sort keys %functionSets) {
1565 my $list = $functionSets{$k};
1567 print "first: $k\n";
1569 foreach $c (@$list) {
1577 my $name = shift @_;
1578 my $callType = shift @_;
1580 $name = $alias{$name} if (defined $alias{$name});
1582 my $type = $data{$name};
1583 if ($type->{category} eq 'struct' || $type->{category} eq 'union') {
1584 if ($callType =~ m/const/) {
1585 $accessMode{$name} |= 2;
1587 $accessMode{$name} |= 1;
1590 # handle any nested types too for this parameter
1591 foreach $p (@{$type->{members}}) {
1592 updateAccess($p->{baseType}, $callType);
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};
1603 foreach $p (@{$cmd->{params}}) {
1604 updateAccess($p->{baseType}, $p->{fullType});
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}};
1617 my $first = $params[0];
1618 my $last = $params[$#params];
1620 # handle parent also?
1621 my $firstFullType = $first->{fullType};
1622 my $lastFullType = $last->{fullType};
1624 next if !defined $data{$first->{baseType}};
1625 next if !defined $data{$last->{baseType}};
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)
1632 && ($data{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE'
1633 || $data{$last->{baseType}}->{type} eq 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'));
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}} = {
1651 # dump all to-dump types
1653 foreach $x (sort keys %dump) {
1655 my $name = $d->{name};
1657 $name = $alias{$name} if (defined $alias{$name});
1662 if ($d->{category} eq "command") {
1663 print Dumper($commands{$name});
1665 print Dumper($data{$name});
1674 #exportFunction(STDOUT, $commands{'vkGetDeviceProcAddr'});
1678 print formatLayout($data{'VkAccelerationStructureInfoNV'});
1680 $name = 'VkAccelerationStructureInfoNV';
1681 while (defined($name)) {
1682 my $s = $data{$name};
1686 $name = $alias{$name};
1691 # ######################################################################
1692 # The main output routine
1694 #my $cmd = $commands{'vkGetQueueCheckpointDataNV'};
1695 #print Dumper($cmd);
1696 #dumpFunctionPrototype($cmd);
1699 $baseDir = $targetPackage;
1700 $baseDir =~ s@\.@.@g;
1701 $baseDir = $targetDirectory.'/'.$baseDir;
1703 make_path($baseDir);
1705 # dump all structure (and enum?) types
1706 foreach $x (sort keys %dump) {
1709 next if $toDrop{$d->{name}};
1710 next if ($d->{category} eq 'command');
1712 my $name = $d->{name};
1713 my $s = $data{$name};
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";
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
1725 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
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>) {
1737 print $f "package $targetPackage;\n";
1738 print $f "import jdk.incubator.foreign.*;\n";
1739 print $f "import java.lang.invoke.*;\n";
1741 print $f "public final class $s->{name} implements Memory.Addressable {\n";
1743 print $f "\tfinal MemorySegment segment;\n";
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";
1752 print $f "\tpublic final MemoryAddress address() { return segment.address(); }\n";
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";
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";
1765 print $f "\tpublic static $s->{name} create(ResourceScope scope) {\n";
1766 print $f "\t\treturn new $s->{name}(MemorySegment.allocateNative(LAYOUT, scope));\n";
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";
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?
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
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
1789 foreach $m (@range) {
1790 my $jtype = functionJavaType($m);
1792 # hmm, only if short?
1793 if ($jtype eq 'String[]' && $m->{len} =~ m/([^,]+),?/) {
1794 my $count = find($1, \@range);
1796 if (defined($count)) {
1797 $count->{lenType} = 'implied-count';
1798 $m->{lenType} = 'implied';
1799 $m->{lenTarget} = $count->{name};
1803 $m->{functionJavaType} = $jtype;
1804 $m->{functionDescriptor} = functionDescriptorType($m);
1806 if ($m->{fullType} =~ m/\[(.+)\]/) {
1807 my $prim = $typeToJavaPrimitive{$m->{baseType}};
1810 $repeat = $apiConstants{$repeat} if defined $apiConstants{$repeat};
1812 if ($prim && $repeat <= 9) {
1813 $m->{shortPrimitiveArrayLength} = $repeat;
1814 $m->{shortPrimitiveArrayType} = $prim;
1815 $totalArgs += $repeat;
1817 } elsif (!($m->{functionDescriptor} =~ m/\.LAYOUT$/)) {
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);
1829 next if ($m->{lenType} eq 'implied-count');
1830 # ignore embedded structs and handle arrays
1831 next if ($m->{functionDescriptor} =~ m/\.LAYOUT$/);
1833 if ($m->{shortPrimitiveArrayLength}) {
1834 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1836 print $f "\t\t$m->{shortPrimitiveArrayType} $m->{name}\$$i";
1840 print $f "\t\t$jtype $m->{name}";
1844 print $f "\t\t$s->{name} self = create(frame);\n";
1846 # Should probably just call set methods, but that's a pain to do here
1847 foreach $m (@range) {
1848 my $jtype = functionJavaType($m);
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});
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";
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";
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";
1873 print $f "\t\t$m->{name}\$VH.set(self.segment, $m->{name});\n";
1876 print $f "\t\treturn self;\n";
1880 if ($totalArgs > 0 && $s->{category} eq 'union') {
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});
1887 print $f "\tpublic static $s->{name} create".ucfirst($m->{name})."(\n";
1888 print $f "\t\tFrame frame";
1889 my $jtype = functionJavaType($m);
1891 if ($m->{shortPrimitiveArrayLength}) {
1892 for (my $i = 0;$i<$m->{shortPrimitiveArrayLength};$i++) {
1894 print $f "\t\t$m->{shortPrimitiveArrayType} $m->{name}\$$i";
1898 print $f "\t\t$jtype $m->{name}";
1902 print $f "\t\t$s->{name} self = create(frame);\n";
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";
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";
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";
1923 print $f "\t\t$m->{name}\$VH.set(self.segment, $m->{name});\n";
1925 print $f "\t\treturn self;\n";
1933 my @range = $isTyped ? @members[1..$#members] : @members;
1935 # for arrays of structs, must obviously be sized properly
1936 print $f "public long length() { return segment.byteSize() / LAYOUT.byteSize(); }\n";
1938 foreach $m (@range) {
1939 my $name = $m->{name};
1940 my $fullType = $m->{fullType};
1941 my $strip = $fullType =~ tr/*/*/;
1943 my $jtype = functionJavaType($m);
1944 my $needFrame = $jtype =~ m/String/;
1947 if ($s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR'
1948 && $m->{name} eq 'pGeometries') {
1949 $name = 'pGeometries0';
1952 # cleanup name for setCamelCase()
1953 $name = ucfirst(substr $name,$strip);
1955 # FIXME: MemoryAddress types
1957 if ((!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 2))
1958 && !(functionDescriptorType($m) =~ m/\.LAYOUT$/ || $m->{fullType} =~ m/\[.*\]/)) {
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/([^,]+),?/) {
1968 print $f "\t\t$src\$VH.set(segment, value != null ? value.length : 0);\n";
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";
1975 print $f "\t\t$m->{name}\$VH.set(segment, value);\n";
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/([^,]+),?/) {
1989 print $f "\t\t$src\$VH.set(seg, value != null ? value.length : 0);\n";
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";
1996 print $f "\t\t$m->{name}\$VH.set(segment, value);\n";
2001 if (!defined($accessMode{$s->{name}}) || ($accessMode{$s->{name}} & 1) || $m->{fullType} =~ m/\[.*\]/ || functionDescriptorType($m) =~ m/\.LAYOUT$/) {
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";
2018 print $f "\t\treturn new $jtype(seg);\n";
2021 print $f "\t\treturn ($jtype)$m->{name}\$VH.get(segment);\n";
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);
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";
2047 print $f "\t\treturn new $jtype(seg);\n";
2050 print $f "\t\treturn ($jtype)$m->{name}\$VH.get(segment.asSlice(index * LAYOUT.byteSize(), LAYOUT.byteSize()));\n";
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>) {
2066 foreach $m (@members) {
2067 print $f "\t// $m->{fullType} $m->{name}\n";
2070 print $f "\tpublic static final GroupLayout LAYOUT = ";
2071 print $f formatLayout($s);
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";
2079 print $f "\tstatic final VarHandle $m->{name}\$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement(\"$m->{name}\"));\n";
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" : "";
2091 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
2093 print $f "package $targetPackage;\n";
2094 print $f "public class $s->{name} {\n";
2099 foreach $m (@members) {
2100 next if ($seen{$m->{name}});
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;
2120 @members = (@later);
2121 } while ($#members >= 0 && $tries++ < 5);
2123 if ($#members >= 0) {
2125 print "Left over\n";
2126 foreach $m (@members) {
2130 foreach $m (keys %seen) {
2131 print Dumper($seen{$m});
2133 die("unable to resolve aliases");
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";
2140 print $f "final static jdk.incubator.foreign.ValueLayout.OfLong LAYOUT = Memory.LONG;\n";
2146 } elsif ($s->{category} eq 'handle') {
2147 open(my $f, ">", "$baseDir/$s->{name}.java") || die("unable to open $baseDir/$s->{name}.java");
2149 print $f "package $targetPackage;\n";
2151 print $f "import jdk.incubator.foreign.*;\n";
2152 print $f "import java.lang.invoke.*;\n";
2154 print $f "public final class $s->{name} implements Memory.Addressable {\n";
2156 print $f "\tfinal MemoryAddress address;\n";
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";
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";
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";
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";
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";
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";
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";
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";
2203 print $f "\t$s->{name}(MemoryAddress address) {\n";
2204 print $f "\t\tthis.address = address;\n";
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";
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";
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";
2220 print $f "\tpublic final MemoryAddress address() { return address; }\n";
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";
2226 foreach $c (@{$functionSets{$s->{name}}}) {
2227 next if ($alias{$c} || $toDrop{$c});
2229 my $cmd = $commands{$c};
2230 my $desc = formatFunctionDescriptor($cmd);
2232 $desc =~ s/^/\t\t/mg;
2233 #print "// MethodHandle $cmd->{name}\n";
2234 #print Dumper($cmd);
2236 if (!defined $cmd->{extensionType}) {
2237 print $f "\tstatic final MethodHandle $cmd->{name}\$FH = Memory.downcall(\n\t\t\"$cmd->{name}\",\n";
2242 print $f "\t/**\n\t * $cmd->{proto}->{fullType} $cmd->{name} (";
2243 foreach $m (@{$cmd->{params}}) {
2244 print $f " $m->{fullType}";
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};
2252 if ($functionCreate{$c}) {
2253 - exportCreateFunction($f, $cmd, 0)
2255 exportFunction($f, $cmd, 0);
2258 # if ($c =~ m/^vkCreateDevice|vkGetDeviceQueue$/) {
2259 # exportCreateFunction($f, $cmd, 0);
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});
2268 my $cmd = $commands{$c};
2269 my $desc = formatFunctionDescriptor($cmd);
2271 $desc =~ s/^/\t\t/mg;
2273 #print "// static MethodHandle $cmd->{name}\n";
2274 #print Dumper($cmd);
2276 print $f "\t// $cmd->{proto}->{fullType} $cmd->{name} (";
2277 foreach $m (@{$cmd->{params}}) {
2278 print $f " $m->{fullType}";
2282 print $f "\tstatic final MethodHandle $cmd->{name}\$FH = Memory.downcall(\n\t\t\"$cmd->{name}\",\n";
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";
2292 if ($functionCreate{$c}) {
2293 exportCreateFunction($f, $cmd, 1);
2295 exportFunction($f, $cmd, 1);
2297 # if ($c eq 'vkCreateInstance') {
2298 # exportCreateFunction($f, $cmd, 1);
2303 if (open(my $template, "<", "template/$s->{name}-part.java")) {
2304 print $f "// << inserted from: 'template/$s->{name}-part.java'\n";
2305 while (<$template>) {
2315 #print "X $s->{category}\n";
2320 # ###################################################################### #
2321 # create extension handles
2322 my %byExtension = ();
2325 foreach $y (keys %functionSets) {
2326 my $x = $functionSets{$y};
2327 foreach $c (@{$x}) {
2328 next if ($alias{$c});
2329 my $cmd = $commands{$c};
2331 my $d = $dump{$cmd->{name}};
2332 my $ext = $d->{extension};
2334 push @{$byExtension{$ext->{name}}}, $c;
2335 push @{$byType{$ext->{type}}}, $c;
2336 push @{$byHandle{$y}}, "$ext->{type} $c";
2342 foreach $ext (sort keys %byHandle) {
2343 print "extension $ext\n";
2344 foreach $c (sort @{$byHandle{$ext}}) {
2350 foreach $ext (sort keys %functionByExtensionType) {
2351 my @list = @{$functionByExtensionType{$ext}};
2352 my $className = 'Dispatch'.ucfirst($ext);
2353 my $typeName = ucfirst($ext);
2355 open(my $f, ">", "$baseDir/$className.java") || die("unable to open $baseDir/$s->{name}.java");
2357 print $f "package $targetPackage;\n";
2359 print $f "import jdk.incubator.foreign.*;\n";
2360 print $f "import java.lang.invoke.*;\n";
2362 print $f "final class $className {\n";
2367 foreach $c (sort @list) {
2368 my $cmd = $commands{$c};
2370 print $f " final MethodHandle $cmd->{name}\$FH;\n";
2375 print $f " $className(Vk$typeName o, ResourceScope scope) {\n";
2377 foreach $c (sort @list) {
2378 my $cmd = $commands{$c};
2379 my $desc = formatFunctionDescriptor($cmd);
2381 # if ($count == 0) {
2382 # print $f " private void init_$index($typeName o, ResourceScope scope) {\n";
2383 # push @inits,"init_$index";
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";
2390 print $f ",\n scope);\n";
2392 # if ($count++ == 100) {
2398 #print $f " }\n" if $count;
2400 # foreach $init (@inits) {
2401 # print $f " $init(o, scope);\n";
2409 print "unexported functions:\n";
2410 foreach $x (values %functionSets) {
2411 foreach $y (@{$x}) {
2412 print " $y alias=$alias{$y}\n" if !$commandsExported{$y};
2419 foreach $x (sort keys %dump) {
2421 my $name = $d->{name};
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});
2426 if ($d->{category} eq "command") {
2427 my $cmd = $commands{$name};
2429 if (defined($cmd)) {
2431 #print Dumper($cmd);
2433 print "\tstatic final MethodHandle $cmd->{name}\$FH = NativeZ.downcall(\n\t\t\"$cmd->{name}\",\n\t\t";
2434 dumpFunctionDescriptor($cmd);
2437 print "\tpublic static ";
2438 dumpFunctionPrototype($cmd);