From d455b8d4f7231b88e4b20ac172ead04dfd8137b2 Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Mon, 19 Sep 2022 22:10:44 +0100 Subject: [PATCH] Add vulkan device --- src/gfx_device_vulkan.cpp | 303 ++++++++++++++++++++------------------ 1 file changed, 163 insertions(+), 140 deletions(-) diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 6ba100c..280cd69 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -45,143 +45,13 @@ namespace engine::gfx { m_layerInfo = std::make_unique(true); #endif m_instance = std::make_shared(appInfo, *m_layerInfo, getRequiredVulkanExtensions(window)); + + volkLoadInstanceOnly(m_instance->getHandle()); + m_debugMessenger = std::make_unique(m_instance); + m_device = std::make_unique(m_instance); - // enumerate physical devices - uint32_t physDeviceCount = 0; - VkResult res; - res = vkEnumeratePhysicalDevices(m_instance->getHandle(), &physDeviceCount, nullptr); - assert(res == VK_SUCCESS); - if (physDeviceCount == 0) { - throw std::runtime_error("No GPU found with vulkan support!"); - } - std::vector physicalDevices(physDeviceCount); - res = vkEnumeratePhysicalDevices(m_instance->getHandle(), &physDeviceCount, physicalDevices.data()); - assert(res == VK_SUCCESS); - - // find suitable device - const std::vector requiredDeviceExtensions{ - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; - - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - - for (const auto& dev : physicalDevices) { - - uint32_t extensionCount; - res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, nullptr); - assert(res == VK_SUCCESS); - std::vector availableExtensions(extensionCount); - res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, availableExtensions.data()); - assert(res == VK_SUCCESS); - - bool suitable = true; - - for (const auto& extToFind : requiredDeviceExtensions) { - - bool extFound = false; - - for (const auto& ext : availableExtensions) { - if (strcmp(extToFind, ext.extensionName) == 0) { - extFound = true; - } - } - - if (!extFound) { - suitable = false; - } - } - - if (suitable) { - physicalDevice = dev; - break; - } - - } - - if (physicalDevice == VK_NULL_HANDLE) { - throw std::runtime_error("No suitable Vulkan physical device found"); - } - - VkPhysicalDeviceProperties devProps; - vkGetPhysicalDeviceProperties(physicalDevice, &devProps); - TRACE("Physical device to use: {}", devProps.deviceName); - - // queue families - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); - - std::optional graphicsFamilyIndex; - std::optional transferFamilyIndex; - std::optional computeFamilyIndex; - - for (uint32_t i = 0; i < queueFamilyCount; i++) { - VkQueueFamilyProperties family = queueFamilies[i]; - if (family.queueCount > 0) { - if (graphicsFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - TRACE("GRAPHICS:"); - graphicsFamilyIndex = i; - } - if (transferFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_TRANSFER_BIT) { - TRACE("TRANSFER:"); - transferFamilyIndex = i; - } - if (computeFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_COMPUTE_BIT) { - TRACE("COMPUTE:"); - computeFamilyIndex = i; - } - TRACE("\t\ti = {}\t\tcount = {}", i, family.queueCount); - } - } - if (graphicsFamilyIndex.has_value() == false || transferFamilyIndex.has_value() == false) { - throw std::runtime_error("Unable to find a queue with the GRAPHICS family flag"); - } - - std::vector queueCreateInfos{}; - - // use a set to filter out duplicate indices - std::unordered_set uniqueQueueFamilies{ graphicsFamilyIndex.value(), transferFamilyIndex.value(), computeFamilyIndex.value() }; - float queuePriority = 1.0f; - for (uint32_t family : uniqueQueueFamilies) { - // create a queue for each unique type to ensure that there are queues available for graphics, transfer, and compute - TRACE("Creating queue from family {}", family); - VkDeviceQueueCreateInfo queueCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueFamilyIndex = family, - .queueCount = 1, - .pQueuePriorities = &queuePriority, - }; - queueCreateInfos.push_back(queueCreateInfo); - } - - VkDeviceCreateInfo deviceCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueCreateInfoCount = (uint32_t)queueCreateInfos.size(), - .pQueueCreateInfos = queueCreateInfos.data(), - // IGNORED: .enabledLayerCount - // IGNORED: .ppEnabledLayerNames - .enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(), - .ppEnabledExtensionNames = requiredDeviceExtensions.data(), - .pEnabledFeatures = nullptr, - }; - - VkDevice device; - - res = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device); - if (res != VK_SUCCESS) { - throw std::runtime_error("Unable to create Vulkan logical device, error code: " + std::to_string(res)); - } - - volkLoadDevice(device); - - vkDestroyDevice(device, nullptr); + volkLoadDevice(m_device->getHandle()); } @@ -286,8 +156,6 @@ namespace engine::gfx { } assert(res == VK_SUCCESS); - volkLoadInstanceOnly(m_handle); - } Instance(const Instance&) = delete; @@ -314,7 +182,7 @@ namespace engine::gfx { { VkDebugUtilsMessengerCreateInfoEXT createInfo = getCreateInfo(); - VkResult res = vkCreateDebugUtilsMessengerEXT(instance->getHandle(), &createInfo, nullptr, &m_messengerHandle); + VkResult res = vkCreateDebugUtilsMessengerEXT(m_instance->getHandle(), &createInfo, nullptr, &m_messengerHandle); assert(res == VK_SUCCESS); } @@ -361,8 +229,8 @@ namespace engine::gfx { } private: - VkDebugUtilsMessengerEXT m_messengerHandle; std::shared_ptr m_instance; + VkDebugUtilsMessengerEXT m_messengerHandle; enum class Severity { VERBOSE, @@ -409,9 +277,164 @@ namespace engine::gfx { }; + class Device { + + public: + Device(std::shared_ptr instance) : m_instance(instance) + { + // enumerate physical devices + uint32_t physDeviceCount = 0; + VkResult res; + res = vkEnumeratePhysicalDevices(m_instance->getHandle(), &physDeviceCount, nullptr); + assert(res == VK_SUCCESS); + if (physDeviceCount == 0) { + throw std::runtime_error("No GPU found with vulkan support!"); + } + std::vector physicalDevices(physDeviceCount); + res = vkEnumeratePhysicalDevices(m_instance->getHandle(), &physDeviceCount, physicalDevices.data()); + assert(res == VK_SUCCESS); + + // find suitable device + const std::vector requiredDeviceExtensions{ + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + + for (const auto& dev : physicalDevices) { + + uint32_t extensionCount; + res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, nullptr); + assert(res == VK_SUCCESS); + std::vector availableExtensions(extensionCount); + res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, availableExtensions.data()); + assert(res == VK_SUCCESS); + + bool suitable = true; + + for (const auto& extToFind : requiredDeviceExtensions) { + + bool extFound = false; + + for (const auto& ext : availableExtensions) { + if (strcmp(extToFind, ext.extensionName) == 0) { + extFound = true; + } + } + + if (!extFound) { + suitable = false; + } + } + + if (suitable) { + physicalDevice = dev; + break; + } + + } + + if (physicalDevice == VK_NULL_HANDLE) { + throw std::runtime_error("No suitable Vulkan physical device found"); + } + + VkPhysicalDeviceProperties devProps; + vkGetPhysicalDeviceProperties(physicalDevice, &devProps); + TRACE("Selected physical device: {}", devProps.deviceName); + + // queue families + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); + + std::optional graphicsFamilyIndex; + std::optional transferFamilyIndex; + std::optional computeFamilyIndex; + + for (uint32_t i = 0; i < queueFamilyCount; i++) { + VkQueueFamilyProperties family = queueFamilies[i]; + if (family.queueCount > 0) { + if (graphicsFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + TRACE("GRAPHICS:"); + graphicsFamilyIndex = i; + } + if (transferFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_TRANSFER_BIT) { + TRACE("TRANSFER:"); + transferFamilyIndex = i; + } + if (computeFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_COMPUTE_BIT) { + TRACE("COMPUTE:"); + computeFamilyIndex = i; + } + TRACE("\t\ti = {}\t\tcount = {}", i, family.queueCount); + } + } + if (graphicsFamilyIndex.has_value() == false || transferFamilyIndex.has_value() == false) { + throw std::runtime_error("Unable to find a queue with the GRAPHICS family flag"); + } + + std::vector queueCreateInfos{}; + + // use a set to filter out duplicate indices + std::unordered_set uniqueQueueFamilies{ graphicsFamilyIndex.value(), transferFamilyIndex.value(), computeFamilyIndex.value() }; + float queuePriority = 1.0f; + for (uint32_t family : uniqueQueueFamilies) { + // create a queue for each unique type to ensure that there are queues available for graphics, transfer, and compute + TRACE("Creating queue from family {}", family); + VkDeviceQueueCreateInfo queueCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = family, + .queueCount = 1, + .pQueuePriorities = &queuePriority, + }; + queueCreateInfos.push_back(queueCreateInfo); + } + + VkDeviceCreateInfo deviceCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueCreateInfoCount = (uint32_t)queueCreateInfos.size(), + .pQueueCreateInfos = queueCreateInfos.data(), + // IGNORED: .enabledLayerCount + // IGNORED: .ppEnabledLayerNames + .enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(), + .ppEnabledExtensionNames = requiredDeviceExtensions.data(), + .pEnabledFeatures = nullptr, + }; + + res = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &m_handle); + if (res != VK_SUCCESS) { + throw std::runtime_error("Unable to create Vulkan logical device, error code: " + std::to_string(res)); + } + } + Device(const Device&) = delete; + Device& operator=(const Device&) = delete; + + ~Device() + { + vkDestroyDevice(m_handle, nullptr); + } + + VkDevice getHandle() + { + return m_handle; + } + + private: + std::shared_ptr m_instance; + VkDevice m_handle; + + }; + std::unique_ptr m_layerInfo; std::shared_ptr m_instance; - std::unique_ptr m_debugMessenger; + std::unique_ptr m_debugMessenger; // uses instance + std::unique_ptr m_device; // uses instance /*