df5d7e8c98bbaaa9be0369c96635161d74a53235
[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(frame,
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
144                         logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
145                 }
146
147                 //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
148         }
149
150         void init_instance() throws Exception {
151                 try ( Frame frame = Frame.frame()) {
152                         VkInstanceCreateInfo info = VkInstanceCreateInfo.create(frame,
153                                 0,
154                                 VkApplicationInfo.create(frame, "cube", 1, "cube-engine", 2, VK_API_VERSION_1_0),
155                                 new String[]{"VK_LAYER_KHRONOS_validation"},
156                                 new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"}
157                         );
158
159                         instance = VkInstance.vkCreateInstance(info, scope);
160                         System.out.printf("instance = %s\n", instance);
161                 }
162         }
163
164         Display display;
165         Window window;
166         VkSurfaceKHR surface;
167
168         void init_surface() throws Exception {
169                 display = Display.createX11Display();
170                 window = display.createWindow(width, height);
171                 surface = window.createVulkanSurface(instance, scope);
172                 System.out.printf("surface: %s\n", surface);
173         }
174
175         void init_device() throws Exception {
176                 try ( Frame frame = Frame.frame()) {
177                         IntArray count$h = IntArray.create(frame, 1);
178                         IntArray present$h = IntArray.create(frame, 1);
179                         HandleArray<VkPhysicalDevice> devs;
180                         int count;
181                         int res;
182
183                         devs = instance.vkEnumeratePhysicalDevices(frame, scope);
184
185                         // Search for device and queue indices
186                         int devid = -1;
187                         int present_queue = -1;
188                         int graphics_queue = -1;
189                         for (int i = 0; i < devs.length(); i++) {
190                                 VkPhysicalDevice dev = devs.getAtIndex(i);
191                                 VkQueueFamilyProperties famprops;
192
193                                 famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
194
195                                 for (int j = 0; j < famprops.length(); j++) {
196                                         boolean present;
197
198                                         dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface, present$h);
199                                         present = present$h.get(0) != 0;
200
201                                         if (present && present_queue == -1)
202                                                 present_queue = j;
203                                         if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
204                                                 graphics_queue = j;
205                                                 if (present) {
206                                                         present_queue = j;
207                                                         break;
208                                                 }
209                                         }
210                                 }
211                                 if (present_queue != -1 && graphics_queue != -1) {
212                                         devid = i;
213                                         break;
214                                 }
215                         }
216
217                         if (devid == -1)
218                                 throw new Exception("Cannot find a suitable device");
219
220                         physicalDevice = devs.getAtIndex(devid);
221                         present_queue_index = present_queue;
222                         graphics_queue_index = graphics_queue;
223
224                         // NOTE: app scope
225                         memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
226                         physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
227                         device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
228                         physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
229
230                         FloatArray qpri = FloatArray.create(frame, 0.0f);
231                         VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
232                                 frame,
233                                 0,
234                                 graphics_queue,
235                                 qpri);
236                         String[] extensions = {
237                                 "VK_KHR_swapchain"
238                         };
239                         VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
240                         features.setDepthClamp(1);
241                         VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
242                                 frame,
243                                 0,
244                                 qinfo,
245                                 null,
246                                 extensions,
247                                 features);
248
249                         device = physicalDevice.vkCreateDevice(devinfo, scope);
250
251                         System.out.printf("device = %s\n", device);
252
253                         /* ************************************************************** */
254                         int format;
255                         VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
256                         // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
257                         // the surface has no preferred format.  Otherwise, at least one
258                         // supported format will be returned.
259                         if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
260                                 format = VK_FORMAT_B8G8R8A8_UNORM;
261                         } else {
262                                 format = surfFormats.getFormatAtIndex(0);
263                         }
264
265                         VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
266
267                         physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
268                         IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
269
270                         VkExtent2D swapchainExtent;
271                         // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
272                         if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
273                                 // If the surface size is undefined, the size is set to
274                                 // the size of the images requested.
275                                 swapchainExtent = VkExtent2D.create(frame,
276                                         clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
277                                         clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()));
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(frame,
296                                 0,
297                                 surface,
298                                 surfCapabilities.getMinImageCount(),
299                                 format,
300                                 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
301                                 1, //.imageArrayLayers = 1,
302                                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
303                                 VK_SHARING_MODE_EXCLUSIVE,
304                                 // assumes queues are same.
305                                 null,
306                                 (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
307                                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
308                                 compositeAlpha,
309                                 VK_PRESENT_MODE_FIFO_KHR,
310                                 VK_TRUE,
311                                 null);
312                         chaininfo.getImageExtent().setWidth(swapchainExtent.getWidth());
313                         chaininfo.getImageExtent().setHeight(swapchainExtent.getHeight());
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(frame,
324                                 0,
325                                 null,
326                                 VK_IMAGE_VIEW_TYPE_2D,
327                                 format);
328                         VkComponentMapping components = viewinfo.getComponents();
329                         components.setR(VK_COMPONENT_SWIZZLE_R);
330                         components.setG(VK_COMPONENT_SWIZZLE_G);
331                         components.setB(VK_COMPONENT_SWIZZLE_B);
332                         components.setA(VK_COMPONENT_SWIZZLE_A);
333                         VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
334                         subresourceRange.setAspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
335                         subresourceRange.setLevelCount(1);
336                         subresourceRange.setLayerCount(1);
337
338                         for (int i = 0; i < chainImageCount; i++) {
339                                 viewinfo.setImage(chainImage.get(i));
340
341                                 chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
342                         }
343
344                         chainImageFormat = format;
345                 }
346         }
347
348         void init_device_queue() {
349                 graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
350                 if (graphics_queue_index == present_queue_index) {
351                         present_queue = graphics_queue;
352                 } else {
353                         present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
354                 }
355         }
356
357         void init_command() throws Exception {
358                 try ( Frame frame = Frame.frame()) {
359                         VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(frame,
360                                 0,
361                                 graphics_queue_index);
362
363                         cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
364
365                         VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(frame,
366                                 cmd_pool,
367                                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
368                                 1);
369
370                         cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
371                 }
372         }
373
374         // parameterise as init_image?
375         void init_depth() throws Exception {
376                 try ( Frame frame = Frame.frame()) {
377                         int format = VK_FORMAT_D16_UNORM;
378                         VkMemoryRequirements req = VkMemoryRequirements.create(frame);
379                         VkImageCreateInfo imageinfo = VkImageCreateInfo.create(frame, 0,
380                                 VK_IMAGE_TYPE_2D,
381                                 format,
382                                 1,
383                                 1,
384                                 NUM_SAMPLES,
385                                 0,
386                                 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
387                                 VK_SHARING_MODE_EXCLUSIVE,
388                                 null,
389                                 VK_IMAGE_LAYOUT_UNDEFINED);
390                         imageinfo.getExtent().setWidth(width);
391                         imageinfo.getExtent().setHeight(height);
392                         imageinfo.getExtent().setDepth(1);
393
394                         depthImage = device.vkCreateImage(imageinfo, scope);
395
396                         device.vkGetImageMemoryRequirements(depthImage, req);
397                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
398                                 req.getSize(),
399                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
400
401                         depthMemory = device.vkAllocateMemory(alloc, scope);
402
403                         device.vkBindImageMemory(depthImage, depthMemory, 0);
404
405                         VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(frame, 0,
406                                 depthImage,
407                                 VK_IMAGE_VIEW_TYPE_2D,
408                                 VK_FORMAT_D16_UNORM);
409
410                         VkComponentMapping components = viewinfo.getComponents();
411                         components.setR(VK_COMPONENT_SWIZZLE_R);
412                         components.setG(VK_COMPONENT_SWIZZLE_G);
413                         components.setB(VK_COMPONENT_SWIZZLE_B);
414                         components.setA(VK_COMPONENT_SWIZZLE_A);
415                         VkImageSubresourceRange subresourceRange = viewinfo.getSubresourceRange();
416                         subresourceRange.setAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
417                         subresourceRange.setLevelCount(1);
418                         subresourceRange.setLayerCount(1);
419
420                         depthView = device.vkCreateImageView(viewinfo, scope);
421
422                         depthFormat = format;
423                 }
424         }
425
426         void init_uniform() throws Exception {
427                 uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp));
428         }
429
430         void init_descriptor() throws Exception {
431                 try ( Frame frame = Frame.frame()) {
432                         HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
433                         VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(frame,
434                                 0,
435                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
436                                 1,
437                                 VK_SHADER_STAGE_VERTEX_BIT,
438                                 null);
439                         VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(frame,
440                                 0,
441                                 layout_binding);
442
443                         desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
444                         layout_table.setAtIndex(0, desc_layout);
445
446                         VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(frame,
447                                 0,
448                                 //1,
449                                 layout_table,
450                                 null);
451
452                         pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
453
454                         VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(frame,
455                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
456                                 1);
457
458                         VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(frame,
459                                 0,
460                                 1,
461                                 type_count);
462
463                         desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
464
465                         VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(frame,
466                                 desc_pool,
467                                 //1,
468                                 layout_table);
469
470                         System.out.println(alloc_info);
471
472                         desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope);
473
474                         VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(frame, uniform.buffer, 0, uniform.size);
475                         VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(frame,
476                                 desc_set.getAtIndex(0),
477                                 0,
478                                 0,
479                                 1,
480                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
481                                 null,
482                                 uniformInfo,
483                                 null);
484
485                         device.vkUpdateDescriptorSets(1, writes, 0, null);
486                 }
487         }
488
489         void init_render() throws Exception {
490                 try ( Frame frame = Frame.frame()) {
491                         VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
492
493                         attachments.setFormat(chainImageFormat);
494                         attachments.setSamples(NUM_SAMPLES);
495                         attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
496                         attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
497                         attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
498                         attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
499                         attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
500                         attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
501                         attachments.setFlags(0);
502
503                         attachments.setFormatAtIndex(1, depthFormat);
504                         attachments.setSamplesAtIndex(1, NUM_SAMPLES);
505                         attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
506                         attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
507                         attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
508                         attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
509                         attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
510                         attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
511                         attachments.setFlagsAtIndex(1, 0);
512
513                         VkAttachmentReference color_reference = VkAttachmentReference.create(frame,
514                                 0,
515                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
516
517                         VkAttachmentReference depth_reference = VkAttachmentReference.create(frame,
518                                 1,
519                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
520
521                         VkSubpassDescription subpass = VkSubpassDescription.create(frame,
522                                 0,
523                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
524                                 null,
525                                 1,
526                                 color_reference,
527                                 null,
528                                 depth_reference,
529                                 null);
530
531                         VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(frame,
532                                 0,
533                                 //(int)attachments.length(),
534                                 attachments,
535                                 subpass,
536                                 null);
537
538                         render_pass = device.vkCreateRenderPass(rp_info, scope);
539                 }
540         }
541
542         void init_framebuffer() throws Exception {
543                 try ( Frame frame = Frame.frame()) {
544                         HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
545
546                         attachments.setAtIndex(1, depthView);
547
548                         // FIXME: I don't think i want lenghts implied for types tbh
549                         VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(frame,
550                                 0,
551                                 render_pass,
552                                 //2,
553                                 attachments,
554                                 width,
555                                 height,
556                                 1);
557
558                         framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
559                         for (int i = 0; i < chainImage.size(); i++) {
560                                 attachments.setAtIndex(0, chainImageView.get(i));
561                                 framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
562                                 System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
563                         }
564                 }
565         }
566
567         void init_vertexbuffer() throws Exception {
568                 try ( Frame frame = Frame.frame()) {
569                         vertex = init_buffer(Cube.data.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(Cube.data));
570
571                         vertexBuffer.setAtIndex(0, vertex.buffer);
572
573                         /* ***************************************** */
574                         vi_binding.setBinding(0);
575                         vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
576                         vi_binding.setStride(Cube.dataStride);
577
578                         vi_attribs.setBinding(0);
579                         vi_attribs.setLocation(0);
580                         vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
581                         vi_attribs.setOffset(0);
582                         vi_attribs.setBindingAtIndex(1, 0);
583                         vi_attribs.setLocationAtIndex(1, 1);
584                         vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
585                         vi_attribs.setOffsetAtIndex(1, 16);
586                 }
587         }
588
589         void init_pipeline() throws Exception {
590                 int res;
591                 try ( Frame frame = Frame.frame()) {
592                         IntArray dynamicStateEnables = IntArray.create(frame,
593                                 VK_DYNAMIC_STATE_VIEWPORT,
594                                 VK_DYNAMIC_STATE_SCISSOR);
595
596                         VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(frame,
597                                 0, dynamicStateEnables);
598
599                         VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(frame,
600                                 0,
601                                 vi_binding,
602                                 vi_attribs);
603
604                         VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(frame,
605                                 0,
606                                 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
607                                 0);
608
609                         VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(frame,
610                                 0,
611                                 VK_TRUE,
612                                 VK_FALSE,
613                                 VK_POLYGON_MODE_FILL,
614                                 VK_CULL_MODE_BACK_BIT,
615                                 VK_FRONT_FACE_CLOCKWISE,
616                                 VK_FALSE,
617                                 0.0f,
618                                 0.0f,
619                                 0.0f,
620                                 1.0f);
621
622                         VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(frame,
623                                 VK_FALSE,
624                                 VK_BLEND_FACTOR_ZERO,
625                                 VK_BLEND_FACTOR_ZERO,
626                                 VK_BLEND_OP_ADD,
627                                 VK_BLEND_FACTOR_ZERO,
628                                 VK_BLEND_FACTOR_ZERO,
629                                 VK_BLEND_OP_ADD,
630                                 0xf);
631
632                         VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(frame,
633                                 0,
634                                 VK_FALSE,
635                                 VK_LOGIC_OP_NO_OP,
636                                 att_state,
637                                 1.0f, 1.0f, 1.0f, 1.0f);
638
639                         VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(frame,
640                                 0,
641                                 1, null,
642                                 1, null);
643
644                         VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(frame,
645                                 0,
646                                 VK_TRUE,
647                                 VK_TRUE,
648                                 VK_COMPARE_OP_LESS_OR_EQUAL,
649                                 VK_FALSE,
650                                 VK_FALSE,
651                                 0.0f,
652                                 0.0f);
653                         VkStencilOpState back = ds.getBack();
654
655                         back.setFailOp(VK_STENCIL_OP_KEEP);
656                         back.setPassOp(VK_STENCIL_OP_KEEP);
657                         back.setCompareOp(VK_COMPARE_OP_ALWAYS);
658                         back.setCompareMask(0);
659                         back.setReference(0);
660                         back.setDepthFailOp(VK_STENCIL_OP_KEEP);
661                         back.setWriteMask(0);
662
663                         VkStencilOpState front = ds.getFront();
664
665                         front.setFailOp(VK_STENCIL_OP_KEEP);
666                         front.setPassOp(VK_STENCIL_OP_KEEP);
667                         front.setCompareOp(VK_COMPARE_OP_ALWAYS);
668                         front.setCompareMask(0);
669                         front.setReference(0);
670                         front.setDepthFailOp(VK_STENCIL_OP_KEEP);
671                         front.setWriteMask(0);
672
673                         VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(frame,
674                                 0,
675                                 NUM_SAMPLES,
676                                 0, //.sampleShadingEnable = VK_FALSE,
677                                 0.0f,
678                                 null,
679                                 0, //.alphaToCoverageEnable = VK_FALSE,
680                                 0 //.alphaToOneEnable = VK_FALSE,
681                         );
682
683                         VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(frame,
684                                 0,
685                                 cube_vs.length() * 4,
686                                 cube_vs);
687                         VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(frame,
688                                 0,
689                                 cube_fs.length() * 4,
690                                 cube_fs);
691
692                         shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
693                         shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
694
695                         VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
696
697                         // FIXME: createArray should initialise this
698                         shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
699                         shaderStages.setName("main", (SegmentAllocator)scope);
700                         shaderStages.setModule(shader.get(0));
701
702                         shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
703                         shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
704                         shaderStages.setModuleAtIndex(1, shader.get(1));
705
706                         VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(frame,
707                                 0,
708                                 //2, shaderStages,
709                                 shaderStages,
710                                 vi,
711                                 ia,
712                                 null,
713                                 vp,
714                                 rs,
715                                 ms,
716                                 ds,
717                                 cb,
718                                 dynamicState,
719                                 pipeline_layout,
720                                 render_pass,
721                                 0,
722                                 null,
723                                 0);
724
725                         res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
726
727                         VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(frame, 0);
728                         chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
729
730                         VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
731                         drawFence = device.vkCreateFence(fenceInfo, scope);
732                 }
733         }
734
735         void execute_begin_command_buffer() throws Exception {
736                 /* DEPENDS on init_command() */
737                 try ( Frame frame = Frame.frame()) {
738                         VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(frame,
739                                 0,
740                                 null);
741
742                         cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
743                 }
744         }
745
746         void execute_end_command_buffer() throws Exception {
747                 cmd.getAtIndex(0).vkEndCommandBuffer();
748         }
749
750         final static long FENCE_TIMEOUT = 100000000;
751
752         void execute_queue_command_buffer() throws Exception {
753                 int res;
754
755                 /* Queue the command buffer for execution */
756  /* FIXME: frame shoudl provide or take explicit scope */
757                 try ( ResourceScope scope = ResourceScope.newConfinedScope();  Frame frame = Frame.frame()) {
758                         IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
759                         VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame, 0);
760                         HandleArray<VkFence> fences = VkFence.createArray(1, frame);
761
762                         fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
763
764                         VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
765                                 1, null, pipe_stage_flags,
766                                 cmd,
767                                 null);
768
769                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
770
771                         do {
772                                 res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
773                         } while (res == VK_TIMEOUT);
774
775                         device.vkDestroyFence(fences.getAtIndex(0));
776                 }
777         }
778
779         void cmd_viewport() {
780                 try ( Frame frame = Frame.frame()) {
781                         VkCommandBuffer cmd = this.cmd.getAtIndex(0);
782                         VkViewport viewport = VkViewport.create(frame,
783                                 0, 0, width, height, 0.0f, 1.0f);
784                         cmd.vkCmdSetViewport(0, 1, viewport);
785                 }
786         }
787
788         void cmd_scissors() {
789                 try ( Frame frame = Frame.frame()) {
790                         VkCommandBuffer cmd = this.cmd.getAtIndex(0);
791                         VkRect2D scissor = VkRect2D.create(frame);
792                         VkExtent2D extent = scissor.getExtent();
793
794                         extent.setWidth(width);
795                         extent.setHeight(height);
796
797                         cmd.vkCmdSetScissor(0, 1, scissor);
798                 }
799         }
800
801         void cmd_paint() throws Exception {
802                 int res;
803                 try ( Frame frame = Frame.frame()) {
804                         int chainIndex;
805                         IntArray chainIndices = IntArray.createArray(1, frame);
806                         VkCommandBuffer cmd = this.cmd.getAtIndex(0);
807
808                         device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
809                         chainIndex = chainIndices.getAtIndex(0);
810                         LongArray offsets = LongArray.createArray(1, frame);
811
812                         VkClearValue clear_values = VkClearValue.createArray(2, frame);
813                         FloatArray col = clear_values.getColor().getFloat32();
814                         col.setAtIndex(0, 0.2f);
815                         col.setAtIndex(1, 0.2f);
816                         col.setAtIndex(2, 0.2f);
817                         col.setAtIndex(3, 0.2f);
818                         VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
819                         depthStencil.setDepth(1.0f);
820                         depthStencil.setStencil(0);
821
822                         System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
823
824                         VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(frame,
825                                 render_pass,
826                                 framebuffers.getAtIndex(chainIndex),
827                                 clear_values);
828                         VkExtent2D extent = rp_begin.getRenderArea().getExtent();
829                         extent.setWidth(width);
830                         extent.setHeight(height);
831
832                         cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
833
834                         cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
835                         cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
836                         cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
837
838                         cmd_viewport();
839                         cmd_scissors();
840
841                         cmd.vkCmdDraw(12 * 3, 1, 0, 0);
842                         cmd.vkCmdEndRenderPass();
843
844                         cmd.vkEndCommandBuffer();
845
846                         IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
847                         HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
848
849                         semaphores.setAtIndex(0, chainSemaphore);
850
851                         VkSubmitInfo submit_info = VkSubmitInfo.create(frame,
852                                 1, semaphores, pipe_stage_flags,
853                                 this.cmd,
854                                 null);
855
856                         HandleArray<VkFence> fences = VkFence.createArray(1, frame);
857
858                         fences.setAtIndex(0, drawFence);
859
860                         // Queue the command buffer for execution
861                         device.vkResetFences(1, fences);
862
863                         graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
864
865                         // Make sure command buffer is finished before presenting
866                         do {
867                                 res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
868                         } while (res == VK_TIMEOUT);
869
870                         // Now present the image in the window
871                         HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
872                         chains.setAtIndex(0, chain);
873                         VkPresentInfoKHR present = VkPresentInfoKHR.create(frame,
874                                 null,
875                                 1,
876                                 chains,
877                                 chainIndices,
878                                 null);
879
880                         present_queue.vkQueuePresentKHR(present);
881                 }
882         }
883
884         /**
885          * Buffers are created in three steps:
886          * 1) create buffer, specifying usage and size
887          * 2) allocate memory based on memory requirements
888          * 3) bind memory
889          * <p>
890          */
891         BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
892                 try ( Frame frame = Frame.frame()) {
893                         VkMemoryRequirements req = VkMemoryRequirements.create(frame);
894                         VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(frame,
895                                 0,
896                                 dataSize,
897                                 usage,
898                                 VK_SHARING_MODE_EXCLUSIVE,
899                                 //0,
900                                 null);
901
902                         VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
903
904                         device.vkGetBufferMemoryRequirements(buffer, req);
905
906                         VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(frame,
907                                 req.getSize(),
908                                 find_memory_type(memory_properties, req.getMemoryTypeBits(), properties));
909
910                         VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
911
912                         if (init != null) {
913                                 MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
914                                 mem.copyFrom(init);
915                                 device.vkUnmapMemory(memory);
916                         }
917
918                         device.vkBindBufferMemory(buffer, memory, 0);
919
920                         return new BufferMemory(buffer, memory, dataSize);
921                 }
922         }
923
924         void shutdown() {
925                 device.vkDestroyFence(drawFence);
926                 device.vkDestroySemaphore(chainSemaphore);
927
928                 device.vkDestroyPipeline(pipeline.getAtIndex(0));
929                 for (int i = 0; i < shader.size(); i++)
930                         device.vkDestroyShaderModule(shader.getAtIndex(i));
931
932                 vertex.free(device);
933                 uniform.free(device);
934
935                 for (int i = 0; i < framebuffers.size(); i++)
936                         device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
937
938                 device.vkDestroyRenderPass(render_pass);
939
940                 device.vkDestroyDescriptorPool(desc_pool);
941                 device.vkDestroyPipelineLayout(pipeline_layout);
942                 device.vkDestroyDescriptorSetLayout(desc_layout);
943
944                 device.vkDestroyImageView(depthView);
945                 device.vkFreeMemory(depthMemory);
946                 device.vkDestroyImage(depthImage);
947
948                 for (int i = 0; i < chainImageView.size(); i++)
949                         device.vkDestroyImageView(chainImageView.getAtIndex(i));
950
951                 device.vkDestroySwapchainKHR(chain);
952
953                 device.vkDestroyCommandPool(cmd_pool);
954                 device.vkDestroyDevice();
955
956                 instance.vkDestroySurfaceKHR(surface);
957                 window.close();
958                 display.close();
959
960                 if (logger != null)
961                         instance.vkDestroyDebugUtilsMessengerEXT(logger);
962                 instance.vkDestroyInstance();
963         }
964
965         /**
966          * This finds the memory type index for the memory on a specific device.
967          */
968         static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
969                 VkMemoryType mtypes = memory.getMemoryTypes();
970
971                 for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
972                         if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
973                                 return i;
974                 }
975                 return -1;
976         }
977
978         static int clampi(int v, int min, int max) {
979                 return v < min ? min : v < max ? v : max;
980         }
981
982         void init_matrices() {
983                 float eye[] = new float[]{-5, 3, -10};
984                 float centre[] = new float[]{0, 0, 0};
985                 float up[] = new float[]{0, -1, 0};
986                 float t0[] = new float[16], t1[] = new float[16];
987
988                 perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
989                 lookAt(view, eye, centre, up);
990                 identity4f(model);
991                 mult4x4f(t0, clip, projection);
992                 mult4x4f(t1, t0, view);
993                 mult4x4f(mvp, t1, model);
994         }
995
996         void demo() throws Exception {
997                 cube_vs = ShaderIO.loadCube_vs((SegmentAllocator)scope);
998                 cube_fs = ShaderIO.loadCube_fs((SegmentAllocator)scope);
999
1000                 init_matrices();
1001
1002                 init_instance();
1003                 init_debug();
1004
1005                 init_surface();
1006                 init_device();
1007                 init_device_queue();
1008                 init_command();
1009                 init_depth();
1010                 init_uniform();
1011
1012                 init_descriptor();
1013                 init_render();
1014                 init_framebuffer();
1015                 init_vertexbuffer();
1016                 init_pipeline();
1017
1018                 execute_begin_command_buffer();
1019
1020                 cmd_paint();
1021
1022                 System.out.println("Any key to quit");
1023                 Event e;
1024 outer:  while ((e = window.nextEvent(true)) != null) {
1025                         switch (e.type) {
1026                         case Event.KEY:
1027                         case Event.CLOSE:
1028                                 break outer;
1029                         }
1030                 }
1031
1032                 shutdown();
1033         }
1034
1035         public static void main(String[] args) throws Throwable {
1036                 System.loadLibrary("vulkan");
1037                 System.loadLibrary("X11");
1038
1039                 new TestCube().demo();
1040         }
1041 }