Added graphics vulkan demo.
authorNot Zed <notzed@gmail.com>
Thu, 28 Apr 2022 02:38:42 +0000 (12:08 +0930)
committerNot Zed <notzed@gmail.com>
Thu, 28 Apr 2022 02:38:42 +0000 (12:08 +0930)
Added indexed accessors for embedded arrays.
Added initialisers for embedded arrays.
Tweaked some of the implied call lengths.

Makefile
src/notzed.vulkan.test/classes/vulkan/test/Cube.java [new file with mode: 0644]
src/notzed.vulkan.test/classes/vulkan/test/GLMaths.java [new file with mode: 0644]
src/notzed.vulkan.test/classes/vulkan/test/TestCube.java [new file with mode: 0644]
src/notzed.vulkan.test/classes/vulkan/test/TestMandelbrot.java
src/notzed.vulkan/gen/command-types.api
src/notzed.vulkan/gen/generate-vulkan
src/notzed.vulkan/gen/struct-types.api
src/notzed.vulkan/gen/vulkan.pm

index 824bbbd..c22d81c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ notzed.ffmpeg_JMAIN = ffmpeg.test.TestFFMPEG
 notzed.clstatic_JMAIN = opencl.test.clinfo
 notzed.vkregistry.test_JMAIN = vulkan.test.TestMandelbrot vulkan.test.TestCube
 notzed.vkheader.test_JMAIN = vulkan.test.TestMandelbrot vulkan.test.TestCube
-notzed.vulkan.test_JMAIN = vulkan.test.TestMandelbrot
+notzed.vulkan.test_JMAIN = vulkan.test.TestMandelbrot vulkan.test.TestCube
 
 $(foreach module,$(java_MODULES),$(eval $(module)_JMAINFLAGS=--enable-native-access=notzed.nativez,$(module)))
 
diff --git a/src/notzed.vulkan.test/classes/vulkan/test/Cube.java b/src/notzed.vulkan.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.vulkan.test/classes/vulkan/test/GLMaths.java b/src/notzed.vulkan.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.vulkan.test/classes/vulkan/test/TestCube.java b/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java
new file mode 100644 (file)
index 0000000..5fce884
--- /dev/null
@@ -0,0 +1,1131 @@
+ /*
+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;
+
+
+       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);
+                       device.vkDestroyBuffer(buffer);
+               }
+       }
+
+       VkDebugUtilsMessengerEXT logger;
+
+       void init_debug() throws Exception {
+               if (!debug)
+                       return;
+               try (Frame frame = Frame.frame()) {
+                       var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
+                                       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, 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, 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, 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;
+
+                               famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
+
+                               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, scope);
+
+                       System.out.printf("device = %s\n", device);
+
+                       /* ************************************************************** */
+                       int format;
+                       VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
+                       // 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 (surfFormats.length() == 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);
+                       IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
+
+                       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, scope);
+
+                       int chainImageCount;
+
+                       chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
+                       chainImageCount = (int)chainImage.length();
+                       chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
+
+                       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, 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, scope);
+
+                       VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
+                               cmd_pool,
+                               VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+                               1);
+
+                       cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
+               }
+       }
+
+       // 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, 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, 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, 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, scope);
+                       layout_table.setAtIndex(0, desc_layout);
+
+                       VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
+                               0,
+                               //1,
+                               layout_table,
+                               null);
+
+                       pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, 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, scope);
+
+                       VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
+                               desc_pool,
+                               //1,
+                               layout_table);
+
+                       System.out.println(alloc_info);
+
+                       desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
+
+                       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(writes, 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,
+                               1,
+                               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, scope);
+               }
+       }
+
+       void init_framebuffer() throws Exception {
+               try (Frame frame = Frame.frame()) {
+                       HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
+
+                       attachments.setAtIndex(1, depthView);
+
+                       // FIXME: I don't think i want lenghts implied for types tbh
+                       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, 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,
+                               1.0f, 1.0f, 1.0f, 1.0f);
+
+                       VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
+                               0,
+                               1, null,
+                               1, null);
+
+                       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, scope));
+                       shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
+
+                       VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
+
+                       // FIXME: createArray should initialise this
+                       shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+                       shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
+                       shaderStages.setName("main", (SegmentAllocator)scope);
+                       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", (SegmentAllocator)scope);
+                       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, pipeline, this.pipeline);
+
+                       VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
+                       chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
+
+                       VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
+                       drawFence = device.vkCreateFence(fenceInfo, 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 */
+               /* FIXME: frame shoudl provide or take explicit scope */
+               try (ResourceScope scope = ResourceScope.newConfinedScope();
+                       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, scope));
+
+                       VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
+                               1, null, pipe_stage_flags,
+                               cmd,
+                               null);
+
+                       graphics_queue.vkQueueSubmit(submit_info, drawFence);
+
+                       do {
+                               res = device.vkWaitForFences(fences, 1, FENCE_TIMEOUT);
+                       } while (res == VK_TIMEOUT);
+
+                       device.vkDestroyFence(fences.getAtIndex(0));
+               }
+       }
+
+       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,
+                               1, semaphores, pipe_stage_flags,
+                               this.cmd,
+                               null);
+
+                       HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+                       fences.setAtIndex(0, drawFence);
+
+                       // Queue the command buffer for execution
+                       device.vkResetFences(fences);
+
+                       graphics_queue.vkQueueSubmit(submit_info, drawFence);
+
+                       // Make sure command buffer is finished before presenting
+                       do {
+                               res = device.vkWaitForFences(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,
+                               null,
+                               1,
+                               chains,
+                               chainIndices,
+                               null);
+
+                       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, 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, 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);
+               device.vkDestroySemaphore(chainSemaphore);
+
+               device.vkDestroyPipeline(pipeline.getAtIndex(0));
+               for (int i=0;i<shader.size();i++)
+                       device.vkDestroyShaderModule(shader.getAtIndex(i));
+
+               vertex.free(device);
+               uniform.free(device);
+
+               for (int i=0;i<framebuffers.size();i++)
+                       device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
+
+               device.vkDestroyRenderPass(render_pass);
+
+               device.vkDestroyDescriptorPool(desc_pool);
+               device.vkDestroyPipelineLayout(pipeline_layout);
+               device.vkDestroyDescriptorSetLayout(desc_layout);
+
+               device.vkDestroyImageView(depthView);
+               device.vkFreeMemory(depthMemory);
+               device.vkDestroyImage(depthImage);
+
+               for (int i = 0; i < chainImageView.size(); i++)
+                       device.vkDestroyImageView(chainImageView.getAtIndex(i));
+
+               device.vkDestroySwapchainKHR(chain);
+
+               device.vkDestroyCommandPool(cmd_pool);
+               device.vkDestroyDevice();
+
+               instance.vkDestroySurfaceKHR(surface);
+
+               if (logger != null)
+                       instance.vkDestroyDebugUtilsMessengerEXT(logger);
+               instance.vkDestroyInstance();
+       }
+
+       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 0de2890..5f5f5c0 100755 (executable)
@@ -377,7 +377,7 @@ public class TestMandelbrot {
 
                        /* Bind the compute operation and data */
                        commandBuffers.get(0).vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get(0));
