5 use File::Path qw(make_path);
12 use lib "$FindBin::Bin", 'bin/linux-amd64/lib';
18 $SIG{__DIE__} = sub { Carp::confess( @_ ) };
19 $SIG{'INT'} = sub { Carp::confess() };
20 $Data::Dumper::Indent = 1;
22 # ###################################################################### #
41 # all seen types for dev only
44 # ###################################################################### #
45 my $vk = new vulkan();
47 my $api = $vk->buildFeatures(
48 [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ],
55 $sys->{output} = 'bin/gen/notzed.vulkan/classes';
56 $sys->{package} = 'vulkan';
59 my $structTypes = loadTypes($api, 'struct-types.api');
60 my $commandTypes = loadTypes($api, 'command-types.api');
62 analyseTypes($vk, $api);
67 foreach my $s (values %{$api->{types}}) {
68 my $overrides = $structTypes->{overrides};
69 my $types = $structTypes->{types};
71 next if (defined($overrides->{$s->{name}}));
74 map { $lengths{$_->{lengthfrom}}++ if $_->{lengthfrom} } @{$s->{items}};
76 foreach my $m (@{$s->{items}}) {
77 my $nstar = $m->{deref} =~ tr/*/*/;
79 # FIXME: this belongs in analyse
80 if ($m->{lengthfrom} && $lengths{$m->{lengthfrom}} != 1) {
81 $m->{'set-length'} = '';
84 if ($m->{lengthfor} && $nstar == 0 && $lengths{$m->{name}} == 1) {
85 $overrides->{$s->{name}}->{$m->{name}}->{type} = $m->{deref}.'-implied';
87 if ($m->{deref} eq 'struct*-length') {
88 $defaultTemplate{$m->{baseType}}->{array} = 1;
89 } elsif ($m->{deref} eq 'struct[]') {
90 $defaultTemplate{$m->{baseType}}->{array} = 1;
94 if ($s->{returnedonly} eq 'true') {
95 $defaultTemplate{$s->{name}}->{name} = 'struct-readonly';
99 # build default overrides for commands
100 foreach my $s (values %{$api->{commands}}) {
101 my $overrides = $commandTypes->{overrides};
102 my $types = $commandTypes->{types};
104 # check type updates anyway
105 foreach my $m (@{$s->{items}}) {
106 if ($m->{deref} eq 'struct*-length') {
107 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
108 $defaultTemplate{$m->{baseType}}->{array} = 1;
109 } elsif ($m->{deref} eq 'struct*') {
110 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
114 next if (defined($overrides->{$s->{name}}));
116 my $first = $s->{items}->[0];
117 my $last = $s->{items}->[$#{$s->{items}}];
118 my $result = $s->{proto};
119 my $index = $s->{index};
121 #map { $index->{$_->{name}} = $_ } @{$s->{items}};
125 # force handles to be instance types
126 if ($first->{deref} eq 'handle') {
127 $override->{$first->{name}}->{type} = 'instance';
130 # extension functions
131 if (defined($s->{extensions})) {
132 $override->{template} = $commandTypes->{templates}->{'method-extension'};
135 if ($last->{deref} eq 'handle*') {
137 my $t = $api->{handles}->{$last->{baseType}};
138 print "constructor: $s->{name}\n";# if $sys->{verbose};
139 $override->{$last->{name}}->{type} =
140 $t->{type} eq 'VK_DEFINE_HANDLE' && $t->{name} ne 'VkInstance' ?
141 'dispatch*-output' : 'handle*-output';
142 } elsif ($index->{$last->{len}}) {
143 print "constructor?: $s->{name}\n";# if $sys->{verbose};
146 print "allocate-constructor?: $s->{name} $last->{len}\n";# if $sys->{verbose};
150 # ones we care about with output
156 if ($s->{successcodes} =~ m/VK_INCOMPLETE/ && $last->{deref} =~ m/-length$/) {
157 my $protoa = "$result->{fullType} $s->{name}("
158 .join(', ', map { "$_->{fullType}" } @{$s->{items}})
160 my $protob = "$result->{deref} $s->{name}("
161 .join(', ', map { $_->{len} ? "$_->{deref} \[$_->{len}\]" : $_->{deref} } @{$s->{items}})
164 print "array-constructor: $protoa\n";
165 print "array-constructor: $protob\n";
166 $override->{template} =
167 defined($s->{extensions}) ?
168 $commandTypes->{templates}->{'method-extension-query'} :
169 $commandTypes->{templates}->{'method-query'};
170 foreach my $m (@{$s->{items}}) {
171 if ($m->{deref} =~ m/-length$/ && (my $len = $index->{$m->{len}})) {
174 if ($m->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE') {
175 $type = 'dispatch*-length-query';
177 $type = $m->{deref}.'-query';
180 die "no template $m->{deref}-query" if !defined($commandTypes->{types}->{$type});
181 $override->{$m->{name}}->{type} = $type;
183 die "no template $len->{deref}-querysize" if !defined($commandTypes->{types}->{$len->{deref}.'-querylen'});
184 $override->{$len->{name}}->{type} = $len->{deref}.'-querylen';
189 # other per-item things
190 foreach my $m (@{$s->{items}}) {
191 my $so = $structTypes->{overrides}->{$m->{baseType}};
194 $m->{deref} .= '-ignore';
197 if ($m->{lengthfor}) {
198 my $nstar = $m->{deref} =~ tr/*/*/;
200 die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
201 $override->{$m->{name}}->{type} = $m->{deref}.'-length';
203 if (defined($s->{extensions})) {
204 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-extension'};
205 print "length-extension: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
207 #die "No '$m->{deref}-output' type ".Dumper($s) if !defined $types->{$m->{deref}.'-otuput'};
209 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-query'};
210 #$overrides->{$s->{name}}->{$m->{name}}->{type} = $types->{$m->{deref}.'-output'};
212 print "length: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
216 # TODO: implied return things
220 $overrides->{$s->{name}} = $override if %{$override};
224 my $overrides = $structTypes->{overrides};
225 my $templates = $structTypes->{templates};
227 print Dumper(\%defaultTemplate);
229 foreach my $k (keys %defaultTemplate) {
230 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
231 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
233 my $t = $defaultTemplate{$k};
234 my $name = $t->{name} || "struct-writeonly";
236 $name .= "-array" if $t->{array};
239 die "No override $k $name" if !$templates->{$name};
240 $overrides->{$k}->{template} = $templates->{$name};
245 #$overrides->{$s->{name}}->{template} = $structTypes->{templates}->{'struct-readonly'};
247 #print Dumper({ types=>$types, templates=>$templates });
250 open(my $f, '>', 'types.pm');
251 print $f Dumper($commandTypes, $structTypes);
257 open(my $f, '>', 'api.pm');
258 print $f Dumper($api);
264 open(my $f, '>', 'data.pm');
266 'handles' => $api->{handles},
267 'types' => $api->{types},
268 'commands' => $api->{commands},
269 'funcpointers' => $api->{funcpointers},
275 my $f = openOutput($sys, "API");
277 print $f "package vulkan;\n";
278 print $f "import jdk.incubator.foreign.*;\n";
279 print $f "import java.lang.invoke.*;\n";
280 print $f "import au.notzed.nativez.*;\n";
281 print $f "public class API {\n";
282 print $f "MemoryAddress self;\n";
284 foreach my $c (values %{$api->{commands}}) {
285 die if ($c->{alias});
286 #print "$c->{name}\n";
287 print $f formatFunction($api, $commandTypes, $c)."\n";
288 #print formatFunctionDescriptor($commandTypes, $c)."\n";
291 closeOutput($sys, "API", $f);
294 exportEnums($vk, $api, 'VkConstants');
296 # dump out the extension function tables
298 my $f = openOutput($sys, 'DispatchInstance');
299 my $template = $structTypes->{templates}->{dispatch};
303 foreach my $k (sort keys %{$api->{commands}}) {
304 my $c = $api->{commands}->{$k};
306 next if !defined($c->{extensions});
308 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
309 push @init, code::formatTemplate($template->{'init'}, $c);
315 Name => 'DispatchInstance',
316 init => join("\n\t\t", @init),
317 'field-init' => join("\n\t", @fieldInit),
319 print $f code::formatTemplateStream($template->{class}, $vars);
321 closeOutput($sys, 'DispatchInstance', $f);
326 foreach my $k (sort keys %{$api->{types}}) {
327 my $s = $api->{data}->{$k};
332 my $override = $structTypes->{overrides}->{$s->{name}};
334 next if $override->{ignore};
336 my $f = openOutput($sys, $s->{Name});
337 print $f formatStruct($vk, $api, $s);
338 closeOutput($sys, $s->{Name}, $f);
341 foreach my $k (sort keys %{$api->{handles}}) {
342 my $s = $api->{data}->{$k};
347 my $f = openOutput($sys, $s->{name});
348 print $f formatHandle($vk, $api, $s);
349 closeOutput($sys, $s->{name}, $f);
352 foreach my $k (sort keys %{$api->{funcpointers}}) {
353 my $s = $api->{data}->{$k};
358 my $override = $commandTypes->{overrides}->{$s->{name}};
360 next if $override->{ignore};
362 my $f = openOutput($sys, $s->{name});
363 print $f formatFunctionPointer($vk, $api, $s);
364 closeOutput($sys, $s->{name}, $f);
370 #print Dumper (grep { !defined $_->{items} } values %{$api->{enums}});
372 #print Dumper($api->{data});
374 print "Unique Types:\n";
375 foreach my $k (sort keys %$all) {
381 foreach my $k (sort keys %{$api->{commands}}) {
382 my $c = $api->{commands}->{$k};
386 foreach my $m ($c->{proto}, @{$c->{items}}) {
387 my $t = $vk->{data}->{$m->{baseType}};
389 die if !defined $m->{baseType};
390 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
392 while ($t->{alias}) {
393 print "Alias: $t->{name} -> $t->{alias}\n";
394 $t = $vk->{data}->{$t->{alias}};
401 foreach my $k (sort keys %{$vk->{index}}) {
408 foreach my $k (sort keys %{$vk->{types}}) {
409 my $s = $vk->{types}->{$k};
411 foreach my $m (@{$s->{items}}) {
412 my $t = $vk->{data}->{$m->{baseType}};
414 die if !defined $m->{baseType};
415 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
417 while ($t->{alias}) {
418 print "Alias: $t->{name} -> $t->{alias}\n";
419 $t = $vk->{data}->{$t->{alias}};
422 $masks->{$t->{name}} = $t if ($t->{category} eq 'bitmask');
423 $enums->{$t->{name}} = $t if ($t->{category} eq 'enum');
427 print Dumper($masks);
428 foreach my $k (sort keys %{$masks}) {
429 my $s = $masks->{$k};
432 if ($s->{requires}) {
433 $t = $vk->{data}->{$s->{requires}};
434 } elsif ($s->{name} =~ m/(.*)Flags([0-9A-Z]*)/o && defined $vk->{data}->{"$1FlagBits$2"}) {
435 print "> $s->{name} $1FlagBits$2\n";
436 $t = $vk->{data}->{"$1FlagBits$2"};
438 print "? $s->{name}\n";
441 print "! $s->{name} r=$s->{requires}\n" if !defined($t);
450 my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
456 foreach my $t (@{$config->{objects}}) {
457 if ($t->{type} eq 'type') {
458 my $nopts = $#{$t->{options}};
461 if ($nopts >= 0 && defined($types->{$t->{options}->[0]})) {
462 $type = { %{$types->{$t->{options}->[0]}} };
463 } elsif ($#{$t->{items}} >= 0) {
466 die ("No prototype provided/found for empty type ".Dumper($t));
469 if ($#{$t->{items}} >= 0) {
470 foreach my $s (@{$t->{items}}) {
472 code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
475 $x->{eval} = 1 if config::optionFlag('eval', $s);
477 $type->{$s->{match}} = $x;
481 # check other options
482 foreach my $o (@{$t->{options}}) {
483 if ($o =~ m/^accessor=(.*)$/o) {
484 die "No template $1" if !defined($templates->{$1});
485 $type->{accessor} = $templates->{$1};
486 } elsif ($o eq 'need-frame') {
487 $type->{'need-frame'} = 1;
488 } elsif ($o eq 'need-scope') {
489 $type->{'need-scope'} = 1;
490 } elsif ($o eq 'trampoline-scope') {
491 $type->{'trampoline-scope'} = 1;
492 } elsif ($o eq 'need-alloc') {
493 $type->{'need-alloc'} = 1;
494 } elsif ($o eq 'is-instance') {
495 $type->{'is-instance'} = 1;
497 # doesn't ignore implied parant type
498 #die "Unknown option '$o' in ".Dumper($t);
502 foreach my $k (split /,/,$t->{name}) {
503 $types->{$k} = $type;
505 } elsif ($t->{type} eq 'code') {
510 foreach my $s (@{$t->{items}}) {
511 $code->{$s->{match}} = $s->{literal};
512 $code->{$s->{match}} =~ s/^\t//gm;
514 foreach my $o (@{$t->{options}}) {
515 if ($o =~ m/insert=(.*)/) {
516 foreach my $t (split /,/,$1) {
517 if ($t =~ m/(.*):(.*)/) {
518 die if !defined $templates->{$1}->{$2};
519 $code->{insert}->{$2} = $templates->{$1}->{$2};
525 $templates->{$t->{name}} = $code;
526 } elsif ($t->{type} eq 'override') {
527 foreach my $s (@{$t->{items}}) {
529 foreach my $o (@{$s->{options}}) {
530 if ($o =~ m/^(.*)=type:(.*)/) {
531 die "No such type $s->{match} $2\n" if !defined $types->{$2};
532 $c->{$1}->{type} = $2;
533 } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
534 die "No accessor template $o" if !defined($templates->{$2});
535 $c->{$1}->{accessor} = $templates->{$2};
536 } elsif ($o =~ m/^template=(.*)/) {
537 die "No template $o" if !defined($templates->{$1});
538 $c->{template} = $templates->{$1};
539 } elsif ($o eq 'ignore') {
543 $overrides->{$s->{match}} = $c;
548 # templates should probably just go in one
551 templates => $templates,
552 overrides => $overrides,
558 return grep { !$seen{$_}++ } @_;
567 my $f = openOutput($sys, $name);
569 print $f "package vulkan;\npublic interface VkConstants {\n";
571 # special case for api constants
572 # special case for api constants
574 my $s = $api->{data}->{'API Constants'};
576 print $f "\n\t// API Constants\n";
578 foreach my $m (@{$s->{items}}) {
579 next if defined($m->{alias});
580 next if $seen->{$m->{name}}++;
582 my $i = $enumInfo->{$m->{type}};
586 $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
588 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
592 foreach my $k (sort keys %{$api->{enums}}) {
593 my $s = $api->{data}->{$k};
594 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
595 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
599 print $f "\n\t// $s->{name} $type\n";
601 foreach my $m (@{$s->{items}}) {
602 next if defined($m->{alias});
603 next if $seen->{$m->{name}}++;
607 $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
609 die Dumper("Ca't work out value", $m, $s) if !defined($v);
610 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
615 closeOutput($sys, $name, $f);
618 # ###################################################################### #
619 # class.name to class/name.java
624 $name = $sys->{package}.'.'.$name;
626 $name = $sys->{output}.'/'.$name.'.java';
634 my $path = classToPath($sys, $name);
637 rename($path.'~', $path) || die ("rename failed: $!");
644 my $path = classToPath($sys, $name);
645 my $dir = dirname($path);
647 make_path($dir) if (!-d $dir);
649 open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
650 print "writing '$path'\n" if $sys->{verbose} > 0;
655 # Calculate canonical derefernce types for each field and parameter
667 map { $index->{$_->{name}} = $_ } @_;
669 $s->{index} = $index;
672 my $t = $api->{data}->{$m->{baseType}};
673 my $nstar = $m->{fullType} =~ tr/*/*/;
678 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
682 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
685 if ($isize =~ m/^\d+$/n) {
688 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
692 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
697 # will be primitive or external
698 $type = $m->{baseType} if ($nstar == 0);
699 $type = "$m->{baseType}*" if ($nstar == 1);
700 $type = "$m->{baseType}**" if ($nstar == 2);
704 while ($t->{alias}) {
705 print "alias $t->{name} -> $t->{alias}\n";
706 $t = $api->{data}->{$t->{alias}};
708 $m->{baseType} = $t->{name};
711 if ($t->{category} =~ m/enum|bitmask/on) {
712 $t = $vk->{data}->{$t->{fullType}};
713 $type = $t->{type} if ($nstar == 0);
714 $type = "$t->{type}*" if ($nstar == 1);
716 } elsif ($t->{category} =~ m/struct|union/on) {
717 $m->{type} = $t->{name};
718 $type = 'struct' if ($nstar == 0);
719 $type = 'struct*' if ($nstar == 1);
720 $type = 'struct**' if ($nstar == 2);
722 } elsif ($t->{category} eq 'handle') {
723 $m->{type} = $t->{name};
724 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
725 # $type = 'dhandle' if ($nstar == 0);
726 # $type = 'dhandle*' if ($nstar == 1);
728 $type = 'handle' if ($nstar == 0);
729 $type = 'handle*' if ($nstar == 1);
732 } elsif ($t->{category} eq 'basetype') {
734 $type = $t->{type} if ($nstar == 0);
735 $type = "$t->{type}*" if ($nstar == 1);
736 die Dumper($m, $t) if $nstar > 1;
737 } elsif ($t->{category} eq 'funcpointer') {
738 $m->{type} = $t->{name};
739 $type = "funcpointer" if ($nstar == 0);
746 # an array type with a length
747 if ($nstar > 0 && $m->{len}) {
748 if ($s->{category} =~ m/struct|union/on) {
750 if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
751 $m->{length} = $1.'VkConstants.'.$2.$3;
752 } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
753 my $len = $index->{$2};
755 $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
756 #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
757 $m->{lengthfrom} = $len->{name};
760 die "Unhandled len/altlen: ".Dumper($m);
762 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
763 my $len = $index->{$1};
765 $m->{length} = "get$len->{Name}()";
766 $m->{lengthfrom} = $len->{name};
767 $len->{lengthfor} = $m->{name};
768 $m->{'set-length'} = "set$len->{Name}((int)Memory.length($m->{name}))";
770 } elsif ($m->{len} eq 'null-terminated') {
772 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
775 my $len = $index->{$m->{len}};
777 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
779 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
780 $m->{length} = "get$len->{Name}()";
781 $m->{lengthfrom} = $len->{name};
782 $len->{lengthfor} = $m->{name};
783 $m->{'set-length'} = "set$len->{Name}($cast"."Memory.length($m->{name}))";
785 die "what?".Dumper($m);
788 } elsif ($s->{category} eq 'command') {
792 $m->{length} = $m->{len} if $index->{$m->{len}};
793 $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
798 $type = $type.'-length' if $m->{length};
801 $seen->{$m->{fullType}} = $type.$array;
802 $m->{deref} = $type.$array;
804 # Calculate name, with some fixup hacks
805 my $name = $m->{name};
806 #if ($s->{type} =~ m/struct|union/on)
808 # Strip leading 'p' for pointers
809 if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
810 $name = 'PGeometries';
811 } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
814 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
818 $name = substr $name, $strip;
821 $name =~ s/^pfn//o if $type eq 'funcpointer';
823 $name =~ s/(?:^|_)(.)/\U$1/og;
834 foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
835 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
837 my $name = $s->{name};
838 $name =~ s/(?:^|_)(.)/\U$1/og;
841 my $first = $s->{items}->[0];
842 my $second = $s->{items}->[1];
844 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
845 $first->{'no-setall'} = 1;
846 $second->{'no-setall'} = 1;
847 print "typed: $s->{name}\n";
849 print "untyped: $s->{name}\n";
853 foreach my $c (values %{$api->{funcpointers}}) {
854 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
857 foreach my $c (values %{$api->{commands}}) {
858 $c->{proto}->{name} = 'result$';
859 $c->{proto}->{Name} = 'result$';
860 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
862 # collect all member functions on handles
863 my $first = $c->{items}->[0];
864 my $last = $c->{items}->[$#{$c->{items}}];
865 if ($first->{deref} eq 'handle') {
866 my $t = $api->{handles}->{$first->{baseType}};
867 while ($t->{alias}) {
868 $t = $api->{handles}->{$t->{alias}};
870 die "No handle found ".Dumper($c) if !defined $t;
871 push @{$t->{commands}}, $c->{name};
872 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
873 push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
875 die "No owner for call ".Dumper($c);
879 print "Unique Types:\n";
881 map { $base->{$_} = 1 } values %$seen;
883 foreach my $k (sort keys %$base) {
890 # this way-over-evaluates, probably only call once on every field and member instead
897 foreach my $k (keys %$type) {
902 } elsif ($t->{eval}) {
903 $v->{$k} = eval $t->{code};
905 die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
906 } elsif (defined($t->{code})) {
907 $v->{$k} = $t->{code};
914 sub formatStructLayout {
920 # This doens't need to worry about overrides
922 foreach my $m (@{$s->{items}}) {
923 my $type = $types->{$m->{deref}};
924 my $diff = $m->{bitOffset} - $offset;
926 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
929 my $v = buildVars($s, $m, $type);
931 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
932 $offset = $m->{bitOffset} + $m->{bitSize};
934 push @fields, "/* Missing: $m->{deref} $m->{name} */";
937 my $diff = $s->{bitSize} - $offset;
938 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
940 return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
947 my $templates = $structTypes->{templates};
948 my $types = $structTypes->{types};
949 my $overrides = $structTypes->{overrides};
951 my $override = $overrides->{$s->{name}};
952 my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
963 if ($s->{category} eq 'struct') {
964 $info->{create}->{create} = {
965 setallArgs => [ 'SegmentAllocator alloc$' ],
968 } elsif ($s->{category} eq 'union') {
969 foreach my $m (@{$s->{items}}) {
970 $info->{create}->{"create$m->{Name}"} = {
971 setallArgs => [ 'SegmentAllocator alloc$' ],
979 #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
981 # FIXME: unions need multiple constructors!
983 foreach my $m (@{$s->{items}}) {
984 my $nstar = $m->{deref} =~ tr/*/*/;
985 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
986 my $type = $types->{$deref};
987 my $v = buildVars($s, $m, $type);
989 die "No type $deref ".Dumper($m, $s) if !$type;
991 #push @{$info->{getset}}, map { "// $_" } split(/\n/, Dumper($m->{deref}, $type, $override->{$m->{name}}));
992 push @{$info->{varhandle}}, "/* ? Accessor: $m->{fullType} [$m->{deref}] $m->{name} len=$m->{len} lenfor=$m->{lengthfor} override=$deref */";
994 if ($type->{accessor}) {
995 push @{$info->{getorset}}, code::formatTemplate($type->{accessor}->{getorset}, $v) if $type->{accessor}->{getorset};
998 push @{$info->{init}}, code::formatTemplate($type->{accessor}->{init}, $v) if $type->{accessor}->{init};
999 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
1001 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
1002 push @{$info->{set}}, code::formatTemplate($type->{accessor}->{set}, $v) if $type->{accessor}->{set};
1004 # FIXME: something here is adding length parameters which are already handled by the setXX() calls
1005 if (!$m->{'no-setall'}) {
1006 my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
1007 push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
1008 push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
1012 push @{$info->{varhandle}}, code::formatTemplate($v->{handle}, $v) if $v->{handle};
1015 # create constructors
1017 package => 'vulkan',
1020 layout => formatStructLayout($types, $s),
1021 init => join ("\n", @{$info->{init}}),
1022 get => join ("\n", @{$info->{get}}),
1023 set => join ("\n", @{$info->{set}}),
1024 getorset => join ("\n", @{$info->{getorset}}),
1025 #'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
1026 #'java-setall' => join ("\n", @{$info->{setall}}),
1027 varhandle => join ("\n", @{$info->{varhandle}}),
1031 # build sub-components using the full $v
1033 foreach my $k (keys %{$template->{insert}}) {
1034 my $t = $template->{insert}->{$k};
1036 if ($k eq 'create-all') {
1037 foreach my $kk (keys %{$info->{create}}) {
1038 my $create = $info->{create}->{$kk};
1040 if ($#{$create->{setallArgs}} > 0) {
1044 'java-setall-arguments' => join (', ', @{$create->{setallArgs}}),
1045 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
1047 push @createAll, code::formatTemplateStream($t, $v);
1051 $v->{$k} = code::formatTemplate($t, $v);
1054 $v->{'create-all'} = join("\n", @createAll);
1056 join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1057 code::formatTemplateStream($template->{class}, $v);
1060 # TODO: the template here could be mapped from types.api perhaps?
1061 # also same for the various fields, init/getset/etc.
1066 my $templates = $structTypes->{templates};
1067 my $overrides = $structTypes->{overrides};
1068 my $override = $overrides->{$s->{name}};
1069 my $template = $override->{template} ? $override->{template} : $templates->{handle};
1076 if (defined $s->{commands}) {
1077 foreach my $k (sort @{$s->{commands}}) {
1078 my $c = $api->{commands}->{$k};
1079 push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
1084 package => 'vulkan',
1087 init => join ("\n", @{$info->{init}}),
1088 commands => join ("\n", @{$info->{commands}}),
1091 code::formatTemplateStream($template->{class}, $v);
1094 sub formatSignature {
1096 my $types = $commandTypes->{types};
1099 foreach my $m (@{$s->{items}}) {
1100 my $x = $types->{$m->{deref}};
1102 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1104 $d .= $x->{sig}->{code};
1108 my $m = $s->{proto};
1109 my $x = $types->{$m->{deref}};
1110 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1111 $d .= $x->{sig}->{code};
1114 # TODO: only collect shit we need
1115 sub collectFunctionInfo {
1119 my $templates = $ct->{templates};
1120 my $types = $ct->{types};
1121 my $overrides = $ct->{overrides};
1122 my $void = $s->{proto}->{fullType} eq 'void';
1123 my $override = $overrides->{$s->{name}};
1126 my @invokeArgs = ();
1127 my @nativeInit = ();
1131 my @nativeArgs = ();
1135 rename => $s->{name},
1137 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1138 'native-result-define' => '',
1139 'native-result-assign' => '',
1140 'native-result' => 'void',
1141 'trampoline-result-define' => '',
1142 'trampoline-result-assign' => '',
1143 'trampoline-scope' => '',
1144 'result-test' => '',
1145 'create-frame' => '',
1146 'java-result' => 'void',
1147 'java-result-assign' => '',
1148 'result-throw' => '',
1150 'java-result-return' => 'return;',
1151 'trampoline-result-return' => 'return;',
1154 my $hasInstance = 0;
1160 #return if !defined($override->{template});
1161 #return if ($s->{name} ne 'vkCmdUpdateBuffer');
1163 foreach my $m (@{$s->{items}}) {
1164 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1165 my $type = $types->{$deref};
1167 die "No type found ".Dumper($m, $s, $override) if !$type;
1169 my $v = buildVars($s, $m, $type);
1171 #push @javaArgs, "/* $m->{name} $m->{deref} */ " if !$v->{'java-argument'};
1173 push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
1174 push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
1176 push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
1177 push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
1179 if ($v->{'query-arg'}) {
1180 push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
1181 } elsif ($v->{'invoke-arg'}) {
1182 push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
1185 push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
1186 push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
1188 $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
1189 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
1190 $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
1192 $needScope = 1 if $type->{'need-scope'};
1193 $needFrame = 1 if $type->{'need-frame'};
1194 $needAlloc = 1 if $type->{'need-alloc'};
1195 $hasInstance = 1 if $type->{'is-instance'};
1196 $trampScope = 1 if $type->{'trampoline-scope'};
1199 $info->{'static'} = $hasInstance ? '' : 'static ';
1201 if ($s->{successcodes}) {
1202 my @codes = split(/,/,$s->{successcodes});
1204 $info->{'native-result-define'} = 'int result$;';
1205 $info->{'native-result-assign'} = 'result$ = (int)';
1206 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1207 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1209 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1210 $info->{'java-result'} = 'int';
1211 $info->{'java-result-return'} = 'return result$;';
1214 } elsif ($s->{proto}->{fullType} ne 'void') {
1215 my $m = $s->{proto};
1216 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1218 die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
1219 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1221 my $v = buildVars($s, $m, $type);
1223 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1224 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1225 #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1226 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1227 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
1229 $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
1230 $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
1231 $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
1232 $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
1234 $needScope = 1 if $type->{'need-scope'};
1237 $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
1238 push @javaArgs, 'SegmentAllocator alloc$' if $needAlloc;
1239 push @javaArgs, 'ResourceScope scope$' if $needScope;
1241 $info->{'java-arguments'} = join ",\n\t", @javaArgs;
1242 $info->{'native-init'} = join "\n\t", @nativeInit;
1243 $info->{'invoke-arguments'} = join ", ", @invokeArgs;
1244 $info->{'query-init'} = join "\n\t\t\t", @queryInit;
1245 $info->{'query-arguments'} = join ", ", @queryArgs;
1247 $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
1248 $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
1249 $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
1251 $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1252 $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1254 if ($s->{category} eq 'funcpointer') {
1255 $info->{'trampoline-signature'} = formatSignature($s);
1261 sub formatFunctionPointer {
1265 my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
1266 my $info = collectFunctionInfo($api, $commandTypes, $s);
1269 package => 'vulkan',
1274 foreach my $k (keys %{$template->{insert}}) {
1275 my $t = $template->{insert}->{$k};
1277 $v->{$k} = code::formatTemplate($t, $info);
1280 code::formatTemplateStream($template->{class}, $v);
1283 sub formatFunctionDescriptor {
1287 my $templates = $ct->{templates};
1288 my $types = $ct->{types};
1289 my $overrides = $ct->{overrides};
1292 my $void = $s->{proto}->{fullType} eq 'void';
1293 my $override = $overrides->{$s->{name}};
1295 foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1296 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1297 my $type = $types->{$deref};
1299 die "No type found ".Dumper($m, $s, $override) if !$type;
1301 my $v = buildVars($s, $m, $type);
1303 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1306 return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1307 .join(",\n\t\t", @fields).')';
1310 sub formatFunction {
1314 my $templates = $ct->{templates};
1315 my $types = $ct->{types};
1316 my $overrides = $ct->{overrides};
1317 my $void = $s->{proto}->{fullType} eq 'void';
1318 my $override = $overrides->{$s->{name}};
1319 my $template = $override->{template} ? $override->{template} : $templates->{method};
1321 my $info = collectFunctionInfo($api, $ct, $s);
1323 #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1324 code::formatTemplate($template->{invoke}, $info);