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