From 6e1393ce643fb7f3095699ed89a2fbc375fbc242 Mon Sep 17 00:00:00 2001 From: Jayden Grubb Date: Thu, 10 Apr 2025 16:59:59 +1000 Subject: [PATCH] Add basic surface handling to RenderDriver and WindowDriver This will likely require significant rework but it will do for now. A considerations worth thinking about: - What happends when the WindowDriver destroys a window, what happens to the corresponding surface? --- engine/include/nova/platform/window_driver.h | 9 +++-- engine/include/nova/render/render_driver.h | 15 +++++++- engine/src/drivers/vulkan/render_driver.cpp | 40 +++++++++++++++----- engine/src/drivers/vulkan/render_driver.h | 13 ++++++- engine/src/drivers/x11/window_driver.cpp | 35 +++++++++++++++-- engine/src/drivers/x11/window_driver.h | 6 +-- 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/engine/include/nova/platform/window_driver.h b/engine/include/nova/platform/window_driver.h index 3f050e9..ffefc64 100644 --- a/engine/include/nova/platform/window_driver.h +++ b/engine/include/nova/platform/window_driver.h @@ -13,6 +13,9 @@ namespace Nova { using WindowID = uptr; + using SurfaceID = uptr; + + class RenderDriver; class NOVA_API WindowDriver { public: @@ -22,15 +25,15 @@ namespace Nova { virtual void poll_events() = 0; virtual void beep() = 0; - virtual WindowID create_window(std::string_view title, u32 width, u32 height) = 0; + [[nodiscard]] virtual u32 get_window_count() const = 0; + [[nodiscard]] virtual WindowID create_window(std::string_view title, u32 width, u32 height) = 0; virtual void destroy_window(WindowID window) = 0; virtual void set_window_title(WindowID window, std::string_view title) = 0; virtual void set_window_size(WindowID window, u32 width, u32 height) = 0; virtual void set_window_position(WindowID window, i32 x, i32 y) = 0; - [[nodiscard]] virtual u32 get_window_count() const = 0; - [[nodiscard]] virtual const char* get_surface_extension() const = 0; + [[nodiscard]] virtual SurfaceID create_surface(WindowID window, RenderDriver* render_driver) = 0; }; } // namespace Nova diff --git a/engine/include/nova/render/render_driver.h b/engine/include/nova/render/render_driver.h index b514779..f7ac2eb 100644 --- a/engine/include/nova/render/render_driver.h +++ b/engine/include/nova/render/render_driver.h @@ -7,7 +7,6 @@ #pragma once #include -#include #include #include #include @@ -15,6 +14,11 @@ #include namespace Nova { + using WindowID = uptr; + using SurfaceID = uptr; + + class WindowDriver; + class NOVA_API RenderDriver { public: static RenderDriver* create(RenderAPI api, WindowDriver* window_driver = nullptr); @@ -28,5 +32,14 @@ namespace Nova { [[nodiscard]] virtual u32 get_device_count() const = 0; [[nodiscard]] virtual const RenderDevice& get_device(u32 index) const = 0; virtual void select_device(u32 index) = 0; + + [[nodiscard]] virtual SurfaceID create_surface(WindowID window) = 0; + virtual void destroy_surface(SurfaceID surface) = 0; + // TODO: get_surface_size + // TODO: get_surface_mode + // TODO: get_surface_state + // TODO: set_surface_size + // TODO: set_surface_mode + // TODO: set_surface_state }; } // namespace Nova diff --git a/engine/src/drivers/vulkan/render_driver.cpp b/engine/src/drivers/vulkan/render_driver.cpp index 548d13e..4594282 100644 --- a/engine/src/drivers/vulkan/render_driver.cpp +++ b/engine/src/drivers/vulkan/render_driver.cpp @@ -9,6 +9,7 @@ #include "drivers/vulkan/render_driver.h" #include +#include #include #include @@ -31,10 +32,10 @@ VulkanRenderDriver::VulkanRenderDriver(WindowDriver* window_driver) : m_window_d VulkanRenderDriver::~VulkanRenderDriver() { NOVA_AUTO_TRACE(); if (m_device) { - vkDestroyDevice(m_device, _get_allocator(VK_OBJECT_TYPE_DEVICE)); + vkDestroyDevice(m_device, get_allocator(VK_OBJECT_TYPE_DEVICE)); } if (m_instance) { - vkDestroyInstance(m_instance, _get_allocator(VK_OBJECT_TYPE_INSTANCE)); + vkDestroyInstance(m_instance, get_allocator(VK_OBJECT_TYPE_INSTANCE)); } } @@ -94,6 +95,31 @@ void VulkanRenderDriver::select_device(u32 index) { _init_device(queues); } +SurfaceID VulkanRenderDriver::create_surface(const WindowID window) { + NOVA_AUTO_TRACE(); + NOVA_ASSERT(m_instance); + NOVA_ASSERT(m_window_driver); + return m_window_driver->create_surface(window, this); +} + +void VulkanRenderDriver::destroy_surface(const SurfaceID surface) { + NOVA_AUTO_TRACE(); + NOVA_ASSERT(m_instance); + SurfaceData* data = reinterpret_cast(surface); + vkDestroySurfaceKHR(m_instance, data->handle, get_allocator(VK_OBJECT_TYPE_SURFACE_KHR)); + delete data; +} + +VkInstance VulkanRenderDriver::get_instance() const { + return m_instance; +} + +VkAllocationCallbacks* VulkanRenderDriver::get_allocator(const VkObjectType type) const { + // TODO: Add custom allocator + (void)type; + return nullptr; +} + void VulkanRenderDriver::_check_version() const { NOVA_AUTO_TRACE(); @@ -206,7 +232,7 @@ void VulkanRenderDriver::_init_instance() { create.enabledExtensionCount = static_cast(m_extensions.size()); create.ppEnabledExtensionNames = m_extensions.data(); - if (vkCreateInstance(&create, _get_allocator(VK_OBJECT_TYPE_INSTANCE), &m_instance) != VK_SUCCESS) { + if (vkCreateInstance(&create, get_allocator(VK_OBJECT_TYPE_INSTANCE), &m_instance) != VK_SUCCESS) { throw std::runtime_error("Failed to create VkInstance"); } @@ -338,17 +364,11 @@ void VulkanRenderDriver::_init_device(const std::vector 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) { + 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; - return nullptr; -} - #endif // NOVA_VULKAN diff --git a/engine/src/drivers/vulkan/render_driver.h b/engine/src/drivers/vulkan/render_driver.h index 8bcdae2..5eb2946 100644 --- a/engine/src/drivers/vulkan/render_driver.h +++ b/engine/src/drivers/vulkan/render_driver.h @@ -14,6 +14,11 @@ #include namespace Nova { + struct SurfaceData { + VkSurfaceKHR handle = VK_NULL_HANDLE; + // TODO: Add stuff here + }; + class VulkanRenderDriver final : public RenderDriver { public: explicit VulkanRenderDriver(WindowDriver* window_driver); @@ -28,6 +33,12 @@ namespace Nova { [[nodiscard]] const RenderDevice& get_device(u32 index) const override; void select_device(u32 index) override; + [[nodiscard]] SurfaceID create_surface(WindowID window) override; + void destroy_surface(SurfaceID surface) override; + + [[nodiscard]] VkInstance get_instance() const; + [[nodiscard]] VkAllocationCallbacks* get_allocator(VkObjectType type) const; + private: WindowDriver* m_window_driver = nullptr; VkInstance m_instance = VK_NULL_HANDLE; @@ -50,8 +61,6 @@ namespace Nova { void _check_device_features(); void _init_queues(std::vector& queues) const; void _init_device(const std::vector& queues); - - static VkAllocationCallbacks* _get_allocator(VkObjectType type); }; } // namespace Nova diff --git a/engine/src/drivers/x11/window_driver.cpp b/engine/src/drivers/x11/window_driver.cpp index 4dfe362..a07bc63 100644 --- a/engine/src/drivers/x11/window_driver.cpp +++ b/engine/src/drivers/x11/window_driver.cpp @@ -9,6 +9,8 @@ #include "drivers/x11/window_driver.h" #ifdef NOVA_VULKAN +#include "drivers/vulkan/render_driver.h" + #include #include #endif @@ -71,6 +73,10 @@ void X11WindowDriver::beep() { XBell(m_display, 100); } +u32 X11WindowDriver::get_window_count() const { + return static_cast(m_windows.size()); +} + WindowID X11WindowDriver::create_window(const std::string_view title, const u32 width, const u32 height) { NOVA_AUTO_TRACE(); @@ -114,10 +120,6 @@ void X11WindowDriver::set_window_position(const WindowID window, const i32 x, co XMoveWindow(m_display, window, x, y); } -u32 X11WindowDriver::get_window_count() const { - return static_cast(m_windows.size()); -} - const char* X11WindowDriver::get_surface_extension() const { #ifdef NOVA_VULKAN return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; @@ -126,4 +128,29 @@ const char* X11WindowDriver::get_surface_extension() const { #endif } +SurfaceID X11WindowDriver::create_surface(const WindowID window, RenderDriver* render_driver) { + NOVA_AUTO_TRACE(); + NOVA_ASSERT(m_windows.contains(window)); + NOVA_ASSERT(render_driver); + NOVA_ASSERT(render_driver->get_api() == RenderAPI::VULKAN); + +#ifdef NOVA_VULKAN + VkXlibSurfaceCreateInfoKHR create {}; + create.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + create.dpy = m_display; + create.window = static_cast(window); + + const auto vkrd = static_cast(render_driver); + SurfaceData* surface = new SurfaceData(); + + if (vkCreateXlibSurfaceKHR(vkrd->get_instance(), &create, vkrd->get_allocator(VK_OBJECT_TYPE_SURFACE_KHR), &surface->handle) + != VK_SUCCESS) { + throw std::runtime_error("Failed to create Vulkan surface"); + } + return reinterpret_cast(surface); +#else + return SurfaceID(); +#endif +} + #endif // NOVA_X11 diff --git a/engine/src/drivers/x11/window_driver.h b/engine/src/drivers/x11/window_driver.h index f084f7e..e5e9c15 100644 --- a/engine/src/drivers/x11/window_driver.h +++ b/engine/src/drivers/x11/window_driver.h @@ -26,16 +26,16 @@ namespace Nova { void poll_events() override; void beep() override; - WindowID create_window(std::string_view title, u32 width, u32 height) override; + [[nodiscard]] u32 get_window_count() const override; + [[nodiscard]] WindowID create_window(std::string_view title, u32 width, u32 height) override; void destroy_window(WindowID window) override; void set_window_title(WindowID window, std::string_view title) override; void set_window_size(WindowID window, u32 width, u32 height) override; void set_window_position(WindowID window, i32 x, i32 y) override; - [[nodiscard]] u32 get_window_count() const override; - [[nodiscard]] const char* get_surface_extension() const override; + [[nodiscard]] SurfaceID create_surface(WindowID window, RenderDriver* render_driver) override; private: Display* m_display = nullptr;