163 lines
5.8 KiB
C++
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;
|
|
}
|