9f022e6430548842f9fc5f9ef08245b3a916c727
[panamaz] / src / notzed.vulkan.test / classes / vulkan / test / TestCube.java
1 /*
2 The MIT License (MIT)
3
4 Copyright (C) 2017 Eric Arneb├Ąck
5 Copyright (C) 2019 Michael Zucchi
6
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:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
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
23 THE SOFTWARE.
24
25  */
26
27  /*
28  * This is a Java conversion of a C conversion of this:
29  * https://github.com/Erkaman/vulkan_minimal_compute
30  *
31  * It's been simplified a bit and converted to the 'zvk' api.
32  */
33 package vulkan.test;
34
35 import au.notzed.display.Display;
36 import jdk.incubator.foreign.*;
37 import au.notzed.nativez.*;
38
39 import vulkan.*;
40 import static vulkan.Vulkan.*;
41
42 import au.notzed.display.*;
43 import static vulkan.test.GLMaths.*;
44
45 public class TestCube {
46
47         static final boolean debug = true;
48
49         final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
50         final static int NUM_DESCRIPTOR_SETS = 1;
51
52         ResourceScope scope = ResourceScope.newSharedScope();
53
54         int width = 800;
55         int height = 800;
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
64         };
65         float mvp[] = new float[16];
66
67         VkInstance instance;
68         VkPhysicalDevice physicalDevice;
69         VkPhysicalDeviceMemoryProperties memory_properties;
70         VkPhysicalDeviceFeatures device_features;
71
72         int present_queue_index;
73         int graphics_queue_index;
74
75         VkDevice device;
76         VkSwapchainKHR chain;
77
78         VkQueue graphics_queue;
79         VkQueue present_queue;
80
81         int chainImageFormat;
82         HandleArray<VkImage> chainImage;
83         HandleArray<VkImageView> chainImageView;
84
85         int depthFormat;
86         VkImage depthImage;
87         VkImageView depthView;
88         VkDeviceMemory depthMemory;
89
90         VkCommandPool cmd_pool;
91         HandleArray<VkCommandBuffer> cmd;
92
93         BufferMemory uniform;
94         VkPipelineLayout pipeline_layout;
95
96         VkDescriptorSetLayout desc_layout;
97         VkDescriptorPool desc_pool;
98         HandleArray<VkDescriptorSet> desc_set;
99
100         VkRenderPass render_pass;
101         HandleArray<VkFramebuffer> framebuffers;
102
103         BufferMemory vertex;
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);
107
108         IntArray cube_vs;
109         IntArray cube_fs;
110         HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
111
112         HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
113
114         VkSemaphore chainSemaphore;
115         VkFence drawFence;
116
117         record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) {
118
119                 public void free(VkDevice device) {
120                         device.vkFreeMemory(memory);
121                         device.vkDestroyBuffer(buffer);
122                 }
123         }
124
125         VkDebugUtilsMessengerEXT logger;
126
127         void init_debug() throws Exception {
128                 if (!debug)
129                         return;
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());
133                                 return 0;
134                         }, scope);
135                         VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(
136                                 0,
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,
141                                 cb,
142                                 null,
143                                 frame);
144
145                         logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
146                 }
147
148                 //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
149         }
150
151         void init_instance() throws Exception {
152                 try ( Frame frame = Frame.frame()) {
153                         VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
154                                 0,
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"},
158                                 frame
159                         );
160
161                         instance = VkInstance.vkCreateInstance(info, scope);
162                         System.out.printf("instance = %s\n", instance);
163                 }
164         }
165
166         Display display;
167         Window window;
168         VkSurfaceKHR surface;
169
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);
175         }
176
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;
182                         int count;
183                         int res;
184
185                         devs = instance.vkEnumeratePhysicalDevices(frame, scope);
186
187                         // Search for device and queue indices
188                         int devid = -1;
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;
194
195                                 famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
196
197                                 for (int j = 0; j < famprops.length(); j++) {
198                                         boolean present;
199
200                                         dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
201                                         present = present$h.get(0) != 0;
202
203                                         if (present && present_queue == -1)
204                                                 present_queue = j;
205                                         if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
206                                                 graphics_queue = j;
207                                                 if (present) {
208                                                         present_queue = j;
209                                                         break;
210                                                 }
211                                         }
212                                 }
213                                 if (present_queue != -1 && graphics_queue != -1) {
214                                         devid = i;
215                                         break;
216                                 }
217                         }
218
219                         if (devid == -1)
220                                 throw new Exception("Cannot find a suitable device");
221
222                         physicalDevice = devs.getAtIndex(devid);
223                         present_queue_index = present_queue;
224                         graphics_queue_index = graphics_queue;
225
226                         // NOTE: app scope
227                         memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
228                         physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
229                         device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
230                         physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
231
232                         FloatArray qpri = FloatArray.create(frame, 0.0f);
233                         VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
234                                 0,
235                                 graphics_queue,
236                                 1, qpri,
237                                 frame);
238                         String[] extensions = {
239                                 "VK_KHR_swapchain"
240                         };
241                         VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
242                         features.setDepthClamp(1);
243                         VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
244                                 0,
245                                 1, qinfo,
246                                 0, null,
247                                 extensions.length, extensions,
248                                 features,
249                                 frame);
250
251                         device = physicalDevice.vkCreateDevice(devinfo, scope);
252
253                         System.out.printf("device = %s\n", device);
254
255                         /* ************************************************************** */
256                         int format;
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;
263                         } else {
264                                 format = surfFormats.getFormatAtIndex(0);
265                         }
266
267                         VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
268
269                         physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
270                         IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
271
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()),
280                                 frame);
281                         } else {
282                                 // If the surface size is defined, the swap chain size must match
283                                 swapchainExtent = surfCapabilities.getCurrentExtent();
284                         }
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;
294                                         break;
295                                 }
296                         }
297
298                         VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(
299                                 0,
300                                 surface,
301                                 surfCapabilities.getMinImageCount(),
302                                 format,
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.
309                                 0, null,
310                                 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
311                                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
312                                 compositeAlpha,
313                                 VK_PRESENT_MODE_FIFO_KHR,
314                                 VK_TRUE,
315                                 null,
316                                 frame);
317
318                         chain = device.vkCreateSwapchainKHR(chaininfo, scope);
319
320                         int chainImageCount;
321
322                         chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
323                         chainImageCount = (int)chainImage.length();
324                         chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
325
326                         VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
327                                 0,
328                                 null,
329                                 VK_IMAGE_VIEW_TYPE_2D,
330                                 format,
331                                 frame);
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);
334
335                         for (int i = 0; i < chainImageCount; i++) {
336                                 viewinfo.setImage(chainImage.get(i));
337
338                                 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
339                         }
340
341                         chainImageFormat = format;
342                 }
343         }
344
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;
349                 } else {
350                         present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
351                 }
352         }
353
354         void init_command() throws Exception {
355                 try ( Frame frame = Frame.frame()) {
356                         VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
357                                 0,
358                                 graphics_queue_index,
359                                 frame);
360
361                         cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
362
363                         VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
364                                 cmd_pool,
365                                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
366                                 1,
367                                 frame);
368
369                         cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
370                 }
371         }
372
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(
379                                 0,
380                                 VK_IMAGE_TYPE_2D,
381                                 format,
382                                 width, height, 1,
383                                 1,
384                                 1,
385                                 NUM_SAMPLES,
386                                 0,
387                                 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
388                                 VK_SHARING_MODE_EXCLUSIVE,
389                                 0, null,
390                                 VK_IMAGE_LAYOUT_UNDEFINED,
391                                 frame);
392
393                         depthImage = device.vkCreateImage(imageinfo, scope);
394
395                         device.vkGetImageMemoryRequirements(depthImage, req);
396                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
397                                 req.getSize(),
398                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
399                                 frame);
400
401                         depthMemory = device.vkAllocateMemory(alloc, scope);
402
403                         device.vkBindImageMemory(depthImage, depthMemory, 0);
404
405                         VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
406                                 0,
407                                 depthImage,
408                                 VK_IMAGE_VIEW_TYPE_2D,
409                                 VK_FORMAT_D16_UNORM,
410                                 frame);
411
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);
421
422                         depthView = device.vkCreateImageView(viewinfo, scope);
423
424                         depthFormat = format;
425                 }
426         }
427
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));
430         }
431
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(
436                                 0,
437                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
438                                 1,
439                                 VK_SHADER_STAGE_VERTEX_BIT,
440                                 null,
441                                 frame);
442                         VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
443                                 0,
444                                 1, layout_binding,
445                                 frame);
446
447                         desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
448                         layout_table.setAtIndex(0, desc_layout);
449
450                         VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
451                                 0,
452                                 1, layout_table,
453                                 0, null,
454                                 frame);
455
456                         pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
457
458                         VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
459                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
460                                 1,
461                                 frame);
462
463                         VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
464                                 0,
465                                 1,
466                                 1, type_count,
467                                 frame);
468
469                         desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
470
471                         VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
472                                 desc_pool,
473                                 1, layout_table,
474                                 frame);
475
476                         System.out.println(alloc_info);
477
478                         desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
479
480                         VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
481                         VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
482                                 desc_set.getAtIndex(0),
483                                 0,
484                                 0,
485                                 1,
486                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
487                                 null,
488                                 uniformInfo,
489                                 null,
490                                 frame);
491
492                         device.vkUpdateDescriptorSets(1, writes, 0, null);
493                 }
494         }
495
496         void init_render() throws Exception {
497                 try ( Frame frame = Frame.frame()) {
498                         VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
499
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);
509
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);
519
520                         VkAttachmentReference color_reference = VkAttachmentReference.create(
521                                 0,
522                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
523                                 frame);
524
525                         VkAttachmentReference depth_reference = VkAttachmentReference.create(
526                                 1,
527                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
528                                 frame);
529
530                         VkSubpassDescription subpass = VkSubpassDescription.create(
531                                 0,
532                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
533                                 0, null,
534                                 1, color_reference,
535                                 null,
536                                 depth_reference,
537                                 0, null,
538                                 frame);
539
540                         VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
541                                 0,
542                                 2, attachments,
543                                 1, subpass,
544                                 0, null,
545                                 frame);
546
547                         render_pass = device.vkCreateRenderPass(rp_info, scope);
548                 }
549         }
550
551         void init_framebuffer() throws Exception {
552                 try ( Frame frame = Frame.frame()) {
553                         HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
554
555                         attachments.setAtIndex(1, depthView);
556
557                         VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
558                                 0,
559                                 render_pass,
560                                 2, attachments,
561                                 width, height, 1,
562                                 frame);
563
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));
569                         }
570                 }
571         }
572
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));
576
577                         vertexBuffer.setAtIndex(0, vertex.buffer);
578
579                         /* ***************************************** */
580                         vi_binding.setBinding(0);
581                         vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
582                         vi_binding.setStride(Cube.dataStride);
583
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);
592                 }
593         }
594
595         void init_pipeline() throws Exception {
596                 int res;
597                 try ( Frame frame = Frame.frame()) {
598                         IntArray dynamicStateEnables = IntArray.create(frame,
599                                 VK_DYNAMIC_STATE_VIEWPORT,
600                                 VK_DYNAMIC_STATE_SCISSOR);
601
602                         VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
603                                 0,
604                                 2, dynamicStateEnables,
605                                 frame);
606
607                         VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
608                                 0,
609                                 (int)vi_binding.length(), vi_binding,
610                                 (int)vi_attribs.length(), vi_attribs,
611                                 frame);
612
613                         VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
614                                 0,
615                                 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
616                                 0,
617                                 frame);
618
619                         VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
620                                 0,
621                                 VK_TRUE,
622                                 VK_FALSE,
623                                 VK_POLYGON_MODE_FILL,
624                                 VK_CULL_MODE_BACK_BIT,
625                                 VK_FRONT_FACE_CLOCKWISE,
626                                 VK_FALSE,
627                                 0.0f,
628                                 0.0f,
629                                 0.0f,
630                                 1.0f,
631                                 frame);
632
633                         VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
634                                 VK_FALSE,
635                                 VK_BLEND_FACTOR_ZERO,
636                                 VK_BLEND_FACTOR_ZERO,
637                                 VK_BLEND_OP_ADD,
638                                 VK_BLEND_FACTOR_ZERO,
639                                 VK_BLEND_FACTOR_ZERO,
640                                 VK_BLEND_OP_ADD,
641                                 0xf,
642                                 frame);
643
644                         VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
645                                 0,
646                                 VK_FALSE,
647                                 VK_LOGIC_OP_NO_OP,
648                                 1, att_state,
649                                 1.0f, 1.0f, 1.0f, 1.0f,
650                                 frame);
651
652                         VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
653                                 0,
654                                 1, null,
655                                 1, null,
656                                 frame);
657
658                         VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
659                                 0,
660                                 VK_TRUE,
661                                 VK_TRUE,
662                                 VK_COMPARE_OP_LESS_OR_EQUAL,
663                                 VK_FALSE,
664                                 VK_FALSE,
665                                 0.0f,
666                                 0.0f,
667                                 frame);
668                         VkStencilOpState back = ds.getBack();
669
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);
677
678                         VkStencilOpState front = ds.getFront();
679
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);
687
688                         VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
689                                 0,
690                                 NUM_SAMPLES,
691                                 0, //.sampleShadingEnable = VK_FALSE,
692                                 0.0f,
693                                 null,
694                                 0, //.alphaToCoverageEnable = VK_FALSE,
695                                 0, //.alphaToOneEnable = VK_FALSE,
696                                 frame
697                         );
698
699                         VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
700                                 0,
701                                 cube_vs.length() * 4,
702                                 cube_vs,
703                                 frame);
704                         VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
705                                 0,
706                                 cube_fs.length() * 4,
707                                 cube_fs,
708                                 frame);
709
710                         shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
711                         shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
712
713                         VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
714
715                         shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
716                         shaderStages.setName("main", (SegmentAllocator)scope);
717                         shaderStages.setModule(shader.get(0));
718
719                         shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
720                         shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
721                         shaderStages.setModuleAtIndex(1, shader.get(1));
722
723                         VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
724                                 0,
725                                 2, shaderStages,
726                                 vi,
727                                 ia,
728                                 null,
729                                 vp,
730                                 rs,
731                                 ms,
732                                 ds,
733                                 cb,
734                                 dynamicState,
735                                 pipeline_layout,
736                                 render_pass,
737                                 0,
738                                 null,
739                                 0,
740                                 frame);
741
742                         res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
743
744                         VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
745                         chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
746
747                         VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
748                         drawFence = device.vkCreateFence(fenceInfo, scope);
749                 }
750         }
751
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(
756                                 0,
757                                 null,
758                                 frame);
759
760                         cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
761                 }
762         }
763
764         void execute_end_command_buffer() throws Exception {
765                 cmd.getAtIndex(0).vkEndCommandBuffer();
766         }
767
768         final static long FENCE_TIMEOUT = 100000000;
769
770         void execute_queue_command_buffer() throws Exception {
771                 int res;
772
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);
779
780                         fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
781
782                         VkSubmitInfo submit_info = VkSubmitInfo.create(
783                                 1, null, pipe_stage_flags,
784                                 (int)cmd.length(), cmd,
785                                 0, null,
786                                 frame);
787
788                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
789
790                         do {
791                                 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
792                         } while (res == VK_TIMEOUT);
793
794                         device.vkDestroyFence(fences.getAtIndex(0));
795                 }
796         }
797
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,
803                                 frame);
804                         cmd.vkCmdSetViewport(0, 1, viewport);
805                 }
806         }
807
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);
813                 }
814         }
815
816         void cmd_paint() throws Exception {
817                 int res;
818                 try ( Frame frame = Frame.frame()) {
819                         int chainIndex;
820                         IntArray chainIndices = IntArray.createArray(1, frame);
821                         VkCommandBuffer cmd = this.cmd.getAtIndex(0);
822
823                         device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
824                         chainIndex = chainIndices.getAtIndex(0);
825                         LongArray offsets = LongArray.createArray(1, frame);
826
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);
836
837                         System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
838
839                         VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
840                                 render_pass,
841                                 framebuffers.getAtIndex(chainIndex),
842                                 0, 0, width, height,
843                                 2, clear_values,
844                                 frame);
845
846                         cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
847
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);
851
852                         cmd_viewport();
853                         cmd_scissors();
854
855                         cmd.vkCmdDraw(12 * 3, 1, 0, 0);
856                         cmd.vkCmdEndRenderPass();
857
858                         cmd.vkEndCommandBuffer();
859
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);
862
863                         semaphores.setAtIndex(0, chainSemaphore);
864
865                         VkSubmitInfo submit_info = VkSubmitInfo.create(
866                                 1, semaphores, pipe_stage_flags,
867                                 (int)this.cmd.length(), this.cmd,
868                                 0, null,
869                                 frame);
870
871                         HandleArray<VkFence> fences = VkFence.createArray(1, frame);
872
873                         fences.setAtIndex(0, drawFence);
874
875                         // Queue the command buffer for execution
876                         device.vkResetFences(1, fences);
877
878                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
879
880                         // Make sure command buffer is finished before presenting
881                         do {
882                                 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
883                         } while (res == VK_TIMEOUT);
884
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(
889                                 0, null,
890                                 1, chains, chainIndices, null,
891                                 frame);
892
893                         present_queue.vkQueuePresentKHR(present);
894                 }
895         }
896
897         /**
898          * Buffers are created in three steps:
899          * 1) create buffer, specifying usage and size
900          * 2) allocate memory based on memory requirements
901          * 3) bind memory
902          * <p>
903          */
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(
908                                 0,
909                                 dataSize,
910                                 usage,
911                                 VK_SHARING_MODE_EXCLUSIVE,
912                                 0, null,
913                                 frame);
914
915                         VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
916
917                         device.vkGetBufferMemoryRequirements(buffer, req);
918
919                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
920                                 req.getSize(),
921                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
922                                 frame);
923
924                         VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
925
926                         if (init != null) {
927                                 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
928                                 mem.copyFrom(init);
929                                 device.vkUnmapMemory(memory);
930                         }
931
932                         device.vkBindBufferMemory(buffer, memory, 0);
933
934                         return new BufferMemory(buffer, memory, dataSize);
935                 }
936         }
937
938         void shutdown() {
939                 device.vkDestroyFence(drawFence);
940                 device.vkDestroySemaphore(chainSemaphore);
941
942                 device.vkDestroyPipeline(pipeline.getAtIndex(0));
943                 for (int i = 0; i < shader.size(); i++)
944                         device.vkDestroyShaderModule(shader.getAtIndex(i));
945
946                 vertex.free(device);
947                 uniform.free(device);
948
949                 for (int i = 0; i < framebuffers.size(); i++)
950                         device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
951
952                 device.vkDestroyRenderPass(render_pass);
953
954                 device.vkDestroyDescriptorPool(desc_pool);
955                 device.vkDestroyPipelineLayout(pipeline_layout);
956                 device.vkDestroyDescriptorSetLayout(desc_layout);
957
958                 device.vkDestroyImageView(depthView);
959                 device.vkFreeMemory(depthMemory);
960                 device.vkDestroyImage(depthImage);
961
962                 for (int i = 0; i < chainImageView.size(); i++)
963                         device.vkDestroyImageView(chainImageView.getAtIndex(i));
964
965                 device.vkDestroySwapchainKHR(chain);
966
967                 device.vkDestroyCommandPool(cmd_pool);
968                 device.vkDestroyDevice();
969
970                 instance.vkDestroySurfaceKHR(surface);
971                 window.close();
972                 display.close();
973
974                 if (logger != null)
975                         instance.vkDestroyDebugUtilsMessengerEXT(logger);
976                 instance.vkDestroyInstance();
977         }
978
979         /**
980          * This finds the memory type index for the memory on a specific device.
981          */
982         static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
983                 VkMemoryType mtypes = memory.getMemoryTypes();
984
985                 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
986                         if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
987                                 return i;
988                 }
989                 return -1;
990         }
991
992         static int clampi(int v, int min, int max) {
993                 return v < min ? min : v < max ? v : max;
994         }
995
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];
1001
1002                 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
1003                 lookAt(view, eye, centre, up);
1004                 identity4f(model);
1005                 mult4x4f(t0, clip, projection);
1006                 mult4x4f(t1, t0, view);
1007                 mult4x4f(mvp, t1, model);
1008         }
1009
1010         void demo() throws Exception {
1011                 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
1012                 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
1013
1014                 init_matrices();
1015
1016                 init_instance();
1017                 init_debug();
1018                 init_surface();
1019                 init_device();
1020                 init_device_queue();
1021
1022                 init_command();
1023                 init_depth();
1024                 init_uniform();
1025
1026                 init_descriptor();
1027                 init_render();
1028                 init_framebuffer();
1029                 init_vertexbuffer();
1030                 init_pipeline();
1031
1032                 execute_begin_command_buffer();
1033
1034                 cmd_paint();
1035
1036                 System.out.println("Any key to quit");
1037                 Event e;
1038 outer:  while ((e = window.nextEvent(true)) != null) {
1039                         switch (e.type) {
1040                         case Event.KEY:
1041                         case Event.CLOSE:
1042                                 break outer;
1043                         }
1044                 }
1045
1046                 shutdown();
1047         }
1048
1049         public static void main(String[] args) throws Throwable {
1050                 System.loadLibrary("vulkan");
1051                 System.loadLibrary("X11");
1052
1053                 new TestCube().demo();
1054         }
1055 }