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.
35 import au.notzed.display.Display;
36 import jdk.incubator.foreign.*;
37 import au.notzed.nativez.*;
40 import static vulkan.Vulkan.*;
42 import au.notzed.display.*;
43 import static vulkan.test.GLMaths.*;
45 public class TestCube {
47 static final boolean debug = true;
49 final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
50 final static int NUM_DESCRIPTOR_SETS = 1;
52 ResourceScope scope = ResourceScope.newSharedScope();
56 float projection[] = new float[16];
57 float view[] = new float[16];
58 float model[] = new float[16];
59 float clip[] = new float[]{
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, -1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 0.5f, 0.0f,
63 0.0f, 0.0f, 0.5f, 1.0f
65 float mvp[] = new float[16];
68 VkPhysicalDevice physicalDevice;
69 VkPhysicalDeviceMemoryProperties memory_properties;
70 VkPhysicalDeviceFeatures device_features;
72 int present_queue_index;
73 int graphics_queue_index;
78 VkQueue graphics_queue;
79 VkQueue present_queue;
82 HandleArray<VkImage> chainImage;
83 HandleArray<VkImageView> chainImageView;
87 VkImageView depthView;
88 VkDeviceMemory depthMemory;
90 VkCommandPool cmd_pool;
91 HandleArray<VkCommandBuffer> cmd;
94 VkPipelineLayout pipeline_layout;
96 VkDescriptorSetLayout desc_layout;
97 VkDescriptorPool desc_pool;
98 HandleArray<VkDescriptorSet> desc_set;
100 VkRenderPass render_pass;
101 HandleArray<VkFramebuffer> framebuffers;
104 HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
105 VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
106 VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(2, (SegmentAllocator)scope);
110 HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
112 HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
114 VkSemaphore chainSemaphore;
117 record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) {
119 public void free(VkDevice device) {
120 device.vkFreeMemory(memory);
121 device.vkDestroyBuffer(buffer);
125 VkDebugUtilsMessengerEXT logger;
127 void init_debug() throws Exception {
130 try ( Frame frame = Frame.frame()) {
131 var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
132 System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
135 VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(frame,
137 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
138 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
139 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
140 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
144 logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
147 //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
150 void init_instance() throws Exception {
151 try ( Frame frame = Frame.frame()) {
152 VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame,
154 VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_API_VERSION_1_0),
155 new String[]{"VK_LAYER_KHRONOS_validation"},
156 new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"}
159 instance = VkInstance.vkCreateInstance(info, scope);
160 System.out.printf("instance = %s\n", instance);
166 VkSurfaceKHR surface;
168 void init_surface() throws Exception {
169 display = Display.createX11Display();
170 window = display.createWindow(width, height);
171 surface = window.createVulkanSurface(instance, scope);
172 System.out.printf("surface: %s\n", surface);
175 void init_device() throws Exception {
176 try ( Frame frame = Frame.frame()) {
177 IntArray count$h = IntArray.create(frame, 1);
178 IntArray present$h = IntArray.create(frame, 1);
179 HandleArray<VkPhysicalDevice> devs;
183 devs = instance.vkEnumeratePhysicalDevices(frame, scope);
185 // Search for device and queue indices
187 int present_queue = -1;
188 int graphics_queue = -1;
189 for (int i = 0; i < devs.length(); i++) {
190 VkPhysicalDevice dev = devs.getAtIndex(i);
191 VkQueueFamilyProperties famprops;
193 famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
195 for (int j = 0; j < famprops.length(); j++) {
198 dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
199 present = present$h.get(0) != 0;
201 if (present && present_queue == -1)
203 if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
211 if (present_queue != -1 && graphics_queue != -1) {
218 throw new Exception("Cannot find a suitable device");
220 physicalDevice = devs.getAtIndex(devid);
221 present_queue_index = present_queue;
222 graphics_queue_index = graphics_queue;
225 memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
226 physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
227 device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
228 physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
230 FloatArray qpri = FloatArray.create(frame, 0.0f);
231 VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
236 String[] extensions = {
239 VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
240 features.setDepthClamp(1);
241 VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
249 device = physicalDevice.vkCreateDevice(devinfo, scope);
251 System.out.printf("device = %s\n", device);
253 /* ************************************************************** */
255 VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
256 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
257 // the surface has no preferred format. Otherwise, at least one
258 // supported format will be returned.
259 if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
260 format = VK_FORMAT_B8G8R8A8_UNORM;
262 format = surfFormats.getFormatAtIndex(0);
265 VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
267 physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
268 IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
270 VkExtent2D swapchainExtent;
271 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
272 if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
273 // If the surface size is undefined, the size is set to
274 // the size of the images requested.
275 swapchainExtent = VkExtent2D.create(frame,
276 clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
277 clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()));
279 // If the surface size is defined, the swap chain size must match
280 swapchainExtent = surfCapabilities.getCurrentExtent();
282 int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
283 int compositeAlphaFlags[] = {
284 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
285 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
286 VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
287 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,};
288 for (int flag: compositeAlphaFlags) {
289 if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
290 compositeAlpha = flag;
295 VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(frame,
298 surfCapabilities.getMinImageCount(),
300 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
301 1, //.imageArrayLayers = 1,
302 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
303 VK_SHARING_MODE_EXCLUSIVE,
304 // assumes queues are same.
306 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
307 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
309 VK_PRESENT_MODE_FIFO_KHR,
312 chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth());
313 chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight());
315 chain = device.vkCreateSwapchainKHR(chaininfo, scope);
319 chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
320 chainImageCount = (int)chainImage.length();
321 chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
323 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame,
326 VK_IMAGE_VIEW_TYPE_2D,
328 VkComponentMapping components = viewinfo.getComponents();
329 components.setR(VK_COMPONENT_SWIZZLE_R);
330 components.setG(VK_COMPONENT_SWIZZLE_G);
331 components.setB(VK_COMPONENT_SWIZZLE_B);
332 components.setA(VK_COMPONENT_SWIZZLE_A);
333 VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
334 subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
335 subresourceRange.setLevelCount(1);
336 subresourceRange.setLayerCount(1);
338 for (int i = 0; i < chainImageCount; i++) {
339 viewinfo.setImage(chainImage.get(i));
341 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
344 chainImageFormat = format;
348 void init_device_queue() {
349 graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
350 if (graphics_queue_index == present_queue_index) {
351 present_queue = graphics_queue;
353 present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
357 void init_command() throws Exception {
358 try ( Frame frame = Frame.frame()) {
359 VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame,
361 graphics_queue_index);
363 cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
365 VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
367 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
370 cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
374 // parameterise as init_image?
375 void init_depth() throws Exception {
376 try ( Frame frame = Frame.frame()) {
377 int format = VK_FORMAT_D16_UNORM;
378 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
379 VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0,
386 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
387 VK_SHARING_MODE_EXCLUSIVE,
389 VK_IMAGE_LAYOUT_UNDEFINED);
390 imageinfo.getExtent().setWidth(width);
391 imageinfo.getExtent().setHeight(height);
392 imageinfo.getExtent().setDepth(1);
394 depthImage = device.vkCreateImage(imageinfo, scope);
396 device.vkGetImageMemoryRequirements(depthImage, req);
397 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
399 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
401 depthMemory = device.vkAllocateMemory(alloc, scope);
403 device.vkBindImageMemory(depthImage, depthMemory, 0);
405 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0,
407 VK_IMAGE_VIEW_TYPE_2D,
408 VK_FORMAT_D16_UNORM);
410 VkComponentMapping components = viewinfo.getComponents();
411 components.setR(VK_COMPONENT_SWIZZLE_R);
412 components.setG(VK_COMPONENT_SWIZZLE_G);
413 components.setB(VK_COMPONENT_SWIZZLE_B);
414 components.setA(VK_COMPONENT_SWIZZLE_A);
415 VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
416 subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
417 subresourceRange.setLevelCount(1);
418 subresourceRange.setLayerCount(1);
420 depthView = device.vkCreateImageView(viewinfo, scope);
422 depthFormat = format;
426 void init_uniform() throws Exception {
427 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));
430 void init_descriptor() throws Exception {
431 try ( Frame frame = Frame.frame()) {
432 HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
433 VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame,
435 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
437 VK_SHADER_STAGE_VERTEX_BIT,
439 VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame,
443 desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
444 layout_table.setAtIndex(0, desc_layout);
446 VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
452 pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
454 VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame,
455 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
458 VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame,
463 desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
465 VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
470 System.out.println(alloc_info);
472 desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
474 VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size);
475 VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame,
476 desc_set.getAtIndex(0),
480 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
485 device.vkUpdateDescriptorSets(1, writes, 0, null);
489 void init_render() throws Exception {
490 try ( Frame frame = Frame.frame()) {
491 VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
493 attachments.setFormat(chainImageFormat);
494 attachments.setSamples(NUM_SAMPLES);
495 attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
496 attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
497 attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
498 attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
499 attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
500 attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
501 attachments.setFlags(0);
503 attachments.setFormatAtIndex(1, depthFormat);
504 attachments.setSamplesAtIndex(1, NUM_SAMPLES);
505 attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
506 attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
507 attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
508 attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
509 attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
510 attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
511 attachments.setFlagsAtIndex(1, 0);
513 VkAttachmentReference color_reference = VkAttachmentReference.create(frame,
515 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
517 VkAttachmentReference depth_reference = VkAttachmentReference.create(frame,
519 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
521 VkSubpassDescription subpass = VkSubpassDescription.create(frame,
523 VK_PIPELINE_BIND_POINT_GRAPHICS,
531 VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame,
533 //(int)attachments.length(),
538 render_pass = device.vkCreateRenderPass(rp_info, scope);
542 void init_framebuffer() throws Exception {
543 try ( Frame frame = Frame.frame()) {
544 HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
546 attachments.setAtIndex(1, depthView);
548 // FIXME: I don't think i want lenghts implied for types tbh
549 VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame,
558 framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
559 for (int i = 0; i < chainImage.size(); i++) {
560 attachments.setAtIndex(0, chainImageView.get(i));
561 framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
562 System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
567 void init_vertexbuffer() throws Exception {
568 try ( Frame frame = Frame.frame()) {
569 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));
571 vertexBuffer.setAtIndex(0, vertex.buffer);
573 /* ***************************************** */
574 vi_binding.setBinding(0);
575 vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
576 vi_binding.setStride(Cube.dataStride);
578 vi_attribs.setBinding(0);
579 vi_attribs.setLocation(0);
580 vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
581 vi_attribs.setOffset(0);
582 vi_attribs.setBindingAtIndex(1, 0);
583 vi_attribs.setLocationAtIndex(1, 1);
584 vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
585 vi_attribs.setOffsetAtIndex(1, 16);
589 void init_pipeline() throws Exception {
591 try ( Frame frame = Frame.frame()) {
592 IntArray dynamicStateEnables = IntArray.create(frame,
593 VK_DYNAMIC_STATE_VIEWPORT,
594 VK_DYNAMIC_STATE_SCISSOR);
596 VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame,
597 0, dynamicStateEnables);
599 VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame,
604 VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame,
606 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
609 VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame,
613 VK_POLYGON_MODE_FILL,
614 VK_CULL_MODE_BACK_BIT,
615 VK_FRONT_FACE_CLOCKWISE,
622 VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame,
624 VK_BLEND_FACTOR_ZERO,
625 VK_BLEND_FACTOR_ZERO,
627 VK_BLEND_FACTOR_ZERO,
628 VK_BLEND_FACTOR_ZERO,
632 VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame,
637 1.0f, 1.0f, 1.0f, 1.0f);
639 VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
644 VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame,
648 VK_COMPARE_OP_LESS_OR_EQUAL,
653 VkStencilOpState back = ds.getBack();
655 back.setFailOp(VK_STENCIL_OP_KEEP);
656 back.setPassOp(VK_STENCIL_OP_KEEP);
657 back.setCompareOp(VK_COMPARE_OP_ALWAYS);
658 back.setCompareMask(0);
659 back.setReference(0);
660 back.setDepthFailOp(VK_STENCIL_OP_KEEP);
661 back.setWriteMask(0);
663 VkStencilOpState front = ds.getFront();
665 front.setFailOp(VK_STENCIL_OP_KEEP);
666 front.setPassOp(VK_STENCIL_OP_KEEP);
667 front.setCompareOp(VK_COMPARE_OP_ALWAYS);
668 front.setCompareMask(0);
669 front.setReference(0);
670 front.setDepthFailOp(VK_STENCIL_OP_KEEP);
671 front.setWriteMask(0);
673 VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame,
676 0, //.sampleShadingEnable = VK_FALSE,
679 0, //.alphaToCoverageEnable = VK_FALSE,
680 0 //.alphaToOneEnable = VK_FALSE,
683 VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame,
685 cube_vs.length() * 4,
687 VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame,
689 cube_fs.length() * 4,
692 shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
693 shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
695 VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
697 // FIXME: createArray should initialise this
698 shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
699 shaderStages.setName("main", (SegmentAllocator)scope);
700 shaderStages.setModule(shader.get(0));
702 shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
703 shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
704 shaderStages.setModuleAtIndex(1, shader.get(1));
706 VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame,
725 res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
727 VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
728 chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
730 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
731 drawFence = device.vkCreateFence(fenceInfo, scope);
735 void execute_begin_command_buffer() throws Exception {
736 /* DEPENDS on init_command() */
737 try ( Frame frame = Frame.frame()) {
738 VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame,
742 cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
746 void execute_end_command_buffer() throws Exception {
747 cmd.getAtIndex(0).vkEndCommandBuffer();
750 final static long FENCE_TIMEOUT = 100000000;
752 void execute_queue_command_buffer() throws Exception {
755 /* Queue the command buffer for execution */
756 /* FIXME: frame shoudl provide or take explicit scope */
757 try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) {
758 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
759 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
760 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
762 fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
764 VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
765 1, null, pipe_stage_flags,
769 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
772 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
773 } while (res == VK_TIMEOUT);
775 device.vkDestroyFence(fences.getAtIndex(0));
779 void cmd_viewport() {
780 try ( Frame frame = Frame.frame()) {
781 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
782 VkViewport viewport = VkViewport.create(frame,
783 0, 0, width, height, 0.0f, 1.0f);
784 cmd.vkCmdSetViewport(0, 1, viewport);
788 void cmd_scissors() {
789 try ( Frame frame = Frame.frame()) {
790 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
791 VkRect2D scissor = VkRect2D.create(frame);
792 VkExtent2D extent = scissor.getExtent();
794 extent.setWidth(width);
795 extent.setHeight(height);
797 cmd.vkCmdSetScissor(0, 1, scissor);
801 void cmd_paint() throws Exception {
803 try ( Frame frame = Frame.frame()) {
805 IntArray chainIndices = IntArray.createArray(1, frame);
806 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
808 device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
809 chainIndex = chainIndices.getAtIndex(0);
810 LongArray offsets = LongArray.createArray(1, frame);
812 VkClearValue clear_values = VkClearValue.createArray(2, frame);
813 FloatArray col = clear_values.getColor().getFloat32();
814 col.setAtIndex(0, 0.2f);
815 col.setAtIndex(1, 0.2f);
816 col.setAtIndex(2, 0.2f);
817 col.setAtIndex(3, 0.2f);
818 VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
819 depthStencil.setDepth(1.0f);
820 depthStencil.setStencil(0);
822 System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
824 VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame,
826 framebuffers.getAtIndex(chainIndex),
828 VkExtent2D extent = rp_begin.getRenderArea().getExtent();
829 extent.setWidth(width);
830 extent.setHeight(height);
832 cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
834 cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
835 cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
836 cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
841 cmd.vkCmdDraw(12 * 3, 1, 0, 0);
842 cmd.vkCmdEndRenderPass();
844 cmd.vkEndCommandBuffer();
846 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
847 HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
849 semaphores.setAtIndex(0, chainSemaphore);
851 VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
852 1, semaphores, pipe_stage_flags,
856 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
858 fences.setAtIndex(0, drawFence);
860 // Queue the command buffer for execution
861 device.vkResetFences(1, fences);
863 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
865 // Make sure command buffer is finished before presenting
867 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
868 } while (res == VK_TIMEOUT);
870 // Now present the image in the window
871 HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
872 chains.setAtIndex(0, chain);
873 VkPresentInfoKHR present = VkPresentInfoKHR.create(frame,
880 present_queue.vkQueuePresentKHR(present);
885 * Buffers are created in three steps:
886 * 1) create buffer, specifying usage and size
887 * 2) allocate memory based on memory requirements
891 BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
892 try ( Frame frame = Frame.frame()) {
893 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
894 VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame,
898 VK_SHARING_MODE_EXCLUSIVE,
902 VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
904 device.vkGetBufferMemoryRequirements(buffer, req);
906 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
908 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties));
910 VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
913 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
915 device.vkUnmapMemory(memory);
918 device.vkBindBufferMemory(buffer, memory, 0);
920 return new BufferMemory(buffer, memory, dataSize);
925 device.vkDestroyFence(drawFence);
926 device.vkDestroySemaphore(chainSemaphore);
928 device.vkDestroyPipeline(pipeline.getAtIndex(0));
929 for (int i = 0; i < shader.size(); i++)
930 device.vkDestroyShaderModule(shader.getAtIndex(i));
933 uniform.free(device);
935 for (int i = 0; i < framebuffers.size(); i++)
936 device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
938 device.vkDestroyRenderPass(render_pass);
940 device.vkDestroyDescriptorPool(desc_pool);
941 device.vkDestroyPipelineLayout(pipeline_layout);
942 device.vkDestroyDescriptorSetLayout(desc_layout);
944 device.vkDestroyImageView(depthView);
945 device.vkFreeMemory(depthMemory);
946 device.vkDestroyImage(depthImage);
948 for (int i = 0; i < chainImageView.size(); i++)
949 device.vkDestroyImageView(chainImageView.getAtIndex(i));
951 device.vkDestroySwapchainKHR(chain);
953 device.vkDestroyCommandPool(cmd_pool);
954 device.vkDestroyDevice();
956 instance.vkDestroySurfaceKHR(surface);
961 instance.vkDestroyDebugUtilsMessengerEXT(logger);
962 instance.vkDestroyInstance();
966 * This finds the memory type index for the memory on a specific device.
968 static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
969 VkMemoryType mtypes = memory.getMemoryTypes();
971 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
972 if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
978 static int clampi(int v, int min, int max) {
979 return v < min ? min : v < max ? v : max;
982 void init_matrices() {
983 float eye[] = new float[]{-5, 3, -10};
984 float centre[] = new float[]{0, 0, 0};
985 float up[] = new float[]{0, -1, 0};
986 float t0[] = new float[16], t1[] = new float[16];
988 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
989 lookAt(view, eye, centre, up);
991 mult4x4f(t0, clip, projection);
992 mult4x4f(t1, t0, view);
993 mult4x4f(mvp, t1, model);
996 void demo() throws Exception {
997 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
998 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
1007 init_device_queue();
1015 init_vertexbuffer();
1018 execute_begin_command_buffer();
1022 System.out.println("Any key to quit");
1024 outer: while ((e = window.nextEvent(true)) != null) {
1035 public static void main(String[] args) throws Throwable {
1036 System.loadLibrary("vulkan");
1037 System.loadLibrary("X11");
1039 new TestCube().demo();