Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

cmake_minimum_required(VERSION 3.10)

project(xgpu VERSION 1.0.0 LANGUAGES CXX)
Expand Down
5 changes: 3 additions & 2 deletions examples/triangle/triangle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
#include <xgpu/shader.h>
#include <xgpu/types.h>
#include <array>
#include <xgpu/instance.h>
#include <xgpu/vulkan.h>

#include <cstddef>
#include <cstdio>
#include <fstream>
#include <functional>
#include <ios>
#include <iostream>
#include <xgpu/instance.h>
#include <xgpu/vulkan.h>
#include <stdexcept>
#include <vector>

Expand Down
11 changes: 11 additions & 0 deletions include/xgpu/constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef XGPU_CONSTANTS_H
#define XGPU_CONSTANTS_H

#include <cstddef>

namespace xgpu
{
constexpr std::size_t BackendObjectBufferSize { 256 };
} // namespace xgpu

#endif // XGPU_CONSTANTS_H
1 change: 0 additions & 1 deletion include/xgpu/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ namespace xgpu
private:
explicit Device() noexcept = default;


private:
std::unique_ptr<IDevice> _handle { nullptr };
};
Expand Down
86 changes: 70 additions & 16 deletions include/xgpu/instance.h
Original file line number Diff line number Diff line change
@@ -1,39 +1,93 @@
#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 <cstddef>
#include <cstring>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>

namespace xgpu
{
class IInstance
// class Instance : public IInstance
class Instance
{
// VTable info for type erasure
private:
struct VTable
{
std::function<auto(void*)->void> destroy;
std::function<auto(const void*)->Backend> backend;
};

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:
// Destroy the handle
virtual auto destroy() noexcept -> void = 0;
virtual auto backend() const noexcept -> Backend = 0;
};

class [[nodiscard]] Instance : public IInstance
{
template <typename T>
static auto get_vtable() -> const VTable&
{
static const VTable& table = {
.destroy = [](void* obj) { static_cast<T*>(obj)->destroy(); },
.backend = [](const void* obj) { return static_cast<const T*>(obj)->backend(); },
};

return table;
}


template <typename T>
auto get_as() -> T* { return reinterpret_cast<T*>(_buffer); }

public:
[[nodiscard("This returns a status code depending on if failed")]]
static auto create(const InstanceContext& ctx) noexcept -> expected<Instance, Error>;
auto destroy() noexcept -> void
{
_vtable->destroy(ptr());
}

auto destroy() noexcept -> void override { _handle->destroy(); }
auto backend() const noexcept -> Backend
{
return _vtable->backend(ptr());
}

[[nodiscard]] auto backend() const noexcept -> Backend override { return _handle->backend(); }
// 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 <typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, xgpu::Instance>>>
Instance(T&& backend_instance)
{
using DecayT = std::decay_t<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<T>(backend_instance));
_vtable = &get_vtable<DecayT>();
}

[[nodiscard]] auto handle() const noexcept -> IInstance* { return _handle.get(); }
public:
[[nodiscard("This returns a status code depending on if failed")]]
static auto create(const InstanceContext& ctx) noexcept -> expected<Instance, Error>;

protected:
explicit Instance() noexcept = default;

private:
std::unique_ptr<IInstance> _handle { nullptr };
};
} // namespace xgpu

Expand Down
2 changes: 2 additions & 0 deletions include/xgpu/vk/device.h
Original file line number Diff line number Diff line change
@@ -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 <cstdint>
Expand Down
12 changes: 7 additions & 5 deletions include/xgpu/vk/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,33 @@
#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 <optional>

namespace xgpu::vk
{
class [[nodiscard]] Instance : public xgpu::IInstance
class Instance
{
// Factory
public:
static auto create(const vk::InstanceContext& ctx) noexcept -> expected<vk::Instance, Error>;

// 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<DebugMessenger> _debug_messenger { std::nullopt };
VkInstance _handle { VK_NULL_HANDLE };
VkInstance _handle { VK_NULL_HANDLE };
};
} // namespace xgpu::vk

Expand Down
2 changes: 2 additions & 0 deletions include/xgpu/vulkan.h
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/instance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ namespace xgpu
return unexpected(expected_instance.unwrap_error());
}

instance._handle = std::make_unique<vk::Instance>(expected_instance.unwrap());
instance = expected_instance.unwrap();

return ok(instance);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/vk/device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ namespace xgpu::vk
}
auto Device::create_default(const DefaultDeviceContext& ctx) noexcept -> expected<Device, Error>
{
auto& vk_handle = *dynamic_cast<vk::Instance*>(ctx.instance.handle());
auto& vk_handle = *ctx.instance.get_as<vk::Instance>();
// auto& vk_handle = *dynamic_cast<vk::Instance*>(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
Expand Down