--- /dev/null
+
+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,
+ };
+}
--- /dev/null
+ /*
+The MIT License (MIT)
+
+Copyright (C) 2017 Eric Arnebäck
+Copyright (C) 2019 Michael Zucchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ */
+
+/*
+ * This is a Java conversion of a C conversion of this:
+ * https://github.com/Erkaman/vulkan_minimal_compute
+ *
+ * It's been simplified a bit and converted to the 'zvk' api.
+ */
+
+package vulkan.test;
+
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.image.MemoryImageSource;
+import javax.swing.AbstractAction;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.KeyStroke;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Collections;
+
+import java.lang.invoke.*;
+import jdk.incubator.foreign.*;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.VkConstants.*;
+
+import xlib.*;
+import static xlib.XLib.*;
+import static vulkan.test.GLMaths.*;
+
+public class TestCube {
+ static final boolean debug = true;
+
+ final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
+ final static int NUM_DESCRIPTOR_SETS = 1;
+
+ ResourceScope scope = ResourceScope.newSharedScope();
+
+ int width = 800;
+ int height = 800;
+ float projection[] = new float[16];
+ float view[] = new float[16];
+ float model[] = new float[16];
+ float clip[] = new float[] {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 1.0f
+ };
+ float mvp[] = new float[16];
+
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ VkPhysicalDeviceFeatures device_features;
+
+ int present_queue_index;
+ int graphics_queue_index;
+
+ VkDevice device;
+ VkSwapchainKHR chain;
+
+ VkQueue graphics_queue;
+ VkQueue present_queue;
+
+ int chainImageFormat;
+ HandleArray<VkImage> chainImage;
+ HandleArray<VkImageView> chainImageView;
+
+ int depthFormat;
+ VkImage depthImage;
+ VkImageView depthView;
+ VkDeviceMemory depthMemory;
+
+ VkCommandPool cmd_pool;
+ HandleArray<VkCommandBuffer> cmd;
+
+ BufferMemory uniform;
+ VkPipelineLayout pipeline_layout;
+
+ VkDescriptorSetLayout desc_layout;
+ VkDescriptorPool desc_pool;
+ HandleArray<VkDescriptorSet> desc_set = VkDescriptorSet.createArray(1, (SegmentAllocator)scope);
+
+
+ VkRenderPass render_pass;
+ HandleArray<VkFramebuffer> framebuffers;
+
+ BufferMemory vertex;
+ HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(2, (SegmentAllocator)scope);
+
+ IntArray cube_vs;
+ IntArray cube_fs;
+ HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
+
+ HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
+
+ VkSemaphore chainSemaphore;
+ VkFence drawFence;
+
+ record BufferMemory (VkBuffer buffer, VkDeviceMemory memory, long size) {
+ public void free(VkDevice device) {
+ device.vkFreeMemory(memory, null);
+ device.vkDestroyBuffer(buffer, null);
+ }
+ }
+
+ VkDebugUtilsMessengerEXT logger;
+
+ void init_debug() throws Exception {
+ if (!debug)
+ return;
+ try (Frame frame = Frame.frame()) {
+ var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data, dummy) -> {
+ System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+ return 0;
+ }, scope);
+ VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame,
+ 0,
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+ cb,
+ null);
+
+ logger = instance.vkCreateDebugUtilsMessengerEXT(info, null, scope);
+ }
+
+ //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
+
+ }
+
+ void init_instance() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame,
+ 0,
+ VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_MAKE_API_VERSION(0, 1, 0, 0)),
+ new String[] { "VK_LAYER_KHRONOS_validation" },
+ new String[] { "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils" }
+ );
+
+ instance = VkInstance.vkCreateInstance(info, null, scope);
+ System.out.printf("instance = %s\n", instance);
+ }
+ }
+
+ XDisplay display;
+ long window;
+ long wm_delete_window;
+ VkSurfaceKHR surface;
+
+ void init_surface() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ XInitThreads();
+ display = XOpenDisplay(null);
+ long visualMask = VisualScreenMask;
+ IntArray numberOfVisuals = IntArray.createArray(1, frame);
+ XVisualInfo vInfoTemplate = XVisualInfo.create(frame);
+
+ vInfoTemplate.setScreen(DefaultScreen(display));
+
+ XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals);
+ long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone);
+
+ XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame);
+
+ windowAttributes.setColormap(colormap);
+ windowAttributes.setBackgroundPixel(0xffffffff);
+ windowAttributes.setBorderPixel(0);
+ windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask);
+
+ window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()),
+ 0, 0, width, height,
+ 0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(),
+ CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, windowAttributes);
+
+ XSelectInput(display, window, ExposureMask | KeyPressMask);
+ XMapWindow(display, window);
+ XFlush(display);
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
+
+ VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(frame,
+ 0,
+ display,
+ window);
+
+ surface = instance.vkCreateXlibSurfaceKHR(surfaceinfo, null, scope);
+ System.out.printf("surface: %s\n", surface);
+ }
+ }
+
+ void init_device() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ IntArray count$h = IntArray.create(frame, 1);
+ IntArray present$h = IntArray.create(frame, 1);
+ HandleArray<VkPhysicalDevice> devs;
+ int count;
+ int res;
+
+ devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+
+ // Search for device and queue indices
+ int devid = -1;
+ int present_queue = -1;
+ int graphics_queue = -1;
+ for (int i = 0; i < devs.length(); i++) {
+ VkPhysicalDevice dev = devs.getAtIndex(i);
+ VkQueueFamilyProperties famprops;
+
+ // TODO: change to return the allocated array directly
+ dev.vkGetPhysicalDeviceQueueFamilyProperties(count$h, null);
+ famprops = VkQueueFamilyProperties.createArray(count$h.getAtIndex(0), frame);
+ dev.vkGetPhysicalDeviceQueueFamilyProperties(count$h, famprops);
+
+ for (int j = 0; j < famprops.length(); j++) {
+ boolean present;
+
+ dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
+ present = present$h.get(0) != 0;
+
+ if (present && present_queue == -1)
+ present_queue = j;
+ if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ graphics_queue = j;
+ if (present) {
+ present_queue = j;
+ break;
+ }
+ }
+ }
+ if (present_queue != -1 && graphics_queue != -1) {
+ devid = i;
+ break;
+ }
+ }
+
+ if (devid == -1)
+ throw new Exception("Cannot find a suitable device");
+
+ physicalDevice = devs.getAtIndex(devid);
+ present_queue_index = present_queue;
+ graphics_queue_index = graphics_queue;
+
+ // NOTE: app scope
+ memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
+ device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
+
+ FloatArray qpri = FloatArray.create(frame, 0.0f);
+ VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
+ frame,
+ 0,
+ graphics_queue,
+ qpri);
+ String [] extensions = {
+ "VK_KHR_swapchain"
+ };
+ VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
+ features.setDepthClamp(1);
+ VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+ frame,
+ 0,
+ qinfo,
+ null,
+ extensions,
+ features);
+
+ device = physicalDevice.vkCreateDevice(devinfo, null, scope);
+
+ System.out.printf("device = %s\n", device);
+
+ /* ************************************************************** */
+ int format;
+ int formatCount;
+ physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, count$h, null);
+ formatCount = count$h.getAtIndex(0);
+ VkSurfaceFormatKHR surfFormats = VkSurfaceFormatKHR.createArray(formatCount, frame);
+ physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, count$h, surfFormats);
+ // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+ // the surface has no preferred format. Otherwise, at least one
+ // supported format will be returned.
+ if (formatCount == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
+ format = VK_FORMAT_B8G8R8A8_UNORM;
+ } else {
+ format = surfFormats.getFormatAtIndex(0);
+ }
+
+ VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
+
+ physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
+
+ physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, count$h, null);
+ IntArray presentModes = IntArray.createArray(count$h.get(0), frame);
+ physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, count$h, presentModes);
+
+ VkExtent2D swapchainExtent;
+ // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+ if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
+ // If the surface size is undefined, the size is set to
+ // the size of the images requested.
+ swapchainExtent = VkExtent2D.create(frame,
+ clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
+ clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()));
+ } else {
+ // If the surface size is defined, the swap chain size must match
+ swapchainExtent = surfCapabilities.getCurrentExtent();
+ }
+ int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ int compositeAlphaFlags[] = {
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ };
+ for (int flag: compositeAlphaFlags) {
+ if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
+ compositeAlpha = flag;
+ break;
+ }
+ }
+
+ VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(frame,
+ 0,
+ surface,
+ surfCapabilities.getMinImageCount(),
+ format,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ 1, //.imageArrayLayers = 1,
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ // assumes queues are same.
+ null,
+ (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
+ ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
+ compositeAlpha,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_TRUE,
+ null);
+ chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth());
+ chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight());
+
+ chain = device.vkCreateSwapchainKHR(chaininfo, null, scope);
+
+ int chainImageCount;
+ device.vkGetSwapchainImagesKHR(chain, count$h, null);
+ chainImageCount = count$h.get(0);
+ chainImage = VkImage.createArray(chainImageCount, (SegmentAllocator)scope);
+ chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
+
+ device.vkGetSwapchainImagesKHR(chain, count$h, chainImage);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame,
+ 0,
+ null,
+ VK_IMAGE_VIEW_TYPE_2D,
+ format);
+ VkComponentMapping components = viewinfo.getComponents();
+ components.setR(VK_COMPONENT_SWIZZLE_R);
+ components.setG(VK_COMPONENT_SWIZZLE_G);
+ components.setB(VK_COMPONENT_SWIZZLE_B);
+ components.setA(VK_COMPONENT_SWIZZLE_A);
+ VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
+ subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
+ subresourceRange.setLevelCount(1);
+ subresourceRange.setLayerCount(1);
+
+ for (int i = 0; i < chainImageCount; i++) {
+ viewinfo.setImage(chainImage.get(i));
+
+ chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, null, scope));
+ }
+
+ chainImageFormat = format;
+ }
+ }
+
+ void init_device_queue() {
+ graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
+ if (graphics_queue_index == present_queue_index) {
+ present_queue = graphics_queue;
+ } else {
+ present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
+ }
+ }
+
+ void init_command() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame,
+ 0,
+ graphics_queue_index);
+
+ cmd_pool = device.vkCreateCommandPool(poolinfo, null, scope);
+
+ VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
+ cmd_pool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ 1);
+
+ cmd = VkCommandBuffer.createArray(instance, 1, (SegmentAllocator)scope, scope);
+ device.vkAllocateCommandBuffers(cmdinfo, cmd);
+ }
+ }
+
+ // parameterise as init_image?
+ void init_depth() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ int format = VK_FORMAT_D16_UNORM;
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0,
+ VK_IMAGE_TYPE_2D,
+ format,
+ 1,
+ 1,
+ NUM_SAMPLES,
+ 0,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ null,
+ VK_IMAGE_LAYOUT_UNDEFINED);
+ imageinfo.getExtent().setWidth(width);
+ imageinfo.getExtent().setHeight(height);
+ imageinfo.getExtent().setDepth(1);
+
+ depthImage = device.vkCreateImage(imageinfo, null, scope);
+
+ device.vkGetImageMemoryRequirements(depthImage, req);
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
+
+ depthMemory = device.vkAllocateMemory(alloc, null, scope);
+
+ device.vkBindImageMemory(depthImage, depthMemory, 0);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0,
+ depthImage,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_FORMAT_D16_UNORM);
+
+ VkComponentMapping components = viewinfo.getComponents();
+ components.setR(VK_COMPONENT_SWIZZLE_R);
+ components.setG(VK_COMPONENT_SWIZZLE_G);
+ components.setB(VK_COMPONENT_SWIZZLE_B);
+ components.setA(VK_COMPONENT_SWIZZLE_A);
+ VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
+ subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
+ subresourceRange.setLevelCount(1);
+ subresourceRange.setLayerCount(1);
+
+ depthView = device.vkCreateImageView(viewinfo, null, scope);
+
+ depthFormat = format;
+ }
+ }
+
+ void init_uniform() throws Exception {
+ uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp));
+ }
+
+ void init_descriptor() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+ VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame,
+ 0,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ null);
+ VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame,
+ 0,
+ layout_binding);
+
+ desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, null, scope);
+ layout_table.setAtIndex(0, desc_layout);
+
+ VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
+ 0,
+ 1,
+ layout_table,
+ null);
+
+ pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, null, scope);
+
+ VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1);
+
+ VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame,
+ 0,
+ 1,
+ type_count);
+
+ desc_pool = device.vkCreateDescriptorPool(descriptor_pool, null, scope);
+
+ VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
+ desc_pool,
+ 1,
+ layout_table);
+
+ device.vkAllocateDescriptorSets(alloc_info, desc_set);
+
+ VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size);
+ VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame,
+ desc_set.getAtIndex(0),
+ 0,
+ 0,
+ //1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ null,
+ uniformInfo,
+ null);
+
+ device.vkUpdateDescriptorSets(1, writes, 0, null);
+ }
+ }
+
+ void init_render() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
+
+ attachments.setFormat(chainImageFormat);
+ attachments.setSamples(NUM_SAMPLES);
+ attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ attachments.setFlags(0);
+
+ attachments.setFormatAtIndex(1, depthFormat);
+ attachments.setSamplesAtIndex(1, NUM_SAMPLES);
+ attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ attachments.setFlagsAtIndex(1, 0);
+
+ VkAttachmentReference color_reference = VkAttachmentReference.create(frame,
+ 0,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ VkAttachmentReference depth_reference = VkAttachmentReference.create(frame,
+ 1,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ VkSubpassDescription subpass = VkSubpassDescription.create(frame,
+ 0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ null,
+ color_reference,
+ null,
+ depth_reference,
+ null);
+
+ VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame,
+ 0,
+ //(int)attachments.length(),
+ attachments,
+ subpass,
+ null);
+
+ render_pass = device.vkCreateRenderPass(rp_info, null, scope);
+ }
+ }
+
+ void init_framebuffer() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
+
+ attachments.setAtIndex(1, depthView);
+
+ VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame,
+ 0,
+ render_pass,
+ 2,
+ attachments,
+ width,
+ height,
+ 1);
+
+ framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
+ for (int i = 0; i < chainImage.size(); i++) {
+ attachments.setAtIndex(0, chainImageView.get(i));
+ framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, null, scope));
+ System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
+ }
+ }
+ }
+
+ void init_vertexbuffer() throws Exception {
+ try (Frame frame = Frame.frame()) {
+ vertex = init_buffer(Cube.data.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(Cube.data));
+
+ vertexBuffer.setAtIndex(0, vertex.buffer);
+
+ /* ***************************************** */
+ vi_binding.setBinding(0);
+ vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
+ vi_binding.setStride(Cube.dataStride);
+
+ vi_attribs.setBinding(0);
+ vi_attribs.setLocation(0);
+ vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
+ vi_attribs.setOffset(0);
+ vi_attribs.setBindingAtIndex(1, 0);
+ vi_attribs.setLocationAtIndex(1, 1);
+ vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
+ vi_attribs.setOffsetAtIndex(1, 16);
+ }
+ }
+
+ void init_pipeline() throws Exception {
+ int res;
+ try (Frame frame = Frame.frame()) {
+ IntArray dynamicStateEnables = IntArray.create(frame,
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR);
+
+ VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame,
+ 0, dynamicStateEnables);
+
+ VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame,
+ 0,
+ vi_binding,
+ vi_attribs);
+
+ VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame,
+ 0,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ 0);
+
+ VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame,
+ 0,
+ VK_TRUE,
+ VK_FALSE,
+ VK_POLYGON_MODE_FILL,
+ VK_CULL_MODE_BACK_BIT,
+ VK_FRONT_FACE_CLOCKWISE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f);
+
+ VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame,
+ VK_FALSE,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ 0xf);
+
+ VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame,
+ 0,
+ VK_FALSE,
+ VK_LOGIC_OP_NO_OP,
+ att_state,
+ new float[] { 1.0f, 1.0f, 1.0f, 1.0f });
+
+ VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
+ 0,
+ //1, null,
+ //1, null);
+ null,
+ null);
+ // TODO: should just take counts
+ vp.setViewportCount(1);
+ vp.setScissorCount(1);
+
+
+ VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame,
+ 0,
+ VK_TRUE,
+ VK_TRUE,
+ VK_COMPARE_OP_LESS_OR_EQUAL,
+ VK_FALSE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f);
+ VkStencilOpState back = ds.getBack();
+
+ back.setFailOp(VK_STENCIL_OP_KEEP);
+ back.setPassOp(VK_STENCIL_OP_KEEP);
+ back.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ back.setCompareMask(0);
+ back.setReference(0);
+ back.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ back.setWriteMask(0);
+
+ VkStencilOpState front = ds.getFront();
+
+ front.setFailOp(VK_STENCIL_OP_KEEP);
+ front.setPassOp(VK_STENCIL_OP_KEEP);
+ front.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ front.setCompareMask(0);
+ front.setReference(0);
+ front.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ front.setWriteMask(0);
+
+ VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame,
+ 0,
+ NUM_SAMPLES,
+ 0, //.sampleShadingEnable = VK_FALSE,
+ 0.0f,
+ null,
+ 0, //.alphaToCoverageEnable = VK_FALSE,
+ 0 //.alphaToOneEnable = VK_FALSE,
+ );
+
+ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame,
+ 0,
+ cube_vs.length() * 4,
+ cube_vs);
+ VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame,
+ 0,
+ cube_fs.length() * 4,
+ cube_fs);
+
+ shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, null, scope));
+ shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, null, scope));
+
+ VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
+
+ shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+ shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
+ shaderStages.setName("main");
+ shaderStages.setModule(shader.get(0));
+
+ shaderStages.setSTypeAtIndex(1, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+ shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
+ shaderStages.setNameAtIndex(1, "main");
+ shaderStages.setModuleAtIndex(1, shader.get(1));
+
+ VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame,
+ 0,
+ //2, shaderStages,
+ shaderStages,
+ vi,
+ ia,
+ null,
+ vp,
+ rs,
+ ms,
+ ds,
+ cb,
+ dynamicState,
+ pipeline_layout,
+ render_pass,
+ 0,
+ null,
+ 0);
+
+ res = device.vkCreateGraphicsPipelines(null, 1, pipeline, null, this.pipeline);
+
+ VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
+ chainSemaphore = device.vkCreateSemaphore(seminfo, null, scope);
+
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
+ drawFence = device.vkCreateFence(fenceInfo, null, scope);
+ }
+ }
+
+
+ void execute_begin_command_buffer() throws Exception {
+ /* DEPENDS on init_command() */
+ try (Frame frame = Frame.frame()) {
+ VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame,
+ 0,
+ null);
+
+ cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
+ }
+ }
+
+ void execute_end_command_buffer() throws Exception {
+ cmd.getAtIndex(0).vkEndCommandBuffer();
+ }
+
+ final static long FENCE_TIMEOUT = 100000000;
+
+ void execute_queue_command_buffer() throws Exception {
+ int res;
+
+ /* Queue the command buffer for execution */
+ try (Frame frame = Frame.frame()) {
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, device.vkCreateFence(fenceInfo, null, scope));
+
+ // FIXME: why is this not autogenerating the length bits for all fields?
+ VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
+ null, pipe_stage_flags,
+ 1, cmd,
+ 0, null);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ do {
+ res = device.vkWaitForFences( 1, fences, 1, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ device.vkDestroyFence(fences.getAtIndex(0), null);
+ }
+ }
+
+ void cmd_viewport() {
+ try (Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkViewport viewport = VkViewport.create(frame,
+ 0, 0, width, height, 0.0f, 1.0f);
+ cmd.vkCmdSetViewport(0, 1, viewport);
+ }
+ }
+
+ void cmd_scissors() {
+ try (Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkRect2D scissor = VkRect2D.create(frame);
+ VkExtent2D extent = scissor.getExtent();
+
+ extent.setWidth(width);
+ extent.setHeight(height);
+
+ cmd.vkCmdSetScissor(0, 1, scissor);
+ }
+ }
+
+ void cmd_paint() throws Exception {
+ int res;
+ try (Frame frame = Frame.frame()) {
+ int chainIndex;
+ IntArray chainIndices = IntArray.createArray(1, frame);
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+
+ device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
+ chainIndex = chainIndices.getAtIndex(0);
+ LongArray offsets = LongArray.createArray(1, frame);
+
+ VkClearValue clear_values = VkClearValue.createArray(2, frame);
+ FloatArray col = clear_values.getColor().getFloat32();
+ col.setAtIndex(0, 0.2f);
+ col.setAtIndex(1, 0.2f);
+ col.setAtIndex(2, 0.2f);
+ col.setAtIndex(3, 0.2f);
+ VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
+ depthStencil.setDepth(1.0f);
+ depthStencil.setStencil(0);
+
+ System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
+
+ VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame,
+ render_pass,
+ framebuffers.getAtIndex(chainIndex),
+ clear_values);
+ VkExtent2D extent = rp_begin.getRenderArea().getExtent();
+ extent.setWidth(width);
+ extent.setHeight(height);
+
+ cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
+ cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
+ cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
+
+ cmd_viewport();
+ cmd_scissors();
+
+ cmd.vkCmdDraw(12 * 3, 1, 0, 0);
+ cmd.vkCmdEndRenderPass();
+
+ cmd.vkEndCommandBuffer();
+
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
+
+ semaphores.setAtIndex(0, chainSemaphore);
+
+ VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
+ semaphores, pipe_stage_flags,
+ 1, this.cmd,
+ 0, null);
+
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, drawFence);
+
+ // Queue the command buffer for execution
+ device.vkResetFences(1, fences);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ // Make sure command buffer is finished before presenting
+ do {
+ res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ // Now present the image in the window
+ HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
+ chains.setAtIndex(0, chain);
+ VkPresentInfoKHR present = VkPresentInfoKHR.create(frame,
+ 0, null,
+ chains,
+ chainIndices,
+ null);
+ // HACK: auto-set length is busted
+ present.setSwapchainCount(chains.size());
+
+ present_queue.vkQueuePresentKHR(present);
+ }
+ }
+
+ /**
+ * Buffers are created in three steps:
+ * 1) create buffer, specifying usage and size
+ * 2) allocate memory based on memory requirements
+ * 3) bind memory
+ *
+ */
+ BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
+ try (Frame frame = Frame.frame()) {
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame,
+ 0,
+ dataSize,
+ usage,
+ VK_SHARING_MODE_EXCLUSIVE,
+ //0,
+ null);
+
+ VkBuffer buffer = device.vkCreateBuffer(buf_info, null, scope);
+
+ device.vkGetBufferMemoryRequirements(buffer, req);
+
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), properties));
+
+ VkDeviceMemory memory = device.vkAllocateMemory(alloc, null, scope);
+
+ if (init != null) {
+ MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
+ mem.copyFrom(init);
+ device.vkUnmapMemory(memory);
+ }
+
+ device.vkBindBufferMemory(buffer, memory, 0);
+
+ return new BufferMemory(buffer, memory, dataSize);
+ }
+ }
+
+ void shutdown() {
+ device.vkDestroyFence(drawFence, null);
+ device.vkDestroySemaphore(chainSemaphore, null);
+
+ device.vkDestroyPipeline(pipeline.getAtIndex(0), null);
+ for (int i=0;i<shader.size();i++)
+ device.vkDestroyShaderModule(shader.getAtIndex(i), null);
+
+ vertex.free(device);
+ uniform.free(device);
+
+ for (int i=0;i<framebuffers.size();i++)
+ device.vkDestroyFramebuffer(framebuffers.getAtIndex(i), null);
+
+ device.vkDestroyRenderPass(render_pass, null);
+
+ device.vkDestroyDescriptorPool(desc_pool, null);
+ device.vkDestroyPipelineLayout(pipeline_layout, null);
+ device.vkDestroyDescriptorSetLayout(desc_layout, null);
+
+ device.vkDestroyImageView(depthView, null);
+ device.vkFreeMemory(depthMemory, null);
+ device.vkDestroyImage(depthImage, null);
+
+ for (int i = 0; i < chainImageView.size(); i++)
+ device.vkDestroyImageView(chainImageView.getAtIndex(i), null);
+
+ device.vkDestroySwapchainKHR(chain, null);
+
+ device.vkDestroyCommandPool(cmd_pool, null);
+ device.vkDestroyDevice(null);
+
+ instance.vkDestroySurfaceKHR(surface, null);
+
+ if (logger != null)
+ instance.vkDestroyDebugUtilsMessengerEXT(logger, null);
+ instance.vkDestroyInstance(null);
+ }
+
+ IntArray loadSPIRV0(String name) throws IOException {
+ // hmm any way to just load this directly?
+ try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+ ByteBuffer bb = ByteBuffer.allocateDirect(8192).order(ByteOrder.nativeOrder());
+ int length = Channels.newChannel(is).read(bb);
+
+ bb.position(0);
+ bb.limit(length);
+
+ return IntArray.create(MemorySegment.ofByteBuffer(bb));
+ }
+ }
+
+ IntArray loadSPIRV(String name) throws IOException {
+ try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+ MemorySegment seg = ((SegmentAllocator)scope).allocateArray(Memory.INT, 2048);
+ int length = Channels.newChannel(is).read(seg.asByteBuffer());
+
+ return IntArray.create(seg.asSlice(0, length));
+ }
+ }
+ IntArray loadSPIRV(String name, SegmentAllocator alloc) throws IOException {
+ try (InputStream is = TestCube.class.getResourceAsStream(name)) {
+ MemorySegment seg = alloc.allocateArray(Memory.INT, 2048);
+ int length = Channels.newChannel(is).read(seg.asByteBuffer());
+
+ return IntArray.create(seg.asSlice(0, length));
+ }
+ }
+
+ /**
+ * This finds the memory type index for the memory on a specific device.
+ */
+ static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
+ VkMemoryType mtypes = memory.getMemoryTypes();
+
+ for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
+ if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
+ return i;
+ }
+ return -1;
+ }
+
+ public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) {
+ return (variant << 29) | (major << 22) | (minor << 12) | patch;
+ }
+
+ static int clampi(int v, int min, int max) {
+ return v < min ? min : v < max ? v : max;
+ }
+
+ void init_matrices() {
+ float eye[] = new float[] {-5, 3, -10};
+ float centre[] = new float[] {0, 0, 0};
+ float up[] = new float[] {0, -1, 0};
+ float t0[] = new float[16], t1[] = new float[16];
+
+ perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
+ lookAt(view, eye, centre, up);
+ identity4f(model);
+ mult4x4f(t0, clip, projection);
+ mult4x4f(t1, t0, view);
+ mult4x4f(mvp, t1, model);
+ }
+
+ void demo() throws Exception {
+ cube_vs = loadSPIRV("cube_vs.bin");
+ cube_fs = loadSPIRV("cube_fs.bin");
+
+ init_matrices();
+
+ init_instance();
+ init_debug();
+
+ init_surface();
+ init_device();
+ init_device_queue();
+ init_command();
+ init_depth();
+ init_uniform();
+
+ init_descriptor();
+ init_render();
+ init_framebuffer();
+ init_vertexbuffer();
+ init_pipeline();
+
+ execute_begin_command_buffer();
+
+ cmd_paint();
+
+ System.out.println("behold the prize!");
+ Thread.sleep(2000);
+
+ shutdown();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ System.loadLibrary("vulkan");
+ System.loadLibrary("X11");
+
+ new TestCube().demo();
+ }
+}