diff --git a/main.cpp b/main.cpp index d3b86bf..9276e0d 100644 --- a/main.cpp +++ b/main.cpp @@ -5,7 +5,7 @@ namespace PB::Renderer { - void CleanupAllAndExit() + void CleanupAllAndExit(int code) { if (!GLFWManager::Cleanup()) std::exit(EXIT_FAILURE); @@ -13,7 +13,7 @@ namespace PB::Renderer if (VulkanManager::Cleanup()) std::exit(EXIT_FAILURE); - std::exit(EXIT_SUCCESS); + std::exit(code); } } @@ -29,17 +29,20 @@ int main() if (!window) return -1; - /* Creates the Vulkan instance and surface */ - if (std::optional instance = VulkanManager::Init(); !instance) + /* Runs Vulkan initialisation functions */ + if (const std::optional instance = VulkanManager::Init(); !instance) { GLFWManager::Cleanup(); - return -1; } - if (std::optional surface = VulkanManager::CreateSurface(window); !surface) + if (const std::optional surface = VulkanManager::CreateSurface(window); !surface) { - CleanupAllAndExit(); - return -1; + CleanupAllAndExit(EXIT_FAILURE); + } + + if (!VulkanManager::PickPhysicalDevice()) + { + CleanupAllAndExit(EXIT_FAILURE); } /* Polls window events whilst it is still open */ @@ -49,5 +52,5 @@ int main() } /* Cleans up GLFW and Vulkan */ - CleanupAllAndExit(); + CleanupAllAndExit(EXIT_SUCCESS); } diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index deb073b..1814e12 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -12,3 +12,4 @@ #include #include #include +#include diff --git a/src/managers/VulkanManager.cpp b/src/managers/VulkanManager.cpp index 23c5231..38eb51f 100644 --- a/src/managers/VulkanManager.cpp +++ b/src/managers/VulkanManager.cpp @@ -5,6 +5,9 @@ namespace PB::Renderer std::optional VulkanManager::s_Instance = std::nullopt; std::optional VulkanManager::s_Surface = std::nullopt; + VkPhysicalDevice VulkanManager::s_PhysicalDevice = VK_NULL_HANDLE; + QueueFamilyIndices VulkanManager::s_QueueIndices; + std::optional VulkanManager::Init() { /* Stops multi initialisation */ @@ -47,6 +50,12 @@ namespace PB::Renderer std::optional VulkanManager::CreateSurface(GLFWwindow* window) { + if (s_Instance == std::nullopt) + { + std::cout << "PB::Renderer::VulkanManager::CreateSurface(): No Vulkan instance" << std::endl; + return std::nullopt; + } + VkSurfaceKHR surface; if (glfwCreateWindowSurface(s_Instance.value(), window, nullptr, &surface) != VK_SUCCESS) { @@ -54,9 +63,130 @@ namespace PB::Renderer return std::nullopt; } + s_Surface = surface; return surface; } + bool VulkanManager::PickPhysicalDevice() + { + if (s_Instance == std::nullopt || s_Surface == std::nullopt) + { + std::cout << "PB::Renderer::VulkanManager::PickPhysicalDevice(): No Vulkan instance or surface" << std::endl; + return false; + } + + const VkInstance& instance = s_Instance.value(); + const VkSurfaceKHR& surface = s_Surface.value(); + + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + if (deviceCount == 0) + { + std::cout << "PB::Renderer::VulkanManager::PickPhysicalDevice(): No GPU with Vulkan support" << std::endl; + return false; + } + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + + for (const auto& device : devices) + { + if (IsDeviceSuitable(device, surface)) + { + s_PhysicalDevice = device; + s_QueueIndices = FindQueueFamilies(device, surface); + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + + std::cout << "Selected GPU: "<< deviceProperties.deviceName << std::endl; + + return true; + } + } + + std::cout << "Failed to find a suitable GPU" << std::endl; + return false; + } + + bool VulkanManager::IsDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface) + { + const QueueFamilyIndices indices = FindQueueFamilies(device, surface); + + if (const bool extensionsSupported = CheckDeviceExtensionSupport(device); !extensionsSupported) + return false; + + VkSurfaceCapabilitiesKHR capabilities; + uint32_t formatCount, presentCount; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentCount, nullptr); + const bool swapChainAdequate = formatCount > 0 && presentCount > 0; + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + + const bool discreteGPU = deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; + return indices.Complete() && swapChainAdequate && discreteGPU; + } + + QueueFamilyIndices VulkanManager::FindQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface) + { + QueueFamilyIndices indices; + + uint32_t queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + + int index = -1; + for (const auto& family : queueFamilies) + { + if (family.queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + indices.graphicsFamily = index; + } + + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, index, surface, &presentSupport); + if (presentSupport) + { + indices.presentFamily = index; + } + + if (indices.Complete()) + { + break; + } + + index++; + } + + return indices; + } + + bool VulkanManager::CheckDeviceExtensionSupport(VkPhysicalDevice device) + { + const std::vector REQUIRED_EXTENSIONS = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); + + std::set required(REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); + for (const auto& [extensionName, specVersion] : availableExtensions) + { + required.erase(extensionName); + } + + return required.empty(); + + } + bool VulkanManager::Cleanup() { if (s_Surface != std::nullopt) diff --git a/src/managers/VulkanManager.h b/src/managers/VulkanManager.h index 0d604d2..823d99d 100644 --- a/src/managers/VulkanManager.h +++ b/src/managers/VulkanManager.h @@ -4,16 +4,35 @@ namespace PB::Renderer { + struct QueueFamilyIndices + { + std::optional graphicsFamily = std::nullopt; + std::optional presentFamily = std::nullopt; + + [[nodiscard]] bool Complete() const + { + return graphicsFamily && presentFamily; + } + }; + class VulkanManager { - private: - static std::optional s_Instance; - static std::optional s_Surface; - public: static std::optional Init(); static bool Cleanup(); static std::optional CreateSurface(GLFWwindow* window); + static bool PickPhysicalDevice(); + + private: + static bool IsDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface); + static QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface); + static bool CheckDeviceExtensionSupport(VkPhysicalDevice device); + + static std::optional s_Instance; + static std::optional s_Surface; + + static VkPhysicalDevice s_PhysicalDevice; + static QueueFamilyIndices s_QueueIndices; }; }