-                       commandBuffers.get(0).vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, descriptorSets, null);
+                       commandBuffers.get(0).vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, descriptorSets, 0, null);
 
                        /* Run it */
                        commandBuffers.get(0).vkCmdDispatch(WIDTH, HEIGHT, 1);
index 309d6c5..c651800 100644 (file)
@@ -14,11 +14,11 @@ code method {
        * errors: {errorcodes}
        */
        public {static}{java-result} {rename}(
-               {java-arguments}) {
+               {java-arg}) {
                {native-result-define}
                try {create-frame}{
                        {native-init}
-                       {native-result-assign}{name}$FH.invokeExact({invoke-arguments});
+                       {native-result-assign}{name}$FH.invokeExact({invoke-arg});
                        {result-test}{
                                {java-result-assign}
                                {java-result-return}
@@ -41,14 +41,14 @@ code method-query {
        * errors: {errorcodes}
        */
        public {static}{java-result} {rename}(
-               {java-arguments}) {
+               {java-arg}) {
                {native-result-define}
                try {create-frame}{
                        {native-init}
-                       {native-result-assign}{name}$FH.invokeExact({query-arguments});
+                       {native-result-assign}{name}$FH.invokeExact({query-arg});
                        {result-test}{
                                {query-init}
-                               {native-result-assign}{name}$FH.invokeExact({invoke-arguments});
+                               {native-result-assign}{name}$FH.invokeExact({invoke-arg});
                                {java-result-assign}
                                {java-result-return}
                        }
@@ -73,11 +73,11 @@ code method-extension {
        * errors: {errorcodes}
        */
        public {static}{java-result} {rename}(
-               {java-arguments}) {
+               {java-arg}) {
                {native-result-define}
                try {create-frame}{
                        {native-init}
-                       {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arguments});
+                       {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arg});
                        {result-test}{
                                {java-result-assign}
                                {java-result-return}
@@ -103,14 +103,14 @@ code method-extension-query {
        * errors: {errorcodes}
        */
        public {static}{java-result} {rename}(
-               {java-arguments}) {
+               {java-arg}) {
                {native-result-define}
                try {create-frame}{
                        {native-init}
-                       {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {query-arguments});
+                       {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {query-arg});
                        {result-test}{
                                {query-init}
-                               {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arguments});
+                               {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arg});
                                {java-result-assign}
                                {java-result-return}
                        }
@@ -127,7 +127,7 @@ code method-extension-query {
 # common parts for funcpointer
 code funcpointer {
   common {{
-       public {java-result} call({java-arguments});
+       public {java-result} call({java-arg});
 
        public final static FunctionDescriptor DESCRIPTOR =
                {function-descriptor};
@@ -135,13 +135,13 @@ code funcpointer {
   upcall {{
        public static FunctionPointer<{rename}> upcall({rename} target$, ResourceScope scope$) {
                interface Trampoline {
-                       {native-result} call({native-arguments});
+                       {native-result} call({native-arg});
                }
-               Trampoline trampoline = ({native-arguments}) -> {
+               Trampoline trampoline = ({native-arg}) -> {
                        // frame?  scope?
                        try {trampoline-scope} {
                                {trampoline-result-define}
-                               {trampoline-result-assign}target$.call({trampoline-arguments});
+                               {trampoline-result-assign}target$.call({trampoline-arg});
                                {trampoline-result-return}
                        } catch (Throwable t) {
                                throw new RuntimeException(t);
@@ -446,10 +446,10 @@ type handle*-length pointer-length {
        typei           {{ {baseType} }}
 }
 
-type struct inline {
-       type    {{ {baseType} }}
-       layout  {{ {baseType}.LAYOUT }}
-}
+#type struct inline {
+#      type    {{ {baseType} }}
+#      layout  {{ {baseType}.LAYOUT }}
+#}
 
 type struct* pointer trampoline-scope {
        type            {{ {baseType} }}
@@ -579,7 +579,7 @@ type void*-length-query void*-length need-alloc {
 
 type uint32_t*-length-query uint32_t*-length need-alloc {
        java-arg        {{ }}
-       invoke-arg      {{ {name} }}
+       invoke-arg      {{ (Addressable){name}.address() }}
        query-arg       {{ (Addressable)MemoryAddress.NULL }}
 
        java-result                     {{ {type} }}
@@ -614,6 +614,7 @@ type handle*-alloc handle* {
        java-result-return      {{ return {name}; }}
 }
 
+# A couple of very special cases
 type VkCommandBuffer-alloc handle*-alloc need-scope need-alloc {
        native-init     {{
                {type} {name} = {typei}.createArray(
@@ -627,7 +628,7 @@ type VkCommandBuffer-alloc handle*-alloc need-scope need-alloc {
 type VkDescriptorSet-alloc handle*-alloc need-alloc {
        native-init     {{
                {type} {name} = {typei}.createArray(
-                       (int)VkCommandBufferAllocateInfo.commandBufferCount$VH.get(pAllocateInfo.segment),
+                       (int)VkDescriptorSetAllocateInfo.descriptorSetCount$VH.get(pAllocateInfo.segment),
                        alloc$);
        }}
 }
@@ -661,6 +662,11 @@ override commands {
 
        vkMapMemory device=type:instance ppData=type:vkMapMemory-output;
 
+       # forces ignoring of lengths, maybe need to do it for all vkCmd
+       #vkCmdSetScissor commandBuffer=type:instance;
+       #vkCmdSetViewport commandBuffer=type:instance;
+       #vkCmdBindDescriptorSets commandBuffer=type:instance;
+
        # Don't need userData
        PFN_vkDebugUtilsMessengerCallbackEXT pUserData=type:void*-ignore;
        PFN_vkDebugReportCallbackEXT pUserData=type:void*-ignore;
index f1477e2..fd859ad 100755 (executable)
@@ -38,11 +38,14 @@ my $enumInfo = {
        },
 };
 
-# all seen types for dev only
-my $all = {};
-
 # ###################################################################### #
-my $vk = new vulkan();
+my $sys = {};
+
+$sys->{output} = 'bin/gen/notzed.vulkan/classes';
+$sys->{package} = 'vulkan';
+$sys->{verbose} = 0;
+
+my $vk = new vulkan($sys);
 
 my $api = $vk->buildFeatures(
        [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ],
@@ -50,12 +53,6 @@ my $api = $vk->buildFeatures(
          #'wayland',
          'xcb' ]);
 
-my $sys = {};
-
-$sys->{output} = 'bin/gen/notzed.vulkan/classes';
-$sys->{package} = 'vulkan';
-$sys->{verbose} = 0;
-
 my $structTypes = loadTypes($api, 'struct-types.api');
 my $commandTypes = loadTypes($api, 'command-types.api');
 
@@ -195,7 +192,8 @@ foreach my $s (values %{$api->{commands}}) {
                        $m->{deref} .= '-ignore';
                }
 
-               if ($m->{lengthfor}) {
+               # All the vkCmd commands shouldn't imply any array lengths, maybe nothing should really?
+               if ($first->{baseType} ne 'VkCommandBuffer' && $m->{lengthfor}) {
                        my $nstar = $m->{deref} =~ tr/*/*/;
                        if ($nstar == 0) {
                                die "No '$m->{deref}-length' type ".Dumper($s) if !defined $types->{$m->{deref}.'-length'};
@@ -246,202 +244,107 @@ foreach my $s (values %{$api->{commands}}) {
 #print Dumper({ types=>$types, templates=>$templates });
 #print Dumper($vk);
 
-open(my $f, '>', 'types.pm');
-print $f Dumper($commandTypes, $structTypes);
-close $f;
-
-if (1) {
-
-       if (0) {
-               open(my $f, '>', 'api.pm');
-               print $f Dumper($api);
-               close $f;
-               die;
-       }
-
-       if (1) {
-               open(my $f, '>', 'data.pm');
-               print $f Dumper({
-                       'handles' => $api->{handles},
-                               'types' => $api->{types},
-                               'commands' => $api->{commands},
-                               'funcpointers' => $api->{funcpointers},
-                                               });
-               close $f;
-       }
-
-       if (0) {
-               my $f = openOutput($sys, "API");
-
-               print $f "package vulkan;\n";
-               print $f "import jdk.incubator.foreign.*;\n";
-               print $f "import java.lang.invoke.*;\n";
-               print $f "import au.notzed.nativez.*;\n";
-               print $f "public class API {\n";
-               print $f "MemoryAddress self;\n";
-
-               foreach my $c (values %{$api->{commands}}) {
-                       die if ($c->{alias});
-                       #print "$c->{name}\n";
-                       print $f formatFunction($api, $commandTypes, $c)."\n";
-                       #print formatFunctionDescriptor($commandTypes, $c)."\n";
-               }
-               print $f "}\n";
-               closeOutput($sys, "API", $f);
-       }
-
-       exportEnums($vk, $api, 'VkConstants');
-
-       # dump out the extension function tables
-       {
-               my $f = openOutput($sys, 'DispatchInstance');
-               my $template = $structTypes->{templates}->{dispatch};
-               my @init = ();
-               my @fieldInit = ();
-
-               foreach my $k (sort keys %{$api->{commands}}) {
-                       my $c = $api->{commands}->{$k};
-
-                       next if !defined($c->{extensions});
-
-                       push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
-                       push @init, code::formatTemplate($template->{'init'}, $c);
-
-               }
-
-               my $vars = {
-                       package => 'vulkan',
-                       Name => 'DispatchInstance',
-                       init => join("\n\t\t", @init),
-                       'field-init' => join("\n\t", @fieldInit),
-               };
-               print $f code::formatTemplateStream($template->{class}, $vars);
-
-               closeOutput($sys, 'DispatchInstance', $f);
-       }
-
-
-
-       foreach my $k (sort keys %{$api->{types}}) {
-               my $s = $api->{data}->{$k};
-
-               die if !defined $s;
-               next if $s->{alias};
-
-               my $override = $structTypes->{overrides}->{$s->{name}};
-
-               next if $override->{ignore};
-
-               my $f = openOutput($sys, $s->{Name});
-               print $f formatStruct($vk, $api, $s);
-               closeOutput($sys, $s->{Name}, $f);
-       }
+if (0) {
+       open(my $f, '>', 'types.pm');
+       print $f Dumper($commandTypes, $structTypes);
+       close $f;
+}
 
-       foreach my $k (sort keys %{$api->{handles}}) {
-               my $s = $api->{data}->{$k};
+if (0) {
+       open(my $f, '>', 'api.pm');
+       print $f Dumper($api);
+       close $f;
+       die;
+}
 
-               die if !defined $s;
-               next if $s->{alias};
+if (0) {
+       open(my $f, '>', 'data.pm');
+       print $f Dumper({
+               'handles' => $api->{handles},
+                       'types' => $api->{types},
+                       'commands' => $api->{commands},
+                       'funcpointers' => $api->{funcpointers},
+                                       });
+       close $f;
+}
 
-               my $f = openOutput($sys, $s->{name});
-               print $f formatHandle($vk, $api, $s);
-               closeOutput($sys, $s->{name}, $f);
-       }
+exportEnums($vk, $api, 'VkConstants');
 
-       foreach my $k (sort keys %{$api->{funcpointers}}) {
-               my $s = $api->{data}->{$k};
+# dump out the extension function tables
+{
+       my $f = openOutput($sys, 'DispatchInstance');
+       my $template = $structTypes->{templates}->{dispatch};
+       my @init = ();
+       my @fieldInit = ();
 
-               die if !defined $s;
-               next if $s->{alias};
+       foreach my $k (sort keys %{$api->{commands}}) {
+               my $c = $api->{commands}->{$k};
 
-               my $override = $commandTypes->{overrides}->{$s->{name}};
+               next if !defined($c->{extensions});
 
-               next if $override->{ignore};
+               push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
+               push @init, code::formatTemplate($template->{'init'}, $c);
 
-               my $f = openOutput($sys, $s->{name});
-               print $f formatFunctionPointer($vk, $api, $s);
-               closeOutput($sys, $s->{name}, $f);
        }
 
+       my $vars = {
+               package => 'vulkan',
+               Name => 'DispatchInstance',
+               init => join("\n\t\t", @init),
+               'field-init' => join("\n\t", @fieldInit),
+       };
+       print $f code::formatTemplateStream($template->{class}, $vars);
 
-       exit 0;
-
-       #print Dumper (grep { !defined $_->{items} } values %{$api->{enums}});
-
-       #print Dumper($api->{data});
-
-       print "Unique Types:\n";
-       foreach my $k (sort keys %$all) {
-               print "$k\n";
-       }
+       closeOutput($sys, 'DispatchInstance', $f);
+}
 
-       exit 0;
+# structs and unions
+foreach my $k (sort keys %{$api->{types}}) {
+       my $s = $api->{data}->{$k};
 
-       foreach my $k (sort keys %{$api->{commands}}) {
-               my $c = $api->{commands}->{$k};
+       die if !defined $s;
+       next if $s->{alias};
 
-               #print Dumper ($c);
+       my $override = $structTypes->{overrides}->{$s->{name}};
 
-               foreach my $m ($c->{proto}, @{$c->{items}}) {
-                       my $t = $vk->{data}->{$m->{baseType}};
+       next if $override->{ignore};
 
-                       die if !defined $m->{baseType};
-                       print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
+       my $f = openOutput($sys, $s->{Name});
+       print $f formatStruct($vk, $api, $s);
+       closeOutput($sys, $s->{Name}, $f);
+}
 
-                       while ($t->{alias}) {
-                               print "Alias: $t->{name} -> $t->{alias}\n";
-                               $t = $vk->{data}->{$t->{alias}};
-                       }
-               }
-       }
+# handles
+foreach my $k (sort keys %{$api->{handles}}) {
+       my $s = $api->{data}->{$k};
 
-} else {
+       die if !defined $s;
+       next if $s->{alias};
 
-foreach my $k (sort keys %{$vk->{index}}) {
-       print "$k\n";
+       my $f = openOutput($sys, $s->{name});
+       print $f formatHandle($vk, $api, $s);
+       closeOutput($sys, $s->{name}, $f);
 }
 
-my $masks = {};
-my $enums = {};
+# upcalls
+foreach my $k (sort keys %{$api->{funcpointers}}) {
+       my $s = $api->{data}->{$k};
 
-foreach my $k (sort keys %{$vk->{types}}) {
-       my $s = $vk->{types}->{$k};
-       #print Dumper($s);
-       foreach my $m (@{$s->{items}}) {
-               my $t = $vk->{data}->{$m->{baseType}};
+       die if !defined $s;
+       next if $s->{alias};
 
-               die if !defined $m->{baseType};
-               print "? $m->{baseType} ($k $m->{name}\n" if !defined($t);
+       my $override = $commandTypes->{overrides}->{$s->{name}};
 
-               while ($t->{alias}) {
-                       print "Alias: $t->{name} -> $t->{alias}\n";
-                       $t = $vk->{data}->{$t->{alias}};
-               }
+       next if $override->{ignore};
 
-               $masks->{$t->{name}} = $t if ($t->{category} eq 'bitmask');
-               $enums->{$t->{name}} = $t if ($t->{category} eq 'enum');
-       }
+       my $f = openOutput($sys, $s->{name});
+       print $f formatFunctionPointer($vk, $api, $s);
+       closeOutput($sys, $s->{name}, $f);
 }
 
-print Dumper($masks);
-foreach my $k (sort keys %{$masks}) {
-       my $s = $masks->{$k};
-       my $t;
-
-       if ($s->{requires}) {
-               $t = $vk->{data}->{$s->{requires}};
-       } elsif ($s->{name} =~ m/(.*)Flags([0-9A-Z]*)/o && defined $vk->{data}->{"$1FlagBits$2"}) {
-               print "> $s->{name} $1FlagBits$2\n";
-               $t = $vk->{data}->{"$1FlagBits$2"};
-       } else {
-               print "? $s->{name}\n";
-               $t = $s;
-       }
-       print "! $s->{name} r=$s->{requires}\n" if !defined($t);
-       #print Dumper($t);
+exit 0;
 
-}
-}
+# ###################################################################### #
 
 sub loadTypes {
        my $api = shift;
@@ -455,29 +358,11 @@ sub loadTypes {
        foreach my $t (@{$config->{objects}}) {
                if ($t->{type} eq 'type') {
                        my $nopts = $#{$t->{options}};
-                       my $type;
-
-                       if ($nopts >= 0 && defined($types->{$t->{options}->[0]})) {
-                               $type = { %{$types->{$t->{options}->[0]}} };
-                       } elsif ($#{$t->{items}} >= 0) {
-                               $type = {};
-                       } else {
-                               die ("No prototype provided/found for empty type ".Dumper($t));
-                       }
-
-                       if ($#{$t->{items}} >= 0) {
-                               foreach my $s (@{$t->{items}}) {
-                                       my $x = {
-                                               code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
-                                       };
+                       my $type = {};
 
-                                       $x->{eval} = 1 if config::optionFlag('eval', $s);
-
-                                       $type->{$s->{match}} = $x;
-                               }
-                       }
+                       die ("No prototype provided/found for empty type ".Dumper($t)) if ($#{$t->{items}} < 0 && $#{$t->{options}} < 0);
 
-                       # check other options
+                       # Check options / load inherited values
                        foreach my $o (@{$t->{options}}) {
                                if ($o =~ m/^accessor=(.*)$/o) {
                                        die "No template $1" if !defined($templates->{$1});
@@ -492,12 +377,26 @@ sub loadTypes {
                                        $type->{'need-alloc'} = 1;
                                } elsif ($o eq 'is-instance') {
                                        $type->{'is-instance'} = 1;
+                               } elsif (defined($types->{$o})) {
+                                       $type = { %$type, %{$types->{$o}} };
                                } else {
-                                       # doesn't ignore implied parant type
-                                       #die "Unknown option '$o' in ".Dumper($t);
+                                       die "Unknown option '$o' in ".Dumper($t);
                                }
                        }
 
+                       # Load the fields
+                       foreach my $s (@{$t->{items}}) {
+                               # FIXME: maybe i don't want  struct here, as with templates
+                               my $x = {
+                                       code => defined($s->{literal}) ? $s->{literal} : $s->{options}->[$#{$s->{options}}]
+                               };
+
+                               $x->{eval} = 1 if config::optionFlag('eval', $s);
+
+                               $type->{$s->{match}} = $x;
+                       }
+
+                       # Write to all aliases
                        foreach my $k (split /,/,$t->{name}) {
                                $types->{$k} = $type;
                        }
@@ -506,10 +405,6 @@ sub loadTypes {
                                insert => {},
                        };
 
-                       foreach my $s (@{$t->{items}}) {
-                               $code->{$s->{match}} = $s->{literal};
-                               $code->{$s->{match}} =~ s/^\t//gm;
-                       }
                        foreach my $o (@{$t->{options}}) {
                                if ($o =~ m/insert=(.*)/) {
                                        foreach my $t (split /,/,$1) {
@@ -518,9 +413,21 @@ sub loadTypes {
                                                        $code->{insert}->{$2} = $templates->{$1}->{$2};
                                                }
                                        }
+                               } elsif ($o =~ m/^fields=(.*)/) {
+                                       $code->{fields} = $1;
+                               } else {
+                                       die ("Unknown option $o");
                                }
                        }
 
+                       foreach my $s (@{$t->{items}}) {
+                               $code->{$s->{match}} = $s->{literal};
+                               $code->{$s->{match}} =~ s/^\t//gm;
+
+                               # hack since the template is a string
+                               $code->{"$s->{match}:eval"}->{eval} = 1 if config::optionFlag('eval', $s);
+                       }
+
                        $templates->{$t->{name}} = $code;
                } elsif ($t->{type} eq 'override') {
                        foreach my $s (@{$t->{items}}) {
@@ -918,27 +825,63 @@ sub formatStructLayout {
 
        # This doens't need to worry about overrides
 
-       foreach my $m (@{$s->{items}}) {
-               my $type = $types->{$m->{deref}};
-               my $diff = $m->{bitOffset} - $offset;
+       if ($s->{category} eq 'struct') {
+               foreach my $m (@{$s->{items}}) {
+                       my $type = $types->{$m->{deref}};
+                       my $diff = $m->{bitOffset} - $offset;
 
-               push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
+                       push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
 
-               if ($type) {
-                       my $v = buildVars($s, $m, $type);
+                       if ($type) {
+                               my $v = buildVars($s, $m, $type);
 
-                       push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
-                       $offset = $m->{bitOffset} + $m->{bitSize};
-               } else {
-                       push @fields, "/* Missing: $m->{deref} $m->{name} */";
+                               push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+                               $offset = $m->{bitOffset} + $m->{bitSize};
+                       } else {
+                               push @fields, "/* Missing: $m->{deref} $m->{name} */";
+                       }
+               }
+       } else {
+               foreach my $m (@{$s->{items}}) {
+                       my $type = $types->{$m->{deref}};
+
+                       if ($type) {
+                               my $v = buildVars($s, $m, $type);
+
+                               push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+                               $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
+                       } else {
+                               push @fields, "/* Missing: $m->{deref} $m->{name} */";
+                       }
                }
        }
+
        my $diff = $s->{bitSize} - $offset;
+
        push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
 
        return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
 }
 
+sub formatAccessorIf {
+       my $s = shift;
+       my $m = shift;
+       my $info = shift;
+       my $type = shift;
+       my $field = shift;
+       my $v = shift;
+       my $accessor = $type->{accessor};
+       my $template = $accessor->{$field};
+
+       if ($template) {
+               $template = eval($template) if ($accessor->{"$field:eval"});
+
+               die "Error executing template $field $accessor->{$field}: $@" if (!defined($template));
+
+               push @{$info->{$field}}, code::formatTemplate($template, $v) if $template;
+       }
+}
+
 sub formatStruct {
        my $vk = shift;
        my $api = shift;
@@ -949,30 +892,29 @@ sub formatStruct {
 
        my $override = $overrides->{$s->{name}};
        my $template = $override->{template} ? $override->{template} : $templates->{'struct-writeonly'};
+       my @fields = split(/,/, $template->{fields});
+       my $info;
 
-       my $info = {
-               get => [],
-               set => [],
-               getorset => [],
-               varhandle => [],
-               init => [],
-               create => {},
-       };
+       map { $info->{$_} = [] } @fields;
 
-       if ($s->{category} eq 'struct') {
-               $info->{create}->{create} = {
-                       setallArgs => [ 'SegmentAllocator alloc$' ],
-                       setall => [],
-               };
-       } elsif ($s->{category} eq 'union') {
-               foreach my $m (@{$s->{items}}) {
-                       $info->{create}->{"create$m->{Name}"} = {
-                               setallArgs => [ 'SegmentAllocator alloc$' ],
+       my $setall = defined $info->{'java-setall'};
+
+       if ($setall) {
+               if ($s->{category} eq 'struct') {
+                       $info->{create}->{create} = {
+                               'setall-arg' => [ 'SegmentAllocator alloc$' ],
                                setall => [],
                        };
+               } elsif ($s->{category} eq 'union') {
+                       foreach my $m (@{$s->{items}}) {
+                               $info->{create}->{"create$m->{Name}"} = {
+                                       'setall-arg' => [ 'SegmentAllocator alloc$' ],
+                                       setall => [],
+                               };
+                       }
+               } else {
+                       die;
                }
-       } else {
-               die;
        }
 
        #map { $_->{typeInfo} = buildVars($s, $_, $types->{$_->{deref}}) } @{$s->{items}};
@@ -983,32 +925,35 @@ sub formatStruct {
                my $nstar = $m->{deref} =~ tr/*/*/;
                my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
                my $type = $types->{$deref};
-               my $v = buildVars($s, $m, $type);
 
                die "No type $deref ".Dumper($m, $s) if !$type;
 
-               #push @{$info->{getset}}, map { "// $_" } split(/\n/, Dumper($m->{deref}, $type, $override->{$m->{name}}));
-               push @{$info->{varhandle}}, "/* ? Accessor: $m->{fullType} [$m->{deref}] $m->{name} len=$m->{len} lenfor=$m->{lengthfor} override=$deref */";
-
                if ($type->{accessor}) {
-                       push @{$info->{getorset}}, code::formatTemplate($type->{accessor}->{getorset}, $v) if $type->{accessor}->{getorset};
+                       my $v = buildVars($s, $m, $type);
+                       my @todump;
 
                        if ($m->{values}) {
-                               push @{$info->{init}}, code::formatTemplate($type->{accessor}->{init}, $v) if $type->{accessor}->{init};
-                               push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
+                               @todump = qw(init initat set setat);
                        } else {
-                               push @{$info->{get}}, code::formatTemplate($type->{accessor}->{get}, $v) if $type->{accessor}->{get};
-                               push @{$info->{set}}, code::formatTemplate($type->{accessor}->{set}, $v) if $type->{accessor}->{set};
+                               @todump = qw(get getat set setat getorset getorsetat);
 
                                # FIXME: something here is adding length parameters which are already handled by the setXX() calls
-                               if (!$m->{'no-setall'}) {
+                               if ($setall && !$m->{'no-setall'}) {
                                        my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
-                                       push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
-                                       push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
+                                       #push @{$create->{setallArgs}}, code::formatTemplate($type->{accessor}->{'setall-arg'}, $v) if $type->{accessor}->{'setall-arg'};
+                                       #push @{$create->{setall}}, code::formatTemplate($type->{accessor}->{setall}, $v) if $type->{accessor}->{setall};
+                                       formatAccessorIf($s, $m, $create, $type, 'setall-arg', $v);
+                                       formatAccessorIf($s, $m, $create, $type, 'setall', $v);
                                }
                        }
+
+                       push @{$info->{handle}}, code::formatTemplate($v->{handle}, $v)." /* $m->{name} $m->{fullType} ($m->{deref}) */" if $info->{handle} && $v->{handle};
+                       push @{$info->{handleat}}, code::formatTemplate($v->{handleat}, $v) if $info->{handleat} && $v->{handleat};
+
+                       foreach my $field (@todump) {
+                               push @{$info->{$field}}, code::formatTemplate($type->{accessor}->{$field}, $v) if $info->{$field} && $type->{accessor}->{$field};
+                       }
                }
-               push @{$info->{varhandle}}, code::formatTemplate($v->{handle}, $v) if $v->{handle};
        }
 
        # create constructors
@@ -1017,15 +962,18 @@ sub formatStruct {
                name => $s->{name},
                Name => $s->{Name},
                layout => formatStructLayout($types, $s),
-               init => join ("\n", @{$info->{init}}),
-               get => join ("\n", @{$info->{get}}),
-               set => join ("\n", @{$info->{set}}),
-               getorset => join ("\n", @{$info->{getorset}}),
-               #'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
-               #'java-setall' => join ("\n", @{$info->{setall}}),
-               varhandle => join ("\n", @{$info->{varhandle}}),
+               #init => join ("\n", @{$info->{init}}),
+               #get => join ("\n", @{$info->{get}}),
+               #set => join ("\n", @{$info->{set}}),
+               #getorset => join ("\n", @{$info->{getorset}}),
+               ##'java-setall-arguments' => join (",", @{$info->{setallArgs}}),
+               ##'java-setall' => join ("\n", @{$info->{setall}}),
+               #varhandle => join ("\n", @{$info->{varhandle}}),
        };
 
+       foreach my $field (@fields) {
+               $v->{$field} = join("\n", @{$info->{$field}});
+       }
 
        # build sub-components using the full $v
        my @createAll = ();
@@ -1033,24 +981,28 @@ sub formatStruct {
                my $t = $template->{insert}->{$k};
 
                if ($k eq 'create-all') {
-                       foreach my $kk (keys %{$info->{create}}) {
-                               my $create = $info->{create}->{$kk};
-
-                               if ($#{$create->{setallArgs}} > 0) {
-                                       my $v = {
-                                               create => $kk,
-                                               Name => $s->{Name},
-                                               'java-setall-arguments' => join (', ', @{$create->{setallArgs}}),
-                                               'java-setall' => join ("\n\t\t", @{$create->{setall}}),
-                                       };
-                                       push @createAll, code::formatTemplateStream($t, $v);
+                       if ($setall) {
+                               foreach my $kk (keys %{$info->{create}}) {
+                                       my $create = $info->{create}->{$kk};
+
+                                       if ($#{$create->{'setall-arg'}} > 0) {
+                                               my $v = {
+                                                       create => $kk,
+                                                       Name => $s->{Name},
+                                                       'java-setall-arguments' => join (', ', @{$create->{'setall-arg'}}),
+                                                       'java-setall' => join ("\n\t\t", @{$create->{setall}}),
+                                               };
+                                               push @createAll, code::formatTemplateStream($t, $v);
+                                       }
                                }
                        }
                } else {
                        $v->{$k} = code::formatTemplate($t, $v);
                }
        }
-       $v->{'create-all'} = join("\n", @createAll);
+       $v->{'create-all'} = join("\n", @createAll) if $setall;
+
+       #die Dumper($info) if $s->{name} eq 'VkMemoryOpaqueCaptureAddressAllocateInfo';
 
        join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
                code::formatTemplateStream($template->{class}, $v);
@@ -1159,6 +1111,11 @@ sub collectFunctionInfo {
        #return if !defined($override->{template});
        #return if ($s->{name} ne 'vkCmdUpdateBuffer');
 
+       my @arrayFields = qw(java-arg invoke-arg native-init query-init query-arg native-arg trampoline-arg);
+       my @fixedFields = qw(java-result java-result-return java-result-assign);
+
+       map { $info->{$_} = [] } @arrayFields;
+
        foreach my $m (@{$s->{items}}) {
                my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
                my $type = $types->{$deref};
@@ -1167,26 +1124,38 @@ sub collectFunctionInfo {
 
                my $v = buildVars($s, $m, $type);
 
-               #push @javaArgs, "/* $m->{name} $m->{deref} */ " if !$v->{'java-argument'};
+               foreach my $field (@arrayFields) {
+                       if ($v->{$field}) {
+                               push @{$info->{$field}}, code::formatTemplate($v->{$field}, $v);
+                       } elsif ($field eq 'query-arg') {
+                               push @{$info->{$field}}, code::formatTemplate($v->{'invoke-arg'}, $v);
+                       }
+               }
+
+               foreach my $field (@fixedFields) {
+                       $info->{$field} = code::formatTemplate($v->{$field}, $v) if ($v->{$field});
+               }
 
-               push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
-               push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
+               if (0) {
+                       push @javaArgs, "/* $m->{name} $m->{deref} */ ".code::formatTemplate($v->{'java-arg'}, $v) if ($v->{'java-arg'});
+                       push @invokeArgs, code::formatTemplate($v->{'invoke-arg'}, $v) if ($v->{'invoke-arg'});
 
-               push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
-               push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
+                       push @nativeInit, code::formatTemplate($v->{'native-init'}, $v) if ($v->{'native-init'});
+                       push @queryInit, code::formatTemplate($v->{'query-init'}, $v) if ($v->{'query-init'});
 
-               if ($v->{'query-arg'}) {
-                       push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
-               } elsif ($v->{'invoke-arg'}) {
-                       push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
-               }
+                       if ($v->{'query-arg'}) {
+                               push @queryArgs, code::formatTemplate($v->{'query-arg'}, $v);
+                       } elsif ($v->{'invoke-arg'}) {
+                               push @queryArgs, code::formatTemplate($v->{'invoke-arg'}, $v);
+                       }
 
-               push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
-               push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
+                       push @nativeArgs, code::formatTemplate($v->{'native-arg'}, $v) if ($v->{'native-arg'});
+                       push @trampArgs, code::formatTemplate($v->{'trampoline-arg'}, $v) if ($v->{'trampoline-arg'});
 
-               $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
-               $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
-               $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
+                       $info->{'java-result'} = code::formatTemplate($v->{'java-result'}, $v) if ($v->{'java-result'});
+                       $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v) if ($v->{'java-result-return'});
+                       $info->{'java-result-assign'} = code::formatTemplate($v->{'java-result-assign'}, $v) if ($v->{'java-result-assign'});
+               }
 
                $needScope = 1 if $type->{'need-scope'};
                $needFrame = 1 if $type->{'need-frame'};
@@ -1234,18 +1203,26 @@ sub collectFunctionInfo {
        }
 
        $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
-       push @javaArgs, 'SegmentAllocator alloc$' if $needAlloc;
-       push @javaArgs, 'ResourceScope scope$' if $needScope;
+       $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
 
-       $info->{'java-arguments'} = join ",\n\t", @javaArgs;
-       $info->{'native-init'} = join "\n\t", @nativeInit;
-       $info->{'invoke-arguments'} = join ", ", @invokeArgs;
-       $info->{'query-init'} = join "\n\t\t\t", @queryInit;
-       $info->{'query-arguments'} = join ", ", @queryArgs;
+       push @{$info->{'java-arg'}}, 'SegmentAllocator alloc$' if $needAlloc;
+       push @{$info->{'java-arg'}}, 'ResourceScope scope$' if $needScope;
 
-       $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
-       $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
-       $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
+       foreach my $field (@arrayFields) {
+               my $with = $field =~ m/-arg$/n ? ",\n\t" : "\n\t";
+               $info->{$field} = join $with, @{$info->{$field}};
+       }
+
+       if (0) {
+               $info->{'java-arguments'} = join ",\n\t", @javaArgs;
+               $info->{'native-init'} = join "\n\t", @nativeInit;
+               $info->{'invoke-arguments'} = join ", ", @invokeArgs;
+               $info->{'query-init'} = join "\n\t\t\t", @queryInit;
+               $info->{'query-arguments'} = join ", ", @queryArgs;
+
+               $info->{'native-arguments'} = join ",\n\t", @nativeArgs;
+               $info->{'trampoline-arguments'} = join ",\n\t", @trampArgs;
+       }
 
        $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
        $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
index 1de0e54..25414fa 100644 (file)
@@ -23,6 +23,16 @@ code value {
                {java-set};
        }
   }}
+  getat {{
+       public {type} get{Name}AtIndex(long i$) {
+               return {java-getat};
+       }
+  }}
+  setat {{
+       public void set{Name}AtIndex(long i$, {type} {name}) {
+               {java-setat};
+       }
+  }}
 
   # FIXME: only handles single element arrays
   init {{ {name}$VH.set(this.segment, VkConstants.{values}); }}
@@ -49,6 +59,29 @@ code value-array {
                {java-seti};
        }
   }}
+
+  setall-arg eval {{
+       if ($m->{len1} <= 4) {
+               join ", ", map { '{typei} {name}$'.$_ } (0 .. $m->{len1}-1);
+       } else {
+               "{typei}[] {name} /* $m->{deref} $m->{len1} */";
+       }
+  }}
+  setall eval {{
+       if ($m->{len1} <= 4) {
+               join "\n\t", map { "self\$.set{Name}Element($_, {name}\$$_);" } (0 .. $m->{len1}-1);
+    } else {
+               <<END;
+               if ({name} != null) {
+                       try {
+                               ((MemorySegment){name}\$SH.invokeExact(self\$.segment)).copyFrom(MemorySegment.ofArray({name}));
+                       } catch (Throwable t) {
+                               System.err.println("Copy error: " + t.getLocalizedMessage());
+                       }
+               }
+END
+    }
+  }}
 }
 
 code value-array2d {
@@ -97,6 +130,18 @@ code value-alloc {
                {java-set};
        }
   }}
+  getat {{
+       /* {deref} */
+       public {type} get{Name}AtIndex(long i$) {
+               return {java-getat};
+       }
+  }}
+  setat {{
+       /* {deref} */
+       public void set{Name}AtIndex(long i$, {type} {name}, SegmentAllocator alloc$) {
+               {java-setat};
+       }
+  }}
   setall-arg {{ {type} {name} }}
   setall {{ self$.set{Name}({name}, alloc$); }}
 }
@@ -165,7 +210,7 @@ code handle {
                }
 
                public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc) {
-                       return HandleArray.createArray(1, alloc, {name}::create);
+                       return HandleArray.createArray(length, alloc, {name}::create);
                }
 
                public MemoryAddress address() {
@@ -240,11 +285,11 @@ code handle-dispatch {
 
                // TODO: evaluate how scope fits here
                public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc, DispatchInstance dispatch, ResourceScope scope) {
-                       return HandleArray.createArray(1, alloc, (a, s) -> create(a, dispatch, s), scope);
+                       return HandleArray.createArray(length, alloc, (a, s) -> create(a, dispatch, s), scope);
                }
 
                public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc, VkInstance instance, ResourceScope scope) {
-                       return HandleArray.createArray(1, alloc, (a, s) -> create(a, instance.dispatch, s), scope);
+                       return HandleArray.createArray(length, alloc, (a, s) -> create(a, instance.dispatch, s), scope);
                }
 
                public MemoryAddress address() {
@@ -349,7 +394,8 @@ code struct {
 }
 
 # default - writeonly struct
-code struct-writeonly insert=struct:header,struct:create-all {
+code struct-writeonly insert=struct:header,struct:create-all
+       fields=init,set,getorset,handle,java-setall {
   class {{
        // template: struct-writeonly:class
        package {package};
@@ -365,12 +411,13 @@ code struct-writeonly insert=struct:header,struct:create-all {
                {set}
                {getorset}
 
-               {varhandle}
+               {handle}
        }
   }}
 }
 
-code struct-writeonly-array insert=struct:header,struct:create-all,struct:array {
+code struct-writeonly-array insert=struct:header,struct:create-all,struct:array
+       fields=init,set,getorset,setat,getorsetat,handle,handleat,java-setall {
   class {{
        // template: struct-writeonly-array:class
        package {package};
@@ -387,12 +434,17 @@ code struct-writeonly-array insert=struct:header,struct:create-all,struct:array
                {set}
                {getorset}
 
-               {varhandle}
+               {setat}
+               {getorsetat}
+
+               {handle}
+               {handleat}
        }
   }}
 }
 
-code struct-readonly insert=struct:header {
+code struct-readonly insert=struct:header
+       fields=init,get,getorset,handle {
   class {{
        // template: struct-readonly:class
        package {package};
@@ -406,12 +458,13 @@ code struct-readonly insert=struct:header {
                {get}
                {getorset}
 
-               {varhandle}
+               {handle}
        }
   }}
 }
 
-code struct-readonly-array insert=struct:header,struct:array {
+code struct-readonly-array insert=struct:header,struct:array
+       fields=init,get,getorset,getat,getorsetat,handle,handleat {
   class {{
        // template: struct-readonly-array:class
        package {package};
@@ -426,12 +479,17 @@ code struct-readonly-array insert=struct:header,struct:array {
                {get}
                {getorset}
 
-               {varhandle}
+               {getat}
+               {getorsetat}
+
+               {handle}
+               {handleat}
        }
   }}
 }
 
-code struct-readwrite insert=struct:header,struct:create-all {
+code struct-readwrite insert=struct:header,struct:create-all
+       fields=init,get,set,getorset,handle,java-setall {
   class {{
        // template: struct-readwrite:class
        package {package};
@@ -448,12 +506,13 @@ code struct-readwrite insert=struct:header,struct:create-all {
                {set}
                {getorset}
 
-               {varhandle}
+               {handle}
        }
   }}
 }
 
-code struct-readwrite-array insert=struct:header,struct:create-all,struct:array {
+code struct-readwrite-array insert=struct:header,struct:create-all,struct:array
+       fields=init,get,getat,set,setat,getorset,getorsetat,handle,handleat,java-setall {
   class {{
        // template: struct-readwrite-array:class
        package {package};
@@ -471,27 +530,41 @@ code struct-readwrite-array insert=struct:header,struct:create-all,struct:array
                {set}
                {getorset}
 
-               {varhandle}
+               {getat}
+               {setat}
+               {getorsetat}
+
+               {handle}
+               {handleat}
        }
   }}
 }
 
 # ###################################################################### #
 
-# how to arrays?  in code?
-# how to lengths?
-
+# Basic value-based accessor
 type value accessor=value {
-       java-get        {{ ({type}){name}$VH.get(this.segment) }}
-       java-set        {{ {name}$VH.set(this.segment, {name}) }}
-       handle          {{ final static VarHandle {name}$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}")); }}
+       native-value    {{ {name} }}
+
+       native-get              {{ ({type}){name}$VH.get(this.segment) }}
+       handle                  {{ final static VarHandle {name}$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}")); }}
+
+       java-get                {{ {native-get} }}
+       java-set                {{ {name}$VH.set(this.segment, {native-value}) }}
+
+       native-getat    {{ ({type}){name}$AH.get(this.segment, i$) }}
+       native-setat    {{ {name}$AH.set(this.segment, i$, {native-value}) }}
+       handleat                {{ final static VarHandle {name}$AH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("{name}")); }}
+
+       java-getat              {{ {native-getat} }}
+       java-setat              {{ {native-setat} }}
 }
 
 type value-array accessor=value-array {
        native-get      {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
        java-get        {{ {type}.create({native-get}) }}
-       java-geti       {{ ({typei}){name}$EH.get(i$) }}
-       java-seti       {{ {name}$EH.set(i$, {name}) }}
+       java-geti       {{ ({typei}){name}$EH.get(this.segment, i$) }}
+       java-seti       {{ {name}$EH.set(this.segment, i$, {name}) }}
        handle          {{
                final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}"));
                final static VarHandle {name}$EH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}"), MemoryLayout.PathElement.sequenceElement());
@@ -501,8 +574,8 @@ type value-array accessor=value-array {
 type value-array2d accessor=value-array2d {
        native-get      {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
        java-get        {{ {type}.create({native-get}) }}
-       java-geti       {{ ({typei}){name}$EH.get(i$, j$) }}
-       java-seti       {{ {name}$EH.set(i$, j$, {name}) }}
+       java-geti       {{ ({typei}){name}$EH.get(this.segment, i$, j$) }}
+       java-seti       {{ {name}$EH.set(this.segment, i$, j$, {name}) }}
        handle          {{
                final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}"));
                final static VarHandle {name}$EH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}"), MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement());
@@ -558,7 +631,6 @@ type double value {
 # ###################################################################### #
 # implied length types
 type uint64_t-implied,size_t-implied uint64_t accessor=value-implied {
-
 }
 
 type uint32_t-implied uint32_t accessor=value-implied {
@@ -607,10 +679,11 @@ type pointer value {
        layout  {{ Memory.POINTER }}
        type    {{ MemoryAddress }}
 
-       native-get      {{ (MemoryAddress){name}$VH.get(this.segment) }}
+       native-value    {{ Memory.address({name}) }}
+       native-get              {{ (MemoryAddress){name}$VH.get(this.segment) }}
 
-       java-get        {{ {native-get} }}
-       java-set        {{ {name}$VH.set(this.segment, Memory.address({name})) }}
+#      java-get        {{ {native-get} }}
+#      java-set        {{ {name}$VH.set(this.segment, Memory.address({name})) }}
 }
 
 type void* pointer;
@@ -669,7 +742,7 @@ type char* pointer accessor=value-alloc {
        type            {{ String }}
 
        java-get        {{ ({native-get}).getUtf8String(0) }}
-       java-set        {{ {name}$VH.set(this.segment, alloc$.allocateUtf8String({name}).address()) }}
+       native-value {{ alloc$.allocateUtf8String({name}).address() }}
 
        # this just verifies it's a string type
        length eval     {{
index e3dfe13..6f3a0bf 100644 (file)
@@ -11,7 +11,9 @@ use Time::HiRes qw(clock_gettime CLOCK_REALTIME);
 
 sub new {
        my $class = shift;
+       my $sys = shift;
        my $self = {
+               sys => $sys,
                data => {},
                extensions => [],
                handles => {},
@@ -154,7 +156,7 @@ sub buildFeatures {
        };
 
        foreach my $feature (grep { $versions->{$_->{name}} } @{$vk->{features}}) {
-               print "Feature $feature->{name}\n";
+               print "Feature $feature->{name}\n" if ($vk->{sys}->{verbose});
                foreach my $req (@{$feature->{require}}) {
                        buildRequirement($vk, $data, $req);
                }
@@ -164,7 +166,7 @@ sub buildFeatures {
                                                   } @{$vk->{extensions}}) {
                foreach my $req (grep { (!defined($_->{feature})) || $versions->{$_->{feature}} }
                                                 @{$extension->{require}}) {
-                       print "Extension $extension->{name} $req->{feature}\n";
+                       print "Extension $extension->{name} $req->{feature}\n" if ($vk->{sys}->{verbose});
                        buildRequirement($vk, $data, $req, $extension);
                }
        }
@@ -219,47 +221,6 @@ sub buildFeatures {
                $s->{fullType} = 'VkFlags' if !defined $s->{fullType};
        }
 
-       if (0) {
-       # Have to actually map the types too
-       {
-               my $del = {};
-               my $add = {};
-               foreach my $c (values %{$types}) {
-                       if ($c->{alias}) {
-                               print "T";
-                               while ($c->{alias}) {
-                                       print " $c->{name}";
-                                       $c = $vk->{data}->{$c->{alias}};
-                               }
-                               print " -> $c->{name}\n";
-                       }
-               }
-               map {delete $types->{$_} } (keys %$del);
-               map {$data->{$_->{name}} = $_; $enums->{$_->{name}} = $_ } (values %$add);
-       }
-
-       # check type sare included?
-       {
-               my $del = {};
-               my $add = {};
-               foreach my $e (values %{$enums}) {
-                       if ($e->{alias}) {
-                               print "D";
-                               while ($e->{alias}) {
-                                       print " $e->{name}";
-                                       $del->{$e->{name}} = $e;
-                                       $e = $vk->{data}->{$e->{alias}};
-                               }
-                               die if !defined($e);
-                               print " -> $e->{name}\n";
-                               $add->{$e->{name}} = $e;
-                       }
-               }
-               map {delete $enums->{$_} } (keys %$del);
-               map {$data->{$_->{name}} = $_; $enums->{$_->{name}} = $_ } (values %$add);
-       }
-       }
-
        my $api = {
                data => $data,
                handles => $handles,