diff --git a/NothinFancy/src/client/render/RenderEngine.cpp b/NothinFancy/src/client/render/RenderEngine.cpp index de479f7..0ad545a 100644 --- a/NothinFancy/src/client/render/RenderEngine.cpp +++ b/NothinFancy/src/client/render/RenderEngine.cpp @@ -10,13 +10,17 @@ namespace nf::cli::render { , m_display(display) , m_instance() , m_surface() + , m_physicalDevice() + , m_queueFIGraphics() + , m_queueFIPresent() { NFLog("Initializing render engine"); - createInstance(); - createSurface(m_window->getHandle()); - m_window->setDisplay(m_display); m_window->show(); + + createInstance(); + createSurface(m_window->getHandle()); + pickPhysicalDevice(); } void RenderEngine::createInstance() { @@ -44,6 +48,83 @@ namespace nf::cli::render { NFError("Could not create Vulkan surface"); } + void RenderEngine::pickPhysicalDevice() { + // TODO: Save GPU choice in DisplayConfig + // First, get list of all GPUs + uint32_t numPhysicalDevices = 0; + vkEnumeratePhysicalDevices(m_instance, &numPhysicalDevices, nullptr); + if (numPhysicalDevices == 0) + NFError("No Vulkan GPUs found"); + + std::vector physicalDevices(numPhysicalDevices); + vkEnumeratePhysicalDevices(m_instance, &numPhysicalDevices, physicalDevices.data()); + + // Then gather information on them and save first dedicated + std::optional firstDedicatedPhysicalDeviceIndex; + std::vector physicalDeviceProperties; + for (int i = 0; i < numPhysicalDevices; i++) { + VkPhysicalDeviceProperties currentPhysicalDeviceProperties = {}; + vkGetPhysicalDeviceProperties(physicalDevices[i], ¤tPhysicalDeviceProperties); + if (currentPhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && !firstDedicatedPhysicalDeviceIndex.has_value()) + firstDedicatedPhysicalDeviceIndex = i; + + physicalDeviceProperties.push_back(currentPhysicalDeviceProperties); + } + + // Try dedicated first, then try every GPU in order + if (firstDedicatedPhysicalDeviceIndex.has_value()) { + int dedicatedIndex = firstDedicatedPhysicalDeviceIndex.value(); + physicalDevices.insert(physicalDevices.begin(), physicalDevices[dedicatedIndex]); + physicalDevices.erase(physicalDevices.begin() + dedicatedIndex + 1); + physicalDeviceProperties.insert(physicalDeviceProperties.begin(), physicalDeviceProperties[dedicatedIndex]); + physicalDeviceProperties.erase(physicalDeviceProperties.begin() + dedicatedIndex + 1); + } + + struct PhysicalDeviceQueueFamilyIndices { + uint32_t graphics, present; + }; + + auto getQueueFamilyIndices = [&](int currentPhysicalDeviceIndex) -> std::optional { + uint32_t numQueueFamilies = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[currentPhysicalDeviceIndex], &numQueueFamilies, nullptr); + std::vector queueFamilyProperties(numQueueFamilies); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[currentPhysicalDeviceIndex], &numQueueFamilies, queueFamilyProperties.data()); + std::optional graphicsIndex, presentIndex; + + for (int i = 0; i < numQueueFamilies; i++) { + if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT && !graphicsIndex.has_value()) + graphicsIndex = i; + + VkBool32 hasPresentSupport = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevices[currentPhysicalDeviceIndex], i, m_surface, &hasPresentSupport); + if (hasPresentSupport && !presentIndex.has_value()) + presentIndex = i; + } + + if (graphicsIndex.has_value() && presentIndex.has_value()) + return PhysicalDeviceQueueFamilyIndices{ graphicsIndex.value(), presentIndex.value() }; + + return std::nullopt; + }; + + std::optional chosenPhysicalDeviceIndices; + for (int i = 0; i < numPhysicalDevices; i++) { + chosenPhysicalDeviceIndices = getQueueFamilyIndices(i); + if (chosenPhysicalDeviceIndices.has_value()) { + // GPU found! + m_physicalDevice = physicalDevices[i]; + m_queueFIGraphics = chosenPhysicalDeviceIndices->graphics; + m_queueFIPresent = chosenPhysicalDeviceIndices->present; + + NFLog(std::format("GPU - {}", physicalDeviceProperties[i].deviceName)); + break; + } + } + + if (m_physicalDevice == nullptr) + NFError("No Vulkan GPUs were found to be compatible"); + } + RenderEngine::~RenderEngine() { vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroyInstance(m_instance, nullptr); diff --git a/NothinFancy/src/client/render/RenderEngine.h b/NothinFancy/src/client/render/RenderEngine.h index b3743f9..554cd87 100644 --- a/NothinFancy/src/client/render/RenderEngine.h +++ b/NothinFancy/src/client/render/RenderEngine.h @@ -13,11 +13,14 @@ namespace nf::cli::render { private: void createInstance(); void createSurface(HWND window); + void pickPhysicalDevice(); std::shared_ptr m_window; DisplayConfig m_display; VkInstance m_instance; VkSurfaceKHR m_surface; + VkPhysicalDevice m_physicalDevice; + uint32_t m_queueFIGraphics, m_queueFIPresent; }; }