diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index ac538984b0ebbce7462fb0c2c5dec52ba991f64f..48ce7c3e7002a882fcff693b272835d1f0ed27f7 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -1,15 +1,10 @@ #include "Context.hpp" -std::vector<const char*> validationLayers = { - "VK_LAYER_KHRONOS_validation" -}; - - namespace vkcv { Context::Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device) - : m_instance(instance), m_physicalDevice(physicalDevice), m_device(device) + : m_instance(instance), m_physicalDevice(physicalDevice), m_device(device) {} Context::~Context() { @@ -19,49 +14,64 @@ namespace vkcv { Context Context::create(const char* applicationName, uint32_t applicationVersion, uint32_t queueCount, std::vector<vk::QueueFlagBits> queueFlags, std::vector<const char*> instanceExtensions, std::vector<const char*> deviceExtensions) { glfwInit(); - + // check for layer support uint32_t layerCount = 0; vk::enumerateInstanceLayerProperties(&layerCount, nullptr); std::vector<vk::LayerProperties> layerProperties(layerCount); vk::enumerateInstanceLayerProperties(&layerCount, layerProperties.data()); std::vector<const char*> supportedLayers; - for (auto& elem : layerProperties) + for (auto& elem : layerProperties) { supportedLayers.push_back(elem.layerName); + } - // if in debug mode, check if validation layers are supported. Enable them if supported - if (enableValidationLayers && !Context::checkSupport(supportedLayers, validationLayers)) +// if in debug mode, check if validation layers are supported. Enable them if supported +#if _DEBUG + std::vector<const char*> validationLayers = { + "VK_LAYER_KHRONOS_validation" + }; + if (!Context::checkSupport(supportedLayers, validationLayers)) { throw std::runtime_error("Validation layers requested but not available!"); - + } +#endif + + // check for extension support std::vector<vk::ExtensionProperties> instanceExtensionProperties = vk::enumerateInstanceExtensionProperties(); std::vector<const char*> supportedExtensions; - for (auto& elem : instanceExtensionProperties) + for (auto& elem : instanceExtensionProperties) { supportedExtensions.push_back(elem.extensionName); - if (!checkSupport(supportedExtensions, instanceExtensions)) + } + if (!checkSupport(supportedExtensions, instanceExtensions)) { throw std::runtime_error("The requested instance extensions are not supported!"); + } // for GLFW: get all required extensions std::vector<const char*> requiredExtensions = Context::getRequiredExtensions(); instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end()); - const vk::ApplicationInfo applicationInfo ( - applicationName, - applicationVersion, - "vkCV", - VK_MAKE_VERSION(0, 0, 1), - VK_HEADER_VERSION_COMPLETE + const vk::ApplicationInfo applicationInfo( + applicationName, + applicationVersion, + "vkCV", + VK_MAKE_VERSION(0, 0, 1), + VK_HEADER_VERSION_COMPLETE ); - const vk::InstanceCreateInfo instanceCreateInfo( + vk::InstanceCreateInfo instanceCreateInfo( vk::InstanceCreateFlags(), &applicationInfo, - (enableValidationLayers) ? static_cast<uint32_t>(validationLayers.size()) : 0, - (enableValidationLayers) ? validationLayers.data() : nullptr, + 0, + nullptr, static_cast<uint32_t>(instanceExtensions.size()), instanceExtensions.data() ); +#if _DEBUG + instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); + instanceCreateInfo.ppEnabledLayerNames = validationLayers.data(); +#endif + vk::Instance instance = vk::createInstance(instanceCreateInfo); std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices(); @@ -70,28 +80,36 @@ namespace vkcv { // check for physical device extension support std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties(); supportedExtensions.clear(); - for (auto& elem : deviceExtensionProperties) + for (auto& elem : deviceExtensionProperties) { supportedExtensions.push_back(elem.extensionName); - if (!checkSupport(supportedExtensions, deviceExtensions)) + } + if (!checkSupport(supportedExtensions, deviceExtensions)) { throw std::runtime_error("The requested device extensions are not supported by the physical device!"); + } // create required queues std::vector<vk::DeviceQueueCreateInfo> qCreateInfos = getQueueCreateInfos(physicalDevice, queueCount, queueFlags); - const vk::DeviceCreateInfo deviceCreateInfo ( - vk::DeviceCreateFlags(), - qCreateInfos.size(), - qCreateInfos.data(), - (enableValidationLayers) ? static_cast<uint32_t>(validationLayers.size()) : 0, - (enableValidationLayers) ? validationLayers.data() : nullptr, - deviceExtensions.size(), - deviceExtensions.data(), - nullptr // Should our device use some features??? If yes: TODO + vk::DeviceCreateInfo deviceCreateInfo( + vk::DeviceCreateFlags(), + qCreateInfos.size(), + qCreateInfos.data(), + 0, + nullptr, + deviceExtensions.size(), + deviceExtensions.data(), + nullptr // Should our device use some features??? If yes: TODO ); - + +#if _DEBUG + deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); + deviceCreateInfo.ppEnabledLayerNames = validationLayers.data(); +#endif + + vk::Device device = physicalDevice.createDevice(deviceCreateInfo); // TODO: implement device.getQueue() to access the queues, if needed - + return Context(instance, physicalDevice, device); } @@ -115,13 +133,12 @@ namespace vkcv { /// <seealso cref="Context.deviceScore"> vk::PhysicalDevice Context::pickPhysicalDevice(vk::Instance& instance) { vk::PhysicalDevice phyDevice; - uint32_t deviceCount = 0; - instance.enumeratePhysicalDevices(&deviceCount, nullptr); - if (deviceCount == 0) { + std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices(); + + if (devices.size() == 0) { throw std::runtime_error("failed to find GPUs with Vulkan support!"); } - std::vector<vk::PhysicalDevice> devices(deviceCount); - instance.enumeratePhysicalDevices(&deviceCount, devices.data()); + int max_score = -1; for (const auto& device : devices) { int score = deviceScore(device); @@ -131,7 +148,7 @@ namespace vkcv { } } - if (&phyDevice == nullptr) { + if (max_score == -1) { throw std::runtime_error("failed to find a suitable GPU!"); } @@ -165,15 +182,10 @@ namespace vkcv { score *= vram; if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { - // nice! score *= 2; } - else if (properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu) { - // not perfect but ok - } - else { - // not so nice - score *= -1; + else if (properties.deviceType != vk::PhysicalDeviceType::eIntegratedGpu) { + score = -1; } return score; @@ -206,31 +218,17 @@ namespace vkcv { uint32_t create = queueCount; for (int i = 0; i < qFamilyCandidates.size() && create > 0; i++) { - const int availableQueues = qFamilyCandidates[i].queueCount; - if (create >= availableQueues) { - float* qPriorities = new float[availableQueues]; - std::fill_n(qPriorities, availableQueues, 1.f); // all queues have the same priorities - vk::DeviceQueueCreateInfo qCreateInfo( - vk::DeviceQueueCreateFlags(), - i, - qFamilyCandidates[i].queueCount, - qPriorities - ); - queueCreateInfos.push_back(qCreateInfo); - create -= qFamilyCandidates[i].queueCount; - } - else { - float* qPriorities = new float[create]; - std::fill_n(qPriorities, create, 1.f); // all queues have the same priorities - vk::DeviceQueueCreateInfo qCreateInfo( - vk::DeviceQueueCreateFlags(), - i, - create, - qPriorities - ); - queueCreateInfos.push_back(qCreateInfo); - create -= create; - } + const int maxCreatableQueues = std::min(create, qFamilyCandidates[i].queueCount); + float* qPriorities = new float[maxCreatableQueues]; // TO CHECK: this seems to solve validation layer errors but the array pointer will not be deleted + std::fill_n(qPriorities, maxCreatableQueues, 1.f); // all queues have the same priorities + vk::DeviceQueueCreateInfo qCreateInfo( + vk::DeviceQueueCreateFlags(), + i, + maxCreatableQueues, + qPriorities + ); + queueCreateInfos.push_back(qCreateInfo); + create -= maxCreatableQueues; } return queueCreateInfos; @@ -267,9 +265,9 @@ namespace vkcv { const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); - if (enableValidationLayers) { - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } +#if _DEBUG + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +#endif return extensions; } diff --git a/src/vkcv/Context.hpp b/src/vkcv/Context.hpp index e9b0f62446e2146982d20047f812ab52e6695182..e27c766b21ec9354be87ef81c8610734903c93b0 100644 --- a/src/vkcv/Context.hpp +++ b/src/vkcv/Context.hpp @@ -3,11 +3,6 @@ #include <GLFW/glfw3.h> #include <iostream> -#ifdef NDEBUG -const bool enableValidationLayers = false; -#else -const bool enableValidationLayers = true; -#endif namespace vkcv { @@ -41,7 +36,7 @@ namespace vkcv { static Context create(const char* applicationName, uint32_t applicationVersion, uint32_t queueCount = 1, const std::vector<vk::QueueFlagBits> queueFlags = {}, std::vector<const char*> instanceExtensions = {}, std::vector<const char*> deviceExtensions = {}); static bool checkSupport(std::vector<const char*> &supported, std::vector<const char*> &check); static std::vector<const char*> getRequiredExtensions(); - static vk::PhysicalDevice Context::pickPhysicalDevice(vk::Instance& instance); + static vk::PhysicalDevice pickPhysicalDevice(vk::Instance& instance); static int deviceScore(const vk::PhysicalDevice &physicalDevice); static std::vector<vk::DeviceQueueCreateInfo> getQueueCreateInfos(vk::PhysicalDevice& physicalDevice, uint32_t queueCount, std::vector<vk::QueueFlagBits> &queueFlags); };