Some work on the header version of vulkan binding.
authorNot Zed <notzed@gmail.com>
Tue, 26 Apr 2022 13:22:52 +0000 (22:52 +0930)
committerNot Zed <notzed@gmail.com>
Tue, 26 Apr 2022 13:22:52 +0000 (22:52 +0930)
It's still incomplete and probably at a dead end.

14 files changed:
src/notzed.nativez/bin/generate-api
src/notzed.nativez/classes/au/notzed/nativez/Memory.java
src/notzed.nativez/classes/au/notzed/nativez/Pointer.java
src/notzed.nativez/lib/api.pm
src/notzed.nativez/lib/config.pm
src/notzed.vkheader.test/classes/module-info.java
src/notzed.vkheader.test/classes/vulkan/test/Cube.java [new file with mode: 0644]
src/notzed.vkheader.test/classes/vulkan/test/GLMaths.java [new file with mode: 0644]
src/notzed.vkheader.test/classes/vulkan/test/TestCube.java [new file with mode: 0644]
src/notzed.vkheader/classes/module-info.java
src/notzed.vkheader/gen/vkheader.api
src/notzed.vkheader/gen/vkheader.h
src/notzed.vkheader/gen/vkheader.pm
src/notzed.vkheader/gen/vulkan.pm

index 9f35fa4..bec646d 100755 (executable)
@@ -25,7 +25,6 @@ use method;
 
 $SIG{__DIE__} = sub { Carp::confess( @_ ) };
 $SIG{'INT'} = sub { Carp::confess() };
-
 $Data::Dumper::Indent = 1;
 
 my $apidef = "api.api";
@@ -139,11 +138,6 @@ sub formatItems {
                $res->{seen}->{"$_->{type}:$_->{name}"}++ == 0
        } $api->findMatches($inc, $res->{ctx});
 
