#include "utils.h" bool discoveredLayers = false; bool discoveredExtensions = false; std::map availableLayers; std::map availableExtensions; Engine::Support Engine::getVulkanLayers(const std::set& requestedLayers) { Engine::Support result; if (!discoveredLayers) { std::vector props = getAvailableVulkanLayers(); for (const VkLayerProperties& prop : props) availableLayers.insert(std::make_pair(prop.layerName, prop)); discoveredLayers = true; } for (const std::string& ext : requestedLayers) { if (availableLayers.count(ext) > 0) result.supported.push_back(ext.c_str()); else result.unsupported.push_back(ext.c_str()); } return result; } Engine::Support Engine::getVulkanExtensions( const std::set& requestedExtensions, const std::vector& criticalExtensions ) { Support result; if (!discoveredExtensions) { std::vector props = getAvailableVulkanExtensions(); for (const VkExtensionProperties& prop : props) availableExtensions.insert(std::make_pair(prop.extensionName, prop)); discoveredExtensions = true; } for (const char* ext : criticalExtensions) { if (availableExtensions.count(ext) > 0) result.supported.push_back(ext); else result.unsupportedCritical.push_back(ext); } for (const std::string& ext : requestedExtensions) { if (availableExtensions.count(ext) > 0) result.supported.push_back(ext.c_str()); else result.unsupported.push_back(ext.c_str()); } return result; } std::vector Engine::getAvailableVulkanExtensions() { unsigned int extCount = 0; VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); if (res != VK_SUCCESS) throw std::runtime_error("unable to query vulkan extension property count"); std::vector extensions(extCount); res = vkEnumerateInstanceExtensionProperties(nullptr, &extCount, extensions.data()); if (res != VK_SUCCESS) throw std::runtime_error("unable to retrieve vulkan instance layer names"); return extensions; } void Engine::populateDebugMessengerCreateInfo( VkDebugUtilsMessengerCreateInfoEXT& createInfo, PFN_vkDebugUtilsMessengerCallbackEXT debugCallback) { createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.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; createInfo.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; createInfo.pfnUserCallback = debugCallback; createInfo.pUserData = nullptr; // Optional } std::vector Engine::getAvailableVulkanLayers() { unsigned int layerCount = 0; VkResult res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); if (res != VK_SUCCESS) throw std::runtime_error("unable to query vulkan instance layer property count"); std::vector layers(layerCount); res = vkEnumerateInstanceLayerProperties(&layerCount, layers.data()); if (res != VK_SUCCESS) throw std::runtime_error("unable to retrieve vulkan instance layer names"); return layers; } VkResult Engine::createDebugUtilsMessengerEXT( VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) { PFN_vkVoidFunction vdfunc = vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)(vdfunc); if (func != nullptr) return func(instance, pCreateInfo, pAllocator, pDebugMessenger); else return VK_ERROR_EXTENSION_NOT_PRESENT; } void Engine::destroyDebugUtilsMessengerEXT( VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { PFN_vkVoidFunction vdfunc = vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)(vdfunc); if (func != nullptr) func(instance, debugMessenger, pAllocator); } Engine::Support::Support(): supported(), unsupported(), unsupportedCritical() {} void Engine::Support::logSupported(const std::string& header) { if (!supported.empty()) { std::cout << header << std::endl; for (const char* element : supported) std::cout << "\t" << element << std::endl; } } bool Engine::SwapChainSupportDetails::adequate() const { return !formats.empty() && !presentModes.empty(); } bool Engine::QueueFamilyIndices::isComplete() const { return graphicsFamily.has_value() && presentFamily.has_value(); } std::vector Engine::readFile(const std::string& filename) { std::ifstream file(filename, std::ios::ate | std::ios::binary); if (!file.is_open()) throw std::runtime_error("failed to open file " + filename); size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize); file.seekg(0); file.read(buffer.data(), fileSize); file.close(); return buffer; } VkSurfaceFormatKHR Engine::chooseSwapSurfaceFormat(const std::vector& availableFormats) { for (const VkSurfaceFormatKHR& availableFormat : availableFormats) { if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) return availableFormat; } return availableFormats[0]; } VkPresentModeKHR Engine::chooseSwapPresentMode(const std::vector& availablePresentModes) { for (const auto& availablePresentMode : availablePresentModes) { if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) return availablePresentMode; } return VK_PRESENT_MODE_FIFO_KHR; }