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(
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,
145 logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
148 //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
151 void init_instance() throws Exception {
152 try ( Frame frame = Frame.frame()) {
153 VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
155 VkApplicationInfo.create("cube", 1, "cube-engine", 2, VK_API_VERSION_1_0, frame),
156 1, new String[]{"VK_LAYER_KHRONOS_validation"},
157 3, new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"},
161 instance = VkInstance.vkCreateInstance(info, scope);
162 System.out.printf("instance = %s\n", instance);
168 VkSurfaceKHR surface;
170 void init_surface() throws Exception {
171 display = Display.createX11Display();
172 window = display.createWindow(width, height);
173 surface = window.createVulkanSurface(instance, scope);
174 System.out.printf("surface: %s\n", surface);
177 void init_device() throws Exception {
178 try ( Frame frame = Frame.frame()) {
179 IntArray count$h = IntArray.create(frame, 1);
180 IntArray present$h = IntArray.create(frame, 1);
181 HandleArray<VkPhysicalDevice> devs;
185 devs = instance.vkEnumeratePhysicalDevices(frame, scope);
187 // Search for device and queue indices
189 int present_queue = -1;
190 int graphics_queue = -1;
191 for (int i = 0; i < devs.length(); i++) {
192 VkPhysicalDevice dev = devs.getAtIndex(i);
193 VkQueueFamilyProperties famprops;
195 famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
197 for (int j = 0; j < famprops.length(); j++) {
198 boolean present = dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface);
200 if (present && present_queue == -1)
202 if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
210 if (present_queue != -1 && graphics_queue != -1) {
217 throw new Exception("Cannot find a suitable device");
219 physicalDevice = devs.getAtIndex(devid);
220 present_queue_index = present_queue;
221 graphics_queue_index = graphics_queue;
224 memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
225 physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
226 device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
227 physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
229 FloatArray qpri = FloatArray.create(frame, 0.0f);
230 VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
235 String[] extensions = {
238 VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
239 features.setDepthClamp(1);
240 VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
244 extensions.length, extensions,
248 device = physicalDevice.vkCreateDevice(devinfo, scope);
250 System.out.printf("device = %s\n", device);
252 /* ************************************************************** */
254 VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
255 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
256 // the surface has no preferred format. Otherwise, at least one
257 // supported format will be returned.
258 if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
259 format = VK_FORMAT_B8G8R8A8_UNORM;
261 format = surfFormats.getFormatAtIndex(0);
264 VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
266 physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
267 IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
269 VkExtent2D swapchainExtent;
270 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
271 if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
272 // If the surface size is undefined, the size is set to
273 // the size of the images requested.
274 swapchainExtent = VkExtent2D.create(
275 clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
276 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(
298 surfCapabilities.getMinImageCount(),
300 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
301 swapchainExtent.getWidth(), swapchainExtent.getHeight(),
302 1, //.imageArrayLayers = 1,
303 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
304 VK_SHARING_MODE_EXCLUSIVE,
305 // assumes queues are same.
307 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
308 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
310 VK_PRESENT_MODE_FIFO_KHR,
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(
326 VK_IMAGE_VIEW_TYPE_2D,
329 viewinfo.getComponents().set(VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A);
330 viewinfo.getSubresourceRange().set(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
332 for (int i = 0; i < chainImageCount; i++) {
333 viewinfo.setImage(chainImage.get(i));
335 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
338 chainImageFormat = format;
342 void init_device_queue() {
343 graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
344 if (graphics_queue_index == present_queue_index) {
345 present_queue = graphics_queue;
347 present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
351 void init_command() throws Exception {
352 try ( Frame frame = Frame.frame()) {
353 VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
355 graphics_queue_index,
358 cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
360 VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
362 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
366 cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
370 // parameterise as init_image?
371 void init_depth() throws Exception {
372 try ( Frame frame = Frame.frame()) {
373 int format = VK_FORMAT_D16_UNORM;
374 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
375 VkImageCreateInfo imageinfo = VkImageCreateInfo.create(
384 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
385 VK_SHARING_MODE_EXCLUSIVE,
387 VK_IMAGE_LAYOUT_UNDEFINED,
390 depthImage = device.vkCreateImage(imageinfo, scope);
392 device.vkGetImageMemoryRequirements(depthImage, req);
393 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
395 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
398 depthMemory = device.vkAllocateMemory(alloc, scope);
400 device.vkBindImageMemory(depthImage, depthMemory, 0);
402 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
405 VK_IMAGE_VIEW_TYPE_2D,
408 viewinfo.getComponents().set(VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A);
409 viewinfo.getSubresourceRange().set(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
411 depthView = device.vkCreateImageView(viewinfo, scope);
412 depthFormat = format;
416 void init_uniform() throws Exception {
417 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));
420 void init_descriptor() throws Exception {
421 try ( Frame frame = Frame.frame()) {
422 HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
423 VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(
425 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
427 VK_SHADER_STAGE_VERTEX_BIT,
430 VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
435 desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
436 layout_table.setAtIndex(0, desc_layout);
438 VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
444 pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
446 VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
447 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
451 VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
457 desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
459 VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
464 System.out.println(alloc_info);
466 desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
468 VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
469 VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
470 desc_set.getAtIndex(0),
474 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
480 device.vkUpdateDescriptorSets(1, writes, 0, null);
484 void init_render() throws Exception {
485 try ( Frame frame = Frame.frame()) {
486 VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
488 attachments.setFormat(chainImageFormat);
489 attachments.setSamples(NUM_SAMPLES);
490 attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
491 attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
492 attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
493 attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
494 attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
495 attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
496 attachments.setFlags(0);
498 attachments.setFormatAtIndex(1, depthFormat);
499 attachments.setSamplesAtIndex(1, NUM_SAMPLES);
500 attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
501 attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
502 attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
503 attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
504 attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
505 attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
506 attachments.setFlagsAtIndex(1, 0);
508 VkAttachmentReference color_reference = VkAttachmentReference.create(
510 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
513 VkAttachmentReference depth_reference = VkAttachmentReference.create(
515 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
518 VkSubpassDescription subpass = VkSubpassDescription.create(
520 VK_PIPELINE_BIND_POINT_GRAPHICS,
528 VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
535 render_pass = device.vkCreateRenderPass(rp_info, scope);
539 void init_framebuffer() throws Exception {
540 try ( Frame frame = Frame.frame()) {
541 HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
543 attachments.setAtIndex(1, depthView);
545 VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
552 framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
553 for (int i = 0; i < chainImage.size(); i++) {
554 attachments.setAtIndex(0, chainImageView.get(i));
555 framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
556 System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
561 void init_vertexbuffer() throws Exception {
562 try ( Frame frame = Frame.frame()) {
563 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));
565 vertexBuffer.setAtIndex(0, vertex.buffer);
567 /* ***************************************** */
568 vi_binding.setBinding(0);
569 vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
570 vi_binding.setStride(Cube.dataStride);
572 vi_attribs.setBinding(0);
573 vi_attribs.setLocation(0);
574 vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
575 vi_attribs.setOffset(0);
576 vi_attribs.setBindingAtIndex(1, 0);
577 vi_attribs.setLocationAtIndex(1, 1);
578 vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
579 vi_attribs.setOffsetAtIndex(1, 16);
583 void init_pipeline() throws Exception {
585 try ( Frame frame = Frame.frame()) {
586 IntArray dynamicStateEnables = IntArray.create(frame,
587 VK_DYNAMIC_STATE_VIEWPORT,
588 VK_DYNAMIC_STATE_SCISSOR);
590 VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
592 2, dynamicStateEnables,
595 VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
597 (int)vi_binding.length(), vi_binding,
598 (int)vi_attribs.length(), vi_attribs,
601 VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
603 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
607 VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
611 VK_POLYGON_MODE_FILL,
612 VK_CULL_MODE_BACK_BIT,
613 VK_FRONT_FACE_CLOCKWISE,
621 VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
623 VK_BLEND_FACTOR_ZERO,
624 VK_BLEND_FACTOR_ZERO,
626 VK_BLEND_FACTOR_ZERO,
627 VK_BLEND_FACTOR_ZERO,
632 VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
637 1.0f, 1.0f, 1.0f, 1.0f,
640 VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
646 VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
650 VK_COMPARE_OP_LESS_OR_EQUAL,
656 VkStencilOpState back = ds.getBack();
658 back.setFailOp(VK_STENCIL_OP_KEEP);
659 back.setPassOp(VK_STENCIL_OP_KEEP);
660 back.setCompareOp(VK_COMPARE_OP_ALWAYS);
661 back.setCompareMask(0);
662 back.setReference(0);
663 back.setDepthFailOp(VK_STENCIL_OP_KEEP);
664 back.setWriteMask(0);
666 VkStencilOpState front = ds.getFront();
668 front.setFailOp(VK_STENCIL_OP_KEEP);
669 front.setPassOp(VK_STENCIL_OP_KEEP);
670 front.setCompareOp(VK_COMPARE_OP_ALWAYS);
671 front.setCompareMask(0);
672 front.setReference(0);
673 front.setDepthFailOp(VK_STENCIL_OP_KEEP);
674 front.setWriteMask(0);
676 VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
679 0, //.sampleShadingEnable = VK_FALSE,
682 0, //.alphaToCoverageEnable = VK_FALSE,
683 0, //.alphaToOneEnable = VK_FALSE,
687 VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
689 cube_vs.length() * 4,
692 VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
694 cube_fs.length() * 4,
698 shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
699 shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
701 VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
703 shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
704 shaderStages.setName("main", (SegmentAllocator)scope);
705 shaderStages.setModule(shader.get(0));
707 shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
708 shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
709 shaderStages.setModuleAtIndex(1, shader.get(1));
711 VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
730 res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
732 VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
733 chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
735 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
736 drawFence = device.vkCreateFence(fenceInfo, scope);
740 void execute_begin_command_buffer() throws Exception {
741 /* DEPENDS on init_command() */
742 try ( Frame frame = Frame.frame()) {
743 VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(
748 cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
752 void execute_end_command_buffer() throws Exception {
753 cmd.getAtIndex(0).vkEndCommandBuffer();
756 final static long FENCE_TIMEOUT = 100000000;
758 void execute_queue_command_buffer() throws Exception {
761 /* Queue the command buffer for execution */
762 /* FIXME: frame shoudl provide or take explicit scope */
763 try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) {
764 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
765 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
766 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
768 fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
770 VkSubmitInfo submit_info = VkSubmitInfo.create(
771 1, null, pipe_stage_flags,
772 (int)cmd.length(), cmd,
776 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
779 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
780 } while (res == VK_TIMEOUT);
782 device.vkDestroyFence(fences.getAtIndex(0));
786 void cmd_viewport() {
787 try ( Frame frame = Frame.frame()) {
788 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
789 VkViewport viewport = VkViewport.create(
790 0, 0, width, height, 0.0f, 1.0f,
792 cmd.vkCmdSetViewport(0, 1, viewport);
796 void cmd_scissors() {
797 try ( Frame frame = Frame.frame()) {
798 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
799 VkRect2D scissor = VkRect2D.create(0, 0, width, height, frame);
800 cmd.vkCmdSetScissor(0, 1, scissor);
804 void cmd_paint() throws Exception {
806 try ( Frame frame = Frame.frame()) {
808 IntArray chainIndices = IntArray.createArray(1, frame);
809 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
811 device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
812 chainIndex = chainIndices.getAtIndex(0);
813 LongArray offsets = LongArray.createArray(1, frame);
815 VkClearValue clear_values = VkClearValue.createArray(2, frame);
816 FloatArray col = clear_values.getColor().getFloat32();
817 col.setAtIndex(0, 0.2f);
818 col.setAtIndex(1, 0.2f);
819 col.setAtIndex(2, 0.2f);
820 col.setAtIndex(3, 0.2f);
821 VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
822 depthStencil.setDepth(1.0f);
823 depthStencil.setStencil(0);
825 System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
827 VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
829 framebuffers.getAtIndex(chainIndex),
834 cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
836 cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
837 cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
838 cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
843 cmd.vkCmdDraw(12 * 3, 1, 0, 0);
844 cmd.vkCmdEndRenderPass();
846 cmd.vkEndCommandBuffer();
848 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
849 HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
851 semaphores.setAtIndex(0, chainSemaphore);
853 VkSubmitInfo submit_info = VkSubmitInfo.create(
854 1, semaphores, pipe_stage_flags,
855 (int)this.cmd.length(), this.cmd,
859 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
861 fences.setAtIndex(0, drawFence);
863 // Queue the command buffer for execution
864 device.vkResetFences(1, fences);
866 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
868 // Make sure command buffer is finished before presenting
870 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
871 } while (res == VK_TIMEOUT);
873 // Now present the image in the window
874 HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
875 chains.setAtIndex(0, chain);
876 VkPresentInfoKHR present = VkPresentInfoKHR.create(
878 1, chains, chainIndices, null,
881 present_queue.vkQueuePresentKHR(present);
886 * Buffers are created in three steps:
887 * 1) create buffer, specifying usage and size
888 * 2) allocate memory based on memory requirements
892 BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
893 try ( Frame frame = Frame.frame()) {
894 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
895 VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(
899 VK_SHARING_MODE_EXCLUSIVE,
903 VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
905 device.vkGetBufferMemoryRequirements(buffer, req);
907 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
909 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
912 VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
915 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
917 device.vkUnmapMemory(memory);
920 device.vkBindBufferMemory(buffer, memory, 0);
922 return new BufferMemory(buffer, memory, dataSize);
927 device.vkDestroyFence(drawFence);
928 device.vkDestroySemaphore(chainSemaphore);
930 device.vkDestroyPipeline(pipeline.getAtIndex(0));
931 for (int i = 0; i < shader.size(); i++)
932 device.vkDestroyShaderModule(shader.getAtIndex(i));
935 uniform.free(device);
937 for (int i = 0; i < framebuffers.size(); i++)
938 device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
940 device.vkDestroyRenderPass(render_pass);
942 device.vkDestroyDescriptorPool(desc_pool);
943 device.vkDestroyPipelineLayout(pipeline_layout);
944 device.vkDestroyDescriptorSetLayout(desc_layout);
946 device.vkDestroyImageView(depthView);
947 device.vkFreeMemory(depthMemory);
948 device.vkDestroyImage(depthImage);
950 for (int i = 0; i < chainImageView.size(); i++)
951 device.vkDestroyImageView(chainImageView.getAtIndex(i));
953 device.vkDestroySwapchainKHR(chain);
955 device.vkDestroyCommandPool(cmd_pool);
956 device.vkDestroyDevice();
958 instance.vkDestroySurfaceKHR(surface);
963 instance.vkDestroyDebugUtilsMessengerEXT(logger);
964 instance.vkDestroyInstance();
968 * This finds the memory type index for the memory on a specific device.
970 static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
971 VkMemoryType mtypes = memory.getMemoryTypes();
973 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
974 if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
980 static int clampi(int v, int min, int max) {
981 return v < min ? min : v < max ? v : max;
984 void init_matrices() {
985 float eye[] = new float[]{-5, 3, -10};
986 float centre[] = new float[]{0, 0, 0};
987 float up[] = new float[]{0, -1, 0};
988 float t0[] = new float[16], t1[] = new float[16];
990 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
991 lookAt(view, eye, centre, up);
993 mult4x4f(t0, clip, projection);
994 mult4x4f(t1, t0, view);
995 mult4x4f(mvp, t1, model);
998 void demo() throws Exception {
999 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
1000 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
1008 init_device_queue();
1017 init_vertexbuffer();
1020 execute_begin_command_buffer();
1024 System.out.println("Any key to quit");
1026 outer: while ((e = window.nextEvent(true)) != null) {
1037 public static void main(String[] args) throws Throwable {
1038 System.loadLibrary("vulkan");
1039 System.loadLibrary("X11");
1041 new TestCube().demo();