1 #include <gmath/gmath.h>
2 #include <vulkan/vulkan.h>
10 #include "allocator.h"
13 /* global variables */
14 VkPhysicalDevice vk_physical;
16 VkCommandPool vk_pool;
18 VkSurfaceKHR vk_surface;
19 VkSwapchainKHR vk_swapchain;
21 VkPipeline *vkgparent_pipeline;
22 VkFramebuffer *vkfbufs;
25 VkCommandBuffer vkcmdbuf; /* primary command buffer */
28 VkSemaphore vk_img_avail_sema;
29 VkSemaphore vk_rend_done_sema;
30 VkImage *vkswapchain_images;
31 VkImageView *vkswapchain_views;
32 int vknum_swapchain_images;
33 int vk_curr_swapchain_image;
35 /* static functions */
36 static const char *get_device_name_str(VkPhysicalDeviceType type);
37 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags);
38 static const char *get_queue_flags_str(VkQueueFlags flags);
39 static const char *get_mem_size_str(long sz);
40 static int ver_major(uint32_t ver);
41 static int ver_minor(uint32_t ver);
42 static int ver_patch(uint32_t ver);
44 /* static variables */
45 static VkPhysicalDevice *phys_devices;
48 static int sel_qfamily;
50 static VkExtensionProperties *vkext, *vkdevext;
51 static uint32_t vkext_count, vkdevext_count;
53 bool vku_have_extension(const char *name)
57 vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0);
59 vkext = new VkExtensionProperties[vkext_count];
60 vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext);
62 printf("instance extensions:\n");
63 for(int i=0; i<(int)vkext_count; i++) {
64 printf(" %s (ver: %u)\n", vkext[i].extensionName, (unsigned int)vkext[i].specVersion);
69 for(int i=0; i<(int)vkext_count; i++) {
70 if(strcmp(vkext[i].extensionName, name) == 0) {
77 bool vku_have_device_extension(const char *name)
79 if(sel_dev < 0) return false;
83 vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0);
85 vkdevext = new VkExtensionProperties[vkdevext_count];
86 vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext);
88 printf("selected device extensions:\n");
89 for(int i=0; i<(int)vkdevext_count; i++) {
90 printf(" %s (ver: %u)\n", vkdevext[i].extensionName, (unsigned int)vkdevext[i].specVersion);
95 for(int i=0; i<(int)vkdevext_count; i++) {
96 if(strcmp(vkdevext[i].extensionName, name) == 0) {
103 bool vku_create_device()
105 VkInstanceCreateInfo inst_info;
106 VkDeviceCreateInfo dev_info;
107 VkDeviceQueueCreateInfo queue_info;
108 VkCommandPoolCreateInfo cmdpool_info;
109 uint32_t num_devices;
112 static const char *ext_names[] = {
113 "VK_KHR_xcb_surface",
117 static const char *devext_names[] = {
124 for(unsigned int i=0; i<sizeof ext_names / sizeof *ext_names; i++) {
125 if(!vku_have_extension(ext_names[i])) {
126 fprintf(stderr, "required extension (%s) not found\n", ext_names[i]);
130 memset(&inst_info, 0, sizeof inst_info);
131 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
132 inst_info.ppEnabledExtensionNames = ext_names;
133 inst_info.enabledExtensionCount = sizeof ext_names / sizeof *ext_names;
135 if(vkCreateInstance(&inst_info, 0, &vkinst) != 0) {
136 fprintf(stderr, "failed to create vulkan instance\n");
139 printf("created vulkan instance\n");
140 if(vkEnumeratePhysicalDevices(vkinst, &num_devices, 0) != 0) {
141 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
144 phys_devices = new VkPhysicalDevice[num_devices];
145 if(vkEnumeratePhysicalDevices(vkinst, &num_devices, phys_devices) != 0) {
146 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
149 printf("found %u physical device(s)\n", (unsigned int)num_devices);
151 for(int i=0; i<(int)num_devices; i++) {
152 VkPhysicalDeviceProperties dev_prop;
153 VkPhysicalDeviceMemoryProperties mem_prop;
154 VkQueueFamilyProperties *qprop;
155 uint32_t qprop_count;
157 vkGetPhysicalDeviceProperties(phys_devices[i], &dev_prop);
159 printf("Device %d: %s\n", i, dev_prop.deviceName);
160 printf(" type: %s\n", get_device_name_str(dev_prop.deviceType));
161 printf(" API version: %d.%d.%d\n", ver_major(dev_prop.apiVersion), ver_minor(dev_prop.apiVersion),
162 ver_patch(dev_prop.apiVersion));
163 printf(" driver version: %d.%d.%d\n", ver_major(dev_prop.driverVersion), ver_minor(dev_prop.driverVersion),
164 ver_patch(dev_prop.driverVersion));
165 printf(" vendor id: %x device id: %x\n", dev_prop.vendorID, dev_prop.deviceID);
168 vkGetPhysicalDeviceMemoryProperties(phys_devices[i], &mem_prop);
169 printf(" %d memory heaps:\n", mem_prop.memoryHeapCount);
170 for(unsigned int j=0; j<mem_prop.memoryHeapCount; j++) {
171 VkMemoryHeap heap = mem_prop.memoryHeaps[j];
172 printf(" Heap %d - size: %s, flags: %s\n", j, get_mem_size_str(heap.size),
173 heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ? "device-local" : "-");
175 printf(" %d memory types:\n", mem_prop.memoryTypeCount);
176 for(unsigned int j=0; j<mem_prop.memoryTypeCount; j++) {
177 VkMemoryType type = mem_prop.memoryTypes[j];
178 printf(" Type %d - heap: %d, flags: %s\n", j, type.heapIndex,
179 get_memtype_flags_str(type.propertyFlags));
182 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, 0);
183 if(qprop_count <= 0) {
186 qprop = new VkQueueFamilyProperties[qprop_count];
187 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, qprop);
189 for(unsigned int j=0; j<qprop_count; j++) {
190 printf(" Queue family %d:\n", j);
191 printf(" flags: %s\n", get_queue_flags_str(qprop[j].queueFlags));
192 printf(" num queues: %u\n", qprop[j].queueCount);
194 if(qprop[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
202 if(sel_dev < 0 || sel_qfamily < 0) {
203 fprintf(stderr, "failed to find any device with a graphics-capable command queue\n");
204 vkDestroyDevice(vk_device, 0);
208 for(unsigned int i=0; i<sizeof devext_names / sizeof *devext_names; i++) {
209 if(!vku_have_device_extension(devext_names[i])) {
210 fprintf(stderr, "required extension (%s) not found on the selected device (%d)\n",
211 ext_names[i], sel_dev);
216 /* create device & command queue */
217 memset(&queue_info, 0, sizeof queue_info);
218 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
219 queue_info.queueFamilyIndex = sel_qfamily;
220 queue_info.queueCount = 1;
221 queue_info.pQueuePriorities = &qprio;
223 memset(&dev_info, 0, sizeof dev_info);
224 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
225 dev_info.queueCreateInfoCount = 1;
226 dev_info.pQueueCreateInfos = &queue_info;
227 dev_info.enabledExtensionCount = sizeof devext_names / sizeof *devext_names;
228 dev_info.ppEnabledExtensionNames = devext_names;
230 if(vkCreateDevice(phys_devices[sel_dev], &dev_info, 0, &vk_device) != 0) {
231 fprintf(stderr, "failed to create device %d\n", sel_dev);
234 printf("created device %d\n", sel_dev);
236 vk_physical = phys_devices[sel_dev];
237 vkqfamily = sel_qfamily;
239 vkGetDeviceQueue(vk_device, sel_qfamily, 0, &vk_queue);
241 /* create command buffer pool */
242 memset(&cmdpool_info, 0, sizeof cmdpool_info);
243 cmdpool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
244 cmdpool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
245 cmdpool_info.queueFamilyIndex = sel_qfamily;
247 if(vkCreateCommandPool(vk_device, &cmdpool_info, 0, &vk_pool) != 0) {
248 fprintf(stderr, "failed to get command queue!\n");
252 /* if(!(vkcmdbuf = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))) {
253 fprintf(stderr, "failed to create primary command buffer\n");
263 vkDeviceWaitIdle(vk_device);
264 vkDestroyCommandPool(vk_device, vk_pool, 0);
266 vkDestroySemaphore(vk_device, vk_img_avail_sema, 0);
267 vkDestroySemaphore(vk_device, vk_rend_done_sema, 0);
269 vkDestroyDevice(vk_device, 0);
270 vkDestroyInstance(vkinst, 0);
274 delete [] phys_devices;
278 bool vku_create_semaphores()
280 VkSemaphoreCreateInfo sinf;
281 memset(&sinf, 0, sizeof sinf);
283 sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
284 if(vkCreateSemaphore(vk_device, &sinf, 0, &vk_img_avail_sema) != VK_SUCCESS) {
285 fprintf(stderr, "Failed to create semaphore\n");
289 if(vkCreateSemaphore(vk_device, &sinf, 0, &vk_rend_done_sema) != VK_SUCCESS) {
290 fprintf(stderr, "Failed to create semaphore\n");
297 VkCommandBuffer vku_alloc_cmdbuf(VkCommandPool pool, VkCommandBufferLevel level)
299 VkCommandBuffer cmdbuf;
300 VkCommandBufferAllocateInfo inf;
302 memset(&inf, 0, sizeof inf);
303 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
304 inf.commandPool = pool;
306 inf.commandBufferCount = 1;
308 if(vkAllocateCommandBuffers(vk_device, &inf, &cmdbuf) != 0) {
314 bool vku_alloc_cmdbufs(VkCommandPool pool, VkCommandBufferLevel level, unsigned int count, VkCommandBuffer *buf_array)
316 VkCommandBufferAllocateInfo cinf;
317 memset(&cinf, 0, sizeof cinf);
319 cinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
320 cinf.commandPool = vk_pool;
322 cinf.commandBufferCount = count;
324 if(vkAllocateCommandBuffers(vk_device, &cinf, buf_array) != VK_SUCCESS) {
325 fprintf(stderr, "Failed to allocate command buffer\n");
332 void vku_free_cmdbuf(VkCommandPool pool, VkCommandBuffer buf)
334 vkFreeCommandBuffers(vk_device, pool, 1, &buf);
337 void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags)
339 VkCommandBufferBeginInfo inf;
341 memset(&inf, 0, sizeof inf);
342 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
345 vkBeginCommandBuffer(buf, &inf);
349 void vku_end_cmdbuf(VkCommandBuffer buf)
351 vkEndCommandBuffer(buf);
354 void vku_reset_cmdbuf(VkCommandBuffer buf)
356 vkResetCommandBuffer(buf, 0);
359 void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence)
363 memset(&info, 0, sizeof info);
364 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
365 info.commandBufferCount = 1;
366 info.pCommandBuffers = &buf;
368 vkQueueSubmit(q, 1, &info, done_fence);
371 bool vku_get_surface_format(VkPhysicalDevice gpu, VkSurfaceKHR surface, VkSurfaceFormatKHR *sformat)
375 if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical,
376 vk_surface, &fcount, 0) != VK_SUCCESS) {
377 fprintf(stderr, "Failed to get format count for physical device.\n");
381 fprintf(stderr, "No color formats were found.\n");
385 VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[fcount];
386 if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical, vk_surface,
387 &fcount, formats) != VK_SUCCESS) {
389 fprintf(stderr, "Failed to get surface formats.\n");
393 *sformat = formats[0];
395 if((fcount == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
396 sformat->format = VK_FORMAT_B8G8R8_UNORM;
404 int vku_get_next_image(VkSwapchainKHR sc)
408 if(vkAcquireNextImageKHR(vk_device, sc, UINT64_MAX, 0, 0, &next) != 0) {
414 void vku_present(VkSwapchainKHR sc, int img_idx)
416 VkPresentInfoKHR inf;
418 uint32_t index = img_idx;
420 memset(&inf, 0, sizeof inf);
421 inf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
422 inf.swapchainCount = 1;
423 inf.pSwapchains = ≻
424 inf.pImageIndices = &index;
427 vkQueuePresentKHR(vk_queue, &inf);
430 struct vku_buffer *vku_create_buffer(int sz, unsigned int usage)
432 struct vku_buffer *buf;
433 VkBufferCreateInfo binfo;
435 buf = new vku_buffer;
437 memset(&binfo, 0, sizeof binfo);
438 binfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
441 binfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
443 if(vkCreateBuffer(vk_device, &binfo, 0, &buf->buf) != 0) {
444 fprintf(stderr, "failed to create %d byte buffer (usage: %x)\n", sz, usage);
448 VkMemoryRequirements mr;
449 vkGetBufferMemoryRequirements(vk_device, buf->buf, &mr);
452 if(!vku_allocate(mr.size, &block))
455 buf->mem_pool = block.dev_mem;
460 void vku_destroy_buffer(struct vku_buffer *buf)
463 vkDestroyBuffer(vk_device, buf->buf, 0);
468 void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
469 VkBuffer src, int soffs, int size)
473 copy.srcOffset = soffs;
474 copy.dstOffset = doffs;
476 vkCmdCopyBuffer(cmdbuf, src, dest, 1, ©);
479 const char *vku_get_vulkan_error_str(VkResult error)
484 errmsg = std::string("VK_SUCCESS");
487 errmsg = std::string("VK_NOT_READY");
490 errmsg = std::string("VK_TIMEOUT");
493 errmsg = std::string("VK_EVENT_SET");
496 errmsg = std::string("VK_EVENT_RESET");
499 errmsg = std::string("VK_EVENT");
501 case VK_ERROR_OUT_OF_HOST_MEMORY:
502 errmsg = std::string("VK_ERROR_OUT_OF_HOST_MEMORY");
504 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
505 errmsg = std::string("VK_ERROR_OUT_OF_DEVICE_MEMORY");
507 case VK_ERROR_INITIALIZATION_FAILED:
508 errmsg = std::string("VK_ERROR_INITIALIZATION_FAILED");
510 case VK_ERROR_DEVICE_LOST:
511 errmsg = std::string("VK_ERROR_DEVICE_LOST");
513 case VK_ERROR_MEMORY_MAP_FAILED:
514 errmsg = std::string("VK_ERROR_MEMORY_MAP_FAILED");
516 case VK_ERROR_LAYER_NOT_PRESENT:
517 errmsg = std::string("VK_ERROR_LAYER_NOT_PRESENT");
519 case VK_ERROR_EXTENSION_NOT_PRESENT:
520 errmsg = std::string("VK_ERROR_EXTENSION_NOT_PRESENT");
522 case VK_ERROR_FEATURE_NOT_PRESENT:
523 errmsg = std::string("VK_ERROR_FEATURE_NOT_PRESENT");
524 case VK_ERROR_INCOMPATIBLE_DRIVER:
525 errmsg = std::string("VK_ERROR_INCOMPATIBLE_DRIVER");
527 case VK_ERROR_TOO_MANY_OBJECTS:
528 errmsg = std::string("VK_ERROR_TOO_MANY_OBJECTS");
530 case VK_ERROR_FORMAT_NOT_SUPPORTED:
531 errmsg = std::string("VK_ERROR_FORMAT_NOT_SUPPORTED");
533 case VK_ERROR_FRAGMENTED_POOL:
534 errmsg = std::string("VK_ERROR_FRAGMENTED_POOL");
537 errmsg = std::string("UNKNOWN");
541 return errmsg.c_str();
545 static const char *get_device_name_str(VkPhysicalDeviceType type)
548 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
549 return "integrated GPU";
550 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
551 return "discrete GPU";
552 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
553 return "virtual GPU";
554 case VK_PHYSICAL_DEVICE_TYPE_CPU:
562 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags)
564 static char str[128];
567 if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
568 strcat(str, "device-local ");
570 if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
571 strcat(str, "host-visible ");
573 if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
574 strcat(str, "host-coherent ");
576 if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
577 strcat(str, "host-cached ");
579 if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
580 strcat(str, "lazily-allocated ");
589 static const char *get_queue_flags_str(VkQueueFlags flags)
591 static char str[128];
594 if(flags & VK_QUEUE_GRAPHICS_BIT) {
595 strcat(str, "graphics ");
597 if(flags & VK_QUEUE_COMPUTE_BIT) {
598 strcat(str, "compute ");
600 if(flags & VK_QUEUE_TRANSFER_BIT) {
601 strcat(str, "transfer ");
603 if(flags & VK_QUEUE_SPARSE_BINDING_BIT) {
604 strcat(str, "sparse-binding ");
612 static int ver_major(uint32_t ver)
614 return (ver >> 22) & 0x3ff;
617 static int ver_minor(uint32_t ver)
619 return (ver >> 12) & 0x3ff;
622 static int ver_patch(uint32_t ver)
627 static const char *get_mem_size_str(long sz)
630 static const char *unitstr[] = { "bytes", "KB", "MB", "GB", "TB", "PB", 0 };
634 while(sz >= 10240 && unitstr[uidx + 1]) {
638 sprintf(str, "%ld.%ld %s", sz / 10, sz % 10, unitstr[uidx]);