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';
190 foreach my $m (@{$s->{items}}) {
191 if ($m->{lengthfor}) {
192 my $nstar = $m->{deref} =~ tr/*/*/;
194 die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
195 $override->{$m->{name}}->{type} = $m->{deref}.'-length';
197 if (defined($s->{extensions})) {
198 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-extension'};
199 print "length-extension: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
201 #die "No '$m->{deref}-output' type ".Dumper($s) if !defined $types->{$m->{deref}.'-otuput'};
203 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-query'};
204 #$overrides->{$s->{name}}->{$m->{name}}->{type} = $types->{$m->{deref}.'-output'};
206 print "length: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
210 # TODO: implied return things
214 $overrides->{$s->{name}} = $override if %{$override};
218 my $overrides = $structTypes->{overrides};
219 my $templates = $structTypes->{templates};
221 print Dumper(\%defaultTemplate);
223 foreach my $k (keys %defaultTemplate) {
224 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
225 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
227 my $t = $defaultTemplate{$k};
228 my $name = $t->{name} || "struct-writeonly";
230 $name .= "-array" if $t->{array};
233 die "No override $k $name" if !$templates->{$name};
234 $overrides->{$k}->{template} = $templates->{$name};
239 #$overrides->{$s->{name}}->{template} = $structTypes->{templates}->{'struct-readonly'};
241 #print Dumper({ types=>$types, templates=>$templates });
244 open(my $f, '>', 'types.pm');
245 print $f Dumper($commandTypes, $structTypes);
251 open(my $f, '>', 'api.pm');
252 print $f Dumper($api);
258 open(my $f, '>', 'data.pm');
260 'handles' => $api->{handles},
261 'types' => $api->{types},
262 'commands' => $api->{commands}
268 my $f = openOutput($sys, "API");
270 print $f "package vulkan;\n";
271 print $f "import jdk.incubator.foreign.*;\n";
272 print $f "import java.lang.invoke.*;\n";
273 print $f "import au.notzed.nativez.*;\n";
274 print $f "public class API {\n";
275 print $f "MemoryAddress self;\n";
277 foreach my $c (values %{$api->{commands}}) {
278 die if ($c->{alias});
279 #print "$c->{name}\n";
280 print $f formatFunction($api, $commandTypes, $c)."\n";
281 #print formatFunctionDescriptor($commandTypes, $c)."\n";
284 closeOutput($sys, "API", $f);
287 exportEnums($vk, $api, 'VkConstants');
289 # dump out the extension function tables
291 my $f = openOutput($sys, 'DispatchInstance');
292 my $template = $structTypes->{templates}->{dispatch};
296 foreach my $k (sort keys %{$api->{commands}}) {
297 my $c = $api->{commands}->{$k};
299 next if !defined($c->{extensions});
301 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
302 push @init, code::formatTemplate($template->{'init'}, $c);
308 Name => 'DispatchInstance',
309 init => join("\n\t\t", @init),
310 'field-init' => join("\n\t", @fieldInit),
312 print $f code::formatTemplateStream($template->{class}, $vars);
314 closeOutput($sys, 'DispatchInstance', $f);
319 foreach my $k (sort keys %{$api->{types}}) {
320 my $s = $api->{data}->{$k};
325 my $f = openOutput($sys, $s->{Name});
326 print $f formatStruct($vk, $api, $s);
327 closeOutput($sys, $s->{Name}, $f);
330 foreach my $k (sort keys %{$api->{handles}}) {
331 my $s = $api->{data}->{$k};
336 my $f = openOutput($sys, $s->{name});
337 print $f formatHandle($vk, $api, $s);
338 closeOutput($sys, $s->{name}, $f);
341 foreach my $k (sort keys %{$api->{funcpointers}}) {
342 my $s = $api->{data}->{$k};
347 my $f = openOutput($sys, $s->{name});
348 print $f formatFunctionPointer($vk, $api, $s);
349 closeOutput($sys, $s->{name}, $f);
355 #print Dumper (grep { !defined $_->{items} } values %{$api->{enums}});
357 #print Dumper($api->{data});
359 print "Unique Types:\n";
360 foreach my $k (sort keys %$all) {
366 foreach my $k (sort keys %{$api->{commands}}) {
367 my $c = $api->{commands}->{$k};
371 foreach my $m ($c->{proto}, @{$c->{items}}) {
372 my $t = $vk->{data}->{$m->{baseType}};
374 die if !defined $m->{baseType};
375 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
377 while ($t->{alias}) {
378 print "Alias: $t->{name} -> $t->{alias}\n";
379 $t = $vk->{data}->{$t->{alias}};
386 foreach my $k (sort keys %{$vk->{index}}) {
393 foreach my $k (sort keys %{$vk->{types}}) {
394 my $s = $vk->{types}->{$k};
396 foreach my $m (@{$s->{items}}) {
397 my $t = $vk->{data}->{$m->{baseType}};
399 die if !defined $m->{baseType};
400 print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
402 while ($t->{alias}) {
403 print "Alias: $t->{name} -> $t->{alias}\n";
404 $t = $vk->{data}->{$t->{alias}};
407 $masks->{$t->{name}} = $t if ($t->{category} eq 'bitmask');
408 $enums->{$t->{name}} = $t if ($t->{category} eq 'enum');
412 print Dumper($masks);
413 foreach my $k (sort keys %{$masks}) {
414 my $s = $masks->{$k};
417 if ($s->{requires}) {
418 $t = $vk->{data}->{$s->{requires}};
419 } elsif ($s->{name} =~ m/(.*)Flags([0-9A-Z]*)/o && defined $vk->{data}->{"$1FlagBits$2"}) {
420 print "> $s->{name} $1FlagBits$2\n";
421 $t = $vk->{data}->{"$1FlagBits$2"};
423 print "? $s->{name}\n";
426 print "! $s->{name} r=$s->{requires}\n" if !defined($t);
435 my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
441 foreach my $t (@{$config->{objects}}) {
442 if ($t->{type} eq 'type') {
443 my $nopts = $#{$t->{options}};
446 if ($nopts >= 0 && defined($types->{$t->{options}->[0]})) {
447 $type = { %{$types->{$t->{options}->[0]}} };
448 } elsif ($#{$t->{items}} >= 0) {
451 die ("No prototype provided/found for empty type ".Dumper($t));
454 if ($#{$t->{items}} >= 0) {
455 foreach my $s (@{$t->{items}}) {
457 code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
460 $x->{eval} = 1 if config::optionFlag('eval', $s);
462 $type->{$s->{match}} = $x;
466 # check other options
467 foreach my $o (@{$t->{options}}) {
468 if ($o =~ m/^accessor=(.*)$/o) {
469 die "No template $1" if !defined($templates->{$1});
470 $type->{accessor} = $templates->{$1};
471 } elsif ($o eq 'need-frame') {
472 $type->{'need-frame'} = 1;
473 } elsif ($o eq 'need-scope') {
474 $type->{'need-scope'} = 1;
475 } elsif ($o eq 'need-alloc') {
476 $type->{'need-alloc'} = 1;
477 } elsif ($o eq 'is-instance') {
478 $type->{'is-instance'} = 1;
480 # doesn't ignore implied parant type
481 #die "Unknown option '$o' in ".Dumper($t);
485 foreach my $k (split /,/,$t->{name}) {
486 $types->{$k} = $type;
488 } elsif ($t->{type} eq 'code') {
493 foreach my $s (@{$t->{items}}) {
494 $code->{$s->{match}} = $s->{literal};
495 $code->{$s->{match}} =~ s/^\t//gm;
497 foreach my $o (@{$t->{options}}) {
498 if ($o =~ m/insert=(.*)/) {
499 foreach my $t (split /,/,$1) {
500 if ($t =~ m/(.*):(.*)/) {
501 die if !defined $templates->{$1}->{$2};
502 $code->{insert}->{$2} = $templates->{$1}->{$2};
508 $templates->{$t->{name}} = $code;
509 } elsif ($t->{type} eq 'override') {
510 foreach my $s (@{$t->{items}}) {
512 foreach my $o (@{$s->{options}}) {
513 if ($o =~ m/^(.*)=type:(.*)/) {
514 die "No such type $s->{match} $2\n" if !defined $types->{$2};
515 $c->{$1}->{type} = $2;
516 } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
517 die "No accessor template $o" if !defined($templates->{$2});
518 $c->{$1}->{accessor} = $templates->{$2};
519 #} elsif ($o =~ m/^(.*)=method:(.*)/) {
520 # die "No method template $o" if !defined($templates->{$2});
521 # $c->{$1}->{method} = $templates->{$2};
522 } elsif ($o =~ m/^template=(.*)/) {
523 die "No template $o" if !defined($templates->{$1});
524 $c->{template} = $templates->{$1};
527 $overrides->{$s->{match}} = $c;
532 # templates should probably just go in one
535 templates => $templates,
536 overrides => $overrides,
542 return grep { !$seen{$_}++ } @_;
551 my $f = openOutput($sys, $name);
553 print $f "package vulkan;\npublic interface VkConstants {\n";
555 # special case for api constants
556 # special case for api constants
558 my $s = $api->{data}->{'API Constants'};
560 print $f "\n\t// API Constants\n";
562 foreach my $m (@{$s->{items}}) {
563 next if defined($m->{alias});
564 next if $seen->{$m->{name}}++;
566 my $i = $enumInfo->{$m->{type}};
570 $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
572 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
576 foreach my $k (sort keys %{$api->{enums}}) {
577 my $s = $api->{data}->{$k};
578 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
579 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
583 print $f "\n\t// $s->{name} $type\n";
585 foreach my $m (@{$s->{items}}) {
586 next if defined($m->{alias});
587 next if $seen->{$m->{name}}++;
591 $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
593 die Dumper("Ca't work out value", $m, $s) if !defined($v);
594 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
599 closeOutput($sys, $name, $f);
602 # ###################################################################### #
603 # class.name to class/name.java
608 $name = $sys->{package}.'.'.$name;
610 $name = $sys->{output}.'/'.$name.'.java';
618 my $path = classToPath($sys, $name);
621 rename($path.'~', $path) || die ("rename failed: $!");
628 my $path = classToPath($sys, $name);
629 my $dir = dirname($path);
631 make_path($dir) if (!-d $dir);
633 open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
634 print "writing '$path'\n" if $sys->{verbose} > 0;
639 # Calculate canonical derefernce types for each field and parameter
651 map { $index->{$_->{name}} = $_ } @_;
653 $s->{index} = $index;
656 my $t = $api->{data}->{$m->{baseType}};
657 my $nstar = $m->{fullType} =~ tr/*/*/;
662 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
666 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
669 if ($isize =~ m/^\d+$/n) {
672 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
676 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
681 # will be primitive or external
682 $type = $m->{baseType} if ($nstar == 0);
683 $type = "$m->{baseType}*" if ($nstar == 1);
684 $type = "$m->{baseType}**" if ($nstar == 2);
688 while ($t->{alias}) {
689 print "alias $t->{name} -> $t->{alias}\n";
690 $t = $api->{data}->{$t->{alias}};
692 $m->{baseType} = $t->{name};
695 if ($t->{category} =~ m/enum|bitmask/on) {
696 $t = $vk->{data}->{$t->{fullType}};
697 $type = $t->{type} if ($nstar == 0);
698 $type = "$t->{type}*" if ($nstar == 1);
700 } elsif ($t->{category} =~ m/struct|union/on) {
701 $m->{type} = $t->{name};
702 $type = 'struct' if ($nstar == 0);
703 $type = 'struct*' if ($nstar == 1);
704 $type = 'struct**' if ($nstar == 2);
706 } elsif ($t->{category} eq 'handle') {
707 $m->{type} = $t->{name};
708 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
709 # $type = 'dhandle' if ($nstar == 0);
710 # $type = 'dhandle*' if ($nstar == 1);
712 $type = 'handle' if ($nstar == 0);
713 $type = 'handle*' if ($nstar == 1);
716 } elsif ($t->{category} eq 'basetype') {
718 $type = $t->{type} if ($nstar == 0);
719 $type = "$t->{type}*" if ($nstar == 1);
720 die Dumper($m, $t) if $nstar > 1;
721 } elsif ($t->{category} eq 'funcpointer') {
722 $m->{type} = $t->{name};
723 $type = "funcpointer" if ($nstar == 0);
730 # an array type with a length
731 if ($nstar > 0 && $m->{len}) {
732 if ($s->{category} =~ m/struct|union/on) {
734 if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
735 $m->{length} = $1.'VkConstants.'.$2.$3;
736 } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
737 my $len = $index->{$2};
739 $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
740 #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
741 $m->{lengthfrom} = $len->{name};
744 die "Unhandled len/altlen: ".Dumper($m);
746 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
747 my $len = $index->{$1};
749 $m->{length} = "get$len->{Name}()";
750 $m->{lengthfrom} = $len->{name};
751 $len->{lengthfor} = $m->{name};
752 $m->{'set-length'} = "set$len->{Name}((int)Memory.length($m->{name}))";
754 } elsif ($m->{len} eq 'null-terminated') {
756 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
759 my $len = $index->{$m->{len}};
761 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
763 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
764 $m->{length} = "get$len->{Name}()";
765 $m->{lengthfrom} = $len->{name};
766 $len->{lengthfor} = $m->{name};
767 $m->{'set-length'} = "set$len->{Name}($cast"."Memory.length($m->{name}))";
769 die "what?".Dumper($m);
772 } elsif ($s->{category} eq 'command') {
776 $m->{length} = $m->{len} if $index->{$m->{len}};
777 $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
782 $type = $type.'-length' if $m->{length};
785 $seen->{$m->{fullType}} = $type.$array;
786 $m->{deref} = $type.$array;
788 my $name = $m->{name};
789 #if ($s->{type} =~ m/struct|union/on)
791 # Strip leading 'p' for pointers
792 if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
793 $name = 'PGeometries';
794 } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
797 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
801 $name = substr $name, $strip;
804 $name =~ s/^pfn//o if $type eq 'funcpointer';
806 $name =~ s/(?:^|_)(.)/\U$1/og;
817 foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
818 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
820 my $name = $s->{name};
821 $name =~ s/(?:^|_)(.)/\U$1/og;
824 my $first = $s->{items}->[0];
825 my $second = $s->{items}->[1];
827 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
828 $first->{'no-setall'} = 1;
829 $second->{'no-setall'} = 1;
830 print "typed: $s->{name}\n";
832 print "untyped: $s->{name}\n";
836 foreach my $c (values %{$api->{funcpointers}}) {
837 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
840 foreach my $c (values %{$api->{commands}}) {
841 $c->{proto}->{name} = 'result$';
842 $c->{proto}->{Name} = 'result$';
843 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
845 # collect all member functions on handles
846 my $first = $c->{items}->[0];
847 my $last = $c->{items}->[$#{$c->{items}}];
848 if ($first->{deref} eq 'handle') {
849 my $t = $api->{handles}->{$first->{baseType}};
850 while ($t->{alias}) {
851 $t = $api->{handles}->{$t->{alias}};
853 die "No handle found ".Dumper($c) if !defined $t;
854 push @{$t->{commands}}, $c->{name};
855 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
856 push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
858 die "No owner for call ".Dumper($c);
862 print "Unique Types:\n";
864 map { $base->{$_} = 1 } values %$seen;
866 foreach my $k (sort keys %$base) {
873 # this way-over-evaluates, probably only call once on every field and member instead
880 foreach my $k (keys %$type) {
885 } elsif ($t->{eval}) {
886 $v->{$k} = eval $t->{code};
888 die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
889 } elsif (defined($t->{code})) {
890 $v->{$k} = $t->{code};
897 sub formatStructLayout {
903 # This doens't need to worry about overrides
905 foreach my $m (@{$s->{items}}) {
906 my $type = $types->{$m->{deref}};
907 my $diff = $m->{bitOffset} - $offset;
909 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
912 my $v = buildVars($s, $m, $type);
914 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
915 $offset = $m->{bitOffset} + $m->{bitSize};
917 push @fields, "/* Missing: $m->{deref} $m->{name} */";
920 my $diff = $s->{bitSize} - $offset;
921 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
923 return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
930 my $templates = $structTypes->{templates};
931 my $types = $structTypes->{types};
932 my $overrides = $structTypes->{overrides};
934 my $override = $overrides->{$s->{name}};
935 my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
946 if ($s->{category} eq 'struct') {
947 $info->{create}->{create} = {
948 setallArgs => [ 'SegmentAllocator alloc$' ],
951 } elsif ($s->{category} eq 'union') {
952 foreach my $m (@{$s->{items}}) {
953 $info->{create}->{"create$m->{Name}"} = {
954 setallArgs => [ 'SegmentAllocator alloc$' ],
962 #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
964 # FIXME: unions need multiple constructors!
966 foreach my $m (@{$s->{items}}) {
967 my $nstar = $m->{deref} =~ tr/*/*/;
968 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
969 my $type = $types->{$deref};
970 my $v = buildVars($s, $m, $type);
972 die "No type $deref ".Dumper($m, $s) if !$type;
974 #push @{$info->{getset}}, map { "// $_" } split(/\n/, Dumper($m->{deref}, $type, $override->{$m->{name}}));
975 push @{$info->{varhandle}}, "/* ? Accessor: $m->{fullType} [$m->{deref}] $m->{name} len=$m->{len} lenfor=$m->{lengthfor} override=$deref */";
977 if ($type->{accessor}) {
978 push @{$info->{getorset}}, code::formatTemplate($type->{accessor}->{getorset}, $v) if $type->{accessor}->{getorset};
981 push @{$info->{init}}, code::formatTemplate($type->{accessor}->{init}, $v) if $type->{accessor}->{init};
982 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
984 push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
985 push @{$info->{set}}, code::formatTemplate($type->{accessor}->{set}, $v) if $type->{accessor}->{set};
987 # FIXME: something here is adding length parameters which are already handled by the setXX() calls
988 if (!$m->{'no-setall'}) {
989 my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
990 push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
991 push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
995 push @{$info->{varhandle}}, code::formatTemplate($v->{handle}, $v) if $v->{handle};
998 # create constructors
1000 package => 'vulkan',
1003 layout => formatStructLayout($types, $s),
1004 init => join ("\n", @{$info->{init}}),
1005 get => join ("\n", @{$info->{get}}),
1006 set => join ("\n", @{$info->{set}}),
1007 getorset => join ("\n", @{$info->{getorset}}),
1008 #'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
1009 #'java-setall' => join ("\n", @{$info->{setall}}),
1010 varhandle => join ("\n", @{$info->{varhandle}}),
1014 # build sub-components using the full $v
1016 foreach my $k (keys %{$template->{insert}}) {
1017 my $t = $template->{insert}->{$k};
1019 if ($k eq 'create-all') {
1020 foreach my $kk (keys %{$info->{create}}) {
1021 my $create = $info->{create}->{$kk};
1023 if ($#{$create->{setallArgs}} > 0) {
1027 'java-setall-arguments' => join (', ', @{$create->{setallArgs}}),
1028 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
1030 push @createAll, code::formatTemplateStream($t, $v);
1034 $v->{$k} = code::formatTemplate($t, $v);
1037 $v->{'create-all'} = join("\n", @createAll);
1039 join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1040 code::formatTemplateStream($template->{class}, $v);
1043 # TODO: the template here could be mapped from types.api perhaps?
1044 # also same for the various fields, init/getset/etc.
1049 my $templates = $structTypes->{templates};
1050 my $overrides = $structTypes->{overrides};
1051 my $override = $overrides->{$s->{name}};
1052 my $template = $override->{template} ? $override->{template} : $templates->{handle};
1059 if (defined $s->{commands}) {
1060 foreach my $k (sort @{$s->{commands}}) {
1061 my $c = $api->{commands}->{$k};
1062 push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
1067 package => 'vulkan',
1070 init => join ("\n", @{$info->{init}}),
1071 commands => join ("\n", @{$info->{commands}}),
1074 code::formatTemplateStream($template->{class}, $v);
1077 sub formatFunctionPointer {
1081 my $templates = $structTypes->{templates};
1082 my $template = $templates->{funcpointer}->{class};
1089 package => 'vulkan',
1095 package => 'vulkan',
1098 init => join ("\n", @{$info->{init}}),
1099 upcall => code::formatTemplateStream($templates->{funcpointer}->{upcall}, $vcall),
1100 downcall => code::formatTemplateStream($templates->{funcpointer}->{downcall}, $vcall),
1103 code::formatTemplateStream($template, $v);
1106 sub formatFunctionDescriptor {
1110 my $templates = $ct->{templates};
1111 my $types = $ct->{types};
1112 my $overrides = $ct->{overrides};
1115 my $void = $s->{proto}->{fullType} eq 'void';
1116 my $override = $overrides->{$s->{name}};
1118 foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1119 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1120 my $type = $types->{$deref};
1122 die "No type found ".Dumper($m, $s, $override) if !$type;
1124 my $v = buildVars($s, $m, $type);
1126 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1129 return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1130 .join(",\n\t\t", @fields).')';
1133 sub formatFunction {
1137 my $templates = $ct->{templates};
1138 my $types = $ct->{types};
1139 my $overrides = $ct->{overrides};
1140 my $void = $s->{proto}->{fullType} eq 'void';
1141 my $override = $overrides->{$s->{name}};
1142 my $template = $override->{template} ? $override->{template} : $templates->{method};
1145 my @invokeArgs = ();
1146 my @nativeInit = ();
1151 rename => $s->{name},
1153 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1154 'native-result-define' => '',
1155 'native-result-assign' => '',
1156 'result-test' => '',
1157 'create-frame' => '',
1158 'java-result' => 'void',
1159 'java-result-assign' => '',
1160 'java-result-return' => 'return;',
1161 'result-throw' => '',
1164 my $hasInstance = 0;
1169 #return if !defined($override->{template});
1170 #return if ($s->{name} ne 'vkCmdUpdateBuffer');
1172 foreach my $m (@{$s->{items}}) {
1173 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1174 my $type = $types->{$deref};
1176 die "No type found ".Dumper($m, $s, $override) if !$type;
1178 my $v = buildVars($s, $m, $type);
1180 #push @javaArgs, "/* $m->{name} $m->{deref} */ " if !$v->{'java-argument'};
1182 push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
1183 push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
1185 push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
1186 push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
1188 if ($v->{'query-arg'}) {
1189 push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
1190 } elsif ($v->{'invoke-arg'}) {
1191 push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
1194 $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
1195 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
1196 $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
1198 $needScope = 1 if $type->{'need-scope'};
1199 $needFrame = 1 if $type->{'need-frame'};
1200 $needAlloc = 1 if $type->{'need-alloc'};
1201 $hasInstance = 1 if $type->{'is-instance'};
1204 $info->{'static'} = $hasInstance ? '' : 'static ';
1206 if ($s->{successcodes}) {
1207 my @codes = split(/,/,$s->{successcodes});
1209 $info->{'native-result-define'} = 'int result$;';
1210 $info->{'native-result-assign'} = 'result$ = (int)';
1211 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1212 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1214 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1215 $info->{'java-result'} = 'int';
1216 $info->{'java-result-return'} = 'return result$;';
1219 } elsif ($s->{proto}->{fullType} ne 'void') {
1220 my $m = $s->{proto};
1221 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1223 die Dumper($m, $s) if !defined($type);
1224 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1226 my $v = buildVars($s, $m, $type);
1228 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1229 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1230 $info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1231 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1232 $info->{'java-result-return'} = code::formatTemplate($v->{'java-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->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1248 $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1250 #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1251 code::formatTemplate($template->{invoke}, $info);