-       if ($obj->{name} eq 'VkInstance') {
-               print Dumper($obj, $inc, \@list);
-               die;
-       }
-
        if ($inc->{type} eq 'func' && $inc->{literal}) {
                push @{$res->{func}}, $inc->{literal};
        } elsif ($inc->{type} eq 'func') {
@@ -217,11 +211,12 @@ sub formatStruct {
        my $accessors = join "\n", map {
                my ($m, $type, $match) = ($_->{field}, $_->{type}, $_->{match});
                map {
-                       my $accessor = $api->{index}->{$_};
+                       my $tname = $_;
+                       my $accessor = $api->{index}->{$tname};
 
                        map { code::applyTemplate($_, $match) } grep { $_ } map { api::findItem($accessor, $_) } map {
                                my @list = ();
-                               if ($_ =~ m/r/o) {
+                               if ($_ =~ m/r/o || $tname eq 'code:getbyvalue') {
                                        push @list, 'get';
                                        push @list, 'geti' if $_ =~ m/i/o;
                                }
@@ -349,6 +344,7 @@ sub exportStructs {
 
                print "gen ".($#list+1)." $obj->{type} $obj->{name}\n" if ($api->{vars}->{verbose} > 0);
                foreach my $s (@list) {
+                       next if !$s->{output};
                        next if $api->{output}->{"$s->{type}:$s->{name}"};
 
                        print "  $s->{name}\n" if ($api->{vars}->{verbose} > 1);
index 1484708..d115205 100644 (file)
@@ -106,18 +106,22 @@ public class Memory {
                }
        }
 
-       public static MemoryAddress address(Addressable v) {
+       public static Addressable address(Addressable v) {
                return v != null ? v.address() : MemoryAddress.NULL;
        }
 
-       public static MemoryAddress address(Pointer v) {
+       public static Addressable address(Pointer v) {
                return v != null ? v.address() : MemoryAddress.NULL;
        }
 
-       public static <T> MemoryAddress address(FunctionPointer<T> v) {
+       public static <T> Addressable address(FunctionPointer<T> v) {
                return v != null ? v.symbol().address() : MemoryAddress.NULL;
        }
 
+       //public static long length(Pointer v) {
+       //      return v != null ? v.length() : 0;
+       //}
+
        public static long length(List<?> list) {
                return list != null ? list.size() : 0;
        }
@@ -137,4 +141,44 @@ public class Memory {
        public static long size(MemorySegment s) {
                return s != null ? s.byteSize() : 0;
        }
+
+       public static String[] copyStringArray(MemoryAddress list, long len) {
+               if (list != MemoryAddress.NULL) {
+                       String[] array = new String[(int)len];
+                       for (int i = 0; i < array.length; i++) {
+                               MemoryAddress fu = list.getAtIndex(Memory.POINTER, i);
+                               array[i] = fu != MemoryAddress.NULL ? fu.getUtf8String(0) : null;
+                       }
+                       return array;
+               } else {
+                       return null;
+               }
+       }
+
+       public static MemorySegment copyStringArray(String[] array, SegmentAllocator alloc) {
+               if (array != null) {
+                       MemorySegment list = alloc.allocateArray(Memory.POINTER, array.length);
+                       for (int i = 0; i < array.length; i++) {
+                               list.setAtIndex(Memory.POINTER, i, array[i] != null ? alloc.allocateUtf8String(array[i]) : MemoryAddress.NULL);
+                       }
+                       return list;
+               } else {
+                       return Memory.NULL;
+               }
+       }
+
+       public static String toString(MemorySegment s, GroupLayout layout) {
+               StringBuilder sb = new StringBuilder();
+               sb.append(layout.name().get());
+               sb.append(" ");
+               sb.append(s.address().toString());
+               sb.append("\n");
+               for (MemoryLayout m: layout.memberLayouts()) {
+                       if (m instanceof jdk.incubator.foreign.ValueLayout) {
+                               var vh = layout.varHandle(jdk.incubator.foreign.MemoryLayout.PathElement.groupElement(m.name().get()));
+                               sb.append(" ").append(m.name().get()).append(": ").append(vh.get(s)).append("\n");
+                       }
+               }
+               return sb.toString();
+       }
 }
index cf93675..3fd6fda 100644 (file)
@@ -11,4 +11,7 @@ public interface Pointer {
        default ResourceScope scope() {
                return ResourceScope.globalScope();
        }
+       //default long length() {
+       //      return 1;
+       //}
 }
index c758616..c3c520b 100644 (file)
@@ -1,6 +1,7 @@
 
 # TODO: define more & consistent stage processing hooks, currently implicit require init() and stage.postprocess
 # TODO: code:<inline> etc should probably instead be code:<type> where <type> is one of the template fields - methods, init, etc.
+# TODO: calls should probably use dynamic invocation - downcall is not bound to address
 
 package api;
 
@@ -125,6 +126,13 @@ sub new {
                }
        }
 
+       # create type indices
+       {
+               my $index = {};
+               map { $index->{$_->{type}}->{$_->{name}} = $_ } values %{$self->{data}};
+               $self->{databytype} = $index;
+       }
+
        analyseAPI($self);
        preprocess($self);
 
@@ -167,6 +175,19 @@ sub new {
                push @{$self->{types}}, initType($self, $copyIndex, $obj);
        }
 
+       # handle external references - rename and supress output
+       # Not sure of the best place to put this
+       foreach my $obj (grep { $_->{type} eq 'extern' } @{$self->{api}}) {
+               foreach my $inc (@{$obj->{items}}) {
+                       my @list = findMatches($self, $inc, $obj);
+
+                       foreach my $s (@list) {
+                               $s->{rename} = $obj->{name}.'.'.$inc->{"$s->{type}:rename"}->($s->{name}, $s);
+                               $s->{output} = 0;
+                       }
+               }
+       }
+
        return $self;
 }
 
@@ -307,16 +328,21 @@ sub findTemplate {
 }
 
 # find value of first option of the given name
+# TBD: moved to config.pm
 sub optionValue {
        my $name = shift;
        my $or = shift;
 
+       #my $match = sub { $_ =~ m/^\Q$name\E=(.*)$/on ? $1 : undef };
+
        #print "optionValue $name\n";
        foreach my $obj (@_) {
                foreach my $opt (@{$obj->{options}}) {
                        #print "? $name $opt = ".($opt =~m/^\Q$name\E=(.*)$/)."\n";
                        #print " = $opt\n" if ($opt =~m/^\Q$name\E=(.*)$/);
                        return $1 if ($opt =~m/^\Q$name\E=(.*)$/);
+                       #my $x =  $match->($opt);
+                       #return $x if defined($x);
                }
        }
        $or;
@@ -355,6 +381,7 @@ sub optionValuesAll {
 }
 
 # find first occurance of a flag
+# TBD: moved to config.pm
 sub optionFlag {
        my $name = shift;
 
@@ -467,17 +494,22 @@ sub findMatches {
        my $api = shift;
        my $inc = shift;
        my $ctx = shift;
-       my $data = $api->{data};
+       my $type = $inc->{type};
+       my $data = $api->{databytype}->{$type};
 
        if ($inc->{matcher}) {
-               grep { $inc->{matcher}->($_, $ctx) } grep { $_->{type} eq $inc->{type} } values %$data;
+               #grep { $inc->{matcher}->($_, $ctx) } grep { $_->{type} eq $inc->{type} } values %$data;
+               grep { $inc->{matcher}->($_, $ctx) } values %$data;
        } else {
-               my $s = $data->{$inc->{match}};
+               my $s = $api->{data}->{$inc->{match}};
 
                if (defined($s)) {
                        $s;
                } else {
-                       map { $data->{$_} } grep { $_ =~ m/$inc->{regex}/ } keys %$data;
+                       #map { $data->{$_} } grep { $_ =~ m/$inc->{regex}/ } keys %$data;
+                       #map { $data->{$_} } grep { "$type:$_" =~ m/$inc->{regex}/ } keys %$data;
+                       grep { "$_->{type}:$_->{name}" =~ m/$inc->{regex}/ } values %$data;
+                       #grep { "$_->{type}:$_->{name}" =~ m/$inc->{regex}/ } values %{$api->{data}};
                }
        }
 }
index 6fb67a3..21a3973 100644 (file)
@@ -40,6 +40,33 @@ sub new {
        return $self;
 }
 
+# find first occurance of flag
+# name, ...objects
+sub optionFlag {
+       my $name = shift;
+
+       foreach my $obj (@_) {
+               foreach my $opt (@{$obj->{options}}) {
+                       return 1 if ($opt eq $name);
+               }
+       }
+       undef;
+}
+
+# find value of first option of the given name
+# name, ...objects
+sub optionValue {
+       my $name = shift;
+       my $or = shift;
+
+       foreach my $obj (@_) {
+               foreach my $opt (@{$obj->{options}}) {
+                       return $1 if ($opt =~m/^\Q$name\E=(.*)$/);
+               }
+       }
+       $or;
+}
+
 sub findInclude {
        my $self = shift;
        my $file = shift;
@@ -101,16 +128,18 @@ sub loadControlFile {
                                die("$tokeniser->{file}->{path}:$tokeniser->{file}->{lineno}:$tokeniser->{colno}: expected match token");
                        }
                } elsif ($state == 2) {
-                       # token token token* [ '{' | literal ]
+                       # token token token* [ '{' | literal | ';' ]
                        if ($t eq '{') {
                                $state = 3;
+                       } elsif ($t eq ';') {
+                               $state = 0;
                        } elsif ($tokeniser->{type} eq 'literal') {
                                $target->{literal} = stripLiteral($t);
-                               $state =0;
+                               $state = 0;
                        } elsif ($tokeniser->{type} eq 'token') {
                                push @{$target->{options}}, $t;
                        } else {
-                               die("$tokeniser->{file}->{path}:$tokeniser->{file}->{lineno}:$tokeniser->{colno}: expecting { or {{literal}} or option: not '$t'");
+                               die("$tokeniser->{file}->{path}:$tokeniser->{file}->{lineno}:$tokeniser->{colno}: expecting {, ;, or {{literal}} or option: not '$t'");
                        }
                } elsif ($state == 3) {
                        if ($t eq '}') {
index 489e41b..47d607e 100644 (file)
@@ -1,6 +1,7 @@
 
 module notzed.vkheader.test {
        requires notzed.vkheader;
+       requires notzed.xlib;
 
        requires java.desktop;
 }
diff --git a/src/notzed.vkheader.test/classes/vulkan/test/Cube.java b/src/notzed.vkheader.test/classes/vulkan/test/Cube.java
new file mode 100644 (file)
index 0000000..e8f824e
--- /dev/null
@@ -0,0 +1,55 @@
+
+package vulkan.test;
+
+//struct Vertex {
+//    float posX, posY, posZ, posW;  // Position data
+//    float r, g, b, a;              // Color
+//};
+
+class Cube {
+       static final int dataStride = 8 * 4;
+       static final float[] data = new float[] {
+               // red face
+               -1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               -1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               -1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+               // green face
+               -1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               -1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               -1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+               // blue face
+               -1, 1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               -1, -1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               -1, 1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               -1, 1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               -1, -1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               -1, -1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+               // yellow face
+               1, 1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               1, 1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               1, -1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               1, -1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               1, 1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               1, -1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+               // magenta face
+               1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               -1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               -1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               -1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+               // cyan face
+               1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+               1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+               -1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+               -1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+               1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+               -1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+       };
+}
diff --git a/src/notzed.vkheader.test/classes/vulkan/test/GLMaths.java b/src/notzed.vkheader.test/classes/vulkan/test/GLMaths.java
new file mode 100644 (file)
index 0000000..3414740
--- /dev/null
@@ -0,0 +1,131 @@
+
+package vulkan.test;
+
+import static java.lang.Math.*;
+import java.util.Arrays;
+
+public class GLMaths {
+       public static void identity4f(float []matrix) {
+               Arrays.fill(matrix, 0.0f);
+               for (int i = 0; i < 4; i++)
+                       matrix[i * 4 + i] = 1.0f;
+       }
+
+       public static float length3f(float [] a) {
+               float sum = 0;
+               for (int i = 0; i < 3; i++)
+                       sum += a[i] * a[i];
+               return (float)sqrt(sum);
+       }
+
+       public static void sub3f(float [] c, float [] a, float [] b) {
+               for (int i = 0; i < 3; i++)
+                       c[i] = a[i] - b[i];
+       }
+
+       public static void norm3f(float [] vec) {
+               float fix = 1.0f / length3f(vec);
+               for (int i = 0; i < 3; i++)
+                       vec[i] *= fix;
+       }
+
+       public static void cross3f(float [] c, float [] a, float [] b) {
+               c[0] = a[1] * b[2] - a[2] * b[1];
+               c[1] = a[2] * b[0] - a[0] * b[2];
+               c[2] = a[0] * b[1] - a[1] * b[0];
+       }
+
+       public static float dot3f(float [] a, float [] b) {
+               return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+       }
+
+       public static float [] mult4x4f(float [] c, float [] b, float [] a) {
+               c[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
+               c[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
+               c[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
+               c[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
+
+               c[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
+               c[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
+               c[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
+               c[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
+
+               c[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
+               c[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
+               c[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
+               c[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
+
+               c[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
+               c[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
+               c[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
+               c[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
+
+               return c;
+       }
+
+       public static void lookAt(float []mat, float []eye, float []centre, float []up) {
+               float forward[] = new float[3], side[] = new float[3], u[] = new float[3];
+
+               sub3f(forward, centre, eye);
+               norm3f(forward);
+               cross3f(side, forward, up);
+               norm3f(side);
+               cross3f(u, side, forward);
+
+               mat[0] = side[0];
+               mat[4] = side[1];
+               mat[8] = side[2];
+
+               mat[1] = u[0];
+               mat[5] = u[1];
+               mat[9] = u[2];
+
+               mat[2] = -forward[0];
+               mat[6] = -forward[1];
+               mat[10] = -forward[2];
+
+               mat[12] = -dot3f(side, eye);
+               mat[13] = -dot3f(u, eye);
+               mat[14] = dot3f(forward, eye);
+
+               mat[3] = 0.0f;
+               mat[7] = 0.0f;
+               mat[11] = 0.0f;
+
+               mat[15] = 1.0f;
+       }
+
+       public static void frustum(float []mat, float left, float right, float bottom, float top, float znear, float zfar) {
+               float temp, temp2, temp3, temp4;
+
+               temp = 2.0f * znear;
+               temp2 = right - left;
+               temp3 = top - bottom;
+               temp4 = zfar - znear;
+               mat[0] = temp / temp2;
+               mat[1] = 0.0f;
+               mat[2] = 0.0f;
+               mat[3] = 0.0f;
+               mat[4] = 0.0f;
+               mat[5] = temp / temp3;
+               mat[6] = 0.0f;
+               mat[7] = 0.0f;
+               mat[8] = (right + left) / temp2;
+               mat[9] = (top + bottom) / temp3;
+               mat[10] = (-zfar - znear) / temp4;
+               mat[11] = -1.0f;
+               mat[12] = 0.0f;
+               mat[13] = 0.0f;
+               mat[14] = (-temp * zfar) / temp4;
+               mat[15] = 0.0f;
+       }
+
+       public static void perspective(float []mat, float fovy, float aspect, float znear, float zfar) {
+               float ymax, xmax;
+
+               ymax = znear * (float)tan(fovy * 0.5f);
+               xmax = ymax * aspect;
+
+               frustum(mat, -xmax, xmax, -ymax, ymax, znear, zfar);
+       }
+}
diff --git a/src/notzed.vkheader.test/classes/vulkan/test/TestCube.java b/src/notzed.vkheader.test/classes/vulkan/test/TestCube.java
new file mode 100644 (file)
index 0000000..1433d08
--- /dev/null
@@ -0,0 +1,1145 @@
+ /*
+The MIT License (MIT)
+
+Copyright (C) 2017 Eric Arnebäck
+Copyright (C) 2019 Michael Zucchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ */
+
+/*
+ * This is a Java conversion of a C conversion of this:
+ * https://github.com/Erkaman/vulkan_minimal_compute
+ *
+ * It's been simplified a bit and converted to the 'zvk' api.
+ */
+
+package vulkan.test;
+
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.image.MemoryImageSource;
+import javax.swing.AbstractAction;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.KeyStroke;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Collections;
+
+import java.lang.invoke.*;
+import jdk.incubator.foreign.*;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.VkConstants.*;
+
+import xlib.*;
+import static xlib.XLib.*;
+import static vulkan.test.GLMaths.*;
+
+public class TestCube {
+       static final boolean debug = true;
+
+       final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
+       final static int NUM_DESCRIPTOR_SETS = 1;
+
+       ResourceScope scope = ResourceScope.newSharedScope();
+
+       int width = 800;
+       int height = 800;
+       float projection[] = new float[16];
+       float view[] = new float[16];
+       float model[] = new float[16];
+       float clip[] = new float[] {
+               1.0f, 0.0f, 0.0f, 0.0f,
+               0.0f, -1.0f, 0.0f, 0.0f,
+               0.0f, 0.0f, 0.5f, 0.0f,
+               0.0f, 0.0f, 0.5f, 1.0f
+       };
+       float mvp[] = new float[16];
+
+       VkInstance instance;
+       VkPhysicalDevice physicalDevice;
+       VkPhysicalDeviceMemoryProperties memory_properties;
+       VkPhysicalDeviceFeatures device_features;
+
+       int present_queue_index;
+       int graphics_queue_index;
+
+       VkDevice device;
+       VkSwapchainKHR chain;
+
+       VkQueue graphics_queue;
+       VkQueue present_queue;
+
+       int chainImageFormat;
+       HandleArray<VkImage> chainImage;
+       HandleArray<VkImageView> chainImageView;
+
+       int depthFormat;
+       VkImage depthImage;
+       VkImageView depthView;
+       VkDeviceMemory depthMemory;
+
+       VkCommandPool cmd_pool;
+       HandleArray<VkCommandBuffer> cmd;
+
+       BufferMemory uniform;
+       VkPipelineLayout pipeline_layout;
+
+       VkDescriptorSetLayout desc_layout;
+       VkDescriptorPool desc_pool;
+       HandleArray<VkDescriptorSet> desc_set = VkDescriptorSet.createArray(1, (SegmentAllocator)scope);
+
+
+       VkRenderPass render_pass;
+       HandleArray<VkFramebuffer> framebuffers;
+
+       BufferMemory vertex;
+       HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
+       VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
+       VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(2, (SegmentAllocator)scope);
+
+       IntArray cube_vs;
+       IntArray cube_fs;
+       HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
+
+       HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
+
+       VkSemaphore chainSemaphore;
+       VkFence drawFence;
+
+       record BufferMemory (VkBuffer buffer, VkDeviceMemory memory, long size) {
+               public void free(VkDevice device) {
+                       device.vkFreeMemory(memory, null);
+                       device.vkDestroyBuffer(buffer, null);
+               }
+       }
+
+       VkDebugUtilsMessengerEXT logger;
+
+       void init_debug() throws Exception {
+               if (!debug)
+                       return;
+               try (Frame frame = Frame.frame()) {
+                       var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data, dummy) -> {
+                                       System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+                                       return 0;
+                               }, scope);
+                       VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame,
+                               0,
+                               VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+                               | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+                               | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+                               VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+                               cb,
+                               null);
+
+                       logger = instance.vkCreateDebugUtilsMessengerEXT(info, null, scope);
+               }
+
+               //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
+
+       }
+
+       void init_instance() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame,
+                               0,
+                               VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_MAKE_API_VERSION(0, 1, 0, 0)),
+                               new String[] { "VK_LAYER_KHRONOS_validation" },
+                               new String[] { "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils" }
+                               );
+
+                       instance = VkInstance.vkCreateInstance(info, null, scope);
+                       System.out.printf("instance = %s\n", instance);
+               }
+       }
+
+       XDisplay display;
+       long window;
+       long wm_delete_window;
+       VkSurfaceKHR surface;
+
+       void init_surface() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       XInitThreads();
+                       display = XOpenDisplay(null);
+                       long visualMask = VisualScreenMask;
+                       IntArray numberOfVisuals = IntArray.createArray(1, frame);
+                       XVisualInfo vInfoTemplate = XVisualInfo.create(frame);
+
+                       vInfoTemplate.setScreen(DefaultScreen(display));
+
+                       XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals);
+                       long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone);
+
+                       XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame);
+
+                       windowAttributes.setColormap(colormap);
+                       windowAttributes.setBackgroundPixel(0xffffffff);
+                       windowAttributes.setBorderPixel(0);
+                       windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask);
+
+                       window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()),
+                               0, 0, width, height,
+                               0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(),
+                               CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, windowAttributes);
+
+                       XSelectInput(display, window, ExposureMask | KeyPressMask);
+                       XMapWindow(display, window);
+                       XFlush(display);
+                       wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
+
+                       VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(frame,
+                               0,
+                               display,
+                               window);
+
+                       surface = instance.vkCreateXlibSurfaceKHR(surfaceinfo, null, scope);
+                       System.out.printf("surface: %s\n", surface);
+               }
+       }
+
+       void init_device() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       IntArray count$h = IntArray.create(frame, 1);
+                       IntArray present$h = IntArray.create(frame, 1);
+                       HandleArray<VkPhysicalDevice> devs;
+                       int count;
+                       int res;
+
+                       devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+
+                       // Search for device and queue indices
+                       int devid = -1;
+                       int present_queue = -1;
+                       int graphics_queue = -1;
+                       for (int i = 0; i < devs.length(); i++) {
+                               VkPhysicalDevice dev = devs.getAtIndex(i);
+                               VkQueueFamilyProperties famprops;
+
+                               // TODO: change to return the allocated array directly
+                               dev.vkGetPhysicalDeviceQueueFamilyProperties(count$h, null);
+                               famprops = VkQueueFamilyProperties.createArray(count$h.getAtIndex(0), frame);
+                               dev.vkGetPhysicalDeviceQueueFamilyProperties(count$h, famprops);
+
+                               for (int j = 0; j < famprops.length(); j++) {
+                                       boolean present;
+
+                                       dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
+                                       present = present$h.get(0) != 0;
+
+                                       if (present && present_queue == -1)
+                                               present_queue = j;
+                                       if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
+                                               graphics_queue = j;
+                                               if (present) {
+                                                       present_queue = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if (present_queue != -1 && graphics_queue != -1) {
+                                       devid = i;
+                                       break;
+                               }
+                       }
+
+                       if (devid == -1)
+                               throw new Exception("Cannot find a suitable device");
+
+                       physicalDevice = devs.getAtIndex(devid);
+                       present_queue_index = present_queue;
+                       graphics_queue_index = graphics_queue;
+
+                       // NOTE: app scope
+                       memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+                       physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
+                       device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
+                       physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
+
+                       FloatArray qpri = FloatArray.create(frame, 0.0f);
+                       VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
+                               frame,
+                               0,
+                               graphics_queue,
+                               qpri);
+                       String [] extensions = {
+                               "VK_KHR_swapchain"
+                       };
+                       VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
+                       features.setDepthClamp(1);
+                       VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+                               frame,
+                               0,
+                               qinfo,
+                               null,
+                               extensions,
+                               features);
+
+                       device = physicalDevice.vkCreateDevice(devinfo, null, scope);
+
+                       System.out.printf("device = %s\n", device);
+
+                       /* ************************************************************** */
+                       int format;
+                       int formatCount;
+                       physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, count$h, null);
+                       formatCount = count$h.getAtIndex(0);
+                       VkSurfaceFormatKHR surfFormats = VkSurfaceFormatKHR.createArray(formatCount, frame);
+                       physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, count$h, surfFormats);
+                       // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+                       // the surface has no preferred format.  Otherwise, at least one
+                       // supported format will be returned.
+                       if (formatCount == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
+                               format = VK_FORMAT_B8G8R8A8_UNORM;
+                       } else {
+                               format = surfFormats.getFormatAtIndex(0);
+                       }
+
+                       VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
+
+                       physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
+
+                       physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, count$h, null);
+                       IntArray presentModes = IntArray.createArray(count$h.get(0), frame);
+                       physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, count$h, presentModes);
+
+                       VkExtent2D swapchainExtent;
+                       // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+                       if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
+                               // If the surface size is undefined, the size is set to
+                               // the size of the images requested.
+                               swapchainExtent = VkExtent2D.create(frame,
+                                       clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
+                                       clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()));
+                       } else {
+                               // If the surface size is defined, the swap chain size must match
+                               swapchainExtent = surfCapabilities.getCurrentExtent();
+                       }
+                       int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+                       int compositeAlphaFlags[] = {
+                               VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+                               VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+                               VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+                               VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+                       };
+                       for (int flag: compositeAlphaFlags) {
+                               if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
+                                       compositeAlpha = flag;
+                                       break;
+                               }
+                       }
+
+                       VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(frame,
+                               0,
+                               surface,
+                               surfCapabilities.getMinImageCount(),
+                               format,
+                               VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+                               1, //.imageArrayLayers = 1,
+                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+                               VK_SHARING_MODE_EXCLUSIVE,
+                               // assumes queues are same.
+                               null,
+                               (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
+                               ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
+                               compositeAlpha,
+                               VK_PRESENT_MODE_FIFO_KHR,
+                               VK_TRUE,
+                               null);
+                       chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth());
+                       chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight());
+
+                       chain = device.vkCreateSwapchainKHR(chaininfo, null, scope);
+
+                       int chainImageCount;
+                       device.vkGetSwapchainImagesKHR(chain, count$h, null);
+                       chainImageCount = count$h.get(0);
+                       chainImage = VkImage.createArray(chainImageCount, (SegmentAllocator)scope);
+                       chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
+
+                       device.vkGetSwapchainImagesKHR(chain, count$h, chainImage);
+
+                       VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame,
+                               0,
+                               null,
+                               VK_IMAGE_VIEW_TYPE_2D,
+                               format);
+                       VkComponentMapping components = viewinfo.getComponents();
+                       components.setR(VK_COMPONENT_SWIZZLE_R);
+                       components.setG(VK_COMPONENT_SWIZZLE_G);
+                       components.setB(VK_COMPONENT_SWIZZLE_B);
+                       components.setA(VK_COMPONENT_SWIZZLE_A);
+                       VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
+                       subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
+                       subresourceRange.setLevelCount(1);
+                       subresourceRange.setLayerCount(1);
+
+                       for (int i = 0; i < chainImageCount; i++) {
+                               viewinfo.setImage(chainImage.get(i));
+
+                               chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, null, scope));
+                       }
+
+                       chainImageFormat = format;
+               }
+       }
+
+       void init_device_queue() {
+               graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
+               if (graphics_queue_index == present_queue_index) {
+                       present_queue = graphics_queue;
+               } else {
+                       present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
+               }
+       }
+
+       void init_command() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame,
+                               0,
+                               graphics_queue_index);
+
+                       cmd_pool = device.vkCreateCommandPool(poolinfo, null, scope);
+
+                       VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
+                               cmd_pool,
+                               VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+                               1);
+
+                       cmd = VkCommandBuffer.createArray(instance, 1, (SegmentAllocator)scope, scope);
+                       device.vkAllocateCommandBuffers(cmdinfo, cmd);
+               }
+       }
+
+       // parameterise as init_image?
+       void init_depth() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       int format = VK_FORMAT_D16_UNORM;
+                       VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+                       VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0,
+                               VK_IMAGE_TYPE_2D,
+                               format,
+                               1,
+                               1,
+                               NUM_SAMPLES,
+                               0,
+                               VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+                               VK_SHARING_MODE_EXCLUSIVE,
+                               null,
+                               VK_IMAGE_LAYOUT_UNDEFINED);
+                       imageinfo.getExtent().setWidth(width);
+                       imageinfo.getExtent().setHeight(height);
+                       imageinfo.getExtent().setDepth(1);
+
+                       depthImage = device.vkCreateImage(imageinfo, null, scope);
+
+                       device.vkGetImageMemoryRequirements(depthImage, req);
+                       VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
+                               req.getSize(),
+                               find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
+
+                       depthMemory = device.vkAllocateMemory(alloc, null, scope);
+
+                       device.vkBindImageMemory(depthImage, depthMemory, 0);
+
+                       VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0,
+                               depthImage,
+                               VK_IMAGE_VIEW_TYPE_2D,
+                               VK_FORMAT_D16_UNORM);
+
+                       VkComponentMapping components = viewinfo.getComponents();
+                       components.setR(VK_COMPONENT_SWIZZLE_R);
+                       components.setG(VK_COMPONENT_SWIZZLE_G);
+                       components.setB(VK_COMPONENT_SWIZZLE_B);
+                       components.setA(VK_COMPONENT_SWIZZLE_A);
+                       VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
+                       subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
+                       subresourceRange.setLevelCount(1);
+                       subresourceRange.setLayerCount(1);
+
+                       depthView = device.vkCreateImageView(viewinfo, null, scope);
+
+                       depthFormat = format;
+               }
+       }
+
+       void init_uniform() throws Exception {
+               uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp));
+       }
+
+       void init_descriptor() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+                       VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame,
+                               0,
+                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                               1,
+                               VK_SHADER_STAGE_VERTEX_BIT,
+                               null);
+                       VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame,
+                               0,
+                               layout_binding);
+
+                       desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, null, scope);
+                       layout_table.setAtIndex(0, desc_layout);
+
+                       VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
+                               0,
+                               1,
+                               layout_table,
+                               null);
+
+                       pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, null, scope);
+
+                       VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame,
+                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                               1);
+
+                       VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame,
+                               0,
+                               1,
+                               type_count);
+
+                       desc_pool = device.vkCreateDescriptorPool(descriptor_pool, null, scope);
+
+                       VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
+                               desc_pool,
+                               1,
+                               layout_table);
+
+                       device.vkAllocateDescriptorSets(alloc_info, desc_set);
+
+                       VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size);
+                       VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame,
+                               desc_set.getAtIndex(0),
+                               0,
+                               0,
+                               //1,
+                               VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+                               null,
+                               uniformInfo,
+                               null);
+
+                       device.vkUpdateDescriptorSets(1, writes, 0, null);
+               }
+       }
+
+       void init_render() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
+
+                       attachments.setFormat(chainImageFormat);
+                       attachments.setSamples(NUM_SAMPLES);
+                       attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
+                       attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
+                       attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+                       attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
+                       attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
+                       attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+                       attachments.setFlags(0);
+
+                       attachments.setFormatAtIndex(1, depthFormat);
+                       attachments.setSamplesAtIndex(1, NUM_SAMPLES);
+                       attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+                       attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
+                       attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+                       attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+                       attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
+                       attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+                       attachments.setFlagsAtIndex(1, 0);
+
+                       VkAttachmentReference color_reference = VkAttachmentReference.create(frame,
+                               0,
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+                       VkAttachmentReference depth_reference = VkAttachmentReference.create(frame,
+                               1,
+                               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+                       VkSubpassDescription subpass = VkSubpassDescription.create(frame,
+                               0,
+                               VK_PIPELINE_BIND_POINT_GRAPHICS,
+                               null,
+                               color_reference,
+                               null,
+                               depth_reference,
+                               null);
+
+                       VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame,
+                               0,
+                               //(int)attachments.length(),
+                               attachments,
+                               subpass,
+                               null);
+
+                       render_pass = device.vkCreateRenderPass(rp_info, null, scope);
+               }
+       }
+
+       void init_framebuffer() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
+
+                       attachments.setAtIndex(1, depthView);
+
+                       VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame,
+                               0,
+                               render_pass,
+                               2,
+                               attachments,
+                               width,
+                               height,
+                               1);
+
+                       framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
+                       for (int i = 0; i < chainImage.size(); i++) {
+                               attachments.setAtIndex(0, chainImageView.get(i));
+                               framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, null, scope));
+                               System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
+                       }
+               }
+       }
+
+       void init_vertexbuffer() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       vertex = init_buffer(Cube.data.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(Cube.data));
+
+                       vertexBuffer.setAtIndex(0, vertex.buffer);
+
+                       /* ***************************************** */
+                       vi_binding.setBinding(0);
+                       vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
+                       vi_binding.setStride(Cube.dataStride);
+
+                       vi_attribs.setBinding(0);
+                       vi_attribs.setLocation(0);
+                       vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
+                       vi_attribs.setOffset(0);
+                       vi_attribs.setBindingAtIndex(1, 0);
+                       vi_attribs.setLocationAtIndex(1, 1);
+                       vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
+                       vi_attribs.setOffsetAtIndex(1, 16);
+               }
+       }
+
+       void init_pipeline() throws Exception {
+               int res;
+               try (Frame frame = Frame.frame()) {
+                       IntArray dynamicStateEnables = IntArray.create(frame,
+                               VK_DYNAMIC_STATE_VIEWPORT,
+                               VK_DYNAMIC_STATE_SCISSOR);
+
+                       VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame,
+                               0, dynamicStateEnables);
+
+                       VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame,
+                               0,
+                               vi_binding,
+                               vi_attribs);
+
+                       VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame,
+                               0,
+                               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+                               0);
+
+                       VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame,
+                               0,
+                               VK_TRUE,
+                               VK_FALSE,
+                               VK_POLYGON_MODE_FILL,
+                               VK_CULL_MODE_BACK_BIT,
+                               VK_FRONT_FACE_CLOCKWISE,
+                               VK_FALSE,
+                               0.0f,
+                               0.0f,
+                               0.0f,
+                               1.0f);
+
+                       VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame,
+                               VK_FALSE,
+                               VK_BLEND_FACTOR_ZERO,
+                               VK_BLEND_FACTOR_ZERO,
+                               VK_BLEND_OP_ADD,
+                               VK_BLEND_FACTOR_ZERO,
+                               VK_BLEND_FACTOR_ZERO,
+                               VK_BLEND_OP_ADD,
+                               0xf);
+
+                       VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame,
+                               0,
+                               VK_FALSE,
+                               VK_LOGIC_OP_NO_OP,
+                               att_state,
+                               new float[] { 1.0f, 1.0f, 1.0f, 1.0f });
+
+                       VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
+                               0,
+                               //1, null,
+                               //1, null);
+                               null,
+                               null);
+                       // TODO: should just take counts
+                       vp.setViewportCount(1);
+                       vp.setScissorCount(1);
+
+
+                       VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame,
+                               0,
+                               VK_TRUE,
+                               VK_TRUE,
+                               VK_COMPARE_OP_LESS_OR_EQUAL,
+                               VK_FALSE,
+                               VK_FALSE,
+                               0.0f,
+                               0.0f);
+                       VkStencilOpState back = ds.getBack();
+
+                       back.setFailOp(VK_STENCIL_OP_KEEP);
+                       back.setPassOp(VK_STENCIL_OP_KEEP);
+                       back.setCompareOp(VK_COMPARE_OP_ALWAYS);
+                       back.setCompareMask(0);
+                       back.setReference(0);
+                       back.setDepthFailOp(VK_STENCIL_OP_KEEP);
+                       back.setWriteMask(0);
+
+                       VkStencilOpState front = ds.getFront();
+
+                       front.setFailOp(VK_STENCIL_OP_KEEP);
+                       front.setPassOp(VK_STENCIL_OP_KEEP);
+                       front.setCompareOp(VK_COMPARE_OP_ALWAYS);
+                       front.setCompareMask(0);
+                       front.setReference(0);
+                       front.setDepthFailOp(VK_STENCIL_OP_KEEP);
+                       front.setWriteMask(0);
+
+                       VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame,
+                               0,
+                               NUM_SAMPLES,
+                               0, //.sampleShadingEnable = VK_FALSE,
+                               0.0f,
+                               null,
+                               0, //.alphaToCoverageEnable = VK_FALSE,
+                               0 //.alphaToOneEnable = VK_FALSE,
+                               );
+
+                       VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame,
+                               0,
+                               cube_vs.length() * 4,
+                               cube_vs);
+                       VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame,
+                               0,
+                               cube_fs.length() * 4,
+                               cube_fs);
+
+                       shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, null, scope));
+                       shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, null, scope));
+
+                       VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
+
+                       shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+                       shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
+                       shaderStages.setName("main");
+                       shaderStages.setModule(shader.get(0));
+
+                       shaderStages.setSTypeAtIndex(1, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+                       shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
+                       shaderStages.setNameAtIndex(1, "main");
+                       shaderStages.setModuleAtIndex(1, shader.get(1));
+
+                       VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame,
+                               0,
+                               //2, shaderStages,
+                               shaderStages,
+                               vi,
+                               ia,
+                               null,
+                               vp,
+                               rs,
+                               ms,
+                               ds,
+                               cb,
+                               dynamicState,
+                               pipeline_layout,
+                               render_pass,
+                               0,
+                               null,
+                               0);
+
+                       res = device.vkCreateGraphicsPipelines(null, 1, pipeline, null, this.pipeline);
+
+                       VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
+                       chainSemaphore = device.vkCreateSemaphore(seminfo, null, scope);
+
+                       VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
+                       drawFence = device.vkCreateFence(fenceInfo, null, scope);
+               }
+       }
+
+
+       void execute_begin_command_buffer() throws Exception {
+               /* DEPENDS on init_command() */
+               try (Frame frame = Frame.frame()) {
+                       VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame,
+                               0,
+                               null);
+
+                       cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
+               }
+       }
+
+       void execute_end_command_buffer() throws Exception {
+               cmd.getAtIndex(0).vkEndCommandBuffer();
+       }
+
+       final static long FENCE_TIMEOUT = 100000000;
+
+       void execute_queue_command_buffer() throws Exception {
+               int res;
+
+               /* Queue the command buffer for execution */
+               try (Frame frame = Frame.frame()) {
+                       IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+                       VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
+                       HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+                       fences.setAtIndex(0, device.vkCreateFence(fenceInfo, null, scope));
+
+                       // FIXME: why is this not autogenerating the length bits for all fields?
+                       VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
+                               null, pipe_stage_flags,
+                               1, cmd,
+                               0, null);
+
+                       graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+                       do {
+                               res = device.vkWaitForFences( 1, fences, 1, FENCE_TIMEOUT);
+                       } while (res == VK_TIMEOUT);
+
+                       device.vkDestroyFence(fences.getAtIndex(0), null);
+               }
+       }
+
+       void cmd_viewport() {
+               try (Frame frame = Frame.frame()) {
+                       VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+                       VkViewport viewport = VkViewport.create(frame,
+                               0, 0, width, height, 0.0f, 1.0f);
+                       cmd.vkCmdSetViewport(0, 1, viewport);
+               }
+       }
+
+       void cmd_scissors() {
+               try (Frame frame = Frame.frame()) {
+                       VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+                       VkRect2D scissor = VkRect2D.create(frame);
+                       VkExtent2D extent = scissor.getExtent();
+
+                       extent.setWidth(width);
+                       extent.setHeight(height);
+
+                       cmd.vkCmdSetScissor(0, 1, scissor);
+               }
+       }
+
+       void cmd_paint() throws Exception {
+               int res;
+               try (Frame frame = Frame.frame()) {
+                       int chainIndex;
+                       IntArray chainIndices = IntArray.createArray(1, frame);
+                       VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+
+                       device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
+                       chainIndex = chainIndices.getAtIndex(0);
+                       LongArray offsets = LongArray.createArray(1, frame);
+
+                       VkClearValue clear_values = VkClearValue.createArray(2, frame);
+                       FloatArray col = clear_values.getColor().getFloat32();
+                       col.setAtIndex(0, 0.2f);
+                       col.setAtIndex(1, 0.2f);
+                       col.setAtIndex(2, 0.2f);
+                       col.setAtIndex(3, 0.2f);
+                       VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
+                       depthStencil.setDepth(1.0f);
+                       depthStencil.setStencil(0);
+
+                       System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
+
+                       VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame,
+                               render_pass,
+                               framebuffers.getAtIndex(chainIndex),
+                               clear_values);
+                       VkExtent2D extent = rp_begin.getRenderArea().getExtent();
+                       extent.setWidth(width);
+                       extent.setHeight(height);
+
+                       cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+                       cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
+                       cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
+                       cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
+
+                       cmd_viewport();
+                       cmd_scissors();
+
+                       cmd.vkCmdDraw(12 * 3, 1, 0, 0);
+                       cmd.vkCmdEndRenderPass();
+
+                       cmd.vkEndCommandBuffer();
+
+                       IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+                       HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
+
+                       semaphores.setAtIndex(0, chainSemaphore);
+
+                       VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
+                               semaphores,     pipe_stage_flags,
+                               1, this.cmd,
+                               0, null);
+
+                       HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+                       fences.setAtIndex(0, drawFence);
+
+                       // Queue the command buffer for execution
+                       device.vkResetFences(1, fences);
+
+                       graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+                       // Make sure command buffer is finished before presenting
+                       do {
+                               res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
+                       } while (res == VK_TIMEOUT);
+
+                       // Now present the image in the window
+                       HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
+                       chains.setAtIndex(0, chain);
+                       VkPresentInfoKHR present = VkPresentInfoKHR.create(frame,
+                               0, null,
+                               chains,
+                               chainIndices,
+                               null);
+                       // HACK: auto-set length is busted
+                       present.setSwapchainCount(chains.size());
+
+                       present_queue.vkQueuePresentKHR(present);
+               }
+       }
+
+       /**
+        * Buffers are created in three steps:
+        * 1) create buffer, specifying usage and size
+        * 2) allocate memory based on memory requirements
+        * 3) bind memory
+        *
+        */
+       BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+                       VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame,
+                               0,
+                               dataSize,
+                               usage,
+                               VK_SHARING_MODE_EXCLUSIVE,
+                               //0,
+                               null);
+
+                       VkBuffer buffer = device.vkCreateBuffer(buf_info, null, scope);
+
+                       device.vkGetBufferMemoryRequirements(buffer, req);
+
+                       VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
+                               req.getSize(),
+                               find_memory_type(memory_properties, req.getMemoryTypeBits(), properties));
+
+                       VkDeviceMemory memory = device.vkAllocateMemory(alloc, null, scope);
+
+                       if (init != null) {
+                               MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
+                               mem.copyFrom(init);
+                               device.vkUnmapMemory(memory);
+                       }
+
+                       device.vkBindBufferMemory(buffer, memory, 0);
+
+                       return new BufferMemory(buffer, memory, dataSize);
+               }
+       }
+
+       void shutdown() {
+               device.vkDestroyFence(drawFence, null);
+               device.vkDestroySemaphore(chainSemaphore, null);
+
+               device.vkDestroyPipeline(pipeline.getAtIndex(0), null);
+               for (int i=0;i<shader.size();i++)
+                       device.vkDestroyShaderModule(shader.getAtIndex(i), null);
+
+               vertex.free(device);
+               uniform.free(device);
+
+               for (int i=0;i<framebuffers.size();i++)
+                       device.vkDestroyFramebuffer(framebuffers.getAtIndex(i), null);
+
+               device.vkDestroyRenderPass(render_pass, null);
+
+               device.vkDestroyDescriptorPool(desc_pool, null);
+               device.vkDestroyPipelineLayout(pipeline_layout, null);
+               device.vkDestroyDescriptorSetLayout(desc_layout, null);
+
+               device.vkDestroyImageView(depthView, null);
+               device.vkFreeMemory(depthMemory, null);
+               device.vkDestroyImage(depthImage, null);
+
+               for (int i = 0; i < chainImageView.size(); i++)
+                       device.vkDestroyImageView(chainImageView.getAtIndex(i), null);
+
+               device.vkDestroySwapchainKHR(chain, null);
+
+               device.vkDestroyCommandPool(cmd_pool, null);
+               device.vkDestroyDevice(null);
+
+               instance.vkDestroySurfaceKHR(surface, null);
+
+               if (logger != null)
+                       instance.vkDestroyDebugUtilsMessengerEXT(logger, null);
+               instance.vkDestroyInstance(null);
+       }
+
+       IntArray loadSPIRV0(String name) throws IOException {
+               // hmm any way to just load this directly?
+               try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+                       ByteBuffer bb = ByteBuffer.allocateDirect(8192).order(ByteOrder.nativeOrder());
+                       int length = Channels.newChannel(is).read(bb);
+
+                       bb.position(0);
+                       bb.limit(length);
+
+                       return IntArray.create(MemorySegment.ofByteBuffer(bb));
+               }
+       }
+
+       IntArray loadSPIRV(String name) throws IOException {
+               try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+                       MemorySegment seg = ((SegmentAllocator)scope).allocateArray(Memory.INT, 2048);
+                       int length = Channels.newChannel(is).read(seg.asByteBuffer());
+
+                       return IntArray.create(seg.asSlice(0, length));
+               }
+       }
+       IntArray loadSPIRV(String name, SegmentAllocator alloc) throws IOException {
+               try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+                       MemorySegment seg = alloc.allocateArray(Memory.INT, 2048);
+                       int length = Channels.newChannel(is).read(seg.asByteBuffer());
+
+                       return IntArray.create(seg.asSlice(0, length));
+               }
+       }
+
+       /**
+        * This finds the memory type index for the memory on a specific device.
+        */
+       static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
+               VkMemoryType mtypes = memory.getMemoryTypes();
+
+               for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
+                       if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
+                               return i;
+               }
+               return -1;
+       }
+
+       public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) {
+               return (variant << 29) | (major << 22) | (minor << 12) | patch;
+       }
+
+       static int clampi(int v, int min, int max) {
+               return v < min ? min : v < max ? v : max;
+       }
+
+       void init_matrices() {
+               float eye[] = new float[] {-5, 3, -10};
+               float centre[] = new float[] {0, 0, 0};
+               float up[] = new float[] {0, -1, 0};
+               float t0[] = new float[16], t1[] = new float[16];
+
+               perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
+               lookAt(view, eye, centre, up);
+               identity4f(model);
+               mult4x4f(t0, clip, projection);
+               mult4x4f(t1, t0, view);
+               mult4x4f(mvp, t1, model);
+       }
+
+       void demo() throws Exception {
+               cube_vs = loadSPIRV("cube_vs.bin");
+               cube_fs = loadSPIRV("cube_fs.bin");
+
+               init_matrices();
+
+               init_instance();
+               init_debug();
+
+               init_surface();
+               init_device();
+               init_device_queue();
+               init_command();
+               init_depth();
+               init_uniform();
+
+               init_descriptor();
+               init_render();
+               init_framebuffer();
+               init_vertexbuffer();
+               init_pipeline();
+
+               execute_begin_command_buffer();
+
+               cmd_paint();
+
+               System.out.println("behold the prize!");
+               Thread.sleep(2000);
+
+               shutdown();
+       }
+
+       public static void main(String[] args) throws Throwable {
+               System.loadLibrary("vulkan");
+               System.loadLibrary("X11");
+
+               new TestCube().demo();
+       }
+}
index ed4a816..78a95d9 100644 (file)
@@ -1,6 +1,7 @@
 
 module notzed.vkheader {
        requires transitive notzed.nativez;
+       requires notzed.xlib;
 
        exports vulkan;
 }
