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 namespace PB::Renderer
{ {
void CleanupAllAndExit() void CleanupAllAndExit(int code)
{ {
if (!GLFWManager::Cleanup()) if (!GLFWManager::Cleanup())
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
@@ -13,7 +13,7 @@ namespace PB::Renderer
if (VulkanManager::Cleanup()) if (VulkanManager::Cleanup())
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
std::exit(EXIT_SUCCESS); std::exit(code);
} }
} }
@@ -29,17 +29,20 @@ int main()
if (!window) if (!window)
return -1; return -1;
/* Creates the Vulkan instance and surface */ /* Runs Vulkan initialisation functions */
if (std::optional<VkInstance> instance = VulkanManager::Init(); !instance) if (const std::optional<VkInstance> instance = VulkanManager::Init(); !instance)
{ {
GLFWManager::Cleanup(); GLFWManager::Cleanup();
return -1;
} }
if (std::optional<VkSurfaceKHR> surface = VulkanManager::CreateSurface(window); !surface) if (const std::optional<VkSurfaceKHR> surface = VulkanManager::CreateSurface(window); !surface)
{ {
CleanupAllAndExit(); CleanupAllAndExit(EXIT_FAILURE);
return -1; }
if (!VulkanManager::PickPhysicalDevice())
{
CleanupAllAndExit(EXIT_FAILURE);
} }
/* Polls window events whilst it is still open */ /* Polls window events whilst it is still open */
@@ -49,5 +52,5 @@ int main()
} }
/* Cleans up GLFW and Vulkan */ /* Cleans up GLFW and Vulkan */
CleanupAllAndExit(); CleanupAllAndExit(EXIT_SUCCESS);
} }

View File

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

View File

@@ -5,6 +5,9 @@ namespace PB::Renderer
std::optional<VkInstance> VulkanManager::s_Instance = std::nullopt; std::optional<VkInstance> VulkanManager::s_Instance = std::nullopt;
std::optional<VkSurfaceKHR> VulkanManager::s_Surface = 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() std::optional<VkInstance> VulkanManager::Init()
{ {
/* Stops multi initialisation */ /* Stops multi initialisation */
@@ -47,6 +50,12 @@ namespace PB::Renderer
std::optional<VkSurfaceKHR> VulkanManager::CreateSurface(GLFWwindow* window) 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; VkSurfaceKHR surface;
if (glfwCreateWindowSurface(s_Instance.value(), window, nullptr, &surface) != VK_SUCCESS) if (glfwCreateWindowSurface(s_Instance.value(), window, nullptr, &surface) != VK_SUCCESS)
{ {
@@ -54,9 +63,130 @@ namespace PB::Renderer
return std::nullopt; return std::nullopt;
} }
s_Surface = surface;
return 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() bool VulkanManager::Cleanup()
{ {
if (s_Surface != std::nullopt) if (s_Surface != std::nullopt)

View File

@@ -4,16 +4,35 @@
namespace PB::Renderer 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 class VulkanManager
{ {
private:
static std::optional<VkInstance> s_Instance;
static std::optional<VkSurfaceKHR> s_Surface;
public: public:
static std::optional<VkInstance> Init(); static std::optional<VkInstance> Init();
static bool Cleanup(); static bool Cleanup();
static std::optional<VkSurfaceKHR> CreateSurface(GLFWwindow* window); 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;
}; };
} }