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++) {
200 dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
201 present = present$h.get(0) != 0;
203 if (present && present_queue == -1)
205 if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
213 if (present_queue != -1 && graphics_queue != -1) {
220 throw new Exception("Cannot find a suitable device");
222 physicalDevice = devs.getAtIndex(devid);
223 present_queue_index = present_queue;
224 graphics_queue_index = graphics_queue;
227 memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
228 physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
229 device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
230 physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
232 FloatArray qpri = FloatArray.create(frame, 0.0f);
233 VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
238 String[] extensions = {
241 VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
242 features.setDepthClamp(1);
243 VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
247 extensions.length, extensions,
251 device = physicalDevice.vkCreateDevice(devinfo, scope);
253 System.out.printf("device = %s\n", device);
255 /* ************************************************************** */
257 VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
258 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
259 // the surface has no preferred format. Otherwise, at least one
260 // supported format will be returned.
261 if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
262 format = VK_FORMAT_B8G8R8A8_UNORM;
264 format = surfFormats.getFormatAtIndex(0);
267 VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
269 physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
270 IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
272 VkExtent2D swapchainExtent;
273 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
274 if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
275 // If the surface size is undefined, the size is set to
276 // the size of the images requested.
277 swapchainExtent = VkExtent2D.create(
278 clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
279 clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()),
282 // If the surface size is defined, the swap chain size must match
283 swapchainExtent = surfCapabilities.getCurrentExtent();
285 int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
286 int compositeAlphaFlags[] = {
287 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
288 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
289 VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
290 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,};
291 for (int flag: compositeAlphaFlags) {
292 if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
293 compositeAlpha = flag;
298 VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(
301 surfCapabilities.getMinImageCount(),
303 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
304 swapchainExtent.getWidth(), swapchainExtent.getHeight(),
305 1, //.imageArrayLayers = 1,
306 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
307 VK_SHARING_MODE_EXCLUSIVE,
308 // assumes queues are same.
310 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
311 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
313 VK_PRESENT_MODE_FIFO_KHR,
318 chain = device.vkCreateSwapchainKHR(chaininfo, scope);
322 chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
323 chainImageCount = (int)chainImage.length();
324 chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
326 VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
329 VK_IMAGE_VIEW_TYPE_2D,
332 viewinfo.getComponents().set(VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A);
333 viewinfo.getSubresourceRange().set(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
335 for (int i = 0; i < chainImageCount; i++) {
336 viewinfo.setImage(chainImage.get(i));
338 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
341 chainImageFormat = format;
345 void init_device_queue() {
346 graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
347 if (graphics_queue_index == present_queue_index) {
348 present_queue = graphics_queue;
350 present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
354 void init_command() throws Exception {
355 try ( Frame frame = Frame.frame()) {
356 VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
358 graphics_queue_index,
361 cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
363 VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
365 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
369 cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
373 // parameterise as init_image?
374 void init_depth() throws Exception {
375 try ( Frame frame = Frame.frame()) {
376 int format = VK_FORMAT_D16_UNORM;
377 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
378 VkImageCreateInfo imageinfo = VkImageCreateInfo.create(
387 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
388 VK_SHARING_MODE_EXCLUSIVE,
390 VK_IMAGE_LAYOUT_UNDEFINED,
393 depthImage = device.vkCreateImage(imageinfo, scope);
395 device.vkGetImageMemoryRequirements(depthImage, req);
396 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
398 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(
408 VK_IMAGE_VIEW_TYPE_2D,
412 VkComponentMapping components = viewinfo.getComponents();
413 components.setR(VK_COMPONENT_SWIZZLE_R);
414 components.setG(VK_COMPONENT_SWIZZLE_G);
415 components.setB(VK_COMPONENT_SWIZZLE_B);
416 components.setA(VK_COMPONENT_SWIZZLE_A);
417 VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
418 subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
419 subresourceRange.setLevelCount(1);
420 subresourceRange.setLayerCount(1);
422 depthView = device.vkCreateImageView(viewinfo, scope);
424 depthFormat = format;
428 void init_uniform() throws Exception {
429 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));
432 void init_descriptor() throws Exception {
433 try ( Frame frame = Frame.frame()) {
434 HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
435 VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(
437 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
439 VK_SHADER_STAGE_VERTEX_BIT,
442 VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
447 desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
448 layout_table.setAtIndex(0, desc_layout);
450 VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
456 pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
458 VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
459 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
463 VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
469 desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
471 VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
476 System.out.println(alloc_info);
478 desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
480 VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
481 VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
482 desc_set.getAtIndex(0),
486 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
492 device.vkUpdateDescriptorSets(1, writes, 0, null);
496 void init_render() throws Exception {
497 try ( Frame frame = Frame.frame()) {
498 VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
500 attachments.setFormat(chainImageFormat);
501 attachments.setSamples(NUM_SAMPLES);
502 attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
503 attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
504 attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
505 attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
506 attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
507 attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
508 attachments.setFlags(0);
510 attachments.setFormatAtIndex(1, depthFormat);
511 attachments.setSamplesAtIndex(1, NUM_SAMPLES);
512 attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
513 attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
514 attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
515 attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
516 attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
517 attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
518 attachments.setFlagsAtIndex(1, 0);
520 VkAttachmentReference color_reference = VkAttachmentReference.create(
522 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
525 VkAttachmentReference depth_reference = VkAttachmentReference.create(
527 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
530 VkSubpassDescription subpass = VkSubpassDescription.create(
532 VK_PIPELINE_BIND_POINT_GRAPHICS,
540 VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
547 render_pass = device.vkCreateRenderPass(rp_info, scope);
551 void init_framebuffer() throws Exception {
552 try ( Frame frame = Frame.frame()) {
553 HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
555 attachments.setAtIndex(1, depthView);
557 VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
564 framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
565 for (int i = 0; i < chainImage.size(); i++) {
566 attachments.setAtIndex(0, chainImageView.get(i));
567 framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
568 System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
573 void init_vertexbuffer() throws Exception {
574 try ( Frame frame = Frame.frame()) {
575 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));
577 vertexBuffer.setAtIndex(0, vertex.buffer);
579 /* ***************************************** */
580 vi_binding.setBinding(0);
581 vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
582 vi_binding.setStride(Cube.dataStride);
584 vi_attribs.setBinding(0);
585 vi_attribs.setLocation(0);
586 vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
587 vi_attribs.setOffset(0);
588 vi_attribs.setBindingAtIndex(1, 0);
589 vi_attribs.setLocationAtIndex(1, 1);
590 vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
591 vi_attribs.setOffsetAtIndex(1, 16);
595 void init_pipeline() throws Exception {
597 try ( Frame frame = Frame.frame()) {
598 IntArray dynamicStateEnables = IntArray.create(frame,
599 VK_DYNAMIC_STATE_VIEWPORT,
600 VK_DYNAMIC_STATE_SCISSOR);
602 VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
604 2, dynamicStateEnables,
607 VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
609 (int)vi_binding.length(), vi_binding,
610 (int)vi_attribs.length(), vi_attribs,
613 VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
615 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
619 VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
623 VK_POLYGON_MODE_FILL,
624 VK_CULL_MODE_BACK_BIT,
625 VK_FRONT_FACE_CLOCKWISE,
633 VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
635 VK_BLEND_FACTOR_ZERO,
636 VK_BLEND_FACTOR_ZERO,
638 VK_BLEND_FACTOR_ZERO,
639 VK_BLEND_FACTOR_ZERO,
644 VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
649 1.0f, 1.0f, 1.0f, 1.0f,
652 VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
658 VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
662 VK_COMPARE_OP_LESS_OR_EQUAL,
668 VkStencilOpState back = ds.getBack();
670 back.setFailOp(VK_STENCIL_OP_KEEP);
671 back.setPassOp(VK_STENCIL_OP_KEEP);
672 back.setCompareOp(VK_COMPARE_OP_ALWAYS);
673 back.setCompareMask(0);
674 back.setReference(0);
675 back.setDepthFailOp(VK_STENCIL_OP_KEEP);
676 back.setWriteMask(0);
678 VkStencilOpState front = ds.getFront();
680 front.setFailOp(VK_STENCIL_OP_KEEP);
681 front.setPassOp(VK_STENCIL_OP_KEEP);
682 front.setCompareOp(VK_COMPARE_OP_ALWAYS);
683 front.setCompareMask(0);
684 front.setReference(0);
685 front.setDepthFailOp(VK_STENCIL_OP_KEEP);
686 front.setWriteMask(0);
688 VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
691 0, //.sampleShadingEnable = VK_FALSE,
694 0, //.alphaToCoverageEnable = VK_FALSE,
695 0, //.alphaToOneEnable = VK_FALSE,
699 VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
701 cube_vs.length() * 4,
704 VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
706 cube_fs.length() * 4,
710 shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
711 shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
713 VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
715 shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
716 shaderStages.setName("main", (SegmentAllocator)scope);
717 shaderStages.setModule(shader.get(0));
719 shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
720 shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
721 shaderStages.setModuleAtIndex(1, shader.get(1));
723 VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
742 res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
744 VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
745 chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
747 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
748 drawFence = device.vkCreateFence(fenceInfo, scope);
752 void execute_begin_command_buffer() throws Exception {
753 /* DEPENDS on init_command() */
754 try ( Frame frame = Frame.frame()) {
755 VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(
760 cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
764 void execute_end_command_buffer() throws Exception {
765 cmd.getAtIndex(0).vkEndCommandBuffer();
768 final static long FENCE_TIMEOUT = 100000000;
770 void execute_queue_command_buffer() throws Exception {
773 /* Queue the command buffer for execution */
774 /* FIXME: frame shoudl provide or take explicit scope */
775 try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) {
776 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
777 VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
778 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
780 fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
782 VkSubmitInfo submit_info = VkSubmitInfo.create(
783 1, null, pipe_stage_flags,
784 (int)cmd.length(), cmd,
788 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
791 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
792 } while (res == VK_TIMEOUT);
794 device.vkDestroyFence(fences.getAtIndex(0));
798 void cmd_viewport() {
799 try ( Frame frame = Frame.frame()) {
800 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
801 VkViewport viewport = VkViewport.create(
802 0, 0, width, height, 0.0f, 1.0f,
804 cmd.vkCmdSetViewport(0, 1, viewport);
808 void cmd_scissors() {
809 try ( Frame frame = Frame.frame()) {
810 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
811 VkRect2D scissor = VkRect2D.create(0, 0, width, height, frame);
812 cmd.vkCmdSetScissor(0, 1, scissor);
816 void cmd_paint() throws Exception {
818 try ( Frame frame = Frame.frame()) {
820 IntArray chainIndices = IntArray.createArray(1, frame);
821 VkCommandBuffer cmd = this.cmd.getAtIndex(0);
823 device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
824 chainIndex = chainIndices.getAtIndex(0);
825 LongArray offsets = LongArray.createArray(1, frame);
827 VkClearValue clear_values = VkClearValue.createArray(2, frame);
828 FloatArray col = clear_values.getColor().getFloat32();
829 col.setAtIndex(0, 0.2f);
830 col.setAtIndex(1, 0.2f);
831 col.setAtIndex(2, 0.2f);
832 col.setAtIndex(3, 0.2f);
833 VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
834 depthStencil.setDepth(1.0f);
835 depthStencil.setStencil(0);
837 System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
839 VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
841 framebuffers.getAtIndex(chainIndex),
846 cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
848 cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
849 cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
850 cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
855 cmd.vkCmdDraw(12 * 3, 1, 0, 0);
856 cmd.vkCmdEndRenderPass();
858 cmd.vkEndCommandBuffer();
860 IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
861 HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
863 semaphores.setAtIndex(0, chainSemaphore);
865 VkSubmitInfo submit_info = VkSubmitInfo.create(
866 1, semaphores, pipe_stage_flags,
867 (int)this.cmd.length(), this.cmd,
871 HandleArray<VkFence> fences = VkFence.createArray(1, frame);
873 fences.setAtIndex(0, drawFence);
875 // Queue the command buffer for execution
876 device.vkResetFences(1, fences);
878 graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
880 // Make sure command buffer is finished before presenting
882 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
883 } while (res == VK_TIMEOUT);
885 // Now present the image in the window
886 HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
887 chains.setAtIndex(0, chain);
888 VkPresentInfoKHR present = VkPresentInfoKHR.create(
890 1, chains, chainIndices, null,
893 present_queue.vkQueuePresentKHR(present);
898 * Buffers are created in three steps:
899 * 1) create buffer, specifying usage and size
900 * 2) allocate memory based on memory requirements
904 BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
905 try ( Frame frame = Frame.frame()) {
906 VkMemoryRequirements req = VkMemoryRequirements.create(frame);
907 VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(
911 VK_SHARING_MODE_EXCLUSIVE,
915 VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
917 device.vkGetBufferMemoryRequirements(buffer, req);
919 VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
921 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
924 VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
927 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
929 device.vkUnmapMemory(memory);
932 device.vkBindBufferMemory(buffer, memory, 0);
934 return new BufferMemory(buffer, memory, dataSize);
939 device.vkDestroyFence(drawFence);
940 device.vkDestroySemaphore(chainSemaphore);
942 device.vkDestroyPipeline(pipeline.getAtIndex(0));
943 for (int i = 0; i < shader.size(); i++)
944 device.vkDestroyShaderModule(shader.getAtIndex(i));
947 uniform.free(device);
949 for (int i = 0; i < framebuffers.size(); i++)
950 device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
952 device.vkDestroyRenderPass(render_pass);
954 device.vkDestroyDescriptorPool(desc_pool);
955 device.vkDestroyPipelineLayout(pipeline_layout);
956 device.vkDestroyDescriptorSetLayout(desc_layout);
958 device.vkDestroyImageView(depthView);
959 device.vkFreeMemory(depthMemory);
960 device.vkDestroyImage(depthImage);
962 for (int i = 0; i < chainImageView.size(); i++)
963 device.vkDestroyImageView(chainImageView.getAtIndex(i));
965 device.vkDestroySwapchainKHR(chain);
967 device.vkDestroyCommandPool(cmd_pool);
968 device.vkDestroyDevice();
970 instance.vkDestroySurfaceKHR(surface);
975 instance.vkDestroyDebugUtilsMessengerEXT(logger);
976 instance.vkDestroyInstance();
980 * This finds the memory type index for the memory on a specific device.
982 static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
983 VkMemoryType mtypes = memory.getMemoryTypes();
985 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
986 if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
992 static int clampi(int v, int min, int max) {
993 return v < min ? min : v < max ? v : max;
996 void init_matrices() {
997 float eye[] = new float[]{-5, 3, -10};
998 float centre[] = new float[]{0, 0, 0};
999 float up[] = new float[]{0, -1, 0};
1000 float t0[] = new float[16], t1[] = new float[16];
1002 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
1003 lookAt(view, eye, centre, up);
1005 mult4x4f(t0, clip, projection);
1006 mult4x4f(t1, t0, view);
1007 mult4x4f(mvp, t1, model);
1010 void demo() throws Exception {
1011 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
1012 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
1020 init_device_queue();
1029 init_vertexbuffer();
1032 execute_begin_command_buffer();
1036 System.out.println("Any key to quit");
1038 outer: while ((e = window.nextEvent(true)) != null) {
1049 public static void main(String[] args) throws Throwable {
1050 System.loadLibrary("vulkan");
1051 System.loadLibrary("X11");
1053 new TestCube().demo();