index 27b5f11..57d12dc 100644 (file)
@@ -102,6 +102,11 @@ type /^u64:u64:\$\{(\w+)\}$/ select=vkinstance copy=<pointer> {
 
 %stage.postprocess vkheader::postprocess;
 
+# extern package ... types
+extern xlib {
+       struct:_XDisplay rename=XDisplay;
+}
+
 # field rename function
 #   field:remname=func:[function]
 #     [function] is a defined function that will take:
@@ -128,7 +133,8 @@ struct VkInstance_T {
                }
        }
   }}
-       func:<invoke=vkheader::matchCreateFunction>;
+#      func:<invoke=vkheader::matchCreateFunction>;
+       func:vkCreateInstance;
        func:<invoke=vkheader::matchObjectFunction>;
 
   # a few helpers
@@ -146,7 +152,7 @@ struct VkInstance_T {
 }
 
 struct VkDevice_T {
-       func:<invoke=vkheader::matchCreateFunction>;
+#      func:<invoke=vkheader::matchCreateFunction>;
        func:<invoke=vkheader::matchObjectFunction>;
 
   code:<inline> {{
@@ -165,7 +171,7 @@ struct VkDevice_T {
 }
 
 struct VkPhysicalDevice_T {
-       func:<invoke=vkheader::matchCreateFunction>;
+#      func:<invoke=vkheader::matchCreateFunction>;
        func:<invoke=vkheader::matchObjectFunction>;
 
   code:<inline> {{
@@ -182,7 +188,7 @@ struct VkPhysicalDevice_T {
 }
 
 struct /Vk/ {
-       func:<invoke=vkheader::matchCreateFunction>;
+#      func:<invoke=vkheader::matchCreateFunction>;
        func:<invoke=vkheader::matchObjectFunction>;
 }
 
@@ -204,8 +210,9 @@ func vkCreateInstance {
 }
 
 library VkConstants {
-       enum://;
+       define:api-constants;           # this is generated by vkheader.pm.init
        define:extensions;
+       enum://;
 }
 
 enum // {
index 3c9b0dd..396aaa2 100644 (file)
@@ -1,2 +1,4 @@
 
+#define VK_USE_PLATFORM_XLIB_KHR
+
 #include <vulkan/vulkan.h>
index bee1f34..6febd49 100644 (file)
@@ -1,6 +1,6 @@
 #
-# TODO: constructors initialise sType
-#
+# TODO: array constructors initialise sType for each item
+# FIXME: if the same len is defined for multiple targes then don't bother hiding it/setting it implicitly#
 
 package vkheader;
 
@@ -48,6 +48,7 @@ sub init {
 
                $r->{vkheader} = $s;
                $api->{data}->{"struct:$r->{name}_T"} = $s;
+               #$api->{databytype}->{'struct'}->{"$r->{name}_T"} = $s;
        }
 
        # link api to registry
@@ -67,6 +68,48 @@ sub init {
        }
 
        map { delete $api->{data}->{$_} } @delete;
+       #map { m/^(.*):(.*)$/; delete $api->{databytype}->{$1}->{$2} } @delete;
+
+       # create psuedo-define of api constants
+       my %typeMap = (
+               uint32_t => 'u32',
+               uint64_t => 'u64',
+               float => 'f32'
+       );
+       my $d = $registry->{data}->{'define:API Constants'};
+       my $apiConstants = {
+               name => 'api-constants',
+               type => 'define',
+               items => []
+       };
+       foreach my $m (@{$d->{items}}) {
+               my $v = $m->{value};
+
+               $v =~ s/LL//;
+               $v =~ s/U|F|\(|\)//g;
+
+               die "Unknown constant type: $m->{type}", if !defined $typeMap{$m->{type}};
+
+               push @{$apiConstants->{items}}, {
+                       name => $m->{name},
+                       value => $v,
+                       type => $typeMap{$m->{type}}
+               };
+       }
+       $api->{data}->{'define:api-constants'} = $apiConstants;
+       #$api->{databytype}->{'define'}->{'api-constants'} = $apiConstants;
+
+       # mark all functions for matchObjectFunction
+       foreach my $c (grep { $_->{type} eq 'func' } values %{$api->{data}}) {
+               my $items = $c->{items};
+
+               if ($items->[0]->{deref} =~ m/^u64:\$\{(.*)\}$/) {
+                       my $type = $registry->{index}->{"type:$1"};
+                       if (defined ($type) && $type->{type} eq 'VK_DEFINE_HANDLE') {
+                               $c->{vkobject} = $1;
+                       }
+               }
+       }
 
        1;
 }
@@ -161,6 +204,8 @@ sub analyseInOut {
 
                $rw = $rw."i" if $arrays->{$r->{name}};
 
+               print "edit: array-struct $s->{name}\n" if $arrays->{$r->{name}};
+
                $s->{vkaccess}= $rw;
                $s->{access} = $rw;
                $s->{"$s->{type}:template"} = 'code:class=struct-array' if $arrays->{$r->{name}};
@@ -219,6 +264,7 @@ sub analyseFunctions {
                        $d->{'init:template'} = $d->{items}->[0]->{deref} eq 'u64:${VkInstance_T}'
                                ? 'code:vulkan=invoke-dynamic-init-instance' : 'code:vulkan=invoke-dynamic-init';
                        $d->{'func:template'} = 'code:vulkan=invoke-dynamic';
+                       print "edit: extension: $c->{name}\n";
                }
 
                # look for constructors and member functions
@@ -249,7 +295,7 @@ sub analyseFunctions {
                        $d->{scope} = $last->{scope} = 'explicit'; # blah, for now
                        $last->{select}->{vkinstance} = 1 if ($flast->{baseType} ne 'VkInstance');
 
-                       print "xxxa static $flast->{baseType}.$c->{name} $last->{deref}  $rlast->{type} ".join("",split(/\n/,Dumper($flast)))."\n";
+                       print "edit: static create: $c->{name}\n";
                } elsif ($ffirst->{fullType} eq $ffirst->{baseType}
                                 && $rfirst->{type} eq 'VK_DEFINE_HANDLE') {
                        # member functions
@@ -257,6 +303,8 @@ sub analyseFunctions {
                        $first->{instance} = 1;
                        $d->{static} = 0;
 
+                       print "edit: member function: $c->{name}\n";
+
                        # member create function
                        if ($iscreate) {
                                $last->{output} = 0;
@@ -265,7 +313,7 @@ sub analyseFunctions {
                                $d->{scope} = $last->{scope} = 'explicit';
                                $last->{select}->{vkinstance} = 1 if ($flast->{baseType} ne 'VkInstance' && $rlast->{type} eq 'VK_DEFINE_HANDLE');
 
-                               print "xxxb $ffirst->{baseType}.$c->{name} $last->{deref}  $rlast->{type} ".join("",split(/\n/,Dumper($flast)))."\n";
+                               print "edit: member create: $c->{name}\n";
                        }
                }
 
@@ -273,6 +321,7 @@ sub analyseFunctions {
                        #&& $rlast->{type} eq 'VK_DEFINE_HANDLE')
                        ) {
                        $last->{array} = 1;
+                       print "edit: array $c->{name} ($flast->{name})\n";
                }
 
                # Link in successcodes (failure codes?)
@@ -281,6 +330,8 @@ sub analyseFunctions {
                        $d->{success}->{success} = join ',', map { "VkConstants.$_" } split /,/,$c->{successcodes};
                        $d->{result}->{output} = 0;
 
+                       print "edit: successcodes: $c->{name}: $c->{successcodes}\n";
+
                        # output return value if there is more than 1 success code
                        if ($c->{successcodes} =~ tr/,/,/ >= 1 && !defined($d->{return})) {
                                $d->{result}->{output} = 1;
@@ -435,15 +486,18 @@ sub matchStruct {
 sub matchObjectFunction {
        my $c = shift;
        my $s = shift;
-       my $items = $c->{items};
-       my $r = $s->{vkregistry};
 
-       die "vkregistry field missing ".Dumper($s) if !defined($r);
+       return $c->{vkobject} eq $s->{name};
 
-       return $r->{type} eq 'VK_DEFINE_HANDLE'
-               #&& !$registry->{alias}->{"type:$s->{name}"}
-               && defined($items->[0])
-               && $items->[0]->{deref} eq "u64:\${$s->{name}}";
+#      my $items = $c->{items};
+#      my $r = $s->{vkregistry};
+
+#      die "vkregistry field missing ".Dumper($s) if !defined($r);
+
+#      return $r->{type} eq 'VK_DEFINE_HANDLE'
+#              #&& !$registry->{alias}->{"type:$s->{name}"}
+#              && defined($items->[0])
+#              && $items->[0]->{deref} eq "u64:\${$s->{name}}";
 }
 
 # a static create function
@@ -453,6 +507,12 @@ sub matchCreateFunction {
        my $items = $c->{items};
        my $r = $s->{vkregistry};
 
+       if (($c->{vkiscreate})
+               && ($c->{vkisstatic})
+               && ($items->[$#$items]->{deref} eq "u64:u64:\${$s->{name}}")) {
+               print "match-create: $c->{name}\n";
+       }
+
        return ($c->{vkiscreate})
                && ($c->{vkisstatic})
                && ($items->[$#$items]->{deref} eq "u64:u64:\${$s->{name}}");
index cc5ec98..fbe0f4a 100644 (file)
@@ -82,8 +82,8 @@ sub new {
                                                my $info = loadMember($yn);
                                                my $s = $ya;
 
-                                               $s->{name} = $info->{name},
-                                                       $s->{type} => $info->{baseType} if defined $info->{baseType};
+                                               $s->{name} = $info->{name};
+                                               $s->{type} => $info->{baseType} if defined $info->{baseType};
 
                                                $data->{"type:$s->{name}"} = $s;
                                        } else {
@@ -101,6 +101,22 @@ sub new {
                        if ($xa->{type} =~ m/enum|bitmask/o) {
                                $data->{"type:$xa->{name}"} = { category => $xa->{type}, name => $xa->{name} };
                        } elsif ($xa->{name} eq 'API Constants') {
+                               my $d = { category => "define", name => $xa->{name}, items =>[] };
+
+                               $data->{"define:$xa->{name}"} = $d;
+
+                               while ($#{$xn} >= 0) {
+                                       my $yt = shift @{$xn};
+                                       my $yn = shift @{$xn};
+
+                                       next if $yt ne 'enum';
+
+                                       my $ya = shift @{$yn};
+
+                                       next if $ya->{alias};
+
+                                       push @{$d->{items}}, $ya;
+                               }
                        }
                } elsif ($xt eq 'commands') {
                        while ($#{$xn} >= 0) {