4 Copyright (C) 2017 Eric Arnebäck
5 Copyright (C) 2019 Michael Zucchi
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 * This is a Java conversion of a C conversion of this:
29 * https://github.com/Erkaman/vulkan_minimal_compute
31 * It's been simplified a bit and converted to the 'zvk' api.
36 import java.io.InputStream;
37 import java.io.FileOutputStream;
38 import java.io.IOException;
39 import java.nio.channels.Channels;
40 import java.nio.ByteBuffer;
41 import java.nio.ByteOrder;
43 import java.awt.Graphics;
44 import java.awt.Image;
45 import java.awt.Toolkit;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.KeyEvent;
48 import java.awt.image.MemoryImageSource;
49 import javax.swing.AbstractAction;
50 import javax.swing.JComponent;
51 import javax.swing.JFrame;
52 import javax.swing.JPanel;
53 import javax.swing.KeyStroke;
55 import java.lang.ref.WeakReference;
56 import java.util.List;
57 import java.util.Collections;
59 import java.lang.invoke.*;
60 import jdk.incubator.foreign.*;
61 import jdk.incubator.foreign.MemoryLayout.PathElement;
62 import au.notzed.nativez.*;
65 import static vulkan.VkConstants.*;
68 import static xlib.XLib.*;
69 import static vulkan.test.GLMaths.*;
71 public class TestCube {
72 static final boolean debug = true;
74 final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
75 final static int NUM_DESCRIPTOR_SETS = 1;
77 ResourceScope scope = ResourceScope.newSharedScope();
81 float projection[] = new float[16];
82 float view[] = new float[16];
83 float model[] = new float[16];
84 float clip[] = new float[] {
85 1.0f, 0.0f, 0.0f, 0.0f,
86 0.0f, -1.0f, 0.0f, 0.0f,
87 0.0f, 0.0f, 0.5f, 0.0f,
88 0.0f, 0.0f, 0.5f, 1.0f
90 float mvp[] = new float[16];
93 VkPhysicalDevice physicalDevice;
94 VkPhysicalDeviceMemoryProperties memory_properties;
95 VkPhysicalDeviceFeatures device_features;
97 int present_queue_index;
98 int graphics_queue_index;
101 VkSwapchainKHR chain;
103 VkQueue graphics_queue;
104 VkQueue present_queue;
106 int chainImageFormat;
107 HandleArray<VkImage> chainImage;
108 HandleArray<VkImageView> chainImageView;
112 VkImageView depthView;
113 VkDeviceMemory depthMemory;
115 VkCommandPool cmd_pool;
116 HandleArray<VkCommandBuffer> cmd;
118 BufferMemory uniform;
119 VkPipelineLayout pipeline_layout;
121 VkDescriptorSetLayout desc_layout;
122 VkDescriptorPool desc_pool;
123 HandleArray<VkDescriptorSet> desc_set;
126 VkRenderPass render_pass;
127 HandleArray<VkFramebuffer> framebuffers;
130 HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
131 VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
132 VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(2, (SegmentAllocator)scope);
136 HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
138 HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
140 VkSemaphore chainSemaphore;
143 record BufferMemory (VkBuffer buffer, VkDeviceMemory memory, long size) {
144 public void free(VkDevice device) {
145 device.vkFreeMemory(memory);
146 device.vkDestroyBuffer(buffer);
150 VkDebugUtilsMessengerEXT logger;
152 void init_debug() throws Exception {
155 try (Frame frame = Frame.frame()) {
156 var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
157 System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
160 VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame,
162 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
163 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
164 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
165 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
169 logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
172 //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
176 void init_instance() throws Exception {
177 try (Frame frame = Frame.frame()) {
178 VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame,
180 VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_MAKE_API_VERSION(0, 1, 0, 0)),
181 new String[] { "VK_LAYER_KHRONOS_validation" },
182 new String[] { "VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils" }
185 instance = VkInstance.vkCreateInstance(info, scope);
186 System.out.printf("instance = %s\n", instance);
192 long wm_delete_window;
193 VkSurfaceKHR surface;
195 void init_surface() throws Exception {
196 try (Frame frame = Frame.frame()) {
198 display = XOpenDisplay(null);
199 long visualMask = VisualScreenMask;
200 IntArray numberOfVisuals = IntArray.createArray(1, frame);
201 XVisualInfo vInfoTemplate = XVisualInfo.create(frame);
203 vInfoTemplate.setScreen(DefaultScreen(display));
205 XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals);
206 long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone);
208 XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame);
210 windowAttributes.setColormap(colormap);
211 windowAttributes.setBackgroundPixel(0xffffffff);
212 windowAttributes.setBorderPixel(0);
213 windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask);
215 window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()),
217 0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(),
218 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, windowAttributes);
220 XSelectInput(display, window, ExposureMask | KeyPressMask);
221 XMapWindow(display, window);
223 wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
225 VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(frame,
230 surface = instance.vkCreateXlibSurfaceKHR(surfaceinfo, scope);
231 System.out.printf("surface: %s\n", surface);
235 void init_device() throws Exception {
236 try (Frame frame = Frame.frame()) {
237 IntArray count$h = IntArray.create(frame, 1);
238 IntArray present$h = IntArray.create(frame, 1);
239 HandleArray<VkPhysicalDevice> devs;
243 devs = instance.vkEnumeratePhysicalDevices(frame, scope);
245 // Search for device and queue indices
247 int present_queue = -1;
248 int graphics_queue = -1;
249 for (int i = 0; i < devs.length(); i++) {
250 VkPhysicalDevice dev = devs.getAtIndex(i);
251 VkQueueFamilyProperties famprops;
253 famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
255 for (int j = 0; j < famprops.length(); j++) {
258 dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
259 present = present$h.get(0) != 0;
261 if (present && present_queue == -1)
263 if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
271 if (present_queue != -1 && graphics_queue != -1) {
278 throw new Exception("Cannot find a suitable device");
280 physicalDevice = devs.getAtIndex(devid);
281 present_queue_index = present_queue;
282 graphics_queue_index = graphics_queue;
285 memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
286 physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
287 device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
288 physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
290 FloatArray qpri = FloatArray.create(frame, 0.0f);
291 VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
296 String [] extensions = {
299 VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
300 features.setDepthClamp(1);
301 VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
309 device = physicalDevice.vkCreateDevice(devinfo, scope);
311 System.out.printf("device = %s\n", device);
313 /* ************************************************************** */
315 VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
316 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
317 // the surface has no preferred format. Otherwise, at least one
318 // supported format will be returned.
319 if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
320 format = VK_FORMAT_B8G8R8A8_UNORM;
322 format = surfFormats.getFormatAtIndex(0);
325 VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
327 physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
328 IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
330 VkExtent2D swapchainExtent;
331 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
332 if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
333 // If the surface size is undefined, the size is set to
334 // the size of the images requested.
335 swapchainExtent = VkExtent2D.create(frame,
336 clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
337 clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()));
339 // If the surface size is defined, the swap chain size must match
340 swapchainExtent = surfCapabilities.getCurrentExtent();
342 int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
343 int compositeAlphaFlags[] = {
344 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
345 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
346 VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
347 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
349 for (int flag: compositeAlphaFlags) {
350 if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
351 compositeAlpha = flag;
356 VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(frame,
359 surfCapabilities.getMinImageCount(),
361 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
362 1, //.imageArrayLayers = 1,
363 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
364 VK_SHARING_MODE_EXCLUSIVE,
365 // assumes queues are same.
367 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
368 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
370 VK_PRESENT_MODE_FIFO_KHR,
373 chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth());
374 chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight());
376 chain = device.vkCreateSwapchainKHR(chaininfo, scope);
380 chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
381 chainImageCount = (int)chainImage.length();
382 chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
384 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame,
387 VK_IMAGE_VIEW_TYPE_2D,
389 VkComponentMapping components = viewinfo.getComponents();
390 components.setR(VK_COMPONENT_SWIZZLE_R);
391 components.setG(VK_COMPONENT_SWIZZLE_G);
392 components.setB(VK_COMPONENT_SWIZZLE_B);
393 components.setA(VK_COMPONENT_SWIZZLE_A);
394 VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
395 subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
396 subresourceRange.setLevelCount(1);
397 subresourceRange.setLayerCount(1);
399 for (int i = 0; i < chainImageCount; i++) {
400 viewinfo.setImage(chainImage.get(i));
402 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
405 chainImageFormat = format;
409 void init_device_queue() {
410 graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
411 if (graphics_queue_index == present_queue_index) {
412 present_queue = graphics_queue;
414 present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
418 void init_command() throws Exception {
419 try (Frame frame = Frame.frame()) {
420 VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame,
422 graphics_queue_index);
424 cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
426 VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
428 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
431 cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
435 // parameterise as init_image?
436 void init_depth() throws Exception {
437 try (Frame frame = Frame.frame()) {
438 int format = VK_FORMAT_D16_UNORM;
439 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
440 VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0,
447 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
448 VK_SHARING_MODE_EXCLUSIVE,
450 VK_IMAGE_LAYOUT_UNDEFINED);
451 imageinfo.getExtent().setWidth(width);
452 imageinfo.getExtent().setHeight(height);
453 imageinfo.getExtent().setDepth(1);
455 depthImage = device.vkCreateImage(imageinfo, scope);
457 device.vkGetImageMemoryRequirements(depthImage, req);
458 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
460 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
462 depthMemory = device.vkAllocateMemory(alloc, scope);
464 device.vkBindImageMemory(depthImage, depthMemory, 0);
466 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0,
468 VK_IMAGE_VIEW_TYPE_2D,
469 VK_FORMAT_D16_UNORM);
471 VkComponentMapping components = viewinfo.getComponents();
472 components.setR(VK_COMPONENT_SWIZZLE_R);
473 components.setG(VK_COMPONENT_SWIZZLE_G);
474 components.setB(VK_COMPONENT_SWIZZLE_B);
475 components.setA(VK_COMPONENT_SWIZZLE_A);
476 VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
477 subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
478 subresourceRange.setLevelCount(1);
479 subresourceRange.setLayerCount(1);
481 depthView = device.vkCreateImageView(viewinfo, scope);
483 depthFormat = format;
487 void init_uniform() throws Exception {
488 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));
491 void init_descriptor() throws Exception {
492 try (Frame frame = Frame.frame()) {
493 HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
494 VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame,
496 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
498 VK_SHADER_STAGE_VERTEX_BIT,
500 VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame,
504 desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
505 layout_table.setAtIndex(0, desc_layout);
507 VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
513 pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
515 VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame,
516 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
519 VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame,
524 desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
526 VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
531 System.out.println(alloc_info);
533 desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
535 VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size);
536 VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame,
537 desc_set.getAtIndex(0),
541 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
546 device.vkUpdateDescriptorSets(writes, null);
550 void init_render() throws Exception {
551 try (Frame frame = Frame.frame()) {
552 VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
554 attachments.setFormat(chainImageFormat);
555 attachments.setSamples(NUM_SAMPLES);
556 attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
557 attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
558 attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
559 attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
560 attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
561 attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
562 attachments.setFlags(0);
564 attachments.setFormatAtIndex(1, depthFormat);
565 attachments.setSamplesAtIndex(1, NUM_SAMPLES);
566 attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
567 attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
568 attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
569 attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
570 attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
571 attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
572 attachments.setFlagsAtIndex(1, 0);
574 VkAttachmentReference color_reference = VkAttachmentReference.create(frame,
576 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
578 VkAttachmentReference depth_reference = VkAttachmentReference.create(frame,
580 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
582 VkSubpassDescription subpass = VkSubpassDescription.create(frame,
584 VK_PIPELINE_BIND_POINT_GRAPHICS,
592 VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame,
594 //(int)attachments.length(),
599 render_pass = device.vkCreateRenderPass(rp_info, scope);
603 void init_framebuffer() throws Exception {
604 try (Frame frame = Frame.frame()) {
605 HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
607 attachments.setAtIndex(1, depthView);
609 // FIXME: I don't think i want lenghts implied for types tbh
610 VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame,
619 framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
620 for (int i = 0; i < chainImage.size(); i++) {
621 attachments.setAtIndex(0, chainImageView.get(i));
622 framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
623 System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
628 void init_vertexbuffer() throws Exception {
629 try (Frame frame = Frame.frame()) {
630 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));
632 vertexBuffer.setAtIndex(0, vertex.buffer);
634 /* ***************************************** */
635 vi_binding.setBinding(0);
636 vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
637 vi_binding.setStride(Cube.dataStride);
639 vi_attribs.setBinding(0);
640 vi_attribs.setLocation(0);
641 vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
642 vi_attribs.setOffset(0);
643 vi_attribs.setBindingAtIndex(1, 0);
644 vi_attribs.setLocationAtIndex(1, 1);
645 vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
646 vi_attribs.setOffsetAtIndex(1, 16);
650 void init_pipeline() throws Exception {
652 try (Frame frame = Frame.frame()) {
653 IntArray dynamicStateEnables = IntArray.create(frame,
654 VK_DYNAMIC_STATE_VIEWPORT,
655 VK_DYNAMIC_STATE_SCISSOR);
657 VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame,
658 0, dynamicStateEnables);
660 VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame,
665 VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame,
667 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
670 VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame,
674 VK_POLYGON_MODE_FILL,
675 VK_CULL_MODE_BACK_BIT,
676 VK_FRONT_FACE_CLOCKWISE,
683 VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame,
685 VK_BLEND_FACTOR_ZERO,
686 VK_BLEND_FACTOR_ZERO,
688 VK_BLEND_FACTOR_ZERO,
689 VK_BLEND_FACTOR_ZERO,
693 VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame,
698 1.0f, 1.0f, 1.0f, 1.0f);
700 VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
705 VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame,
709 VK_COMPARE_OP_LESS_OR_EQUAL,
714 VkStencilOpState back = ds.getBack();
716 back.setFailOp(VK_STENCIL_OP_KEEP);
717 back.setPassOp(VK_STENCIL_OP_KEEP);
718 back.setCompareOp(VK_COMPARE_OP_ALWAYS);
719 back.setCompareMask(0);
720 back.setReference(0);
721 back.setDepthFailOp(VK_STENCIL_OP_KEEP);
722 back.setWriteMask(0);
724 VkStencilOpState front = ds.getFront();
726 front.setFailOp(VK_STENCIL_OP_KEEP);
727 front.setPassOp(VK_STENCIL_OP_KEEP);
728 front.setCompareOp(VK_COMPARE_OP_ALWAYS);
729 front.setCompareMask(0);
730 front.setReference(0);
731 front.setDepthFailOp(VK_STENCIL_OP_KEEP);
732 front.setWriteMask(0);
734 VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame,
737 0, //.sampleShadingEnable = VK_FALSE,
740 0, //.alphaToCoverageEnable = VK_FALSE,
741 0 //.alphaToOneEnable = VK_FALSE,
744 VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame,
746 cube_vs.length() * 4,
748 VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame,
750 cube_fs.length() * 4,
753 shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
754 shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
756 VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
758 // FIXME: createArray should initialise this
759 shaderStages.setSType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
760 shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
761 shaderStages.setName("main", (SegmentAllocator)scope);
762 shaderStages.setModule(shader.get(0));
764 shaderStages.setSTypeAtIndex(1, VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
765 shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
766 shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
767 shaderStages.setModuleAtIndex(1, shader.get(1));
769 VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame,
788 res = device.vkCreateGraphicsPipelines(null, pipeline, this.pipeline);
790 VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
791 chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
793 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
794 drawFence = device.vkCreateFence(fenceInfo, scope);
799 void execute_begin_command_buffer() throws Exception {
800 /* DEPENDS on init_command() */
801 try (Frame frame = Frame.frame()) {
802 VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame,
806 cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
810 void execute_end_command_buffer() throws Exception {
811 cmd.getAtIndex(0).vkEndCommandBuffer();
814 final static long FENCE_TIMEOUT = 100000000;
816 void execute_queue_command_buffer() throws Exception {
819 /* Queue the command buffer for execution */
820 /* FIXME: frame shoudl provide or take explicit scope */
821 try (ResourceScope scope = ResourceScope.newConfinedScope();
822 Frame frame = Frame.frame()) {
823 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
824 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
825 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
827 fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
829 VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
830 1, null, pipe_stage_flags,
834 graphics_queue.vkQueueSubmit(submit_info, drawFence);
837 res = device.vkWaitForFences(fences, 1, FENCE_TIMEOUT);
838 } while (res == VK_TIMEOUT);
840 device.vkDestroyFence(fences.getAtIndex(0));
844 void cmd_viewport() {
845 try (Frame frame = Frame.frame()) {
846 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
847 VkViewport viewport = VkViewport.create(frame,
848 0, 0, width, height, 0.0f, 1.0f);
849 cmd.vkCmdSetViewport(0, 1, viewport);
853 void cmd_scissors() {
854 try (Frame frame = Frame.frame()) {
855 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
856 VkRect2D scissor = VkRect2D.create(frame);
857 VkExtent2D extent = scissor.getExtent();
859 extent.setWidth(width);
860 extent.setHeight(height);
862 cmd.vkCmdSetScissor(0, 1, scissor);
866 void cmd_paint() throws Exception {
868 try (Frame frame = Frame.frame()) {
870 IntArray chainIndices = IntArray.createArray(1, frame);
871 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
873 device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
874 chainIndex = chainIndices.getAtIndex(0);
875 LongArray offsets = LongArray.createArray(1, frame);
877 VkClearValue clear_values = VkClearValue.createArray(2, frame);
878 FloatArray col = clear_values.getColor().getFloat32();
879 col.setAtIndex(0, 0.2f);
880 col.setAtIndex(1, 0.2f);
881 col.setAtIndex(2, 0.2f);
882 col.setAtIndex(3, 0.2f);
883 VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
884 depthStencil.setDepth(1.0f);
885 depthStencil.setStencil(0);
887 System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
889 VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame,
891 framebuffers.getAtIndex(chainIndex),
893 VkExtent2D extent = rp_begin.getRenderArea().getExtent();
894 extent.setWidth(width);
895 extent.setHeight(height);
897 cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
899 cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
900 cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
901 cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
906 cmd.vkCmdDraw(12 * 3, 1, 0, 0);
907 cmd.vkCmdEndRenderPass();
909 cmd.vkEndCommandBuffer();
911 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
912 HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
914 semaphores.setAtIndex(0, chainSemaphore);
916 VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
917 1, semaphores, pipe_stage_flags,
921 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
923 fences.setAtIndex(0, drawFence);
925 // Queue the command buffer for execution
926 device.vkResetFences(fences);
928 graphics_queue.vkQueueSubmit(submit_info, drawFence);
930 // Make sure command buffer is finished before presenting
932 res = device.vkWaitForFences(fences, VK_TRUE, FENCE_TIMEOUT);
933 } while (res == VK_TIMEOUT);
935 // Now present the image in the window
936 HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
937 chains.setAtIndex(0, chain);
938 VkPresentInfoKHR present = VkPresentInfoKHR.create(frame,
945 present_queue.vkQueuePresentKHR(present);
950 * Buffers are created in three steps:
951 * 1) create buffer, specifying usage and size
952 * 2) allocate memory based on memory requirements
956 BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
957 try (Frame frame = Frame.frame()) {
958 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
959 VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame,
963 VK_SHARING_MODE_EXCLUSIVE,
967 VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
969 device.vkGetBufferMemoryRequirements(buffer, req);
971 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
973 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties));
975 VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
978 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
980 device.vkUnmapMemory(memory);
983 device.vkBindBufferMemory(buffer, memory, 0);
985 return new BufferMemory(buffer, memory, dataSize);
990 device.vkDestroyFence(drawFence);
991 device.vkDestroySemaphore(chainSemaphore);
993 device.vkDestroyPipeline(pipeline.getAtIndex(0));
994 for (int i=0;i<shader.size();i++)
995 device.vkDestroyShaderModule(shader.getAtIndex(i));
998 uniform.free(device);
1000 for (int i=0;i<framebuffers.size();i++)
1001 device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
1003 device.vkDestroyRenderPass(render_pass);
1005 device.vkDestroyDescriptorPool(desc_pool);
1006 device.vkDestroyPipelineLayout(pipeline_layout);
1007 device.vkDestroyDescriptorSetLayout(desc_layout);
1009 device.vkDestroyImageView(depthView);
1010 device.vkFreeMemory(depthMemory);
1011 device.vkDestroyImage(depthImage);
1013 for (int i = 0; i < chainImageView.size(); i++)
1014 device.vkDestroyImageView(chainImageView.getAtIndex(i));
1016 device.vkDestroySwapchainKHR(chain);
1018 device.vkDestroyCommandPool(cmd_pool);
1019 device.vkDestroyDevice();
1021 instance.vkDestroySurfaceKHR(surface);
1024 instance.vkDestroyDebugUtilsMessengerEXT(logger);
1025 instance.vkDestroyInstance();
1028 IntArray loadSPIRV0(String name) throws IOException {
1029 // hmm any way to just load this directly?
1030 try (InputStream is = TestCube.class.getResourceAsStream(name)) {
1031 ByteBuffer bb = ByteBuffer.allocateDirect(8192).order(ByteOrder.nativeOrder());
1032 int length = Channels.newChannel(is).read(bb);
1037 return IntArray.create(MemorySegment.ofByteBuffer(bb));
1041 IntArray loadSPIRV(String name) throws IOException {
1042 try (InputStream is = TestCube.class.getResourceAsStream(name)) {
1043 MemorySegment seg = ((SegmentAllocator)scope).allocateArray(Memory.INT, 2048);
1044 int length = Channels.newChannel(is).read(seg.asByteBuffer());
1046 return IntArray.create(seg.asSlice(0, length));
1049 IntArray loadSPIRV(String name, SegmentAllocator alloc) throws IOException {
1050 try (InputStream is = TestCube.class.getResourceAsStream(name)) {
1051 MemorySegment seg = alloc.allocateArray(Memory.INT, 2048);
1052 int length = Channels.newChannel(is).read(seg.asByteBuffer());
1054 return IntArray.create(seg.asSlice(0, length));
1059 * This finds the memory type index for the memory on a specific device.
1061 static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
1062 VkMemoryType mtypes = memory.getMemoryTypes();
1064 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
1065 if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
1071 public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) {
1072 return (variant << 29) | (major << 22) | (minor << 12) | patch;
1075 static int clampi(int v, int min, int max) {
1076 return v < min ? min : v < max ? v : max;
1079 void init_matrices() {
1080 float eye[] = new float[] {-5, 3, -10};
1081 float centre[] = new float[] {0, 0, 0};
1082 float up[] = new float[] {0, -1, 0};
1083 float t0[] = new float[16], t1[] = new float[16];
1085 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
1086 lookAt(view, eye, centre, up);
1088 mult4x4f(t0, clip, projection);
1089 mult4x4f(t1, t0, view);
1090 mult4x4f(mvp, t1, model);
1093 void demo() throws Exception {
1094 cube_vs = loadSPIRV("cube_vs.bin");
1095 cube_fs = loadSPIRV("cube_fs.bin");
1104 init_device_queue();
1112 init_vertexbuffer();
1115 execute_begin_command_buffer();
1119 System.out.println("behold the prize!");
1125 public static void main(String[] args) throws Throwable {
1126 System.loadLibrary("vulkan");
1127 System.loadLibrary("X11");
1129 new TestCube().demo();