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