051ee4dc7174b101c6301ba2924046ec7a55f34e
[demo] / src / vulkan / vkutil.cc
1 #include <vulkan/vulkan.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <string>
7 #include <vector>
8
9 #include "vkutil.h"
10
11 /* global variables */
12
13 VkSwapchainKHR vkswapchain;
14 VkImage *vkswapchain_images;
15 int vknext_swapchain_image;
16 VkSurfaceKHR vksurface;
17 VkInstance vkinst;
18 VkPhysicalDevice vkpdev;
19 VkDevice vkdev;
20 VkQueue vkq;
21 VkCommandPool vkcmdpool;
22 VkCommandBuffer vkcmdbuf;       /* primary command buffer */
23 int vkqfamily;
24
25 /* static functions */
26 static const char *get_device_name_str(VkPhysicalDeviceType type);
27 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags);
28 static const char *get_queue_flags_str(VkQueueFlags flags);
29 static const char *get_mem_size_str(long sz);
30 static int ver_major(uint32_t ver);
31 static int ver_minor(uint32_t ver);
32 static int ver_patch(uint32_t ver);
33
34 /* static variables */
35 static VkPhysicalDevice *phys_devices;
36
37 static int sel_dev;
38 static int sel_qfamily;
39
40 static VkExtensionProperties *vkext, *vkdevext;
41 static uint32_t vkext_count, vkdevext_count;
42
43 bool vku_have_extension(const char *name)
44 {
45         if(!vkext) {
46                 vkext_count = 0;
47                 vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0);
48                 if(vkext_count) {
49                         if(!(vkext = (VkExtensionProperties *)malloc(vkext_count * sizeof *vkext))) {
50                                 perror("failed to allocate instance extension list");
51                                 return false;
52                         }
53                         vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext);
54
55                         printf("instance extensions:\n");
56                         for(int i=0; i<(int)vkext_count; i++) {
57                                 printf(" %s (ver: %u)\n", vkext[i].extensionName, (unsigned int)vkext[i].specVersion);
58                         }
59                 }
60         }
61
62         for(int i=0; i<(int)vkext_count; i++) {
63                 if(strcmp(vkext[i].extensionName, name) == 0) {
64                         return true;
65                 }
66         }
67         return false;
68 }
69
70 bool vku_have_device_extension(const char *name)
71 {
72         if(sel_dev < 0) return false;
73
74         if(!vkdevext) {
75                 vkdevext_count = 0;
76                 vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0);
77                 if(vkdevext_count) {
78                         if(!(vkdevext = (VkExtensionProperties *)malloc(vkdevext_count * sizeof *vkdevext))) {
79                                 perror("failed to allocate device extension list");
80                                 return false;
81                         }
82                         vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext);
83
84                         printf("selected device extensions:\n");
85                         for(int i=0; i<(int)vkdevext_count; i++) {
86                                 printf(" %s (ver: %u)\n", vkdevext[i].extensionName, (unsigned int)vkdevext[i].specVersion);
87                         }
88                 }
89         }
90
91         for(int i=0; i<(int)vkdevext_count; i++) {
92                 if(strcmp(vkdevext[i].extensionName, name) == 0) {
93                         return true;
94                 }
95         }
96         return false;
97 }
98
99 bool vku_create_device()
100 {
101         VkInstanceCreateInfo inst_info;
102         VkDeviceCreateInfo dev_info;
103         VkDeviceQueueCreateInfo queue_info;
104         VkCommandPoolCreateInfo cmdpool_info;
105         uint32_t num_devices;
106         float qprio = 0.0f;
107
108         static const char *ext_names[] = {
109                 "VK_KHR_xcb_surface",
110                 "VK_KHR_surface"
111         };
112
113         static const char *devext_names[] = {
114                 "VK_KHR_swapchain"
115         };
116
117         sel_dev = -1;
118         sel_qfamily = -1;
119
120         for(unsigned int i=0; i<sizeof ext_names / sizeof *ext_names; i++) {
121                 if(!vku_have_extension(ext_names[i])) {
122                         fprintf(stderr, "required extension (%s) not found\n", ext_names[i]);
123                         return false;
124                 }
125         }
126         memset(&inst_info, 0, sizeof inst_info);
127         inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
128         inst_info.ppEnabledExtensionNames = ext_names;
129         inst_info.enabledExtensionCount = sizeof ext_names / sizeof *ext_names;
130
131         if(vkCreateInstance(&inst_info, 0, &vkinst) != 0) {
132                 fprintf(stderr, "failed to create vulkan instance\n");
133                 return false;
134         }
135         printf("created vulkan instance\n");
136         if(vkEnumeratePhysicalDevices(vkinst, &num_devices, 0) != 0) {
137                 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
138                 return false;
139         }
140         phys_devices = (VkPhysicalDevice *)malloc(num_devices * sizeof *phys_devices);
141         if(vkEnumeratePhysicalDevices(vkinst, &num_devices, phys_devices) != 0) {
142                 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
143                 return false;
144         }
145         printf("found %u physical device(s)\n", (unsigned int)num_devices);
146
147         for(int i=0; i<(int)num_devices; i++) {
148                 VkPhysicalDeviceProperties dev_prop;
149                 VkPhysicalDeviceMemoryProperties mem_prop;
150                 VkQueueFamilyProperties *qprop;
151                 uint32_t qprop_count;
152
153                 vkGetPhysicalDeviceProperties(phys_devices[i], &dev_prop);
154
155                 printf("Device %d: %s\n", i, dev_prop.deviceName);
156                 printf("  type: %s\n", get_device_name_str(dev_prop.deviceType));
157                 printf("  API version: %d.%d.%d\n", ver_major(dev_prop.apiVersion), ver_minor(dev_prop.apiVersion),
158                        ver_patch(dev_prop.apiVersion));
159                 printf("  driver version: %d.%d.%d\n", ver_major(dev_prop.driverVersion), ver_minor(dev_prop.driverVersion),
160                        ver_patch(dev_prop.driverVersion));
161                 printf("  vendor id: %x  device id: %x\n", dev_prop.vendorID, dev_prop.deviceID);
162
163
164                 vkGetPhysicalDeviceMemoryProperties(phys_devices[i], &mem_prop);
165                 printf("  %d memory heaps:\n", mem_prop.memoryHeapCount);
166                 for(unsigned int j=0; j<mem_prop.memoryHeapCount; j++) {
167                         VkMemoryHeap heap = mem_prop.memoryHeaps[j];
168                         printf("    Heap %d - size: %s, flags: %s\n", j, get_mem_size_str(heap.size),
169                                heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ? "device-local" : "-");
170                 }
171                 printf("  %d memory types:\n", mem_prop.memoryTypeCount);
172                 for(unsigned int j=0; j<mem_prop.memoryTypeCount; j++) {
173                         VkMemoryType type = mem_prop.memoryTypes[j];
174                         printf("    Type %d - heap: %d, flags: %s\n", j, type.heapIndex,
175                                get_memtype_flags_str(type.propertyFlags));
176                 }
177
178                 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, 0);
179                 if(qprop_count <= 0) {
180                         continue;
181                 }
182                 qprop = (VkQueueFamilyProperties *)malloc(qprop_count * sizeof *qprop);
183                 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, qprop);
184
185                 for(unsigned int j=0; j<qprop_count; j++) {
186                         printf("  Queue family %d:\n", j);
187                         printf("    flags: %s\n", get_queue_flags_str(qprop[j].queueFlags));
188                         printf("    num queues: %u\n", qprop[j].queueCount);
189
190                         if(qprop[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
191                                 sel_dev = i;
192                                 sel_qfamily = j;
193                         }
194                 }
195                 free(qprop);
196         }
197
198         if(sel_dev < 0 || sel_qfamily < 0) {
199                 fprintf(stderr, "failed to find any device with a graphics-capable command queue\n");
200                 vkDestroyDevice(vkdev, 0);
201                 return false;
202         }
203
204         for(unsigned int i=0; i<sizeof devext_names / sizeof *devext_names; i++) {
205                 if(!vku_have_device_extension(devext_names[i])) {
206                         fprintf(stderr, "required extension (%s) not found on the selected device (%d)\n",
207                                 ext_names[i], sel_dev);
208                         return false;
209                 }
210         }
211
212         /* create device & command queue */
213         memset(&queue_info, 0, sizeof queue_info);
214         queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
215         queue_info.queueFamilyIndex = sel_qfamily;
216         queue_info.queueCount = 1;
217         queue_info.pQueuePriorities = &qprio;
218
219         memset(&dev_info, 0, sizeof dev_info);
220         dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
221         dev_info.queueCreateInfoCount = 1;
222         dev_info.pQueueCreateInfos = &queue_info;
223         dev_info.enabledExtensionCount = sizeof devext_names / sizeof *devext_names;
224         dev_info.ppEnabledExtensionNames = devext_names;
225
226         if(vkCreateDevice(phys_devices[sel_dev], &dev_info, 0, &vkdev) != 0) {
227                 fprintf(stderr, "failed to create device %d\n", sel_dev);
228                 return false;
229         }
230         printf("created device %d\n", sel_dev);
231
232         vkpdev = phys_devices[sel_dev];
233         vkqfamily = sel_qfamily;
234
235         vkGetDeviceQueue(vkdev, sel_qfamily, 0, &vkq);
236
237         /* create command buffer pool */
238         memset(&cmdpool_info, 0, sizeof cmdpool_info);
239         cmdpool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
240         cmdpool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
241         cmdpool_info.queueFamilyIndex = sel_qfamily;
242
243         if(vkCreateCommandPool(vkdev, &cmdpool_info, 0, &vkcmdpool) != 0) {
244                 fprintf(stderr, "failed to get command quque!\n");
245                 return false;
246         }
247
248         if(!(vkcmdbuf = vku_alloc_cmdbuf(vkcmdpool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))) {
249                 fprintf(stderr, "failed to create primary command buffer\n");
250                 return false;
251         }
252
253         return true;
254 }
255
256 void vku_cleanup()
257 {
258         if(vkinst) {
259                 vkDeviceWaitIdle(vkdev);
260                 vkDestroyCommandPool(vkdev, vkcmdpool, 0);
261                 vkDestroyDevice(vkdev, 0);
262                 vkDestroyInstance(vkinst, 0);
263                 vkinst = 0;
264         }
265
266         free(phys_devices);
267         phys_devices = 0;
268 }
269
270 VkCommandBuffer vku_alloc_cmdbuf(VkCommandPool pool, VkCommandBufferLevel level)
271 {
272         VkCommandBuffer cmdbuf;
273         VkCommandBufferAllocateInfo inf;
274
275         memset(&inf, 0, sizeof inf);
276         inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
277         inf.commandPool = pool;
278         inf.level = level;
279         inf.commandBufferCount = 1;
280
281         if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
282                 return 0;
283         }
284         return cmdbuf;
285 }
286
287 void vku_free_cmdbuf(VkCommandPool pool, VkCommandBuffer buf)
288 {
289         vkFreeCommandBuffers(vkdev, pool, 1, &buf);
290 }
291
292 void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags)
293 {
294         VkCommandBufferBeginInfo inf;
295
296         memset(&inf, 0, sizeof inf);
297         inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
298         inf.flags = flags;
299
300         vkBeginCommandBuffer(buf, &inf);
301 }
302
303
304 void vku_end_cmdbuf(VkCommandBuffer buf)
305 {
306         vkEndCommandBuffer(buf);
307 }
308
309 void vku_reset_cmdbuf(VkCommandBuffer buf)
310 {
311         vkResetCommandBuffer(buf, 0);
312 }
313
314 void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence)
315 {
316         VkSubmitInfo info;
317
318         memset(&info, 0, sizeof info);
319         info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
320         info.commandBufferCount = 1;
321         info.pCommandBuffers = &buf;
322
323         vkQueueSubmit(q, 1, &info, done_fence);
324 }
325
326 VkSwapchainKHR vku_create_swapchain(VkSurfaceKHR surf, int xsz, int ysz, int n,
327                                     VkPresentModeKHR pmode, VkSwapchainKHR prev)
328 {
329         VkSwapchainKHR sc;
330         VkSwapchainCreateInfoKHR inf;
331
332         memset(&inf, 0, sizeof inf);
333         inf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
334         inf.surface = surf;
335         inf.minImageCount = n;
336         inf.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;     /* TODO enumerate and choose */
337         inf.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
338         inf.imageExtent.width = xsz;
339         inf.imageExtent.height = ysz;
340         inf.imageArrayLayers = 1;
341         inf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
342         inf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;       /* XXX make this an option? */
343         inf.preTransform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
344         inf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
345         inf.presentMode = pmode;
346         inf.oldSwapchain = prev;
347
348         if(vkCreateSwapchainKHR(vkdev, &inf, 0, &sc) != 0) {
349                 return 0;
350         }
351         return sc;
352 }
353
354 VkImage *vku_get_swapchain_images(VkSwapchainKHR sc, int *count)
355 {
356         uint32_t nimg;
357         VkImage *images;
358
359         if(vkGetSwapchainImagesKHR(vkdev, sc, &nimg, 0) != 0) {
360                 return 0;
361         }
362         if(!(images = (VkImage *)malloc(nimg * sizeof *images))) {
363                 return 0;
364         }
365         vkGetSwapchainImagesKHR(vkdev, sc, &nimg, images);
366
367         if(count) *count = (int)nimg;
368         return images;
369 }
370
371 int vku_get_next_image(VkSwapchainKHR sc)
372 {
373         uint32_t next;
374
375         if(vkAcquireNextImageKHR(vkdev, sc, UINT64_MAX, 0, 0, &next) != 0) {
376                 return -1;
377         }
378         return (int)next;
379 }
380
381 void vku_present(VkSwapchainKHR sc, int img_idx)
382 {
383         VkPresentInfoKHR inf;
384         VkResult res;
385         uint32_t index = img_idx;
386
387         memset(&inf, 0, sizeof inf);
388         inf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
389         inf.swapchainCount = 1;
390         inf.pSwapchains = &sc;
391         inf.pImageIndices = &index;
392         inf.pResults = &res;
393
394         vkQueuePresentKHR(vkq, &inf);
395 }
396
397 struct vku_buffer *vku_create_buffer(int sz, unsigned int usage)
398 {
399         struct vku_buffer *buf;
400         VkBufferCreateInfo binfo;
401
402         if(!(buf = (vku_buffer *)malloc(sizeof *buf))) {
403                 perror("failed to allocate vk_buffer structure");
404                 return 0;
405         }
406
407         memset(&binfo, 0, sizeof binfo);
408         binfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
409         binfo.size = sz;
410         binfo.usage = usage;
411         binfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
412
413         if(vkCreateBuffer(vkdev, &binfo, 0, &buf->buf) != 0) {
414                 fprintf(stderr, "failed to create %d byte buffer (usage: %x)\n", sz, usage);
415                 return 0;
416         }
417         // TODO back with memory
418         return buf;
419 }
420
421 void vku_destroy_buffer(struct vku_buffer *buf)
422 {
423         if(buf) {
424                 vkDestroyBuffer(vkdev, buf->buf, 0);
425                 free(buf);
426         }
427 }
428
429 void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
430                      VkBuffer src, int soffs, int size)
431 {
432         VkBufferCopy copy;
433         copy.size = size;
434         copy.srcOffset = soffs;
435         copy.dstOffset = doffs;
436
437         vkCmdCopyBuffer(cmdbuf, src, dest, 1, &copy);
438 }
439
440 /* paste
441
442 static bool create_instance()
443 {
444         uint32_t layer_count = 0;
445         std::vector<const char *> enabled_layers;
446
447         if(vkEnumerateInstanceLayerProperties(&layer_count, 0) != VK_SUCCESS) {
448                 fprintf(stderr, "Failed to query layer properties.\n");
449                 return false;
450         }
451
452         if(layer_count > 0) {
453                 VkLayerProperties *layers = (VkLayerProperties *)alloca(layer_count * sizeof *layers);
454                 vkEnumerateInstanceLayerProperties(&layer_count, layers);
455                 for(uint32_t i=0; i<layer_count; i++) {
456                         if(strcmp(layers[i].layerName, "VK_LAYER_LUNARG_standard_validation")) {
457                                 enabled_layers.push_back(layers[i].layerName);
458                         }
459                 }
460         }
461
462         uint32_t extensions_count = 0;
463         std::vector<const char *> enabled_extensions;
464
465         if(vkEnumerateInstanceExtensionProperties(0, &extensions_count, 0) != VK_SUCCESS) {
466                 fprintf(stderr, "Failed to enumerate instance extension properties\n");
467                 return false;
468         }
469
470         if(extensions_count > 0) {
471                 VkExtensionProperties *extensions = (VkExtensionProperties *)alloca(extensions_count * sizeof *extensions);
472                 vkEnumerateInstanceExtensionProperties(0, &extensions_count, extensions);
473
474                 for(uint32_t i=0; i<extensions_count; i++) {
475                         printf("Extension %u: %s %u.\n", i, extensions[i].extensionName, extensions[i].specVersion);
476                         //enable all the available extensions
477                         enabled_extensions.push_back(extensions[i].extensionName);
478                         enabled_extension_names.push_back(std::string(extensions[i].extensionName));
479                 }
480         }
481
482         VkInstanceCreateInfo create_info;
483         memset(&create_info, 0, sizeof create_info);
484         create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
485
486         if(!enabled_layers.empty()) {
487                 create_info.enabledLayerCount = enabled_layers.size();
488                 create_info.ppEnabledLayerNames = enabled_layers.data();
489         }
490
491         if(!enabled_extensions.empty()) {
492                 create_info.enabledExtensionCount = enabled_extensions.size();
493                 create_info.ppEnabledExtensionNames = enabled_extensions.data();
494         }
495
496         if(vkCreateInstance(&create_info, 0, &inst) != VK_SUCCESS) {
497                 fprintf(stderr, "Failed to create instance.\n");
498                 return false;
499         }
500
501         if(!create_device())
502                 return false;
503
504         return true;
505 }
506
507 static bool create_device()
508 {
509         int qfam_idx = -1;
510         int pdev_idx = -1;
511
512         uint32_t dev_count;
513         if(vkEnumeratePhysicalDevices(inst, &dev_count, 0) != VK_SUCCESS) {
514                 fprintf(stderr, "Failed to enumerate physical devices.\n");
515                 return false;
516         }
517         printf("%u devices found.\n", (unsigned int)dev_count);
518
519         VkPhysicalDevice *phys_dev = (VkPhysicalDevice *)alloca(dev_count * sizeof *phys_dev);
520         vkEnumeratePhysicalDevices(inst, &dev_count, phys_dev);
521         VkPhysicalDeviceMemoryProperties memprop;
522
523         for(uint32_t i=0; i<dev_count; i++) {
524                 VkPhysicalDeviceProperties dev_props;
525                 vkGetPhysicalDeviceProperties(phys_dev[i], &dev_props);
526
527                 //memory heaps:
528                 vkGetPhysicalDeviceMemoryProperties(phys_dev[i], &memprop);
529                 printf("\tNumber of heaps: %u\n", memprop.memoryHeapCount);
530                 for(uint32_t j=0; j<memprop.memoryHeapCount; j++) {
531                         printf("\t\tHeap %u size: %lu\n", j, (unsigned long)memprop.memoryHeaps[j].size);
532                         printf("\t\tHeap %u flags: %s\n", j, heap_flags_str(memprop.memoryHeaps[j].flags));
533                 }
534                 //memory types
535                 printf("\tMemory types: %u\n", memprop.memoryTypeCount);
536                 for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
537                         printf("\t\tType %u heap index: %u\n", j, memprop.memoryTypes[j].heapIndex);
538                         printf("\t\tType %u flags: %s\n", j, memtype_flags_str(memprop.memoryTypes[j].propertyFlags));
539                 }
540
541                 //supported features
542                 VkPhysicalDeviceFeatures features;
543                 vkGetPhysicalDeviceFeatures(phys_dev[i], &features);
544
545                 //queue families
546                 uint32_t qfam_count;
547                 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, 0);
548                 printf("\tQueue Families: %u\n", qfam_count);
549                 VkQueueFamilyProperties *qfam_props = new VkQueueFamilyProperties[qfam_count];
550                 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, qfam_props);
551                 for(uint32_t j=0; j<qfam_count; j++) {
552                         printf("\t\tFamily %u flags: %s\n", j, queue_flags_str(qfam_props[j].queueFlags));
553                         printf("\t\tFamily %u number of queues: %u\n", j, qfam_props[j].queueCount);
554
555                         if((qfam_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (pdev_idx == -1)) {
556                                 pdev_idx = i;
557                                 qfam_idx = j;
558                                 num_queues = qfam_props[j].queueCount;
559                         }
560                 }
561                 delete [] qfam_props;
562         }
563
564         if(pdev_idx == -1) {
565                 fprintf(stderr, "No suitable devices found.\n");
566                 return false;
567         }
568
569         pdev = *(phys_dev + pdev_idx);
570         qfamily_idx = qfam_idx;
571
572                 uint32_t layer_count;
573                 if(vkEnumerateDeviceLayerProperties(pdev, &layer_count, 0) != VK_SUCCESS) {
574                         fprintf(stderr, "Failed to enumerate device layers.\n");
575                         return false;
576                 }
577                 if(layer_count > 0) {
578                         VkLayerProperties *layers = (VkLayerProperties*)alloca(layer_count * sizeof *layers);
579                         vkEnumerateDeviceLayerProperties(pdev, &layer_count, layers);
580                         printf("%u layers found.\n", layer_count);
581                         for(uint32_t i=0; i<layer_count; i++) {
582                                 printf("Layer %u: %s (%u, %u)\n", i, layers[i].layerName,
583                                                 layers[i].specVersion, layers[i].implementationVersion);
584                                 printf("\tDesc: %s\n", layers[i].description);
585                         }
586                 }
587
588         VkDeviceCreateInfo dev_info;
589         memset(&dev_info, 0, sizeof dev_info);
590         dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
591
592         VkDeviceQueueCreateInfo dev_qinfo;
593         memset(&dev_qinfo, 0, sizeof dev_qinfo);
594         dev_qinfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
595         dev_qinfo.queueFamilyIndex = qfam_idx;
596         dev_qinfo.queueCount = 1;
597
598         dev_info.queueCreateInfoCount = 1;
599         dev_info.pQueueCreateInfos = &dev_qinfo;
600
601         if(vkCreateDevice(pdev, &dev_info, 0, &device) != VK_SUCCESS) {
602                 fprintf(stderr, "Failed to create logical device.\n");
603                 return false;
604         }
605
606         vkGetPhysicalDeviceMemoryProperties(pdev, &memprop);
607         for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
608                 if(memprop.memoryTypes[j].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
609                         device_mem_idx = j;
610                         printf("Selected device memory index: %u\n", device_mem_idx);
611                         break;
612                 }
613         }
614
615         return true;
616 }
617
618 static const char *dev_type_str(VkPhysicalDeviceType type)
619 {
620         switch(type) {
621         case VK_PHYSICAL_DEVICE_TYPE_OTHER:
622                 return "other";
623         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
624                 return "integrated GPU";
625         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
626                 return "discrete GPU";
627         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
628                 return "virtual GPU";
629         case VK_PHYSICAL_DEVICE_TYPE_CPU:
630                 return "CPU";
631         default:
632                 break;
633         }
634         return "unknown";
635 }
636
637 static const char *heap_flags_str(VkMemoryHeapFlags flags)
638 {
639         static std::string str;
640         str.clear();
641         if(flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
642                 str += "device-local ";
643         }
644         if(!str.empty())
645                 str.pop_back();
646         return str.c_str();
647 }
648
649 static const char *memtype_flags_str(VkMemoryPropertyFlags flags)
650 {
651         static std::string str;
652         str.clear();
653         if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
654                 str += "device-local ";
655         }
656         if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
657                 str += "host-visible ";
658         }
659         if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
660                 str += "host-coherent ";
661         }
662         if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
663                 str += "host-cached ";
664         }
665         if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
666                 str += "lazily-allocated ";
667         }
668         if(!str.empty())
669                 str.pop_back();
670         return str.c_str();
671 }
672
673 static const char *queue_flags_str(VkQueueFlags flags)
674 {
675         static std::string str;
676         str.clear();
677         if(flags & VK_QUEUE_GRAPHICS_BIT)
678                 str += "graphics ";
679         if(flags & VK_QUEUE_COMPUTE_BIT)
680                 str += "compute ";
681         if(flags & VK_QUEUE_TRANSFER_BIT)
682                 str += "transfer ";
683         if(flags & VK_QUEUE_SPARSE_BINDING_BIT)
684                 str += "sparse-binding ";
685         if(!str.empty())
686                 str.pop_back();
687         return str.c_str();
688 }
689 */
690
691 const char *vku_get_vulkan_error_str(VkResult error)
692 {
693         std::string errmsg;
694         switch(error) {
695         case VK_SUCCESS:
696                 errmsg = std::string("VK_SUCCESS");
697                 break;
698         case VK_NOT_READY:
699                 errmsg = std::string("VK_NOT_READY");
700                 break;
701         case VK_TIMEOUT:
702                 errmsg = std::string("VK_TIMEOUT");
703                 break;
704         case VK_EVENT_SET:
705                 errmsg = std::string("VK_EVENT_SET");
706                 break;
707         case VK_EVENT_RESET:
708                 errmsg = std::string("VK_EVENT_RESET");
709                 break;
710         case VK_INCOMPLETE:
711                 errmsg = std::string("VK_EVENT");
712                 break;
713         case VK_ERROR_OUT_OF_HOST_MEMORY:
714                 errmsg = std::string("VK_ERROR_OUT_OF_HOST_MEMORY");
715                 break;
716         case VK_ERROR_OUT_OF_DEVICE_MEMORY:
717                 errmsg = std::string("VK_ERROR_OUT_OF_DEVICE_MEMORY");
718                 break;
719         case VK_ERROR_INITIALIZATION_FAILED:
720                 errmsg = std::string("VK_ERROR_INITIALIZATION_FAILED");
721                 break;
722         case VK_ERROR_DEVICE_LOST:
723                 errmsg = std::string("VK_ERROR_DEVICE_LOST");
724                 break;
725         case VK_ERROR_MEMORY_MAP_FAILED:
726                 errmsg = std::string("VK_ERROR_MEMORY_MAP_FAILED");
727                 break;
728         case VK_ERROR_LAYER_NOT_PRESENT:
729                 errmsg = std::string("VK_ERROR_LAYER_NOT_PRESENT");
730                 break;
731         case VK_ERROR_EXTENSION_NOT_PRESENT:
732                 errmsg = std::string("VK_ERROR_EXTENSION_NOT_PRESENT");
733                 break;
734         case VK_ERROR_FEATURE_NOT_PRESENT:
735                 errmsg = std::string("VK_ERROR_FEATURE_NOT_PRESENT");
736                 break;
737         case VK_ERROR_INCOMPATIBLE_DRIVER:
738                 errmsg = std::string("VK_ERROR_INCOMPATIBLE_DRIVER");
739                 break;
740         case VK_ERROR_TOO_MANY_OBJECTS:
741                 errmsg = std::string("VK_ERROR_TOO_MANY_OBJECTS");
742                 break;
743         case VK_ERROR_FORMAT_NOT_SUPPORTED:
744                 errmsg = std::string("VK_ERROR_FORMAT_NOT_SUPPORTED");
745                 break;
746         case VK_ERROR_FRAGMENTED_POOL:
747                 errmsg = std::string("VK_ERROR_FRAGMENTED_POOL");
748                 break;
749         default:
750                 errmsg = std::string("UNKNOWN");
751                 break;
752         }
753
754         return errmsg.c_str();
755 }
756
757 static const char *get_device_name_str(VkPhysicalDeviceType type)
758 {
759         switch(type) {
760         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
761                 return "integrated GPU";
762         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
763                 return "discrete GPU";
764         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
765                 return "virtual GPU";
766         case VK_PHYSICAL_DEVICE_TYPE_CPU:
767                 return "CPU";
768         default:
769                 break;
770         }
771         return "unknown";
772 }
773
774 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags)
775 {
776         static char str[128];
777
778         str[0] = 0;
779         if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
780                 strcat(str, "device-local ");
781         }
782         if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
783                 strcat(str, "host-visible ");
784         }
785         if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
786                 strcat(str, "host-coherent ");
787         }
788         if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
789                 strcat(str, "host-cached ");
790         }
791         if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
792                 strcat(str, "lazily-allocated ");
793         }
794
795         if(!*str) {
796                 strcat(str, "-");
797         }
798         return str;
799 }
800
801 static const char *get_queue_flags_str(VkQueueFlags flags)
802 {
803         static char str[128];
804
805         str[0] = 0;
806         if(flags & VK_QUEUE_GRAPHICS_BIT) {
807                 strcat(str, "graphics ");
808         }
809         if(flags & VK_QUEUE_COMPUTE_BIT) {
810                 strcat(str, "compute ");
811         }
812         if(flags & VK_QUEUE_TRANSFER_BIT) {
813                 strcat(str, "transfer ");
814         }
815         if(flags & VK_QUEUE_SPARSE_BINDING_BIT) {
816                 strcat(str, "sparse-binding ");
817         }
818         if(!*str) {
819                 strcat(str, "-");
820         }
821         return str;
822 }
823
824 static int ver_major(uint32_t ver)
825 {
826         return (ver >> 22) & 0x3ff;
827 }
828
829 static int ver_minor(uint32_t ver)
830 {
831         return (ver >> 12) & 0x3ff;
832 }
833
834 static int ver_patch(uint32_t ver)
835 {
836         return ver & 0xfff;
837 }
838
839 static const char *get_mem_size_str(long sz)
840 {
841         static char str[64];
842         static const char *unitstr[] = { "bytes", "KB", "MB", "GB", "TB", "PB", 0 };
843         int uidx = 0;
844         sz *= 10;
845
846         while(sz >= 10240 && unitstr[uidx + 1]) {
847                 sz /= 1024;
848                 ++uidx;
849         }
850         sprintf(str, "%ld.%ld %s", sz / 10, sz % 10, unitstr[uidx]);
851         return str;
852 }