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 # ###################################################################### #
44 $sys->{output} = 'bin/gen/notzed.vulkan/classes';
45 $sys->{package} = 'vulkan';
48 my $vk = new vulkan($sys);
50 my $api = $vk->buildFeatures(
51 [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ],
56 my $structTypes = loadTypes($api, 'struct-types.api');
57 my $commandTypes = loadTypes($api, 'command-types.api');
59 analyseTypes($vk, $api);
61 # Use some heuristics to create overrides for improving the api
63 # - object constructor functions return values rather take pointer* values
64 # - array query functions perform the query and return the array
65 # - extension functions use a different invocation mechanism
66 # - drop any 'ignore' types from argument lists
68 # - [attempt to] determine which types need to be read/write/arrays
73 foreach my $s (values %{$api->{types}}) {
74 my $overrides = $structTypes->{overrides};
75 my $types = $structTypes->{types};
77 next if (defined($overrides->{$s->{name}}));
80 map { $lengths{$_->{lengthfrom}}++ if $_->{lengthfrom} } @{$s->{items}};
82 foreach my $m (@{$s->{items}}) {
83 my $nstar = $m->{deref} =~ tr/*/*/;
85 if ($m->{lengthfor} && $nstar == 0 && $lengths{$m->{name}} == 1) {
86 die "No type '$m->{deref}-implied'" if !defined($types->{"$m->{deref}-implied"});
88 $overrides->{$s->{name}}->{$m->{name}}->{type} = "$m->{deref}-implied";
89 print "implied: $s->{name} $m->{name} $m->{deref} $s->{index}->{$m->{lengthfor}}->{deref}\n" if $sys->{verbose};
92 if ($m->{deref} eq 'struct*-length') {
93 $defaultTemplate{$m->{baseType}}->{array} = 1;
94 } elsif ($m->{deref} eq 'struct[]') {
95 $defaultTemplate{$m->{baseType}}->{array} = 1;
99 $defaultTemplate{$s->{name}}->{name} = 'struct-readonly' if ($s->{returnedonly} eq 'true');
102 # build default overrides for commands
103 foreach my $s (values %{$api->{commands}}) {
104 my $overrides = $commandTypes->{overrides};
105 my $types = $commandTypes->{types};
106 my $first = $s->{items}->[0];
107 my $last = $s->{items}->[$#{$s->{items}}];
108 my $llast = $s->{items}->[$#{$s->{items}}-1];
109 my $result = $s->{proto};
110 my $index = $s->{index};
112 # check type updates anyway
113 foreach my $m (@{$s->{items}}) {
114 if ($m->{deref} eq 'struct*-length') {
115 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n) && $api->{types}->{$m->{baseType}}->{returnedonly} ne 'true';
116 $defaultTemplate{$m->{baseType}}->{array} = 1;
117 } elsif ($m->{deref} eq 'struct*') {
118 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
122 next if (defined($overrides->{$s->{name}}));
126 # force handles to be instance types
127 if ($first->{deref} eq 'handle') {
128 $override->{$first->{name}}->{type} = 'instance';
131 # extension function default template
132 if (defined($s->{extensions})) {
133 $override->{template} = 'method-extension';
137 if ($last->{deref} eq 'handle*') {
139 my $t = $api->{handles}->{$last->{baseType}};
140 print "constructor: $s->{name}\n" if $sys->{verbose};
141 $override->{$last->{name}}->{type} =
142 $t->{type} eq 'VK_DEFINE_HANDLE' && $t->{name} ne 'VkInstance' ?
143 'dispatch*-output' : 'handle*-output';
144 } elsif ($index->{$last->{len}}) {
145 print "constructor?: $s->{name}\n";# if $sys->{verbose};
148 print "allocate-constructor?: $s->{name} $last->{len}\n";# if $sys->{verbose};
152 # turn array-query functions into auto-allocate/return types
153 # ones we care about with output
159 if ($last->{deref} =~ m/-length$/ && (my $len = $index->{$last->{len}})) {
160 if (index($len->{deref}, '*') >= 0) {
161 my $protoa = "$result->{fullType} $s->{name}("
162 .join(', ', map { "$_->{fullType}" } @{$s->{items}})
164 print "array-constructor: $protoa\n" if $sys->{verbose} > 1;
166 my $otype = ($last->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE')
167 ? 'dispatch*-length-query' : $last->{deref}.'-query';
168 my $ltype = $len->{deref}.'-querylen';
170 die "no template $otype" if !defined($commandTypes->{types}->{$otype});
171 die "no template $ltype" if !defined($commandTypes->{types}->{$ltype});
173 $override->{template} = defined($s->{extensions}) ? 'method-extension-query' : 'method-query';
174 $override->{$last->{name}}->{type} = $otype;
175 $override->{$len->{name}}->{type} = $ltype;
179 # other per-item things
180 foreach my $m (@{$s->{items}}) {
181 my $so = $structTypes->{overrides}->{$m->{baseType}};
184 die "No type '$m->{deref}-ignore'" if !defined($types->{$m->{deref}.'-ignore'});
185 $override->{$m->{name}}->{type} = $m->{deref}.'-ignore';
189 $overrides->{$s->{name}} = $override if %{$override};
193 my $overrides = $structTypes->{overrides};
194 my $templates = $structTypes->{templates};
196 foreach my $k (keys %defaultTemplate) {
197 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
198 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
200 my $t = $defaultTemplate{$k};
201 my $name = $t->{name} || "struct-writeonly";
203 $name .= "-array" if $t->{array};
205 print "$name: $k\n" if $sys->{verbose} > 1;
206 die "No override $k $name" if !$templates->{$name};
207 $overrides->{$k}->{template} = $name;
212 open(my $f, '>', 'types.pm');
213 print $f Dumper($commandTypes, $structTypes);
218 open(my $f, '>', 'api.pm');
219 print $f Dumper($api);
224 exportEnums($vk, $api, 'VkConstants');
226 # dump out the extension function-pointer tables
228 my $f = openOutput($sys, 'DispatchInstance');
229 my $template = $structTypes->{templates}->{dispatch};
233 foreach my $k (sort keys %{$api->{commands}}) {
234 my $c = $api->{commands}->{$k};
236 next if !defined($c->{extensions});
238 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
239 push @init, code::formatTemplate($template->{'init'}, $c);
245 Name => 'DispatchInstance',
246 init => join("\n\t\t", @init),
247 'field-init' => join("\n\t", @fieldInit),
249 print $f code::formatTemplateStream($template->{class}, $vars);
251 closeOutput($sys, 'DispatchInstance', $f);
255 foreach my $k (sort keys %{$api->{types}}) {
256 my $s = $api->{data}->{$k};
261 my $override = $structTypes->{overrides}->{$s->{name}};
263 next if $override->{ignore};
265 my $f = openOutput($sys, $s->{Name});
266 print $f formatStruct($vk, $api, $s);
267 closeOutput($sys, $s->{Name}, $f);
271 foreach my $k (sort keys %{$api->{handles}}) {
272 my $s = $api->{data}->{$k};
277 my $f = openOutput($sys, $s->{name});
278 print $f formatHandle($vk, $api, $s);
279 closeOutput($sys, $s->{name}, $f);
283 foreach my $k (sort keys %{$api->{funcpointers}}) {
284 my $s = $api->{data}->{$k};
289 my $override = $commandTypes->{overrides}->{$s->{name}};
291 next if $override->{ignore};
293 my $f = openOutput($sys, $s->{name});
294 print $f formatFunctionPointer($vk, $api, $s);
295 closeOutput($sys, $s->{name}, $f);
300 # ###################################################################### #
305 my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
311 foreach my $t (@{$config->{objects}}) {
312 if ($t->{type} eq 'type') {
313 my $nopts = $#{$t->{options}};
316 die ("No prototype provided/found for empty type ".Dumper($t)) if ($#{$t->{items}} < 0 && $#{$t->{options}} < 0);
318 # Check options / load inherited values
319 foreach my $o (@{$t->{options}}) {
320 if ($o =~ m/^accessor=(.*)$/o) {
321 die "No template $1" if !defined($templates->{$1});
322 $type->{accessor} = $templates->{$1};
323 } elsif ($o eq 'need-frame') {
324 $type->{'need-frame'} = 1;
325 } elsif ($o eq 'need-scope') {
326 $type->{'need-scope'} = 1;
327 } elsif ($o eq 'trampoline-scope') {
328 $type->{'trampoline-scope'} = 1;
329 } elsif ($o eq 'need-alloc') {
330 $type->{'need-alloc'} = 1;
331 } elsif ($o eq 'is-instance') {
332 $type->{'is-instance'} = 1;
333 } elsif (defined($types->{$o})) {
334 $type = { %$type, %{$types->{$o}} };
336 die "Unknown option '$o' in ".Dumper($t);
341 foreach my $s (@{$t->{items}}) {
342 if (defined $s->{literal}) {
343 $type->{$s->{match}} = $s->{literal};
344 } elsif ($#{$s->{options}} >= 0) {
345 $type->{$s->{match}} = $s->{options}->[$#{$s->{options}}];
347 $type->{$s->{match}} = 0;
350 $type->{"$s->{match}:eval"} = 1 if config::optionFlag('eval', $s);
353 # Write to all aliases
354 foreach my $k (split /,/,$t->{name}) {
355 $types->{$k} = $type;
357 } elsif ($t->{type} eq 'code') {
362 foreach my $o (@{$t->{options}}) {
363 if ($o =~ m/insert=(.*)/) {
364 foreach my $x (split /,/,$1) {
365 if ($x =~ m/(.*):(.*)/) {
366 die "$x $t->{name} ".Dumper($templates->{$1}) if !defined $templates->{$1}->{$2};
367 $code->{insert}->{$2} = $templates->{$1}->{$2};
370 } elsif ($o =~ m/^fields=(.*)/) {
371 $code->{fields} = $1;
372 } elsif (defined($templates->{$o})) {
373 $code = { %$code, %{$templates->{$o}} };
375 die ("Unknown option '$o'");
379 foreach my $s (@{$t->{items}}) {
380 if (defined $s->{literal}) {
381 my $t = $s->{literal};
384 $code->{$s->{match}} = $t;
386 delete $code->{$s->{match}};
389 $code->{"$s->{match}:eval"} = 1 if config::optionFlag('eval', $s);
392 $templates->{$t->{name}} = $code;
393 } elsif ($t->{type} eq 'override') {
394 foreach my $s (@{$t->{items}}) {
396 foreach my $o (@{$s->{options}}) {
397 if ($o =~ m/^(.*)=type:(.*)/) {
398 die "No such type $s->{match} $2\n" if !defined $types->{$2};
399 $c->{$1}->{type} = $2;
400 } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
401 die "No accessor template $o" if !defined($templates->{$2});
402 $c->{$1}->{accessor} = $templates->{$2};
403 } elsif ($o =~ m/^template=(.*)/) {
404 die "No template $o" if !defined($templates->{$1});
406 } elsif ($o eq 'ignore') {
410 $overrides->{$s->{match}} = $c;
415 # templates should probably just go in one
418 templates => $templates,
419 overrides => $overrides,
425 return grep { !$seen{$_}++ } @_;
434 my $f = openOutput($sys, $name);
436 print $f "package vulkan;\npublic interface VkConstants {\n";
438 # special case for api constants
439 # special case for api constants
441 my $s = $api->{data}->{'API Constants'};
443 print $f "\n\t// API Constants\n";
445 foreach my $m (@{$s->{items}}) {
446 next if defined($m->{alias});
447 next if $seen->{$m->{name}}++;
449 my $i = $enumInfo->{$m->{type}};
453 $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
455 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
459 foreach my $k (sort keys %{$api->{enums}}) {
460 my $s = $api->{data}->{$k};
461 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
462 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
466 print $f "\n\t// $s->{name} $type\n";
468 foreach my $m (@{$s->{items}}) {
469 next if defined($m->{alias});
470 next if $seen->{$m->{name}}++;
474 $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
476 die Dumper("Ca't work out value", $m, $s) if !defined($v);
477 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
482 closeOutput($sys, $name, $f);
485 # ###################################################################### #
486 # class.name to class/name.java
491 $name = $sys->{package}.'.'.$name;
493 $name = $sys->{output}.'/'.$name.'.java';
501 my $path = classToPath($sys, $name);
504 rename($path.'~', $path) || die ("rename failed: $!");
511 my $path = classToPath($sys, $name);
512 my $dir = dirname($path);
514 make_path($dir) if (!-d $dir);
516 open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
517 print "writing '$path'\n" if $sys->{verbose} > 0;
522 # Calculate canonical derefernce types for each field and parameter
534 map { $index->{$_->{name}} = $_ } @_;
536 $s->{index} = $index;
539 my $t = $api->{data}->{$m->{baseType}};
540 my $nstar = $m->{fullType} =~ tr/*/*/;
545 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
549 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
552 if ($isize =~ m/^\d+$/n) {
555 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
559 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
564 # will be primitive or external
565 $type = $m->{baseType} if ($nstar == 0);
566 $type = "$m->{baseType}*" if ($nstar == 1);
567 $type = "$m->{baseType}**" if ($nstar == 2);
571 while ($t->{alias}) {
572 print "alias $t->{name} -> $t->{alias}\n";
573 $t = $api->{data}->{$t->{alias}};
575 $m->{baseType} = $t->{name};
578 if ($t->{category} =~ m/enum|bitmask/on) {
579 $t = $vk->{data}->{$t->{fullType}};
580 $type = $t->{type} if ($nstar == 0);
581 $type = "$t->{type}*" if ($nstar == 1);
583 } elsif ($t->{category} =~ m/struct|union/on) {
584 $m->{type} = $t->{name};
585 $type = 'struct' if ($nstar == 0);
586 $type = 'struct*' if ($nstar == 1);
587 $type = 'struct**' if ($nstar == 2);
589 } elsif ($t->{category} eq 'handle') {
590 $m->{type} = $t->{name};
591 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
592 # $type = 'dhandle' if ($nstar == 0);
593 # $type = 'dhandle*' if ($nstar == 1);
595 $type = 'handle' if ($nstar == 0);
596 $type = 'handle*' if ($nstar == 1);
599 } elsif ($t->{category} eq 'basetype') {
601 $type = $t->{type} if ($nstar == 0);
602 $type = "$t->{type}*" if ($nstar == 1);
603 die Dumper($m, $t) if $nstar > 1;
604 } elsif ($t->{category} eq 'funcpointer') {
605 $m->{type} = $t->{name};
606 $type = "funcpointer" if ($nstar == 0);
613 # an array type with a length
614 if ($nstar > 0 && $m->{len}) {
615 if ($s->{category} =~ m/struct|union/on) {
617 if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
618 $m->{length} = $1.'VkConstants.'.$2.$3;
619 } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
620 my $len = $index->{$2};
622 $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
623 #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
624 $m->{lengthfrom} = $len->{name};
627 die "Unhandled len/altlen: ".Dumper($m);
629 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
630 my $len = $index->{$1};
632 $m->{length} = "get$len->{Name}()";
633 $m->{lengthfrom} = $len->{name};
634 $len->{lengthfor} = $m->{name};
636 } elsif ($m->{len} eq 'null-terminated') {
638 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
641 my $len = $index->{$m->{len}};
643 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
645 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
646 $m->{length} = "get$len->{Name}()";
647 $m->{lengthfrom} = $len->{name};
648 $len->{lengthfor} = $m->{name};
650 die "what?".Dumper($m);
653 } elsif ($s->{category} eq 'command') {
657 $m->{length} = $m->{len} if $index->{$m->{len}};
658 $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
663 $type = $type.'-length' if $m->{length};
666 $seen->{$m->{fullType}} = $type.$array;
667 $m->{deref} = $type.$array;
669 # Calculate name, with some fixup hacks
670 my $name = $m->{name};
671 #if ($s->{type} =~ m/struct|union/on)
673 # Strip leading 'p' for pointers
674 if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
675 $name = 'PGeometries';
676 } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
679 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
683 $name = substr $name, $strip;
686 $name =~ s/^pfn//o if $type eq 'funcpointer';
688 $name =~ s/(?:^|_)(.)/\U$1/og;
699 foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
700 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
702 my $name = $s->{name};
703 $name =~ s/(?:^|_)(.)/\U$1/og;
706 my $first = $s->{items}->[0];
707 my $second = $s->{items}->[1];
709 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
710 $first->{'no-setall'} = 1;
711 $second->{'no-setall'} = 1;
712 print "typed: $s->{name}\n" if $sys->{verbose} > 1;
714 print "untyped: $s->{name}\n" if $sys->{verbose} > 1;
718 foreach my $c (values %{$api->{funcpointers}}) {
719 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
722 foreach my $c (values %{$api->{commands}}) {
723 $c->{proto}->{name} = 'result$';
724 $c->{proto}->{Name} = 'result$';
725 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
727 # collect all member functions on handles
728 my $first = $c->{items}->[0];
729 my $last = $c->{items}->[$#{$c->{items}}];
730 if ($first->{deref} eq 'handle') {
731 my $t = $api->{handles}->{$first->{baseType}};
732 while ($t->{alias}) {
733 $t = $api->{handles}->{$t->{alias}};
735 die "No handle found ".Dumper($c) if !defined $t;
736 push @{$t->{commands}}, $c->{name};
737 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
738 push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
740 die "No owner for call ".Dumper($c);
744 print "Unique Types:\n";
746 map { $base->{$_} = 1 } values %$seen;
748 foreach my $k (sort keys %$base) {
755 # this way-over-evaluates, probably only call once on every field and member instead
762 foreach my $k (grep { index($_, ':') == -1 } keys %$type) {
765 if ($type->{"$k:eval"}) {
767 die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
776 sub formatStructLayout {
782 # This doens't need to worry about overrides
784 if ($s->{category} eq 'struct') {
785 foreach my $m (@{$s->{items}}) {
786 my $type = $types->{$m->{deref}};
787 my $diff = $m->{bitOffset} - $offset;
789 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
792 my $v = buildVars($s, $m, $type);
794 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
795 $offset = $m->{bitOffset} + $m->{bitSize};
797 push @fields, "/* Missing: $m->{deref} $m->{name} */";
801 foreach my $m (@{$s->{items}}) {
802 my $type = $types->{$m->{deref}};
805 my $v = buildVars($s, $m, $type);
807 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
808 $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
810 push @fields, "/* Missing: $m->{deref} $m->{name} */";
815 my $diff = $s->{bitSize} - $offset;
817 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
819 return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
822 sub formatAccessorIf {
829 my $accessor = $type->{accessor};
830 my $template = $accessor->{$field};
833 $template = eval($template) if ($accessor->{"$field:eval"});
835 die "Error executing template $field $accessor->{$field}: $@" if (!defined($template));
837 push @{$info->{$field}}, code::formatTemplate($template, $v) if $template;
845 my $templates = $structTypes->{templates};
846 my $types = $structTypes->{types};
847 my $overrides = $structTypes->{overrides};
849 my $override = $overrides->{$s->{name}};
850 my $tempname = $override->{template} ? $override->{template} : 'struct-writeonly';
851 my $template = $templates->{$tempname};
852 my @fields = split(/,/, $template->{fields});
855 map { $info->{$_} = [] } @fields;
857 my $setall = defined $info->{'java-setall'};
859 # unions need multiple constructors
861 if ($s->{category} eq 'struct') {
862 $info->{create}->{create} = {
863 'setall-arg' => [ 'SegmentAllocator alloc$' ],
866 } elsif ($s->{category} eq 'union') {
867 foreach my $m (@{$s->{items}}) {
868 $info->{create}->{"create$m->{Name}"} = {
869 'setall-arg' => [ 'SegmentAllocator alloc$' ],
879 foreach my $m (@{$s->{items}}) {
880 my $nstar = $m->{deref} =~ tr/*/*/;
881 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
882 my $type = $types->{$deref};
884 die "No type $deref ".Dumper($m, $s) if !$type;
886 if ($type->{accessor}) {
887 my $v = buildVars($s, $m, $type);
891 @todump = qw(init initat init-array set setat);
893 @todump = qw(get getat set setat getorset getorsetat);
895 if ($setall && !$m->{'no-setall'}) {
896 my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
897 formatAccessorIf($s, $m, $create, $type, 'setall-arg', $v);
898 formatAccessorIf($s, $m, $create, $type, 'setall', $v);
902 push @{$info->{handle}}, code::formatTemplate($v->{handle}, $v)." /* $m->{name} $m->{fullType} ($m->{deref}) */" if $info->{handle} && $v->{handle};
903 push @{$info->{handleat}}, code::formatTemplate($v->{handleat}, $v) if $info->{handleat} && $v->{handleat};
905 foreach my $field (@todump) {
906 if ($info->{$field} && $type->{accessor}->{$field}) {
907 my $t = $type->{accessor}->{$field};
909 $t = eval $t if $type->{accessor}->{"$field:eval"};
910 die "$@" if !defined($t);
912 push @{$info->{$field}}, code::formatTemplate($t, $v);
918 # create constructors
923 layout => formatStructLayout($types, $s),
926 foreach my $field (@fields) {
927 $v->{$field} = join("\n", @{$info->{$field}});
930 # build sub-components using the full $v
932 foreach my $k (keys %{$template->{insert}}) {
933 my $t = $template->{insert}->{$k};
935 if ($k eq 'create-all') {
937 foreach my $kk (keys %{$info->{create}}) {
938 my $create = $info->{create}->{$kk};
940 if ($#{$create->{'setall-arg'}} > 0) {
944 'java-setall-arguments' => join (', ', @{$create->{'setall-arg'}}),
945 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
947 push @createAll, code::formatTemplateStream($t, $v);
952 $v->{$k} = code::formatTemplate($t, $v);
955 $v->{'create-all'} = join("\n", @createAll) if $setall;
957 #die Dumper($info) if $s->{name} eq 'VkMemoryOpaqueCaptureAddressAllocateInfo';
959 join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
960 code::formatTemplateStream($template->{class}, $v);
963 # TODO: the template here could be mapped from types.api perhaps?
964 # also same for the various fields, init/getset/etc.
969 my $templates = $structTypes->{templates};
970 my $overrides = $structTypes->{overrides};
971 my $override = $overrides->{$s->{name}};
972 my $tempname = $override->{template} ? $override->{template} : 'handle';
973 my $template = $templates->{$tempname};
980 if (defined $s->{commands}) {
981 foreach my $k (sort @{$s->{commands}}) {
982 my $c = $api->{commands}->{$k};
983 push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
991 init => join ("\n", @{$info->{init}}),
992 commands => join ("\n", @{$info->{commands}}),
995 code::formatTemplateStream($template->{class}, $v);
998 sub formatSignature {
1000 my $types = $commandTypes->{types};
1003 foreach my $m (@{$s->{items}}) {
1004 my $x = $types->{$m->{deref}};
1006 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1012 my $m = $s->{proto};
1013 my $x = $types->{$m->{deref}};
1014 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1018 # Forms all the parameter templates
1019 sub collectFunctionInfo {
1023 my $types = $ct->{types};
1024 my $overrides = $ct->{overrides};
1025 my $void = $s->{proto}->{fullType} eq 'void';
1026 my $override = $overrides->{$s->{name}};
1029 my @invokeArgs = ();
1030 my @nativeInit = ();
1034 my @nativeArgs = ();
1038 rename => $s->{name},
1040 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1041 'native-result-define' => '',
1042 'native-result-assign' => '',
1043 'native-result' => 'void',
1044 'trampoline-result-define' => '',
1045 'trampoline-result-assign' => '',
1046 'trampoline-scope' => '',
1047 'result-test' => '',
1048 'create-frame' => '',
1049 'java-result' => 'void',
1050 'java-result-assign' => '',
1051 'result-throw' => '',
1053 'java-result-return' => 'return;',
1054 'trampoline-result-return' => 'return;',
1057 my $hasInstance = 0;
1063 my @arrayFields = qw(java-arg invoke-arg native-init query-init query-arg native-arg trampoline-arg);
1064 my @fixedFields = qw(java-result java-result-return java-result-assign);
1066 map { $info->{$_} = [] } @arrayFields;
1068 # Calculate parameters
1069 foreach my $m (@{$s->{items}}) {
1070 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1071 my $type = $types->{$deref};
1073 die "No type found ".Dumper($m, $s, $override) if !$type;
1075 my $v = buildVars($s, $m, $type);
1077 foreach my $field (@arrayFields) {
1079 push @{$info->{$field}}, code::formatTemplate($v->{$field}, $v);
1080 } elsif ($field eq 'query-arg') {
1081 push @{$info->{$field}}, code::formatTemplate($v->{'invoke-arg'}, $v);
1085 foreach my $field (@fixedFields) {
1086 $info->{$field} = code::formatTemplate($v->{$field}, $v) if ($v->{$field});
1089 $needScope = 1 if $type->{'need-scope'};
1090 $needFrame = 1 if $type->{'need-frame'};
1091 $needAlloc = 1 if $type->{'need-alloc'};
1092 $hasInstance = 1 if $type->{'is-instance'};
1093 $trampScope = 1 if $type->{'trampoline-scope'};
1096 $info->{'static'} = $hasInstance ? '' : 'static ';
1098 # Handle default return types, others are handled by the fixedFields above
1099 if ($s->{successcodes}) {
1100 my @codes = split(/,/,$s->{successcodes});
1102 $info->{'native-result-define'} = 'int result$;';
1103 $info->{'native-result-assign'} = 'result$ = (int)';
1104 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1105 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1107 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1108 $info->{'java-result'} = 'int';
1109 $info->{'java-result-return'} = 'return result$;';
1111 } elsif ($s->{proto}->{fullType} ne 'void') {
1112 my $m = $s->{proto};
1113 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1115 die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
1116 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1118 my $v = buildVars($s, $m, $type);
1120 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1121 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1122 #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1123 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1124 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
1126 $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
1127 $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
1128 $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
1129 $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
1131 $needScope = 1 if $type->{'need-scope'};
1134 $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
1135 $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
1137 push @{$info->{'java-arg'}}, 'SegmentAllocator alloc$' if $needAlloc;
1138 push @{$info->{'java-arg'}}, 'ResourceScope scope$' if $needScope;
1140 foreach my $field (@arrayFields) {
1141 my $with = $field =~ m/-arg$/n ? ",\n\t" : "\n\t";
1142 $info->{$field} = join $with, @{$info->{$field}};
1145 $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1146 $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1148 if ($s->{category} eq 'funcpointer') {
1149 $info->{'trampoline-signature'} = formatSignature($s);
1155 sub formatFunctionPointer {
1159 my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
1160 my $info = collectFunctionInfo($api, $commandTypes, $s);
1163 package => 'vulkan',
1168 foreach my $k (keys %{$template->{insert}}) {
1169 my $t = $template->{insert}->{$k};
1171 $v->{$k} = code::formatTemplate($t, $info);
1174 code::formatTemplateStream($template->{class}, $v);
1177 sub formatFunctionDescriptor {
1180 my $types = $ct->{types};
1182 my $void = $s->{proto}->{fullType} eq 'void';
1183 my $override = $ct->{overrides}->{$s->{name}};
1185 foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1186 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1187 my $type = $types->{$deref};
1189 die "No type found ".Dumper($m, $s, $override) if !$type;
1191 my $v = buildVars($s, $m, $type);
1193 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1196 return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1197 .join(",\n\t\t", @fields).')';
1200 sub formatFunction {
1204 my $void = $s->{proto}->{fullType} eq 'void';
1205 my $override = $ct->{overrides}->{$s->{name}};
1206 my $tempname = $override->{template} ? $override->{template} : 'method';
1207 my $template = $ct->{templates}->{$tempname};
1209 my $info = collectFunctionInfo($api, $ct, $s);
1211 #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1212 " /* template: $tempname */\n".
1213 code::formatTemplate($template->{invoke}, $info);