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