From 918e0d99b8814c9182c3b887943c54edd8b18194 Mon Sep 17 00:00:00 2001 From: raustin9 Date: Wed, 11 Feb 2026 15:32:08 -0500 Subject: [PATCH 1/3] update xgpu::Instance type erasure --- include/xgpu/constants.h | 11 +++++++ include/xgpu/instance.h | 68 +++++++++++++++++++++++++++++++++++++--- src/instance.cc | 3 +- src/vk/device.cc | 3 +- 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 include/xgpu/constants.h diff --git a/include/xgpu/constants.h b/include/xgpu/constants.h new file mode 100644 index 0000000..f9e7d53 --- /dev/null +++ b/include/xgpu/constants.h @@ -0,0 +1,11 @@ +#ifndef XGPU_CONSTANTS_H +#define XGPU_CONSTANTS_H + +#include + +namespace xgpu +{ + constexpr std::size_t BackendObjectBufferSize { 256 }; +} // namespace xgpu + +#endif // XGPU_CONSTANTS_H diff --git a/include/xgpu/instance.h b/include/xgpu/instance.h index dcfd0d1..6900014 100644 --- a/include/xgpu/instance.h +++ b/include/xgpu/instance.h @@ -1,11 +1,16 @@ #ifndef RHI_INSTANCE_H #define RHI_INSTANCE_H +#include "xgpu/constants.h" #include "xgpu/instance_context.h" #include "xgpu/expected.h" #include "xgpu/error.h" #include "xgpu/platform.h" +#include +#include #include +#include +#include namespace xgpu { @@ -17,17 +22,72 @@ namespace xgpu virtual auto backend() const noexcept -> Backend = 0; }; - class [[nodiscard]] Instance : public IInstance + // class Instance : public IInstance + class Instance { + public: + struct VTable + { + std::functionvoid> destroy; + std::functionBackend> backend; + }; + + + private: + alignas(std::max_align_t) char8_t _buffer[BackendObjectBufferSize]; + const VTable* _vtable { nullptr }; + + public: + template + static auto get_vtable() -> const VTable& + { + static const VTable& table = { + .destroy = [](void* obj) { static_cast(obj)->destroy(); }, + .backend = [](const void* obj) { return static_cast(obj)->backend(); }, + }; + + return table; + } + + auto ptr() -> void* { return _buffer; } + auto ptr() const -> const void* { return _buffer; } + + template + auto get_as() -> T* { return reinterpret_cast(_buffer); } + + public: + auto destroy() noexcept -> void + { + _vtable->destroy(ptr()); + } + + auto backend() const noexcept -> Backend + { + return _vtable->backend(ptr()); + } + + // Private conversion constructor from backend object instance + private: + template + Instance(T&& backend_instance) + { + using DecayT = std::decay_t; + static_assert(sizeof(DecayT) <= BackendObjectBufferSize, "Backend object T is too large to store in xgpu::Instance"); + static_assert(alignof(DecayT) <= alignof(std::max_align_t), "Backend object T has incompatible alignment"); + + new (_buffer) DecayT(std::forward(backend_instance)); + _vtable = &get_vtable(); + } + public: [[nodiscard("This returns a status code depending on if failed")]] static auto create(const InstanceContext& ctx) noexcept -> expected; - auto destroy() noexcept -> void override { _handle->destroy(); } + // auto destroy() noexcept -> void override { _handle->destroy(); } - [[nodiscard]] auto backend() const noexcept -> Backend override { return _handle->backend(); } + // [[nodiscard]] auto backend() const noexcept -> Backend override { return _handle->backend(); } - [[nodiscard]] auto handle() const noexcept -> IInstance* { return _handle.get(); } + // [[nodiscard]] auto handle() const noexcept -> IInstance* { return _handle.get(); } protected: explicit Instance() noexcept = default; diff --git a/src/instance.cc b/src/instance.cc index e507dce..bae9d13 100644 --- a/src/instance.cc +++ b/src/instance.cc @@ -26,8 +26,9 @@ namespace xgpu { return unexpected(expected_instance.unwrap_error()); } + instance = expected_instance.unwrap(); - instance._handle = std::make_unique(expected_instance.unwrap()); + // instance._handle = std::make_unique(expected_instance.unwrap()); return ok(instance); } } diff --git a/src/vk/device.cc b/src/vk/device.cc index cb658c8..09b2e65 100644 --- a/src/vk/device.cc +++ b/src/vk/device.cc @@ -227,7 +227,8 @@ namespace xgpu::vk } auto Device::create_default(const DefaultDeviceContext& ctx) noexcept -> expected { - auto& vk_handle = *dynamic_cast(ctx.instance.handle()); + auto& vk_handle = *ctx.instance.get_as(); + // auto& vk_handle = *dynamic_cast(ctx.instance.handle()); auto available_devices = getPhysicalDevices(vk_handle.native_handle()); // This is largely based on https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families From a345e52b5f68c588dcd60308d2488226e35c3a46 Mon Sep 17 00:00:00 2001 From: raustin9 Date: Wed, 11 Feb 2026 16:02:00 -0500 Subject: [PATCH 2/3] tighten up instance --- include/xgpu/instance.h | 40 ++++++++++++++++---------------------- include/xgpu/vk/instance.h | 12 +++++++----- src/instance.cc | 2 +- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/include/xgpu/instance.h b/include/xgpu/instance.h index 6900014..6cfba78 100644 --- a/include/xgpu/instance.h +++ b/include/xgpu/instance.h @@ -1,12 +1,14 @@ #ifndef RHI_INSTANCE_H #define RHI_INSTANCE_H +#include "types.h" #include "xgpu/constants.h" #include "xgpu/instance_context.h" #include "xgpu/expected.h" #include "xgpu/error.h" #include "xgpu/platform.h" #include +#include #include #include #include @@ -14,28 +16,23 @@ namespace xgpu { - class IInstance - { - public: - // Destroy the handle - virtual auto destroy() noexcept -> void = 0; - virtual auto backend() const noexcept -> Backend = 0; - }; - // class Instance : public IInstance class Instance { - public: + // VTable info for type erasure + private: struct VTable { std::functionvoid> destroy; std::functionBackend> backend; }; - - private: alignas(std::max_align_t) char8_t _buffer[BackendObjectBufferSize]; const VTable* _vtable { nullptr }; + + // Getters for underlying pointer to buffer + auto ptr() -> void* { return _buffer; } + auto ptr() const -> const void* { return _buffer; } public: template @@ -49,8 +46,6 @@ namespace xgpu return table; } - auto ptr() -> void* { return _buffer; } - auto ptr() const -> const void* { return _buffer; } template auto get_as() -> T* { return reinterpret_cast(_buffer); } @@ -66,9 +61,17 @@ namespace xgpu return _vtable->backend(ptr()); } + // Special members + public: + Instance(Instance&&) = default; + Instance(const Instance&) = default; + + auto operator=(Instance&&) -> Instance& = default; + auto operator=(const Instance&) -> Instance& = default; + // Private conversion constructor from backend object instance private: - template + template , xgpu::Instance>>> Instance(T&& backend_instance) { using DecayT = std::decay_t; @@ -82,18 +85,9 @@ namespace xgpu public: [[nodiscard("This returns a status code depending on if failed")]] static auto create(const InstanceContext& ctx) noexcept -> expected; - - // auto destroy() noexcept -> void override { _handle->destroy(); } - - // [[nodiscard]] auto backend() const noexcept -> Backend override { return _handle->backend(); } - - // [[nodiscard]] auto handle() const noexcept -> IInstance* { return _handle.get(); } protected: explicit Instance() noexcept = default; - - private: - std::unique_ptr _handle { nullptr }; }; } // namespace xgpu diff --git a/include/xgpu/vk/instance.h b/include/xgpu/vk/instance.h index d1ea313..9f76fc4 100644 --- a/include/xgpu/vk/instance.h +++ b/include/xgpu/vk/instance.h @@ -4,15 +4,16 @@ #ifdef RHI_COMPILE_VULKAN_BACKEND #include "xgpu/platform.h" -#include "xgpu/instance.h" #include "xgpu/vk/debug.h" +#include "xgpu/vk/instance_context.h" +#include "xgpu/error.h" #include "xgpu/vk/core.h" #include namespace xgpu::vk { - class [[nodiscard]] Instance : public xgpu::IInstance + class Instance { // Factory public: @@ -20,15 +21,16 @@ namespace xgpu::vk // API public: - auto destroy() noexcept -> void override; + auto destroy() noexcept -> void; - auto backend() const noexcept -> Backend override { return Backend::Vulkan; } + auto backend() const noexcept -> Backend { return Backend::Vulkan; } auto native_handle() const noexcept -> VkInstance { return _handle; } + // Private fields private: std::optional _debug_messenger { std::nullopt }; - VkInstance _handle { VK_NULL_HANDLE }; + VkInstance _handle { VK_NULL_HANDLE }; }; } // namespace xgpu::vk diff --git a/src/instance.cc b/src/instance.cc index bae9d13..8f3d6e9 100644 --- a/src/instance.cc +++ b/src/instance.cc @@ -26,9 +26,9 @@ namespace xgpu { return unexpected(expected_instance.unwrap_error()); } + instance = expected_instance.unwrap(); - // instance._handle = std::make_unique(expected_instance.unwrap()); return ok(instance); } } From de43a18421ec4869d4595a03b74f3c4fae016282 Mon Sep 17 00:00:00 2001 From: raustin9 Date: Mon, 2 Mar 2026 16:31:55 -0500 Subject: [PATCH 3/3] use new pattern in instance --- CMakeLists.txt | 1 - examples/triangle/triangle.cc | 5 +++-- include/xgpu/device.h | 1 - include/xgpu/vk/device.h | 2 ++ include/xgpu/vulkan.h | 2 ++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7289c9..85ca8d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ - cmake_minimum_required(VERSION 3.10) project(xgpu VERSION 1.0.0 LANGUAGES CXX) diff --git a/examples/triangle/triangle.cc b/examples/triangle/triangle.cc index c1ee872..bb71ab7 100644 --- a/examples/triangle/triangle.cc +++ b/examples/triangle/triangle.cc @@ -11,14 +11,15 @@ #include #include #include +#include +#include + #include #include #include #include #include #include -#include -#include #include #include diff --git a/include/xgpu/device.h b/include/xgpu/device.h index bead99c..273443e 100644 --- a/include/xgpu/device.h +++ b/include/xgpu/device.h @@ -82,7 +82,6 @@ namespace xgpu private: explicit Device() noexcept = default; - private: std::unique_ptr _handle { nullptr }; }; diff --git a/include/xgpu/vk/device.h b/include/xgpu/vk/device.h index ccbc0ef..83ebfc0 100644 --- a/include/xgpu/vk/device.h +++ b/include/xgpu/vk/device.h @@ -1,5 +1,7 @@ #ifndef RHI_VK_DEVICE_H #define RHI_VK_DEVICE_H +#include "xgpu/constants.h" +#include "xgpu/platform.h" #ifdef RHI_COMPILE_VULKAN_BACKEND #include diff --git a/include/xgpu/vulkan.h b/include/xgpu/vulkan.h index ba040d4..d542b3c 100644 --- a/include/xgpu/vulkan.h +++ b/include/xgpu/vulkan.h @@ -1,7 +1,9 @@ #ifndef RHI_VULKAN_H #define RHI_VULKAN_H +#include "xgpu/vk/core.h" #include "xgpu/vk/instance.h" #include "xgpu/vk/device.h" +#include "xgpu/vk/buffer.h" #endif // RHI_VULKAN_H