Experimentation using Vulkan.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

864 lines
26 KiB

#include <Vulkan/Context.h>
#include <Vulkan/Memory.h>
#include <utils.h>
#include <Logger.h>
#include <SDL2/SDL_vulkan.h>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <tuple>
namespace Vulkan {
ContextSettings::ContextSettings() {
}
ContextSettings::~ContextSettings() {
}
bool ContextSettings::debug() const {
return m_debug;
}
ContextSettings& ContextSettings::with_debug(bool enabled) {
m_debug = enabled;
return *this;
}
const std::optional<Uuid>& ContextSettings::physical_device() const {
return m_physical_device;
}
ContextSettings& ContextSettings::with_physical_device(Uuid uuid) {
m_physical_device = uuid;
return *this;
}
const std::vector<ContextSettings::QueueInfo>& ContextSettings::queues() const {
return m_queues;
}
ContextSettings& ContextSettings::with_queue(
uint32_t index, VkQueueFlagBits flags, bool use_swapchain_images
) {
m_queues.emplace_back(QueueInfo { index, flags, use_swapchain_images });
return *this;
}
SDL_Window* ContextSettings::window() const {
return m_window;
}
ContextSettings& ContextSettings::with_window(SDL_Window* window) {
m_window = window;
return *this;
}
//////////////////////////////////////////////////////////////////////////////
// Context
Context::Context() {
}
Context::~Context() {
shutdown();
}
VkInstance Context::instance() {
return m_instance;
}
VkPhysicalDevice Context::physical_device() {
return m_physical_device;
}
VkDevice Context::device() {
return m_device;
}
uint32_t Context::queue_family(size_t queue_index) const {
return m_queue_families[queue_index];
}
uint32_t Context::presentation_queue_family() const {
return m_presentation_queue_family;
}
VkQueue Context::queue(size_t queue_index) {
return m_queues[queue_index];
}
VkQueue Context::presentation_queue() {
return m_presentation_queue;
}
SDL_Window* Context::window() {
return m_window;
}
VkSurfaceKHR Context::surface() {
return m_surface;
}
VkSurfaceFormatKHR Context::surface_format() const {
return m_surface_format;
}
VkPresentModeKHR Context::present_mode() const {
return m_present_mode;
}
void Context::initialize(const ContextSettings& settings) {
m_window = settings.window();
create_instance(settings);
create_surface(settings);
choose_physical_device(settings);
create_device(settings);
create_internal_objects();
m_allocator.reset(new Allocator(this));
}
void Context::shutdown() {
if(!m_instance)
return;
vkDeviceWaitIdle(m_device);
for(auto& callback: m_context_destruction_callbacks)
callback();
m_allocator->free_all_pages();
m_allocator.reset();
destroy_fence(m_transfer_fence);
destroy_command_pool(m_transfer_command_pool);
destroy_device(m_device);
destroy_surface(m_surface);
destroy_debug_messenger(m_debug_messenger);
destroy_instance(m_instance);
}
void Context::register_context_destruction_callback(ContextDestructionCallback callback) {
m_context_destruction_callbacks.emplace_back(std::move(callback));
}
std::vector<VkExtensionProperties> Context::available_extensions() {
uint32_t count;
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
std::vector<VkExtensionProperties> extensions(count);
vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data());
return extensions;
}
std::vector<VkLayerProperties> Context::available_layers() {
uint32_t count;
vkEnumerateInstanceLayerProperties(&count, nullptr);
std::vector<VkLayerProperties> layers(count);
vkEnumerateInstanceLayerProperties(&count, layers.data());
return layers;
}
std::vector<const char*> Context::sdl_vulkan_extensions() const {
unsigned count;
if(!SDL_Vulkan_GetInstanceExtensions(m_window, &count, nullptr))
throw std::runtime_error("failed to get window's vulkan extensions");
std::vector<const char*> extensions(count);
if(!SDL_Vulkan_GetInstanceExtensions(m_window, &count, extensions.data()))
throw std::runtime_error("failed to get window's vulkan extensions");
return extensions;
}
std::vector<VkPhysicalDevice> Context::physical_devices() const {
uint32_t devices_count = 0;
vkEnumeratePhysicalDevices(m_instance, &devices_count, nullptr);
std::vector<VkPhysicalDevice> physical_devices(devices_count);
vkEnumeratePhysicalDevices(m_instance, &devices_count, physical_devices.data());
return physical_devices;
}
std::vector<VkQueueFamilyProperties> Context::queue_families(VkPhysicalDevice physical_device) const {
uint32_t queue_families_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(queue_families_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, queue_families.data());
return queue_families;
}
std::vector<VkExtensionProperties> Context::device_extensions(VkPhysicalDevice physical_device) const {
uint32_t extensions_count = 0;
vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extensions_count, nullptr);
std::vector<VkExtensionProperties> extensions(extensions_count);
vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extensions_count, extensions.data());
return extensions;
}
std::vector<VkSurfaceFormatKHR> Context::surface_formats(VkPhysicalDevice physical_device) const {
uint32_t surface_formats_count = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, m_surface, &surface_formats_count, nullptr);
std::vector<VkSurfaceFormatKHR> surface_formats(surface_formats_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, m_surface, &surface_formats_count, surface_formats.data());
return surface_formats;
}
std::vector<VkPresentModeKHR> Context::present_modes(VkPhysicalDevice physical_device) const {
uint32_t present_modes_count = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, m_surface, &present_modes_count, nullptr);
std::vector<VkPresentModeKHR> present_modes(present_modes_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, m_surface, &present_modes_count, present_modes.data());
return present_modes;
}
void Context::set_object_name(VkObjectType type, uint64_t object, const char* name) {
VkDebugUtilsObjectNameInfoEXT name_info {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.objectType = type,
.objectHandle = object,
.pObjectName = name
};
if(setDebugUtilsObjectName(m_device, &name_info) != VK_SUCCESS)
throw std::runtime_error("failed to set debug name");
}
void Context::set_object_name(VkObjectType type, uint64_t object, const std::string& name) {
set_object_name(type, object, name.c_str());
}
VkShaderModule Context::create_shader_module(const std::vector<char> bytecode) {
VkShaderModuleCreateInfo shader_info {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.codeSize = bytecode.size(),
.pCode = reinterpret_cast<const uint32_t*>(bytecode.data()),
};
VkShaderModule shader_module = VK_NULL_HANDLE;
if(vkCreateShaderModule(
m_device,
&shader_info,
nullptr,
&shader_module
) != VK_SUCCESS)
throw std::runtime_error("failed to create shader module");
return shader_module;
}
VkShaderModule Context::create_shader_module_from_file(const char* path) {
auto const bytecode = read_binary_file(path);
try {
return create_shader_module(bytecode);
}
catch(std::exception err) {
throw std::runtime_error(cat("failed to create shader '", path, "':\n ", err.what()));
}
return VK_NULL_HANDLE;
}
void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size) {
VkCommandBufferAllocateInfo alloc_info {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = m_transfer_command_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
VkCommandBuffer command_buffer;
vkAllocateCommandBuffers(m_device, &alloc_info, &command_buffer);
auto const command_buffer_guard = make_guard([this, command_buffer]() {
vkFreeCommandBuffers(m_device, m_transfer_command_pool, 1, &command_buffer);
});
VkCommandBufferBeginInfo begin_info {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
vkBeginCommandBuffer(command_buffer, &begin_info);
VkBufferCopy region {
.srcOffset = 0,
.dstOffset = 0,
.size = size,
};
vkCmdCopyBuffer(command_buffer, src, dst, 1, &region);
VkBufferMemoryBarrier buffer_barrier {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.srcQueueFamilyIndex = queue_family(VK_QUEUE_TRANSFER_BIT),
.dstQueueFamilyIndex = dst_queue_family,
.buffer = dst,
.offset = 0,
.size = size,
};
vkCmdPipelineBarrier(
command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0,
0, nullptr,
1, &buffer_barrier,
0, nullptr
);
vkEndCommandBuffer(command_buffer);
vkResetFences(m_device, 1, &m_transfer_fence);
VkSubmitInfo submit_info {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
};
vkQueueSubmit(
queue(m_transfer_queue_index),
1, &submit_info,
m_transfer_fence
);
vkWaitForFences(m_device, 1, &m_transfer_fence, VK_TRUE, UINT64_MAX);
}
void Context::destroy_instance(VkInstance& instance) {
if(instance == nullptr)
return;
vkDestroyInstance(instance, nullptr);
instance = nullptr;
}
void Context::destroy_debug_messenger(VkDebugUtilsMessengerEXT& debug_messenger) {
if(debug_messenger == VK_NULL_HANDLE)
return;
destroyDebugUtilsMessenger(m_instance, debug_messenger, nullptr);
debug_messenger = VK_NULL_HANDLE;
}
void Context::destroy_surface(VkSurfaceKHR& surface) {
if(surface == VK_NULL_HANDLE)
return;
vkDestroySurfaceKHR(m_instance, surface, nullptr);
surface = VK_NULL_HANDLE;
}
void Context::destroy_device(VkDevice& device) {
if(device == nullptr)
return;
vkDestroyDevice(device, nullptr);
device = nullptr;
}
void Context::destroy_swapchain(VkSwapchainKHR& swapchain) {
if(swapchain == VK_NULL_HANDLE)
return;
vkDestroySwapchainKHR(m_device, swapchain, nullptr);
swapchain = VK_NULL_HANDLE;
}
void Context::destroy_image(VkImage& image) {
if(image == VK_NULL_HANDLE)
return;
vkDestroyImage(m_device, image, nullptr);
image = VK_NULL_HANDLE;
}
void Context::destroy_image_view(VkImageView& image_view) {
if(image_view == VK_NULL_HANDLE)
return;
vkDestroyImageView(m_device, image_view, nullptr);
image_view = VK_NULL_HANDLE;
}
void Context::destroy_framebuffer(VkFramebuffer& framebuffer) {
if(framebuffer == VK_NULL_HANDLE)
return;
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
framebuffer = VK_NULL_HANDLE;
}
void Context::destroy_buffer(VkBuffer& buffer) {
if(buffer == VK_NULL_HANDLE)
return;
vkDestroyBuffer(m_device, buffer, nullptr);
buffer = VK_NULL_HANDLE;
}
void Context::destroy_command_pool(VkCommandPool& command_pool) {
if(command_pool == VK_NULL_HANDLE)
return;
vkDestroyCommandPool(m_device, command_pool, nullptr);
command_pool = VK_NULL_HANDLE;
}
void Context::destroy_descriptor_pool(VkDescriptorPool& descriptor_pool) {
if(descriptor_pool == VK_NULL_HANDLE)
return;
vkDestroyDescriptorPool(m_device, descriptor_pool, nullptr);
descriptor_pool = VK_NULL_HANDLE;
}
void Context::destroy_render_pass(VkRenderPass& render_pass) {
if(render_pass == VK_NULL_HANDLE)
return;
vkDestroyRenderPass(m_device, render_pass, nullptr);
render_pass = VK_NULL_HANDLE;
}
void Context::destroy_descriptor_set_layout(VkDescriptorSetLayout& descriptor_set_layout) {
if(descriptor_set_layout == VK_NULL_HANDLE)
return;
vkDestroyDescriptorSetLayout(m_device, descriptor_set_layout, nullptr);
descriptor_set_layout = VK_NULL_HANDLE;
}
void Context::destroy_pipeline_layout(VkPipelineLayout& pipeline_layout) {
if(pipeline_layout == VK_NULL_HANDLE)
return;
vkDestroyPipelineLayout(m_device, pipeline_layout, nullptr);
pipeline_layout = VK_NULL_HANDLE;
}
void Context::destroy_pipeline(VkPipeline& pipeline) {
if(pipeline == VK_NULL_HANDLE)
return;
vkDestroyPipeline(m_device, pipeline, nullptr);
pipeline = VK_NULL_HANDLE;
}
void Context::destroy_semaphore(VkSemaphore& semaphore) {
if(semaphore == VK_NULL_HANDLE)
return;
vkDestroySemaphore(m_device, semaphore, nullptr);
semaphore = VK_NULL_HANDLE;
}
void Context::destroy_fence(VkFence& fence) {
if(fence == VK_NULL_HANDLE)
return;
vkDestroyFence(m_device, fence, nullptr);
fence = VK_NULL_HANDLE;
}
void Context::free_memory(VkDeviceMemory& memory) {
if(memory == VK_NULL_HANDLE)
return;
vkFreeMemory(m_device, memory, nullptr);
memory = VK_NULL_HANDLE;
}
void Context::create_instance(const ContextSettings& settings) {
if(m_instance)
return;
char const* const name = "vk_expe";
uint32_t const version = VK_MAKE_VERSION(0, 1, 0);
VkApplicationInfo const app_info {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = name,
.applicationVersion = version,
.pEngineName = name,
.engineVersion = version,
.apiVersion = VK_API_VERSION_1_1,
};
std::vector<char const*> layers;
std::vector<char const*> extensions = sdl_vulkan_extensions();
if(settings.debug()) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
auto const available_layers = Context::available_layers();
auto add_layer_if_available = [&](const char* requested_layer) {
if(std::find_if(
available_layers.begin(),
available_layers.end(),
[requested_layer](const VkLayerProperties& layer) {
return std::strcmp(layer.layerName, requested_layer) == 0;
}
) != available_layers.end()) {
layers.push_back(requested_layer);
}
else {
logger.warning() << "requested layer '" << requested_layer
<< "' is not available";
}
};
add_layer_if_available("VK_LAYER_KHRONOS_validation");
}
VkDebugUtilsMessengerCreateInfoEXT const debug_info {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = &log_debug_message,
.pUserData = nullptr,
};
VkInstanceCreateInfo const instance_info {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = &debug_info,
.pApplicationInfo = &app_info,
.enabledLayerCount = uint32_t(layers.size()),
.ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = uint32_t(extensions.size()),
.ppEnabledExtensionNames = extensions.data(),
};
logger.debug() << "Requested extensions:";
for(char const* extension: extensions)
logger.debug() << " " << extension;
logger.debug() << "Requested layers:";
for(char const* layer: layers)
logger.debug() << " " << layer;
logger.debug() << "create vulkan instance...";
if(vkCreateInstance(&instance_info, nullptr, &m_instance) != VK_SUCCESS)
throw std::runtime_error("failed to create vulkan instance");
initialize_extension_functions();
if(settings.debug()) {
createDebugUtilsMessenger(
m_instance, &debug_info, nullptr, &m_debug_messenger);
}
}
void Context::create_surface(const ContextSettings& settings) {
if(!SDL_Vulkan_CreateSurface(m_window, m_instance, &m_surface))
throw std::runtime_error("failed to create surface");
}
void Context::choose_physical_device(const ContextSettings& settings) {
auto physical_devices = this->physical_devices();
if(settings.physical_device()) {
auto const device_it = std::find_if(
physical_devices.begin(),
physical_devices.end(),
[&settings] (VkPhysicalDevice physical_device) {
VkPhysicalDeviceProperties device_properties;
vkGetPhysicalDeviceProperties(physical_device, &device_properties);
return make_uuid(device_properties.pipelineCacheUUID)
== *settings.physical_device();
}
);
if(device_it != physical_devices.end()) {
using std::swap;
swap(physical_devices[0], *device_it);
}
}
for(auto const physical_device: physical_devices) {
auto maybe_properties = select_physical_device(physical_device, settings);
if(maybe_properties) {
m_physical_device = physical_device;
m_physical_device_properties = *maybe_properties;
vkGetPhysicalDeviceMemoryProperties(m_physical_device, &m_memory_properties);
break;
}
}
if(!m_physical_device)
throw std::runtime_error("failed to find suitable physical device");
logger.info() << "use suitable device: " << m_physical_device_properties.deviceName;
logger.debug() << "swapchain format: " << m_surface_format.format;
logger.debug() << "present mode: " << m_present_mode;
}
std::optional<VkPhysicalDeviceProperties> Context::select_physical_device(
VkPhysicalDevice physical_device,
const ContextSettings& settings
) {
VkPhysicalDeviceProperties device_properties;
vkGetPhysicalDeviceProperties(physical_device, &device_properties);
VkPhysicalDeviceFeatures available_features;
vkGetPhysicalDeviceFeatures(physical_device, &available_features);
if (!available_features.geometryShader)
return std::nullopt;
m_transfer_queue_index = settings.queues().size();
m_queue_families.assign(settings.queues().size() + 1, INVALID_QUEUE_FAMILY);
m_presentation_queue_family = INVALID_QUEUE_FAMILY;
auto const queue_families = this->queue_families(physical_device);
uint32_t queue_family_index = 0;
for(auto const& queue_family: queue_families) {
if(m_window != nullptr) {
VkBool32 support_surface = false;
vkGetPhysicalDeviceSurfaceSupportKHR(
physical_device,
queue_family_index,
m_surface,
&support_surface
);
if(support_surface)
m_presentation_queue_family = queue_family_index;
}
for(auto const queue_info: settings.queues()) {
uint32_t const index = queue_info.index;
VkQueueFlagBits flags = queue_info.flags;
if(m_queue_families[index] != INVALID_QUEUE_FAMILY)
continue;
if((queue_family.queueFlags & flags) == flags)
m_queue_families[index] = queue_family_index;
}
if(m_queue_families[m_transfer_queue_index] == INVALID_QUEUE_FAMILY
&& queue_family.queueFlags == VK_QUEUE_TRANSFER_BIT)
m_queue_families[m_transfer_queue_index] = queue_family_index;
queue_family_index += 1;
}
for(auto const queue_family: m_queue_families) {
if(queue_family == INVALID_QUEUE_FAMILY)
return std::nullopt;
}
auto const available_extensions = this->device_extensions(physical_device);
auto has_extension = [&available_extensions](const char* required_extension) {
return std::find_if(
available_extensions.begin(),
available_extensions.end(),
[required_extension](const VkExtensionProperties& extension) {
return strcmp(extension.extensionName, required_extension) == 0;
}
) != available_extensions.end();
};
if(m_window) {
if(!has_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME))
return std::nullopt;
auto const surface_formats = this->surface_formats(physical_device);
if(surface_formats.empty())
return std::nullopt;
auto const present_modes = this->present_modes(physical_device);
if(present_modes.empty())
return std::nullopt;
auto const surface_format_it = std::find_if(
surface_formats.begin(),
surface_formats.end(),
[](const VkSurfaceFormatKHR& surface_format) {
return surface_format.format == VK_FORMAT_B8G8R8A8_SRGB
&& surface_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
}
);
m_surface_format = (surface_format_it != surface_formats.end())?
*surface_format_it:
surface_formats[0];
m_present_mode = VK_PRESENT_MODE_FIFO_KHR;
// m_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
return device_properties;
}
void Context::create_device(const ContextSettings& settings) {
std::vector<uint32_t> queue_families = m_queue_families;
std::sort(queue_families.begin(), queue_families.end());
queue_families.erase(
std::unique(queue_families.begin(), queue_families.end()),
queue_families.end()
);
float const queue_priority = 1.0f;
std::vector<VkDeviceQueueCreateInfo> queue_infos;
for(uint32_t queue_family: queue_families) {
queue_infos.emplace_back(VkDeviceQueueCreateInfo {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = queue_family,
.queueCount = 1,
.pQueuePriorities = &queue_priority,
});
}
VkPhysicalDeviceFeatures const device_features {
.geometryShader = true,
};
std::vector<const char*> extensions;
if(m_window) {
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
};
VkDeviceCreateInfo const device_info {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = uint32_t(queue_infos.size()),
.pQueueCreateInfos = queue_infos.data(),
.enabledExtensionCount = uint32_t(extensions.size()),
.ppEnabledExtensionNames = extensions.data(),
.pEnabledFeatures = &device_features,
};
logger.debug() << "create vulkan device...";
if(vkCreateDevice(
m_physical_device,
&device_info,
nullptr,
&m_device
) != VK_SUCCESS)
throw std::runtime_error("failed to create logical device");
m_queues.resize(m_queue_families.size());
for(size_t index = 0; index < m_queue_families.size(); ++index) {
vkGetDeviceQueue(
m_device,
m_queue_families[index],
0,
&m_queues[index]
);
}
vkGetDeviceQueue(m_device, m_presentation_queue_family, 0, &m_presentation_queue);
}
void Context::create_internal_objects() {
VkCommandPoolCreateInfo pool_info {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = 0,
.queueFamilyIndex = queue_family(m_transfer_queue_index),
};
if(vkCreateCommandPool(
m_device,
&pool_info,
nullptr,
&m_transfer_command_pool
) != VK_SUCCESS) {
throw std::runtime_error("failed to create command pool");
}
VkFenceCreateInfo fence_info {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
};
if(vkCreateFence(m_device, &fence_info, nullptr, &m_transfer_fence) != VK_SUCCESS)
throw std::runtime_error("failed to create fence");
}
void Context::initialize_extension_functions() {
uint32_t errors_count = 0;
#define GET_PROC_ADDR(ptr_name, func_name) \
ptr_name = (PFN_vk ## func_name)vkGetInstanceProcAddr( \
m_instance, "vk" #func_name); \
if(ptr_name == nullptr) \
{ \
logger.error() << "failed to load extension function 'vk" #func_name "'"; \
errors_count += 1; \
}
GET_PROC_ADDR(createDebugUtilsMessenger, CreateDebugUtilsMessengerEXT)
GET_PROC_ADDR(destroyDebugUtilsMessenger, DestroyDebugUtilsMessengerEXT)
GET_PROC_ADDR(setDebugUtilsObjectName, SetDebugUtilsObjectNameEXT)
if(errors_count != 0)
throw std::runtime_error("failed to load extensions");
}
VKAPI_ATTR VkBool32 VKAPI_CALL Context::log_debug_message(
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* data,
void* user_data
) {
{
auto stream = [severity]() {
switch(severity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
return logger.debug();
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
return logger.info();
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
return logger.warning();
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
return logger.error();
}
return logger.debug();
}();
switch(type) {
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
stream << "[vk:general] ";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
stream << "[vk:validation] ";
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
stream << "[vk:performance] ";
break;
}
stream << data->pMessage;
}
if(severity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
&& data->messageIdNumber != 2094043421 // wrong swapchain extent
)
abort();
return VK_FALSE;
}
}