1 #include <vulkan/vulkan.h>
11 /* global variables */
13 VkPipeline *vkgraphics_pipeline;
14 VkFramebuffer *vkfbufs;
16 VkSwapchainKHR vkswapchain;
17 VkImage *vkswapchain_images;
18 VkImageView *vkswapchain_views;
19 int vknum_swapchain_images;
20 int vknext_swapchain_image;
21 VkSurfaceKHR vksurface;
23 VkPhysicalDevice vkpdev;
26 VkCommandPool vkcmdpool;
27 VkCommandBuffer vkcmdbuf; /* primary command buffer */
30 /* static functions */
31 static const char *get_device_name_str(VkPhysicalDeviceType type);
32 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags);
33 static const char *get_queue_flags_str(VkQueueFlags flags);
34 static const char *get_mem_size_str(long sz);
35 static int ver_major(uint32_t ver);
36 static int ver_minor(uint32_t ver);
37 static int ver_patch(uint32_t ver);
39 /* static variables */
40 static VkPhysicalDevice *phys_devices;
43 static int sel_qfamily;
45 static VkExtensionProperties *vkext, *vkdevext;
46 static uint32_t vkext_count, vkdevext_count;
48 bool vku_have_extension(const char *name)
52 vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0);
54 vkext = new VkExtensionProperties[vkext_count];
55 vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext);
57 printf("instance extensions:\n");
58 for(int i=0; i<(int)vkext_count; i++) {
59 printf(" %s (ver: %u)\n", vkext[i].extensionName, (unsigned int)vkext[i].specVersion);
64 for(int i=0; i<(int)vkext_count; i++) {
65 if(strcmp(vkext[i].extensionName, name) == 0) {
72 bool vku_have_device_extension(const char *name)
74 if(sel_dev < 0) return false;
78 vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0);
80 vkdevext = new VkExtensionProperties[vkdevext_count];
81 vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext);
83 printf("selected device extensions:\n");
84 for(int i=0; i<(int)vkdevext_count; i++) {
85 printf(" %s (ver: %u)\n", vkdevext[i].extensionName, (unsigned int)vkdevext[i].specVersion);
90 for(int i=0; i<(int)vkdevext_count; i++) {
91 if(strcmp(vkdevext[i].extensionName, name) == 0) {
98 bool vku_create_device()
100 VkInstanceCreateInfo inst_info;
101 VkDeviceCreateInfo dev_info;
102 VkDeviceQueueCreateInfo queue_info;
103 VkCommandPoolCreateInfo cmdpool_info;
104 uint32_t num_devices;
107 static const char *ext_names[] = {
108 "VK_KHR_xcb_surface",
112 static const char *devext_names[] = {
119 for(unsigned int i=0; i<sizeof ext_names / sizeof *ext_names; i++) {
120 if(!vku_have_extension(ext_names[i])) {
121 fprintf(stderr, "required extension (%s) not found\n", ext_names[i]);
125 memset(&inst_info, 0, sizeof inst_info);
126 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
127 inst_info.ppEnabledExtensionNames = ext_names;
128 inst_info.enabledExtensionCount = sizeof ext_names / sizeof *ext_names;
130 if(vkCreateInstance(&inst_info, 0, &vkinst) != 0) {
131 fprintf(stderr, "failed to create vulkan instance\n");
134 printf("created vulkan instance\n");
135 if(vkEnumeratePhysicalDevices(vkinst, &num_devices, 0) != 0) {
136 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
139 phys_devices = new VkPhysicalDevice[num_devices];
140 if(vkEnumeratePhysicalDevices(vkinst, &num_devices, phys_devices) != 0) {
141 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
144 printf("found %u physical device(s)\n", (unsigned int)num_devices);
146 for(int i=0; i<(int)num_devices; i++) {
147 VkPhysicalDeviceProperties dev_prop;
148 VkPhysicalDeviceMemoryProperties mem_prop;
149 VkQueueFamilyProperties *qprop;
150 uint32_t qprop_count;
152 vkGetPhysicalDeviceProperties(phys_devices[i], &dev_prop);
154 printf("Device %d: %s\n", i, dev_prop.deviceName);
155 printf(" type: %s\n", get_device_name_str(dev_prop.deviceType));
156 printf(" API version: %d.%d.%d\n", ver_major(dev_prop.apiVersion), ver_minor(dev_prop.apiVersion),
157 ver_patch(dev_prop.apiVersion));
158 printf(" driver version: %d.%d.%d\n", ver_major(dev_prop.driverVersion), ver_minor(dev_prop.driverVersion),
159 ver_patch(dev_prop.driverVersion));
160 printf(" vendor id: %x device id: %x\n", dev_prop.vendorID, dev_prop.deviceID);
163 vkGetPhysicalDeviceMemoryProperties(phys_devices[i], &mem_prop);
164 printf(" %d memory heaps:\n", mem_prop.memoryHeapCount);
165 for(unsigned int j=0; j<mem_prop.memoryHeapCount; j++) {
166 VkMemoryHeap heap = mem_prop.memoryHeaps[j];
167 printf(" Heap %d - size: %s, flags: %s\n", j, get_mem_size_str(heap.size),
168 heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ? "device-local" : "-");
170 printf(" %d memory types:\n", mem_prop.memoryTypeCount);
171 for(unsigned int j=0; j<mem_prop.memoryTypeCount; j++) {
172 VkMemoryType type = mem_prop.memoryTypes[j];
173 printf(" Type %d - heap: %d, flags: %s\n", j, type.heapIndex,
174 get_memtype_flags_str(type.propertyFlags));
177 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, 0);
178 if(qprop_count <= 0) {
181 qprop = new VkQueueFamilyProperties[qprop_count];
182 vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, qprop);
184 for(unsigned int j=0; j<qprop_count; j++) {
185 printf(" Queue family %d:\n", j);
186 printf(" flags: %s\n", get_queue_flags_str(qprop[j].queueFlags));
187 printf(" num queues: %u\n", qprop[j].queueCount);
189 if(qprop[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
197 if(sel_dev < 0 || sel_qfamily < 0) {
198 fprintf(stderr, "failed to find any device with a graphics-capable command queue\n");
199 vkDestroyDevice(vkdev, 0);
203 for(unsigned int i=0; i<sizeof devext_names / sizeof *devext_names; i++) {
204 if(!vku_have_device_extension(devext_names[i])) {
205 fprintf(stderr, "required extension (%s) not found on the selected device (%d)\n",
206 ext_names[i], sel_dev);
211 /* create device & command queue */
212 memset(&queue_info, 0, sizeof queue_info);
213 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
214 queue_info.queueFamilyIndex = sel_qfamily;
215 queue_info.queueCount = 1;
216 queue_info.pQueuePriorities = &qprio;
218 memset(&dev_info, 0, sizeof dev_info);
219 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
220 dev_info.queueCreateInfoCount = 1;
221 dev_info.pQueueCreateInfos = &queue_info;
222 dev_info.enabledExtensionCount = sizeof devext_names / sizeof *devext_names;
223 dev_info.ppEnabledExtensionNames = devext_names;
225 if(vkCreateDevice(phys_devices[sel_dev], &dev_info, 0, &vkdev) != 0) {
226 fprintf(stderr, "failed to create device %d\n", sel_dev);
229 printf("created device %d\n", sel_dev);
231 vkpdev = phys_devices[sel_dev];
232 vkqfamily = sel_qfamily;
234 vkGetDeviceQueue(vkdev, sel_qfamily, 0, &vkq);
236 /* create command buffer pool */
237 memset(&cmdpool_info, 0, sizeof cmdpool_info);
238 cmdpool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
239 cmdpool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
240 cmdpool_info.queueFamilyIndex = sel_qfamily;
242 if(vkCreateCommandPool(vkdev, &cmdpool_info, 0, &vkcmdpool) != 0) {
243 fprintf(stderr, "failed to get command quque!\n");
247 if(!(vkcmdbuf = vku_alloc_cmdbuf(vkcmdpool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))) {
248 fprintf(stderr, "failed to create primary command buffer\n");
258 vkDeviceWaitIdle(vkdev);
259 vkDestroyCommandPool(vkdev, vkcmdpool, 0);
260 vkDestroyDevice(vkdev, 0);
261 vkDestroyInstance(vkinst, 0);
265 delete [] phys_devices;
269 VkCommandBuffer vku_alloc_cmdbuf(VkCommandPool pool, VkCommandBufferLevel level)
271 VkCommandBuffer cmdbuf;
272 VkCommandBufferAllocateInfo inf;
274 memset(&inf, 0, sizeof inf);
275 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
276 inf.commandPool = pool;
278 inf.commandBufferCount = 1;
280 if(vkAllocateCommandBuffers(vkdev, &inf, &cmdbuf) != 0) {
286 void vku_free_cmdbuf(VkCommandPool pool, VkCommandBuffer buf)
288 vkFreeCommandBuffers(vkdev, pool, 1, &buf);
291 void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags)
293 VkCommandBufferBeginInfo inf;
295 memset(&inf, 0, sizeof inf);
296 inf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
299 vkBeginCommandBuffer(buf, &inf);
303 void vku_end_cmdbuf(VkCommandBuffer buf)
305 vkEndCommandBuffer(buf);
308 void vku_reset_cmdbuf(VkCommandBuffer buf)
310 vkResetCommandBuffer(buf, 0);
313 void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence)
317 memset(&info, 0, sizeof info);
318 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
319 info.commandBufferCount = 1;
320 info.pCommandBuffers = &buf;
322 vkQueueSubmit(q, 1, &info, done_fence);
325 VkSwapchainKHR vku_create_swapchain(VkSurfaceKHR surf, int xsz, int ysz, int n,
326 VkPresentModeKHR pmode, VkSwapchainKHR prev)
329 VkSwapchainCreateInfoKHR inf;
331 memset(&inf, 0, sizeof inf);
332 inf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
334 inf.minImageCount = n;
335 inf.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; /* TODO enumerate and choose */
336 inf.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
337 inf.imageExtent.width = xsz;
338 inf.imageExtent.height = ysz;
339 inf.imageArrayLayers = 1;
340 inf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
341 inf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* XXX make this an option? */
342 inf.preTransform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
343 inf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
344 inf.presentMode = pmode;
345 inf.oldSwapchain = prev;
347 if(vkCreateSwapchainKHR(vkdev, &inf, 0, &sc) != 0) {
353 VkImage *vku_get_swapchain_images(VkSwapchainKHR sc, int *count)
358 if(vkGetSwapchainImagesKHR(vkdev, sc, &nimg, 0) != 0) {
361 images = new VkImage[nimg];
362 vkGetSwapchainImagesKHR(vkdev, sc, &nimg, images);
364 if(count) *count = (int)nimg;
368 VkImageView *vku_create_image_views(VkImage *images, int count)
372 iviews = new VkImageView[count];
373 for(int i=0; i<count; i++) {
374 VkImageViewCreateInfo inf;
375 memset(&inf, 0, sizeof inf);
377 inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
378 inf.image = images[i];
379 inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
380 inf.format = VK_FORMAT_B8G8R8A8_UNORM; //TODO
381 inf.components.r = inf.components.g = inf.components.b =
382 inf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
383 inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
384 inf.subresourceRange.levelCount = 1;
385 inf.subresourceRange.layerCount = 1;
387 if(vkCreateImageView(vkdev, &inf, 0, iviews) != 0) {
388 fprintf(stderr, "Failed to create image views.\n");
397 int vku_get_next_image(VkSwapchainKHR sc)
401 if(vkAcquireNextImageKHR(vkdev, sc, UINT64_MAX, 0, 0, &next) != 0) {
407 void vku_present(VkSwapchainKHR sc, int img_idx)
409 VkPresentInfoKHR inf;
411 uint32_t index = img_idx;
413 memset(&inf, 0, sizeof inf);
414 inf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
415 inf.swapchainCount = 1;
416 inf.pSwapchains = ≻
417 inf.pImageIndices = &index;
420 vkQueuePresentKHR(vkq, &inf);
423 bool vku_create_renderpass()
425 VkAttachmentDescription attachments[2];
426 memset(&attachments, 0, 2 * sizeof *attachments);
429 attachments[0].format = VK_FORMAT_B8G8R8A8_UNORM;
430 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
431 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
432 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
433 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
434 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
435 attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
436 attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
439 attachments[1].format = VK_FORMAT_D32_SFLOAT_S8_UINT; //TODO
440 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
441 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
442 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
443 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
444 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
445 attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
446 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
448 VkAttachmentReference color_ref;
449 color_ref.attachment = 0;
450 color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
452 VkAttachmentReference depth_ref;
453 depth_ref.attachment = 1;
454 depth_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
456 VkSubpassDescription subpass_desc;
457 memset(&subpass_desc, 0, sizeof subpass_desc);
459 subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
460 subpass_desc.colorAttachmentCount = 1;
461 subpass_desc.pColorAttachments = &color_ref;
462 subpass_desc.pDepthStencilAttachment = &depth_ref;
464 VkRenderPassCreateInfo inf;
465 memset(&inf, 0, sizeof inf);
467 inf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
468 inf.attachmentCount = 2;
469 inf.pAttachments = attachments;
470 inf.subpassCount = 1;
471 inf.pSubpasses = &subpass_desc;
473 if(vkCreateRenderPass(vkdev, &inf, 0, &vkrpass) != VK_SUCCESS) {
480 bool vku_create_framebuffers(VkImageView *image_views, int count, int w, int h)
483 vkfbufs = new VkFramebuffer[count];
485 VkFramebufferCreateInfo inf;
486 memset(&inf, 0, sizeof inf);
488 inf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
489 inf.renderPass = vkrpass;
490 inf.attachmentCount = count;
491 inf.pAttachments = image_views;
496 for(int i=0; i<count; i++) {
497 if(vkCreateFramebuffer(vkdev, &inf, 0, &vkfbufs[i]) != VK_SUCCESS) {
498 fprintf(stderr, "Failed to create framebuffer for image view: %d\n", i);
506 struct vku_buffer *vku_create_buffer(int sz, unsigned int usage)
508 struct vku_buffer *buf;
509 VkBufferCreateInfo binfo;
511 buf = new vku_buffer;
513 memset(&binfo, 0, sizeof binfo);
514 binfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
517 binfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
519 if(vkCreateBuffer(vkdev, &binfo, 0, &buf->buf) != 0) {
520 fprintf(stderr, "failed to create %d byte buffer (usage: %x)\n", sz, usage);
523 // TODO back with memory
527 void vku_destroy_buffer(struct vku_buffer *buf)
530 vkDestroyBuffer(vkdev, buf->buf, 0);
535 void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
536 VkBuffer src, int soffs, int size)
540 copy.srcOffset = soffs;
541 copy.dstOffset = doffs;
543 vkCmdCopyBuffer(cmdbuf, src, dest, 1, ©);
548 static bool create_instance()
550 uint32_t layer_count = 0;
551 std::vector<const char *> enabled_layers;
553 if(vkEnumerateInstanceLayerProperties(&layer_count, 0) != VK_SUCCESS) {
554 fprintf(stderr, "Failed to query layer properties.\n");
558 if(layer_count > 0) {
559 VkLayerProperties *layers = (VkLayerProperties *)alloca(layer_count * sizeof *layers);
560 vkEnumerateInstanceLayerProperties(&layer_count, layers);
561 for(uint32_t i=0; i<layer_count; i++) {
562 if(strcmp(layers[i].layerName, "VK_LAYER_LUNARG_standard_validation")) {
563 enabled_layers.push_back(layers[i].layerName);
568 uint32_t extensions_count = 0;
569 std::vector<const char *> enabled_extensions;
571 if(vkEnumerateInstanceExtensionProperties(0, &extensions_count, 0) != VK_SUCCESS) {
572 fprintf(stderr, "Failed to enumerate instance extension properties\n");
576 if(extensions_count > 0) {
577 VkExtensionProperties *extensions = (VkExtensionProperties *)alloca(extensions_count * sizeof *extensions);
578 vkEnumerateInstanceExtensionProperties(0, &extensions_count, extensions);
580 for(uint32_t i=0; i<extensions_count; i++) {
581 printf("Extension %u: %s %u.\n", i, extensions[i].extensionName, extensions[i].specVersion);
582 //enable all the available extensions
583 enabled_extensions.push_back(extensions[i].extensionName);
584 enabled_extension_names.push_back(std::string(extensions[i].extensionName));
588 VkInstanceCreateInfo create_info;
589 memset(&create_info, 0, sizeof create_info);
590 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
592 if(!enabled_layers.empty()) {
593 create_info.enabledLayerCount = enabled_layers.size();
594 create_info.ppEnabledLayerNames = enabled_layers.data();
597 if(!enabled_extensions.empty()) {
598 create_info.enabledExtensionCount = enabled_extensions.size();
599 create_info.ppEnabledExtensionNames = enabled_extensions.data();
602 if(vkCreateInstance(&create_info, 0, &inst) != VK_SUCCESS) {
603 fprintf(stderr, "Failed to create instance.\n");
613 static bool create_device()
619 if(vkEnumeratePhysicalDevices(inst, &dev_count, 0) != VK_SUCCESS) {
620 fprintf(stderr, "Failed to enumerate physical devices.\n");
623 printf("%u devices found.\n", (unsigned int)dev_count);
625 VkPhysicalDevice *phys_dev = (VkPhysicalDevice *)alloca(dev_count * sizeof *phys_dev);
626 vkEnumeratePhysicalDevices(inst, &dev_count, phys_dev);
627 VkPhysicalDeviceMemoryProperties memprop;
629 for(uint32_t i=0; i<dev_count; i++) {
630 VkPhysicalDeviceProperties dev_props;
631 vkGetPhysicalDeviceProperties(phys_dev[i], &dev_props);
634 vkGetPhysicalDeviceMemoryProperties(phys_dev[i], &memprop);
635 printf("\tNumber of heaps: %u\n", memprop.memoryHeapCount);
636 for(uint32_t j=0; j<memprop.memoryHeapCount; j++) {
637 printf("\t\tHeap %u size: %lu\n", j, (unsigned long)memprop.memoryHeaps[j].size);
638 printf("\t\tHeap %u flags: %s\n", j, heap_flags_str(memprop.memoryHeaps[j].flags));
641 printf("\tMemory types: %u\n", memprop.memoryTypeCount);
642 for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
643 printf("\t\tType %u heap index: %u\n", j, memprop.memoryTypes[j].heapIndex);
644 printf("\t\tType %u flags: %s\n", j, memtype_flags_str(memprop.memoryTypes[j].propertyFlags));
648 VkPhysicalDeviceFeatures features;
649 vkGetPhysicalDeviceFeatures(phys_dev[i], &features);
653 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, 0);
654 printf("\tQueue Families: %u\n", qfam_count);
655 VkQueueFamilyProperties *qfam_props = new VkQueueFamilyProperties[qfam_count];
656 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, qfam_props);
657 for(uint32_t j=0; j<qfam_count; j++) {
658 printf("\t\tFamily %u flags: %s\n", j, queue_flags_str(qfam_props[j].queueFlags));
659 printf("\t\tFamily %u number of queues: %u\n", j, qfam_props[j].queueCount);
661 if((qfam_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (pdev_idx == -1)) {
664 num_queues = qfam_props[j].queueCount;
667 delete [] qfam_props;
671 fprintf(stderr, "No suitable devices found.\n");
675 pdev = *(phys_dev + pdev_idx);
676 qfamily_idx = qfam_idx;
678 uint32_t layer_count;
679 if(vkEnumerateDeviceLayerProperties(pdev, &layer_count, 0) != VK_SUCCESS) {
680 fprintf(stderr, "Failed to enumerate device layers.\n");
683 if(layer_count > 0) {
684 VkLayerProperties *layers = (VkLayerProperties*)alloca(layer_count * sizeof *layers);
685 vkEnumerateDeviceLayerProperties(pdev, &layer_count, layers);
686 printf("%u layers found.\n", layer_count);
687 for(uint32_t i=0; i<layer_count; i++) {
688 printf("Layer %u: %s (%u, %u)\n", i, layers[i].layerName,
689 layers[i].specVersion, layers[i].implementationVersion);
690 printf("\tDesc: %s\n", layers[i].description);
694 VkDeviceCreateInfo dev_info;
695 memset(&dev_info, 0, sizeof dev_info);
696 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
698 VkDeviceQueueCreateInfo dev_qinfo;
699 memset(&dev_qinfo, 0, sizeof dev_qinfo);
700 dev_qinfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
701 dev_qinfo.queueFamilyIndex = qfam_idx;
702 dev_qinfo.queueCount = 1;
704 dev_info.queueCreateInfoCount = 1;
705 dev_info.pQueueCreateInfos = &dev_qinfo;
707 if(vkCreateDevice(pdev, &dev_info, 0, &device) != VK_SUCCESS) {
708 fprintf(stderr, "Failed to create logical device.\n");
712 vkGetPhysicalDeviceMemoryProperties(pdev, &memprop);
713 for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
714 if(memprop.memoryTypes[j].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
716 printf("Selected device memory index: %u\n", device_mem_idx);
724 static const char *dev_type_str(VkPhysicalDeviceType type)
727 case VK_PHYSICAL_DEVICE_TYPE_OTHER:
729 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
730 return "integrated GPU";
731 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
732 return "discrete GPU";
733 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
734 return "virtual GPU";
735 case VK_PHYSICAL_DEVICE_TYPE_CPU:
743 static const char *heap_flags_str(VkMemoryHeapFlags flags)
745 static std::string str;
747 if(flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
748 str += "device-local ";
755 static const char *memtype_flags_str(VkMemoryPropertyFlags flags)
757 static std::string str;
759 if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
760 str += "device-local ";
762 if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
763 str += "host-visible ";
765 if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
766 str += "host-coherent ";
768 if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
769 str += "host-cached ";
771 if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
772 str += "lazily-allocated ";
779 static const char *queue_flags_str(VkQueueFlags flags)
781 static std::string str;
783 if(flags & VK_QUEUE_GRAPHICS_BIT)
785 if(flags & VK_QUEUE_COMPUTE_BIT)
787 if(flags & VK_QUEUE_TRANSFER_BIT)
789 if(flags & VK_QUEUE_SPARSE_BINDING_BIT)
790 str += "sparse-binding ";
797 const char *vku_get_vulkan_error_str(VkResult error)
802 errmsg = std::string("VK_SUCCESS");
805 errmsg = std::string("VK_NOT_READY");
808 errmsg = std::string("VK_TIMEOUT");
811 errmsg = std::string("VK_EVENT_SET");
814 errmsg = std::string("VK_EVENT_RESET");
817 errmsg = std::string("VK_EVENT");
819 case VK_ERROR_OUT_OF_HOST_MEMORY:
820 errmsg = std::string("VK_ERROR_OUT_OF_HOST_MEMORY");
822 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
823 errmsg = std::string("VK_ERROR_OUT_OF_DEVICE_MEMORY");
825 case VK_ERROR_INITIALIZATION_FAILED:
826 errmsg = std::string("VK_ERROR_INITIALIZATION_FAILED");
828 case VK_ERROR_DEVICE_LOST:
829 errmsg = std::string("VK_ERROR_DEVICE_LOST");
831 case VK_ERROR_MEMORY_MAP_FAILED:
832 errmsg = std::string("VK_ERROR_MEMORY_MAP_FAILED");
834 case VK_ERROR_LAYER_NOT_PRESENT:
835 errmsg = std::string("VK_ERROR_LAYER_NOT_PRESENT");
837 case VK_ERROR_EXTENSION_NOT_PRESENT:
838 errmsg = std::string("VK_ERROR_EXTENSION_NOT_PRESENT");
840 case VK_ERROR_FEATURE_NOT_PRESENT:
841 errmsg = std::string("VK_ERROR_FEATURE_NOT_PRESENT");
843 case VK_ERROR_INCOMPATIBLE_DRIVER:
844 errmsg = std::string("VK_ERROR_INCOMPATIBLE_DRIVER");
846 case VK_ERROR_TOO_MANY_OBJECTS:
847 errmsg = std::string("VK_ERROR_TOO_MANY_OBJECTS");
849 case VK_ERROR_FORMAT_NOT_SUPPORTED:
850 errmsg = std::string("VK_ERROR_FORMAT_NOT_SUPPORTED");
852 case VK_ERROR_FRAGMENTED_POOL:
853 errmsg = std::string("VK_ERROR_FRAGMENTED_POOL");
856 errmsg = std::string("UNKNOWN");
860 return errmsg.c_str();
863 bool vku_create_graphics_pipeline(VkPipelineLayout *layout)
865 VkGraphicsPipelineCreateInfo inf;
866 memset(&inf, 0, sizeof inf);
868 inf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
869 inf.layout = *layout;
870 inf.renderPass = vkrpass;
874 /* how primitives are assembled */
875 VkPipelineInputAssemblyStateCreateInfo ias;
876 memset(&ias, 0, sizeof ias);
877 ias.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
878 ias.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
881 VkPipelineRasterizationStateCreateInfo rsi;
882 memset(&rsi, 0, sizeof rsi);
883 rsi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
884 rsi.polygonMode = VK_POLYGON_MODE_FILL;
885 rsi.cullMode = VK_CULL_MODE_BACK_BIT;
886 rsi.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
887 rsi.lineWidth = 1.0f;
890 VkPipelineColorBlendAttachmentState bas[1];
891 memset(&bas[0], 0, sizeof bas[0]);
893 VkPipelineColorBlendStateCreateInfo cbs;
894 memset(&cbs, 0, sizeof cbs);
895 cbs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
896 cbs.attachmentCount = 1;
897 cbs.pAttachments = bas;
899 /* number of viewport and scissors in this pipeline */
900 VkPipelineViewportStateCreateInfo vs;
901 memset(&vs, 0, sizeof vs);
902 vs.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
903 vs.viewportCount = 1;
906 /* dynamic states: that can be changed later */
907 std::vector<VkDynamicState> ds_enabled;
908 ds_enabled.push_back(VK_DYNAMIC_STATE_VIEWPORT);
909 //ds_enabled.push_back(VK_DYNAMIC_STATE_SCISSOR);
910 VkPipelineDynamicStateCreateInfo ds;
911 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
912 ds.pDynamicStates = ds_enabled.data();
913 ds.dynamicStateCount = static_cast<uint32_t>(ds_enabled.size());
916 VkPipelineDepthStencilStateCreateInfo dsi;
917 memset(&dsi, 0, sizeof dsi);
918 dsi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
919 dsi.depthTestEnable = VK_TRUE;
920 dsi.depthWriteEnable = VK_TRUE;
921 dsi.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
922 dsi.back.failOp = VK_STENCIL_OP_KEEP;
923 dsi.back.passOp = VK_STENCIL_OP_KEEP;
924 dsi.back.compareOp = VK_COMPARE_OP_ALWAYS;
925 dsi.front = dsi.back;
927 /* multisampling - must be set even if not used */
928 VkPipelineMultisampleStateCreateInfo msi;
929 memset(&msi, 0, sizeof msi);
930 msi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
931 msi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
937 static const char *get_device_name_str(VkPhysicalDeviceType type)
940 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
941 return "integrated GPU";
942 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
943 return "discrete GPU";
944 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
945 return "virtual GPU";
946 case VK_PHYSICAL_DEVICE_TYPE_CPU:
954 static const char *get_memtype_flags_str(VkMemoryPropertyFlags flags)
956 static char str[128];
959 if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
960 strcat(str, "device-local ");
962 if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
963 strcat(str, "host-visible ");
965 if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
966 strcat(str, "host-coherent ");
968 if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
969 strcat(str, "host-cached ");
971 if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
972 strcat(str, "lazily-allocated ");
981 static const char *get_queue_flags_str(VkQueueFlags flags)
983 static char str[128];
986 if(flags & VK_QUEUE_GRAPHICS_BIT) {
987 strcat(str, "graphics ");
989 if(flags & VK_QUEUE_COMPUTE_BIT) {
990 strcat(str, "compute ");
992 if(flags & VK_QUEUE_TRANSFER_BIT) {
993 strcat(str, "transfer ");
995 if(flags & VK_QUEUE_SPARSE_BINDING_BIT) {
996 strcat(str, "sparse-binding ");
1004 static int ver_major(uint32_t ver)
1006 return (ver >> 22) & 0x3ff;
1009 static int ver_minor(uint32_t ver)
1011 return (ver >> 12) & 0x3ff;
1014 static int ver_patch(uint32_t ver)
1019 static const char *get_mem_size_str(long sz)
1021 static char str[64];
1022 static const char *unitstr[] = { "bytes", "KB", "MB", "GB", "TB", "PB", 0 };
1026 while(sz >= 10240 && unitstr[uidx + 1]) {
1030 sprintf(str, "%ld.%ld %s", sz / 10, sz % 10, unitstr[uidx]);