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?
This commit is contained in:
2025-04-10 16:59:59 +10:00
parent 536a1e8773
commit 6e1393ce64
6 changed files with 95 additions and 23 deletions

View File

@@ -9,6 +9,7 @@
#include "drivers/vulkan/render_driver.h"
#include <nova/core/debug.h>
#include <nova/platform/window_driver.h>
#include <nova/version.h>
#include <vulkan/vulkan.h>
@@ -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<SurfaceData*>(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<u32>(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<VkDeviceQueueCreateInfo>
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

View File

@@ -14,6 +14,11 @@
#include <vector>
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<VkDeviceQueueCreateInfo>& queues) const;
void _init_device(const std::vector<VkDeviceQueueCreateInfo>& queues);
static VkAllocationCallbacks* _get_allocator(VkObjectType type);
};
} // namespace Nova

View File

@@ -9,6 +9,8 @@
#include "drivers/x11/window_driver.h"
#ifdef NOVA_VULKAN
#include "drivers/vulkan/render_driver.h"
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_xlib.h>
#endif
@@ -71,6 +73,10 @@ void X11WindowDriver::beep() {
XBell(m_display, 100);
}
u32 X11WindowDriver::get_window_count() const {
return static_cast<u32>(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<u32>(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>(window);
const auto vkrd = static_cast<VulkanRenderDriver*>(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<SurfaceID>(surface);
#else
return SurfaceID();
#endif
}
#endif // NOVA_X11

View File

@@ -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;