Try to auto-detect some simple-type query functions.
[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 = dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface);
199
200                                         if (present && present_queue == -1)
201                                                 present_queue = j;
202                                         if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
203                                                 graphics_queue = j;
204                                                 if (present) {
205                                                         present_queue = j;
206                                                         break;
207                                                 }
208                                         }
209                                 }
210                                 if (present_queue != -1 && graphics_queue != -1) {
211                                         devid = i;
212                                         break;
213                                 }
214                         }
215
216                         if (devid == -1)
217                                 throw new Exception("Cannot find a suitable device");
218
219                         physicalDevice = devs.getAtIndex(devid);
220                         present_queue_index = present_queue;
221                         graphics_queue_index = graphics_queue;
222
223                         // NOTE: app scope
224                         memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
225                         physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
226                         device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
227                         physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
228
229                         FloatArray qpri = FloatArray.create(frame, 0.0f);
230                         VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
231                                 0,
232                                 graphics_queue,
233                                 1, qpri,
234                                 frame);
235                         String[] extensions = {
236                                 "VK_KHR_swapchain"
237                         };
238                         VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
239                         features.setDepthClamp(1);
240                         VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
241                                 0,
242                                 1, qinfo,
243                                 0, null,
244                                 extensions.length, extensions,
245                                 features,
246                                 frame);
247
248                         device = physicalDevice.vkCreateDevice(devinfo, scope);
249
250                         System.out.printf("device = %s\n", device);
251
252                         /* ************************************************************** */
253                         int format;
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;
260                         } else {
261                                 format = surfFormats.getFormatAtIndex(0);
262                         }
263
264                         VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
265
266                         physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
267                         IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
268
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()),
277                                 frame);
278                         } else {
279                                 // If the surface size is defined, the swap chain size must match
280                                 swapchainExtent = surfCapabilities.getCurrentExtent();
281                         }
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;
291                                         break;
292                                 }
293                         }
294
295                         VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(
296                                 0,
297                                 surface,
298                                 surfCapabilities.getMinImageCount(),
299                                 format,
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.
306                                 0, null,
307                                 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
308                                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
309                                 compositeAlpha,
310                                 VK_PRESENT_MODE_FIFO_KHR,
311                                 VK_TRUE,
312                                 null,
313                                 frame);
314
315                         chain = device.vkCreateSwapchainKHR(chaininfo, scope);
316
317                         int chainImageCount;
318
319                         chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope);
320                         chainImageCount = (int)chainImage.length();
321                         chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
322
323                         VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
324                                 0,
325                                 null,
326                                 VK_IMAGE_VIEW_TYPE_2D,
327                                 format,
328                                 frame);
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);
331
332                         for (int i = 0; i < chainImageCount; i++) {
333                                 viewinfo.setImage(chainImage.get(i));
334
335                                 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
336                         }
337
338                         chainImageFormat = format;
339                 }
340         }
341
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;
346                 } else {
347                         present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
348                 }
349         }
350
351         void init_command() throws Exception {
352                 try ( Frame frame = Frame.frame()) {
353                         VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
354                                 0,
355                                 graphics_queue_index,
356                                 frame);
357
358                         cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
359
360                         VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
361                                 cmd_pool,
362                                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
363                                 1,
364                                 frame);
365
366                         cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
367                 }
368         }
369
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(
376                                 0,
377                                 VK_IMAGE_TYPE_2D,
378                                 format,
379                                 width, height, 1,
380                                 1,
381                                 1,
382                                 NUM_SAMPLES,
383                                 0,
384                                 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
385                                 VK_SHARING_MODE_EXCLUSIVE,
386                                 0, null,
387                                 VK_IMAGE_LAYOUT_UNDEFINED,
388                                 frame);
389
390                         depthImage = device.vkCreateImage(imageinfo, scope);
391
392                         device.vkGetImageMemoryRequirements(depthImage, req);
393                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
394                                 req.getSize(),
395                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
396                                 frame);
397
398                         depthMemory = device.vkAllocateMemory(alloc, scope);
399
400                         device.vkBindImageMemory(depthImage, depthMemory, 0);
401
402                         VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
403                                 0,
404                                 depthImage,
405                                 VK_IMAGE_VIEW_TYPE_2D,
406                                 VK_FORMAT_D16_UNORM,
407                                 frame);
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);
410
411                         depthView = device.vkCreateImageView(viewinfo, scope);
412                         depthFormat = format;
413                 }
414         }
415
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));
418         }
419
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(
424                                 0,
425                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
426                                 1,
427                                 VK_SHADER_STAGE_VERTEX_BIT,
428                                 null,
429                                 frame);
430                         VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
431                                 0,
432                                 1, layout_binding,
433                                 frame);
434
435                         desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
436                         layout_table.setAtIndex(0, desc_layout);
437
438                         VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
439                                 0,
440                                 1, layout_table,
441                                 0, null,
442                                 frame);
443
444                         pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
445
446                         VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
447                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
448                                 1,
449                                 frame);
450
451                         VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
452                                 0,
453                                 1,
454                                 1, type_count,
455                                 frame);
456
457                         desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
458
459                         VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
460                                 desc_pool,
461                                 1, layout_table,
462                                 frame);
463
464                         System.out.println(alloc_info);
465
466                         desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
467
468                         VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
469                         VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
470                                 desc_set.getAtIndex(0),
471                                 0,
472                                 0,
473                                 1,
474                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
475                                 null,
476                                 uniformInfo,
477                                 null,
478                                 frame);
479
480                         device.vkUpdateDescriptorSets(1, writes, 0, null);
481                 }
482         }
483
484         void init_render() throws Exception {
485                 try ( Frame frame = Frame.frame()) {
486                         VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
487
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);
497
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);
507
508                         VkAttachmentReference color_reference = VkAttachmentReference.create(
509                                 0,
510                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
511                                 frame);
512
513                         VkAttachmentReference depth_reference = VkAttachmentReference.create(
514                                 1,
515                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
516                                 frame);
517
518                         VkSubpassDescription subpass = VkSubpassDescription.create(
519                                 0,
520                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
521                                 0, null,
522                                 1, color_reference,
523                                 null,
524                                 depth_reference,
525                                 0, null,
526                                 frame);
527
528                         VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
529                                 0,
530                                 2, attachments,
531                                 1, subpass,
532                                 0, null,
533                                 frame);
534
535                         render_pass = device.vkCreateRenderPass(rp_info, scope);
536                 }
537         }
538
539         void init_framebuffer() throws Exception {
540                 try ( Frame frame = Frame.frame()) {
541                         HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
542
543                         attachments.setAtIndex(1, depthView);
544
545                         VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
546                                 0,
547                                 render_pass,
548                                 2, attachments,
549                                 width, height, 1,
550                                 frame);
551
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));
557                         }
558                 }
559         }
560
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));
564
565                         vertexBuffer.setAtIndex(0, vertex.buffer);
566
567                         /* ***************************************** */
568                         vi_binding.setBinding(0);
569                         vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
570                         vi_binding.setStride(Cube.dataStride);
571
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);
580                 }
581         }
582
583         void init_pipeline() throws Exception {
584                 int res;
585                 try ( Frame frame = Frame.frame()) {
586                         IntArray dynamicStateEnables = IntArray.create(frame,
587                                 VK_DYNAMIC_STATE_VIEWPORT,
588                                 VK_DYNAMIC_STATE_SCISSOR);
589
590                         VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
591                                 0,
592                                 2, dynamicStateEnables,
593                                 frame);
594
595                         VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
596                                 0,
597                                 (int)vi_binding.length(), vi_binding,
598                                 (int)vi_attribs.length(), vi_attribs,
599                                 frame);
600
601                         VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
602                                 0,
603                                 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
604                                 0,
605                                 frame);
606
607                         VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
608                                 0,
609                                 VK_TRUE,
610                                 VK_FALSE,
611                                 VK_POLYGON_MODE_FILL,
612                                 VK_CULL_MODE_BACK_BIT,
613                                 VK_FRONT_FACE_CLOCKWISE,
614                                 VK_FALSE,
615                                 0.0f,
616                                 0.0f,
617                                 0.0f,
618                                 1.0f,
619                                 frame);
620
621                         VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
622                                 VK_FALSE,
623                                 VK_BLEND_FACTOR_ZERO,
624                                 VK_BLEND_FACTOR_ZERO,
625                                 VK_BLEND_OP_ADD,
626                                 VK_BLEND_FACTOR_ZERO,
627                                 VK_BLEND_FACTOR_ZERO,
628                                 VK_BLEND_OP_ADD,
629                                 0xf,
630                                 frame);
631
632                         VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
633                                 0,
634                                 VK_FALSE,
635                                 VK_LOGIC_OP_NO_OP,
636                                 1, att_state,
637                                 1.0f, 1.0f, 1.0f, 1.0f,
638                                 frame);
639
640                         VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
641                                 0,
642                                 1, null,
643                                 1, null,
644                                 frame);
645
646                         VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
647                                 0,
648                                 VK_TRUE,
649                                 VK_TRUE,
650                                 VK_COMPARE_OP_LESS_OR_EQUAL,
651                                 VK_FALSE,
652                                 VK_FALSE,
653                                 0.0f,
654                                 0.0f,
655                                 frame);
656                         VkStencilOpState back = ds.getBack();
657
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);
665
666                         VkStencilOpState front = ds.getFront();
667
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);
675
676                         VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
677                                 0,
678                                 NUM_SAMPLES,
679                                 0, //.sampleShadingEnable = VK_FALSE,
680                                 0.0f,
681                                 null,
682                                 0, //.alphaToCoverageEnable = VK_FALSE,
683                                 0, //.alphaToOneEnable = VK_FALSE,
684                                 frame
685                         );
686
687                         VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
688                                 0,
689                                 cube_vs.length() * 4,
690                                 cube_vs,
691                                 frame);
692                         VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
693                                 0,
694                                 cube_fs.length() * 4,
695                                 cube_fs,
696                                 frame);
697
698                         shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
699                         shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
700
701                         VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
702
703                         shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
704                         shaderStages.setName("main", (SegmentAllocator)scope);
705                         shaderStages.setModule(shader.get(0));
706
707                         shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
708                         shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
709                         shaderStages.setModuleAtIndex(1, shader.get(1));
710
711                         VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
712                                 0,
713                                 2, shaderStages,
714                                 vi,
715                                 ia,
716                                 null,
717                                 vp,
718                                 rs,
719                                 ms,
720                                 ds,
721                                 cb,
722                                 dynamicState,
723                                 pipeline_layout,
724                                 render_pass,
725                                 0,
726                                 null,
727                                 0,
728                                 frame);
729
730                         res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
731
732                         VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
733                         chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
734
735                         VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
736                         drawFence = device.vkCreateFence(fenceInfo, scope);
737                 }
738         }
739
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(
744                                 0,
745                                 null,
746                                 frame);
747
748                         cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
749                 }
750         }
751
752         void execute_end_command_buffer() throws Exception {
753                 cmd.getAtIndex(0).vkEndCommandBuffer();
754         }
755
756         final static long FENCE_TIMEOUT = 100000000;
757
758         void execute_queue_command_buffer() throws Exception {
759                 int res;
760
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);
767
768                         fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
769
770                         VkSubmitInfo submit_info = VkSubmitInfo.create(
771                                 1, null, pipe_stage_flags,
772                                 (int)cmd.length(), cmd,
773                                 0, null,
774                                 frame);
775
776                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
777
778                         do {
779                                 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
780                         } while (res == VK_TIMEOUT);
781
782                         device.vkDestroyFence(fences.getAtIndex(0));
783                 }
784         }
785
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,
791                                 frame);
792                         cmd.vkCmdSetViewport(0, 1, viewport);
793                 }
794         }
795
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);
801                 }
802         }
803
804         void cmd_paint() throws Exception {
805                 int res;
806                 try ( Frame frame = Frame.frame()) {
807                         int chainIndex;
808                         IntArray chainIndices = IntArray.createArray(1, frame);
809                         VkCommandBuffer cmd = this.cmd.getAtIndex(0);
810
811                         device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
812                         chainIndex = chainIndices.getAtIndex(0);
813                         LongArray offsets = LongArray.createArray(1, frame);
814
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);
824
825                         System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
826
827                         VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
828                                 render_pass,
829                                 framebuffers.getAtIndex(chainIndex),
830                                 0, 0, width, height,
831                                 2, clear_values,
832                                 frame);
833
834                         cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
835
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);
839
840                         cmd_viewport();
841                         cmd_scissors();
842
843                         cmd.vkCmdDraw(12 * 3, 1, 0, 0);
844                         cmd.vkCmdEndRenderPass();
845
846                         cmd.vkEndCommandBuffer();
847
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);
850
851                         semaphores.setAtIndex(0, chainSemaphore);
852
853                         VkSubmitInfo submit_info = VkSubmitInfo.create(
854                                 1, semaphores, pipe_stage_flags,
855                                 (int)this.cmd.length(), this.cmd,
856                                 0, null,
857                                 frame);
858
859                         HandleArray<VkFence> fences = VkFence.createArray(1, frame);
860
861                         fences.setAtIndex(0, drawFence);
862
863                         // Queue the command buffer for execution
864                         device.vkResetFences(1, fences);
865
866                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
867
868                         // Make sure command buffer is finished before presenting
869                         do {
870                                 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
871                         } while (res == VK_TIMEOUT);
872
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(
877                                 0, null,
878                                 1, chains, chainIndices, null,
879                                 frame);
880
881                         present_queue.vkQueuePresentKHR(present);
882                 }
883         }
884
885         /**
886          * Buffers are created in three steps:
887          * 1) create buffer, specifying usage and size
888          * 2) allocate memory based on memory requirements
889          * 3) bind memory
890          * <p>
891          */
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(
896                                 0,
897                                 dataSize,
898                                 usage,
899                                 VK_SHARING_MODE_EXCLUSIVE,
900                                 0, null,
901                                 frame);
902
903                         VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
904
905                         device.vkGetBufferMemoryRequirements(buffer, req);
906
907                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
908                                 req.getSize(),
909                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
910                                 frame);
911
912                         VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
913
914                         if (init != null) {
915                                 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
916                                 mem.copyFrom(init);
917                                 device.vkUnmapMemory(memory);
918                         }
919
920                         device.vkBindBufferMemory(buffer, memory, 0);
921
922                         return new BufferMemory(buffer, memory, dataSize);
923                 }
924         }
925
926         void shutdown() {
927                 device.vkDestroyFence(drawFence);
928                 device.vkDestroySemaphore(chainSemaphore);
929
930                 device.vkDestroyPipeline(pipeline.getAtIndex(0));
931                 for (int i = 0; i < shader.size(); i++)
932                         device.vkDestroyShaderModule(shader.getAtIndex(i));
933
934                 vertex.free(device);
935                 uniform.free(device);
936
937                 for (int i = 0; i < framebuffers.size(); i++)
938                         device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
939
940                 device.vkDestroyRenderPass(render_pass);
941
942                 device.vkDestroyDescriptorPool(desc_pool);
943                 device.vkDestroyPipelineLayout(pipeline_layout);
944                 device.vkDestroyDescriptorSetLayout(desc_layout);
945
946                 device.vkDestroyImageView(depthView);
947                 device.vkFreeMemory(depthMemory);
948                 device.vkDestroyImage(depthImage);
949
950                 for (int i = 0; i < chainImageView.size(); i++)
951                         device.vkDestroyImageView(chainImageView.getAtIndex(i));
952
953                 device.vkDestroySwapchainKHR(chain);
954
955                 device.vkDestroyCommandPool(cmd_pool);
956                 device.vkDestroyDevice();
957
958                 instance.vkDestroySurfaceKHR(surface);
959                 window.close();
960                 display.close();
961
962                 if (logger != null)
963                         instance.vkDestroyDebugUtilsMessengerEXT(logger);
964                 instance.vkDestroyInstance();
965         }
966
967         /**
968          * This finds the memory type index for the memory on a specific device.
969          */
970         static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
971                 VkMemoryType mtypes = memory.getMemoryTypes();
972
973                 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
974                         if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
975                                 return i;
976                 }
977                 return -1;
978         }
979
980         static int clampi(int v, int min, int max) {
981                 return v < min ? min : v < max ? v : max;
982         }
983
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];
989
990                 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
991                 lookAt(view, eye, centre, up);
992                 identity4f(model);
993                 mult4x4f(t0, clip, projection);
994                 mult4x4f(t1, t0, view);
995                 mult4x4f(mvp, t1, model);
996         }
997
998         void demo() throws Exception {
999                 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
1000                 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
1001
1002                 init_matrices();
1003
1004                 init_instance();
1005                 init_debug();
1006                 init_surface();
1007                 init_device();
1008                 init_device_queue();
1009
1010                 init_command();
1011                 init_depth();
1012                 init_uniform();
1013
1014                 init_descriptor();
1015                 init_render();
1016                 init_framebuffer();
1017                 init_vertexbuffer();
1018                 init_pipeline();
1019
1020                 execute_begin_command_buffer();
1021
1022                 cmd_paint();
1023
1024                 System.out.println("Any key to quit");
1025                 Event e;
1026 outer:  while ((e = window.nextEvent(true)) != null) {
1027                         switch (e.type) {
1028                         case Event.KEY:
1029                         case Event.CLOSE:
1030                                 break outer;
1031                         }
1032                 }
1033
1034                 shutdown();
1035         }
1036
1037         public static void main(String[] args) throws Throwable {
1038                 System.loadLibrary("vulkan");
1039                 System.loadLibrary("X11");
1040
1041                 new TestCube().demo();
1042         }
1043 }