From ee2637cd36e8fb02cdf6e2aae870906d42044008 Mon Sep 17 00:00:00 2001 From: Jayden Grubb Date: Sun, 16 Mar 2025 00:15:24 +1000 Subject: [PATCH] Add RenderDriver::create_device() --- engine/include/nova/render/render_driver.h | 1 + engine/src/drivers/vulkan/render_driver.cpp | 134 +++++++++++++++++++- engine/src/drivers/vulkan/render_driver.h | 13 +- 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/engine/include/nova/render/render_driver.h b/engine/include/nova/render/render_driver.h index ee44118..528faf2 100644 --- a/engine/include/nova/render/render_driver.h +++ b/engine/include/nova/render/render_driver.h @@ -21,5 +21,6 @@ namespace Nova { [[nodiscard]] virtual u32 get_device_count() const = 0; [[nodiscard]] virtual const RenderDevice& get_device(u32 index) const = 0; + virtual void create_device(u32 index) = 0; }; } // namespace Nova diff --git a/engine/src/drivers/vulkan/render_driver.cpp b/engine/src/drivers/vulkan/render_driver.cpp index 1b08b17..57a788e 100644 --- a/engine/src/drivers/vulkan/render_driver.cpp +++ b/engine/src/drivers/vulkan/render_driver.cpp @@ -25,12 +25,17 @@ VulkanRenderDriver::VulkanRenderDriver() { _check_extensions(); _check_layers(); _init_instance(); - _init_devices(); + _init_hardware(); } VulkanRenderDriver::~VulkanRenderDriver() { NOVA_AUTO_TRACE(); - vkDestroyInstance(m_instance, _get_allocator(VK_OBJECT_TYPE_INSTANCE)); + if (m_device) { + vkDestroyDevice(m_device, _get_allocator(VK_OBJECT_TYPE_DEVICE)); + } + if (m_instance) { + vkDestroyInstance(m_instance, _get_allocator(VK_OBJECT_TYPE_INSTANCE)); + } } RenderAPI VulkanRenderDriver::get_api() const { @@ -51,6 +56,24 @@ const RenderDevice& VulkanRenderDriver::get_device(const u32 index) const { return m_devices[index]; } +void VulkanRenderDriver::create_device(const u32 index) { + NOVA_AUTO_TRACE(); + + if (m_device) { + NOVA_ERROR("VkDevice already created"); + return; + } + + m_physical_device = static_cast(m_devices[index].handle); + std::vector queues; + + _check_device_extensions(); + _check_device_features(); + // TODO: Check device capabilities + _init_queues(queues); + _init_device(queues); +} + void VulkanRenderDriver::_check_version() const { NOVA_AUTO_TRACE(); @@ -169,7 +192,7 @@ void VulkanRenderDriver::_init_instance() { NOVA_LOG("VkInstance created"); } -void VulkanRenderDriver::_init_devices() { +void VulkanRenderDriver::_init_hardware() { NOVA_AUTO_TRACE(); u32 count; @@ -189,9 +212,114 @@ void VulkanRenderDriver::_init_devices() { m_devices.back().type = static_cast(properties.deviceType); m_devices.back().deviceID = properties.deviceID; m_devices.back().handle = device; + + NOVA_LOG("Found device: {}", properties.deviceName); } } +void VulkanRenderDriver::_check_device_extensions() { + NOVA_AUTO_TRACE(); + + std::unordered_map requested; // + requested[VK_KHR_SWAPCHAIN_EXTENSION_NAME] = true; + // TODO: Add other device extensions + + // Get available extensions + u32 count; + vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &count, nullptr); // TODO: Check result + std::vector available(count); + vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &count, available.data()); // TODO: Check result + + // Check found extensions + for (const auto& extension : available) { + if (auto it = requested.find(extension.extensionName); it != requested.end()) { + NOVA_LOG("Using device extension: {}", extension.extensionName); + m_device_extensions.push_back(it->first.data()); + requested.erase(it); + } + } + + // Check remaining extensions + bool error = false; + for (auto [name, required] : requested) { + if (required) { + NOVA_ERROR("Required device extension not found: {}", name); + error = true; + } else { + NOVA_WARN("Optional device extension not found: {}", name); + } + } + if (error) { + throw std::runtime_error("Failed to find required device extensions"); + } +} + +void VulkanRenderDriver::_check_device_features() { + NOVA_AUTO_TRACE(); + + vkGetPhysicalDeviceFeatures(m_physical_device, &m_features); + // TODO: Check required features + // TODO: Disable unwanted features + + NOVA_WARN("{}() not implemented", NOVA_FUNC_NAME); +} + +void VulkanRenderDriver::_init_queues(std::vector& queues) const { + NOVA_AUTO_TRACE(); + + u32 count; + vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &count, nullptr); + std::vector available(count); + vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &count, available.data()); + + constexpr VkQueueFlags mask = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + static float priority = 1.0f; + VkQueueFlags found = 0; + + for (u32 i = 0; i < count; i++) { + if ((available[i].queueFlags & mask) == 0) { + continue; + } + if (!available[i].queueCount) { + continue; + } + + NOVA_LOG("Using queue family: {}", i); + found |= available[i].queueFlags; + + queues.emplace_back(); + queues.back().sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queues.back().queueFamilyIndex = i; + queues.back().queueCount = 1; // TODO: Does it make sense to have more than one queue? + queues.back().pQueuePriorities = &priority; + } + + if ((found & mask) != mask) { + throw std::runtime_error("Failed to find required queue family"); + } +} + +void VulkanRenderDriver::_init_device(const std::vector& queues) { + NOVA_AUTO_TRACE(); + + VkDeviceCreateInfo create {}; + create.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + create.enabledLayerCount = m_layers.size(); + create.ppEnabledLayerNames = m_layers.data(); + create.enabledExtensionCount = m_device_extensions.size(); + create.ppEnabledExtensionNames = m_device_extensions.data(); + create.queueCreateInfoCount = queues.size(); + create.pQueueCreateInfos = queues.data(); + create.pEnabledFeatures = &m_features; + // TODO: pNext for additional features + + if (vkCreateDevice(m_physical_device, &create, _get_allocator(VK_OBJECT_TYPE_DEVICE), &m_device) != VK_SUCCESS) { + throw std::runtime_error("Failed to create VkDevice"); + } + + NOVA_LOG("VkDevice created"); +} + VkAllocationCallbacks* VulkanRenderDriver::_get_allocator(const VkObjectType type) { // TODO: Add custom allocator (void)type; diff --git a/engine/src/drivers/vulkan/render_driver.h b/engine/src/drivers/vulkan/render_driver.h index b010a8d..8adde92 100644 --- a/engine/src/drivers/vulkan/render_driver.h +++ b/engine/src/drivers/vulkan/render_driver.h @@ -22,19 +22,30 @@ namespace Nova { [[nodiscard]] u32 get_device_count() const override; [[nodiscard]] const RenderDevice& get_device(u32 index) const override; + void create_device(u32 index) override; private: VkInstance m_instance = VK_NULL_HANDLE; + VkPhysicalDevice m_physical_device = VK_NULL_HANDLE; + VkDevice m_device = VK_NULL_HANDLE; + VkPhysicalDeviceFeatures m_features = {}; std::vector m_extensions; std::vector m_layers; + std::vector m_device_extensions; std::vector m_devices; void _check_version() const; void _check_extensions(); void _check_layers(); void _init_instance(); - void _init_devices(); + void _init_hardware(); + + // TODO: Other init functions for device + void _check_device_extensions(); + void _check_device_features(); + void _init_queues(std::vector& queues) const; + void _init_device(const std::vector& queues); static VkAllocationCallbacks* _get_allocator(VkObjectType type); };