#include "instance.h" constexpr const char* validationLayerName("VK_LAYER_KHRONOS_validation"); Engine::Instance::Instance() : initialized(false), validationLayersEnabledAndSupported(false), layerNames(), extensionNames(), layers(), extensions(), vk(), debugMessenger() {} Engine::Instance::~Instance() { deinitialize(); } void Engine::Instance::initialize(const std::vector& requiredExtensions) { if (initialized) return; VkApplicationInfo appInfo {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Hello Triangle"; appInfo.applicationVersion = VK_MAKE_VERSION(0, 0, 1); appInfo.pEngineName = "Stories"; appInfo.engineVersion = VK_MAKE_VERSION(0, 0, 1); appInfo.apiVersion = VK_API_VERSION_1_0; appInfo.pNext = nullptr; //TODO handle exception Support exts = getVulkanExtensions(extensionNames, requiredExtensions); if (exts.unsupportedCritical.size() > 0) { std::string error("Unable to create Vulkan instance, following critical extensions are unsupported:\n"); for (const char* ext : exts.unsupportedCritical) error += "\t" + std::string(ext) + "\n"; throw std::runtime_error(error); } //TODO log unsupported; exts.logSupported("Applying extensions:"); //TODO handle exception Support layers = getVulkanLayers(layerNames); //TODO log unsupported layers.logSupported("Applying layers:"); VkInstanceCreateInfo createInfo {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; createInfo.flags = 0; createInfo.enabledExtensionCount = static_cast(exts.supported.size()); createInfo.ppEnabledExtensionNames = exts.supported.data(); createInfo.enabledLayerCount = static_cast(layers.supported.size()); createInfo.ppEnabledLayerNames = layers.supported.data(); VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo {}; if (hasValidationLayers()) { validationLayersEnabledAndSupported = true; //TODO make sure it's actually supported, this shows that they are just enabled; populateDebugMessengerCreateInfo(debugCreateInfo, debugCallback); createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo; } VkResult res = vkCreateInstance(&createInfo, nullptr, &vk); switch (res) { case VK_SUCCESS: break; case VK_ERROR_INCOMPATIBLE_DRIVER: throw std::runtime_error("unable to create vulkan instance, cannot find a compatible Vulkan ICD"); case VK_ERROR_OUT_OF_HOST_MEMORY: throw std::runtime_error("unable to create vulkan instance, out of host memory"); case VK_ERROR_OUT_OF_DEVICE_MEMORY: throw std::runtime_error("unable to create vulkan instance, out of device memory"); case VK_ERROR_INITIALIZATION_FAILED: throw std::runtime_error("unable to create vulkan instance, initialization failed"); case VK_ERROR_LAYER_NOT_PRESENT: throw std::runtime_error("unable to create vulkan instance, layer not present"); case VK_ERROR_EXTENSION_NOT_PRESENT: throw std::runtime_error("unable to create vulkan instance, extension not present"); default: throw std::runtime_error("unable to create Vulkan instance: unknown error"); } if (validationLayersEnabledAndSupported) setupDebugMessenger(); initialized = true; } void Engine::Instance::deinitialize() { if (!initialized) return; if (validationLayersEnabledAndSupported) destroyDebugUtilsMessengerEXT(vk, debugMessenger, nullptr); vkDestroyInstance(vk, nullptr); initialized = false; } void Engine::Instance::addExtension(const std::string& extensionName) { if (initialized) throw std::runtime_error("Adding extension to an initialized engine is not supported yet"); std::pair::const_iterator, bool> pair = extensionNames.insert(extensionName); if (pair.second) extensions.push_back(pair.first->c_str()); } void Engine::Instance::addLayer(const std::string& layerName) { if (initialized) throw std::runtime_error("Adding layers to an initialized engine is not supported yet"); std::pair::const_iterator, bool> pair = layerNames.insert(layerName); if (pair.second) layers.push_back(pair.first->c_str()); } bool Engine::Instance::hasValidationLayers() { return extensionNames.count(VK_EXT_DEBUG_REPORT_EXTENSION_NAME) > 0 && extensionNames.count(VK_EXT_DEBUG_UTILS_EXTENSION_NAME) > 0 && layerNames.count(validationLayerName) > 0; } void Engine::Instance::enableDebug() { addLayer(validationLayerName); addExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); addExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } void Engine::Instance::setupDebugMessenger() { VkDebugUtilsMessengerCreateInfoEXT createInfo{}; populateDebugMessengerCreateInfo(createInfo, debugCallback); VkResult res = createDebugUtilsMessengerEXT(vk, &createInfo, nullptr, &debugMessenger); switch (res) { case VK_SUCCESS: break; case VK_ERROR_EXTENSION_NOT_PRESENT: throw std::runtime_error("failed to set up debug messenger: extension not present"); break; default: throw std::runtime_error("failed to set up debug messenger"); } } std::vector Engine::Instance::enumeratePhysicalDevices() const { uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(vk, &deviceCount, nullptr); std::vector devices(deviceCount); if (deviceCount > 0) vkEnumeratePhysicalDevices(vk, &deviceCount, devices.data()); return devices; } std::vector Engine::Instance::getLayers() const { return layers; }