File vulkan_utils.cpp
File List > utils > vulkan_utils.cpp
Go to the documentation of this file
#define VMA_IMPLEMENTATION
#include "illixr/vk/vulkan_utils.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __linux__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Weverything"
#endif
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include "illixr/switchboard.hpp"
#ifdef __linux__
# include "illixr/vk/third_party/vk_mem_alloc.h"
#else
# include
#endif
#ifdef __linux__
# pragma clang diagnostic pop
#endif
using namespace ILLIXR::vulkan;
std::string ILLIXR::vulkan::error_string(VkResult err_code) {
switch (err_code) {
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_FRAGMENTED_POOL:
return "VK_ERROR_FRAGMENTED_POOL";
case VK_ERROR_UNKNOWN:
return "VK_ERROR_UNKNOWN";
case VK_ERROR_OUT_OF_POOL_MEMORY:
return "VK_ERROR_OUT_OF_POOL_MEMORY";
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
case VK_ERROR_FRAGMENTATION:
return "VK_ERROR_FRAGMENTATION";
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
case VK_ERROR_NOT_PERMITTED_EXT:
return "VK_ERROR_NOT_PERMITTED_EXT";
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
default:
return "UNKNOWN_ERROR";
}
}
VkShaderModule ILLIXR::vulkan::create_shader_module(VkDevice device, std::vector<char>&& code) {
VkShaderModuleCreateInfo createInfo{
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType
nullptr, // pNext
0, // flags
code.size(), // codeSize
reinterpret_cast<const uint32_t*>(code.data()) // pCode
};
VkShaderModule shaderModule;
VK_ASSERT_SUCCESS(vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule))
return shaderModule;
}
VkSemaphore ILLIXR::vulkan::create_timeline_semaphore(VkDevice device, int initial_value,
VkExportSemaphoreCreateInfo* export_semaphore_create_info) {
VkSemaphoreTypeCreateInfo timeline_create_info{};
timeline_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO;
timeline_create_info.pNext = export_semaphore_create_info;
timeline_create_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
timeline_create_info.initialValue = initial_value;
VkSemaphoreCreateInfo semaphore_create_info{};
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphore_create_info.pNext = &timeline_create_info;
semaphore_create_info.flags = 0;
VkSemaphore semaphore;
auto ret = vkCreateSemaphore(device, &semaphore_create_info, nullptr, &semaphore);
VK_ASSERT_SUCCESS(ret);
return semaphore;
}
[[maybe_unused]] void ILLIXR::vulkan::wait_timeline_semaphore(VkDevice device, VkSemaphore semaphore, uint64_t value) {
VkSemaphoreWaitInfo wait_info{};
wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
wait_info.pNext = nullptr;
wait_info.flags = 0;
wait_info.semaphoreCount = 1;
wait_info.pSemaphores = &semaphore;
wait_info.pValues = &value;
auto ret = vkWaitSemaphores(device, &wait_info, UINT64_MAX);
VK_ASSERT_SUCCESS(ret);
}
void ILLIXR::vulkan::wait_timeline_semaphores(VkDevice device, const std::map<VkSemaphore, uint64_t>& semaphores) {
VkSemaphoreWaitInfo wait_info{};
wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
wait_info.pNext = nullptr;
wait_info.flags = 0;
wait_info.semaphoreCount = semaphores.size();
std::vector<VkSemaphore> semaphore_vec;
std::vector<uint64_t> value_vec;
for (auto& [semaphore, value] : semaphores) {
semaphore_vec.push_back(semaphore);
value_vec.push_back(value);
}
wait_info.pSemaphores = semaphore_vec.data();
wait_info.pValues = value_vec.data();
auto ret = vkWaitSemaphores(device, &wait_info, UINT64_MAX);
VK_ASSERT_SUCCESS(ret);
}
VmaAllocator ILLIXR::vulkan::create_vma_allocator(VkInstance vk_instance, VkPhysicalDevice vk_physical_device,
VkDevice vk_device, uint32_t api_version) {
VmaVulkanFunctions vulkanFunctions{};
vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
VmaAllocatorCreateInfo allocatorCreateInfo{};
allocatorCreateInfo.physicalDevice = vk_physical_device;
allocatorCreateInfo.device = vk_device;
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
allocatorCreateInfo.instance = vk_instance;
// This must not exceed the API requested when creating the instance.
// A newer physical-device version alone does not enable core entry points.
allocatorCreateInfo.vulkanApiVersion = api_version;
VmaAllocator allocator;
VK_ASSERT_SUCCESS(vmaCreateAllocator(&allocatorCreateInfo, &allocator))
return allocator;
}
VkCommandBuffer ILLIXR::vulkan::begin_one_time_command(VkDevice vk_device, VkCommandPool vk_command_pool) {
VkCommandBufferAllocateInfo allocInfo{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
nullptr, // pNext
vk_command_pool, // commandPool
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
1 // commandBufferCount
};
VkCommandBuffer commandBuffer;
VK_ASSERT_SUCCESS(vkAllocateCommandBuffers(vk_device, &allocInfo, &commandBuffer))
VkCommandBufferBeginInfo beginInfo{
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType
nullptr, // pNext
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // flags
nullptr // pInheritanceInfo
};
VK_ASSERT_SUCCESS(vkBeginCommandBuffer(commandBuffer, &beginInfo))
return commandBuffer;
}
void ILLIXR::vulkan::end_one_time_command(VkDevice vk_device, VkCommandPool vk_command_pool, const queue& q,
VkCommandBuffer vk_command_buffer) {
VK_ASSERT_SUCCESS(vkEndCommandBuffer(vk_command_buffer))
VkSubmitInfo submitInfo{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
nullptr, // pNext
0, // waitSemaphoreCount
nullptr, // pWaitSemaphores
nullptr, // pWaitDstStageMask
1, // commandBufferCount
&vk_command_buffer, // pCommandBuffers
0, // signalSemaphoreCount
nullptr // pSignalSemaphores
};
std::lock_guard<std::mutex> lock(*q.mutex);
VK_ASSERT_SUCCESS(vkQueueSubmit(q.vk_queue, 1, &submitInfo, VK_NULL_HANDLE))
VK_ASSERT_SUCCESS(vkQueueWaitIdle(q.vk_queue))
vkFreeCommandBuffers(vk_device, vk_command_pool, 1, &vk_command_buffer);
}
VkCommandPool ILLIXR::vulkan::create_command_pool(VkDevice device, uint32_t queue_family_index) {
VkCommandPoolCreateInfo poolInfo = {
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // sType
nullptr, // pNext
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // flags
queue_family_index // queueFamilyIndex
};
VkCommandPool command_pool;
VK_ASSERT_SUCCESS(vkCreateCommandPool(device, &poolInfo, nullptr, &command_pool))
return command_pool;
}
VkCommandBuffer ILLIXR::vulkan::create_command_buffer(VkDevice device, VkCommandPool command_pool) {
VkCommandBufferAllocateInfo allocInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
nullptr, // pNext
command_pool, // commandPool
VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
1 // commandBufferCount
};
VkCommandBuffer command_buffer;
VK_ASSERT_SUCCESS(vkAllocateCommandBuffers(device, &allocInfo, &command_buffer))
return command_buffer;
}
VkResult ILLIXR::vulkan::locked_queue_submit(queue& q, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) {
std::lock_guard<std::mutex> lock(*q.mutex);
return vkQueueSubmit(q.vk_queue, submitCount, pSubmits, fence);
}
std::vector<char> ILLIXR::vulkan::read_file(const std::string& path) {
std::ifstream file(path, std::ios::ate | std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("failed to open file!");
}
size_t fileSize = (size_t) file.tellg();
std::vector<char> buffer(fileSize);
file.seekg(0);
file.read(buffer.data(), static_cast<long>(fileSize));
file.close();
return buffer;
}
void ILLIXR::vulkan::copy_buffer_to_image(VkDevice vk_device, queue q, VkCommandPool vk_command_pool, VkBuffer buffer,
VkImage image, uint32_t width, uint32_t height) {
VkCommandBuffer command_buffer = begin_one_time_command(vk_device, vk_command_pool);
VkBufferImageCopy region{
0, // bufferOffset
0, // bufferRowLength
0, // bufferImageHeight
{
// imageSubresource
VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
0, // mipLevel
0, // baseArrayLayer
1, // layerCount
},
{0, 0, 0}, // imageOffset
{width, height, 1} // imageExtent
};
vkCmdCopyBufferToImage(command_buffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
end_one_time_command(vk_device, vk_command_pool, std::move(q), command_buffer);
}
swapchain_details ILLIXR::vulkan::query_swapchain_details(VkPhysicalDevice const& physical_device,
VkSurfaceKHR const& vk_surface) {
swapchain_details details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, vk_surface, &details.capabilities);
uint32_t format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &format_count, nullptr);
if (format_count != 0) {
details.formats.resize(format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &format_count, details.formats.data());
}
uint32_t present_mode_count;
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &present_mode_count, nullptr);
if (present_mode_count != 0) {
details.present_modes.resize(present_mode_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &present_mode_count,
details.present_modes.data());
}
return details;
}
queue_families ILLIXR::vulkan::find_queue_families(VkPhysicalDevice const& physical_device, VkSurfaceKHR const& vk_surface,
bool no_present) {
queue_families indices;
uint32_t queue_family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queueFamilies.data());
int i = 0;
for (const auto& queue_family : queueFamilies) {
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphics_family = i;
}
#if defined(VK_ENABLE_BETA_EXTENSIONS)
#endif
if (queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT) {
indices.compute_family = i;
}
// if (queue_family.queueFlags & VK_QUEUE_TRANSFER_BIT) {
// if (!(queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) && !(queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT)) {
// indices.dedicated_transfer = i;
// }
// }
if (!no_present) {
VkBool32 present_support = false;
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, vk_surface, &present_support);
if (present_support) {
indices.present_family = i;
}
}
if (indices.has_compression()) {
break;
}
i++;
}
return indices;
}
VkImageView ILLIXR::vulkan::create_image_view(VkDevice device, VkImage image, VkFormat format,
VkImageAspectFlags aspect_flags) {
VkImageViewCreateInfo vk_image_view_create_info{};
vk_image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vk_image_view_create_info.image = image;
vk_image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
vk_image_view_create_info.format = format;
vk_image_view_create_info.subresourceRange.aspectMask = aspect_flags;
vk_image_view_create_info.subresourceRange.baseMipLevel = 0;
vk_image_view_create_info.subresourceRange.levelCount = 1;
vk_image_view_create_info.subresourceRange.baseArrayLayer = 0;
vk_image_view_create_info.subresourceRange.layerCount = 1;
vk_image_view_create_info.pNext = nullptr;
VkImageView vk_image_view;
VK_ASSERT_SUCCESS(vkCreateImageView(device, &vk_image_view_create_info, nullptr, &vk_image_view))
return vk_image_view;
}