From bf8f8eced4353bf75734ecee2d47c972f46bcc74 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Thu, 28 Apr 2022 12:08:42 +0930 Subject: [PATCH] Added graphics vulkan demo. Added indexed accessors for embedded arrays. Added initialisers for embedded arrays. Tweaked some of the implied call lengths. --- Makefile | 2 +- .../classes/vulkan/test/Cube.java | 55 + .../classes/vulkan/test/GLMaths.java | 131 ++ .../classes/vulkan/test/TestCube.java | 1131 +++++++++++++++++ .../classes/vulkan/test/TestMandelbrot.java | 2 +- src/notzed.vulkan/gen/command-types.api | 46 +- src/notzed.vulkan/gen/generate-vulkan | 561 ++++---- src/notzed.vulkan/gen/struct-types.api | 133 +- src/notzed.vulkan/gen/vulkan.pm | 47 +- 9 files changed, 1721 insertions(+), 387 deletions(-) create mode 100644 src/notzed.vulkan.test/classes/vulkan/test/Cube.java create mode 100644 src/notzed.vulkan.test/classes/vulkan/test/GLMaths.java create mode 100644 src/notzed.vulkan.test/classes/vulkan/test/TestCube.java diff --git a/Makefile b/Makefile index 824bbbd..c22d81c 100644 --- 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 index 0000000..e8f824e --- /dev/null +++ b/src/notzed.vulkan.test/classes/vulkan/test/Cube.java @@ -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 index 0000000..3414740 --- /dev/null +++ b/src/notzed.vulkan.test/classes/vulkan/test/GLMaths.java @@ -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 index 0000000..5fce884 --- /dev/null +++ b/src/notzed.vulkan.test/classes/vulkan/test/TestCube.java @@ -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 chainImage; + HandleArray chainImageView; + + int depthFormat; + VkImage depthImage; + VkImageView depthView; + VkDeviceMemory depthMemory; + + VkCommandPool cmd_pool; + HandleArray cmd; + + BufferMemory uniform; + VkPipelineLayout pipeline_layout; + + VkDescriptorSetLayout desc_layout; + VkDescriptorPool desc_pool; + HandleArray desc_set; + + + VkRenderPass render_pass; + HandleArray framebuffers; + + BufferMemory vertex; + HandleArray 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 shader = VkShaderModule.createArray(2, (SegmentAllocator)scope); + + HandleArray 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 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 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 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 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 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 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 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 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; diff --git a/src/notzed.vulkan/gen/generate-vulkan b/src/notzed.vulkan/gen/generate-vulkan index f1477e2..fd859ad 100755 --- a/src/notzed.vulkan/gen/generate-vulkan +++ b/src/notzed.vulkan/gen/generate-vulkan @@ -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}: ''; diff --git a/src/notzed.vulkan/gen/struct-types.api b/src/notzed.vulkan/gen/struct-types.api index 1de0e54..25414fa 100644 --- a/src/notzed.vulkan/gen/struct-types.api +++ b/src/notzed.vulkan/gen/struct-types.api @@ -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 { + < 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 {{ diff --git a/src/notzed.vulkan/gen/vulkan.pm b/src/notzed.vulkan/gen/vulkan.pm index e3dfe13..6f3a0bf 100644 --- a/src/notzed.vulkan/gen/vulkan.pm +++ b/src/notzed.vulkan/gen/vulkan.pm @@ -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, -- 2.39.2