From 930bba636eaf0f6add36fc7f0f6e637f97ac0fe5 Mon Sep 17 00:00:00 2001 From: Jayden Grubb Date: Sat, 12 Apr 2025 20:27:30 +1000 Subject: [PATCH] Check surface support when choosing device --- engine/include/nova/render/render_device.h | 18 ++++++++++--- engine/include/nova/render/render_driver.h | 3 ++- engine/src/drivers/vulkan/render_driver.cpp | 24 +++++++++++++----- engine/src/drivers/vulkan/render_driver.h | 1 + engine/src/render/render_device.cpp | 28 +++++++++++++++++---- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/engine/include/nova/render/render_device.h b/engine/include/nova/render/render_device.h index d0d75cc..a5b091b 100644 --- a/engine/include/nova/render/render_device.h +++ b/engine/include/nova/render/render_device.h @@ -9,12 +9,16 @@ #include #include +#include +#include #include -#include namespace Nova { - struct RenderDevice { - static constexpr u32 AUTO = static_cast(-1); + using SurfaceID = uptr; + + class RenderDriver; + + struct NOVA_API RenderDevice { enum class Vendor { UNKNOWN = 0, INTEL = 0x8086, AMD = 0x1002, NVIDIA = 0x10de }; enum class Type { OTHER = 0, INTEGRATED = 1, DISCRETE = 2, VIRTUAL = 3, CPU = 4 }; @@ -24,6 +28,12 @@ namespace Nova { u32 deviceID; void* handle; - NOVA_API static u32 choose_device(const std::vector& devices); + static u32 choose_device(RenderDriver* driver, std::span surfaces = {}); + static u32 choose_device(RenderDriver* driver, std::initializer_list surfaces) { + return choose_device(driver, {surfaces.begin(), surfaces.end()}); + } + static u32 choose_device(RenderDriver* driver, SurfaceID surface) { + return choose_device(driver, {surface}); + } }; } // namespace Nova diff --git a/engine/include/nova/render/render_driver.h b/engine/include/nova/render/render_driver.h index f7ac2eb..739fed2 100644 --- a/engine/include/nova/render/render_driver.h +++ b/engine/include/nova/render/render_driver.h @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -17,6 +16,7 @@ namespace Nova { using WindowID = uptr; using SurfaceID = uptr; + struct RenderDevice; class WindowDriver; class NOVA_API RenderDriver { @@ -31,6 +31,7 @@ namespace Nova { [[nodiscard]] virtual u32 get_device_count() const = 0; [[nodiscard]] virtual const RenderDevice& get_device(u32 index) const = 0; + [[nodiscard]] virtual bool get_device_supports_surface(u32 index, SurfaceID surface) const = 0; virtual void select_device(u32 index) = 0; [[nodiscard]] virtual SurfaceID create_surface(WindowID window) = 0; diff --git a/engine/src/drivers/vulkan/render_driver.cpp b/engine/src/drivers/vulkan/render_driver.cpp index 4db9cef..3f12e36 100644 --- a/engine/src/drivers/vulkan/render_driver.cpp +++ b/engine/src/drivers/vulkan/render_driver.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -73,15 +74,26 @@ const RenderDevice& VulkanRenderDriver::get_device(const u32 index) const { return m_devices[index]; } +bool VulkanRenderDriver::get_device_supports_surface(const u32 index, const SurfaceID surface) const { + NOVA_AUTO_TRACE(); + NOVA_ASSERT(index < m_devices.size()); + NOVA_ASSERT(surface); + + // TODO: Check other queue families? + + SurfaceData* data = reinterpret_cast(surface); + VkBool32 supported = false; + if (vkGetPhysicalDeviceSurfaceSupportKHR(static_cast(m_devices[index].handle), 0, data->handle, &supported) + != VK_SUCCESS) { + return false; + } + return supported; +} + void VulkanRenderDriver::select_device(u32 index) { NOVA_AUTO_TRACE(); NOVA_ASSERT(!m_device); - - if (index == RenderDevice::AUTO) { - index = RenderDevice::choose_device(m_devices); - } else { - NOVA_ASSERT(index < m_devices.size()); - } + NOVA_ASSERT(index < m_devices.size()); NOVA_LOG("Using device: {}", m_devices[index].name); m_physical_device = static_cast(m_devices[index].handle); diff --git a/engine/src/drivers/vulkan/render_driver.h b/engine/src/drivers/vulkan/render_driver.h index 5eb2946..43c15a8 100644 --- a/engine/src/drivers/vulkan/render_driver.h +++ b/engine/src/drivers/vulkan/render_driver.h @@ -31,6 +31,7 @@ namespace Nova { [[nodiscard]] u32 get_device_count() const override; [[nodiscard]] const RenderDevice& get_device(u32 index) const override; + [[nodiscard]] bool get_device_supports_surface(u32 index, SurfaceID surface) const override; void select_device(u32 index) override; [[nodiscard]] SurfaceID create_surface(WindowID window) override; diff --git a/engine/src/render/render_device.cpp b/engine/src/render/render_device.cpp index ea364fd..352ddf2 100644 --- a/engine/src/render/render_device.cpp +++ b/engine/src/render/render_device.cpp @@ -6,18 +6,31 @@ #include #include +#include using namespace Nova; -u32 RenderDevice::choose_device(const std::vector& devices) { +u32 RenderDevice::choose_device(RenderDriver* driver, std::span surfaces) { NOVA_AUTO_TRACE(); - u32 best_index = 0; + u32 best_index = -1; u32 best_score = 0; - for (u32 i = 0; i < devices.size(); i++) { - u32 score = 0; - switch (devices[i].type) { + for (u32 i = 0; i < driver->get_device_count(); i++) { + auto& device = driver->get_device(i); + u32 score = 1; + + for (SurfaceID surface : surfaces) { + if (!driver->get_device_supports_surface(i, surface)) { + score = 0; + break; + } + } + if (score == 0) { + continue; + } + + switch (device.type) { case Type::DISCRETE: score += 4; break; @@ -33,11 +46,16 @@ u32 RenderDevice::choose_device(const std::vector& devices) { default: break; } + if (score > best_score) { best_index = i; best_score = score; } } + if (best_index == -1U) { + throw std::runtime_error("No suitable render device found"); + } + return best_index; }