Added pick device support

This commit is contained in:
Pasha Bibko
2025-11-15 19:19:43 +00:00
parent 2eb357b2ed
commit 12cdd4e515
4 changed files with 166 additions and 13 deletions

View File

@@ -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<VkInstance> instance = VulkanManager::Init(); !instance)
/* Runs Vulkan initialisation functions */
if (const std::optional<VkInstance> instance = VulkanManager::Init(); !instance)
{
GLFWManager::Cleanup();
return -1;
}
if (std::optional<VkSurfaceKHR> surface = VulkanManager::CreateSurface(window); !surface)
if (const std::optional<VkSurfaceKHR> 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);
}

View File

@@ -12,3 +12,4 @@
#include <iostream>
#include <optional>
#include <vector>
#include <set>

View File

@@ -5,6 +5,9 @@ namespace PB::Renderer
std::optional<VkInstance> VulkanManager::s_Instance = std::nullopt;
std::optional<VkSurfaceKHR> VulkanManager::s_Surface = std::nullopt;
VkPhysicalDevice VulkanManager::s_PhysicalDevice = VK_NULL_HANDLE;
QueueFamilyIndices VulkanManager::s_QueueIndices;
std::optional<VkInstance> VulkanManager::Init()
{
/* Stops multi initialisation */
@@ -47,6 +50,12 @@ namespace PB::Renderer
std::optional<VkSurfaceKHR> 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<VkPhysicalDevice> 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<VkQueueFamilyProperties> 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<const char*> REQUIRED_EXTENSIONS = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> 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)

View File

@@ -4,16 +4,35 @@
namespace PB::Renderer
{
struct QueueFamilyIndices
{
std::optional<uint32_t> graphicsFamily = std::nullopt;
std::optional<uint32_t> presentFamily = std::nullopt;
[[nodiscard]] bool Complete() const
{
return graphicsFamily && presentFamily;
}
};
class VulkanManager
{
private:
static std::optional<VkInstance> s_Instance;
static std::optional<VkSurfaceKHR> s_Surface;
public:
static std::optional<VkInstance> Init();
static bool Cleanup();
static std::optional<VkSurfaceKHR> 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<VkInstance> s_Instance;
static std::optional<VkSurfaceKHR> s_Surface;
static VkPhysicalDevice s_PhysicalDevice;
static QueueFamilyIndices s_QueueIndices;
};
}