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