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);
64 foreach my $s (values %{$api->{types}}) {
65 my $overrides = $structTypes->{overrides};
66 my $types = $structTypes->{types};
68 next if (defined($overrides->{$s->{name}}));
71 map { $lengths{$_->{lengthfrom}}++ if $_->{lengthfrom} } @{$s->{items}};
73 foreach my $m (@{$s->{items}}) {
74 my $nstar = $m->{deref} =~ tr/*/*/;
76 # FIXME: this belongs in analyse
77 if ($m->{lengthfrom} && $lengths{$m->{lengthfrom}} != 1) {
78 $m->{'set-length'} = '';
81 if ($m->{lengthfor} && $nstar == 0 && $lengths{$m->{name}} == 1) {
82 $overrides->{$s->{name}}->{$m->{name}}->{type} = $m->{deref}.'-implied';
84 if ($m->{deref} eq 'struct*-length') {
85 $defaultTemplate{$m->{baseType}}->{array} = 1;
86 } elsif ($m->{deref} eq 'struct[]') {
87 $defaultTemplate{$m->{baseType}}->{array} = 1;
91 if ($s->{returnedonly} eq 'true') {
92 $defaultTemplate{$s->{name}}->{name} = 'struct-readonly';
96 # build default overrides for commands
97 foreach my $s (values %{$api->{commands}}) {
98 my $overrides = $commandTypes->{overrides};
99 my $types = $commandTypes->{types};
101 # check type updates anyway
102 foreach my $m (@{$s->{items}}) {
103 if ($m->{deref} eq 'struct*-length') {
104 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
105 $defaultTemplate{$m->{baseType}}->{array} = 1;
106 } elsif ($m->{deref} eq 'struct*') {
107 $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n);
111 next if (defined($overrides->{$s->{name}}));
113 my $first = $s->{items}->[0];
114 my $last = $s->{items}->[$#{$s->{items}}];
115 my $result = $s->{proto};
116 my $index = $s->{index};
118 #map { $index->{$_->{name}} = $_ } @{$s->{items}};
122 # force handles to be instance types
123 if ($first->{deref} eq 'handle') {
124 $override->{$first->{name}}->{type} = 'instance';
127 # extension functions
128 if (defined($s->{extensions})) {
129 $override->{template} = $commandTypes->{templates}->{'method-extension'};
132 if ($last->{deref} eq 'handle*') {
134 my $t = $api->{handles}->{$last->{baseType}};
135 print "constructor: $s->{name}\n" if $sys->{verbose};
136 $override->{$last->{name}}->{type} =
137 $t->{type} eq 'VK_DEFINE_HANDLE' && $t->{name} ne 'VkInstance' ?
138 'dispatch*-output' : 'handle*-output';
139 } elsif ($index->{$last->{len}}) {
140 print "constructor?: $s->{name}\n";# if $sys->{verbose};
143 print "allocate-constructor?: $s->{name} $last->{len}\n";# if $sys->{verbose};
147 # ones we care about with output
153 if ($s->{successcodes} =~ m/VK_INCOMPLETE/ && $last->{deref} =~ m/-length$/) {
154 my $protoa = "$result->{fullType} $s->{name}("
155 .join(', ', map { "$_->{fullType}" } @{$s->{items}})
157 my $protob = "$result->{deref} $s->{name}("
158 .join(', ', map { $_->{len} ? "$_->{deref} \[$_->{len}\]" : $_->{deref} } @{$s->{items}})
161 print "array-constructor: $protoa\n" if $sys->{verbose} > 1;
162 print "array-constructor: $protob\n" if $sys->{verbose} > 1;
164 $override->{template} =
165 defined($s->{extensions}) ?
166 $commandTypes->{templates}->{'method-extension-query'} :
167 $commandTypes->{templates}->{'method-query'};
168 foreach my $m (@{$s->{items}}) {
169 if ($m->{deref} =~ m/-length$/ && (my $len = $index->{$m->{len}})) {
172 if ($m->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE') {
173 $type = 'dispatch*-length-query';
175 $type = $m->{deref}.'-query';
178 die "no template $m->{deref}-query" if !defined($commandTypes->{types}->{$type});
179 $override->{$m->{name}}->{type} = $type;
181 die "no template $len->{deref}-querysize" if !defined($commandTypes->{types}->{$len->{deref}.'-querylen'});
182 $override->{$len->{name}}->{type} = $len->{deref}.'-querylen';
187 # other per-item things
188 foreach my $m (@{$s->{items}}) {
189 my $so = $structTypes->{overrides}->{$m->{baseType}};
192 $m->{deref} .= '-ignore';
195 # All the vkCmd commands shouldn't imply any array lengths, maybe nothing should really?
196 if ($first->{baseType} ne 'VkCommandBuffer' && $m->{lengthfor}) {
197 my $nstar = $m->{deref} =~ tr/*/*/;
199 die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
200 $override->{$m->{name}}->{type} = $m->{deref}.'-length';
202 if (defined($s->{extensions})) {
203 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-extension'};
204 print "length-extension: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
206 #die "No '$m->{deref}-output' type ".Dumper($s) if !defined $types->{$m->{deref}.'-otuput'};
208 #$overrides->{$s->{name}}->{template} = $commandTypes->{templates}->{'method-query'};
209 #$overrides->{$s->{name}}->{$m->{name}}->{type} = $types->{$m->{deref}.'-output'};
211 print "length: $m->{deref} $s->{name} $m->{name} $m->{lengthfor}\n" if $sys->{verbose};
215 # TODO: implied return things
219 $overrides->{$s->{name}} = $override if %{$override};
223 my $overrides = $structTypes->{overrides};
224 my $templates = $structTypes->{templates};
226 foreach my $k (keys %defaultTemplate) {
227 print "what?: ".Dumper($overrides->{$k}->{template}) if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
228 next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
230 my $t = $defaultTemplate{$k};
231 my $name = $t->{name} || "struct-writeonly";
233 $name .= "-array" if $t->{array};
235 print "$name: $k\n" if $sys->{verbose} > 1;
236 die "No override $k $name" if !$templates->{$name};
237 $overrides->{$k}->{template} = $templates->{$name};
242 #$overrides->{$s->{name}}->{template} = $structTypes->{templates}->{'struct-readonly'};
244 #print Dumper({ types=>$types, templates=>$templates });
248 open(my $f, '>', 'types.pm');
249 print $f Dumper($commandTypes, $structTypes);
254 open(my $f, '>', 'api.pm');
255 print $f Dumper($api);
261 open(my $f, '>', 'data.pm');
263 'handles' => $api->{handles},
264 'types' => $api->{types},
265 'commands' => $api->{commands},
266 'funcpointers' => $api->{funcpointers},
271 exportEnums($vk, $api, 'VkConstants');
273 # dump out the extension function tables
275 my $f = openOutput($sys, 'DispatchInstance');
276 my $template = $structTypes->{templates}->{dispatch};
280 foreach my $k (sort keys %{$api->{commands}}) {
281 my $c = $api->{commands}->{$k};
283 next if !defined($c->{extensions});
285 push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
286 push @init, code::formatTemplate($template->{'init'}, $c);
292 Name => 'DispatchInstance',
293 init => join("\n\t\t", @init),
294 'field-init' => join("\n\t", @fieldInit),
296 print $f code::formatTemplateStream($template->{class}, $vars);
298 closeOutput($sys, 'DispatchInstance', $f);
302 foreach my $k (sort keys %{$api->{types}}) {
303 my $s = $api->{data}->{$k};
308 my $override = $structTypes->{overrides}->{$s->{name}};
310 next if $override->{ignore};
312 my $f = openOutput($sys, $s->{Name});
313 print $f formatStruct($vk, $api, $s);
314 closeOutput($sys, $s->{Name}, $f);
318 foreach my $k (sort keys %{$api->{handles}}) {
319 my $s = $api->{data}->{$k};
324 my $f = openOutput($sys, $s->{name});
325 print $f formatHandle($vk, $api, $s);
326 closeOutput($sys, $s->{name}, $f);
330 foreach my $k (sort keys %{$api->{funcpointers}}) {
331 my $s = $api->{data}->{$k};
336 my $override = $commandTypes->{overrides}->{$s->{name}};
338 next if $override->{ignore};
340 my $f = openOutput($sys, $s->{name});
341 print $f formatFunctionPointer($vk, $api, $s);
342 closeOutput($sys, $s->{name}, $f);
347 # ###################################################################### #
352 my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
358 foreach my $t (@{$config->{objects}}) {
359 if ($t->{type} eq 'type') {
360 my $nopts = $#{$t->{options}};
363 die ("No prototype provided/found for empty type ".Dumper($t)) if ($#{$t->{items}} < 0 && $#{$t->{options}} < 0);
365 # Check options / load inherited values
366 foreach my $o (@{$t->{options}}) {
367 if ($o =~ m/^accessor=(.*)$/o) {
368 die "No template $1" if !defined($templates->{$1});
369 $type->{accessor} = $templates->{$1};
370 } elsif ($o eq 'need-frame') {
371 $type->{'need-frame'} = 1;
372 } elsif ($o eq 'need-scope') {
373 $type->{'need-scope'} = 1;
374 } elsif ($o eq 'trampoline-scope') {
375 $type->{'trampoline-scope'} = 1;
376 } elsif ($o eq 'need-alloc') {
377 $type->{'need-alloc'} = 1;
378 } elsif ($o eq 'is-instance') {
379 $type->{'is-instance'} = 1;
380 } elsif (defined($types->{$o})) {
381 $type = { %$type, %{$types->{$o}} };
383 die "Unknown option '$o' in ".Dumper($t);
388 foreach my $s (@{$t->{items}}) {
389 # FIXME: maybe i don't want struct here, as with templates
391 code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
394 $x->{eval} = 1 if config::optionFlag('eval', $s);
396 $type->{$s->{match}} = $x;
399 # Write to all aliases
400 foreach my $k (split /,/,$t->{name}) {
401 $types->{$k} = $type;
403 } elsif ($t->{type} eq 'code') {
408 foreach my $o (@{$t->{options}}) {
409 if ($o =~ m/insert=(.*)/) {
410 foreach my $t (split /,/,$1) {
411 if ($t =~ m/(.*):(.*)/) {
412 die if !defined $templates->{$1}->{$2};
413 $code->{insert}->{$2} = $templates->{$1}->{$2};
416 } elsif ($o =~ m/^fields=(.*)/) {
417 $code->{fields} = $1;
419 die ("Unknown option $o");
423 foreach my $s (@{$t->{items}}) {
424 $code->{$s->{match}} = $s->{literal};
425 $code->{$s->{match}} =~ s/^\t//gm;
427 # hack since the template is a string
428 $code->{"$s->{match}:eval"}->{eval} = 1 if config::optionFlag('eval', $s);
431 $templates->{$t->{name}} = $code;
432 } elsif ($t->{type} eq 'override') {
433 foreach my $s (@{$t->{items}}) {
435 foreach my $o (@{$s->{options}}) {
436 if ($o =~ m/^(.*)=type:(.*)/) {
437 die "No such type $s->{match} $2\n" if !defined $types->{$2};
438 $c->{$1}->{type} = $2;
439 } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
440 die "No accessor template $o" if !defined($templates->{$2});
441 $c->{$1}->{accessor} = $templates->{$2};
442 } elsif ($o =~ m/^template=(.*)/) {
443 die "No template $o" if !defined($templates->{$1});
444 $c->{template} = $templates->{$1};
445 } elsif ($o eq 'ignore') {
449 $overrides->{$s->{match}} = $c;
454 # templates should probably just go in one
457 templates => $templates,
458 overrides => $overrides,
464 return grep { !$seen{$_}++ } @_;
473 my $f = openOutput($sys, $name);
475 print $f "package vulkan;\npublic interface VkConstants {\n";
477 # special case for api constants
478 # special case for api constants
480 my $s = $api->{data}->{'API Constants'};
482 print $f "\n\t// API Constants\n";
484 foreach my $m (@{$s->{items}}) {
485 next if defined($m->{alias});
486 next if $seen->{$m->{name}}++;
488 my $i = $enumInfo->{$m->{type}};
492 $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
494 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
498 foreach my $k (sort keys %{$api->{enums}}) {
499 my $s = $api->{data}->{$k};
500 my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
501 my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
505 print $f "\n\t// $s->{name} $type\n";
507 foreach my $m (@{$s->{items}}) {
508 next if defined($m->{alias});
509 next if $seen->{$m->{name}}++;
513 $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
515 die Dumper("Ca't work out value", $m, $s) if !defined($v);
516 print $f "\tpublic final static $i->{type} $m->{name} = $v$i->{suffix};\n";
521 closeOutput($sys, $name, $f);
524 # ###################################################################### #
525 # class.name to class/name.java
530 $name = $sys->{package}.'.'.$name;
532 $name = $sys->{output}.'/'.$name.'.java';
540 my $path = classToPath($sys, $name);
543 rename($path.'~', $path) || die ("rename failed: $!");
550 my $path = classToPath($sys, $name);
551 my $dir = dirname($path);
553 make_path($dir) if (!-d $dir);
555 open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
556 print "writing '$path'\n" if $sys->{verbose} > 0;
561 # Calculate canonical derefernce types for each field and parameter
573 map { $index->{$_->{name}} = $_ } @_;
575 $s->{index} = $index;
578 my $t = $api->{data}->{$m->{baseType}};
579 my $nstar = $m->{fullType} =~ tr/*/*/;
584 if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
588 } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
591 if ($isize =~ m/^\d+$/n) {
594 $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
598 } elsif ($m->{fullType} =~ m/[\[\]]/on) {
603 # will be primitive or external
604 $type = $m->{baseType} if ($nstar == 0);
605 $type = "$m->{baseType}*" if ($nstar == 1);
606 $type = "$m->{baseType}**" if ($nstar == 2);
610 while ($t->{alias}) {
611 print "alias $t->{name} -> $t->{alias}\n";
612 $t = $api->{data}->{$t->{alias}};
614 $m->{baseType} = $t->{name};
617 if ($t->{category} =~ m/enum|bitmask/on) {
618 $t = $vk->{data}->{$t->{fullType}};
619 $type = $t->{type} if ($nstar == 0);
620 $type = "$t->{type}*" if ($nstar == 1);
622 } elsif ($t->{category} =~ m/struct|union/on) {
623 $m->{type} = $t->{name};
624 $type = 'struct' if ($nstar == 0);
625 $type = 'struct*' if ($nstar == 1);
626 $type = 'struct**' if ($nstar == 2);
628 } elsif ($t->{category} eq 'handle') {
629 $m->{type} = $t->{name};
630 #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
631 # $type = 'dhandle' if ($nstar == 0);
632 # $type = 'dhandle*' if ($nstar == 1);
634 $type = 'handle' if ($nstar == 0);
635 $type = 'handle*' if ($nstar == 1);
638 } elsif ($t->{category} eq 'basetype') {
640 $type = $t->{type} if ($nstar == 0);
641 $type = "$t->{type}*" if ($nstar == 1);
642 die Dumper($m, $t) if $nstar > 1;
643 } elsif ($t->{category} eq 'funcpointer') {
644 $m->{type} = $t->{name};
645 $type = "funcpointer" if ($nstar == 0);
652 # an array type with a length
653 if ($nstar > 0 && $m->{len}) {
654 if ($s->{category} =~ m/struct|union/on) {
656 if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
657 $m->{length} = $1.'VkConstants.'.$2.$3;
658 } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
659 my $len = $index->{$2};
661 $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
662 #$index->{$2}->{lengthfor} = $m->{name} if $index->{$2};
663 $m->{lengthfrom} = $len->{name};
666 die "Unhandled len/altlen: ".Dumper($m);
668 } elsif ($m->{len} =~ m/(.*),null-terminated/) {
669 my $len = $index->{$1};
671 $m->{length} = "get$len->{Name}()";
672 $m->{lengthfrom} = $len->{name};
673 $len->{lengthfor} = $m->{name};
674 $m->{'set-length'} = "set$len->{Name}((int)Memory.length($m->{name}))";
676 } elsif ($m->{len} eq 'null-terminated') {
678 } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
681 my $len = $index->{$m->{len}};
683 my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
685 die "Not simple type" if ($len->{fullType} ne $len->{baseType});
686 $m->{length} = "get$len->{Name}()";
687 $m->{lengthfrom} = $len->{name};
688 $len->{lengthfor} = $m->{name};
689 $m->{'set-length'} = "set$len->{Name}($cast"."Memory.length($m->{name}))";
691 die "what?".Dumper($m);
694 } elsif ($s->{category} eq 'command') {
698 $m->{length} = $m->{len} if $index->{$m->{len}};
699 $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
704 $type = $type.'-length' if $m->{length};
707 $seen->{$m->{fullType}} = $type.$array;
708 $m->{deref} = $type.$array;
710 # Calculate name, with some fixup hacks
711 my $name = $m->{name};
712 #if ($s->{type} =~ m/struct|union/on)
714 # Strip leading 'p' for pointers
715 if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
716 $name = 'PGeometries';
717 } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
720 if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
724 $name = substr $name, $strip;
727 $name =~ s/^pfn//o if $type eq 'funcpointer';
729 $name =~ s/(?:^|_)(.)/\U$1/og;
740 foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
741 analyseFields($vk, $api, $seen, $s, @{$s->{items}});
743 my $name = $s->{name};
744 $name =~ s/(?:^|_)(.)/\U$1/og;
747 my $first = $s->{items}->[0];
748 my $second = $s->{items}->[1];
750 if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
751 $first->{'no-setall'} = 1;
752 $second->{'no-setall'} = 1;
753 print "typed: $s->{name}\n" if $sys->{verbose} > 1;
755 print "untyped: $s->{name}\n" if $sys->{verbose} > 1;
759 foreach my $c (values %{$api->{funcpointers}}) {
760 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
763 foreach my $c (values %{$api->{commands}}) {
764 $c->{proto}->{name} = 'result$';
765 $c->{proto}->{Name} = 'result$';
766 analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
768 # collect all member functions on handles
769 my $first = $c->{items}->[0];
770 my $last = $c->{items}->[$#{$c->{items}}];
771 if ($first->{deref} eq 'handle') {
772 my $t = $api->{handles}->{$first->{baseType}};
773 while ($t->{alias}) {
774 $t = $api->{handles}->{$t->{alias}};
776 die "No handle found ".Dumper($c) if !defined $t;
777 push @{$t->{commands}}, $c->{name};
778 } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
779 push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
781 die "No owner for call ".Dumper($c);
785 print "Unique Types:\n";
787 map { $base->{$_} = 1 } values %$seen;
789 foreach my $k (sort keys %$base) {
796 # this way-over-evaluates, probably only call once on every field and member instead
803 foreach my $k (keys %$type) {
808 } elsif ($t->{eval}) {
809 $v->{$k} = eval $t->{code};
811 die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
812 } elsif (defined($t->{code})) {
813 $v->{$k} = $t->{code};
820 sub formatStructLayout {
826 # This doens't need to worry about overrides
828 if ($s->{category} eq 'struct') {
829 foreach my $m (@{$s->{items}}) {
830 my $type = $types->{$m->{deref}};
831 my $diff = $m->{bitOffset} - $offset;
833 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
836 my $v = buildVars($s, $m, $type);
838 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
839 $offset = $m->{bitOffset} + $m->{bitSize};
841 push @fields, "/* Missing: $m->{deref} $m->{name} */";
845 foreach my $m (@{$s->{items}}) {
846 my $type = $types->{$m->{deref}};
849 my $v = buildVars($s, $m, $type);
851 push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
852 $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
854 push @fields, "/* Missing: $m->{deref} $m->{name} */";
859 my $diff = $s->{bitSize} - $offset;
861 push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
863 return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
866 sub formatAccessorIf {
873 my $accessor = $type->{accessor};
874 my $template = $accessor->{$field};
877 $template = eval($template) if ($accessor->{"$field:eval"});
879 die "Error executing template $field $accessor->{$field}: $@" if (!defined($template));
881 push @{$info->{$field}}, code::formatTemplate($template, $v) if $template;
889 my $templates = $structTypes->{templates};
890 my $types = $structTypes->{types};
891 my $overrides = $structTypes->{overrides};
893 my $override = $overrides->{$s->{name}};
894 my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
895 my @fields = split(/,/, $template->{fields});
898 map { $info->{$_} = [] } @fields;
900 my $setall = defined $info->{'java-setall'};
903 if ($s->{category} eq 'struct') {
904 $info->{create}->{create} = {
905 'setall-arg' => [ 'SegmentAllocator alloc$' ],
908 } elsif ($s->{category} eq 'union') {
909 foreach my $m (@{$s->{items}}) {
910 $info->{create}->{"create$m->{Name}"} = {
911 'setall-arg' => [ 'SegmentAllocator alloc$' ],
920 #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
922 # FIXME: unions need multiple constructors!
924 foreach my $m (@{$s->{items}}) {
925 my $nstar = $m->{deref} =~ tr/*/*/;
926 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
927 my $type = $types->{$deref};
929 die "No type $deref ".Dumper($m, $s) if !$type;
931 if ($type->{accessor}) {
932 my $v = buildVars($s, $m, $type);
936 @todump = qw(init initat set setat);
938 @todump = qw(get getat set setat getorset getorsetat);
940 # FIXME: something here is adding length parameters which are already handled by the setXX() calls
941 if ($setall && !$m->{'no-setall'}) {
942 my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
943 #push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
944 #push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
945 formatAccessorIf($s, $m, $create, $type, 'setall-arg', $v);
946 formatAccessorIf($s, $m, $create, $type, 'setall', $v);
950 push @{$info->{handle}}, code::formatTemplate($v->{handle}, $v)." /* $m->{name} $m->{fullType} ($m->{deref}) */" if $info->{handle} && $v->{handle};
951 push @{$info->{handleat}}, code::formatTemplate($v->{handleat}, $v) if $info->{handleat} && $v->{handleat};
953 foreach my $field (@todump) {
954 push @{$info->{$field}}, code::formatTemplate($type->{accessor}->{$field}, $v) if $info->{$field} && $type->{accessor}->{$field};
959 # create constructors
964 layout => formatStructLayout($types, $s),
965 #init => join ("\n", @{$info->{init}}),
966 #get => join ("\n", @{$info->{get}}),
967 #set => join ("\n", @{$info->{set}}),
968 #getorset => join ("\n", @{$info->{getorset}}),
969 ##'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
970 ##'java-setall' => join ("\n", @{$info->{setall}}),
971 #varhandle => join ("\n", @{$info->{varhandle}}),
974 foreach my $field (@fields) {
975 $v->{$field} = join("\n", @{$info->{$field}});
978 # build sub-components using the full $v
980 foreach my $k (keys %{$template->{insert}}) {
981 my $t = $template->{insert}->{$k};
983 if ($k eq 'create-all') {
985 foreach my $kk (keys %{$info->{create}}) {
986 my $create = $info->{create}->{$kk};
988 if ($#{$create->{'setall-arg'}} > 0) {
992 'java-setall-arguments' => join (', ', @{$create->{'setall-arg'}}),
993 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
995 push @createAll, code::formatTemplateStream($t, $v);
1000 $v->{$k} = code::formatTemplate($t, $v);
1003 $v->{'create-all'} = join("\n", @createAll) if $setall;
1005 #die Dumper($info) if $s->{name} eq 'VkMemoryOpaqueCaptureAddressAllocateInfo';
1007 join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1008 code::formatTemplateStream($template->{class}, $v);
1011 # TODO: the template here could be mapped from types.api perhaps?
1012 # also same for the various fields, init/getset/etc.
1017 my $templates = $structTypes->{templates};
1018 my $overrides = $structTypes->{overrides};
1019 my $override = $overrides->{$s->{name}};
1020 my $template = $override->{template} ? $override->{template} : $templates->{handle};
1027 if (defined $s->{commands}) {
1028 foreach my $k (sort @{$s->{commands}}) {
1029 my $c = $api->{commands}->{$k};
1030 push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
1035 package => 'vulkan',
1038 init => join ("\n", @{$info->{init}}),
1039 commands => join ("\n", @{$info->{commands}}),
1042 code::formatTemplateStream($template->{class}, $v);
1045 sub formatSignature {
1047 my $types = $commandTypes->{types};
1050 foreach my $m (@{$s->{items}}) {
1051 my $x = $types->{$m->{deref}};
1053 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1055 $d .= $x->{sig}->{code};
1059 my $m = $s->{proto};
1060 my $x = $types->{$m->{deref}};
1061 die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
1062 $d .= $x->{sig}->{code};
1065 # TODO: only collect shit we need
1066 sub collectFunctionInfo {
1070 my $templates = $ct->{templates};
1071 my $types = $ct->{types};
1072 my $overrides = $ct->{overrides};
1073 my $void = $s->{proto}->{fullType} eq 'void';
1074 my $override = $overrides->{$s->{name}};
1077 my @invokeArgs = ();
1078 my @nativeInit = ();
1082 my @nativeArgs = ();
1086 rename => $s->{name},
1088 'function-descriptor' => formatFunctionDescriptor($ct, $s),
1089 'native-result-define' => '',
1090 'native-result-assign' => '',
1091 'native-result' => 'void',
1092 'trampoline-result-define' => '',
1093 'trampoline-result-assign' => '',
1094 'trampoline-scope' => '',
1095 'result-test' => '',
1096 'create-frame' => '',
1097 'java-result' => 'void',
1098 'java-result-assign' => '',
1099 'result-throw' => '',
1101 'java-result-return' => 'return;',
1102 'trampoline-result-return' => 'return;',
1105 my $hasInstance = 0;
1111 #return if !defined($override->{template});
1112 #return if ($s->{name} ne 'vkCmdUpdateBuffer');
1114 my @arrayFields = qw(java-arg invoke-arg native-init query-init query-arg native-arg trampoline-arg);
1115 my @fixedFields = qw(java-result java-result-return java-result-assign);
1117 map { $info->{$_} = [] } @arrayFields;
1119 foreach my $m (@{$s->{items}}) {
1120 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1121 my $type = $types->{$deref};
1123 die "No type found ".Dumper($m, $s, $override) if !$type;
1125 my $v = buildVars($s, $m, $type);
1127 foreach my $field (@arrayFields) {
1129 push @{$info->{$field}}, code::formatTemplate($v->{$field}, $v);
1130 } elsif ($field eq 'query-arg') {
1131 push @{$info->{$field}}, code::formatTemplate($v->{'invoke-arg'}, $v);
1135 foreach my $field (@fixedFields) {
1136 $info->{$field} = code::formatTemplate($v->{$field}, $v) if ($v->{$field});
1140 push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
1141 push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
1143 push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
1144 push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
1146 if ($v->{'query-arg'}) {
1147 push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
1148 } elsif ($v->{'invoke-arg'}) {
1149 push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
1152 push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
1153 push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
1155 $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
1156 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
1157 $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
1160 $needScope = 1 if $type->{'need-scope'};
1161 $needFrame = 1 if $type->{'need-frame'};
1162 $needAlloc = 1 if $type->{'need-alloc'};
1163 $hasInstance = 1 if $type->{'is-instance'};
1164 $trampScope = 1 if $type->{'trampoline-scope'};
1167 $info->{'static'} = $hasInstance ? '' : 'static ';
1169 if ($s->{successcodes}) {
1170 my @codes = split(/,/,$s->{successcodes});
1172 $info->{'native-result-define'} = 'int result$;';
1173 $info->{'native-result-assign'} = 'result$ = (int)';
1174 $info->{'result-test'} = 'if ('.join("||", map { '(result$ == VkConstants.'.$_.')' } @codes).')';
1175 $info->{'result-throw'} = 'throw new RuntimeException("error " + result$);';
1177 if ($#codes > 0 && $info->{'java-result'} eq 'void') {
1178 $info->{'java-result'} = 'int';
1179 $info->{'java-result-return'} = 'return result$;';
1182 } elsif ($s->{proto}->{fullType} ne 'void') {
1183 my $m = $s->{proto};
1184 my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
1186 die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
1187 die Dumper($m, $s) if !defined($type->{'java-result-return'});
1189 my $v = buildVars($s, $m, $type);
1191 $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
1192 $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
1193 #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
1194 $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
1195 $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
1197 $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
1198 $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
1199 $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
1200 $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
1202 $needScope = 1 if $type->{'need-scope'};
1205 $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
1206 $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
1208 push @{$info->{'java-arg'}}, 'SegmentAllocator alloc$' if $needAlloc;
1209 push @{$info->{'java-arg'}}, 'ResourceScope scope$' if $needScope;
1211 foreach my $field (@arrayFields) {
1212 my $with = $field =~ m/-arg$/n ? ",\n\t" : "\n\t";
1213 $info->{$field} = join $with, @{$info->{$field}};
1217 $info->{'java-arguments'} = join ",\n\t", @javaArgs;
1218 $info->{'native-init'} = join "\n\t", @nativeInit;
1219 $info->{'invoke-arguments'} = join ", ", @invokeArgs;
1220 $info->{'query-init'} = join "\n\t\t\t", @queryInit;
1221 $info->{'query-arguments'} = join ", ", @queryArgs;
1223 $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
1224 $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
1227 $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
1228 $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
1230 if ($s->{category} eq 'funcpointer') {
1231 $info->{'trampoline-signature'} = formatSignature($s);
1237 sub formatFunctionPointer {
1241 my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
1242 my $info = collectFunctionInfo($api, $commandTypes, $s);
1245 package => 'vulkan',
1250 foreach my $k (keys %{$template->{insert}}) {
1251 my $t = $template->{insert}->{$k};
1253 $v->{$k} = code::formatTemplate($t, $info);
1256 code::formatTemplateStream($template->{class}, $v);
1259 sub formatFunctionDescriptor {
1263 my $templates = $ct->{templates};
1264 my $types = $ct->{types};
1265 my $overrides = $ct->{overrides};
1268 my $void = $s->{proto}->{fullType} eq 'void';
1269 my $override = $overrides->{$s->{name}};
1271 foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
1272 my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
1273 my $type = $types->{$deref};
1275 die "No type found ".Dumper($m, $s, $override) if !$type;
1277 my $v = buildVars($s, $m, $type);
1279 push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
1282 return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
1283 .join(",\n\t\t", @fields).')';
1286 sub formatFunction {
1290 my $templates = $ct->{templates};
1291 my $types = $ct->{types};
1292 my $overrides = $ct->{overrides};
1293 my $void = $s->{proto}->{fullType} eq 'void';
1294 my $override = $overrides->{$s->{name}};
1295 my $template = $override->{template} ? $override->{template} : $templates->{method};
1297 my $info = collectFunctionInfo($api, $ct, $s);
1299 #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
1300 code::formatTemplate($template->{invoke}, $info);