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" if $sys->{verbose} > 1;
165 print "array-constructor: $protob\n" if $sys->{verbose} > 1;
167 $override->{template} =
168 defined($s->{extensions}) ?
169 $commandTypes->{templates}->{'method-extension-query'} :
170 $commandTypes->{templates}->{'method-query'};
171 foreach my $m (@{$s->{items}}) {
172 if ($m->{deref} =~ m/-length$/ && (my $len = $index->{$m->{len}})) {
175 if ($m->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE') {
176 $type = 'dispatch*-length-query';
178 $type = $m->{deref}.'-query';
181 die "no template $m->{deref}-query" if !defined($commandTypes->{types}->{$type});
182 $override->{$m->{name}}->{type} = $type;
184 die "no template $len->{deref}-querysize" if !defined($commandTypes->{types}->{$len->{deref}.'-querylen'});
185 $override->{$len->{name}}->{type} = $len->{deref}.'-querylen';
190 # other per-item things
191 foreach my $m (@{$s->{items}}) {
192 my $so = $structTypes->{overrides}->{$m->{baseType}};
195 $m->{deref} .= '-ignore';
198 if ($m->{lengthfor}) {
199 my $nstar = $m->{deref} =~ tr/*/*/;
201 die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
202 $override->{$m->{name}}->{type} = $m->{deref}.'-length';
204 if (defined($s->{extensions})) {
205 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-extension'};
206 print "length-extension: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
208 #die "No '$m->{deref}-output' type ".Dumper($s) if !defined $types->{$m->{deref}.'-otuput'};
210 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-query'};
211 #$overrides->{$s->{name}}->{$m->{name}}->{type} = $types->{$m->{deref}.'-output'};
213 print "length: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
217 # TODO: implied return things
221 $overrides->{$s->{name}} = $override if %{$override};
225 my $overrides = $structTypes->{overrides};
226 my $templates = $structTypes->{templates};
228 foreach my $k (keys %defaultTemplate) {
229 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
230 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
232 my $t = $defaultTemplate{$k};
233 my $name = $t->{name} || "struct-writeonly";
235 $name .= "-array" if $t->{array};
237 print "$name: $k\n" if $sys->{verbose} > 1;
238 die "No override $k $name" if !$templates->{$name};
239 $overrides->{$k}->{template} = $templates->{$name};
244 #$overrides->{$s->{name}}->{template} = $structTypes->{templates}->{'struct-readonly'};
246 #print Dumper({ types=>$types, templates=>$templates });
249 open(my $f, '>', 'types.pm');
250 print $f Dumper($commandTypes, $structTypes);
256 open(my $f, '>', 'api.pm');
257 print $f Dumper($api);
263 open(my $f, '>', 'data.pm');
265 'handles' => $api->{handles},
266 'types' => $api->{types},
267 'commands' => $api->{commands},
268 'funcpointers' => $api->{funcpointers},
274 my $f = openOutput($sys, "API");
276 print $f "package vulkan;\n";
277 print $f "import jdk.incubator.foreign.*;\n";
278 print $f "import java.lang.invoke.*;\n";
279 print $f "import au.notzed.nativez.*;\n";
280 print $f "public class API {\n";
281 print $f "MemoryAddress self;\n";
283 foreach my $c (values %{$api->{commands}}) {
284 die if ($c->{alias});
285 #print "$c->{name}\n";
286 print $f formatFunction($api, $commandTypes, $c)."\n";
287 #print formatFunctionDescriptor($commandTypes, $c)."\n";
290 closeOutput($sys, "API", $f);
293 exportEnums($vk, $api, 'VkConstants');
295 # dump out the extension function tables
297 my $f = openOutput($sys, 'DispatchInstance');
298 my $template = $structTypes->{templates}->{dispatch};
302 foreach my $k (sort keys %{$api->{commands}}) {
303 my $c = $api->{commands}->{$k};
305 next if !defined($c->{extensions});
307 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
308 push @init, code::formatTemplate($template->{'init'}, $c);
314 Name => 'DispatchInstance',
315 init => join("\n\t\t", @init),
316 'field-init' => join("\n\t", @fieldInit),
318 print $f code::formatTemplateStream($template->{class}, $vars);
320 closeOutput($sys, 'DispatchInstance', $f);
325 foreach my $k (sort keys %{$api->{types}}) {
326 my $s = $api->{data}->{$k};
331 my $override = $structTypes->{overrides}->{$s->{name}};
333 next if $override->{ignore};
335 my $f = openOutput($sys, $s->{Name});
336 print $f formatStruct($vk, $api, $s);
337 closeOutput($sys, $s->{Name}, $f);
340 foreach my $k (sort keys %{$api->{handles}}) {
341 my $s = $api->{data}->{$k};
346 my $f = openOutput($sys, $s->{name});
347 print $f formatHandle($vk, $api, $s);
348 closeOutput($sys, $s->{name}, $f);
351 foreach my $k (sort keys %{$api->{funcpointers}}) {
352 my $s = $api->{data}->{$k};
357 my $override = $commandTypes->{overrides}->{$s->{name}};
359 next if $override->{ignore};
361 my $f = openOutput($sys, $s->{name});
362 print $f formatFunctionPointer($vk, $api, $s);
363 closeOutput($sys, $s->{name}, $f);
369 #print Dumper (grep { !defined $_->{items} } values %{$api->{enums}});
371 #print Dumper($api->{data});
373 print "Unique Types:\n";
374 foreach my $k (sort keys %$all) {
380 foreach my $k (sort keys %{$api->{commands}}) {
381 my $c = $api->{commands}->{$k};
385 foreach my $m ($c->{proto}, @{$c->{items}}) {
386 my $t = $vk->{data}->{$m->{baseType}};
388 die if !defined $m->{baseType};
389 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
391 while ($t->{alias}) {
392 print "Alias: $t->{name} -> $t->{alias}\n";
393 $t = $vk->{data}->{$t->{alias}};
400 foreach my $k (sort keys %{$vk->{index}}) {
407 foreach my $k (sort keys %{$vk->{types}}) {
408 my $s = $vk->{types}->{$k};
410 foreach my $m (@{$s->{items}}) {
411 my $t = $vk->{data}->{$m->{baseType}};
413 die if !defined $m->{baseType};
414 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
416 while ($t->{alias}) {
417 print "Alias: $t->{name} -> $t->{alias}\n";
418 $t = $vk->{data}->{$t->{alias}};
421 $masks->{$t->{name}} = $t if ($t->{category} eq 'bitmask');
422 $enums->{$t->{name}} = $t if ($t->{category} eq 'enum');
426 print Dumper($masks);
427 foreach my $k (sort keys %{$masks}) {
428 my $s = $masks->{$k};
431 if ($s->{requires}) {
432 $t = $vk->{data}->{$s->{requires}};
433 } elsif ($s->{name} =~ m/(.*)Flags([0-9A-Z]*)/o && defined $vk->{data}->{"$1FlagBits$2"}) {
434 print "> $s->{name} $1FlagBits$2\n";
435 $t = $vk->{data}->{"$1FlagBits$2"};
437 print "? $s->{name}\n";
440 print "! $s->{name} r=$s->{requires}\n" if !defined($t);
449 my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
455 foreach my $t (@{$config->{objects}}) {
456 if ($t->{type} eq 'type') {
457 my $nopts = $#{$t->{options}};
460 if ($nopts >= 0 && defined($types->{$t->{options}->[0]})) {
461 $type = { %{$types->{$t->{options}->[0]}} };
462 } elsif ($#{$t->{items}} >= 0) {
465 die ("No prototype provided/found for empty type ".Dumper($t));
468 if ($#{$t->{items}} >= 0) {
469 foreach my $s (@{$t->{items}}) {
471 code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
474 $x->{eval} = 1 if config::optionFlag('eval', $s);
476 $type->{$s->{match}} = $x;
480 # check other options
481 foreach my $o (@{$t->{options}}) {
482 if ($o =~ m/^accessor=(.*)$/o) {
483 die "No template $1" if !defined($templates->{$1});
484 $type->{accessor} = $templates->{$1};
485 } elsif ($o eq 'need-frame') {
486 $type->{'need-frame'} = 1;
487 } elsif ($o eq 'need-scope') {
488 $type->{'need-scope'} = 1;
489 } elsif ($o eq 'trampoline-scope') {
490 $type->{'trampoline-scope'} = 1;
491 } elsif ($o eq 'need-alloc') {
492 $type->{'need-alloc'} = 1;
493 } elsif ($o eq 'is-instance') {
494 $type->{'is-instance'} = 1;
496 # doesn't ignore implied parant type
497 #die "Unknown option '$o' in ".Dumper($t);
501 foreach my $k (split /,/,$t->{name}) {
502 $types->{$k} = $type;
504 } elsif ($t->{type} eq 'code') {
509 foreach my $s (@{$t->{items}}) {
510 $code->{$s->{match}} = $s->{literal};
511 $code->{$s->{match}} =~ s/^\t//gm;
513 foreach my $o (@{$t->{options}}) {
514 if ($o =~ m/insert=(.*)/) {
515 foreach my $t (split /,/,$1) {
516 if ($t =~ m/(.*):(.*)/) {
517 die if !defined $templates->{$1}->{$2};
518 $code->{insert}->{$2} = $templates->{$1}->{$2};
524 $templates->{$t->{name}} = $code;
525 } elsif ($t->{type} eq 'override') {
526 foreach my $s (@{$t->{items}}) {
528 foreach my $o (@{$s->{options}}) {
529 if ($o =~ m/^(.*)=type:(.*)/) {
530 die "No such type $s->{match} $2\n" if !defined $types->{$2};
531 $c->{$1}->{type} = $2;
532 } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
533 die "No accessor template $o" if !defined($templates->{$2});
534 $c->{$1}->{accessor} = $templates->{$2};
535 } elsif ($o =~ m/^template=(.*)/) {
536 die "No template $o" if !defined($templates->{$1});
537 $c->{template} = $templates->{$1};
538 } elsif ($o eq 'ignore') {
542 $overrides->{$s->{match}} = $c;
547 # templates should probably just go in one
550 templates => $templates,
551 overrides => $overrides,
557 return grep { !$seen{$_}++ } @_;
566 my $f = openOutput($sys, $name);
568 print $f "package vulkan;\npublic interface VkConstants {\n";
570 # special case for api constants
571 # special case for api constants
573 my $s = $api->{data}->{'API Constants'};
575 print $f "\n\t// API Constants\n";
577 foreach my $m (@{$s->{items}}) {
578 next if defined($m->{alias});
579 next if $seen->{$m->{name}}++;
581 my $i = $enumInfo->{$m->{type}};
585 $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
587 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
591 foreach my $k (sort keys %{$api->{enums}}) {
592 my $s = $api->{data}->{$k};
593 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
594 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
598 print $f "\n\t// $s->{name} $type\n";
600 foreach my $m (@{$s->{items}}) {
601 next if defined($m->{alias});
602 next if $seen->{$m->{name}}++;
606 $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
608 die Dumper("Ca't work out value", $m, $s) if !defined($v);
609 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
614 closeOutput($sys, $name, $f);
617 # ###################################################################### #
618 # class.name to class/name.java
623 $name = $sys->{package}.'.'.$name;
625 $name = $sys->{output}.'/'.$name.'.java';
633 my $path = classToPath($sys, $name);
636 rename($path.'~', $path) || die ("rename failed: $!");
643 my $path = classToPath($sys, $name);
644 my $dir = dirname($path);
646 make_path($dir) if (!-d $dir);
648 open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
649 print "writing '$path'\n" if $sys->{verbose} > 0;
654 # Calculate canonical derefernce types for each field and parameter
666 map { $index->{$_->{name}} = $_ } @_;
668 $s->{index} = $index;
671 my $t = $api->{data}->{$m->{baseType}};
672 my $nstar = $m->{fullType} =~ tr/*/*/;
677 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
681 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
684 if ($isize =~ m/^\d+$/n) {
687 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
691 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
696 # will be primitive or external
697 $type = $m->{baseType} if ($nstar == 0);
698 $type = "$m->{baseType}*" if ($nstar == 1);
699 $type = "$m->{baseType}**" if ($nstar == 2);
703 while ($t->{alias}) {
704 print "alias $t->{name} -> $t->{alias}\n";
705 $t = $api->{data}->{$t->{alias}};
707 $m->{baseType} = $t->{name};
710 if ($t->{category} =~ m/enum|bitmask/on) {
711 $t = $vk->{data}->{$t->{fullType}};
712 $type = $t->{type} if ($nstar == 0);
713 $type = "$t->{type}*" if ($nstar == 1);
715 } elsif ($t->{category} =~ m/struct|union/on) {
716 $m->{type} = $t->{name};
717 $type = 'struct' if ($nstar == 0);
718 $type = 'struct*' if ($nstar == 1);
719 $type = 'struct**' if ($nstar == 2);
721 } elsif ($t->{category} eq 'handle') {
722 $m->{type} = $t->{name};
723 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
724 # $type = 'dhandle' if ($nstar == 0);
725 # $type = 'dhandle*' if ($nstar == 1);
727 $type = 'handle' if ($nstar == 0);
728 $type = 'handle*' if ($nstar == 1);
731 } elsif ($t->{category} eq 'basetype') {
733 $type = $t->{type} if ($nstar == 0);
734 $type = "$t->{type}*" if ($nstar == 1);
735 die Dumper($m, $t) if $nstar > 1;
736 } elsif ($t->{category} eq 'funcpointer') {
737 $m->{type} = $t->{name};
738 $type = "funcpointer" if ($nstar == 0);
745 # an array type with a length
746 if ($nstar > 0 && $m->{len}) {
747 if ($s->{category} =~ m/struct|union/on) {
749 if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
750 $m->{length} = $1.'VkConstants.'.$2.$3;
751 } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
752 my $len = $index->{$2};
754 $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
755 #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
756 $m->{lengthfrom} = $len->{name};
759 die "Unhandled len/altlen: ".Dumper($m);
761 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
762 my $len = $index->{$1};
764 $m->{length} = "get$len->{Name}()";
765 $m->{lengthfrom} = $len->{name};
766 $len->{lengthfor} = $m->{name};
767 $m->{'set-length'} = "set$len->{Name}((int)Memory.length($m->{name}))";
769 } elsif ($m->{len} eq 'null-terminated') {
771 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
774 my $len = $index->{$m->{len}};
776 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
778 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
779 $m->{length} = "get$len->{Name}()";
780 $m->{lengthfrom} = $len->{name};
781 $len->{lengthfor} = $m->{name};
782 $m->{'set-length'} = "set$len->{Name}($cast"."Memory.length($m->{name}))";
784 die "what?".Dumper($m);
787 } elsif ($s->{category} eq 'command') {
791 $m->{length} = $m->{len} if $index->{$m->{len}};
792 $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
797 $type = $type.'-length' if $m->{length};
800 $seen->{$m->{fullType}} = $type.$array;
801 $m->{deref} = $type.$array;
803 # Calculate name, with some fixup hacks
804 my $name = $m->{name};
805 #if ($s->{type} =~ m/struct|union/on)
807 # Strip leading 'p' for pointers
808 if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
809 $name = 'PGeometries';
810 } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
813 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
817 $name = substr $name, $strip;
820 $name =~ s/^pfn//o if $type eq 'funcpointer';
822 $name =~ s/(?:^|_)(.)/\U$1/og;
833 foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
834 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
836 my $name = $s->{name};
837 $name =~ s/(?:^|_)(.)/\U$1/og;
840 my $first = $s->{items}->[0];
841 my $second = $s->{items}->[1];
843 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
844 $first->{'no-setall'} = 1;
845 $second->{'no-setall'} = 1;
846 print "typed: $s->{name}\n" if $sys->{verbose} > 1;
848 print "untyped: $s->{name}\n" if $sys->{verbose} > 1;
852 foreach my $c (values %{$api->{funcpointers}}) {
853 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
856 foreach my $c (values %{$api->{commands}}) {
857 $c->{proto}->{name} = 'result$';
858 $c->{proto}->{Name} = 'result$';
859 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
861 # collect all member functions on handles
862 my $first = $c->{items}->[0];
863 my $last = $c->{items}->[$#{$c->{items}}];
864 if ($first->{deref} eq 'handle') {
865 my $t = $api->{handles}->{$first->{baseType}};
866 while ($t->{alias}) {
867 $t = $api->{handles}->{$t->{alias}};
869 die "No handle found ".Dumper($c) if !defined $t;
870 push @{$t->{commands}}, $c->{name};
871 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
872 push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
874 die "No owner for call ".Dumper($c);
878 print "Unique Types:\n";
880 map { $base->{$_} = 1 } values %$seen;
882 foreach my $k (sort keys %$base) {
889 # this way-over-evaluates, probably only call once on every field and member instead
896 foreach my $k (keys %$type) {
901 } elsif ($t->{eval}) {
902 $v->{$k} = eval $t->{code};
904 die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
905 } elsif (defined($t->{code})) {
906 $v->{$k} = $t->{code};
913 sub formatStructLayout {
919 # This doens't need to worry about overrides
921 foreach my $m (@{$s->{items}}) {
922 my $type = $types->{$m->{deref}};
923 my $diff = $m->{bitOffset} - $offset;
925 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
928 my $v = buildVars($s, $m, $type);
930 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
931 $offset = $m->{bitOffset} + $m->{bitSize};
933 push @fields, "/* Missing: $m->{deref} $m->{name} */";
936 my $diff = $s->{bitSize} - $offset;
937 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
939 return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
946 my $templates = $structTypes->{templates};
947 my $types = $structTypes->{types};
948 my $overrides = $structTypes->{overrides};
950 my $override = $overrides->{$s->{name}};
951 my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
962 if ($s->{category} eq 'struct') {
963 $info->{create}->{create} = {
964 setallArgs => [ 'SegmentAllocator alloc$' ],
967 } elsif ($s->{category} eq 'union') {
968 foreach my $m (@{$s->{items}}) {
969 $info->{create}->{"create$m->{Name}"} = {
970 setallArgs => [ 'SegmentAllocator alloc$' ],
978 #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
980 # FIXME: unions need multiple constructors!
982 foreach my $m (@{$s->{items}}) {
983 my $nstar = $m->{deref} =~ tr/*/*/;
984 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
985 my $type = $types->{$deref};
986 my $v = buildVars($s, $m, $type);
988 die "No type $deref ".Dumper($m, $s) if !$type;
990 #push @{$info->{getset}}, map { "// $_" } split(/\n/, Dumper($m->{deref}, $type, $override->{$m->{name}}));
991 push @{$info->{varhandle}}, "/* ? Accessor: $m->{fullType} [$m->{deref}] $m->{name} len=$m->{len} lenfor=$m->{lengthfor} override=$deref */";
993 if ($type->{accessor}) {
994 push @{$info->{getorset}}, code::formatTemplate($type->{accessor}->{getorset}, $v) if $type->{accessor}->{getorset};
997 push @{$info->{init}}, code::formatTemplate($type->{accessor}->{init}, $v) if $type->{accessor}->{init};
998 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
1000 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
1001 push @{$info->{set}}, code::formatTemplate($type->{accessor}->{set}, $v) if $type->{accessor}->{set};
1003 # FIXME: something here is adding length parameters which are already handled by the setXX() calls
1004 if (!$m->{'no-setall'}) {
1005 my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
1006 push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
1007 push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
1011 push @{$info->{varhandle}}, code::formatTemplate($v->{handle}, $v) if $v->{handle};
1014 # create constructors
1016 package => 'vulkan',
1019 layout => formatStructLayout($types, $s),
1020 init => join ("\n", @{$info->{init}}),
1021 get => join ("\n", @{$info->{get}}),
1022 set => join ("\n", @{$info->{set}}),
1023 getorset => join ("\n", @{$info->{getorset}}),
1024 #'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
1025 #'java-setall' => join ("\n", @{$info->{setall}}),
1026 varhandle => join ("\n", @{$info->{varhandle}}),
1030 # build sub-components using the full $v
1032 foreach my $k (keys %{$template->{insert}}) {
1033 my $t = $template->{insert}->{$k};
1035 if ($k eq 'create-all') {
1036 foreach my $kk (keys %{$info->{create}}) {
1037 my $create = $info->{create}->{$kk};
1039 if ($#{$create->{setallArgs}} > 0) {
1043 'java-setall-arguments' => join (', ', @{$create->{setallArgs}}),
1044 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
1046 push @createAll, code::formatTemplateStream($t, $v);
1050 $v->{$k} = code::formatTemplate($t, $v);
1053 $v->{'create-all'} = join("\n", @createAll);
1055 join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1056 code::formatTemplateStream($template->{class}, $v);
1059 # TODO: the template here could be mapped from types.api perhaps?
1060 # also same for the various fields, init/getset/etc.
1065 my $templates = $structTypes->{templates};
1066 my $overrides = $structTypes->{overrides};
1067 my $override = $overrides->{$s->{name}};
1068 my $template = $override->{template} ? $override->{template} : $templates->{handle};
1075 if (defined $s->{commands}) {
1076 foreach my $k (sort @{$s->{commands}}) {
1077 my $c = $api->{commands}->{$k};
1078 push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
1083 package => 'vulkan',
1086 init => join ("\n", @{$info->{init}}),
1087 commands => join ("\n", @{$info->{commands}}),
1090 code::formatTemplateStream($template->{class}, $v);
1093 sub formatSignature {
1095 my $types = $commandTypes->{types};
1098 foreach my $m (@{$s->{items}}) {
1099 my $x = $types->{$m->{deref}};
1101 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1103 $d .= $x->{sig}->{code};
1107 my $m = $s->{proto};
1108 my $x = $types->{$m->{deref}};
1109 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1110 $d .= $x->{sig}->{code};
1113 # TODO: only collect shit we need
1114 sub collectFunctionInfo {
1118 my $templates = $ct->{templates};
1119 my $types = $ct->{types};
1120 my $overrides = $ct->{overrides};
1121 my $void = $s->{proto}->{fullType} eq 'void';
1122 my $override = $overrides->{$s->{name}};
1125 my @invokeArgs = ();
1126 my @nativeInit = ();
1130 my @nativeArgs = ();
1134 rename => $s->{name},
1136 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1137 'native-result-define' => '',
1138 'native-result-assign' => '',
1139 'native-result' => 'void',
1140 'trampoline-result-define' => '',
1141 'trampoline-result-assign' => '',
1142 'trampoline-scope' => '',
1143 'result-test' => '',
1144 'create-frame' => '',
1145 'java-result' => 'void',
1146 'java-result-assign' => '',
1147 'result-throw' => '',
1149 'java-result-return' => 'return;',
1150 'trampoline-result-return' => 'return;',
1153 my $hasInstance = 0;
1159 #return if !defined($override->{template});
1160 #return if ($s->{name} ne 'vkCmdUpdateBuffer');
1162 foreach my $m (@{$s->{items}}) {
1163 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1164 my $type = $types->{$deref};
1166 die "No type found ".Dumper($m, $s, $override) if !$type;
1168 my $v = buildVars($s, $m, $type);
1170 #push @javaArgs, "/* $m->{name} $m->{deref} */ " if !$v->{'java-argument'};
1172 push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
1173 push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
1175 push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
1176 push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
1178 if ($v->{'query-arg'}) {
1179 push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
1180 } elsif ($v->{'invoke-arg'}) {
1181 push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
1184 push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
1185 push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
1187 $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
1188 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
1189 $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
1191 $needScope = 1 if $type->{'need-scope'};
1192 $needFrame = 1 if $type->{'need-frame'};
1193 $needAlloc = 1 if $type->{'need-alloc'};
1194 $hasInstance = 1 if $type->{'is-instance'};
1195 $trampScope = 1 if $type->{'trampoline-scope'};
1198 $info->{'static'} = $hasInstance ? '' : 'static ';
1200 if ($s->{successcodes}) {
1201 my @codes = split(/,/,$s->{successcodes});
1203 $info->{'native-result-define'} = 'int result$;';
1204 $info->{'native-result-assign'} = 'result$ = (int)';
1205 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1206 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1208 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1209 $info->{'java-result'} = 'int';
1210 $info->{'java-result-return'} = 'return result$;';
1213 } elsif ($s->{proto}->{fullType} ne 'void') {
1214 my $m = $s->{proto};
1215 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1217 die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
1218 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1220 my $v = buildVars($s, $m, $type);
1222 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1223 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1224 #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1225 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1226 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
1228 $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
1229 $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
1230 $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
1231 $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
1233 $needScope = 1 if $type->{'need-scope'};
1236 $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
1237 push @javaArgs, 'SegmentAllocator alloc$' if $needAlloc;
1238 push @javaArgs, 'ResourceScope scope$' if $needScope;
1240 $info->{'java-arguments'} = join ",\n\t", @javaArgs;
1241 $info->{'native-init'} = join "\n\t", @nativeInit;
1242 $info->{'invoke-arguments'} = join ", ", @invokeArgs;
1243 $info->{'query-init'} = join "\n\t\t\t", @queryInit;
1244 $info->{'query-arguments'} = join ", ", @queryArgs;
1246 $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
1247 $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
1248 $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
1250 $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1251 $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1253 if ($s->{category} eq 'funcpointer') {
1254 $info->{'trampoline-signature'} = formatSignature($s);
1260 sub formatFunctionPointer {
1264 my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
1265 my $info = collectFunctionInfo($api, $commandTypes, $s);
1268 package => 'vulkan',
1273 foreach my $k (keys %{$template->{insert}}) {
1274 my $t = $template->{insert}->{$k};
1276 $v->{$k} = code::formatTemplate($t, $info);
1279 code::formatTemplateStream($template->{class}, $v);
1282 sub formatFunctionDescriptor {
1286 my $templates = $ct->{templates};
1287 my $types = $ct->{types};
1288 my $overrides = $ct->{overrides};
1291 my $void = $s->{proto}->{fullType} eq 'void';
1292 my $override = $overrides->{$s->{name}};
1294 foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1295 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1296 my $type = $types->{$deref};
1298 die "No type found ".Dumper($m, $s, $override) if !$type;
1300 my $v = buildVars($s, $m, $type);
1302 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1305 return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1306 .join(",\n\t\t", @fields).')';
1309 sub formatFunction {
1313 my $templates = $ct->{templates};
1314 my $types = $ct->{types};
1315 my $overrides = $ct->{overrides};
1316 my $void = $s->{proto}->{fullType} eq 'void';
1317 my $override = $overrides->{$s->{name}};
1318 my $template = $override->{template} ? $override->{template} : $templates->{method};
1320 my $info = collectFunctionInfo($api, $ct, $s);
1322 #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1323 code::formatTemplate($template->{invoke}, $info);