stories/engine/instance.cpp

163 lines
5.8 KiB
C++

#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<const char*>& 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<uint32_t>(exts.supported.size());
createInfo.ppEnabledExtensionNames = exts.supported.data();
createInfo.enabledLayerCount = static_cast<uint32_t>(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<std::set<std::string>::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<std::set<std::string>::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<VkPhysicalDevice> Engine::Instance::enumeratePhysicalDevices() const {
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(vk, &deviceCount, nullptr);
std::vector<VkPhysicalDevice> devices(deviceCount);
if (deviceCount > 0)
vkEnumeratePhysicalDevices(vk, &deviceCount, devices.data());
return devices;
}
std::vector<const char *> Engine::Instance::getLayers() const {
return layers;
}