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